mirror of
https://github.com/dhall-lang/dhall-kubernetes.git
synced 2024-09-10 23:15:30 +03:00
Extract and check examples (#27)
* We move all the example code from the readme to the `examples` folder. * We provide a `scripts/build-readme.sh` script that inlines referenced examples in `README.md.in` and outputs `README.md`. The script also verifies that the output readme is the same as in version control. * We provide a `scripts/build-examples.py` script that builds the Yaml output for all examples. The script also verifies that the generated Yaml files are the same as in version control.
This commit is contained in:
parent
e132545c34
commit
4a7f02cd0d
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/result
|
||||
/result-*
|
125
README.md
125
README.md
@ -16,58 +16,62 @@ For a version compatible with a previous version, check out [this commit](https:
|
||||
|
||||
## Quick start
|
||||
|
||||
In the `types` folder you'll find the types for the Kubernetes definitions. E.g. [here's][Deployment] the type for a Deployment.
|
||||
In the `types` folder you'll find the types for the Kubernetes definitions. E.g.
|
||||
[here's][Deployment] the type for a Deployment.
|
||||
|
||||
Since _most_ of the fields in all definitions are optional, for better ergonomics while coding Dhall we also generate default values for all types, in the `default` folder.
|
||||
When some fields are required, the default value is a function whose input is a record of required fields, that returns the object with these fields set. E.g. the default for the Deployment is [this function][Deployment-default].
|
||||
Since _most_ of the fields in all definitions are optional, for better
|
||||
ergonomics while coding Dhall we also generate default values for all types, in
|
||||
the `default` folder. When some fields are required, the default value is a
|
||||
function whose input is a record of required fields, that returns the object
|
||||
with these fields set. E.g. the default for the Deployment is [this
|
||||
function][Deployment-default].
|
||||
|
||||
Since this might sound a bit abstract, let's go with some examples.
|
||||
Since this might sound a bit abstract, let's go with some examples. You can find
|
||||
these examples in the [`./examples` folder](./examples) and evaluate them there.
|
||||
|
||||
### Example: Deployment
|
||||
|
||||
Let's say we have several services, whose configuration has this type:
|
||||
```haskell
|
||||
-- Service.dhall
|
||||
-- examples/Service.dhall
|
||||
{ name : Text
|
||||
, host : Text
|
||||
, version : Text
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
So a configuration for a service might look like this:
|
||||
```haskell
|
||||
-- service-foo.dhall
|
||||
-- examples/service-foo.dhall
|
||||
{ name = "foo"
|
||||
, host = "foo.example.com"
|
||||
, version = "1.0.1"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
We can then make a Deployment object for this service:
|
||||
```haskell
|
||||
-- deployment.yaml.dhall
|
||||
|
||||
-- examples/deployment.dhall
|
||||
-- Prelude imports
|
||||
let map = https://raw.githubusercontent.com/dhall-lang/Prelude/e44284bc37a5808861dacd4c8bd13d18411cb961/List/map
|
||||
in let Some = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/Some
|
||||
in let None = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/None
|
||||
|
||||
-- import dhall-kubernetes types and defaults
|
||||
in let Deployment = ./types/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
in let Spec = ./types/io.k8s.api.apps.v1beta2.DeploymentSpec.dhall
|
||||
in let PodSpec = ./types/io.k8s.api.core.v1.PodSpec.dhall
|
||||
in let ContainerPort = ./types/io.k8s.api.core.v1.ContainerPort.dhall
|
||||
in let defaultDeployment = ./default/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
in let defaultMeta = ./default/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta.dhall
|
||||
in let defaultSpec = ./default/io.k8s.api.apps.v1beta2.DeploymentSpec.dhall
|
||||
in let defaultTemplate = ./default/io.k8s.api.core.v1.PodTemplateSpec.dhall
|
||||
in let defaultPodSpec = ./default/io.k8s.api.core.v1.PodSpec.dhall
|
||||
in let defaultSelector = ./default/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector.dhall
|
||||
in let defaultContainer = ./default/io.k8s.api.core.v1.Container.dhall
|
||||
in let defaultContainerPort = ./default/io.k8s.api.core.v1.ContainerPort.dhall
|
||||
|
||||
-- Our Service type
|
||||
in let Service = ./Service.dhall
|
||||
in let Deployment = ../types/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
in let Spec = ../types/io.k8s.api.apps.v1beta2.DeploymentSpec.dhall
|
||||
in let PodSpec = ../types/io.k8s.api.core.v1.PodSpec.dhall
|
||||
in let ContainerPort = ../types/io.k8s.api.core.v1.ContainerPort.dhall
|
||||
in let defaultDeployment = ../default/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
in let defaultMeta = ../default/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta.dhall
|
||||
in let defaultSpec = ../default/io.k8s.api.apps.v1beta2.DeploymentSpec.dhall
|
||||
in let defaultTemplate = ../default/io.k8s.api.core.v1.PodTemplateSpec.dhall
|
||||
in let defaultPodSpec = ../default/io.k8s.api.core.v1.PodSpec.dhall
|
||||
in let defaultSelector = ../default/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector.dhall
|
||||
in let defaultContainer = ../default/io.k8s.api.core.v1.Container.dhall
|
||||
in let defaultContainerPort = ../default/io.k8s.api.core.v1.ContainerPort.dhall
|
||||
|
||||
-- and our service
|
||||
in let fooService = ./service-foo.dhall
|
||||
@ -85,15 +89,15 @@ in let spec = defaultSpec
|
||||
} //
|
||||
{ spec = Some PodSpec (defaultPodSpec
|
||||
{ containers = [
|
||||
defaultContainer
|
||||
{ name = fooService.name } //
|
||||
{ image = Some Text "your-container-service.io/${fooService.name}:${fooService.version}"
|
||||
, imagePullPolicy = Some Text "Always"
|
||||
, ports = Some
|
||||
(List ContainerPort)
|
||||
[(defaultContainerPort {containerPort = 8080})]
|
||||
}
|
||||
]})
|
||||
defaultContainer
|
||||
{ name = fooService.name } //
|
||||
{ image = Some Text "your-container-service.io/${fooService.name}:${fooService.version}"
|
||||
, imagePullPolicy = Some Text "Always"
|
||||
, ports = Some
|
||||
(List ContainerPort)
|
||||
[(defaultContainerPort {containerPort = 8080})]
|
||||
}
|
||||
]})
|
||||
}
|
||||
} //
|
||||
{ replicas = Some Natural 2
|
||||
@ -111,12 +115,13 @@ in defaultDeployment
|
||||
We convert it to yaml with:
|
||||
|
||||
```bash
|
||||
dhall-to-yaml --omitNull < deployment.yaml.dhall
|
||||
dhall-to-yaml --omitNull < deployment.dhall
|
||||
```
|
||||
|
||||
And we get:
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
-- examples/out/deployment.yaml
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
spec:
|
||||
revisionHistoryLimit: 10
|
||||
@ -138,29 +143,31 @@ spec:
|
||||
replicas: 2
|
||||
metadata:
|
||||
name: foo
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Example: Ingress
|
||||
|
||||
Let's say we now want to generate an Ingress definition (for an Nginx Ingress) that contains TLS certs and routes for every service. It would be something like this:
|
||||
Let's say we now want to generate an Ingress definition (for an Nginx Ingress)
|
||||
that contains TLS certs and routes for every service. It would be something like
|
||||
this:
|
||||
```haskell
|
||||
-- ingress.yaml.dhall
|
||||
|
||||
-- examples/ingress.dhall
|
||||
-- Prelude imports
|
||||
let map = https://raw.githubusercontent.com/dhall-lang/Prelude/e44284bc37a5808861dacd4c8bd13d18411cb961/List/map
|
||||
in let Some = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/Some
|
||||
in let None = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/None
|
||||
|
||||
-- dhall-kubernetes types and defaults
|
||||
in let TLS = ./types/io.k8s.api.extensions.v1beta1.IngressTLS.dhall
|
||||
in let Rule = ./types/io.k8s.api.extensions.v1beta1.IngressRule.dhall
|
||||
in let RuleVal = ./types/io.k8s.api.extensions.v1beta1.HTTPIngressRuleValue.dhall
|
||||
in let Spec = ./types/io.k8s.api.extensions.v1beta1.IngressSpec.dhall
|
||||
in let Ingress = ./types/io.k8s.api.extensions.v1beta1.Ingress.dhall
|
||||
in let defaultIngress = ./default/io.k8s.api.extensions.v1beta1.Ingress.dhall
|
||||
in let defaultMeta = ./default/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta.dhall
|
||||
in let defaultSpec = ./default/io.k8s.api.extensions.v1beta1.IngressSpec.dhall
|
||||
in let TLS = ../types/io.k8s.api.extensions.v1beta1.IngressTLS.dhall
|
||||
in let Rule = ../types/io.k8s.api.extensions.v1beta1.IngressRule.dhall
|
||||
in let RuleVal = ../types/io.k8s.api.extensions.v1beta1.HTTPIngressRuleValue.dhall
|
||||
in let Spec = ../types/io.k8s.api.extensions.v1beta1.IngressSpec.dhall
|
||||
in let Ingress = ../types/io.k8s.api.extensions.v1beta1.Ingress.dhall
|
||||
in let defaultIngress = ../default/io.k8s.api.extensions.v1beta1.Ingress.dhall
|
||||
in let defaultMeta = ../default/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta.dhall
|
||||
in let defaultSpec = ../default/io.k8s.api.extensions.v1beta1.IngressSpec.dhall
|
||||
|
||||
-- Our Service type
|
||||
in let Service = ./Service.dhall
|
||||
@ -179,10 +186,14 @@ in let makeRule = \(service : Service) ->
|
||||
, servicePort = "80"
|
||||
}
|
||||
, path = None Text
|
||||
}]}}
|
||||
}]}}
|
||||
|
||||
-- Nginx ingress requires a default service as a catchall
|
||||
in let defaultService = { name = "default", host = "default.example.com" }
|
||||
in let defaultService =
|
||||
{ name = "default"
|
||||
, host = "default.example.com"
|
||||
, version = " 1.0"
|
||||
}
|
||||
|
||||
-- List of services
|
||||
in let fooService = ./service-foo.dhall
|
||||
@ -213,7 +224,7 @@ in defaultIngress
|
||||
{ name = "nginx" } //
|
||||
{ annotations = annotations }
|
||||
} //
|
||||
{ spec = spec } : Ingress
|
||||
{ spec = Some Spec spec } : Ingress
|
||||
|
||||
```
|
||||
|
||||
@ -225,6 +236,7 @@ dhall-to-yaml --omitNull < ingress.yaml.dhall
|
||||
|
||||
And we get:
|
||||
```yaml
|
||||
-- examples/out/ingress.yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
spec:
|
||||
@ -253,9 +265,26 @@ metadata:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
kubernetes.io/ingress.allow-http: 'false'
|
||||
name: nginx
|
||||
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Tests
|
||||
|
||||
All tests are defined in `release.nix`. We run these tests in CI in a [Hydra
|
||||
project][hydra-project]. You can run the tests locally with `nix build --no-link
|
||||
release.nix`.
|
||||
|
||||
### Changing the README
|
||||
|
||||
We build `README.md` from `docs/README.md.dhall` and check it into source control.
|
||||
The build script `./scripts/build-readme.sh` inlines source code from the
|
||||
`examples` directory. If you make changes to the readme or the examples you need
|
||||
to run `scripts/build-readme.sh`.
|
||||
|
||||
|
||||
[hydra-project]: http://hydra.dhall-lang.org/project/dhall-kubernetes
|
||||
[dhall-lang]: https://github.com/dhall-lang/dhall-lang
|
||||
[Deployment]: https://github.com/dhall-lang/dhall-kubernetes/blob/master/types/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
[Deployment-default]: https://github.com/dhall-lang/dhall-kubernetes/blob/master/default/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
|
108
docs/README.md.dhall
Normal file
108
docs/README.md.dhall
Normal file
@ -0,0 +1,108 @@
|
||||
''
|
||||
# `dhall-kubernetes`
|
||||
|
||||
Dhall bindings to Kubernetes.
|
||||
This will let you typecheck, template and modularize your Kubernetes definitions with [Dhall][dhall-lang].
|
||||
|
||||
## Prerequisites
|
||||
|
||||
**NOTE**: `dhall-kubernetes` requires at least version `1.14.0` of [the interpreter](https://github.com/dhall-lang/dhall-haskell).
|
||||
|
||||
You can install the latest version with the following:
|
||||
```bash
|
||||
stack install dhall dhall-json --resolver=nightly
|
||||
```
|
||||
|
||||
For a version compatible with a previous version, check out [this commit](https://github.com/dhall-lang/dhall-kubernetes/tree/b2357dcfa42a008efa203a850163d26f0d106e01).
|
||||
|
||||
## Quick start
|
||||
|
||||
In the `types` folder you'll find the types for the Kubernetes definitions. E.g.
|
||||
[here's][Deployment] the type for a Deployment.
|
||||
|
||||
Since _most_ of the fields in all definitions are optional, for better
|
||||
ergonomics while coding Dhall we also generate default values for all types, in
|
||||
the `default` folder. When some fields are required, the default value is a
|
||||
function whose input is a record of required fields, that returns the object
|
||||
with these fields set. E.g. the default for the Deployment is [this
|
||||
function][Deployment-default].
|
||||
|
||||
Since this might sound a bit abstract, let's go with some examples. You can find
|
||||
these examples in the [`./examples` folder](./examples) and evaluate them there.
|
||||
|
||||
### Example: Deployment
|
||||
|
||||
Let's say we have several services, whose configuration has this type:
|
||||
```haskell
|
||||
-- examples/Service.dhall
|
||||
${../examples/Service.dhall as Text}
|
||||
```
|
||||
|
||||
So a configuration for a service might look like this:
|
||||
```haskell
|
||||
-- examples/service-foo.dhall
|
||||
${../examples/service-foo.dhall as Text}
|
||||
```
|
||||
|
||||
We can then make a Deployment object for this service:
|
||||
```haskell
|
||||
-- examples/deployment.dhall
|
||||
${../examples/deployment.dhall as Text}
|
||||
```
|
||||
|
||||
We convert it to yaml with:
|
||||
|
||||
```bash
|
||||
dhall-to-yaml --omitNull < deployment.dhall
|
||||
```
|
||||
|
||||
And we get:
|
||||
```yaml
|
||||
-- examples/out/deployment.yaml
|
||||
${../examples/out/deployment.yaml as Text}
|
||||
```
|
||||
|
||||
|
||||
### Example: Ingress
|
||||
|
||||
Let's say we now want to generate an Ingress definition (for an Nginx Ingress)
|
||||
that contains TLS certs and routes for every service. It would be something like
|
||||
this:
|
||||
```haskell
|
||||
-- examples/ingress.dhall
|
||||
${../examples/ingress.dhall as Text}
|
||||
```
|
||||
|
||||
As usual we get the yaml out by running:
|
||||
|
||||
```bash
|
||||
dhall-to-yaml --omitNull < ingress.yaml.dhall
|
||||
```
|
||||
|
||||
And we get:
|
||||
```yaml
|
||||
-- examples/out/ingress.yaml
|
||||
${../examples/out/ingress.yaml as Text}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Tests
|
||||
|
||||
All tests are defined in `release.nix`. We run these tests in CI in a [Hydra
|
||||
project][hydra-project]. You can run the tests locally with `nix build --no-link
|
||||
release.nix`.
|
||||
|
||||
### Changing the README
|
||||
|
||||
We build `README.md` from `docs/README.md.dhall` and check it into source control.
|
||||
The build script `./scripts/build-readme.sh` inlines source code from the
|
||||
`examples` directory. If you make changes to the readme or the examples you need
|
||||
to run `scripts/build-readme.sh`.
|
||||
|
||||
|
||||
[hydra-project]: http://hydra.dhall-lang.org/project/dhall-kubernetes
|
||||
[dhall-lang]: https://github.com/dhall-lang/dhall-lang
|
||||
[Deployment]: https://github.com/dhall-lang/dhall-kubernetes/blob/master/types/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
[Deployment-default]: https://github.com/dhall-lang/dhall-kubernetes/blob/master/default/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
''
|
4
examples/Service.dhall
Normal file
4
examples/Service.dhall
Normal file
@ -0,0 +1,4 @@
|
||||
{ name : Text
|
||||
, host : Text
|
||||
, version : Text
|
||||
}
|
55
examples/deployment.dhall
Normal file
55
examples/deployment.dhall
Normal file
@ -0,0 +1,55 @@
|
||||
-- Prelude imports
|
||||
let map = https://raw.githubusercontent.com/dhall-lang/Prelude/e44284bc37a5808861dacd4c8bd13d18411cb961/List/map
|
||||
in let Some = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/Some
|
||||
in let None = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/None
|
||||
|
||||
-- import dhall-kubernetes types and defaults
|
||||
in let Deployment = ../types/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
in let Spec = ../types/io.k8s.api.apps.v1beta2.DeploymentSpec.dhall
|
||||
in let PodSpec = ../types/io.k8s.api.core.v1.PodSpec.dhall
|
||||
in let ContainerPort = ../types/io.k8s.api.core.v1.ContainerPort.dhall
|
||||
in let defaultDeployment = ../default/io.k8s.api.apps.v1beta2.Deployment.dhall
|
||||
in let defaultMeta = ../default/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta.dhall
|
||||
in let defaultSpec = ../default/io.k8s.api.apps.v1beta2.DeploymentSpec.dhall
|
||||
in let defaultTemplate = ../default/io.k8s.api.core.v1.PodTemplateSpec.dhall
|
||||
in let defaultPodSpec = ../default/io.k8s.api.core.v1.PodSpec.dhall
|
||||
in let defaultSelector = ../default/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector.dhall
|
||||
in let defaultContainer = ../default/io.k8s.api.core.v1.Container.dhall
|
||||
in let defaultContainerPort = ../default/io.k8s.api.core.v1.ContainerPort.dhall
|
||||
|
||||
-- and our service
|
||||
in let fooService = ./service-foo.dhall
|
||||
|
||||
-- Generate the DeploymentSpec for the service
|
||||
in let selector = Some
|
||||
(List { mapKey : Text, mapValue : Text })
|
||||
[{ mapKey = "app", mapValue = fooService.name }]
|
||||
|
||||
in let spec = defaultSpec
|
||||
{ selector = defaultSelector // { matchLabels = selector }
|
||||
, template = defaultTemplate
|
||||
{ metadata = defaultMeta
|
||||
{ name = fooService.name } // { labels = selector }
|
||||
} //
|
||||
{ spec = Some PodSpec (defaultPodSpec
|
||||
{ containers = [
|
||||
defaultContainer
|
||||
{ name = fooService.name } //
|
||||
{ image = Some Text "your-container-service.io/${fooService.name}:${fooService.version}"
|
||||
, imagePullPolicy = Some Text "Always"
|
||||
, ports = Some
|
||||
(List ContainerPort)
|
||||
[(defaultContainerPort {containerPort = 8080})]
|
||||
}
|
||||
]})
|
||||
}
|
||||
} //
|
||||
{ replicas = Some Natural 2
|
||||
, revisionHistoryLimit = Some Natural 10
|
||||
}
|
||||
|
||||
-- and here's the Deployment
|
||||
in defaultDeployment
|
||||
{ metadata = defaultMeta { name = fooService.name }
|
||||
} //
|
||||
{ spec = Some Spec spec } : Deployment
|
71
examples/ingress.dhall
Normal file
71
examples/ingress.dhall
Normal file
@ -0,0 +1,71 @@
|
||||
-- Prelude imports
|
||||
let map = https://raw.githubusercontent.com/dhall-lang/Prelude/e44284bc37a5808861dacd4c8bd13d18411cb961/List/map
|
||||
in let Some = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/Some
|
||||
in let None = https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/Optional/None
|
||||
|
||||
-- dhall-kubernetes types and defaults
|
||||
in let TLS = ../types/io.k8s.api.extensions.v1beta1.IngressTLS.dhall
|
||||
in let Rule = ../types/io.k8s.api.extensions.v1beta1.IngressRule.dhall
|
||||
in let RuleVal = ../types/io.k8s.api.extensions.v1beta1.HTTPIngressRuleValue.dhall
|
||||
in let Spec = ../types/io.k8s.api.extensions.v1beta1.IngressSpec.dhall
|
||||
in let Ingress = ../types/io.k8s.api.extensions.v1beta1.Ingress.dhall
|
||||
in let defaultIngress = ../default/io.k8s.api.extensions.v1beta1.Ingress.dhall
|
||||
in let defaultMeta = ../default/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta.dhall
|
||||
in let defaultSpec = ../default/io.k8s.api.extensions.v1beta1.IngressSpec.dhall
|
||||
|
||||
-- Our Service type
|
||||
in let Service = ./Service.dhall
|
||||
|
||||
-- Given a service, make a TLS definition with their host and certificate
|
||||
in let makeTLS = \(service : Service) ->
|
||||
{ hosts = Some (List Text) [ service.host ]
|
||||
, secretName = Some Text "${service.name}-certificate"
|
||||
}
|
||||
|
||||
-- Given a service, make an Ingress Rule
|
||||
in let makeRule = \(service : Service) ->
|
||||
{ host = Some Text service.host
|
||||
, http = Some RuleVal
|
||||
{ paths = [ { backend = { serviceName = service.name
|
||||
, servicePort = "80"
|
||||
}
|
||||
, path = None Text
|
||||
}]}}
|
||||
|
||||
-- Nginx ingress requires a default service as a catchall
|
||||
in let defaultService =
|
||||
{ name = "default"
|
||||
, host = "default.example.com"
|
||||
, version = " 1.0"
|
||||
}
|
||||
|
||||
-- List of services
|
||||
in let fooService = ./service-foo.dhall
|
||||
in let services =
|
||||
[ fooService
|
||||
, defaultService
|
||||
]
|
||||
|
||||
-- Some metadata annotations
|
||||
-- NOTE: `dhall-to-yaml` will generate a record with arbitrary keys from a list
|
||||
-- of records where mapKey is the key and mapValue is the value of that key
|
||||
in let genericRecord = List { mapKey : Text, mapValue : Text }
|
||||
in let kv = \(k : Text) -> \(v : Text) -> { mapKey = k, mapValue = v }
|
||||
|
||||
in let annotations = Some genericRecord
|
||||
[ kv "kubernetes.io/ingress.class" "nginx"
|
||||
, kv "kubernetes.io/ingress.allow-http" "false"
|
||||
]
|
||||
|
||||
-- Generate spec from services
|
||||
in let spec = defaultSpec //
|
||||
{ tls = Some (List TLS) (map Service TLS makeTLS services)
|
||||
, rules = Some (List Rule) (map Service Rule makeRule services)
|
||||
}
|
||||
|
||||
in defaultIngress
|
||||
{ metadata = defaultMeta
|
||||
{ name = "nginx" } //
|
||||
{ annotations = annotations }
|
||||
} //
|
||||
{ spec = Some Spec spec } : Ingress
|
22
examples/out/deployment.yaml
Normal file
22
examples/out/deployment.yaml
Normal file
@ -0,0 +1,22 @@
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
spec:
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: foo
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: your-container-service.io/foo:1.0.1
|
||||
imagePullPolicy: Always
|
||||
name: foo
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
metadata:
|
||||
name: foo
|
||||
labels:
|
||||
app: foo
|
||||
replicas: 2
|
||||
metadata:
|
||||
name: foo
|
28
examples/out/ingress.yaml
Normal file
28
examples/out/ingress.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- backend:
|
||||
servicePort: '80'
|
||||
serviceName: foo
|
||||
host: foo.example.com
|
||||
- http:
|
||||
paths:
|
||||
- backend:
|
||||
servicePort: '80'
|
||||
serviceName: default
|
||||
host: default.example.com
|
||||
tls:
|
||||
- hosts:
|
||||
- foo.example.com
|
||||
secretName: foo-certificate
|
||||
- hosts:
|
||||
- default.example.com
|
||||
secretName: default-certificate
|
||||
metadata:
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
kubernetes.io/ingress.allow-http: 'false'
|
||||
name: nginx
|
4
examples/service-foo.dhall
Normal file
4
examples/service-foo.dhall
Normal file
@ -0,0 +1,4 @@
|
||||
{ name = "foo"
|
||||
, host = "foo.example.com"
|
||||
, version = "1.0.1"
|
||||
}
|
67
release.nix
67
release.nix
@ -1,34 +1,55 @@
|
||||
let
|
||||
pkgs = import ./nixpkgs.nix;
|
||||
|
||||
dhall-kubernetes-smoketests =
|
||||
pkgs.runCommand
|
||||
"all-generated-files-compile"
|
||||
{ nativeBuildInputs = [
|
||||
pkgs.python3
|
||||
pkgs.bash
|
||||
pkgs.dhall
|
||||
pkgs.glibcLocales
|
||||
];
|
||||
}
|
||||
nativeBuildInputs = [
|
||||
pkgs.git
|
||||
pkgs.python3
|
||||
pkgs.bash
|
||||
pkgs.dhall
|
||||
pkgs.dhall-json
|
||||
pkgs.dhall-text
|
||||
pkgs.glibcLocales
|
||||
];
|
||||
|
||||
runCommand = name: script:
|
||||
pkgs.runCommand name { inherit nativeBuildInputs; } script;
|
||||
|
||||
generatedFilesCompile =
|
||||
runCommand
|
||||
"generated-files-compile"
|
||||
''
|
||||
cd ${./.}
|
||||
LC_ALL=en_US.UTF-8 python3 ${./check-source.py}
|
||||
LC_ALL=en_US.UTF-8 ./scripts/check-source.py
|
||||
|
||||
touch $out
|
||||
'';
|
||||
|
||||
# Derivation that trivially depends on the current directory so that Hydra's
|
||||
# pull request builder always posts a GitHub status on each revision
|
||||
pwd = pkgs.runCommand "pwd" { here = ./.; } "touch $out";
|
||||
buildReadme =
|
||||
runCommand
|
||||
"build-readme"
|
||||
''
|
||||
cd ${./.}
|
||||
./scripts/build-readme.sh $out
|
||||
|
||||
in
|
||||
{ dhall-kubernetes = pkgs.releaseTools.aggregate {
|
||||
name = "dhall-kubernetes";
|
||||
diff --unified --color=always README.md $out
|
||||
'';
|
||||
|
||||
constituents = [
|
||||
dhall-kubernetes-smoketests
|
||||
pwd
|
||||
];
|
||||
};
|
||||
}
|
||||
validateExamples =
|
||||
runCommand
|
||||
"validate-examples"
|
||||
''
|
||||
cd ${./.}
|
||||
mkdir $out
|
||||
LC_ALL=en_US.UTF-8 ./scripts/build-examples.py $out
|
||||
'';
|
||||
|
||||
in {
|
||||
dhall-kubernetes = pkgs.releaseTools.aggregate {
|
||||
name = "dhall-kubernetes";
|
||||
constituents = [
|
||||
generatedFilesCompile
|
||||
validateExamples
|
||||
buildReadme
|
||||
];
|
||||
};
|
||||
}
|
||||
|
71
scripts/build-examples.py
Executable file
71
scripts/build-examples.py
Executable file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Build YAML files from the example Dhall sources.
|
||||
#
|
||||
# An optional second argument determines the directory to write the YAML
|
||||
# files to. Defaults to the exmaples directory.
|
||||
#
|
||||
# Also checks that the generated files do not differ from what is
|
||||
# checked into source control. We list all generated files that differ
|
||||
# and exit with status code 1 if the list is non-empty.
|
||||
|
||||
import os
|
||||
from subprocess import run, DEVNULL
|
||||
import sys
|
||||
|
||||
examples_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'examples'))
|
||||
examples = [
|
||||
'deployment',
|
||||
'ingress'
|
||||
]
|
||||
|
||||
TERM_FAIL = '\033[91m'
|
||||
TERM_CLEAR = '\033[0m'
|
||||
|
||||
|
||||
def check_clean(path_1, path_2):
|
||||
if path_1 == path_2:
|
||||
cmd = ['git', 'diff', '--exit-code', '--', path_1]
|
||||
else:
|
||||
cmd = ['diff', '--unified', '--', path_1, path_2]
|
||||
|
||||
result = run(cmd, check=False, stdout=DEVNULL)
|
||||
if result.returncode == 0:
|
||||
return True
|
||||
elif result.returncode == 1:
|
||||
return False
|
||||
else:
|
||||
# Raises a `CalledProcessError`
|
||||
result.check_returncode()
|
||||
|
||||
|
||||
def build_yaml (example, out_dir):
|
||||
source = os.path.join(examples_dir, example + '.dhall')
|
||||
print('Building {}'.format(source))
|
||||
target = os.path.join(out_dir, example + '.yaml')
|
||||
expected = os.path.join(examples_dir, 'out', example + '.yaml')
|
||||
cmd = 'dhall-to-yaml --omitNull <<< "./{source}" >{target}'.format(source=source, target=target)
|
||||
run(cmd, shell=True, executable='bash', check=True)
|
||||
return check_clean(expected, target)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) >= 2:
|
||||
out_dir = sys.argv[1]
|
||||
else:
|
||||
out_dir = os.path.join(examples_dir, 'out')
|
||||
|
||||
clean_failures = []
|
||||
for example in examples:
|
||||
is_clean = build_yaml(example, out_dir)
|
||||
if is_clean == False:
|
||||
clean_failures.append(example + '.yaml')
|
||||
|
||||
if len(clean_failures) > 0:
|
||||
print(TERM_FAIL + 'Clean check failed. The following files differ' + TERM_CLEAR)
|
||||
for failure in clean_failures:
|
||||
print(' ' + failure)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
9
scripts/build-readme.sh
Executable file
9
scripts/build-readme.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ -z $1 ]]; then
|
||||
output=README.md
|
||||
else
|
||||
output="$1"
|
||||
fi
|
||||
|
||||
LC_ALL=en_US.UTF-8 dhall-to-text <<< './docs/README.md.dhall' > $output
|
Loading…
Reference in New Issue
Block a user