| 
 | 1 | +/**  | 
 | 2 | + * \file Library with public methods provided by component patch-operator.  | 
 | 3 | + */  | 
 | 4 | + | 
 | 5 | +local kap = import 'lib/kapitan.libjsonnet';  | 
 | 6 | +local kube = import 'lib/kube.libjsonnet';  | 
 | 7 | +local kyverno = import 'lib/kyverno.libsonnet';  | 
 | 8 | + | 
 | 9 | +local inv = kap.inventory();  | 
 | 10 | +local kyverno_params = inv.parameters.kyverno;  | 
 | 11 | +local namespace = kyverno_params.namespace;  | 
 | 12 | +local instance = inv.parameters._instance;  | 
 | 13 | + | 
 | 14 | +local apiVersion = 'redhatcop.redhat.io/v1alpha1';  | 
 | 15 | + | 
 | 16 | +local render_patch(patch, _, patch_id='patch1') =  | 
 | 17 | +  { [patch_id]: patch };  | 
 | 18 | + | 
 | 19 | + | 
 | 20 | +local targetData(obj) =  | 
 | 21 | +  local apigrp = std.split(obj.apiVersion, '/')[0];  | 
 | 22 | +  {  | 
 | 23 | +    apiVersion: obj.apiVersion,  | 
 | 24 | +    apigroup:: if apigrp == 'v1' then '' else apigrp,  | 
 | 25 | +    kind: obj.kind,  | 
 | 26 | +    name: obj.metadata.name,  | 
 | 27 | +    namespace: if std.objectHas(obj.metadata, 'namespace') then obj.metadata.namespace,  | 
 | 28 | +  };  | 
 | 29 | + | 
 | 30 | +local patchName(targetObj) =  | 
 | 31 | +  local target = targetData(targetObj);  | 
 | 32 | + | 
 | 33 | +  // Some objects like ClusterRoleBinding can contain colons.  | 
 | 34 | +  local name = std.strReplace(target.name, ':', '-');  | 
 | 35 | +  local unhashed = '%s-%s-%s-%s-%s' % [ instance, target.kind, target.apigroup, target.namespace, name ];  | 
 | 36 | +  // Take 15 characters of the md5 hash, to leave room for a human-readable  | 
 | 37 | +  // prefix.  | 
 | 38 | +  local hashed = std.substr(std.md5(unhashed), 0, 15);  | 
 | 39 | + | 
 | 40 | +  local prefix =  | 
 | 41 | +    local p =  | 
 | 42 | +      if target.namespace != null then  | 
 | 43 | +        // for namespaced objects, use `<ns>-<name>` as the prefix  | 
 | 44 | +        '%s-%s' % [ std.asciiLower(target.namespace), name ]  | 
 | 45 | +      else  | 
 | 46 | +        // for cluster-scoped objects, use `<kind>-<name>` as the prefix  | 
 | 47 | +        // We could also add `<apigroup>` in the prefix, but we don't  | 
 | 48 | +        // need to do this, since the apigroup is part of the hashed string.  | 
 | 49 | +        '%s-%s' % [ std.asciiLower(target.kind), name ];  | 
 | 50 | +    // Trim the prefix if it's too long, make sure the kind/namespace part of  | 
 | 51 | +    // the prefix remains.  | 
 | 52 | +    if std.length(p) > 31 then  | 
 | 53 | +      std.substr(p, 0, 31)  | 
 | 54 | +    else  | 
 | 55 | +      p;  | 
 | 56 | + | 
 | 57 | +  local n = '%s-%s' % [ prefix, hashed ];  | 
 | 58 | + | 
 | 59 | +  // We generate names with a max length of 47, so there's a few characters  | 
 | 60 | +  // left for adding `manager` in `clusterRoleName()` and `saname`.  | 
 | 61 | +  assert  | 
 | 62 | +    std.length(n) <= 47 :  | 
 | 63 | +    "name generated by rl_obj_name() is longer than 47 characters, this shouldn't happen";  | 
 | 64 | +  n;  | 
 | 65 | + | 
 | 66 | +local Patch(targetobj, patchTemplate, patchStrategy='application/strategic-merge-patch+json') =  | 
 | 67 | +  local name = patchName(targetobj);  | 
 | 68 | +  [  | 
 | 69 | +    kyverno.ClusterPolicy(name) {  | 
 | 70 | +      spec: {  | 
 | 71 | +        rules: [ {  | 
 | 72 | +          name: name,  | 
 | 73 | +          match: {  | 
 | 74 | +            all: [ {  | 
 | 75 | +              resources: {  | 
 | 76 | +                kinds: [ '%s/%s' % [ targetobj.apiVersion, targetobj.kind ] ],  | 
 | 77 | +                [if std.objectHas(targetobj.metadata, 'namespace') && targetobj.metadata.namespace != null then 'namespaces']: [ targetobj.metadata.namespace ],  | 
 | 78 | +                names: [ targetobj.metadata.name ],  | 
 | 79 | +              },  | 
 | 80 | +            } ],  | 
 | 81 | +          },  | 
 | 82 | +          mutate: {  | 
 | 83 | +            patchStrategicMerge: patchTemplate,  | 
 | 84 | +          },  | 
 | 85 | +        } ],  | 
 | 86 | +      },  | 
 | 87 | +    },  | 
 | 88 | +  ];  | 
 | 89 | + | 
 | 90 | +local Resource(obj) =  | 
 | 91 | +  error "kyverno doesn't support kind `Resource`, please manage full resources directly in your component";  | 
 | 92 | + | 
 | 93 | +{  | 
 | 94 | +  apiVersion: apiVersion,  | 
 | 95 | +  Resource: Resource,  | 
 | 96 | +  Patch: Patch,  | 
 | 97 | +  renderPatch: render_patch,  | 
 | 98 | +}  | 
0 commit comments