Skip to content

Commit 6019cf5

Browse files
committed
Add handling for Kustomize directories
- Add handling for directories with a `kustomization.yaml` file - Add Kustomize directory example - Update reference YAML - Add note about supporting Kustomize directories - Add deprecation tag to patching Signed-off-by: Dale Haiducek <[email protected]>
1 parent 1e0b216 commit 6019cf5

File tree

10 files changed

+319
-9
lines changed

10 files changed

+319
-9
lines changed

docs/policygenerator-reference.yaml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ policies:
122122
manifests:
123123
# Required. Path to a single file or a flat directory of files relative to the
124124
# kustomization.yaml file. This path cannot be in a directory outside of the directory with
125-
# the kustomization.yaml file. Subdirectories within the directory with kustomization.yaml
126-
# file are allowed.
125+
# the kustomization.yaml file. Subdirectories within the directory of the kustomization.yaml
126+
# file are allowed. Kustomization subdirectories are also supported and will not process any
127+
# YAML files in the subdirectory if a kustomization.yaml file is found.
127128
# Supported manifests:
128129
# 1) Non-root policy type manifests such as IamPolicy, CertificatePolicy, and ConfigurationPolicy
129130
# that have a "Policy" suffix. These are not modified except for patches and are directly added
@@ -137,10 +138,10 @@ policies:
137138
metadataComplianceType: ""
138139
# Optional. (See policyDefaults.evaluationInterval for description.)
139140
evaluationInterval: {}
140-
# Optional. A Kustomize patch to apply to the manifest(s) at the path. If there
141-
# are multiple manifests, the patch requires the apiVersion, kind, metadata.name,
142-
# and metadata.namespace (if applicable) fields to be set so Kustomize
143-
# can identify the manifest the patch applies to.
141+
# (Note: a path to a directory containing a Kustomize manifest is a supported alternative.) Optional. A
142+
# Kustomize patch to apply to the manifest(s) at the path. If there are multiple manifests, the patch requires
143+
# the apiVersion, kind, metadata.name, and metadata.namespace (if applicable) fields to be set so Kustomize can
144+
# identify the manifest the patch applies to.
144145
patches:
145146
# Optional: Only required when there are multiple manifests in the path.
146147
- apiVersion: ""
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resources:
2+
- nginx-pod.yaml
3+
labels:
4+
- pairs:
5+
app: myapp
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: v1
2+
kind: Pod
3+
metadata:
4+
name: myapp-pod
5+
spec:
6+
containers:
7+
- name: nginx
8+
image: nginx:1.8.0
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
resources:
2+
- ../base
3+
namePrefix: dev-
4+
namespace: myapp-dev
5+
labels:
6+
- pairs:
7+
env: dev
8+
images:
9+
- name: nginx
10+
newTag: latest
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
resources:
2+
- dev
3+
- prod
4+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
resources:
2+
- ../base
3+
namePrefix: prod-
4+
labels:
5+
- pairs:
6+
env: prod
7+
images:
8+
- name: nginx
9+
newTag: latest

examples/kustomization.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
generators:
22
- ./policyGenerator.yaml
3+
- ./policyGenerator-kustomize.yaml
34
patchesStrategicMerge:
45
- input/patch.yaml
56
commonLabels:
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: policy.open-cluster-management.io/v1
2+
kind: PolicyGenerator
3+
metadata:
4+
name: policy-generator-kustomize
5+
policyDefaults:
6+
namespace: my-policies
7+
# Put each object in its own ConfigurationPolicy in the Policy
8+
consolidateManifests: false
9+
# Use the name of an existing placement rule
10+
placement:
11+
placementRuleName: placement-red-hat-cloud
12+
policies:
13+
- name: myapp
14+
manifests:
15+
- path: input-kustomize/

internal/utils.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ import (
1616
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1717
"open-cluster-management.io/ocm-kustomize-generator-plugins/internal/expanders"
1818
"open-cluster-management.io/ocm-kustomize-generator-plugins/internal/types"
19+
"sigs.k8s.io/kustomize/api/krusty"
20+
"sigs.k8s.io/kustomize/kyaml/filesys"
1921
)
2022

2123
// getManifests will get all of the manifest files associated with the input policy configuration
2224
// separated by policyConf.Manifests entries. An error is returned if a manifest path cannot
2325
// be read.
2426
func getManifests(policyConf *types.PolicyConfig) ([][]map[string]interface{}, error) {
2527
manifests := [][]map[string]interface{}{}
28+
hasKustomize := map[string]bool{}
2629

2730
for _, manifest := range policyConf.Manifests {
2831
manifestPaths := []string{}
@@ -34,6 +37,8 @@ func getManifests(policyConf *types.PolicyConfig) ([][]map[string]interface{}, e
3437
return nil, readErr
3538
}
3639

40+
resolvedFiles := []string{}
41+
3742
if manifestPathInfo.IsDir() {
3843
files, err := ioutil.ReadDir(manifest.Path)
3944
if err != nil {
@@ -45,14 +50,26 @@ func getManifests(policyConf *types.PolicyConfig) ([][]map[string]interface{}, e
4550
continue
4651
}
4752

48-
ext := path.Ext(f.Name())
53+
filepath := f.Name()
54+
ext := path.Ext(filepath)
55+
4956
if ext != ".yaml" && ext != ".yml" {
5057
continue
5158
}
59+
// Handle when a Kustomization directory is specified
60+
_, filename := path.Split(filepath)
61+
if filename == "kustomization.yml" || filename == "kustomization.yaml" {
62+
hasKustomize[manifest.Path] = true
63+
resolvedFiles = []string{manifest.Path}
64+
65+
break
66+
}
5267

5368
yamlPath := path.Join(manifest.Path, f.Name())
54-
manifestPaths = append(manifestPaths, yamlPath)
69+
resolvedFiles = append(resolvedFiles, yamlPath)
5570
}
71+
72+
manifestPaths = append(manifestPaths, resolvedFiles...)
5673
} else {
5774
// Unmarshal the manifest in order to check for metadata patch replacement
5875
manifestFile, err := unmarshalManifestFile(manifest.Path)
@@ -85,7 +102,15 @@ func getManifests(policyConf *types.PolicyConfig) ([][]map[string]interface{}, e
85102
}
86103

87104
for _, manifestPath := range manifestPaths {
88-
manifestFile, err := unmarshalManifestFile(manifestPath)
105+
var manifestFile *[]map[string]interface{}
106+
var err error
107+
108+
if hasKustomize[manifestPath] {
109+
manifestFile, err = processKustomizeDir(manifestPath)
110+
} else {
111+
manifestFile, err = unmarshalManifestFile(manifestPath)
112+
}
113+
89114
if err != nil {
90115
return nil, err
91116
}
@@ -245,6 +270,28 @@ func setNamespaceSelector(policyConf *types.PolicyConfig, policyTemplate *map[st
245270
}
246271
}
247272

273+
// processKustomizeDir runs a provided directory through Kustomize in order to generate the manifests within it.
274+
func processKustomizeDir(path string) (*[]map[string]interface{}, error) {
275+
k := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
276+
277+
resourceMap, err := k.Run(filesys.MakeFsOnDisk(), path)
278+
if err != nil {
279+
return nil, fmt.Errorf("failed to process provided kustomize directory '%s': %w", path, err)
280+
}
281+
282+
manifestsYAML, err := resourceMap.AsYaml()
283+
if err != nil {
284+
return nil, fmt.Errorf("failed to convert the kustomize manifest(s) to YAML from directory '%s': %w", path, err)
285+
}
286+
287+
manifests, err := unmarshalManifestBytes(manifestsYAML)
288+
if err != nil {
289+
return nil, fmt.Errorf("failed to read the kustomize manifest(s) from directory '%s': %w", path, err)
290+
}
291+
292+
return manifests, nil
293+
}
294+
248295
// buildPolicyTemplate generates single policy template by using objectTemplates with manifests.
249296
// policyNum defines which number the configuration policy is in the policy. If it is greater than
250297
// one then the configuration policy name will have policyNum appended to it.

0 commit comments

Comments
 (0)