diff --git a/README.md b/README.md index e7e20da4..0617028c 100644 --- a/README.md +++ b/README.md @@ -168,8 +168,6 @@ We can now expose this service out to the world with the Ingress: -- Prelude imports let map = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/List/map -in let Some = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/Optional/Some -in let None = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/Optional/None -- dhall-kubernetes types and defaults in let TLS = ../types/io.k8s.api.extensions.v1beta1.IngressTLS.dhall @@ -192,30 +190,30 @@ in let mkIngress : Config -> Ingress = \(config : Config) -> -- Given a service, make a TLS definition with their host and certificate - let makeTLS = \(service : Service) -> - { hosts = Some (List Text) [ service.host ] - , secretName = Some Text "${service.name}-certificate" - } + let makeTLS = \(service : Service) -> + { hosts = Some [ service.host ] + , secretName = Some "${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 = IntOrString.Int 80 - } - , path = None Text - } - ] - } - } + { host = Some service.host + , http = Some + { paths = [ { backend = { serviceName = service.name + , servicePort = IntOrString.Int 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" - } + { name = "default" + , host = "default.example.com" + , version = " 1.0" + } -- List of services in let services = config.services # [ defaultService ] @@ -226,23 +224,23 @@ in let mkIngress : Config -> Ingress = 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" - ] + in let annotations = Some + [ 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) - } + { tls = Some (map Service TLS makeTLS services) + , rules = Some (map Service Rule makeRule services) + } in defaultIngress - { metadata = defaultMeta - { name = "nginx" } // - { annotations = annotations } - } // - { spec = Some Spec spec } + { metadata = defaultMeta + { name = "nginx" } // + { annotations = annotations } + } // + { spec = Some spec } -- Here we import our example service, and generate the ingress with it diff --git a/api/Deployment/mkDeployment b/api/Deployment/mkDeployment index f0e6a6ed..2623a4d8 100644 --- a/api/Deployment/mkDeployment +++ b/api/Deployment/mkDeployment @@ -1,8 +1,6 @@ -- Prelude - let Prelude = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/package.dhall + let Prelude = https://raw.githubusercontent.com/dhall-lang/Prelude/v3.0.0/package.dhall in let map = Prelude.`List`.map -in let Some = Prelude.`Optional`.Some -in let None = Prelude.`Optional`.None in let kv = Prelude.JSON.keyText -- Kubernetes types and defaults @@ -18,14 +16,14 @@ in let mkProbe : ./Probe → Optional Types.Probe = λ(probe : ./Probe) → - Some Types.Probe + Some (default.probe // - { initialDelaySeconds = Some Natural probe.initial - , periodSeconds = Some Natural probe.period - , httpGet = Some Types.HttpGet + { initialDelaySeconds = Some probe.initial + , periodSeconds = Some probe.period + , httpGet = Some (default.httpGet { port = default.Int probe.port } // - { path = Some Text probe.path + { path = Some probe.path }) }) @@ -36,7 +34,7 @@ in let mkEnvVar : KV → Types.EnvVar = default.envVar { name = var.mapKey } // - { value = Some Text var.mapValue } + { value = Some var.mapValue } in let mkEmptyVolume : { name : Text } → Types.Volume = @@ -45,7 +43,7 @@ in let mkEmptyVolume : { name : Text } → Types.Volume = default.volume { name = vol.name } // - { emptyDir = Some Types.EmptyVolume default.emptyVolume } + { emptyDir = Some default.emptyVolume } in let mkSecretVolume : { name : Text } → Types.Volume = @@ -54,8 +52,8 @@ in let mkSecretVolume : { name : Text } → Types.Volume = default.volume { name = vol.name } // - { secret = Some Types.SecretVolume - (default.secretVolume // { secretName = Some Text vol.name } ) + { secret = Some + (default.secretVolume // { secretName = Some vol.name } ) } @@ -65,7 +63,7 @@ in let mkPathVolume : { name : Text, path : Text } → Types.Volume = default.volume { name = vol.name } // - { hostPath = Some Types.PathVolume + { hostPath = Some (default.pathVolume { path = vol.path }) } @@ -87,21 +85,21 @@ in let mkContainer : ./Container → Types.Container = default.container { name = container.name } // - { image = Some Text "${container.imageName}:${container.imageTag}" - , imagePullPolicy = Some Text container.imagePullPolicy + { image = Some "${container.imageName}:${container.imageTag}" + , imagePullPolicy = Some container.imagePullPolicy , ports = Optional/fold Natural container.port (Optional (List Types.ContainerPort)) - (λ(port : Natural) → Some (List Types.ContainerPort) + (λ(port : Natural) → Some [(default.containerPort { containerPort = port })]) (None (List Types.ContainerPort)) - , resources = Some Types.Resources - { limits = Some ListKV [kv "cpu" "${Natural/show container.maxCPU}m"] - , requests = Some ListKV [kv "cpu" "${Natural/show container.minCPU}m"] + , resources = Some + { limits = Some [kv "cpu" "${Natural/show container.maxCPU}m"] + , requests = Some [kv "cpu" "${Natural/show container.minCPU}m"] } , command = container.command - , volumeMounts = Some (List Types.Mount) + , volumeMounts = Some (map ./Mount Types.Mount mkMount container.mounts) -- Poll the container to see if the it's alive or we should restart it , livenessProbe = Optional/fold @@ -117,7 +115,7 @@ in let mkContainer : ./Container → Types.Container = (Optional Types.Probe) mkProbe (None Types.Probe) - , env = Some (List Types.EnvVar) + , env = Some (map { mapKey : Text , mapValue : Text } Types.EnvVar mkEnvVar container.envVars) } @@ -126,12 +124,12 @@ in let mkDeployment : ./Deployment → Types.Deployment = λ(deployment : ./Deployment) → - let selector = Some ListKV [kv "app" deployment.name] + let selector = Some [kv "app" deployment.name] in let emptyVolumes = map { name : Text } Types.Volume mkEmptyVolume deployment.emptyVolumes in let secretVolumes = map { name : Text } Types.Volume mkSecretVolume deployment.secretVolumes in let pathVolumes = map { name : Text, path : Text } Types.Volume mkPathVolume deployment.pathVolumes - in let volumes = Some (List Types.Volume) (emptyVolumes # secretVolumes # pathVolumes) + in let volumes = Some (emptyVolumes # secretVolumes # pathVolumes) in let spec = default.spec { selector = default.selector // { matchLabels = selector } @@ -139,23 +137,23 @@ in let mkDeployment : ./Deployment → Types.Deployment = { metadata = default.meta { name = deployment.name } // { labels = selector } } // - { spec = Some Types.PodSpec (default.podSpec + { spec = Some (default.podSpec { containers = map ./Container Types.Container mkContainer deployment.containers } // { volumes = volumes }) } } // - { replicas = Some Natural deployment.replicas + { replicas = Some deployment.replicas -- Don't keep all the ReplicaSets - , revisionHistoryLimit = Some Natural deployment.revisionHistoryLimit - , strategy = Some Types.Strategy + , revisionHistoryLimit = Some deployment.revisionHistoryLimit + , strategy = Some -- Control the RollingUpdate so the app is always available. For more info see: -- https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ - { type = Some Text "RollingUpdate" - , rollingUpdate = Some Types.RollingUpdate - { maxSurge = Some Types.IntOrString (default.Int deployment.maxSurge) - , maxUnavailable = Some Types.IntOrString (default.Int deployment.maxUnavailable) + { type = Some "RollingUpdate" + , rollingUpdate = Some + { maxSurge = Some (default.Int deployment.maxSurge) + , maxUnavailable = Some (default.Int deployment.maxUnavailable) } } } @@ -163,7 +161,7 @@ in let mkDeployment : ./Deployment → Types.Deployment = in default.deployment { metadata = default.meta { name = deployment.name } } // - { spec = Some Types.Spec spec + { spec = Some spec } diff --git a/api/Service/mkService b/api/Service/mkService index 329a8817..e98bf57d 100644 --- a/api/Service/mkService +++ b/api/Service/mkService @@ -1,6 +1,5 @@ -- Prelude - let Prelude = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/package.dhall -in let Some = Prelude.`Optional`.Some + let Prelude = https://raw.githubusercontent.com/dhall-lang/Prelude/v3.0.0/package.dhall in let kv = Prelude.JSON.keyText -- Kubernetes types and defaults @@ -16,12 +15,12 @@ in let mkService : ./Service → Types.Service = λ(service : ./Service) → - let selector = Some ListKV [kv "app" service.name] + let selector = Some [kv "app" service.name] in let meta = default.meta { name = service.name } // { labels = selector - , annotations = Some ListKV service.annotations + , annotations = Some service.annotations } -- Handlers for the ServiceType union @@ -33,11 +32,11 @@ in let mkService : ./Service → Types.Service = } in let spec = default.spec // - { type = Some Text (merge handlers service.type : Text) - , ports = Some (List Types.Port) + { type = Some (merge handlers service.type : Text) + , ports = Some [ default.port { port = service.outPort } // - { targetPort = Some Types.IntOrString (default.Int service.containerPort) } + { targetPort = Some (default.Int service.containerPort) } ] , selector = selector } @@ -45,7 +44,7 @@ in let mkService : ./Service → Types.Service = in default.service { metadata = meta } // - { spec = Some Types.Spec spec + { spec = Some spec } : Types.Service in mkService diff --git a/examples/deploymentRaw.dhall b/examples/deploymentRaw.dhall index 30b14520..b73f0248 100644 --- a/examples/deploymentRaw.dhall +++ b/examples/deploymentRaw.dhall @@ -1,7 +1,5 @@ -- 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 @@ -32,36 +30,34 @@ in let mkDeployment : Config -> Deployment = \(deployment : Config) -> - let selector = Some (List { mapKey : Text, mapValue : Text }) - [{ mapKey = "app", mapValue = deployment.name }] + let selector = Some [{ mapKey = "app", mapValue = deployment.name }] in let spec = defaultSpec - { selector = defaultSelector // { matchLabels = selector } - , template = defaultTemplate - { metadata = defaultMeta - { name = deployment.name } // { labels = selector } - } // - { spec = Some PodSpec (defaultPodSpec - { containers = [ - defaultContainer - { name = deployment.name } // - { image = Some Text "your-container-service.io/${deployment.name}:${deployment.version}" - , imagePullPolicy = Some Text "Always" - , ports = Some (List ContainerPort) - [(defaultContainerPort {containerPort = 8080})] - } - ] - }) - } - } // - { replicas = Some Natural 2 - , revisionHistoryLimit = Some Natural 10 - } + { selector = defaultSelector // { matchLabels = selector } + , template = defaultTemplate + { metadata = defaultMeta + { name = deployment.name } // { labels = selector } + } // + { spec = Some (defaultPodSpec + { containers = [ + defaultContainer + { name = deployment.name } // + { image = Some "your-container-service.io/${deployment.name}:${deployment.version}" + , imagePullPolicy = Some "Always" + , ports = Some [(defaultContainerPort {containerPort = 8080})] + } + ] + }) + } + } // + { replicas = Some 2 + , revisionHistoryLimit = Some 10 + } in defaultDeployment - { metadata = defaultMeta { name = deployment.name } - } // - { spec = Some Spec spec } : Deployment + { metadata = defaultMeta { name = deployment.name } + } // + { spec = Some spec } : Deployment {- diff --git a/examples/ingressRaw.dhall b/examples/ingressRaw.dhall index 1d112de4..9d6daed8 100644 --- a/examples/ingressRaw.dhall +++ b/examples/ingressRaw.dhall @@ -1,7 +1,5 @@ -- Prelude imports let map = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/List/map -in let Some = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/Optional/Some -in let None = https://raw.githubusercontent.com/dhall-lang/Prelude/v2.0.0/Optional/None -- dhall-kubernetes types and defaults in let TLS = ../types/io.k8s.api.extensions.v1beta1.IngressTLS.dhall @@ -24,30 +22,30 @@ in let mkIngress : Config -> Ingress = \(config : Config) -> -- Given a service, make a TLS definition with their host and certificate - let makeTLS = \(service : Service) -> - { hosts = Some (List Text) [ service.host ] - , secretName = Some Text "${service.name}-certificate" - } + let makeTLS = \(service : Service) -> + { hosts = Some [ service.host ] + , secretName = Some "${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 = IntOrString.Int 80 - } - , path = None Text - } - ] - } - } + { host = Some service.host + , http = Some + { paths = [ { backend = { serviceName = service.name + , servicePort = IntOrString.Int 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" - } + { name = "default" + , host = "default.example.com" + , version = " 1.0" + } -- List of services in let services = config.services # [ defaultService ] @@ -58,23 +56,23 @@ in let mkIngress : Config -> Ingress = 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" - ] + in let annotations = Some + [ 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) - } + { tls = Some (map Service TLS makeTLS services) + , rules = Some (map Service Rule makeRule services) + } in defaultIngress - { metadata = defaultMeta - { name = "nginx" } // - { annotations = annotations } - } // - { spec = Some Spec spec } + { metadata = defaultMeta + { name = "nginx" } // + { annotations = annotations } + } // + { spec = Some spec } -- Here we import our example service, and generate the ingress with it diff --git a/nix/dhall-1.18.0.nix b/nix/dhall-1.18.0.nix new file mode 100644 index 00000000..b8abe2f6 --- /dev/null +++ b/nix/dhall-1.18.0.nix @@ -0,0 +1,36 @@ +{ mkDerivation, ansi-terminal, base, bytestring, case-insensitive +, cborg, containers, contravariant, criterion, cryptonite, deepseq +, Diff, directory, doctest, exceptions, filepath, haskeline +, http-client, http-client-tls, lens-family-core, megaparsec +, memory, mockery, mtl, optparse-applicative, parsers +, prettyprinter, prettyprinter-ansi-terminal, QuickCheck +, quickcheck-instances, repline, scientific, serialise, stdenv +, tasty, tasty-hunit, tasty-quickcheck, template-haskell, text +, transformers, unordered-containers, vector +}: +mkDerivation { + pname = "dhall"; + version = "1.18.0"; + sha256 = "b528ecff4f757fa085f61636ffb8a6eb90c761106d7d20bd735bee48a6abab94"; + isLibrary = true; + isExecutable = true; + libraryHaskellDepends = [ + ansi-terminal base bytestring case-insensitive cborg containers + contravariant cryptonite Diff directory exceptions filepath + haskeline http-client http-client-tls lens-family-core megaparsec + memory mtl optparse-applicative parsers prettyprinter + prettyprinter-ansi-terminal repline scientific serialise + template-haskell text transformers unordered-containers vector + ]; + executableHaskellDepends = [ base ]; + testHaskellDepends = [ + base containers deepseq directory doctest filepath mockery + prettyprinter QuickCheck quickcheck-instances serialise tasty + tasty-hunit tasty-quickcheck text transformers vector + ]; + benchmarkHaskellDepends = [ + base bytestring containers criterion directory serialise text + ]; + description = "A configuration language guaranteed to terminate"; + license = stdenv.lib.licenses.bsd3; +} diff --git a/nix/dhall-json-1.2.4.nix b/nix/dhall-json-1.2.4.nix new file mode 100644 index 00000000..2bcc2260 --- /dev/null +++ b/nix/dhall-json-1.2.4.nix @@ -0,0 +1,23 @@ +{ mkDerivation, aeson, aeson-pretty, base, bytestring, dhall +, optparse-applicative, stdenv, tasty, tasty-hunit, text +, unordered-containers, vector, yaml +}: +mkDerivation { + pname = "dhall-json"; + version = "1.2.4"; + sha256 = "e594b47a168c47225d929d94c8dce12b9b32a195c9faa02ff091b3f18adb63e7"; + isLibrary = true; + isExecutable = true; + libraryHaskellDepends = [ + aeson base dhall optparse-applicative text unordered-containers + ]; + executableHaskellDepends = [ + aeson aeson-pretty base bytestring dhall optparse-applicative text + vector yaml + ]; + testHaskellDepends = [ + aeson base bytestring dhall tasty tasty-hunit text + ]; + description = "Compile Dhall to JSON or YAML"; + license = stdenv.lib.licenses.bsd3; +} diff --git a/nix/megaparsec-7.0.2.nix b/nix/megaparsec-7.0.2.nix new file mode 100644 index 00000000..f584b56f --- /dev/null +++ b/nix/megaparsec-7.0.2.nix @@ -0,0 +1,25 @@ +{ mkDerivation, base, bytestring, case-insensitive, containers +, criterion, deepseq, hspec, hspec-expectations, mtl +, parser-combinators, QuickCheck, scientific, stdenv, text +, transformers, weigh +}: +mkDerivation { + pname = "megaparsec"; + version = "7.0.2"; + sha256 = "e888f6a1ef6c9908c9893f2cd4105d12d7778cf88f885b416915fcd89526c5db"; + libraryHaskellDepends = [ + base bytestring case-insensitive containers deepseq mtl + parser-combinators scientific text transformers + ]; + testHaskellDepends = [ + base bytestring case-insensitive containers hspec + hspec-expectations mtl parser-combinators QuickCheck scientific + text transformers + ]; + benchmarkHaskellDepends = [ + base containers criterion deepseq text weigh + ]; + homepage = "https://github.com/mrkkrp/megaparsec"; + description = "Monadic parser combinators"; + license = stdenv.lib.licenses.bsd2; +} diff --git a/nix/repline-0.2.0.0.nix b/nix/repline-0.2.0.0.nix new file mode 100644 index 00000000..e9fa564e --- /dev/null +++ b/nix/repline-0.2.0.0.nix @@ -0,0 +1,11 @@ +{ mkDerivation, base, containers, haskeline, mtl, process, stdenv +}: +mkDerivation { + pname = "repline"; + version = "0.2.0.0"; + sha256 = "ecc72092d0340b896ee6bf96bf6645694dbcd33361725a2cd28c5ab5d60c02de"; + libraryHaskellDepends = [ base containers haskeline mtl process ]; + homepage = "https://github.com/sdiehl/repline"; + description = "Haskeline wrapper for GHCi-like REPL interfaces"; + license = stdenv.lib.licenses.mit; +} diff --git a/nixpkgs.nix b/nixpkgs.nix index 746f7528..15e84431 100644 --- a/nixpkgs.nix +++ b/nixpkgs.nix @@ -1,10 +1,23 @@ let - rev = "c5f9cd4cde81bcef2c8882d359d9d30313bebeb3"; - outputSha256 = "1nilhz6rhfg3ckp8yfmgy6v3q6spbyxfg0yn8rc2ydyn7119h4fn"; + rev = "19013d809297cb9dbba69bda24e52a2833f4e05a"; + outputSha256 = "148nqqyb39xmxlnw4vgqin2s7ywq51yi64d2hqmd6pk2gqnhmpv9"; nixpkgs = builtins.fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz"; sha256 = outputSha256; }; + + config = { + packageOverrides = pkgs: rec { + haskellPackages = pkgs.haskellPackages.override { + overrides = haskellPackagesNew: haskellPackagesOld: rec { + dhall = haskellPackagesNew.callPackage ./nix/dhall-1.18.0.nix {}; + dhall-json = haskellPackagesNew.callPackage ./nix/dhall-json-1.2.4.nix {}; + megaparsec = haskellPackagesNew.callPackage ./nix/megaparsec-7.0.2.nix {}; + repline = haskellPackagesNew.callPackage ./nix/repline-0.2.0.0.nix {}; + }; + }; + }; + }; in - import nixpkgs {} + import nixpkgs { inherit config; }