├── .gitignore ├── README.md ├── csharp ├── README.md ├── genyaml │ ├── Program.cs │ └── genyaml.csproj └── kubectl │ ├── Program.cs │ └── kubectl.csproj ├── go ├── README.md ├── create │ └── main.go └── generate │ └── main.go ├── java ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── io │ └── learnk8s │ └── KubernetesClientCLI.java ├── javascript ├── README.md ├── gen-yaml.js ├── kubectl.js ├── package-lock.json └── package.json └── python ├── README.md ├── create.py └── generate.py /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | 4 | *.env 5 | *.dev 6 | .DS_Store 7 | .vscode/ 8 | bin 9 | obj 10 | .idea/ 11 | target/ 12 | *.iml 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Templating Kubernetes resources with code 2 | 3 | This repository is meant to demonstrate how to create definitions for Kubernetes resources with code. 4 | 5 | You can find examples in the following languages: 6 | 7 | - [Java](java/README.md) 8 | - [Go](go/README.md) 9 | - [Python](python/README.md) 10 | - [Node.js](javascript/README.md) 11 | - [C#](csharp/README.md) 12 | 13 | Feel free to contribute if can translate the examples in other languages. 14 | -------------------------------------------------------------------------------- /csharp/README.md: -------------------------------------------------------------------------------- 1 | # Templating Kubernetes resources with .NET Core 2 | 3 | In this section you will learn how to use Javascript to: 4 | 5 | - create JSON (and YAML) definition for a Kubernetes Pod 6 | - submit a Pod definition to the cluster with code 7 | 8 | Let's get started. 9 | 10 | ## Prerequisites 11 | 12 | Ensure that you have installed .NET Core 3.1. See [documentation](https://dotnet.microsoft.com/download) for installation instructions. 13 | 14 | ## Generating Pod definitions 15 | 16 | You can generate yaml by navigating to `genyaml` project and running it. 17 | 18 | ```shell 19 | cd genyaml 20 | dotnet build 21 | dotnet run 22 | ``` 23 | 24 | The output is a JSON object for the Pod. 25 | 26 | ```json 27 | { 28 | "apiVersion": "v1", 29 | "kind": "Pod", 30 | "metadata": { 31 | "name": "test-pod" 32 | }, 33 | "spec": { 34 | "containers": [ 35 | { 36 | "env": [ 37 | { 38 | "name": "ENV", 39 | "value": "dev" 40 | } 41 | ], 42 | "image": "k8s.gcr.io/busybox", 43 | "name": "test-container" 44 | } 45 | ] 46 | } 47 | } 48 | ``` 49 | 50 | _But isn't Kubernetes accepting only YAML?_ 51 | 52 | YAML is a superset of JSON and any JSON file is also a valid YAML file. 53 | 54 | You can create the Pod in the cluster with the following commands: 55 | 56 | ```shell 57 | dotnet run > pod.yaml 58 | kubectl apply -f pod.yaml 59 | ``` 60 | 61 | ## Creating a custom Kubectl 62 | 63 | Instead of exporting the JSON and feeding it to kubectl, you can send the payload to the cluster directly. 64 | 65 | You can use the [official Kubernetes client library](https://github.com/kubernetes-client/csharp) to send the Pod definition to the cluster. 66 | 67 | Assuming you are connected to a running cluster, you can create the pod by navigating to `kubectl` project and running it. 68 | 69 | ```shell 70 | cd kubectl 71 | dotnet build 72 | dotnet run 73 | ``` 74 | 75 | And you can verify that the Pod was created with: 76 | 77 | ```shell 78 | kubectl get pods 79 | ``` 80 | 81 | ## What's next 82 | 83 | As you can imagine, this is a short demo and you can build more complex objects and use the power of dotnet to compose large objects from smaller ones. -------------------------------------------------------------------------------- /csharp/genyaml/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json; 4 | using k8s.Models; 5 | 6 | namespace genyaml 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | var pod = new V1Pod() 13 | { 14 | ApiVersion = "v1", 15 | Kind = "Pod", 16 | Metadata = new V1ObjectMeta() 17 | { 18 | Name = "test-pod" 19 | }, 20 | Spec = new V1PodSpec() 21 | { 22 | Containers = new List() 23 | { 24 | new V1Container() 25 | { 26 | Name = "test-container", 27 | Image = "nginx", 28 | Env = new List(){ 29 | new V1EnvVar(){ 30 | Name="ENV", Value="dev" 31 | } 32 | } 33 | } 34 | } 35 | } 36 | }; 37 | 38 | var serialiseOptions = new JsonSerializerOptions() 39 | { 40 | WriteIndented = true, 41 | IgnoreNullValues = true, 42 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase, 43 | }; 44 | 45 | Console.WriteLine(JsonSerializer.Serialize(pod, serialiseOptions)); 46 | } 47 | } 48 | } 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /csharp/genyaml/genyaml.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp/kubectl/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json; 4 | using k8s; 5 | using k8s.Models; 6 | 7 | namespace kubectl 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | var k8SClientConfig = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 14 | var client = new Kubernetes(k8SClientConfig); 15 | 16 | var pod = new V1Pod() 17 | { 18 | ApiVersion = "v1", 19 | Kind = "Pod", 20 | Metadata = new V1ObjectMeta() 21 | { 22 | Name = "test-pod" 23 | }, 24 | Spec = new V1PodSpec() 25 | { 26 | Containers = new List() 27 | { 28 | new V1Container() 29 | { 30 | Name = "test-container", 31 | Image = "nginx", 32 | Env = new List(){ 33 | new V1EnvVar(){ 34 | Name="ENV", Value="dev" 35 | } 36 | } 37 | } 38 | } 39 | } 40 | }; 41 | 42 | var result = client.CreateNamespacedPod(pod, "default"); 43 | Console.WriteLine(result); 44 | } 45 | } 46 | } 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /csharp/kubectl/kubectl.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /go/README.md: -------------------------------------------------------------------------------- 1 | # Templating Kubernetes resources with Go 2 | 3 | In this section you will learn how to use Go to: 4 | 5 | - Create a JSON resource definition of a Kubernetes Pod 6 | - Submit the resource definition to the cluster to create the Pod 7 | 8 | For both tasks you will use the official Kubernetes [Go client library](https://github.com/kubernetes/client-go) (client-go). 9 | 10 | Let's get started. 11 | 12 | ## Prerequisites 13 | 14 | Make sure you have the `go` command installed. You can find installation instructions in the [Go documentation](https://golang.org/dl/). 15 | 16 | ## Generating a Pod resource definition 17 | 18 | First, create a new directory for the program that you are going to write: 19 | 20 | ```bash 21 | mkdir generate 22 | cd generate 23 | ``` 24 | 25 | The code for generating a Pod resource definition in JSON looks as follows: 26 | 27 | ```go 28 | package main 29 | 30 | import ( 31 | "fmt" 32 | corev1 "k8s.io/api/core/v1" 33 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 | "k8s.io/apimachinery/pkg/util/json" 35 | ) 36 | 37 | func main() { 38 | pod := createPod("dev") 39 | bytes, err := json.Marshal(pod) 40 | if err != nil { 41 | panic(err) 42 | } 43 | fmt.Println(string(bytes)) 44 | } 45 | 46 | func createPod(environment string) *corev1.Pod { 47 | return &corev1.Pod{ 48 | TypeMeta: metav1.TypeMeta{ 49 | Kind: "Pod", 50 | APIVersion: "v1", 51 | }, 52 | ObjectMeta: metav1.ObjectMeta{ 53 | Name: "test-pod", 54 | }, 55 | Spec: corev1.PodSpec{ 56 | Containers: []corev1.Container{ 57 | { 58 | Name: "test-container", 59 | Image: "nginx", 60 | Env: []corev1.EnvVar{ 61 | { 62 | Name: "ENV", 63 | Value: environment, 64 | }, 65 | }, 66 | }, 67 | }, 68 | }, 69 | } 70 | } 71 | ``` 72 | 73 | Go on and save the above code in a file named `main.go`. 74 | 75 | > The above code uses several packages from the [client-go](https://github.com/kubernetes/client-go) library. You can find the documentation of every Go package by pasting its full import path into the search field on [godoc.org](https://godoc.org/). For example, the documentation of the `k8s.io/api/core/v1` package can be found on [godoc.org/k8s.io/api/core/v1](https://godoc.org/k8s.io/api/core/v1). 76 | 77 | You can then execute your program with: 78 | 79 | ```shell 80 | go run main.go 81 | ``` 82 | 83 | The output is the JSON resource definition of a Pod. 84 | 85 | Note that this JSON has no newlines and indentation, which makes it hard to read. If you want, you can pretty-print the JSON with [`jq`](https://stedolan.github.io/jq/): 86 | 87 | ```shell 88 | $ go run main.go | jq 89 | { 90 | "kind": "Pod", 91 | "apiVersion": "v1", 92 | "metadata": { 93 | "name": "test-pod", 94 | "creationTimestamp": null 95 | }, 96 | "spec": { 97 | "containers": [ 98 | { 99 | "name": "test-container", 100 | "image": "nginx", 101 | "env": [ 102 | { 103 | "name": "ENV", 104 | "value": "dev" 105 | } 106 | ], 107 | "resources": {} 108 | } 109 | ] 110 | }, 111 | "status": {} 112 | } 113 | ``` 114 | 115 | You can save this JSON definition in a file: 116 | 117 | ```shell 118 | go run main.go >pod.json 119 | ``` 120 | 121 | And then you can submit it to the cluster with kubectl as ususal: 122 | 123 | ```shell 124 | kubectl apply -f pod.json 125 | ``` 126 | 127 | You can verify that the Pod has been created correctly with: 128 | 129 | ```shell 130 | kubectl get pods 131 | ``` 132 | 133 | ## Submitting a Pod resource definition to the cluster 134 | 135 | Instead of saving the JSON resource definition to a file and then using kubectl to submit it to the cluster, you can submit the resource definition to the cluster directly in your code. 136 | 137 | First of all, create a new directory for the new program that you are going to write: 138 | 139 | ```shell 140 | cd .. 141 | mkdir create 142 | cd create 143 | ``` 144 | 145 | The code to generate a Pod resource definition _and_ submitting it to the cluster is as follows: 146 | 147 | ```go 148 | package main 149 | 150 | import ( 151 | "fmt" 152 | corev1 "k8s.io/api/core/v1" 153 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 154 | "k8s.io/client-go/kubernetes" 155 | "k8s.io/client-go/tools/clientcmd" 156 | "k8s.io/client-go/util/homedir" 157 | "path/filepath" 158 | ) 159 | 160 | func main() { 161 | kubeconfig, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config")) 162 | if err != nil { 163 | panic(err) 164 | } 165 | clientset, err := kubernetes.NewForConfig(kubeconfig) 166 | if err != nil { 167 | panic(err) 168 | } 169 | pod := createPod("dev") 170 | _, err = clientset.CoreV1().Pods("default").Create(pod) 171 | if err != nil { 172 | panic(err) 173 | } 174 | fmt.Printf("pod/%s created\n", pod.Name) 175 | } 176 | 177 | func createPod(environment string) *corev1.Pod { 178 | // ...same as in the previous program 179 | } 180 | ``` 181 | 182 | Go on and save the above code in a file named `main.go`. 183 | 184 | You can then run the program with: 185 | 186 | ```shell 187 | go run main.go 188 | ``` 189 | 190 | The ouptut should be `pod/test-pod created`. 191 | 192 | You can verify that the Pod has indeed been created with: 193 | 194 | ```shell 195 | kubectl get pods 196 | ``` 197 | 198 | ## What's next 199 | 200 | As you can imagine, this was just a short demo. You can compose any type of Kubernetes object with the Go client library and you can create, read, update, and delete these objects in your Kubernetes cluster. 201 | 202 | Feel free to check out the [example programs](https://github.com/kubernetes/client-go/tree/master/examples) of the Go client library. 203 | -------------------------------------------------------------------------------- /go/create/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | corev1 "k8s.io/api/core/v1" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | "k8s.io/client-go/kubernetes" 8 | "k8s.io/client-go/tools/clientcmd" 9 | "k8s.io/client-go/util/homedir" 10 | "path/filepath" 11 | ) 12 | 13 | func main() { 14 | kubeconfig, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config")) 15 | if err != nil { 16 | panic(err) 17 | } 18 | clientset, err := kubernetes.NewForConfig(kubeconfig) 19 | if err != nil { 20 | panic(err) 21 | } 22 | pod := createPod("dev") 23 | _, err = clientset.CoreV1().Pods("default").Create(pod) 24 | if err != nil { 25 | panic(err) 26 | } 27 | fmt.Printf("pod/%s created\n", pod.Name) 28 | } 29 | 30 | func createPod(environment string) *corev1.Pod { 31 | return &corev1.Pod{ 32 | TypeMeta: metav1.TypeMeta{ 33 | Kind: "Pod", 34 | APIVersion: "v1", 35 | }, 36 | ObjectMeta: metav1.ObjectMeta{ 37 | Name: "test-pod", 38 | }, 39 | Spec: corev1.PodSpec{ 40 | Containers: []corev1.Container{ 41 | { 42 | Name: "test-container", 43 | Image: "nginx", 44 | Env: []corev1.EnvVar{ 45 | { 46 | Name: "ENV", 47 | Value: environment, 48 | }, 49 | }, 50 | }, 51 | }, 52 | }, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /go/generate/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | corev1 "k8s.io/api/core/v1" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | "k8s.io/apimachinery/pkg/util/json" 8 | ) 9 | 10 | func main() { 11 | pod := createPod("dev") 12 | bytes, err := json.Marshal(pod) 13 | if err != nil { 14 | panic(err) 15 | } 16 | fmt.Println(string(bytes)) 17 | } 18 | 19 | func createPod(environment string) *corev1.Pod { 20 | return &corev1.Pod{ 21 | TypeMeta: metav1.TypeMeta{ 22 | Kind: "Pod", 23 | APIVersion: "v1", 24 | }, 25 | ObjectMeta: metav1.ObjectMeta{ 26 | Name: "test-pod", 27 | }, 28 | Spec: corev1.PodSpec{ 29 | Containers: []corev1.Container{ 30 | { 31 | Name: "test-container", 32 | Image: "nginx", 33 | Env: []corev1.EnvVar{ 34 | { 35 | Name: "ENV", 36 | Value: environment, 37 | }, 38 | }, 39 | }, 40 | }, 41 | }, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /java/README.md: -------------------------------------------------------------------------------- 1 | # Templating Kubernetes resources with Java 2 | 3 | In this section you will learn how to use Java and Maven to: 4 | 5 | - create JSON (and YAML) definition for a Kubernetes Pod 6 | - submit a Pod definition to the cluster with code 7 | 8 | Let's get started. 9 | 10 | ## Prerequisites 11 | 12 | To your Maven application you need to add the `io.fabric8:kubernetes-client` dependency inside the `pom.xml` file 13 | 14 | ```xml 15 | 16 | io.fabric8 17 | kubernetes-client 18 | 4.6.4 19 | 20 | ``` 21 | 22 | ## Generating Pod definitions 23 | 24 | The code is short: 25 | 26 | ```java 27 | public static void main(String[] args) throws Exception { 28 | String environment = "production"; 29 | Pod pod = createPod(namespace); 30 | 31 | if (args[0].equals("yaml")) { 32 | System.out.println(SerializationUtils.dumpAsYaml(pod)); 33 | } else { 34 | System.out.println(mapper.writeValueAsString(pod)); 35 | } 36 | 37 | } 38 | 39 | public static Pod createPod( String environment ) { 40 | return new PodBuilder().withNewMetadata() 41 | .withName("test-pod") 42 | .endMetadata() 43 | .withNewSpec() 44 | .addNewContainer() 45 | .withName("test-container") 46 | .withImage("k8s.gcr.io/busybox") 47 | .withEnv(new EnvVarBuilder().withName("ENV").withValue(environment).build()) 48 | .endContainer() 49 | .endSpec() 50 | .build(); 51 | } 52 | ``` 53 | 54 | You can compile and package the Maven application with: 55 | ```shell 56 | mvn clean package 57 | ``` 58 | 59 | You can execute the the application with: 60 | 61 | ```shell 62 | java -jar target/k8s-client-1.0.jar --dry-run 63 | ``` 64 | 65 | The output is a JSON object for the Pod. 66 | 67 | ```json 68 | { 69 | "apiVersion" : "v1", 70 | "kind" : "Pod", 71 | "metadata" : { 72 | "annotations" : { }, 73 | "labels" : { }, 74 | "name" : "test-pod" 75 | }, 76 | "spec" : { 77 | "containers" : [ { 78 | "env" : [ { 79 | "name" : "ENV", 80 | "value" : "production" 81 | } ], 82 | "image" : "k8s.gcr.io/busybox", 83 | "name" : "test-container" 84 | } ], 85 | "nodeSelector" : { } 86 | } 87 | } 88 | ``` 89 | 90 | _But isn't Kubernetes accepting only YAML?_ 91 | 92 | YAML is a superset of JSON and any JSON file is also a valid YAML file. 93 | 94 | You can create the Pod in the cluster with the following commands: 95 | 96 | ```shell 97 | java -jar target/k8s-client-1.0.jar yaml --dry-run 98 | kubectl apply -f pod.yaml 99 | ``` 100 | 101 | ## Creating a custom Kubectl 102 | 103 | Instead of exporting the JSON and feeding it to kubectl, you can send the payload to the cluster directly. 104 | 105 | You can use the [Fabric8 Kubernetes API](https://github.com/fabric8io/kubernetes-client) to send the Pod definition to the cluster. 106 | 107 | Here's the code: 108 | 109 | ```java 110 | Config config = new ConfigBuilder().build(); 111 | 112 | try (final KubernetesClient client = new DefaultKubernetesClient(config)) { 113 | if (namespace == null) { 114 | namespace = client.getNamespace(); 115 | } 116 | 117 | boolean dryRun = false; 118 | for (String arg : args) { 119 | if (arg.equals("--dry-run")) { 120 | dryRun = true; 121 | } 122 | } 123 | if (!dryRun) { 124 | client.pods().inNamespace(namespace).create(pod); 125 | System.out.println("Pod created!"); 126 | } 127 | 128 | 129 | } 130 | 131 | ``` 132 | 133 | Assuming you are connected to a running cluster, you can execute the script with: 134 | 135 | ```shell 136 | java -jar target/k8s-client-1.0.jar yaml 137 | ``` 138 | 139 | And you can verify that the Pod was created with: 140 | 141 | ```shell 142 | kubectl get pods 143 | ``` 144 | 145 | ## What's next 146 | 147 | As you can imagine, this is a short demo and you can build more complex objects and use the power of Java and the Fabric8 Kubernetes API to compose large objects from smaller ones. -------------------------------------------------------------------------------- /java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | io.learnk8s 7 | k8s-client 8 | 1.0 9 | 10 | k8s-client 11 | 12 | 13 | 14 | 11 15 | 16 | 17 | 18 | 19 | io.fabric8 20 | kubernetes-client 21 | 4.6.4 22 | 23 | 24 | org.slf4j 25 | slf4j-api 26 | 1.7.25 27 | 28 | 29 | org.slf4j 30 | slf4j-jdk14 31 | 1.7.25 32 | 33 | 34 | 35 | 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-compiler-plugin 40 | 41 | 11 42 | 11 43 | 44 | 45 | 46 | maven-assembly-plugin 47 | 48 | 49 | package 50 | 51 | single 52 | 53 | 54 | 55 | 56 | 57 | 58 | true 59 | io.learnk8s.KubernetesClientCLI 60 | 61 | 62 | 63 | jar-with-dependencies 64 | 65 | ${project.name}-${project.version} 66 | false 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /java/src/main/java/io/learnk8s/KubernetesClientCLI.java: -------------------------------------------------------------------------------- 1 | package io.learnk8s; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.databind.SerializationFeature; 5 | import io.fabric8.kubernetes.api.model.*; 6 | import io.fabric8.kubernetes.client.*; 7 | import io.fabric8.kubernetes.client.Config; 8 | import io.fabric8.kubernetes.client.ConfigBuilder; 9 | import io.fabric8.kubernetes.client.internal.SerializationUtils; 10 | 11 | 12 | public class KubernetesClientCLI { 13 | 14 | 15 | private static final ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); 16 | private static String namespace = null; 17 | 18 | public static void main(String[] args) throws Exception { 19 | String environment = "production"; 20 | Pod pod = createPod(environment); 21 | 22 | if (args.length > 0 && args[0].equals("yaml")) { 23 | System.out.println(SerializationUtils.dumpAsYaml(pod)); 24 | } else { 25 | System.out.println(mapper.writeValueAsString(pod)); 26 | } 27 | 28 | Config config = new ConfigBuilder().build(); 29 | 30 | try (final KubernetesClient client = new DefaultKubernetesClient(config)) { 31 | if (namespace == null) { 32 | namespace = client.getNamespace(); 33 | } 34 | 35 | boolean dryRun = false; 36 | for (String arg : args) { 37 | if (arg.equals("--dry-run")) { 38 | dryRun = true; 39 | } 40 | } 41 | if (!dryRun) { 42 | client.pods().inNamespace(namespace).create(pod); 43 | System.out.println("Pod created!"); 44 | } 45 | 46 | 47 | } 48 | } 49 | 50 | public static Pod createPod(String environment){ 51 | return new PodBuilder().withNewMetadata() 52 | .withName("test-pod") 53 | .endMetadata() 54 | .withNewSpec() 55 | .addNewContainer() 56 | .withName("test-container") 57 | .withImage("nginx") 58 | .withEnv(new EnvVarBuilder().withName("ENV").withValue(environment).build()) 59 | .endContainer() 60 | .endSpec() 61 | .build(); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /javascript/README.md: -------------------------------------------------------------------------------- 1 | # Templating Kubernetes resources with Javascript 2 | 3 | In this section you will learn how to use Javascript to: 4 | 5 | - create JSON (and YAML) definition for a Kubernetes Pod 6 | - submit a Pod definition to the cluster with code 7 | 8 | Let's get started. 9 | 10 | ## Prerequisites 11 | 12 | Make sure you install all the dependencies with: 13 | 14 | ```shell 15 | npm install 16 | ``` 17 | 18 | ## Generating Pod definitions 19 | 20 | The code is short: 21 | 22 | ```js 23 | const { Pod, Container } = require('kubernetes-models/v1') 24 | 25 | function createPod(environment = 'production') { 26 | return new Pod({ 27 | metadata: { 28 | name: 'test-pod', 29 | }, 30 | spec: { 31 | containers: [ 32 | new Container({ 33 | name: 'test-container', 34 | image: 'k8s.gcr.io/busybox', 35 | env: [{ name: 'ENV', value: environment }], 36 | }), 37 | ], 38 | }, 39 | }) 40 | } 41 | 42 | const pod = createPod('dev') 43 | 44 | // Any valid JSON is also valid YAML 45 | const json = JSON.stringify(pod, null, 2) 46 | 47 | console.log(json) 48 | ``` 49 | 50 | You can execute the `gen-yaml.js` script with: 51 | 52 | ```shell 53 | node gen-yaml.js 54 | ``` 55 | 56 | The output is a JSON object for the Pod. 57 | 58 | ```json 59 | { 60 | "metadata": { 61 | "name": "test-pod" 62 | }, 63 | "spec": { 64 | "containers": [ 65 | { 66 | "name": "test-container", 67 | "image": "k8s.gcr.io/busybox", 68 | "env": [ 69 | { 70 | "name": "ENV", 71 | "value": "dev" 72 | } 73 | ] 74 | } 75 | ] 76 | }, 77 | "apiVersion": "v1", 78 | "kind": "Pod" 79 | } 80 | ``` 81 | 82 | _But isn't Kubernetes accepting only YAML?_ 83 | 84 | YAML is a superset of JSON and any JSON file is also a valid YAML file. 85 | 86 | You can create the Pod in the cluster with the following commands: 87 | 88 | ```shell 89 | node gen-yaml.js > pod.yaml 90 | kubectl apply -f pod.yaml 91 | ``` 92 | 93 | ## Creating a custom Kubectl 94 | 95 | Instead of exporting the JSON and feeding it to kubectl, you can send the payload to the cluster directly. 96 | 97 | You can use the [official Kubernetes client library](https://github.com/kubernetes-client/javascript) to send the Pod definition to the cluster. 98 | 99 | Here's the code: 100 | 101 | ```js 102 | const { Pod, Container } = require('kubernetes-models/v1') 103 | const k8s = require('@kubernetes/client-node') 104 | const kc = new k8s.KubeConfig() 105 | 106 | // Using the default credentials for kubectl 107 | kc.loadFromDefault() 108 | const k8sApi = kc.makeApiClient(k8s.CoreV1Api) 109 | 110 | function createPod(environment = 'production') { 111 | /* return pod definition */ 112 | } 113 | 114 | const pod = createPod('dev') 115 | 116 | k8sApi.createNamespacedPod('default', pod).then(() => console.log('success')) 117 | ``` 118 | 119 | Assuming you are connected to a running cluster, you can execute the script with: 120 | 121 | ```shell 122 | node kubectl.js 123 | ``` 124 | 125 | And you can verify that the Pod was created with: 126 | 127 | ```shell 128 | kubectl get pods 129 | ``` 130 | 131 | ## What's next 132 | 133 | As you can imagine, this is a short demo and you can build more complex objects and use the power of Javascript to compose large objects from smaller ones. -------------------------------------------------------------------------------- /javascript/gen-yaml.js: -------------------------------------------------------------------------------- 1 | const { Pod, Container } = require('kubernetes-models/v1') 2 | 3 | function createPod(environment = 'production') { 4 | return new Pod({ 5 | metadata: { 6 | name: 'test-pod', 7 | }, 8 | spec: { 9 | containers: [ 10 | new Container({ 11 | name: 'test-container', 12 | image: 'nginx', 13 | env: [{ name: 'ENV', value: environment }], 14 | }), 15 | ], 16 | }, 17 | }) 18 | } 19 | 20 | const pod = createPod('dev') 21 | 22 | // Any valid JSON is also valid YAML 23 | const json = JSON.stringify(pod, null, 2) 24 | 25 | console.log(json) -------------------------------------------------------------------------------- /javascript/kubectl.js: -------------------------------------------------------------------------------- 1 | const { Pod, Container } = require('kubernetes-models/v1') 2 | const k8s = require('@kubernetes/client-node') 3 | const kc = new k8s.KubeConfig() 4 | 5 | // Using the default credentials for kubectl 6 | kc.loadFromDefault() 7 | const k8sApi = kc.makeApiClient(k8s.CoreV1Api) 8 | 9 | function createPod(environment = 'production') { 10 | return new Pod({ 11 | metadata: { 12 | name: 'test-pod', 13 | }, 14 | spec: { 15 | containers: [ 16 | new Container({ 17 | name: 'test-container', 18 | image: 'nginx', 19 | env: [{ name: 'ENV', value: environment }], 20 | }), 21 | ], 22 | }, 23 | }) 24 | } 25 | 26 | const pod = createPod('dev') 27 | 28 | k8sApi.createNamespacedPod('default', pod).then(() => console.log('success')) -------------------------------------------------------------------------------- /javascript/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "templating-kubernetes", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@kubernetes-models/base": { 8 | "version": "0.1.2", 9 | "resolved": "https://registry.npmjs.org/@kubernetes-models/base/-/base-0.1.2.tgz", 10 | "integrity": "sha512-3QUnSs14TFIToN5jS6dFZHhXMNitCCSO353oLUimdzI6UNbJOYXTKuyVoPWob+pENrppkefymihIPWqFBWMh4g==", 11 | "requires": { 12 | "@kubernetes-models/validate": "^0.1.1", 13 | "is-plain-object": "^3.0.0", 14 | "tslib": "^1.10.0" 15 | } 16 | }, 17 | "@kubernetes-models/validate": { 18 | "version": "0.1.1", 19 | "resolved": "https://registry.npmjs.org/@kubernetes-models/validate/-/validate-0.1.1.tgz", 20 | "integrity": "sha512-uLUFqJgBhDgFSHGQK69Bue1fiiCys+BzSj/dOh1EyzzXEAQV16jsjhjK5y6/jR8RAKwa3HJcOKwveGAFqYNDbw==", 21 | "requires": { 22 | "ajv": "^6.10.2", 23 | "big-integer": "^1.6.44", 24 | "tslib": "^1.10.0" 25 | } 26 | }, 27 | "@kubernetes/client-node": { 28 | "version": "0.11.0", 29 | "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.11.0.tgz", 30 | "integrity": "sha512-1DQG9rNgn1fNpfStCBnvErGMcuF29ixGuQAjh3CVPLCFVsQCtNQjbSOIEV7XV18YEa2fj2hLU52TmJMSII0Kzw==", 31 | "requires": { 32 | "@types/js-yaml": "^3.12.1", 33 | "@types/node": "^10.12.0", 34 | "@types/request": "^2.47.1", 35 | "@types/underscore": "^1.8.9", 36 | "@types/ws": "^6.0.1", 37 | "byline": "^5.0.0", 38 | "execa": "1.0.0", 39 | "isomorphic-ws": "^4.0.1", 40 | "js-yaml": "^3.13.1", 41 | "jsonpath-plus": "^0.19.0", 42 | "openid-client": "2.5.0", 43 | "request": "^2.88.0", 44 | "shelljs": "^0.8.2", 45 | "tslib": "^1.9.3", 46 | "underscore": "^1.9.1", 47 | "ws": "^6.1.0" 48 | } 49 | }, 50 | "@sindresorhus/is": { 51 | "version": "0.7.0", 52 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", 53 | "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" 54 | }, 55 | "@types/caseless": { 56 | "version": "0.12.2", 57 | "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", 58 | "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" 59 | }, 60 | "@types/js-yaml": { 61 | "version": "3.12.1", 62 | "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.1.tgz", 63 | "integrity": "sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==" 64 | }, 65 | "@types/node": { 66 | "version": "10.17.13", 67 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", 68 | "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==" 69 | }, 70 | "@types/request": { 71 | "version": "2.48.4", 72 | "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.4.tgz", 73 | "integrity": "sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==", 74 | "requires": { 75 | "@types/caseless": "*", 76 | "@types/node": "*", 77 | "@types/tough-cookie": "*", 78 | "form-data": "^2.5.0" 79 | } 80 | }, 81 | "@types/tough-cookie": { 82 | "version": "2.3.6", 83 | "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.6.tgz", 84 | "integrity": "sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ==" 85 | }, 86 | "@types/underscore": { 87 | "version": "1.9.4", 88 | "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.9.4.tgz", 89 | "integrity": "sha512-CjHWEMECc2/UxOZh0kpiz3lEyX2Px3rQS9HzD20lxMvx571ivOBQKeLnqEjxUY0BMgp6WJWo/pQLRBwMW5v4WQ==" 90 | }, 91 | "@types/ws": { 92 | "version": "6.0.4", 93 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.4.tgz", 94 | "integrity": "sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg==", 95 | "requires": { 96 | "@types/node": "*" 97 | } 98 | }, 99 | "aggregate-error": { 100 | "version": "1.0.0", 101 | "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", 102 | "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", 103 | "requires": { 104 | "clean-stack": "^1.0.0", 105 | "indent-string": "^3.0.0" 106 | } 107 | }, 108 | "ajv": { 109 | "version": "6.10.2", 110 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", 111 | "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", 112 | "requires": { 113 | "fast-deep-equal": "^2.0.1", 114 | "fast-json-stable-stringify": "^2.0.0", 115 | "json-schema-traverse": "^0.4.1", 116 | "uri-js": "^4.2.2" 117 | } 118 | }, 119 | "argparse": { 120 | "version": "1.0.10", 121 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 122 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 123 | "requires": { 124 | "sprintf-js": "~1.0.2" 125 | } 126 | }, 127 | "asn1": { 128 | "version": "0.2.4", 129 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 130 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 131 | "requires": { 132 | "safer-buffer": "~2.1.0" 133 | } 134 | }, 135 | "assert-plus": { 136 | "version": "1.0.0", 137 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 138 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 139 | }, 140 | "async-limiter": { 141 | "version": "1.0.1", 142 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", 143 | "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" 144 | }, 145 | "asynckit": { 146 | "version": "0.4.0", 147 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 148 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 149 | }, 150 | "aws-sign2": { 151 | "version": "0.7.0", 152 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 153 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 154 | }, 155 | "aws4": { 156 | "version": "1.9.0", 157 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", 158 | "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" 159 | }, 160 | "balanced-match": { 161 | "version": "1.0.0", 162 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 163 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 164 | }, 165 | "base64url": { 166 | "version": "3.0.1", 167 | "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", 168 | "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" 169 | }, 170 | "bcrypt-pbkdf": { 171 | "version": "1.0.2", 172 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 173 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 174 | "requires": { 175 | "tweetnacl": "^0.14.3" 176 | } 177 | }, 178 | "big-integer": { 179 | "version": "1.6.48", 180 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", 181 | "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" 182 | }, 183 | "brace-expansion": { 184 | "version": "1.1.11", 185 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 186 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 187 | "requires": { 188 | "balanced-match": "^1.0.0", 189 | "concat-map": "0.0.1" 190 | } 191 | }, 192 | "byline": { 193 | "version": "5.0.0", 194 | "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", 195 | "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=" 196 | }, 197 | "cacheable-request": { 198 | "version": "2.1.4", 199 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", 200 | "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", 201 | "requires": { 202 | "clone-response": "1.0.2", 203 | "get-stream": "3.0.0", 204 | "http-cache-semantics": "3.8.1", 205 | "keyv": "3.0.0", 206 | "lowercase-keys": "1.0.0", 207 | "normalize-url": "2.0.1", 208 | "responselike": "1.0.2" 209 | }, 210 | "dependencies": { 211 | "get-stream": { 212 | "version": "3.0.0", 213 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", 214 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" 215 | }, 216 | "lowercase-keys": { 217 | "version": "1.0.0", 218 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", 219 | "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" 220 | } 221 | } 222 | }, 223 | "caseless": { 224 | "version": "0.12.0", 225 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 226 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 227 | }, 228 | "clean-stack": { 229 | "version": "1.3.0", 230 | "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", 231 | "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=" 232 | }, 233 | "clone-response": { 234 | "version": "1.0.2", 235 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", 236 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", 237 | "requires": { 238 | "mimic-response": "^1.0.0" 239 | } 240 | }, 241 | "combined-stream": { 242 | "version": "1.0.8", 243 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 244 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 245 | "requires": { 246 | "delayed-stream": "~1.0.0" 247 | } 248 | }, 249 | "concat-map": { 250 | "version": "0.0.1", 251 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 252 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 253 | }, 254 | "core-util-is": { 255 | "version": "1.0.2", 256 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 257 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 258 | }, 259 | "cross-spawn": { 260 | "version": "6.0.5", 261 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 262 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 263 | "requires": { 264 | "nice-try": "^1.0.4", 265 | "path-key": "^2.0.1", 266 | "semver": "^5.5.0", 267 | "shebang-command": "^1.2.0", 268 | "which": "^1.2.9" 269 | } 270 | }, 271 | "dashdash": { 272 | "version": "1.14.1", 273 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 274 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 275 | "requires": { 276 | "assert-plus": "^1.0.0" 277 | } 278 | }, 279 | "decode-uri-component": { 280 | "version": "0.2.0", 281 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", 282 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" 283 | }, 284 | "decompress-response": { 285 | "version": "3.3.0", 286 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", 287 | "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", 288 | "requires": { 289 | "mimic-response": "^1.0.0" 290 | } 291 | }, 292 | "delayed-stream": { 293 | "version": "1.0.0", 294 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 295 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 296 | }, 297 | "duplexer3": { 298 | "version": "0.1.4", 299 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", 300 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" 301 | }, 302 | "ecc-jsbn": { 303 | "version": "0.1.2", 304 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 305 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 306 | "requires": { 307 | "jsbn": "~0.1.0", 308 | "safer-buffer": "^2.1.0" 309 | } 310 | }, 311 | "end-of-stream": { 312 | "version": "1.4.4", 313 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 314 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 315 | "requires": { 316 | "once": "^1.4.0" 317 | } 318 | }, 319 | "es6-promise": { 320 | "version": "4.2.8", 321 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 322 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" 323 | }, 324 | "esprima": { 325 | "version": "4.0.1", 326 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 327 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" 328 | }, 329 | "execa": { 330 | "version": "1.0.0", 331 | "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", 332 | "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", 333 | "requires": { 334 | "cross-spawn": "^6.0.0", 335 | "get-stream": "^4.0.0", 336 | "is-stream": "^1.1.0", 337 | "npm-run-path": "^2.0.0", 338 | "p-finally": "^1.0.0", 339 | "signal-exit": "^3.0.0", 340 | "strip-eof": "^1.0.0" 341 | } 342 | }, 343 | "extend": { 344 | "version": "3.0.2", 345 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 346 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 347 | }, 348 | "extsprintf": { 349 | "version": "1.3.0", 350 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 351 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 352 | }, 353 | "fast-deep-equal": { 354 | "version": "2.0.1", 355 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 356 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 357 | }, 358 | "fast-json-stable-stringify": { 359 | "version": "2.1.0", 360 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 361 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 362 | }, 363 | "forever-agent": { 364 | "version": "0.6.1", 365 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 366 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 367 | }, 368 | "form-data": { 369 | "version": "2.5.1", 370 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", 371 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", 372 | "requires": { 373 | "asynckit": "^0.4.0", 374 | "combined-stream": "^1.0.6", 375 | "mime-types": "^2.1.12" 376 | } 377 | }, 378 | "from2": { 379 | "version": "2.3.0", 380 | "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", 381 | "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", 382 | "requires": { 383 | "inherits": "^2.0.1", 384 | "readable-stream": "^2.0.0" 385 | } 386 | }, 387 | "fs.realpath": { 388 | "version": "1.0.0", 389 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 390 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 391 | }, 392 | "get-stream": { 393 | "version": "4.1.0", 394 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 395 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 396 | "requires": { 397 | "pump": "^3.0.0" 398 | } 399 | }, 400 | "getpass": { 401 | "version": "0.1.7", 402 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 403 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 404 | "requires": { 405 | "assert-plus": "^1.0.0" 406 | } 407 | }, 408 | "glob": { 409 | "version": "7.1.6", 410 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 411 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 412 | "requires": { 413 | "fs.realpath": "^1.0.0", 414 | "inflight": "^1.0.4", 415 | "inherits": "2", 416 | "minimatch": "^3.0.4", 417 | "once": "^1.3.0", 418 | "path-is-absolute": "^1.0.0" 419 | } 420 | }, 421 | "got": { 422 | "version": "8.3.2", 423 | "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", 424 | "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", 425 | "requires": { 426 | "@sindresorhus/is": "^0.7.0", 427 | "cacheable-request": "^2.1.1", 428 | "decompress-response": "^3.3.0", 429 | "duplexer3": "^0.1.4", 430 | "get-stream": "^3.0.0", 431 | "into-stream": "^3.1.0", 432 | "is-retry-allowed": "^1.1.0", 433 | "isurl": "^1.0.0-alpha5", 434 | "lowercase-keys": "^1.0.0", 435 | "mimic-response": "^1.0.0", 436 | "p-cancelable": "^0.4.0", 437 | "p-timeout": "^2.0.1", 438 | "pify": "^3.0.0", 439 | "safe-buffer": "^5.1.1", 440 | "timed-out": "^4.0.1", 441 | "url-parse-lax": "^3.0.0", 442 | "url-to-options": "^1.0.1" 443 | }, 444 | "dependencies": { 445 | "get-stream": { 446 | "version": "3.0.0", 447 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", 448 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" 449 | } 450 | } 451 | }, 452 | "har-schema": { 453 | "version": "2.0.0", 454 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 455 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 456 | }, 457 | "har-validator": { 458 | "version": "5.1.3", 459 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 460 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 461 | "requires": { 462 | "ajv": "^6.5.5", 463 | "har-schema": "^2.0.0" 464 | } 465 | }, 466 | "has-symbol-support-x": { 467 | "version": "1.4.2", 468 | "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", 469 | "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" 470 | }, 471 | "has-to-string-tag-x": { 472 | "version": "1.4.1", 473 | "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", 474 | "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", 475 | "requires": { 476 | "has-symbol-support-x": "^1.4.1" 477 | } 478 | }, 479 | "http-cache-semantics": { 480 | "version": "3.8.1", 481 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", 482 | "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" 483 | }, 484 | "http-signature": { 485 | "version": "1.2.0", 486 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 487 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 488 | "requires": { 489 | "assert-plus": "^1.0.0", 490 | "jsprim": "^1.2.2", 491 | "sshpk": "^1.7.0" 492 | } 493 | }, 494 | "indent-string": { 495 | "version": "3.2.0", 496 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", 497 | "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" 498 | }, 499 | "inflight": { 500 | "version": "1.0.6", 501 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 502 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 503 | "requires": { 504 | "once": "^1.3.0", 505 | "wrappy": "1" 506 | } 507 | }, 508 | "inherits": { 509 | "version": "2.0.4", 510 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 511 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 512 | }, 513 | "interpret": { 514 | "version": "1.2.0", 515 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", 516 | "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" 517 | }, 518 | "into-stream": { 519 | "version": "3.1.0", 520 | "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", 521 | "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", 522 | "requires": { 523 | "from2": "^2.1.1", 524 | "p-is-promise": "^1.1.0" 525 | } 526 | }, 527 | "is-object": { 528 | "version": "1.0.1", 529 | "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", 530 | "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" 531 | }, 532 | "is-plain-obj": { 533 | "version": "1.1.0", 534 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", 535 | "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" 536 | }, 537 | "is-plain-object": { 538 | "version": "3.0.0", 539 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", 540 | "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", 541 | "requires": { 542 | "isobject": "^4.0.0" 543 | } 544 | }, 545 | "is-retry-allowed": { 546 | "version": "1.2.0", 547 | "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", 548 | "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" 549 | }, 550 | "is-stream": { 551 | "version": "1.1.0", 552 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 553 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 554 | }, 555 | "is-typedarray": { 556 | "version": "1.0.0", 557 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 558 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 559 | }, 560 | "isarray": { 561 | "version": "1.0.0", 562 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 563 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 564 | }, 565 | "isexe": { 566 | "version": "2.0.0", 567 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 568 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 569 | }, 570 | "isobject": { 571 | "version": "4.0.0", 572 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", 573 | "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==" 574 | }, 575 | "isomorphic-ws": { 576 | "version": "4.0.1", 577 | "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", 578 | "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" 579 | }, 580 | "isstream": { 581 | "version": "0.1.2", 582 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 583 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 584 | }, 585 | "isurl": { 586 | "version": "1.0.0", 587 | "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", 588 | "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", 589 | "requires": { 590 | "has-to-string-tag-x": "^1.2.0", 591 | "is-object": "^1.0.1" 592 | } 593 | }, 594 | "js-yaml": { 595 | "version": "3.13.1", 596 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 597 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 598 | "requires": { 599 | "argparse": "^1.0.7", 600 | "esprima": "^4.0.0" 601 | } 602 | }, 603 | "jsbn": { 604 | "version": "0.1.1", 605 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 606 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 607 | }, 608 | "json-buffer": { 609 | "version": "3.0.0", 610 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", 611 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" 612 | }, 613 | "json-schema": { 614 | "version": "0.2.3", 615 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 616 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 617 | }, 618 | "json-schema-traverse": { 619 | "version": "0.4.1", 620 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 621 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 622 | }, 623 | "json-stringify-safe": { 624 | "version": "5.0.1", 625 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 626 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 627 | }, 628 | "jsonpath-plus": { 629 | "version": "0.19.0", 630 | "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-0.19.0.tgz", 631 | "integrity": "sha512-GSVwsrzW9LsA5lzsqe4CkuZ9wp+kxBb2GwNniaWzI2YFn5Ig42rSW8ZxVpWXaAfakXNrx5pgY5AbQq7kzX29kg==" 632 | }, 633 | "jsprim": { 634 | "version": "1.4.1", 635 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 636 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 637 | "requires": { 638 | "assert-plus": "1.0.0", 639 | "extsprintf": "1.3.0", 640 | "json-schema": "0.2.3", 641 | "verror": "1.10.0" 642 | } 643 | }, 644 | "keyv": { 645 | "version": "3.0.0", 646 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", 647 | "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", 648 | "requires": { 649 | "json-buffer": "3.0.0" 650 | } 651 | }, 652 | "kubernetes-models": { 653 | "version": "0.7.3", 654 | "resolved": "https://registry.npmjs.org/kubernetes-models/-/kubernetes-models-0.7.3.tgz", 655 | "integrity": "sha512-vmepB3YobThQJCyDCHSF559Ie1pWwdkmj0KMxvykF1hg8B01Ses7K6/rOdudccTAU6CW+VfzTgvNa6U5GpKeUA==", 656 | "requires": { 657 | "@kubernetes-models/base": "^0.1.2", 658 | "@kubernetes-models/validate": "^0.1.1", 659 | "tslib": "^1.10.0" 660 | } 661 | }, 662 | "lodash": { 663 | "version": "4.17.15", 664 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 665 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" 666 | }, 667 | "long": { 668 | "version": "4.0.0", 669 | "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", 670 | "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" 671 | }, 672 | "lowercase-keys": { 673 | "version": "1.0.1", 674 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 675 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" 676 | }, 677 | "lru-cache": { 678 | "version": "5.1.1", 679 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 680 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 681 | "requires": { 682 | "yallist": "^3.0.2" 683 | } 684 | }, 685 | "mime-db": { 686 | "version": "1.43.0", 687 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", 688 | "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" 689 | }, 690 | "mime-types": { 691 | "version": "2.1.26", 692 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", 693 | "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", 694 | "requires": { 695 | "mime-db": "1.43.0" 696 | } 697 | }, 698 | "mimic-response": { 699 | "version": "1.0.1", 700 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", 701 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" 702 | }, 703 | "minimatch": { 704 | "version": "3.0.4", 705 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 706 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 707 | "requires": { 708 | "brace-expansion": "^1.1.7" 709 | } 710 | }, 711 | "nice-try": { 712 | "version": "1.0.5", 713 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 714 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" 715 | }, 716 | "node-forge": { 717 | "version": "0.8.5", 718 | "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", 719 | "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==" 720 | }, 721 | "node-jose": { 722 | "version": "1.1.3", 723 | "resolved": "https://registry.npmjs.org/node-jose/-/node-jose-1.1.3.tgz", 724 | "integrity": "sha512-kupfi4uGWhRjnOmtie2T64cLge5a1TZyalEa8uWWWBgtKBcu41A4IGKpI9twZAxRnmviamEUQRK7LSyfFb2w8A==", 725 | "requires": { 726 | "base64url": "^3.0.1", 727 | "es6-promise": "^4.2.6", 728 | "lodash": "^4.17.11", 729 | "long": "^4.0.0", 730 | "node-forge": "^0.8.1", 731 | "uuid": "^3.3.2" 732 | } 733 | }, 734 | "normalize-url": { 735 | "version": "2.0.1", 736 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", 737 | "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", 738 | "requires": { 739 | "prepend-http": "^2.0.0", 740 | "query-string": "^5.0.1", 741 | "sort-keys": "^2.0.0" 742 | } 743 | }, 744 | "npm-run-path": { 745 | "version": "2.0.2", 746 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 747 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 748 | "requires": { 749 | "path-key": "^2.0.0" 750 | } 751 | }, 752 | "oauth-sign": { 753 | "version": "0.9.0", 754 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 755 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 756 | }, 757 | "object-assign": { 758 | "version": "4.1.1", 759 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 760 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 761 | }, 762 | "object-hash": { 763 | "version": "1.3.1", 764 | "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", 765 | "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" 766 | }, 767 | "oidc-token-hash": { 768 | "version": "3.0.2", 769 | "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-3.0.2.tgz", 770 | "integrity": "sha512-dTzp80/y/da+um+i+sOucNqiPpwRL7M/xPwj7pH1TFA2/bqQ+OK2sJahSXbemEoLtPkHcFLyhLhLWZa9yW5+RA==" 771 | }, 772 | "once": { 773 | "version": "1.4.0", 774 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 775 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 776 | "requires": { 777 | "wrappy": "1" 778 | } 779 | }, 780 | "openid-client": { 781 | "version": "2.5.0", 782 | "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-2.5.0.tgz", 783 | "integrity": "sha512-t3hFD7xEoW1U25RyBcRFaL19fGGs6hNVTysq9pgmiltH0IVUPzH/bQV9w24pM5Q7MunnGv2/5XjIru6BQcWdxg==", 784 | "requires": { 785 | "base64url": "^3.0.0", 786 | "got": "^8.3.2", 787 | "lodash": "^4.17.11", 788 | "lru-cache": "^5.1.1", 789 | "node-jose": "^1.1.0", 790 | "object-hash": "^1.3.1", 791 | "oidc-token-hash": "^3.0.1", 792 | "p-any": "^1.1.0" 793 | } 794 | }, 795 | "p-any": { 796 | "version": "1.1.0", 797 | "resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz", 798 | "integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==", 799 | "requires": { 800 | "p-some": "^2.0.0" 801 | } 802 | }, 803 | "p-cancelable": { 804 | "version": "0.4.1", 805 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", 806 | "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==" 807 | }, 808 | "p-finally": { 809 | "version": "1.0.0", 810 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 811 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" 812 | }, 813 | "p-is-promise": { 814 | "version": "1.1.0", 815 | "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", 816 | "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" 817 | }, 818 | "p-some": { 819 | "version": "2.0.1", 820 | "resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.1.tgz", 821 | "integrity": "sha1-Zdh8ixVO289SIdFnd4ttLhUPbwY=", 822 | "requires": { 823 | "aggregate-error": "^1.0.0" 824 | } 825 | }, 826 | "p-timeout": { 827 | "version": "2.0.1", 828 | "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", 829 | "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", 830 | "requires": { 831 | "p-finally": "^1.0.0" 832 | } 833 | }, 834 | "path-is-absolute": { 835 | "version": "1.0.1", 836 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 837 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 838 | }, 839 | "path-key": { 840 | "version": "2.0.1", 841 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 842 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" 843 | }, 844 | "path-parse": { 845 | "version": "1.0.6", 846 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 847 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 848 | }, 849 | "performance-now": { 850 | "version": "2.1.0", 851 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 852 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 853 | }, 854 | "pify": { 855 | "version": "3.0.0", 856 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 857 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" 858 | }, 859 | "prepend-http": { 860 | "version": "2.0.0", 861 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", 862 | "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" 863 | }, 864 | "process-nextick-args": { 865 | "version": "2.0.1", 866 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 867 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 868 | }, 869 | "psl": { 870 | "version": "1.7.0", 871 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", 872 | "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" 873 | }, 874 | "pump": { 875 | "version": "3.0.0", 876 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 877 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 878 | "requires": { 879 | "end-of-stream": "^1.1.0", 880 | "once": "^1.3.1" 881 | } 882 | }, 883 | "punycode": { 884 | "version": "2.1.1", 885 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 886 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 887 | }, 888 | "qs": { 889 | "version": "6.5.2", 890 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 891 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 892 | }, 893 | "query-string": { 894 | "version": "5.1.1", 895 | "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", 896 | "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", 897 | "requires": { 898 | "decode-uri-component": "^0.2.0", 899 | "object-assign": "^4.1.0", 900 | "strict-uri-encode": "^1.0.0" 901 | } 902 | }, 903 | "readable-stream": { 904 | "version": "2.3.7", 905 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 906 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 907 | "requires": { 908 | "core-util-is": "~1.0.0", 909 | "inherits": "~2.0.3", 910 | "isarray": "~1.0.0", 911 | "process-nextick-args": "~2.0.0", 912 | "safe-buffer": "~5.1.1", 913 | "string_decoder": "~1.1.1", 914 | "util-deprecate": "~1.0.1" 915 | }, 916 | "dependencies": { 917 | "safe-buffer": { 918 | "version": "5.1.2", 919 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 920 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 921 | } 922 | } 923 | }, 924 | "rechoir": { 925 | "version": "0.6.2", 926 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 927 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 928 | "requires": { 929 | "resolve": "^1.1.6" 930 | } 931 | }, 932 | "request": { 933 | "version": "2.88.0", 934 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 935 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 936 | "requires": { 937 | "aws-sign2": "~0.7.0", 938 | "aws4": "^1.8.0", 939 | "caseless": "~0.12.0", 940 | "combined-stream": "~1.0.6", 941 | "extend": "~3.0.2", 942 | "forever-agent": "~0.6.1", 943 | "form-data": "~2.3.2", 944 | "har-validator": "~5.1.0", 945 | "http-signature": "~1.2.0", 946 | "is-typedarray": "~1.0.0", 947 | "isstream": "~0.1.2", 948 | "json-stringify-safe": "~5.0.1", 949 | "mime-types": "~2.1.19", 950 | "oauth-sign": "~0.9.0", 951 | "performance-now": "^2.1.0", 952 | "qs": "~6.5.2", 953 | "safe-buffer": "^5.1.2", 954 | "tough-cookie": "~2.4.3", 955 | "tunnel-agent": "^0.6.0", 956 | "uuid": "^3.3.2" 957 | }, 958 | "dependencies": { 959 | "form-data": { 960 | "version": "2.3.3", 961 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 962 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 963 | "requires": { 964 | "asynckit": "^0.4.0", 965 | "combined-stream": "^1.0.6", 966 | "mime-types": "^2.1.12" 967 | } 968 | } 969 | } 970 | }, 971 | "resolve": { 972 | "version": "1.14.1", 973 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", 974 | "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", 975 | "requires": { 976 | "path-parse": "^1.0.6" 977 | } 978 | }, 979 | "responselike": { 980 | "version": "1.0.2", 981 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", 982 | "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", 983 | "requires": { 984 | "lowercase-keys": "^1.0.0" 985 | } 986 | }, 987 | "safe-buffer": { 988 | "version": "5.2.0", 989 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", 990 | "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" 991 | }, 992 | "safer-buffer": { 993 | "version": "2.1.2", 994 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 995 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 996 | }, 997 | "semver": { 998 | "version": "5.7.1", 999 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 1000 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 1001 | }, 1002 | "shebang-command": { 1003 | "version": "1.2.0", 1004 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1005 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1006 | "requires": { 1007 | "shebang-regex": "^1.0.0" 1008 | } 1009 | }, 1010 | "shebang-regex": { 1011 | "version": "1.0.0", 1012 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1013 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" 1014 | }, 1015 | "shelljs": { 1016 | "version": "0.8.3", 1017 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", 1018 | "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", 1019 | "requires": { 1020 | "glob": "^7.0.0", 1021 | "interpret": "^1.0.0", 1022 | "rechoir": "^0.6.2" 1023 | } 1024 | }, 1025 | "signal-exit": { 1026 | "version": "3.0.2", 1027 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1028 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 1029 | }, 1030 | "sort-keys": { 1031 | "version": "2.0.0", 1032 | "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", 1033 | "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", 1034 | "requires": { 1035 | "is-plain-obj": "^1.0.0" 1036 | } 1037 | }, 1038 | "sprintf-js": { 1039 | "version": "1.0.3", 1040 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1041 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" 1042 | }, 1043 | "sshpk": { 1044 | "version": "1.16.1", 1045 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 1046 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 1047 | "requires": { 1048 | "asn1": "~0.2.3", 1049 | "assert-plus": "^1.0.0", 1050 | "bcrypt-pbkdf": "^1.0.0", 1051 | "dashdash": "^1.12.0", 1052 | "ecc-jsbn": "~0.1.1", 1053 | "getpass": "^0.1.1", 1054 | "jsbn": "~0.1.0", 1055 | "safer-buffer": "^2.0.2", 1056 | "tweetnacl": "~0.14.0" 1057 | } 1058 | }, 1059 | "strict-uri-encode": { 1060 | "version": "1.1.0", 1061 | "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", 1062 | "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" 1063 | }, 1064 | "string_decoder": { 1065 | "version": "1.1.1", 1066 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1067 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1068 | "requires": { 1069 | "safe-buffer": "~5.1.0" 1070 | }, 1071 | "dependencies": { 1072 | "safe-buffer": { 1073 | "version": "5.1.2", 1074 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1075 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1076 | } 1077 | } 1078 | }, 1079 | "strip-eof": { 1080 | "version": "1.0.0", 1081 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 1082 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" 1083 | }, 1084 | "timed-out": { 1085 | "version": "4.0.1", 1086 | "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", 1087 | "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" 1088 | }, 1089 | "tough-cookie": { 1090 | "version": "2.4.3", 1091 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 1092 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 1093 | "requires": { 1094 | "psl": "^1.1.24", 1095 | "punycode": "^1.4.1" 1096 | }, 1097 | "dependencies": { 1098 | "punycode": { 1099 | "version": "1.4.1", 1100 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 1101 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 1102 | } 1103 | } 1104 | }, 1105 | "tslib": { 1106 | "version": "1.10.0", 1107 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", 1108 | "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" 1109 | }, 1110 | "tunnel-agent": { 1111 | "version": "0.6.0", 1112 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1113 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 1114 | "requires": { 1115 | "safe-buffer": "^5.0.1" 1116 | } 1117 | }, 1118 | "tweetnacl": { 1119 | "version": "0.14.5", 1120 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 1121 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 1122 | }, 1123 | "underscore": { 1124 | "version": "1.9.1", 1125 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", 1126 | "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" 1127 | }, 1128 | "uri-js": { 1129 | "version": "4.2.2", 1130 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1131 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1132 | "requires": { 1133 | "punycode": "^2.1.0" 1134 | } 1135 | }, 1136 | "url-parse-lax": { 1137 | "version": "3.0.0", 1138 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", 1139 | "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", 1140 | "requires": { 1141 | "prepend-http": "^2.0.0" 1142 | } 1143 | }, 1144 | "url-to-options": { 1145 | "version": "1.0.1", 1146 | "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", 1147 | "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" 1148 | }, 1149 | "util-deprecate": { 1150 | "version": "1.0.2", 1151 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1152 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1153 | }, 1154 | "uuid": { 1155 | "version": "3.3.3", 1156 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", 1157 | "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" 1158 | }, 1159 | "verror": { 1160 | "version": "1.10.0", 1161 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1162 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 1163 | "requires": { 1164 | "assert-plus": "^1.0.0", 1165 | "core-util-is": "1.0.2", 1166 | "extsprintf": "^1.2.0" 1167 | } 1168 | }, 1169 | "which": { 1170 | "version": "1.3.1", 1171 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1172 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1173 | "requires": { 1174 | "isexe": "^2.0.0" 1175 | } 1176 | }, 1177 | "wrappy": { 1178 | "version": "1.0.2", 1179 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1180 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1181 | }, 1182 | "ws": { 1183 | "version": "6.2.1", 1184 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", 1185 | "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", 1186 | "requires": { 1187 | "async-limiter": "~1.0.0" 1188 | } 1189 | }, 1190 | "yallist": { 1191 | "version": "3.1.1", 1192 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1193 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 1194 | } 1195 | } 1196 | } 1197 | -------------------------------------------------------------------------------- /javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "templating-kubernetes", 3 | "version": "1.0.0", 4 | "description": "Templating Kubernetes resources with Javascript", 5 | "main": "index.js", 6 | "scripts": {}, 7 | "author": "Learnk8s Ltd", 8 | "license": "MIT", 9 | "dependencies": { 10 | "@kubernetes/client-node": "^0.11.0", 11 | "kubernetes-models": "^0.7.3" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # Templating Kubernetes resources with Python 2 | 3 | In this section you will learn how to use Python to: 4 | 5 | - Create a JSON resource definition of a Kubernetes Pod 6 | - Submit the resource definition to the cluster to create the Pod 7 | 8 | For both tasks you will use the official Kubernetes [Python client library](https://github.com/kubernetes-client/python). 9 | 10 | Let's get started. 11 | 12 | ## Prerequisites 13 | 14 | First, make sure you have Python and the pip package manager installed. You can find installation instructions in the [Python documentation](https://www.python.org/downloads/). 15 | 16 | Then, install the Kubernetes Python client library: 17 | 18 | ```shell 19 | pip install kubernetes 20 | ``` 21 | 22 | ## Generating a Pod resource definition 23 | 24 | The following is the code for generating and printing out a Pod resource definition in JSON: 25 | 26 | ```python 27 | from kubernetes import client, config 28 | import json 29 | 30 | def main(): 31 | pod = create_pod("dev") 32 | print(json.dumps(client.ApiClient().sanitize_for_serialization(pod))) 33 | 34 | def create_pod(environment): 35 | return client.V1Pod( 36 | api_version = "v1", 37 | kind = "Pod", 38 | metadata = client.V1ObjectMeta( 39 | name = "test-pod", 40 | ), 41 | spec = client.V1PodSpec( 42 | containers = [ 43 | client.V1Container( 44 | name = "test-container", 45 | image = "nginx", 46 | env = [ 47 | client.V1EnvVar( 48 | name = "ENV", 49 | value = environment, 50 | ) 51 | ] 52 | ) 53 | ] 54 | ) 55 | ) 56 | 57 | if __name__ == '__main__': 58 | main() 59 | ``` 60 | 61 | Save the above code in a file named `generate.py`. 62 | 63 | > You can find the documentation of the Kubernetes Python client in the project's [GitHub repository](https://github.com/kubernetes-client/python). 64 | 65 | You can then run your Python script with: 66 | 67 | ```shell 68 | python generate.py 69 | ``` 70 | 71 | The output is the JSON resource definition of a Pod. 72 | 73 | Note that this JSON has no newlines and indentation, which makes it hard to read. If you want, you can pretty-print the JSON with [`jq`](https://stedolan.github.io/jq/): 74 | 75 | ```shell 76 | $ python generate.py | jq 77 | { 78 | "apiVersion": "v1", 79 | "kind": "Pod", 80 | "metadata": { 81 | "name": "test-pod" 82 | }, 83 | "spec": { 84 | "containers": [ 85 | { 86 | "env": [ 87 | { 88 | "name": "ENV", 89 | "value": "dev" 90 | } 91 | ], 92 | "image": "nginx", 93 | "name": "test-container" 94 | } 95 | ] 96 | } 97 | } 98 | ``` 99 | 100 | You can save this JSON definition in a file: 101 | 102 | ```shell 103 | python generate.py >pod.json 104 | ``` 105 | 106 | And then you can submit it to the cluster with kubectl as ususal: 107 | 108 | ```shell 109 | kubectl apply -f pod.json 110 | ``` 111 | 112 | You can verify that the Pod has been created correctly with: 113 | 114 | ```shell 115 | kubectl get pods 116 | ``` 117 | 118 | ## Submitting a Pod resource definition to the cluster 119 | 120 | Instead of saving the JSON resource definition to a file and then using kubectl to submit it to the cluster, you can submit the resource definition to the cluster directly in your code. 121 | 122 | The code to generate a Pod resource definition _and_ submitting it to the cluster is as follows: 123 | 124 | ```go 125 | from kubernetes import client, config 126 | 127 | def main(): 128 | config.load_kube_config() 129 | pod = create_pod("dev") 130 | client.CoreV1Api().create_namespaced_pod("default", pod) 131 | print("pod/%s created" % pod.metadata.name) 132 | 133 | def create_pod(environment): 134 | # ...same as above 135 | 136 | if __name__ == '__main__': 137 | main() 138 | ``` 139 | 140 | Go on and save the above code in a file named `create.py`. 141 | 142 | You can then run the script with: 143 | 144 | ```shell 145 | python create.py 146 | ``` 147 | 148 | The ouptut should be `pod/test-pod created`. 149 | 150 | You can verify that the Pod has indeed been created with: 151 | 152 | ```shell 153 | kubectl get pods 154 | ``` 155 | 156 | ## What's next 157 | 158 | As you can imagine, this was just a short demo. You can compose any type of Kubernetes object with the Python client library and you can create, read, update, and delete these objects in your Kubernetes cluster. 159 | 160 | Feel free to check out the [example programs](https://github.com/kubernetes-client/python/tree/master/examples) of the Python client library. 161 | -------------------------------------------------------------------------------- /python/create.py: -------------------------------------------------------------------------------- 1 | from kubernetes import client, config 2 | 3 | def main(): 4 | config.load_kube_config() 5 | pod = create_pod("dev") 6 | client.CoreV1Api().create_namespaced_pod("default", pod) 7 | print("pod/%s created" % pod.metadata.name) 8 | 9 | def create_pod(environment): 10 | return client.V1Pod( 11 | api_version = "v1", 12 | kind = "Pod", 13 | metadata = client.V1ObjectMeta( 14 | name = "test-pod", 15 | ), 16 | spec = client.V1PodSpec( 17 | containers = [ 18 | client.V1Container( 19 | name = "test-container", 20 | image = "nginx", 21 | env = [ 22 | client.V1EnvVar( 23 | name = "ENV", 24 | value = environment, 25 | ) 26 | ] 27 | ) 28 | ] 29 | ) 30 | ) 31 | 32 | if __name__ == '__main__': 33 | main() 34 | -------------------------------------------------------------------------------- /python/generate.py: -------------------------------------------------------------------------------- 1 | from kubernetes import client, config 2 | import json 3 | 4 | def main(): 5 | pod = create_pod("dev") 6 | print(json.dumps(client.ApiClient().sanitize_for_serialization(pod))) 7 | 8 | def create_pod(environment): 9 | return client.V1Pod( 10 | api_version = "v1", 11 | kind = "Pod", 12 | metadata = client.V1ObjectMeta( 13 | name = "test-pod", 14 | ), 15 | spec = client.V1PodSpec( 16 | containers = [ 17 | client.V1Container( 18 | name = "test-container", 19 | image = "nginx", 20 | env = [ 21 | client.V1EnvVar( 22 | name = "ENV", 23 | value = environment, 24 | ) 25 | ] 26 | ) 27 | ] 28 | ) 29 | ) 30 | 31 | if __name__ == '__main__': 32 | main() 33 | --------------------------------------------------------------------------------