diff --git a/build/Dockerfile b/build/Dockerfile index bb816e1..386d814 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,10 +1,10 @@ FROM quay.io/operator-framework/ansible-operator:v0.13.0 # dhall versions and digests -ARG DHALL_VERSION=1.30.0 -ARG DHALL_JSON_VERSION=1.6.2 -ARG DHALL_JSON_DIGEST=ea37627c4e19789af33def099d4cb145b874c03b4d5b98cb33ce06be1debf4f3 -ARG DHALL_LANG_REF=v14.0.0 +ARG DHALL_VERSION=1.33.1 +ARG DHALL_JSON_VERSION=1.7.0 +ARG DHALL_JSON_DIGEST=cc9fc70e492d35a3986183b589a435653e782f67cda51d33a935dff1ddd15aec +ARG DHALL_LANG_REF=v17.0.0 ARG DHALL_KUBE_REF=v4.0.0 # kubectl versions and digests diff --git a/conf/CertManager.dhall b/conf/CertManager.dhall index 9dfa026..0979b27 100644 --- a/conf/CertManager.dhall +++ b/conf/CertManager.dhall @@ -32,11 +32,11 @@ let CertificateSpec = , issuerRef : { name : Text, kind : Text, group : Text } } , default = - { isCA = None Bool - , usages = None (List Text) - , commonName = None Text - , dnsNames = None (List Text) - } + { isCA = None Bool + , usages = None (List Text) + , commonName = None Text + , dnsNames = None (List Text) + } } let Certificate = @@ -47,7 +47,7 @@ let Certificate = , spec : CertificateSpec.Type } , default = - { apiVersion = "cert-manager.io/v1alpha3", kind = "Certificate" } + { apiVersion = "cert-manager.io/v1alpha3", kind = "Certificate" } } let Union = @@ -56,9 +56,4 @@ let Union = | Certificate : Certificate.Type > -in { IssuerSpec = IssuerSpec - , Issuer = Issuer - , CertificateSpec = CertificateSpec - , Certificate = Certificate - , Union = Union - } +in { IssuerSpec, Issuer, CertificateSpec, Certificate, Union } diff --git a/conf/Prelude.dhall b/conf/Prelude.dhall index 5a78300..b83b4cd 100644 --- a/conf/Prelude.dhall +++ b/conf/Prelude.dhall @@ -24,5 +24,5 @@ * https://github.com/dhall-lang/dhall-nethack/blob/master/Prelude.dhall -} env:DHALL_PRELUDE -? https://prelude.dhall-lang.org/v13.0.0/package.dhall sha256:4aa8581954f7734d09b7b21fddbf5d8df901a44b54b4ef26ea71db92de0b1a12 -? https://prelude.dhall-lang.org/v13.0.0/package.dhall +? https://prelude.dhall-lang.org/v17.0.0/package.dhall sha256:10db3c919c25e9046833df897a8ffe2701dc390fa0893d958c3430524be5a43e +? https://prelude.dhall-lang.org/v17.0.0/package.dhall diff --git a/conf/zuul/components/Database.dhall b/conf/zuul/components/Database.dhall index 57ded9e..b10bc1d 100644 --- a/conf/zuul/components/Database.dhall +++ b/conf/zuul/components/Database.dhall @@ -4,41 +4,41 @@ let F = ../functions.dhall let db-volumes = [ F.Volume::{ name = "pg-data", dir = "/var/lib/pg/" } ] -in \(app-name : Text) - -> \ ( db-internal-password-env - : forall (env-name : Text) -> List Kubernetes.EnvVar.Type - ) - -> F.KubernetesComponent::{ - , Service = Some (F.mkService app-name "db" "pg" 5432) - , StatefulSet = Some - ( F.mkStatefulSet - app-name - F.Component::{ +in \(app-name : Text) -> + \ ( db-internal-password-env + : forall (env-name : Text) -> List Kubernetes.EnvVar.Type + ) -> + F.KubernetesComponent::{ + , Service = Some (F.mkService app-name "db" "pg" 5432) + , StatefulSet = Some + ( F.mkStatefulSet + app-name + F.Component::{ + , name = "db" + , count = 1 + , data-dir = db-volumes + , claim-size = 1 + , container = Kubernetes.Container::{ , name = "db" - , count = 1 - , data-dir = db-volumes - , claim-size = 1 - , container = Kubernetes.Container::{ - , name = "db" - , image = Some "docker.io/library/postgres:12.1" - , imagePullPolicy = Some "IfNotPresent" - , ports = Some - [ Kubernetes.ContainerPort::{ - , name = Some "pg" - , containerPort = 5432 - } - ] - , env = Some - ( F.mkEnvVarValue - ( toMap - { POSTGRES_USER = "zuul" - , PGDATA = "/var/lib/pg/data" - } - ) - # db-internal-password-env "POSTGRES_PASSWORD" - ) - , volumeMounts = Some (F.mkVolumeMount db-volumes) - } + , image = Some "docker.io/library/postgres:12.1" + , imagePullPolicy = Some "IfNotPresent" + , ports = Some + [ Kubernetes.ContainerPort::{ + , name = Some "pg" + , containerPort = 5432 + } + ] + , env = Some + ( F.mkEnvVarValue + ( toMap + { POSTGRES_USER = "zuul" + , PGDATA = "/var/lib/pg/data" + } + ) + # db-internal-password-env "POSTGRES_PASSWORD" + ) + , volumeMounts = Some (F.mkVolumeMount db-volumes) } - ) - } + } + ) + } diff --git a/conf/zuul/components/Executor.dhall b/conf/zuul/components/Executor.dhall index c80ca89..1b20670 100644 --- a/conf/zuul/components/Executor.dhall +++ b/conf/zuul/components/Executor.dhall @@ -6,63 +6,63 @@ let InputExecutor = (../input.dhall).Executor.Type let JobVolume = (../input.dhall).JobVolume.Type -in \(app-name : Text) - -> \(input-executor : InputExecutor) - -> \(data-dir : List F.Volume.Type) - -> \(volumes : List F.Volume.Type) - -> \(env : List Kubernetes.EnvVar.Type) - -> \(jobVolumes : Optional (List JobVolume)) - -> F.KubernetesComponent::{ - , Service = Some (F.mkService app-name "executor" "finger" 7900) - , StatefulSet = Some - ( F.mkStatefulSet - app-name - F.Component::{ +in \(app-name : Text) -> + \(input-executor : InputExecutor) -> + \(data-dir : List F.Volume.Type) -> + \(volumes : List F.Volume.Type) -> + \(env : List Kubernetes.EnvVar.Type) -> + \(jobVolumes : Optional (List JobVolume)) -> + F.KubernetesComponent::{ + , Service = Some (F.mkService app-name "executor" "finger" 7900) + , StatefulSet = Some + ( F.mkStatefulSet + app-name + F.Component::{ + , name = "executor" + , count = 1 + , data-dir + , volumes + , extra-volumes = + let job-volumes = + F.mkJobVolume + Kubernetes.Volume.Type + (\(job-volume : JobVolume) -> job-volume.volume) + jobVolumes + + in job-volumes + , claim-size = 0 + , container = Kubernetes.Container::{ , name = "executor" - , count = 1 - , data-dir = data-dir - , volumes = volumes - , extra-volumes = - let job-volumes = + , image = input-executor.image + , args = Some [ "zuul-executor", "-d" ] + , imagePullPolicy = Some "IfNotPresent" + , ports = Some + [ Kubernetes.ContainerPort::{ + , name = Some "finger" + , containerPort = 7900 + } + ] + , env = Some env + , volumeMounts = + let job-volumes-mount = F.mkJobVolume - Kubernetes.Volume.Type - (\(job-volume : JobVolume) -> job-volume.volume) + F.Volume.Type + ( \(job-volume : JobVolume) -> + F.Volume::{ + , name = job-volume.volume.name + , dir = job-volume.dir + } + ) jobVolumes - in job-volumes - , claim-size = 0 - , container = Kubernetes.Container::{ - , name = "executor" - , image = input-executor.image - , args = Some [ "zuul-executor", "-d" ] - , imagePullPolicy = Some "IfNotPresent" - , ports = Some - [ Kubernetes.ContainerPort::{ - , name = Some "finger" - , containerPort = 7900 - } - ] - , env = Some env - , volumeMounts = - let job-volumes-mount = - F.mkJobVolume - F.Volume.Type - ( \(job-volume : JobVolume) - -> F.Volume::{ - , name = job-volume.volume.name - , dir = job-volume.dir - } - ) - jobVolumes - - in Some - ( F.mkVolumeMount - (data-dir # volumes # job-volumes-mount) - ) - , securityContext = Some Kubernetes.SecurityContext::{ - , privileged = Some True - } + in Some + ( F.mkVolumeMount + (data-dir # volumes # job-volumes-mount) + ) + , securityContext = Some Kubernetes.SecurityContext::{ + , privileged = Some True } } - ) - } + } + ) + } diff --git a/conf/zuul/components/Merger.dhall b/conf/zuul/components/Merger.dhall index e2dc490..537efa5 100644 --- a/conf/zuul/components/Merger.dhall +++ b/conf/zuul/components/Merger.dhall @@ -4,28 +4,28 @@ let F = ../functions.dhall let InputMerger = (../input.dhall).Merger.Type -in \(app-name : Text) - -> \(input-merger : InputMerger) - -> \(data-dir : List F.Volume.Type) - -> \(volumes : List F.Volume.Type) - -> \(env : List Kubernetes.EnvVar.Type) - -> F.KubernetesComponent::{ - , Deployment = Some - ( F.mkDeployment - app-name - F.Component::{ +in \(app-name : Text) -> + \(input-merger : InputMerger) -> + \(data-dir : List F.Volume.Type) -> + \(volumes : List F.Volume.Type) -> + \(env : List Kubernetes.EnvVar.Type) -> + F.KubernetesComponent::{ + , Deployment = Some + ( F.mkDeployment + app-name + F.Component::{ + , name = "merger" + , count = 1 + , data-dir + , volumes + , container = Kubernetes.Container::{ , name = "merger" - , count = 1 - , data-dir = data-dir - , volumes = volumes - , container = Kubernetes.Container::{ - , name = "merger" - , image = input-merger.image - , args = Some [ "zuul-merger", "-d" ] - , imagePullPolicy = Some "IfNotPresent" - , env = Some env - , volumeMounts = Some (F.mkVolumeMount (data-dir # volumes)) - } + , image = input-merger.image + , args = Some [ "zuul-merger", "-d" ] + , imagePullPolicy = Some "IfNotPresent" + , env = Some env + , volumeMounts = Some (F.mkVolumeMount (data-dir # volumes)) } - ) - } + } + ) + } diff --git a/conf/zuul/components/Preview.dhall b/conf/zuul/components/Preview.dhall index 6e205d6..27288c6 100644 --- a/conf/zuul/components/Preview.dhall +++ b/conf/zuul/components/Preview.dhall @@ -4,36 +4,36 @@ let F = ../functions.dhall let InputPreview = (../input.dhall).Preview.Type -in \(app-name : Text) - -> \(input-preview : InputPreview) - -> \(data-dir : List F.Volume.Type) - -> F.KubernetesComponent::{ - , Service = Some (F.mkService app-name "preview" "preview" 80) - , Deployment = Some - ( F.mkDeployment - app-name - F.Component::{ +in \(app-name : Text) -> + \(input-preview : InputPreview) -> + \(data-dir : List F.Volume.Type) -> + F.KubernetesComponent::{ + , Service = Some (F.mkService app-name "preview" "preview" 80) + , Deployment = Some + ( F.mkDeployment + app-name + F.Component::{ + , name = "preview" + , count = F.defaultNat input-preview.count 0 + , data-dir + , container = Kubernetes.Container::{ , name = "preview" - , count = F.defaultNat input-preview.count 0 - , data-dir = data-dir - , container = Kubernetes.Container::{ - , name = "preview" - , image = input-preview.image - , imagePullPolicy = Some "IfNotPresent" - , ports = Some - [ Kubernetes.ContainerPort::{ - , name = Some "preview" - , containerPort = 80 - } - ] - , env = Some - [ Kubernetes.EnvVar::{ - , name = "ZUUL_API_URL" - , value = Some "http://web:9000" - } - ] - , volumeMounts = Some (F.mkVolumeMount data-dir) - } + , image = input-preview.image + , imagePullPolicy = Some "IfNotPresent" + , ports = Some + [ Kubernetes.ContainerPort::{ + , name = Some "preview" + , containerPort = 80 + } + ] + , env = Some + [ Kubernetes.EnvVar::{ + , name = "ZUUL_API_URL" + , value = Some "http://web:9000" + } + ] + , volumeMounts = Some (F.mkVolumeMount data-dir) } - ) - } + } + ) + } diff --git a/conf/zuul/components/Registry.dhall b/conf/zuul/components/Registry.dhall index 64dd91e..1624f75 100644 --- a/conf/zuul/components/Registry.dhall +++ b/conf/zuul/components/Registry.dhall @@ -7,65 +7,61 @@ let F = ../functions.dhall let InputRegistry = (../input.dhall).Registry.Type let registry-volumes = - \(app-name : Text) - -> [ F.Volume::{ - , name = app-name ++ "-registry-tls" - , dir = "/etc/zuul-registry" - } - ] + \(app-name : Text) -> + [ F.Volume::{ + , name = app-name ++ "-registry-tls" + , dir = "/etc/zuul-registry" + } + ] let registry-env = - \(app-name : Text) - -> F.mkEnvVarSecret - ( Prelude.List.map - Text - F.EnvSecret - ( \(key : Text) - -> { name = "ZUUL_REGISTRY_${key}" - , key = key - , secret = "${app-name}-registry-user-rw" - } - ) - [ "secret", "username", "password" ] - ) - -in \(app-name : Text) - -> \(input-registry : InputRegistry) - -> \(data-dir : List F.Volume.Type) - -> \(volumes : List F.Volume.Type) - -> F.KubernetesComponent::{ - , Service = Some (F.mkService app-name "registry" "registry" 9000) - , StatefulSet = Some - ( F.mkStatefulSet - app-name - F.Component::{ - , name = "registry" - , count = F.defaultNat input-registry.count 0 - , data-dir = data-dir - , volumes = volumes # registry-volumes app-name - , claim-size = F.defaultNat input-registry.storage-size 20 - , container = Kubernetes.Container::{ - , name = "registry" - , image = input-registry.image - , args = Some - [ "zuul-registry" - , "-c" - , "/etc/zuul/registry.yaml" - , "serve" - ] - , imagePullPolicy = Some "IfNotPresent" - , ports = Some - [ Kubernetes.ContainerPort::{ - , name = Some "registry" - , containerPort = 9000 - } - ] - , env = Some (registry-env app-name) - , volumeMounts = Some - ( F.mkVolumeMount - (data-dir # volumes # registry-volumes app-name) - ) + \(app-name : Text) -> + F.mkEnvVarSecret + ( Prelude.List.map + Text + F.EnvSecret + ( \(key : Text) -> + { name = "ZUUL_REGISTRY_${key}" + , key + , secret = "${app-name}-registry-user-rw" } + ) + [ "secret", "username", "password" ] + ) + +in \(app-name : Text) -> + \(input-registry : InputRegistry) -> + \(data-dir : List F.Volume.Type) -> + \(volumes : List F.Volume.Type) -> + F.KubernetesComponent::{ + , Service = Some (F.mkService app-name "registry" "registry" 9000) + , StatefulSet = Some + ( F.mkStatefulSet + app-name + F.Component::{ + , name = "registry" + , count = F.defaultNat input-registry.count 0 + , data-dir + , volumes = volumes # registry-volumes app-name + , claim-size = F.defaultNat input-registry.storage-size 20 + , container = Kubernetes.Container::{ + , name = "registry" + , image = input-registry.image + , args = Some + [ "zuul-registry", "-c", "/etc/zuul/registry.yaml", "serve" ] + , imagePullPolicy = Some "IfNotPresent" + , ports = Some + [ Kubernetes.ContainerPort::{ + , name = Some "registry" + , containerPort = 9000 + } + ] + , env = Some (registry-env app-name) + , volumeMounts = Some + ( F.mkVolumeMount + (data-dir # volumes # registry-volumes app-name) + ) } - ) - } + } + ) + } diff --git a/conf/zuul/components/Scheduler.dhall b/conf/zuul/components/Scheduler.dhall index 7fffcf3..855507b 100644 --- a/conf/zuul/components/Scheduler.dhall +++ b/conf/zuul/components/Scheduler.dhall @@ -4,36 +4,36 @@ let F = ../functions.dhall let InputScheduler = (../input.dhall).Scheduler.Type -in \(app-name : Text) - -> \(input-scheduler : InputScheduler) - -> \(data-dir : List F.Volume.Type) - -> \(volumes : List F.Volume.Type) - -> \(env : List Kubernetes.EnvVar.Type) - -> F.KubernetesComponent::{ - , Service = Some (F.mkService app-name "scheduler" "gearman" 4730) - , StatefulSet = Some - ( F.mkStatefulSet - app-name - F.Component::{ +in \(app-name : Text) -> + \(input-scheduler : InputScheduler) -> + \(data-dir : List F.Volume.Type) -> + \(volumes : List F.Volume.Type) -> + \(env : List Kubernetes.EnvVar.Type) -> + F.KubernetesComponent::{ + , Service = Some (F.mkService app-name "scheduler" "gearman" 4730) + , StatefulSet = Some + ( F.mkStatefulSet + app-name + F.Component::{ + , name = "scheduler" + , count = 1 + , data-dir + , volumes + , claim-size = 5 + , container = Kubernetes.Container::{ , name = "scheduler" - , count = 1 - , data-dir = data-dir - , volumes = volumes - , claim-size = 5 - , container = Kubernetes.Container::{ - , name = "scheduler" - , image = input-scheduler.image - , args = Some [ "zuul-scheduler", "-d" ] - , imagePullPolicy = Some "IfNotPresent" - , ports = Some - [ Kubernetes.ContainerPort::{ - , name = Some "gearman" - , containerPort = 4730 - } - ] - , env = Some env - , volumeMounts = Some (F.mkVolumeMount (data-dir # volumes)) - } + , image = input-scheduler.image + , args = Some [ "zuul-scheduler", "-d" ] + , imagePullPolicy = Some "IfNotPresent" + , ports = Some + [ Kubernetes.ContainerPort::{ + , name = Some "gearman" + , containerPort = 4730 + } + ] + , env = Some env + , volumeMounts = Some (F.mkVolumeMount (data-dir # volumes)) } - ) - } + } + ) + } diff --git a/conf/zuul/components/Web.dhall b/conf/zuul/components/Web.dhall index 7c9a305..c84f3d1 100644 --- a/conf/zuul/components/Web.dhall +++ b/conf/zuul/components/Web.dhall @@ -4,35 +4,35 @@ let F = ../functions.dhall let InputWeb = (../input.dhall).Web.Type -in \(app-name : Text) - -> \(input-web : InputWeb) - -> \(data-dir : List F.Volume.Type) - -> \(volumes : List F.Volume.Type) - -> \(env : List Kubernetes.EnvVar.Type) - -> F.KubernetesComponent::{ - , Service = Some (F.mkService app-name "web" "api" 9000) - , Deployment = Some - ( F.mkDeployment - app-name - F.Component::{ +in \(app-name : Text) -> + \(input-web : InputWeb) -> + \(data-dir : List F.Volume.Type) -> + \(volumes : List F.Volume.Type) -> + \(env : List Kubernetes.EnvVar.Type) -> + F.KubernetesComponent::{ + , Service = Some (F.mkService app-name "web" "api" 9000) + , Deployment = Some + ( F.mkDeployment + app-name + F.Component::{ + , name = "web" + , count = 1 + , data-dir + , volumes + , container = Kubernetes.Container::{ , name = "web" - , count = 1 - , data-dir = data-dir - , volumes = volumes - , container = Kubernetes.Container::{ - , name = "web" - , image = input-web.image - , args = Some [ "zuul-web", "-d" ] - , imagePullPolicy = Some "IfNotPresent" - , ports = Some - [ Kubernetes.ContainerPort::{ - , name = Some "api" - , containerPort = 9000 - } - ] - , env = Some env - , volumeMounts = Some (F.mkVolumeMount (data-dir # volumes)) - } + , image = input-web.image + , args = Some [ "zuul-web", "-d" ] + , imagePullPolicy = Some "IfNotPresent" + , ports = Some + [ Kubernetes.ContainerPort::{ + , name = Some "api" + , containerPort = 9000 + } + ] + , env = Some env + , volumeMounts = Some (F.mkVolumeMount (data-dir # volumes)) } - ) - } + } + ) + } diff --git a/conf/zuul/components/ZooKeeper.dhall b/conf/zuul/components/ZooKeeper.dhall index fdae1c1..0fd3670 100644 --- a/conf/zuul/components/ZooKeeper.dhall +++ b/conf/zuul/components/ZooKeeper.dhall @@ -10,41 +10,41 @@ let data-volumes = , F.Volume::{ name = "zk-dat", dir = "/var/lib/zookeeper/" } ] -in \(app-name : Text) - -> \(client-conf : List F.Volume.Type) - -> F.KubernetesComponent::{ - , Service = Some (F.mkService app-name "zk" "zk" 2281) - , StatefulSet = Some - ( F.mkStatefulSet - app-name - F.Component::{ +in \(app-name : Text) -> + \(client-conf : List F.Volume.Type) -> + F.KubernetesComponent::{ + , Service = Some (F.mkService app-name "zk" "zk" 2281) + , StatefulSet = Some + ( F.mkStatefulSet + app-name + F.Component::{ + , name = "zk" + , count = 1 + , data-dir = data-volumes + , volumes = client-conf + , claim-size = 1 + , container = Kubernetes.Container::{ , name = "zk" - , count = 1 - , data-dir = data-volumes - , volumes = client-conf - , claim-size = 1 - , container = Kubernetes.Container::{ - , name = "zk" - , command = Some - [ "sh" - , "-c" - , "cp /conf-tls/zoo.cfg /conf/ && " - ++ "cp /etc/zookeeper-tls/zk.pem /conf/zk.pem && " - ++ "cp /etc/zookeeper-tls/ca.crt /conf/ca.pem && " - ++ "chown zookeeper /conf/zoo.cfg /conf/zk.pem /conf/ca.pem && " - ++ "exec /docker-entrypoint.sh zkServer.sh start-foreground" - ] - , image = Some "docker.io/library/zookeeper" - , imagePullPolicy = Some "IfNotPresent" - , ports = Some - [ Kubernetes.ContainerPort::{ - , name = Some "zk" - , containerPort = 2281 - } - ] - , volumeMounts = Some - (F.mkVolumeMount (data-volumes # client-conf)) - } + , command = Some + [ "sh" + , "-c" + , "cp /conf-tls/zoo.cfg /conf/ && " + ++ "cp /etc/zookeeper-tls/zk.pem /conf/zk.pem && " + ++ "cp /etc/zookeeper-tls/ca.crt /conf/ca.pem && " + ++ "chown zookeeper /conf/zoo.cfg /conf/zk.pem /conf/ca.pem && " + ++ "exec /docker-entrypoint.sh zkServer.sh start-foreground" + ] + , image = Some "docker.io/library/zookeeper" + , imagePullPolicy = Some "IfNotPresent" + , ports = Some + [ Kubernetes.ContainerPort::{ + , name = Some "zk" + , containerPort = 2281 + } + ] + , volumeMounts = Some + (F.mkVolumeMount (data-volumes # client-conf)) } - ) - } + } + ) + } diff --git a/conf/zuul/files/nodepool.yaml.dhall b/conf/zuul/files/nodepool.yaml.dhall index f5f9016..266e8db 100644 --- a/conf/zuul/files/nodepool.yaml.dhall +++ b/conf/zuul/files/nodepool.yaml.dhall @@ -2,10 +2,10 @@ TODO: replace opaque Text by structured zk host list and tls configuration -} - \(zk-host : Text) --> '' - ${zk-host} +\(zk-host : Text) -> + '' + ${zk-host} - webapp: - port: 5000 - '' + webapp: + port: 5000 + '' diff --git a/conf/zuul/files/registry.yaml.dhall b/conf/zuul/files/registry.yaml.dhall index 5aa429c..f6ce554 100644 --- a/conf/zuul/files/registry.yaml.dhall +++ b/conf/zuul/files/registry.yaml.dhall @@ -1,20 +1,20 @@ {- This function converts a public-url Text to a registry.yaml file content -} - \(public-url : Text) --> '' - registry: - address: '0.0.0.0' - port: 9000 - public-url: ${public-url} - tls-cert: /etc/zuul-registry/tls.crt - tls-key: /etc/zuul-registry/tls.key - secret: "%(ZUUL_REGISTRY_secret)" - storage: - driver: filesystem - root: /var/lib/zuul - users: - - name: "%(ZUUL_REGISTRY_username)" - pass: "%(ZUUL_REGISTRY_password)" - access: write - '' +\(public-url : Text) -> + '' + registry: + address: '0.0.0.0' + port: 9000 + public-url: ${public-url} + tls-cert: /etc/zuul-registry/tls.crt + tls-key: /etc/zuul-registry/tls.key + secret: "%(ZUUL_REGISTRY_secret)" + storage: + driver: filesystem + root: /var/lib/zuul + users: + - name: "%(ZUUL_REGISTRY_username)" + pass: "%(ZUUL_REGISTRY_password)" + access: write + '' diff --git a/conf/zuul/files/zoo.cfg.dhall b/conf/zuul/files/zoo.cfg.dhall index 73c935d..790b488 100644 --- a/conf/zuul/files/zoo.cfg.dhall +++ b/conf/zuul/files/zoo.cfg.dhall @@ -1,23 +1,23 @@ {- This function converts a client-dir and server-dir Text to a zoo.cfg file content -} - \(client-dir : Text) --> \(server-dir : Text) --> '' - dataDir=/data - dataLogDir=/datalog - tickTime=2000 - initLimit=5 - syncLimit=2 - autopurge.snapRetainCount=3 - autopurge.purgeInterval=0 - maxClientCnxns=60 - standaloneEnabled=true - admin.enableServer=true - server.1=0.0.0.0:2888:3888 +\(client-dir : Text) -> +\(server-dir : Text) -> + '' + dataDir=/data + dataLogDir=/datalog + tickTime=2000 + initLimit=5 + syncLimit=2 + autopurge.snapRetainCount=3 + autopurge.purgeInterval=0 + maxClientCnxns=60 + standaloneEnabled=true + admin.enableServer=true + server.1=0.0.0.0:2888:3888 - # TLS configuration - secureClientPort=2281 - serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory - ssl.keyStore.location=${server-dir}/zk.pem - ssl.trustStore.location=${client-dir}/ca.pem - '' + # TLS configuration + secureClientPort=2281 + serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory + ssl.keyStore.location=${server-dir}/zk.pem + ssl.trustStore.location=${client-dir}/ca.pem + '' diff --git a/conf/zuul/files/zuul.conf.dhall b/conf/zuul/files/zuul.conf.dhall index 4a56418..23005a4 100644 --- a/conf/zuul/files/zuul.conf.dhall +++ b/conf/zuul/files/zuul.conf.dhall @@ -3,192 +3,190 @@ TODO: replace input schemas by the required attributes. -} - \(input : (../input.dhall).Input.Type) --> \(zk-hosts : Text) --> let Prelude = ../../Prelude.dhall +\(input : (../input.dhall).Input.Type) -> +\(zk-hosts : Text) -> + let Prelude = ../../Prelude.dhall - let Schemas = ../input.dhall + let Schemas = ../input.dhall - let F = ../functions.dhall + let F = ../functions.dhall - let {- This is a high level method. It takes: - * a Connection type such as `Schemas.Gerrit.Type`, - * an Optional List of that type - * a function that goes from that type to a zuul.conf text blob + let {- This is a high level method. It takes: + * a Connection type such as `Schemas.Gerrit.Type`, + * an Optional List of that type + * a function that goes from that type to a zuul.conf text blob - Then it returns a text blob for all the connections - -} mkConns = - \(type : Type) - -> \(list : Optional (List type)) - -> \(f : type -> Text) - -> F.newlineSep - ( merge - { None = [] : List Text - , Some = Prelude.List.map type Text f - } - list - ) - - let merger-email = - F.defaultText input.merger.git_user_email "${input.name}@localhost" - - let merger-user = F.defaultText input.merger.git_user_name "Zuul" - - let executor-key-name = F.defaultText input.executor.ssh_key.key "id_rsa" - - let sched-config = F.defaultText input.scheduler.config.key "main.yaml" - - let web-url = F.defaultText input.web.status_url "http://web:9000" - - let extra-kube-path = "/etc/nodepool-kubernetes/" - - let db-uri = - merge - { None = "postgresql://zuul:%(ZUUL_DB_PASSWORD)s@db/zuul" - , Some = \(some : Schemas.UserSecret.Type) -> "%(ZUUL_DB_URI)s" - } - input.database - - let gerrits-conf = - mkConns - Schemas.Gerrit.Type - input.connections.gerrits - ( \(gerrit : Schemas.Gerrit.Type) - -> let key = F.defaultText gerrit.sshkey.key "id_rsa" - - let server = F.defaultText gerrit.server gerrit.name - - in '' - [connection ${gerrit.name}] - driver=gerrit - server=${server} - sshkey=/etc/zuul-gerrit-${gerrit.name}/${key} - user=${gerrit.user} - baseurl=${gerrit.baseurl} - '' + Then it returns a text blob for all the connections + -} mkConns = + \(type : Type) -> + \(list : Optional (List type)) -> + \(f : type -> Text) -> + F.newlineSep + ( merge + { None = [] : List Text, Some = Prelude.List.map type Text f } + list ) - let githubs-conf = - mkConns - Schemas.GitHub.Type - input.connections.githubs - ( \(github : Schemas.GitHub.Type) - -> let key = F.defaultText github.app_key.key "github_rsa" + let merger-email = + F.defaultText input.merger.git_user_email "${input.name}@localhost" - in '' - [connection ${github.name}] - driver=github - server=github.com - app_id={github.app_id} - app_key=/etc/zuul-github-${github.name}/${key} - '' - ) + let merger-user = F.defaultText input.merger.git_user_name "Zuul" - let gits-conf = - mkConns - Schemas.Git.Type - input.connections.gits - ( \(git : Schemas.Git.Type) - -> '' - [connection ${git.name}] - driver=git - baseurl=${git.baseurl} + let executor-key-name = F.defaultText input.executor.ssh_key.key "id_rsa" + let sched-config = F.defaultText input.scheduler.config.key "main.yaml" + + let web-url = F.defaultText input.web.status_url "http://web:9000" + + let extra-kube-path = "/etc/nodepool-kubernetes/" + + let db-uri = + merge + { None = "postgresql://zuul:%(ZUUL_DB_PASSWORD)s@db/zuul" + , Some = \(some : Schemas.UserSecret.Type) -> "%(ZUUL_DB_URI)s" + } + input.database + + let gerrits-conf = + mkConns + Schemas.Gerrit.Type + input.connections.gerrits + ( \(gerrit : Schemas.Gerrit.Type) -> + let key = F.defaultText gerrit.sshkey.key "id_rsa" + + let server = F.defaultText gerrit.server gerrit.name + + in '' + [connection ${gerrit.name}] + driver=gerrit + server=${server} + sshkey=/etc/zuul-gerrit-${gerrit.name}/${key} + user=${gerrit.user} + baseurl=${gerrit.baseurl} '' - ) + ) - let mqtts-conf = - mkConns - Schemas.Mqtt.Type - input.connections.mqtts - ( \(mqtt : Schemas.Mqtt.Type) - -> let user = - merge - { None = "", Some = \(some : Text) -> "user=${some}" } - mqtt.user + let githubs-conf = + mkConns + Schemas.GitHub.Type + input.connections.githubs + ( \(github : Schemas.GitHub.Type) -> + let key = F.defaultText github.app_key.key "github_rsa" - let password = - merge - { None = "" - , Some = - \(some : Schemas.UserSecret.Type) - -> "password=%(ZUUL_MQTT_PASSWORD)" - } - mqtt.password + in '' + [connection ${github.name}] + driver=github + server=github.com + app_id={github.app_id} + app_key=/etc/zuul-github-${github.name}/${key} + '' + ) - in '' - [connection ${mqtt.name}] - driver=mqtt - server=${mqtt.server} - ${user} - ${password} - '' - ) + let gits-conf = + mkConns + Schemas.Git.Type + input.connections.gits + ( \(git : Schemas.Git.Type) -> + '' + [connection ${git.name}] + driver=git + baseurl=${git.baseurl} - let job-volumes = - F.mkJobVolume - Text - ( \(job-volume : Schemas.JobVolume.Type) - -> let {- TODO: add support for abritary lists of path per (context, access) - -} context = - merge - { trusted = "trusted", untrusted = "untrusted" } - job-volume.context + '' + ) - let access = - merge - { None = "ro" - , Some = - \(access : < ro | rw >) - -> merge { ro = "ro", rw = "rw" } access - } - job-volume.access + let mqtts-conf = + mkConns + Schemas.Mqtt.Type + input.connections.mqtts + ( \(mqtt : Schemas.Mqtt.Type) -> + let user = + merge + { None = "", Some = \(some : Text) -> "user=${some}" } + mqtt.user - in "${context}_${access}_paths=${job-volume.path}" - ) - input.jobVolumes + let password = + merge + { None = "" + , Some = + \(some : Schemas.UserSecret.Type) -> + "password=%(ZUUL_MQTT_PASSWORD)" + } + mqtt.password - in '' - [gearman] - server=scheduler - ssl_ca=/etc/zuul-gearman/ca.crt - ssl_cert=/etc/zuul-gearman/tls.crt - ssl_key=/etc/zuul-gearman/tls.key + in '' + [connection ${mqtt.name}] + driver=mqtt + server=${mqtt.server} + ${user} + ${password} + '' + ) - [gearman_server] - start=true - ssl_ca=/etc/zuul-gearman/ca.crt - ssl_cert=/etc/zuul-gearman/tls.crt - ssl_key=/etc/zuul-gearman/tls.key + let job-volumes = + F.mkJobVolume + Text + ( \(job-volume : Schemas.JobVolume.Type) -> + let {- TODO: add support for abritary lists of path per (context, access) + -} context = + merge + { trusted = "trusted", untrusted = "untrusted" } + job-volume.context - [zookeeper] - ${zk-hosts} + let access = + merge + { None = "ro" + , Some = + \(access : < ro | rw >) -> + merge { ro = "ro", rw = "rw" } access + } + job-volume.access - [merger] - git_user_email=${merger-email} - git_user_name=${merger-user} + in "${context}_${access}_paths=${job-volume.path}" + ) + input.jobVolumes - [scheduler] - tenant_config=/etc/zuul-scheduler/${sched-config} + in '' + [gearman] + server=scheduler + ssl_ca=/etc/zuul-gearman/ca.crt + ssl_cert=/etc/zuul-gearman/tls.crt + ssl_key=/etc/zuul-gearman/tls.key - [web] - listen_address=0.0.0.0 - root=${web-url} + [gearman_server] + start=true + ssl_ca=/etc/zuul-gearman/ca.crt + ssl_cert=/etc/zuul-gearman/tls.crt + ssl_key=/etc/zuul-gearman/tls.key - [executor] - private_key_file=/etc/zuul-executor/${executor-key-name} - manage_ansible=false + [zookeeper] + ${zk-hosts} - '' - ++ Prelude.Text.concatSep "\n" job-volumes - ++ '' + [merger] + git_user_email=${merger-email} + git_user_name=${merger-user} - [connection "sql"] - driver=sql - dburi=${db-uri} + [scheduler] + tenant_config=/etc/zuul-scheduler/${sched-config} - '' - ++ gits-conf - ++ gerrits-conf - ++ githubs-conf - ++ mqtts-conf + [web] + listen_address=0.0.0.0 + root=${web-url} + + [executor] + private_key_file=/etc/zuul-executor/${executor-key-name} + manage_ansible=false + + '' + ++ Prelude.Text.concatSep "\n" job-volumes + ++ '' + + [connection "sql"] + driver=sql + dburi=${db-uri} + + '' + ++ gits-conf + ++ gerrits-conf + ++ githubs-conf + ++ mqtts-conf diff --git a/conf/zuul/functions.dhall b/conf/zuul/functions.dhall index 1de9f7f..1d74cc3 100644 --- a/conf/zuul/functions.dhall +++ b/conf/zuul/functions.dhall @@ -16,86 +16,85 @@ let {- This methods process the optional input.job-volumes list. It takes: Then it returns a list of the output type -} mkJobVolume = - \(OutputType : Type) - -> \(f : JobVolume -> OutputType) - -> \(job-volumes : Optional (List JobVolume)) - -> merge - { None = [] : List OutputType - , Some = Prelude.List.map JobVolume OutputType f - } - job-volumes + \(OutputType : Type) -> + \(f : JobVolume -> OutputType) -> + \(job-volumes : Optional (List JobVolume)) -> + merge + { None = [] : List OutputType + , Some = Prelude.List.map JobVolume OutputType f + } + job-volumes let defaultNat = - \(value : Optional Natural) - -> \(default : Natural) - -> merge { None = default, Some = \(some : Natural) -> some } value + \(value : Optional Natural) -> + \(default : Natural) -> + merge { None = default, Some = \(some : Natural) -> some } value let defaultText = - \(value : Optional Text) - -> \(default : Text) - -> merge { None = default, Some = \(some : Text) -> some } value + \(value : Optional Text) -> + \(default : Text) -> + merge { None = default, Some = \(some : Text) -> some } value let defaultKey = - \(secret : Optional UserSecret) - -> \(default : Text) - -> merge - { None = default - , Some = \(some : UserSecret) -> defaultText some.key default - } - secret + \(secret : Optional UserSecret) -> + \(default : Text) -> + merge + { None = default + , Some = \(some : UserSecret) -> defaultText some.key default + } + secret let mkAppLabels = - \(app-name : Text) - -> [ { mapKey = "app.kubernetes.io/name", mapValue = app-name } - , { mapKey = "app.kubernetes.io/instance", mapValue = app-name } - , { mapKey = "app.kubernetes.io/part-of", mapValue = "zuul" } - ] + \(app-name : Text) -> + [ { mapKey = "app.kubernetes.io/name", mapValue = app-name } + , { mapKey = "app.kubernetes.io/instance", mapValue = app-name } + , { mapKey = "app.kubernetes.io/part-of", mapValue = "zuul" } + ] let mkComponentLabel = - \(app-name : Text) - -> \(component-name : Text) - -> mkAppLabels app-name - # [ { mapKey = "app.kubernetes.io/component" - , mapValue = component-name - } - ] + \(app-name : Text) -> + \(component-name : Text) -> + mkAppLabels app-name + # [ { mapKey = "app.kubernetes.io/component" + , mapValue = component-name + } + ] let Label = { mapKey : Text, mapValue : Text } let Labels = List Label let mkObjectMeta = - \(name : Text) - -> \(labels : Labels) - -> Kubernetes.ObjectMeta::{ name = name, labels = Some labels } + \(name : Text) -> + \(labels : Labels) -> + Kubernetes.ObjectMeta::{ name, labels = Some labels } let mkSelector = - \(labels : Labels) - -> Kubernetes.LabelSelector::{ matchLabels = Some labels } + \(labels : Labels) -> + Kubernetes.LabelSelector::{ matchLabels = Some labels } let mkService = - \(app-name : Text) - -> \(name : Text) - -> \(port-name : Text) - -> \(port : Natural) - -> let labels = mkComponentLabel app-name name + \(app-name : Text) -> + \(name : Text) -> + \(port-name : Text) -> + \(port : Natural) -> + let labels = mkComponentLabel app-name name - in Kubernetes.Service::{ - , metadata = mkObjectMeta name labels - , spec = Some Kubernetes.ServiceSpec::{ - , type = Some "ClusterIP" - , selector = Some labels - , ports = Some - [ Kubernetes.ServicePort::{ - , name = Some port-name - , protocol = Some "TCP" - , targetPort = Some - (Kubernetes.IntOrString.String port-name) - , port = port - } - ] - } + in Kubernetes.Service::{ + , metadata = mkObjectMeta name labels + , spec = Some Kubernetes.ServiceSpec::{ + , type = Some "ClusterIP" + , selector = Some labels + , ports = Some + [ Kubernetes.ServicePort::{ + , name = Some port-name + , protocol = Some "TCP" + , targetPort = Some (Kubernetes.IntOrString.String port-name) + , port + } + ] } + } let EnvSecret = { name : Text, secret : Text, key : Text } @@ -118,11 +117,11 @@ let {- A high level description of a component such as the scheduler or the laun , claim-size : Natural } , default = - { data-dir = [] : List Volume.Type - , volumes = [] : List Volume.Type - , extra-volumes = [] : List Kubernetes.Volume.Type - , claim-size = 0 - } + { data-dir = [] : List Volume.Type + , volumes = [] : List Volume.Type + , extra-volumes = [] : List Kubernetes.Volume.Type + , claim-size = 0 + } } let {- The Kubernetes resources of a Component @@ -133,169 +132,163 @@ let {- The Kubernetes resources of a Component , StatefulSet : Optional Kubernetes.StatefulSet.Type } , default = - { Service = None Kubernetes.Service.Type - , Deployment = None Kubernetes.Deployment.Type - , StatefulSet = None Kubernetes.StatefulSet.Type - } + { Service = None Kubernetes.Service.Type + , Deployment = None Kubernetes.Deployment.Type + , StatefulSet = None Kubernetes.StatefulSet.Type + } } let mkVolumeEmptyDir = Prelude.List.map Volume.Type Kubernetes.Volume.Type - ( \(volume : Volume.Type) - -> Kubernetes.Volume::{ - , name = volume.name - , emptyDir = Some Kubernetes.EmptyDirVolumeSource::{=} - } + ( \(volume : Volume.Type) -> + Kubernetes.Volume::{ + , name = volume.name + , emptyDir = Some Kubernetes.EmptyDirVolumeSource::{=} + } ) let mkVolumeSecret = Prelude.List.map Volume.Type Kubernetes.Volume.Type - ( \(volume : Volume.Type) - -> Kubernetes.Volume::{ - , name = volume.name - , secret = Some Kubernetes.SecretVolumeSource::{ - , secretName = Some volume.name - , defaultMode = Some 256 - } + ( \(volume : Volume.Type) -> + Kubernetes.Volume::{ + , name = volume.name + , secret = Some Kubernetes.SecretVolumeSource::{ + , secretName = Some volume.name + , defaultMode = Some 256 } + } ) let mkPodTemplateSpec = - \(component : Component.Type) - -> \(labels : Labels) - -> Kubernetes.PodTemplateSpec::{ - , metadata = mkObjectMeta component.name labels - , spec = Some Kubernetes.PodSpec::{ - , volumes = Some - ( mkVolumeSecret component.volumes - # mkVolumeEmptyDir component.data-dir - # component.extra-volumes - ) - , containers = [ component.container ] - , automountServiceAccountToken = Some False - } + \(component : Component.Type) -> + \(labels : Labels) -> + Kubernetes.PodTemplateSpec::{ + , metadata = mkObjectMeta component.name labels + , spec = Some Kubernetes.PodSpec::{ + , volumes = Some + ( mkVolumeSecret component.volumes + # mkVolumeEmptyDir component.data-dir + # component.extra-volumes + ) + , containers = [ component.container ] + , automountServiceAccountToken = Some False } + } let mkStatefulSet = - \(app-name : Text) - -> \(component : Component.Type) - -> let labels = mkComponentLabel app-name component.name + \(app-name : Text) -> + \(component : Component.Type) -> + let labels = mkComponentLabel app-name component.name - let component-name = app-name ++ "-" ++ component.name + let component-name = app-name ++ "-" ++ component.name - let claim = - if Natural/isZero component.claim-size - - then [] : List Kubernetes.PersistentVolumeClaim.Type - - else [ Kubernetes.PersistentVolumeClaim::{ - , apiVersion = "" - , kind = "" - , metadata = Kubernetes.ObjectMeta::{ - , name = component-name - } - , spec = Some Kubernetes.PersistentVolumeClaimSpec::{ - , accessModes = Some [ "ReadWriteOnce" ] - , resources = Some Kubernetes.ResourceRequirements::{ - , requests = Some - ( toMap - { storage = - Natural/show component.claim-size - ++ "Gi" - } - ) - } + let claim = + if Natural/isZero component.claim-size + then [] : List Kubernetes.PersistentVolumeClaim.Type + else [ Kubernetes.PersistentVolumeClaim::{ + , apiVersion = "" + , kind = "" + , metadata = Kubernetes.ObjectMeta::{ + , name = component-name + } + , spec = Some Kubernetes.PersistentVolumeClaimSpec::{ + , accessModes = Some [ "ReadWriteOnce" ] + , resources = Some Kubernetes.ResourceRequirements::{ + , requests = Some + ( toMap + { storage = + Natural/show component.claim-size ++ "Gi" + } + ) } } - ] + } + ] - in Kubernetes.StatefulSet::{ - , metadata = mkObjectMeta component-name labels - , spec = Some Kubernetes.StatefulSetSpec::{ - , serviceName = component.name - , replicas = Some component.count - , selector = mkSelector labels - , template = mkPodTemplateSpec component labels - , volumeClaimTemplates = Some claim - } + in Kubernetes.StatefulSet::{ + , metadata = mkObjectMeta component-name labels + , spec = Some Kubernetes.StatefulSetSpec::{ + , serviceName = component.name + , replicas = Some component.count + , selector = mkSelector labels + , template = mkPodTemplateSpec component labels + , volumeClaimTemplates = Some claim } + } let mkDeployment = - \(app-name : Text) - -> \(component : Component.Type) - -> let labels = mkComponentLabel app-name component.name + \(app-name : Text) -> + \(component : Component.Type) -> + let labels = mkComponentLabel app-name component.name - let component-name = app-name ++ "-" ++ component.name + let component-name = app-name ++ "-" ++ component.name - in Kubernetes.Deployment::{ - , metadata = mkObjectMeta component-name labels - , spec = Some Kubernetes.DeploymentSpec::{ - , replicas = Some component.count - , selector = mkSelector labels - , template = mkPodTemplateSpec component labels - } + in Kubernetes.Deployment::{ + , metadata = mkObjectMeta component-name labels + , spec = Some Kubernetes.DeploymentSpec::{ + , replicas = Some component.count + , selector = mkSelector labels + , template = mkPodTemplateSpec component labels } + } let mkEnvVarValue = Prelude.List.map Label Kubernetes.EnvVar.Type - ( \(env : Label) - -> Kubernetes.EnvVar::{ - , name = env.mapKey - , value = Some env.mapValue - } + ( \(env : Label) -> + Kubernetes.EnvVar::{ name = env.mapKey, value = Some env.mapValue } ) let mkEnvVarSecret = Prelude.List.map EnvSecret Kubernetes.EnvVar.Type - ( \(env : EnvSecret) - -> Kubernetes.EnvVar::{ - , name = env.name - , valueFrom = Some Kubernetes.EnvVarSource::{ - , secretKeyRef = Some Kubernetes.SecretKeySelector::{ - , key = env.key - , name = Some env.secret - } + ( \(env : EnvSecret) -> + Kubernetes.EnvVar::{ + , name = env.name + , valueFrom = Some Kubernetes.EnvVarSource::{ + , secretKeyRef = Some Kubernetes.SecretKeySelector::{ + , key = env.key + , name = Some env.secret } } + } ) let mkVolumeMount = Prelude.List.map Volume.Type Kubernetes.VolumeMount.Type - ( \(volume : Volume.Type) - -> Kubernetes.VolumeMount::{ - , name = volume.name - , mountPath = volume.dir - } + ( \(volume : Volume.Type) -> + Kubernetes.VolumeMount::{ + , name = volume.name + , mountPath = volume.dir + } ) -in { defaultNat = defaultNat - , defaultText = defaultText - , defaultKey = defaultKey +in { defaultNat + , defaultText + , defaultKey , newlineSep = Prelude.Text.concatSep "\n" - , mkJobVolume = mkJobVolume - , mkComponentLabel = mkComponentLabel - , mkObjectMeta = mkObjectMeta - , mkSelector = mkSelector - , mkService = mkService - , mkDeployment = mkDeployment - , mkStatefulSet = mkStatefulSet - , mkVolumeMount = mkVolumeMount - , mkEnvVarValue = mkEnvVarValue - , mkEnvVarSecret = mkEnvVarSecret - , EnvSecret = EnvSecret - , Label = Label - , Labels = Labels - , Volume = Volume - , Component = Component - , KubernetesComponent = KubernetesComponent + , mkJobVolume + , mkComponentLabel + , mkObjectMeta + , mkSelector + , mkService + , mkDeployment + , mkStatefulSet + , mkVolumeMount + , mkEnvVarValue + , mkEnvVarSecret + , EnvSecret + , Label + , Labels + , Volume + , Component + , KubernetesComponent } diff --git a/conf/zuul/input.dhall b/conf/zuul/input.dhall index 1974ab4..3f9082c 100644 --- a/conf/zuul/input.dhall +++ b/conf/zuul/input.dhall @@ -42,95 +42,92 @@ let Git = { name : Text, baseurl : Text } let Schemas = { Merger = - { Type = - { image : Optional Text - , count : Optional Natural - , git_user_email : Optional Text - , git_user_name : Optional Text - } - , default = - { image = None Text - , count = None Natural - , git_user_email = None Text - , git_user_name = None Text - } + { Type = + { image : Optional Text + , count : Optional Natural + , git_user_email : Optional Text + , git_user_name : Optional Text + } + , default = + { image = None Text + , count = None Natural + , git_user_email = None Text + , git_user_name = None Text } + } , Executor = - { Type = - { image : Optional Text - , count : Optional Natural - , ssh_key : UserSecret - } - , default = { image = None Text, count = None Natural } - } + { Type = + { image : Optional Text + , count : Optional Natural + , ssh_key : UserSecret + } + , default = { image = None Text, count = None Natural } + } , Web = - { Type = - { image : Optional Text - , count : Optional Natural - , status_url : Optional Text - } - , default = - { image = None Text - , count = None Natural - , status_url = None Text - } - } + { Type = + { image : Optional Text + , count : Optional Natural + , status_url : Optional Text + } + , default = + { image = None Text, count = None Natural, status_url = None Text } + } , Scheduler = - { Type = - { image : Optional Text - , count : Optional Natural - , config : UserSecret - } - , default = { image = None Text, count = None Natural } - } + { Type = + { image : Optional Text + , count : Optional Natural + , config : UserSecret + } + , default = { image = None Text, count = None Natural } + } , Registry = - { Type = - { image : Optional Text - , count : Optional Natural - , storage-size : Optional Natural - , public-url : Optional Text - } - , default = - { image = None Text - , count = None Natural - , storage-size = None Natural - , public-url = None Text - } + { Type = + { image : Optional Text + , count : Optional Natural + , storage-size : Optional Natural + , public-url : Optional Text + } + , default = + { image = None Text + , count = None Natural + , storage-size = None Natural + , public-url = None Text } + } , Preview = - { Type = { image : Optional Text, count : Optional Natural } - , default = { image = None Text, count = None Natural } - } + { Type = { image : Optional Text, count : Optional Natural } + , default = { image = None Text, count = None Natural } + } , Launcher = - { Type = { image : Optional Text, config : UserSecret } - , default.image = None Text - } + { Type = { image : Optional Text, config : UserSecret } + , default.image = None Text + } , Connections = - { Type = - { gerrits : Optional (List Gerrit) - , githubs : Optional (List GitHub) - , mqtts : Optional (List Mqtt) - , gits : Optional (List Git) - } - , default = - { gerrits = None (List Gerrit) - , githubs = None (List GitHub) - , mqtts = None (List Mqtt) - , gits = None (List Git) - } + { Type = + { gerrits : Optional (List Gerrit) + , githubs : Optional (List GitHub) + , mqtts : Optional (List Mqtt) + , gits : Optional (List Git) + } + , default = + { gerrits = None (List Gerrit) + , githubs = None (List GitHub) + , mqtts = None (List Mqtt) + , gits = None (List Git) } + } , ExternalConfigs = - { Type = - { openstack : Optional UserSecret - , kubernetes : Optional UserSecret - , amazon : Optional UserSecret - } - , default = - { openstack = None UserSecret - , kubernetes = None UserSecret - , amazon = None UserSecret - } + { Type = + { openstack : Optional UserSecret + , kubernetes : Optional UserSecret + , amazon : Optional UserSecret + } + , default = + { openstack = None UserSecret + , kubernetes = None UserSecret + , amazon = None UserSecret } + } , JobVolume = { Type = JobVolume, default.access = Some < ro | rw >.ro } , UserSecret = { Type = UserSecret, default.key = None Text } , Gerrit.Type = Gerrit @@ -158,21 +155,21 @@ let Input = , withCertManager : Bool } , default = - { imagePrefix = None Text - , database = None UserSecret - , zookeeper = None UserSecret - , externalConfig = Schemas.ExternalConfigs.default - , merger = Schemas.Merger.default - , web = Schemas.Web.default - , scheduler = Schemas.Scheduler.default - , registry = Schemas.Registry.default - , preview = Schemas.Preview.default - , executor = Schemas.Executor.default - , launcher = Schemas.Launcher.default - , connections = Schemas.Connections.default - , jobVolumes = None (List JobVolume) - , withCertManager = True - } + { imagePrefix = None Text + , database = None UserSecret + , zookeeper = None UserSecret + , externalConfig = Schemas.ExternalConfigs.default + , merger = Schemas.Merger.default + , web = Schemas.Web.default + , scheduler = Schemas.Scheduler.default + , registry = Schemas.Registry.default + , preview = Schemas.Preview.default + , executor = Schemas.Executor.default + , launcher = Schemas.Launcher.default + , connections = Schemas.Connections.default + , jobVolumes = None (List JobVolume) + , withCertManager = True + } } -in Schemas // { Input = Input } +in Schemas // { Input } diff --git a/conf/zuul/resources.dhall b/conf/zuul/resources.dhall index 41f426d..350da35 100644 --- a/conf/zuul/resources.dhall +++ b/conf/zuul/resources.dhall @@ -54,552 +54,539 @@ let UserSecret = Schemas.UserSecret.Type let Volume = F.Volume -in \(input : Input) - -> let zk-conf = - merge - { None = - { ServiceVolumes = - [ Volume::{ - , name = "${input.name}-secret-zk" - , dir = "/conf-tls" - , files = - [ { path = "zoo.cfg" - , content = ./files/zoo.cfg.dhall "/conf" "/conf" - } - ] +in \(input : Input) -> + let zk-conf = + merge + { None = + { ServiceVolumes = + [ Volume::{ + , name = "${input.name}-secret-zk" + , dir = "/conf-tls" + , files = + [ { path = "zoo.cfg" + , content = ./files/zoo.cfg.dhall "/conf" "/conf" } ] - , ClientVolumes = - [ Volume::{ - , name = "${input.name}-zookeeper-tls" - , dir = "/etc/zookeeper-tls" - } - ] - , Zuul = - '' - hosts=zk:2281 - tls_cert=/etc/zookeeper-tls/tls.crt - tls_key=/etc/zookeeper-tls/tls.key - tls_ca=/etc/zookeeper-tls/ca.crt - '' - , Nodepool = - '' - zookeeper-servers: - - host: zk - port: 2281 - zookeeper-tls: - cert: /etc/zookeeper-tls/tls.crt - key: /etc/zookeeper-tls/tls.key - ca: /etc/zookeeper-tls/ca.crt - '' - , Env = [] : List Kubernetes.EnvVar.Type } - , Some = - \(some : UserSecret) - -> let empty = [] : List Volume.Type - - in { ServiceVolumes = empty - , ClientVolumes = empty - , Zuul = "hosts=%(ZUUL_ZK_HOSTS)" - , Nodepool = - '' - zookeeper-servers: - - hosts: %(ZUUL_ZK_HOSTS)" - '' - , Env = - F.mkEnvVarSecret - [ { name = "ZUUL_ZK_HOSTS" - , secret = some.secretName - , key = F.defaultText some.key "hosts" - } - ] - } + ] + , ClientVolumes = + [ Volume::{ + , name = "${input.name}-zookeeper-tls" + , dir = "/etc/zookeeper-tls" + } + ] + , Zuul = + '' + hosts=zk:2281 + tls_cert=/etc/zookeeper-tls/tls.crt + tls_key=/etc/zookeeper-tls/tls.key + tls_ca=/etc/zookeeper-tls/ca.crt + '' + , Nodepool = + '' + zookeeper-servers: + - host: zk + port: 2281 + zookeeper-tls: + cert: /etc/zookeeper-tls/tls.crt + key: /etc/zookeeper-tls/tls.key + ca: /etc/zookeeper-tls/ca.crt + '' + , Env = [] : List Kubernetes.EnvVar.Type } - input.zookeeper + , Some = + \(some : UserSecret) -> + let empty = [] : List Volume.Type - let db-internal-password-env = - \(env-name : Text) - -> F.mkEnvVarSecret - [ { name = env-name - , secret = "${input.name}-database-password" - , key = "password" - } - ] - - let org = - merge - { None = "docker.io/zuul", Some = \(prefix : Text) -> prefix } - input.imagePrefix - - let version = "latest" - - let image = \(name : Text) -> "${org}/${name}:${version}" - - let set-image = - \(default-name : Text) - -> \(input-name : Optional Text) - -> { image = - merge - { None = Some default-name - , Some = \(_ : Text) -> input-name - } - input-name - } - - let etc-zuul = - Volume::{ - , name = input.name ++ "-secret-zuul" - , dir = "/etc/zuul" - , files = - [ { path = "zuul.conf" - , content = ./files/zuul.conf.dhall input zk-conf.Zuul - } - ] - } - - let etc-zuul-registry = - Volume::{ - , name = input.name ++ "-secret-registry" - , dir = "/etc/zuul" - , files = - [ { path = "registry.yaml" - , content = - let public-url = - F.defaultText - input.registry.public-url - "https://registry:9000" - - in ./files/registry.yaml.dhall public-url - } - ] - } - - let etc-nodepool = - Volume::{ - , name = input.name ++ "-secret-nodepool" - , dir = "/etc/nodepool" - , files = - [ { path = "nodepool.yaml" - , content = ./files/nodepool.yaml.dhall zk-conf.Nodepool - } - ] - } - - let Components = - { CertManager = - let issuer = - { kind = "Issuer" - , group = "cert-manager.io" - , name = "${input.name}-ca" - } - - let registry-enabled = - Natural/isZero (F.defaultNat input.registry.count 0) - == False - - let registry-cert = - if registry-enabled - - then [ CertManager.Certificate::{ - , metadata = - F.mkObjectMeta - "${input.name}-registry-tls" - ( F.mkComponentLabel - input.name - "cert-registry" - ) - , spec = CertManager.CertificateSpec::{ - , secretName = "${input.name}-registry-tls" - , issuerRef = issuer - , dnsNames = Some [ "registry" ] - , usages = Some - [ "server auth", "client auth" ] - } + in { ServiceVolumes = empty + , ClientVolumes = empty + , Zuul = "hosts=%(ZUUL_ZK_HOSTS)" + , Nodepool = + '' + zookeeper-servers: + - hosts: %(ZUUL_ZK_HOSTS)" + '' + , Env = + F.mkEnvVarSecret + [ { name = "ZUUL_ZK_HOSTS" + , secret = some.secretName + , key = F.defaultText some.key "hosts" } ] + } + } + input.zookeeper - else [] : List CertManager.Certificate.Type + let db-internal-password-env = + \(env-name : Text) -> + F.mkEnvVarSecret + [ { name = env-name + , secret = "${input.name}-database-password" + , key = "password" + } + ] - in { Issuers = - [ CertManager.Issuer::{ - , metadata = - F.mkObjectMeta - "${input.name}-selfsigning" - ( F.mkComponentLabel - input.name - "issuer-selfsigning" - ) - , spec = CertManager.IssuerSpec::{ - , selfSigned = Some {=} - } - } - , CertManager.Issuer::{ - , metadata = - F.mkObjectMeta - "${input.name}-ca" - (F.mkComponentLabel input.name "issuer-ca") - , spec = CertManager.IssuerSpec::{ - , ca = Some { secretName = "${input.name}-ca" } - } - } - ] - , Certificates = - [ CertManager.Certificate::{ + let org = + merge + { None = "docker.io/zuul", Some = \(prefix : Text) -> prefix } + input.imagePrefix + + let version = "latest" + + let image = \(name : Text) -> "${org}/${name}:${version}" + + let set-image = + \(default-name : Text) -> + \(input-name : Optional Text) -> + { image = + merge + { None = Some default-name + , Some = \(_ : Text) -> input-name + } + input-name + } + + let etc-zuul = + Volume::{ + , name = input.name ++ "-secret-zuul" + , dir = "/etc/zuul" + , files = + [ { path = "zuul.conf" + , content = ./files/zuul.conf.dhall input zk-conf.Zuul + } + ] + } + + let etc-zuul-registry = + Volume::{ + , name = input.name ++ "-secret-registry" + , dir = "/etc/zuul" + , files = + [ { path = "registry.yaml" + , content = + let public-url = + F.defaultText + input.registry.public-url + "https://registry:9000" + + in ./files/registry.yaml.dhall public-url + } + ] + } + + let etc-nodepool = + Volume::{ + , name = input.name ++ "-secret-nodepool" + , dir = "/etc/nodepool" + , files = + [ { path = "nodepool.yaml" + , content = ./files/nodepool.yaml.dhall zk-conf.Nodepool + } + ] + } + + let Components = + { CertManager = + let issuer = + { kind = "Issuer" + , group = "cert-manager.io" + , name = "${input.name}-ca" + } + + let registry-enabled = + Natural/isZero (F.defaultNat input.registry.count 0) + == False + + let registry-cert = + if registry-enabled + then [ CertManager.Certificate::{ , metadata = F.mkObjectMeta - "${input.name}-ca" - (F.mkComponentLabel input.name "cert-ca") - , spec = CertManager.CertificateSpec::{ - , secretName = "${input.name}-ca" - , isCA = Some True - , commonName = Some "selfsigned-root-ca" - , issuerRef = - issuer - // { name = "${input.name}-selfsigning" } - , usages = Some - [ "server auth", "client auth", "cert sign" ] - } - } - , CertManager.Certificate::{ - , metadata = - F.mkObjectMeta - "${input.name}-gearman-tls" + "${input.name}-registry-tls" ( F.mkComponentLabel input.name - "cert-gearman" + "cert-registry" ) , spec = CertManager.CertificateSpec::{ - , secretName = "${input.name}-gearman-tls" + , secretName = "${input.name}-registry-tls" , issuerRef = issuer - , dnsNames = Some [ "gearman" ] + , dnsNames = Some [ "registry" ] , usages = Some [ "server auth", "client auth" ] } } ] - # registry-cert - } - , Backend = - { Database = + else [] : List CertManager.Certificate.Type + + in { Issuers = + [ CertManager.Issuer::{ + , metadata = + F.mkObjectMeta + "${input.name}-selfsigning" + ( F.mkComponentLabel + input.name + "issuer-selfsigning" + ) + , spec = CertManager.IssuerSpec::{ + , selfSigned = Some {=} + } + } + , CertManager.Issuer::{ + , metadata = + F.mkObjectMeta + "${input.name}-ca" + (F.mkComponentLabel input.name "issuer-ca") + , spec = CertManager.IssuerSpec::{ + , ca = Some { secretName = "${input.name}-ca" } + } + } + ] + , Certificates = + [ CertManager.Certificate::{ + , metadata = + F.mkObjectMeta + "${input.name}-ca" + (F.mkComponentLabel input.name "cert-ca") + , spec = CertManager.CertificateSpec::{ + , secretName = "${input.name}-ca" + , isCA = Some True + , commonName = Some "selfsigned-root-ca" + , issuerRef = + issuer + // { name = "${input.name}-selfsigning" } + , usages = Some + [ "server auth", "client auth", "cert sign" ] + } + } + , CertManager.Certificate::{ + , metadata = + F.mkObjectMeta + "${input.name}-gearman-tls" + (F.mkComponentLabel input.name "cert-gearman") + , spec = CertManager.CertificateSpec::{ + , secretName = "${input.name}-gearman-tls" + , issuerRef = issuer + , dnsNames = Some [ "gearman" ] + , usages = Some [ "server auth", "client auth" ] + } + } + ] + # registry-cert + } + , Backend = + { Database = + merge + { None = + ./components/Database.dhall + input.name + db-internal-password-env + , Some = + \(some : UserSecret) -> F.KubernetesComponent.default + } + input.database + , ZooKeeper = + merge + { None = + ./components/ZooKeeper.dhall + input.name + (zk-conf.ClientVolumes # zk-conf.ServiceVolumes) + , Some = + \(some : UserSecret) -> F.KubernetesComponent.default + } + input.zookeeper + } + , Zuul = + let zuul-image = + \(name : Text) -> set-image (image "zuul-${name}") + + let zuul-env = + F.mkEnvVarValue (toMap { HOME = "/var/lib/zuul" }) + + let db-secret-env = merge - { None = - ./components/Database.dhall - input.name - db-internal-password-env + { None = db-internal-password-env "ZUUL_DB_PASSWORD" , Some = - \(some : UserSecret) - -> F.KubernetesComponent.default + \(some : UserSecret) -> + F.mkEnvVarSecret + [ { name = "ZUUL_DB_URI" + , secret = some.secretName + , key = F.defaultText some.key "db_uri" + } + ] } input.database - , ZooKeeper = - merge - { None = - ./components/ZooKeeper.dhall - input.name - (zk-conf.ClientVolumes # zk-conf.ServiceVolumes) - , Some = - \(some : UserSecret) - -> F.KubernetesComponent.default - } - input.zookeeper - } - , Zuul = - let zuul-image = - \(name : Text) -> set-image (image "zuul-${name}") - let zuul-env = - F.mkEnvVarValue (toMap { HOME = "/var/lib/zuul" }) + let {- executor and merger do not need database info, but they fail to parse config without the env variable + -} db-nosecret-env = + F.mkEnvVarValue (toMap { ZUUL_DB_PASSWORD = "unused" }) - let db-secret-env = - merge - { None = db-internal-password-env "ZUUL_DB_PASSWORD" - , Some = - \(some : UserSecret) - -> F.mkEnvVarSecret - [ { name = "ZUUL_DB_URI" - , secret = some.secretName - , key = F.defaultText some.key "db_uri" - } - ] - } - input.database + let zuul-data-dir = + [ Volume::{ name = "zuul-data", dir = "/var/lib/zuul" } ] - let {- executor and merger do not need database info, but they fail to parse config without the env variable - -} db-nosecret-env = - F.mkEnvVarValue (toMap { ZUUL_DB_PASSWORD = "unused" }) - - let zuul-data-dir = - [ Volume::{ name = "zuul-data", dir = "/var/lib/zuul" } - ] - - let sched-config = - Volume::{ - , name = input.scheduler.config.secretName - , dir = "/etc/zuul-scheduler" - } - - let gearman-config = - Volume::{ - , name = input.name ++ "-gearman-tls" - , dir = "/etc/zuul-gearman" - } - - let executor-ssh-key = - Volume::{ - , name = input.executor.ssh_key.secretName - , dir = "/etc/zuul-executor" - } - - let zuul-volumes = - [ etc-zuul, gearman-config ] # zk-conf.ClientVolumes - - in { Scheduler = - ./components/Scheduler.dhall - input.name - ( input.scheduler - // zuul-image "scheduler" input.scheduler.image - ) - zuul-data-dir - (zuul-volumes # [ sched-config ]) - (zuul-env # db-secret-env # zk-conf.Env) - , Executor = - ./components/Executor.dhall - input.name - ( input.executor - // zuul-image "executor" input.executor.image - ) - zuul-data-dir - (zuul-volumes # [ executor-ssh-key ]) - (zuul-env # db-nosecret-env) - input.jobVolumes - , Web = - ./components/Web.dhall - input.name - (input.web // zuul-image "web" input.web.image) - zuul-data-dir - zuul-volumes - (zuul-env # db-secret-env # zk-conf.Env) - , Merger = - ./components/Merger.dhall - input.name - ( input.merger - // zuul-image "merger" input.merger.image - ) - zuul-data-dir - zuul-volumes - (zuul-env # db-nosecret-env) - , Registry = - ./components/Registry.dhall - input.name - ( input.registry - // zuul-image "registry" input.registry.image - ) - zuul-data-dir - [ etc-zuul-registry ] - , Preview = - ./components/Preview.dhall - input.name - ( input.preview - // zuul-image "preview" input.preview.image - ) - zuul-data-dir + let sched-config = + Volume::{ + , name = input.scheduler.config.secretName + , dir = "/etc/zuul-scheduler" } - , Nodepool = - let nodepool-image = - \(name : Text) -> Some (image ("nodepool-" ++ name)) - let nodepool-data-dir = - [ Volume::{ - , name = "nodepool-data" - , dir = "/var/lib/nodepool" - } - ] + let gearman-config = + Volume::{ + , name = input.name ++ "-gearman-tls" + , dir = "/etc/zuul-gearman" + } - let nodepool-config = - Volume::{ - , name = input.launcher.config.secretName - , dir = "/etc/nodepool-config" + let executor-ssh-key = + Volume::{ + , name = input.executor.ssh_key.secretName + , dir = "/etc/zuul-executor" + } + + let zuul-volumes = + [ etc-zuul, gearman-config ] # zk-conf.ClientVolumes + + in { Scheduler = + ./components/Scheduler.dhall + input.name + ( input.scheduler + // zuul-image "scheduler" input.scheduler.image + ) + zuul-data-dir + (zuul-volumes # [ sched-config ]) + (zuul-env # db-secret-env # zk-conf.Env) + , Executor = + ./components/Executor.dhall + input.name + ( input.executor + // zuul-image "executor" input.executor.image + ) + zuul-data-dir + (zuul-volumes # [ executor-ssh-key ]) + (zuul-env # db-nosecret-env) + input.jobVolumes + , Web = + ./components/Web.dhall + input.name + (input.web // zuul-image "web" input.web.image) + zuul-data-dir + zuul-volumes + (zuul-env # db-secret-env # zk-conf.Env) + , Merger = + ./components/Merger.dhall + input.name + ( input.merger + // zuul-image "merger" input.merger.image + ) + zuul-data-dir + zuul-volumes + (zuul-env # db-nosecret-env) + , Registry = + ./components/Registry.dhall + input.name + ( input.registry + // zuul-image "registry" input.registry.image + ) + zuul-data-dir + [ etc-zuul-registry ] + , Preview = + ./components/Preview.dhall + input.name + ( input.preview + // zuul-image "preview" input.preview.image + ) + zuul-data-dir + } + , Nodepool = + let nodepool-image = + \(name : Text) -> Some (image ("nodepool-" ++ name)) + + let nodepool-data-dir = + [ Volume::{ + , name = "nodepool-data" + , dir = "/var/lib/nodepool" } + ] - let openstack-config = - merge - { None = [] : List Volume.Type - , Some = - \(some : UserSecret) - -> [ Volume::{ - , name = some.secretName - , dir = "/etc/nodepool-openstack" - } + let nodepool-config = + Volume::{ + , name = input.launcher.config.secretName + , dir = "/etc/nodepool-config" + } + + let openstack-config = + merge + { None = [] : List Volume.Type + , Some = + \(some : UserSecret) -> + [ Volume::{ + , name = some.secretName + , dir = "/etc/nodepool-openstack" + } + ] + } + input.externalConfig.openstack + + let kubernetes-config = + merge + { None = [] : List Volume.Type + , Some = + \(some : UserSecret) -> + [ Volume::{ + , name = some.secretName + , dir = "/etc/nodepool-kubernetes" + } + ] + } + input.externalConfig.kubernetes + + let nodepool-env = + F.mkEnvVarValue + ( toMap + { HOME = "/var/lib/nodepool" + , OS_CLIENT_CONFIG_FILE = + "/etc/nodepool-openstack/" + ++ F.defaultKey + input.externalConfig.openstack + "clouds.yaml" + , KUBECONFIG = + "/etc/nodepool-kubernetes/" + ++ F.defaultKey + input.externalConfig.kubernetes + "kube.config" + } + ) + + let nodepool-volumes = + [ etc-nodepool, nodepool-config ] + # openstack-config + # kubernetes-config + # zk-conf.ClientVolumes + + let shard-config = + "cat /etc/nodepool/nodepool.yaml /etc/nodepool-config/*.yaml > /var/lib/nodepool/config.yaml; " + + in { Launcher = F.KubernetesComponent::{ + , Deployment = Some + ( F.mkDeployment + input.name + F.Component::{ + , name = "launcher" + , count = 1 + , data-dir = nodepool-data-dir + , volumes = nodepool-volumes + , container = Kubernetes.Container::{ + , name = "launcher" + , image = nodepool-image "launcher" + , args = Some + [ "sh" + , "-c" + , shard-config + ++ "nodepool-launcher -d -c /var/lib/nodepool/config.yaml" ] - } - input.externalConfig.openstack - - let kubernetes-config = - merge - { None = [] : List Volume.Type - , Some = - \(some : UserSecret) - -> [ Volume::{ - , name = some.secretName - , dir = "/etc/nodepool-kubernetes" - } - ] - } - input.externalConfig.kubernetes - - let nodepool-env = - F.mkEnvVarValue - ( toMap - { HOME = "/var/lib/nodepool" - , OS_CLIENT_CONFIG_FILE = - "/etc/nodepool-openstack/" - ++ F.defaultKey - input.externalConfig.openstack - "clouds.yaml" - , KUBECONFIG = - "/etc/nodepool-kubernetes/" - ++ F.defaultKey - input.externalConfig.kubernetes - "kube.config" + , imagePullPolicy = Some "IfNotPresent" + , env = Some nodepool-env + , volumeMounts = Some + ( F.mkVolumeMount + (nodepool-volumes # nodepool-data-dir) + ) + } } ) - - let nodepool-volumes = - [ etc-nodepool, nodepool-config ] - # openstack-config - # kubernetes-config - # zk-conf.ClientVolumes - - let shard-config = - "cat /etc/nodepool/nodepool.yaml /etc/nodepool-config/*.yaml > /var/lib/nodepool/config.yaml; " - - in { Launcher = F.KubernetesComponent::{ - , Deployment = Some - ( F.mkDeployment - input.name - F.Component::{ - , name = "launcher" - , count = 1 - , data-dir = nodepool-data-dir - , volumes = nodepool-volumes - , container = Kubernetes.Container::{ - , name = "launcher" - , image = nodepool-image "launcher" - , args = Some - [ "sh" - , "-c" - , shard-config - ++ "nodepool-launcher -d -c /var/lib/nodepool/config.yaml" - ] - , imagePullPolicy = Some "IfNotPresent" - , env = Some nodepool-env - , volumeMounts = Some - ( F.mkVolumeMount - (nodepool-volumes # nodepool-data-dir) - ) - } - } - ) - } } - } - - let mkSecret = - \(volume : Volume.Type) - -> Kubernetes.Resource.Secret - Kubernetes.Secret::{ - , metadata = Kubernetes.ObjectMeta::{ name = volume.name } - , stringData = Some - ( Prelude.List.map - { path : Text, content : Text } - { mapKey : Text, mapValue : Text } - ( \(config : { path : Text, content : Text }) - -> { mapKey = config.path - , mapValue = config.content - } - ) - volume.files - ) } - - let {- This function transforms the different types into the Kubernetes.Resource - union to enable using them inside a single List array - -} mkUnion = - \(component : F.KubernetesComponent.Type) - -> let empty = [] : List Kubernetes.Resource - - in merge - { None = empty - , Some = - \(some : Kubernetes.Service.Type) - -> [ Kubernetes.Resource.Service some ] - } - component.Service - # merge - { None = empty - , Some = - \(some : Kubernetes.StatefulSet.Type) - -> [ Kubernetes.Resource.StatefulSet some ] - } - component.StatefulSet - # merge - { None = empty - , Some = - \(some : Kubernetes.Deployment.Type) - -> [ Kubernetes.Resource.Deployment some ] - } - component.Deployment - - let {- This function transform the Kubernetes.Resources type into the new Union - that combines Kubernetes and CertManager resources - -} transformKubernetesResource = - Prelude.List.map - Kubernetes.Resource - CertManager.Union - ( \(resource : Kubernetes.Resource) - -> CertManager.Union.Kubernetes resource - ) - - let {- if cert-manager is enabled, then includes and transforms the CertManager types - into the new Union that combines Kubernetes and CertManager resources - -} all-certificates = - if input.withCertManager - - then Prelude.List.map - CertManager.Issuer.Type - CertManager.Union - CertManager.Union.Issuer - Components.CertManager.Issuers - # Prelude.List.map - CertManager.Certificate.Type - CertManager.Union - CertManager.Union.Certificate - Components.CertManager.Certificates - - else [] : List CertManager.Union - - in { Components = Components - , List = - { apiVersion = "v1" - , kind = "List" - , items = - all-certificates - # transformKubernetesResource - ( Prelude.List.map - Volume.Type - Kubernetes.Resource - mkSecret - ( zk-conf.ServiceVolumes - # [ etc-zuul, etc-nodepool, etc-zuul-registry ] - ) - # mkUnion Components.Backend.Database - # mkUnion Components.Backend.ZooKeeper - # mkUnion Components.Zuul.Scheduler - # mkUnion Components.Zuul.Executor - # mkUnion Components.Zuul.Web - # mkUnion Components.Zuul.Merger - # mkUnion Components.Zuul.Registry - # mkUnion Components.Zuul.Preview - # mkUnion Components.Nodepool.Launcher - ) - } } + + let mkSecret = + \(volume : Volume.Type) -> + Kubernetes.Resource.Secret + Kubernetes.Secret::{ + , metadata = Kubernetes.ObjectMeta::{ name = volume.name } + , stringData = Some + ( Prelude.List.map + { path : Text, content : Text } + { mapKey : Text, mapValue : Text } + ( \(config : { path : Text, content : Text }) -> + { mapKey = config.path, mapValue = config.content } + ) + volume.files + ) + } + + let {- This function transforms the different types into the Kubernetes.Resource + union to enable using them inside a single List array + -} mkUnion = + \(component : F.KubernetesComponent.Type) -> + let empty = [] : List Kubernetes.Resource + + in merge + { None = empty + , Some = + \(some : Kubernetes.Service.Type) -> + [ Kubernetes.Resource.Service some ] + } + component.Service + # merge + { None = empty + , Some = + \(some : Kubernetes.StatefulSet.Type) -> + [ Kubernetes.Resource.StatefulSet some ] + } + component.StatefulSet + # merge + { None = empty + , Some = + \(some : Kubernetes.Deployment.Type) -> + [ Kubernetes.Resource.Deployment some ] + } + component.Deployment + + let {- This function transform the Kubernetes.Resources type into the new Union + that combines Kubernetes and CertManager resources + -} transformKubernetesResource = + Prelude.List.map + Kubernetes.Resource + CertManager.Union + ( \(resource : Kubernetes.Resource) -> + CertManager.Union.Kubernetes resource + ) + + let {- if cert-manager is enabled, then includes and transforms the CertManager types + into the new Union that combines Kubernetes and CertManager resources + -} all-certificates = + if input.withCertManager + then Prelude.List.map + CertManager.Issuer.Type + CertManager.Union + CertManager.Union.Issuer + Components.CertManager.Issuers + # Prelude.List.map + CertManager.Certificate.Type + CertManager.Union + CertManager.Union.Certificate + Components.CertManager.Certificates + else [] : List CertManager.Union + + in { Components + , List = + { apiVersion = "v1" + , kind = "List" + , items = + all-certificates + # transformKubernetesResource + ( Prelude.List.map + Volume.Type + Kubernetes.Resource + mkSecret + ( zk-conf.ServiceVolumes + # [ etc-zuul, etc-nodepool, etc-zuul-registry ] + ) + # mkUnion Components.Backend.Database + # mkUnion Components.Backend.ZooKeeper + # mkUnion Components.Zuul.Scheduler + # mkUnion Components.Zuul.Executor + # mkUnion Components.Zuul.Web + # mkUnion Components.Zuul.Merger + # mkUnion Components.Zuul.Registry + # mkUnion Components.Zuul.Preview + # mkUnion Components.Nodepool.Launcher + ) + } + }