From 83c8cf09e614868bd870af73ac506d8b7945b7e3 Mon Sep 17 00:00:00 2001 From: Jeroen Op 't Eynde Date: Tue, 1 Jun 2021 10:22:08 +0200 Subject: [PATCH] feat: s/ksonnet-lib/k8s-alpha (#563) * feat: s/ksonnet-lib/k8s-alpha * fix(example): remove jb installed vendor/ * fix(example): update ksonnet-util * docs: fix import references * apply suggestions from code review Co-authored-by: malcolmholmes <42545407+malcolmholmes@users.noreply.github.com> * fix: update arg description * docs: don't stack libs on root scope * --k8s= Co-authored-by: malcolmholmes <42545407+malcolmholmes@users.noreply.github.com> --- cmd/tk/init.go | 31 +++-- docs/docs/directory-structure.md | 15 +-- docs/docs/known-issues.md | 17 ++- docs/docs/tutorial/environments.mdx | 22 ++-- docs/docs/tutorial/k-lib.mdx | 109 ++++++++++-------- .../prom-grafana/dev/main.jsonnet | 3 +- .../prom-grafana/patched/main.jsonnet | 15 ++- examples/prom-grafana/jsonnetfile.json | 6 +- examples/prom-grafana/jsonnetfile.lock.json | 14 +-- examples/prom-grafana/lib/k.libsonnet | 2 +- .../lib/prom-grafana/prom-grafana.libsonnet | 31 ++--- 11 files changed, 147 insertions(+), 118 deletions(-) diff --git a/cmd/tk/init.go b/cmd/tk/init.go index 5c21a9a3e..09b1b854e 100644 --- a/cmd/tk/init.go +++ b/cmd/tk/init.go @@ -7,12 +7,15 @@ import ( "log" "os" "os/exec" + "strconv" "github.com/go-clix/cli" "github.com/grafana/tanka/pkg/spec/v1alpha1" ) +const defaultK8sVersion = "1.20" + // initCmd creates a new application func initCmd() *cli.Command { cmd := &cli.Command{ @@ -22,7 +25,7 @@ func initCmd() *cli.Command { } force := cmd.Flags().BoolP("force", "f", false, "ignore the working directory not being empty") - installK8sLibFlag := cmd.Flags().Bool("k8s", true, "set to false to skip installation of k.libsonnet") + installK8s := cmd.Flags().String("k8s", defaultK8sVersion, "choose the version of k8s-alpha, set to false to skip") inline := cmd.Flags().BoolP("inline", "i", false, "create an inline environment") cmd.Run = func(cmd *cli.Command, args []string) error { @@ -53,15 +56,29 @@ func initCmd() *cli.Command { return err } - if *installK8sLibFlag { - if err := installK8sLib(); err != nil { + version := *installK8s + doInstall, err := strconv.ParseBool(*installK8s) + if doInstall && err == nil { + // --k8s=true, fallback to default version + version = defaultK8sVersion + } else { + // --k8s= + doInstall = true + } + + if doInstall { + if err := installK8sLib(version); err != nil { // This is not fatal, as most of Tanka will work anyways log.Println("Installing k.libsonnet:", err) failed = true } } - fmt.Println("Directory structure set up! Remember to configure the API endpoint:\n`tk env set environments/default --server=https://127.0.0.1:6443`") + if *inline { + fmt.Println("Directory structure set up! Remember to configure the API endpoint in environments/default/main.jsonnet") + } else { + fmt.Println("Directory structure set up! Remember to configure the API endpoint:\n`tk env set environments/default --server=https://127.0.0.1:6443`") + } if failed { log.Println("Errors occured while initializing the project. Check the above logs for details.") } @@ -71,7 +88,7 @@ func initCmd() *cli.Command { return cmd } -func installK8sLib() error { +func installK8sLib(version string) error { jbBinary := "jb" if env := os.Getenv("TANKA_JB_PATH"); env != "" { jbBinary = env @@ -82,11 +99,11 @@ func installK8sLib() error { } var initialPackages = []string{ - "github.com/ksonnet/ksonnet-lib/ksonnet.beta.4", + "github.com/jsonnet-libs/k8s-alpha/" + version, "github.com/grafana/jsonnet-libs/ksonnet-util", } - if err := writeNewFile("lib/k.libsonnet", "import 'github.com/ksonnet/ksonnet-lib/ksonnet.beta.4/k.libsonnet'\n"); err != nil { + if err := writeNewFile("lib/k.libsonnet", "import 'github.com/jsonnet-libs/k8s-alpha/"+version+"/main.libsonnet'\n"); err != nil { return err } diff --git a/docs/docs/directory-structure.md b/docs/docs/directory-structure.md index 405bc6773..842993e5c 100644 --- a/docs/docs/directory-structure.md +++ b/docs/docs/directory-structure.md @@ -17,19 +17,20 @@ Tanka uses the following directories and special files: ├── jsonnetfile.json # direct dependencies ├── jsonnetfile.lock.json # all dependencies with exact versions ├── lib # libraries for this project only -│   └── k.libsonnet # alias file for vendor/github.com/ksonnet/ksonnet-lib/ksonnet.beta.4/k.libsonnet +│   └── k.libsonnet # alias file for vendor/github.com/jsonnet-libs/k8s-alpha/1.21/main.libsonnet └── vendor # external libraries installed using jb ├── github.com │   ├── grafana │   │   └── jsonnet-libs │   │   └── ksonnet-util # Grafana Labs' usability extensions to k.libsonnet + │   │   ├── ... │   │   └── kausal.libsonnet - │   └── ksonnet - │   └── ksonnet-lib - │   └── ksonnet.beta.4 # kubernetes library - │   ├── k8s.libsonnet - │   └── k.libsonnet - ├── ksonnet.beta.4 -> github.com/ksonnet/ksonnet-lib/ksonnet.beta.4 + │   └── jsonnet-libs + │   └── k8s-alpha + │   └── 1.21 # kubernetes library + │   ├── ... + │   └── main.libsonnet + ├── 1.21 -> github.com/jsonnet-libs/k8s-alpha/1.21 └── ksonnet-util -> github.com/grafana/jsonnet-libs/ksonnet-util ``` diff --git a/docs/docs/known-issues.md b/docs/docs/known-issues.md index efb6a91da..71c71a482 100644 --- a/docs/docs/known-issues.md +++ b/docs/docs/known-issues.md @@ -11,29 +11,26 @@ Below is a list of common errors and how to address them. When migrating from `ksonnet`, this error might occur, because Tanka does not provide the global `__ksonnet` variable, nor does it strictly have the concept -of components. +of components. You will need to use the plain Jsonnet `import` feature instead. Note that this requires your code to be inside of one of the [import paths](directory-structure/#import-paths). ### Evaluating jsonnet: RUNTIME ERROR: couldn't open import "k.libsonnet": no match locally or in the Jsonnet library paths -This error can occur when the `ksonnet` kubernetes libraries are missing in the -import paths. While `ksonnet` used to magically include them, Tanka follows a +This error can occur when the `k8s-alpha` kubernetes libraries are missing in the +import paths. While `k8s-alpha` used to magically include them, Tanka follows a more explicit approach and requires you to install them using `jb`: ```bash -$ jb install github.com/ksonnet/ksonnet-lib/ksonnet.beta.4 -$ echo "import 'github.com/ksonnet/ksonnet-lib/ksonnet.beta.4/k.libsonnet'" > lib/k.libsonnet +$ jb install github.com/jsonnet-libs/k8s-alpha/1.21 +$ echo "import 'github.com/jsonnet-libs/k8s-alpha/1.21/main.libsonnet'" > lib/k.libsonnet ``` This does 2 things: -1) It installs the ksonnet library (in `vendor/github.com/ksonnet/ksonnet-lib/ksonnet.beta.4`). -If you need a specific version, take a look at -https://github.com/ksonnet/ksonnet-lib. When a pre-compiled version is -available, install it using `jb`, otherwise compile it yourself and place it -under `lib/`. +1) It installs the `k8s-alpha` library (in `vendor/github.com/jsonnet-libs/k8s-alpha/1.21/`). +You can replace the `1.21` matching the Kubernetes version you want to run against. 2) It makes an alias for libraries importing `k.libsonnet` directly. See https://tanka.dev/tutorial/k-lib#aliasing for the alias rationale. diff --git a/docs/docs/tutorial/environments.mdx b/docs/docs/tutorial/environments.mdx index 8ad613bd2..0efaf7f40 100644 --- a/docs/docs/tutorial/environments.mdx +++ b/docs/docs/tutorial/environments.mdx @@ -79,13 +79,14 @@ For documentation purposes it is handy to have a separate file for parameters an ##### prom-grafana.libsonnet ```jsonnet -(import "ksonnet-util/kausal.libsonnet") + +local k = import "ksonnet-util/kausal.libsonnet"; + (import "./config.libsonnet") + { - local deployment = $.apps.v1.deployment, - local container = $.core.v1.container, - local port = $.core.v1.containerPort, - local service = $.core.v1.service, + local deployment = k.apps.v1.deployment, + local container = k.core.v1.container, + local port = k.core.v1.containerPort, + local service = k.core.v1.service, // alias our params, too long to type every time local c = $._config.promgrafana, @@ -99,7 +100,7 @@ For documentation purposes it is handy to have a separate file for parameters an + container.withPorts([port.new("api", c.prometheus.port)]), ], ), - service: $.util.serviceFor(self.deployment), + service: k.util.serviceFor(self.deployment), }, grafana: { @@ -110,7 +111,9 @@ For documentation purposes it is handy to have a separate file for parameters an + container.withPorts([port.new("ui", c.grafana.port)]), ], ), - service: $.util.serviceFor(self.deployment) + service.mixin.spec.withType("NodePort"), + service: + k.util.serviceFor(self.deployment) + + service.mixin.spec.withType("NodePort"), }, } } @@ -131,8 +134,7 @@ All that's left now is importing the library and configuring it. For `dev`, the ```jsonnet // environments/prom-grafana/dev -(import "ksonnet-util/kausal.libsonnet") + -(import "prom-grafana/prom-grafana.libsonnet") +import "prom-grafana/prom-grafana.libsonnet" ``` For `prod` however, it is a bad idea to rely on `latest` for the images .. let's @@ -140,7 +142,6 @@ add some proper tags: ```jsonnet // environments/prom-grafana/prod -(import "ksonnet-util/kausal.libsonnet") + (import "prom-grafana/prom-grafana.libsonnet") + { // again, we only want to patch, not replace, thus +:: @@ -164,7 +165,6 @@ Here comes the already familiar `+:` (or `+::`) syntax into play. It allows to **partially** override values of an object. Let's say we wanted to add some labels to the Prometheus `Deployment`, but our `_config` params don't allow us to. We can still do this in our `main.jsonnet`: ```jsonnet -(import "ksonnet-util/kausal.libsonnet") + (import "prom-grafana/prom-grafana.libsonnet") + { promgrafana+: { diff --git a/docs/docs/tutorial/k-lib.mdx b/docs/docs/tutorial/k-lib.mdx index ad6a52caa..2a45014f2 100644 --- a/docs/docs/tutorial/k-lib.mdx +++ b/docs/docs/tutorial/k-lib.mdx @@ -15,39 +15,41 @@ Writing and maintaining such a library could be a full-time job on it's own. Luckily, it is possible to generate such a library from the Kubernetes OpenAPI specification! Even better, it has already been done for you. -## k.libsonnet +## k8s-alpha -The library is called `k.libsonnet` (sometimes also `ksonnet-lib`), currently -available at https://github.com/ksonnet/ksonnet-lib. +The library is called `k8s-alpha` (replacing the discontinued `ksonnet-lib`), +currently available at https://github.com/jsonnet-libs/k8s-alpha. -> **Note**: Being part of the discontinued `ksonnet` project, the library is not -> really maintained at the moment. However, Grafana Labs will soon pick this up and -> take care of it :D -> Nevertheless, it has already proven to be stable enough for our own production -> setup to rely on it. +> **Note**: The `ksonnet` project has been abandoned, the library is not maintained +> anymore. However, the community backed by Grafana Labs has picked up on this with +> the `k8s-alpha` library. -However while using it internally we have discovered that the exposed API has -several annoyances. To address them, we developed another library that builds on -top of the generated one but improves the developer experience: +As `k8s-alpha` has broken compatibility in a few places with `ksonnet-lib` (for good +reason), we have instrumented the widely used `ksonnet-util` library with a +compatibility layer to improve the developer and user experience: https://github.com/grafana/jsonnet-libs/tree/master/ksonnet-util If you do not have any strong reasons against it, just adopt the wrapper as -well, it will ease your work. Ultimately, we hope to integrate our enhancements -in the original library as well. +well, it will ease your work. Many of the original `ksonnet-util` enhancements +have already made their way into `k8s-alpha`. + +The docs for `k8s-alpha` library can be found here: +https://jsonnet-libs.github.io/k8s-alpha/ ## Installation -Like every other external library, `ksonnet-lib` can be installed using -`jsonnet-bundler`. +Like every other external library, `k8s-alpha` can be installed using +`jsonnet-bundler`. However, Tanka already **did this for you** during [project creation (`tk init`)](/tutorial/jsonnet#creating-a-new-project): ```bash $ tk init - └─ jb install github.com/ksonnet/ksonnet-lib/ksonnet.beta.4 github.com/grafana/jsonnet-libs/ksonnet-util + └─ jb install github.com/jsonnet-libs/k8s-alpha/1.21 github.com/grafana/jsonnet-libs/ksonnet-util + ``` -This created the following files in `/vendor`: +This created the following structure in `/vendor`: ```bash vendor @@ -55,13 +57,14 @@ vendor │   ├── grafana │   │   └── jsonnet-libs │   │   └── ksonnet-util +│   │   ├── ... │   │   └── kausal.libsonnet # Grafana's wrapper -│   └── ksonnet -│   └── ksonnet-lib -│   └── ksonnet.beta.4 -│   ├── k8s.libsonnet # literally the entire API as a library. Very huge file -│   └── k.libsonnet # human friendly wrapper (this is what we use in our code) -├── ksonnet.beta.4 -> github.com/ksonnet/ksonnet-lib/ksonnet.beta.4 +│   └── jsonnet-libs +│   └── k8s-alpha +│   └── 1.21 +│   ├── ... +│   └── main.libsonnet # k8s-alpha entrypoint +├── 1.21 -> github.com/jsonnet-libs/k8s-alpha/1.21 └── ksonnet-util -> github.com/grafana/jsonnet-libs/ksonnet-util ``` @@ -70,44 +73,49 @@ vendor > for more information. #### Aliasing -Because of how `jb` works, the library can be imported as `github.com/ksonnet/ksonnet-lib/ksonnet.beta.4/k.libsonnet`. -Most external libraries (including our wrapper) expect it as a simple `k.libsonnet` (without +Because of how `jb` works, the library can be imported as +`github.com/jsonnet-libs/k8s-alpha/1.21/main.libsonnet`. Most external +libraries (including our wrapper) expect it as a simple `k.libsonnet` (without the package prefix). -To support both, Tanka automatically created an alias file for you: `/lib/k.libsonnet` that just imports actual library, exposing it under this alternative name as well. +To support both, Tanka automatically created an alias file for you: +`/lib/k.libsonnet` that just imports the actual library, exposing it under this +alternative name as well. -> **More information**: -> This works, because `import` behaves like copy-pasting. So -> the contents of `ksonnet.beta.4` are "copied" into our new file, making them -> behave exactly the same. +> **More information**: +> This works, because `import` behaves like copy-pasting. So the contents of +> `k8s-alpha/1.21` are "copied" into our new file, making them behave exactly the +> same. ## Using it First we need to import it in `main.jsonnet`: ```diff -- (import "kubernetes.libsonnet") + -+ (import "github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet") + - (import "grafana.jsonnet") + - (import "prometheus.jsonnet") + +- local k = import "kubernetes.libsonnet"; ++ local k = import "github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet"; + local grafana = import "grafana.jsonnet"; + local prometheus = import "prometheus.jsonnet"; { /* ... */ } ``` -> **Note**: `kausal.libsonnet` imports literal `k.libsonnet`, so -> [aliasing](#aliasing) is a must here. This works, because `/lib` and `/vendor` -> are automatically searched for libraries, and `k.libsonnet` can be found in -> `/lib` due to aforementioned aliasing. +> **Note**: `ksonnet-util` imports literal `k.libsonnet`, so [aliasing](#aliasing) is +> a must here. This works, because `/lib` and `/vendor` are automatically searched +> for libraries, and `k.libsonnet` can be found in `/lib` due to aforementioned +> aliasing. Now that we have installed the correct version, let's use it in `/environments/default/grafana.jsonnet` instead of our own helper: ```jsonnet +local k = import "github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet"; + { // use locals to extract the parts we need - local deploy = $.apps.v1.deployment, - local container = $.core.v1.container, - local port = $.core.v1.containerPort, - local service = $.core.v1.service, + local deploy = k.apps.v1.deployment, + local container = k.core.v1.container, + local port = k.core.v1.containerPort, + local service = k.core.v1.service, // defining the objects: grafana: { // deployment constructor: name, replicas, containers @@ -134,7 +142,8 @@ merge it all back into a single file (`main.jsonnet`) and take a look at the whole picture: ```jsonnet -(import "ksonnet-util/kausal.libsonnet") + +local k = import "github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet"; + { _config:: { grafana: { @@ -147,10 +156,10 @@ whole picture: } }, - local deployment = $.apps.v1.deployment, - local container = $.core.v1.container, - local port = $.core.v1.containerPort, - local service = $.core.v1.service, + local deployment = k.apps.v1.deployment, + local container = k.core.v1.container, + local port = k.core.v1.containerPort, + local service = k.core.v1.service, prometheus: { deployment: deployment.new( @@ -160,7 +169,7 @@ whole picture: + container.withPorts([port.new("api", $._config.prometheus.port)]), ], ), - service: $.util.serviceFor(self.deployment), + service: k.util.serviceFor(self.deployment), }, grafana: { deployment: deployment.new( @@ -170,7 +179,9 @@ whole picture: + container.withPorts([port.new("ui", $._config.grafana.port)]), ], ), - service: $.util.serviceFor(self.deployment) + service.mixin.spec.withType("NodePort"), + service: + k.util.serviceFor(self.deployment) + + service.mixin.spec.withType("NodePort"), }, } ``` diff --git a/examples/prom-grafana/environments/prom-grafana/dev/main.jsonnet b/examples/prom-grafana/environments/prom-grafana/dev/main.jsonnet index 79ae694b9..b6d0f43dc 100644 --- a/examples/prom-grafana/environments/prom-grafana/dev/main.jsonnet +++ b/examples/prom-grafana/environments/prom-grafana/dev/main.jsonnet @@ -1,2 +1 @@ -(import "ksonnet-util/kausal.libsonnet") + -(import "prom-grafana/prom-grafana.libsonnet") +import 'prom-grafana/prom-grafana.libsonnet' diff --git a/examples/prom-grafana/environments/prom-grafana/patched/main.jsonnet b/examples/prom-grafana/environments/prom-grafana/patched/main.jsonnet index cb5f2aefe..34f93e241 100644 --- a/examples/prom-grafana/environments/prom-grafana/patched/main.jsonnet +++ b/examples/prom-grafana/environments/prom-grafana/patched/main.jsonnet @@ -1,15 +1,14 @@ -(import "ksonnet-util/kausal.libsonnet") + -(import "prom-grafana/prom-grafana.libsonnet") + +(import 'prom-grafana/prom-grafana.libsonnet') + { promgrafana+: { prometheus+: { deployment+: { metadata+: { labels+: { - foo: "bar" - } - } - } - } - } + foo: 'bar', + }, + }, + }, + }, + }, } diff --git a/examples/prom-grafana/jsonnetfile.json b/examples/prom-grafana/jsonnetfile.json index 0db30b864..bb91cf732 100644 --- a/examples/prom-grafana/jsonnetfile.json +++ b/examples/prom-grafana/jsonnetfile.json @@ -4,7 +4,7 @@ { "source": { "git": { - "remote": "https://github.com/grafana/jsonnet-libs", + "remote": "https://github.com/grafana/jsonnet-libs.git", "subdir": "ksonnet-util" } }, @@ -13,8 +13,8 @@ { "source": { "git": { - "remote": "https://github.com/ksonnet/ksonnet-lib", - "subdir": "ksonnet.beta.4" + "remote": "https://github.com/jsonnet-libs/k8s-alpha.git", + "subdir": "1.21" } }, "version": "master" diff --git a/examples/prom-grafana/jsonnetfile.lock.json b/examples/prom-grafana/jsonnetfile.lock.json index 22f794376..e34896d4e 100644 --- a/examples/prom-grafana/jsonnetfile.lock.json +++ b/examples/prom-grafana/jsonnetfile.lock.json @@ -4,22 +4,22 @@ { "source": { "git": { - "remote": "https://github.com/grafana/jsonnet-libs", + "remote": "https://github.com/grafana/jsonnet-libs.git", "subdir": "ksonnet-util" } }, - "version": "b7d0399a4c8b9fe3ee381b3dc8752e7c778b3f1a", - "sum": "+NXJP8shQKw88Rs/X1firb7V2NzRSUvujBsMkKGh3e4=" + "version": "84686ea681cd35c15f5ecd66c0d1eee3cc4a0981", + "sum": "jelt5QWEerVPLHHZN6Ga0B4OQ/MLBl+OLj3kVzTET+Y=" }, { "source": { "git": { - "remote": "https://github.com/ksonnet/ksonnet-lib", - "subdir": "ksonnet.beta.4" + "remote": "https://github.com/jsonnet-libs/k8s-alpha.git", + "subdir": "1.21" } }, - "version": "0d2f82676817bbf9e4acf6495b2090205f323b9f", - "sum": "ur22hPQq0JAPBxm8hNMcwjumj4MkozDwOKiGZvVMYh4=" + "version": "b3200f1ead8ebb74932673a41748194950564686", + "sum": "QVUm2JrNnhjorXlfsNBDV0uvPgSWUolMYG9UzWLo1qQ=" } ], "legacyImports": false diff --git a/examples/prom-grafana/lib/k.libsonnet b/examples/prom-grafana/lib/k.libsonnet index f503c9b9d..4102b7230 100644 --- a/examples/prom-grafana/lib/k.libsonnet +++ b/examples/prom-grafana/lib/k.libsonnet @@ -1 +1 @@ -import 'github.com/ksonnet/ksonnet-lib/ksonnet.beta.4/k.libsonnet' +import 'github.com/jsonnet-libs/k8s-alpha/1.21/main.libsonnet' diff --git a/examples/prom-grafana/lib/prom-grafana/prom-grafana.libsonnet b/examples/prom-grafana/lib/prom-grafana/prom-grafana.libsonnet index 07a7ee324..4cc655cff 100644 --- a/examples/prom-grafana/lib/prom-grafana/prom-grafana.libsonnet +++ b/examples/prom-grafana/lib/prom-grafana/prom-grafana.libsonnet @@ -1,10 +1,11 @@ -(import "ksonnet-util/kausal.libsonnet") + -(import "./config.libsonnet") + +local k = import 'ksonnet-util/kausal.libsonnet'; + +(import './config.libsonnet') + { - local deployment = $.apps.v1.deployment, - local container = $.core.v1.container, - local port = $.core.v1.containerPort, - local service = $.core.v1.service, + local deployment = k.apps.v1.deployment, + local container = k.core.v1.container, + local port = k.core.v1.containerPort, + local service = k.core.v1.service, // alias our params, too long to type every time local c = $._config.promgrafana, @@ -12,24 +13,28 @@ promgrafana: { prometheus: { deployment: deployment.new( - name=c.prometheus.name, replicas=1, + name=c.prometheus.name, + replicas=1, containers=[ container.new(c.prometheus.name, $._images.promgrafana.prometheus) - + container.withPorts([port.new("api", c.prometheus.port)]), + + container.withPorts([port.new('api', c.prometheus.port)]), ], ), - service: $.util.serviceFor(self.deployment), + service: k.util.serviceFor(self.deployment), }, grafana: { deployment: deployment.new( - name=c.grafana.name, replicas=1, + name=c.grafana.name, + replicas=1, containers=[ container.new(c.grafana.name, $._images.promgrafana.grafana) - + container.withPorts([port.new("ui", c.grafana.port)]), + + container.withPorts([port.new('ui', c.grafana.port)]), ], ), - service: $.util.serviceFor(self.deployment) + service.mixin.spec.withType("NodePort"), + service: + k.util.serviceFor(self.deployment) + + service.mixin.spec.withType('NodePort'), }, - } + }, }