Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions class/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,13 @@ parameters:
- syn

namespaces: {}

labelSync:
ignoreNames: []
Comment thread
DebakelOrakel marked this conversation as resolved.
ignorePrefixes:
- cilium
- kube
- openshift
- appuio
- syn
applyOnPrefix: {}
1 change: 1 addition & 0 deletions class/namespaces.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ parameters:
output_path: .
- input_paths:
- ${_base_directory}/component/main.jsonnet
- ${_base_directory}/component/espejote.jsonnet
input_type: jsonnet
output_path: ${_instance}/
68 changes: 68 additions & 0 deletions component/espejote-templates/label-sync.jsonnet
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefix and contains labels should probably be concatenated.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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.
i could get rid of it in that component and deal with the exception seperatly


// 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)
])
)
135 changes: 135 additions & 0 deletions component/espejote.jsonnet
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 {}
57 changes: 57 additions & 0 deletions docs/modules/ROOT/pages/references/parameters.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,63 @@ default:: {}
Contains a list of namespaces to create.


== `labelSync`

Configures dynamic Roles and RoleBindings managed by Espejote.

=== `labelSync.ignoredNames`

[horizontal]
type:: list of strings
default:: empty list

A list of namespace names where no labels will be applied.
Entries in the list can be removed by adding the entry prefixed with a `~`.

=== `labelSync.ignoredPrefixes`

[horizontal]
type:: list of strings
default::
+
[source,yaml]
----
labelSync:
ignoredPrefixes:
- kube
- openshift
- appuio
- syn
----

A list of namespace name-prefixes where no labels will be applied.
Entries in the list can be removed by adding the entry prefixed with a `~`.

=== `labelSync.applyOnPrefix`

[horizontal]
type:: dict
default:: `{}`
example::
+
[source,yaml]
----
labelSync:
applyOnPrefix:
'vshn-postgres': <1>
'set.rbac.syn.tools/allow-team1': '' <2>
----
<1> Matches all namespaces that start with `vshn-postgres`.
<2> Applies the label `set.rbac.syn.tools/allow-team1=''` to the matching namespace.

Custom set of namespace prefixes, where the listed labels will be applied.

[IMPORTANT]
====
Using this with too broad settings can have unintended sideeffects!
====


== Example

[source,yaml]
Expand Down
Loading
Loading