Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

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

Open
tehho opened this issue Jan 28, 2022 · 3 comments
Open

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

tehho opened this issue Jan 28, 2022 · 3 comments

Comments

@tehho
Copy link

tehho commented Jan 28, 2022

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
Copy link
Contributor

jjo commented Jan 28, 2022

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:

  • mykube.libsonnet (overloaded kube.libsonnet library):
// mykube.libsonnet

(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': 'refer_to-$(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
Copy link
Author

tehho commented Jan 28, 2022

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
Copy link
Contributor

jjo commented Jan 28, 2022

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 ;)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants