-
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| local esp = import 'espejote.libsonnet'; | ||
| local context = esp.context(); | ||
|
|
||
| local ignoreNamespace(namespace) = | ||
| 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) = | ||
| local prefixes = std.filter( | ||
| function(prefix) std.startsWith(namespace.metadata.name, prefix), | ||
| std.objectFields(config.applyOnPrefix) | ||
| ); | ||
|
|
||
| if std.length(prefixes) > 0 then prefixLabels[prefixes[0]] else {}; | ||
|
|
||
| // Reconcile the given namespace. | ||
| local reconcileNamespace(namespace) = | ||
| // Check if the namespace can be ignored | ||
| if ignoreNamespace(namespace) then [] | ||
| // Apply labels if the namespace name contains 'carema' | ||
| else if labelsFromContains(namespace) != {} then [ | ||
| namespace { | ||
| metadata+: { | ||
| labels+: labelsFromContains(namespace), | ||
| }, | ||
| }, | ||
| ] | ||
| // Apply labels if the namespace name starts with defined prefix | ||
| else if labelsFromPrefix(namespace) != {} then [ | ||
| namespace { | ||
| metadata+: { | ||
| labels+: labelsFromPrefix(namespace), | ||
| }, | ||
| }, | ||
| ] | ||
| else []; | ||
|
Comment on lines
+30
to
+45
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefix and contains labels should probably be concatenated.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i dont like the contains at all, but we have it in place for one customer. |
||
|
|
||
| // 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) | ||
| ) else ( | ||
| // Reconcile all namespaces for managedresource reconcile. | ||
| local namespaces = context.namespaces; | ||
| std.flattenArrays([ | ||
| reconcileNamespace(ns) | ||
| for ns in namespaces | ||
| if !inDelete(ns) | ||
| ]) | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| 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; | ||
|
|
||
| // Check if there are overlapping prefixes in applyOnPrefix | ||
| local overlappingPrefixes = std.filter( | ||
| function(prefix) | ||
| std.length(std.filter( | ||
| function(other) other != prefix && std.startsWith(other, prefix), | ||
| std.objectFields(params.labelSync.applyOnPrefix) | ||
| )) > 0, | ||
| std.objectFields(params.labelSync.applyOnPrefix) | ||
| ); | ||
| assert std.length(overlappingPrefixes) < 1 : 'overlapping prefixes in parameters.%s.labelSync.applyOnPrefix' % 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: '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 {} |
Uh oh!
There was an error while loading. Please reload this page.