jkcfg / jk

Configuration as Code with ECMAScript
https://jkcfg.github.io
Apache License 2.0
404 stars 30 forks source link

Running JK in Node #342

Closed alexec closed 4 years ago

alexec commented 4 years ago

Is it possible to invoke JK using Node please? That would we could use it with any library we wanted

squaremo commented 4 years ago

Hi Alex, which bit do you want to use with Node? Do you want to, e.g., use @jkcfg/std from a Node.JS script? Or something else.

alexec commented 4 years ago

Maybe I should explain why I'm asking all these questions. I work on Argo CD and Argo Workflows. I'm trying to see if I can use JK to template apps because Helm, Kustomize, and Jsonnet don't do what I need.

I have around 160 apps to template, one for each Kubernetes cluster. These apps are largely homogenic - BUT not quite.

All the clusters are listed in a single YAML file which is generated by combining three other JSON files and a CSV, which is done using a Golang script. The output is

- arn: arn:aws:acm:us-west-2:469802291...
  bu: sbg ;# this business uint
  hostName: ;# the host name of the ingress
  ingress: true
  name: my-cluster.cluster.k8s.local
  server: https://REDACTED.west-2.elb.amazonaws.com
  splunk: https://REDACTED
  type: preprod ;# or prod
  wave: 3 ;# which release wave they go in and therefore which manifests and images they are based

So I have one control-plane app in Argo CD that create one app for each cluster (this is know as "app-of-apps").

So those apps should use one script to generate the YAML.

For Argo CD to support JK in this use case we need to:

Argo CD requires you print the YAML to stdout, not to a file, e.g.:

  print(manifests, {
                format: Format.YAMLStream
            });

An you must invoke jk run main.js not jk generate main.js (aside - I tried path: '/dev/stdout' - it did not seem to work).

The way you parametrize a build in Argo CD is using environment variables. ARGOCD_APP_NAME; is the app name, which is also the cluster name.

So I have a script to generate the control plane:

read("data/cluster-configs.yaml").then(cs => {
    const apps = cs.map(c => {
...
        return m;
    });
    print(apps, {format: Format.YAMLStream});
});

An one to generate each cluster app:

read("data/cluster-configs.yaml").then(cs => {
    const c = cs.find(c => c.name = cluster);
    read("base/wave" + c.wave + "/image-tag.json", {
        format: Format.Raw
    }).then(imageTag => {
        read(
            "src/argo-workflows/base/wave" + c.wave + "/resources/upstream.yaml",
            {format: Format.YAMLStream}
        ).then(upstream => {

I thought I could do this using:

const cluster = process.ENV.ARGOCD_APP_NAME;

But that does not seem to work?

alexec commented 4 years ago

If you have time, it'd be great to Zoom about this.

squaremo commented 4 years ago

Argo CD requires you print the YAML to stdout, not to a file, e.g.:

You can get jk generate to print to stdout with jk generate --stdout. The draft documentation in https://github.com/jkcfg/website/pull/39 (files on that branch) go a little way towards explaining run vs generate and the rest.

The way you parametrize a build in Argo CD is using environment variables. ARGOCD_APP_NAME; is the app name, which is also the cluster name.

There's no access to environment variables from within a script, at present. You will need to wrap jk in a shell script that translates environment variables to parameters passed to jk at invocation, or the equivalent.

"src/argo-workflows/base/wave" + c.wave + "/resources/upstream.yaml"

A slightly neater way to construct strings is

`src/argo-workflows/base/wave${c.wave}/resources/upstream.yaml`

(backticks deliberate)