-
Notifications
You must be signed in to change notification settings - Fork 0
Support label namespaces based on prefixes #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+586
−0
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| local esp = import 'espejote.libsonnet'; | ||
| local context = esp.context(); | ||
|
|
||
| // Check if the namespace should be ignored | ||
| local ignoreNamespace(namespace, config) = | ||
| if std.member(config.ignoreNames, namespace.metadata.name) then | ||
| true | ||
| else if std.length(std.filter( | ||
| function(prefix) std.startsWith(namespace.metadata.name, prefix), | ||
| config.ignorePrefixes | ||
| )) > 0 then | ||
| true | ||
| else false; | ||
|
|
||
| // Get the labels from a namespace name prefix by | ||
| // first finding the prefixes that match with the namespace name | ||
| // then return the labels defined for that prefix. | ||
| local labelsFromPrefix(namespace, config) = | ||
| local filteredPrefixes = std.filter( | ||
| function(prefix) std.startsWith(namespace.metadata.name, prefix), | ||
| std.objectFields(config.applyOnPrefix) | ||
| ); | ||
| // If multiple prefixes define the same key, the more specific prefix wins. | ||
| local sortedPrefixes = std.sort( | ||
| filteredPrefixes, | ||
| function(obj) std.length(obj) | ||
| ); | ||
| // Merge the labels from the prefixes | ||
| local mergedLabels = std.foldl( | ||
| function(acc, prefix) acc + config.applyOnPrefix[prefix], | ||
| sortedPrefixes, | ||
| {} | ||
| ); | ||
|
|
||
| { | ||
| [key]: mergedLabels[key] | ||
| for key in std.objectFields(mergedLabels) | ||
| if mergedLabels[key] != null | ||
| }; | ||
|
|
||
| // Reconcile the given namespace. | ||
| local reconcileNamespace(namespace, config) = | ||
| // Check if the namespace can be ignored | ||
| if ignoreNamespace(namespace, config) then [] | ||
| // Apply labels if the namespace name starts with defined prefixes | ||
| else if labelsFromPrefix(namespace, config) != {} then [ | ||
| namespace { | ||
| metadata+: { | ||
| labels+: labelsFromPrefix(namespace, config), | ||
| }, | ||
| }, | ||
| ] | ||
| else []; | ||
|
|
||
| // check if the object is getting deleted by checking if it has | ||
| // `metadata.deletionTimestamp`. | ||
| local inDelete(obj) = std.get(obj.metadata, 'deletionTimestamp', '') != ''; | ||
|
|
||
| // Do the thing | ||
| if esp.triggerName() == 'namespace' then ( | ||
| // Handle single namespace update on namespace trigger | ||
| local nsTrigger = esp.triggerData(); | ||
| // nsTrigger.resource can be null if we're called when the namespace is getting | ||
| // deleted. If it's not null, we still don't want to do anything when the | ||
| // namespace is getting deleted. | ||
| if nsTrigger.resource != null && !inDelete(nsTrigger.resource) then | ||
| reconcileNamespace(nsTrigger.resource, config) | ||
| ) else ( | ||
| // Reconcile all namespaces for managedresource reconcile. | ||
| local namespaces = context.namespaces; | ||
| std.flattenArrays([ | ||
| reconcileNamespace(ns, config) | ||
| for ns in namespaces | ||
| if !inDelete(ns) | ||
| ]) | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| local com = import 'lib/commodore.libjsonnet'; | ||
| local esp = import 'lib/espejote.libsonnet'; | ||
| local kap = import 'lib/kapitan.libjsonnet'; | ||
| local kube = import 'lib/kube.libjsonnet'; | ||
| local utils = import 'utils.libsonnet'; | ||
|
|
||
| // The hiera parameters for the component | ||
| local inv = kap.inventory(); | ||
| local params = inv.parameters.namespaces; | ||
| local instanceName = inv.parameters._instance; | ||
|
|
||
| local espNamespace = inv.parameters.espejote.namespace; | ||
| local mrName = '%s-label-sync' % instanceName; | ||
| local rbacName = 'managedresource-%s-label-sync' % instanceName; | ||
|
|
||
| // RBAC for Espejote | ||
| local espejoteRBAC = [ | ||
| { | ||
| apiVersion: 'v1', | ||
| kind: 'ServiceAccount', | ||
| metadata: { | ||
| labels: { | ||
| 'app.kubernetes.io/component': 'rbac', | ||
| 'app.kubernetes.io/name': mrName, | ||
| }, | ||
| name: mrName, | ||
| namespace: espNamespace, | ||
| }, | ||
| }, | ||
| { | ||
| apiVersion: 'rbac.authorization.k8s.io/v1', | ||
| kind: 'ClusterRole', | ||
| metadata: { | ||
| labels: { | ||
| 'app.kubernetes.io/component': 'rbac', | ||
| 'app.kubernetes.io/name': rbacName, | ||
| }, | ||
| name: rbacName, | ||
| }, | ||
| rules: [ | ||
| { | ||
| apiGroups: [ '' ], | ||
| resources: [ 'namespaces' ], | ||
| verbs: [ 'get', 'list', 'watch', 'patch' ], | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| apiVersion: 'rbac.authorization.k8s.io/v1', | ||
| kind: 'ClusterRoleBinding', | ||
| metadata: { | ||
| labels: { | ||
| 'app.kubernetes.io/component': 'rbac', | ||
| 'app.kubernetes.io/name': rbacName, | ||
| }, | ||
| name: rbacName, | ||
| }, | ||
| roleRef: { | ||
| apiGroup: 'rbac.authorization.k8s.io', | ||
| kind: 'ClusterRole', | ||
| name: rbacName, | ||
| }, | ||
| subjects: [ | ||
| { | ||
| kind: 'ServiceAccount', | ||
| name: mrName, | ||
| namespace: espNamespace, | ||
| }, | ||
| ], | ||
| }, | ||
| ]; | ||
|
|
||
| // Espejote resources | ||
| local managedResource = esp.managedResource(mrName, espNamespace) { | ||
| metadata+: { | ||
| annotations: { | ||
| 'syn.tools/description': ||| | ||
| Manages labels of namespaces based on namespace prefixes. | ||
| See https://hub.syn.tools/namespaces/index.html for details. | ||
| |||, | ||
| }, | ||
| }, | ||
| spec: { | ||
| context: [ | ||
| { | ||
| name: 'namespaces', | ||
| resource: { | ||
| apiVersion: 'v1', | ||
| kind: 'Namespace', | ||
| }, | ||
| }, | ||
| ], | ||
| triggers: [ | ||
| { | ||
| name: 'namespace', | ||
| watchContextResource: { | ||
| name: 'namespaces', | ||
| }, | ||
| }, | ||
| ], | ||
| serviceAccountRef: { | ||
| name: espejoteRBAC[0].metadata.name, | ||
| }, | ||
| template: ('local config = %s;\n' % std.manifestJson(params.labelSync)) | ||
| + (importstr 'espejote-templates/label-sync.jsonnet'), | ||
| }, | ||
| }; | ||
|
|
||
| // Check if espejote is installed and resources are configured | ||
| local hasEspejote = std.member(inv.applications, 'espejote'); | ||
| local hasDynamicLabels = std.length(params.labelSync.applyOnPrefix) > 0; | ||
|
|
||
| // Define outputs below | ||
| if hasDynamicLabels && hasEspejote then | ||
| { | ||
| '00_espejote_rbac': espejoteRBAC, | ||
| '00_espejote_mr': managedResource, | ||
| } | ||
| else if hasDynamicLabels then | ||
| std.trace( | ||
| 'espejote must be installed', | ||
| {} | ||
| ) | ||
| else {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| = Using LabelSync on Namespace Prefixes | ||
|
|
||
| Whit this component you can label namespaces based on their prefixes. | ||
|
|
||
| == Customizing Labels and Prefixes | ||
|
|
||
| You can define sets of labels that should be applied on namespaces that match the defined prefixes. | ||
|
|
||
| [TIP] | ||
| ==== | ||
| All labels from all matched prefixes get applied, if a label key is defined multiple times the longest prefix has precedence. | ||
| ==== | ||
|
|
||
| [source,yaml] | ||
| ---- | ||
| labelSync: | ||
| applyOnPrefix: | ||
| vshn-postgres: <1> | ||
| set.rbac.syn.tools/allow-team2: '' <2> | ||
| syn.tools/environment: test <2> | ||
| vshn-postgres-test: | ||
| set.rbac.syn.tools/allow-team2: null <3> | ||
| set.rbac.syn.tools/allow-team3: '' | ||
| vshn-postgres-prod: | ||
| syn.tools/environment: prod <4> | ||
| ---- | ||
| <1> Prefix that will be matched to namespaces. | ||
| <2> Defines the label that will be applied if the prefix matches. | ||
| <3> Labels with a value of null will be removed, eg. if a less precise prefix match adds this label. | ||
| <4> Overwrites the value of a label, eg. if a less precise prefix match has a different value. | ||
|
|
||
| == Examples | ||
|
|
||
| Using above configuration, here are a couple of examples for better understanding. | ||
|
|
||
| === Overwriting Labels | ||
|
|
||
| If you have the following namespaces: | ||
|
|
||
| [source,yaml] | ||
| ---- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| name: vshn-postgres-abc | ||
| --- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| name: vshn-postgres-prod-abc | ||
| ---- | ||
|
|
||
| Then the following labels will be applied: | ||
|
|
||
| [source,yaml] | ||
| ---- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| labels: | ||
| set.rbac.syn.tools/allow-team2: '' | ||
| syn.tools/environment: test | ||
| name: vshn-postgres-abc | ||
| --- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| labels: | ||
| set.rbac.syn.tools/allow-team2: '' | ||
| syn.tools/environment: prod <1> | ||
| name: vshn-postgres-prod-abc | ||
| ---- | ||
| <1> This label got overwritten by the more precise prefix match. | ||
|
|
||
| === Removing Labels | ||
|
|
||
|
|
||
| If you have the following namespaces: | ||
|
|
||
| [source,yaml] | ||
| ---- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| name: vshn-postgres-abc | ||
| --- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| name: vshn-postgres-test-abc | ||
| ---- | ||
|
|
||
| Then the following labels will be applied: | ||
|
|
||
| [source,yaml] | ||
| ---- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| labels: | ||
| set.rbac.syn.tools/allow-team2: '' | ||
| syn.tools/environment: test | ||
| name: vshn-postgres-abc | ||
| --- | ||
| apiVersion: v1 | ||
| kind: Namespace | ||
| metadata: | ||
| labels: | ||
| set.rbac.syn.tools/allow-team3: '' <1> <2> | ||
| syn.tools/environment: test | ||
| name: vshn-postgres-test-abc | ||
| ---- | ||
| <1> This label was added by the more precise prefix match. | ||
| <2> The label `set.rbac.syn.tools/allow-team2` was removed by the rule: | ||
| + | ||
| [source,yaml] | ||
| ---- | ||
| vshn-postgres-test: | ||
| set.rbac.syn.tools/allow-team2: null | ||
| ---- |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.