bitnami / kube-libsonnet

Bitnami's jsonnet library for building Kubernetes manifests
https://bitnami.com
Apache License 2.0
172 stars 49 forks source link

Env reference is order dependent - {better title here} #72

Open tehho opened 2 years ago

tehho commented 2 years ago

Hi. Great repo! Many thanks.

We noticed that using $() in env does not work 100% since this is order dependent, see link here.

Our solution atm is to prefix A_ on data variables. Any tips on how to add/sort dependent variables?

jjo commented 2 years ago

You're totally right, it's not supported at all by kube-libsonnet library.

That said, jsonnet gives you the possibility to override "just" that part (the env_{} -> env[] mapping), copying below an implementation that may help here:

(import 'vendor/github.com/bitnami-labs/kube-libsonnet/kube.libsonnet') { // Override env (map) -> env (array) generation with a orderedEnvList() implementation // that uses '/NUM' env name prefix to build an ordered env[] array. // Example usage: // // kube.Container("foo") { // env:: { // 'ZZZ/1': 'someval', // 'FOO/2': 'refer_to-$(ZZZ)', // 'BAR': 'referto-$(FOO)', // } // Container(name):: super.Container(name) { local this = self, envListWithOrder(map):: [ local order = std.split(x, '/'); if std.type(map[x]) == 'object' then { name: order[0], valueFrom: map[x], norder: if std.length(order > 1) then std.parseInt(order[1]) else 999, } else { order:: std.split(x, '/'), name: order[0], // Let null value stay as such (vs string-ified) value: if map[x] == null then null else std.toString(map[x]), norder: if std.length(order) > 1 then std.parseInt(order[1]) else 999, } for x in std.objectFields(map) ], orderedEnvList(map):: std.foldl( function(l, e) l + [e { norder:: null }], std.sort( this.envListWithOrder(map), function(x) x.norder ), [] ), env: self.orderedEnvList(self.env), }, }


* `mykube_test.jsonnet` (example usage):

// mykube_test.jsonnet

local kube = import 'mykube.libsonnet'; kube.Container('foo') { image: 'foo', env_:: { 'ZZZ/1': 'someval', 'FOO/2': 'refer_to-$(ZZZ)', BAR: 'refer_to-$(FOO)', }, }


* sample run:

$ jsonnet mykube_test.jsonnet { "args": [ ], "env": [ { "name": "ZZZ", "value": "someval" }, { "name": "FOO", "value": "refer_to-$(ZZZ)" }, { "name": "BAR", "value": "refer_to-$(FOO)" } ], "image": "foo", "imagePullPolicy": "IfNotPresent", "name": "foo", "ports": [ ], "stdin": false, "tty": false, "volumeMounts": [ ] }



You could then use `local kube = import "mykube.libsonnet";` instead of importing upstream, which will also give you another tweaking place should you wanted/needed to further change it.
tehho commented 2 years ago

Thank you very much!

We already have our own abstract layer above kube.libsonnet, will be adding this snippet to our template.

Container(p):: kube.Container(p.name) + {
  envList(map):: 
      std.sort( std.objectValues( std.mapWithKey(
            function(key, value) 
              local order = std.split(key, '/');
              { name: order[0], order:: if std.length(order) > 1 then std.parseInt(order[1]) else 0, } + 
              if std.isObject(value) then { valueFrom: value } else { value: value }, 
            map)), 
        function(x) x.order)
}
jjo commented 2 years ago

Thank you very much!

We already have our own abstract layer above kube.libsonnet, will be adding this snippet to our template.

Container(p):: kube.Container(p.name) + {
  envList(map):: 
      std.sort( std.objectValues( std.mapWithKey(
            function(key, value) 
              local order = std.split(key, '/');
              { name: order[0], order:: if std.length(order) > 1 then std.parseInt(order[1]) else 0, } + 
              if std.isObject(value) then { valueFrom: value } else { value: value }, 
            map)), 
        function(x) x.order)
}

Great!, thanks for optimizing that 1st implementation ;)