local kube = import "../../../kube/kube.libsonnet"; { IX: { local ix = self, local cfg = ix.cfg, cfg:: { image: "registry.k0.hswaw.net/bgpwtf/cccampix:1566584484-a2960f526c36de0dbcd911f05ee9db587e63eb9b", octorpki: { image: cfg.image, storageClassName: "waw-hdd-redundant-2", resources: { requests: { cpu: "200m", memory: "1Gi" }, limits: { cpu: "1", memory: "2Gi" }, }, }, verifier: { image: cfg.image, domain: "ix-grpc.bgp.wtf", db: { host: "public.crdb-waw1.svc.cluster.local", port: 26257, username: "cccampix", name: "cccampix", tlsSecret: "client-cccampix-certificate", }, }, pgpencryptor: { image: cfg.image, db: { host: "public.crdb-waw1.svc.cluster.local", port: 26257, username: "cccampix", name: "cccampix-pgpencryptor", tlsSecret: "client-cccampix-certificate", }, }, irr: { image: cfg.image, }, peeringdb: { image: cfg.image, }, frontend: { domain: "ix-status.bgp.wtf", image: cfg.image, }, alice: { domain: "ix-lg.bgp.wtf", image: "registry.k0.hswaw.net/q3k/alice-lg:20190823-1557", }, appName: "ix", namespace: error "namespace must be defined", prefix: "", }, namespace: kube.Namespace(cfg.namespace), name(component):: cfg.prefix + component, metadata(component):: { namespace: cfg.namespace, labels: { "app.kubernetes.io/name": cfg.appName, "app.kubernetes.io/managed-by": "kubecfg", "app.kubernetes.io/component": component, }, }, octorpki: { address:: "%s.%s.svc.cluster.local:%d" % [ "octorpki", ix.cfg.namespace, 8080, ], cache: kube.PersistentVolumeClaim(ix.name("octorpki")) { metadata+: ix.metadata("octorpki"), spec+: { storageClassName: cfg.octorpki.storageClassName, accessModes: [ "ReadWriteOnce" ], resources: { requests: { storage: "2Gi", }, }, }, }, deployment: kube.Deployment(ix.name("octorpki")) { metadata+: ix.metadata("octorpki"), spec+: { template+: { spec+: { volumes_: { cache: kube.PersistentVolumeClaimVolume(ix.octorpki.cache), }, containers_: { octorpki: kube.Container(ix.name("octorpki")){ image: cfg.octorpki.image, args: [ "/octorpki/entrypoint.sh", ], ports_: { client: { containerPort: 8080 }, }, volumeMounts_: { cache: { mountPath: "/cache" }, }, resources: cfg.octorpki.resources, }, }, }, }, }, }, svc: kube.Service(ix.name("octorpki")) { metadata+: ix.metadata("octorpki"), target_pod:: ix.octorpki.deployment.spec.template, spec+: { ports: [ { name: "client", port: 8080, targetPort: 8080, protocol: "TCP" }, ], }, }, }, component(name):: { local component = self, args:: error "args must be set", name:: name, port:: 4200, volumes:: {}, volumeMounts:: {}, deployment: kube.Deployment(ix.name(name)) { metadata+: ix.metadata(name), spec+: { template+: { spec+: { volumes_: component.volumes, containers_: { [name]: kube.Container(ix.name(name)) { image: cfg[name].image, args: component.args, volumeMounts_: component.volumeMounts, }, }, }, }, }, }, svc: kube.Service(ix.name(name)) { metadata+: ix.metadata(name), target_pod:: component.deployment.spec.template, spec+: { ports: [ { name: "client", port: component.port, targetPort: component.port, protocol: "TCP" }, ], }, }, address:: "%s.%s.svc.cluster.local:%d" % [ component.name, ix.cfg.namespace, component.port, ], }, irr: ix.component("irr") { args: [ "/ix/irr", "-hspki_disable", "-listen_address=0.0.0.0:4200", ], }, peeringdb: ix.component("peeringdb") { args: [ "/ix/peeringdb", "-hspki_disable", "-listen_address=0.0.0.0:4200", ], }, crdb:: { volumes: { tls: { secret: { secretName: cfg.verifier.db.tlsSecret, defaultMode: kube.parseOctal("0400"), }, }, }, volumeMounts: { tls: { mountPath: "/tls", }, }, args(dbconf): [ "-dsn", "postgres://%s@%s:%d/%s?sslmode=require&sslrootcert=%s&sslcert=%s&sslkey=%s" % [ dbconf.username, dbconf.host, dbconf.port, dbconf.name, "/tls/ca.crt", "/tls/tls.crt", "/tls/tls.key", ], ] }, verifier: ix.component("verifier") { volumes: ix.crdb.volumes, volumeMounts: ix.crdb.volumeMounts, args: [ "/ix/verifier", "-hspki_disable", "-listen_address=0.0.0.0:4200", "-peeringdb=" + ix.peeringdb.address, "-irr=" + ix.irr.address, "-octorpki=" + ix.octorpki.address, "-pgpencryptor=" + ix.pgpencryptor.address, ] + ix.crdb.args(cfg.verifier.db), }, pgpencryptor: ix.component("pgpencryptor") { volumes: ix.crdb.volumes, volumeMounts: ix.crdb.volumeMounts, args: [ "/ix/pgpencryptor", "-hspki_disable", "-listen_address=0.0.0.0:4200", ] + ix.crdb.args(cfg.pgpencryptor.db), }, frontend: ix.component("frontend") { port: 8080, args: [ "/ix/frontend.par", "--flask_secret=dupa", "--listen=0.0.0.0:8080", "--verifier=" + ix.verifier.address, ], }, alice: ix.component("alice") { port: 7340, volumes: { config: kube.ConfigMapVolume(ix.alice.configMap), theme: kube.ConfigMapVolume(ix.alice.themeMap), }, volumeMounts: { config: { mountPath: "/etc/alice", }, theme: { mountPath: "/etc/alice-theme", }, }, args: [ "/usr/bin/alice-lg", "-config", "/etc/alice/alice", ], themeMap: kube.ConfigMap(ix.name("alice-theme")) { metadata+: ix.metadata("alice-theme"), data: { "content.js": ||| Alice.updateContent({ header: { title: "CCCampIX Looking Glass", tagline: "powered by alice-lg" }, welcome: { title: "CCCampIX Looking Glass", tagline: "BGP to the tent." } }); |||, }, }, configMap: kube.ConfigMap(ix.name("alice")) { metadata+: ix.metadata("alice"), data: { config: ||| [server] listen_http = 0.0.0.0:7340 enable_neighbors_status_refresh = false asn = 208521 [housekeeping] interval = 5 force_release_memory = true [theme] path = /etc/alice-theme [pagination] routes_filtered_page_size = 250 routes_accepted_page_size = 250 routes_not_exported_page_size = 250 [rejection_reasons] 208521:65666:1 = An IP Bogon was detected 208521:65666:2 = Prefix is longer than 64 208521:65666:3 = Prefix is longer than 24 208521:65666:4 = AS path contains a bogon AS 208521:65666:5 = AS path length is longer than 64 208521:65666:6 = BGP Path invalid (must be only peer) 208521:65666:9 = Prefix not found in RPKI for Origin AS [neighbours_columns] Description = Description address = Neighbour asn = ASN state = State Uptime = Uptime routes_received = Routes Received routes_filtered = Filtered [routes_columns] network = Network gateway = Gateway interface = Interface metric = Metric bgp.as_path = AS Path [lookup_columns] network = Network gateway = Gateway neighbour.asn = ASN neighbour.description = Description bgp.as_path = AS Path routeserver.name = RS [source.rs1-camp-v4] name = rs1.camp.bgp.wtf (IPv4) group = Camp [source.rs1-camp-v4.birdwatcher] timezone = UTC api = http://isw01.camp.bgp.wtf:3000/ type = single_table neighbors_refresh_timeout = 2 servertime = 2006-01-02T15:04:05Z servertime_short = 2006-01-02 15:04:05 servertime_ext = 2006-01-02 15:04:05 [source.rs1-camp-v6] name = rs1.camp.bgp.wtf (IPv6) group = Camp [source.rs1-camp-v6.birdwatcher] timezone = UTC api = http://isw01.camp.bgp.wtf:3001/ type = single_table neighbors_refresh_timeout = 2 servertime = 2006-01-02T15:04:05Z servertime_short = 2006-01-02 15:04:05 servertime_ext = 2006-01-02 15:04:05 [source.rs2-camp-v4] name = rs2.camp.bgp.wtf (IPv4) group = Camp [source.rs2-camp-v4.birdwatcher] timezone = UTC api = http://isw01.camp.bgp.wtf:3002/ type = single_table neighbors_refresh_timeout = 2 servertime = 2006-01-02T15:04:05Z servertime_short = 2006-01-02 15:04:05 servertime_ext = 2006-01-02 15:04:05 [source.rs2-camp-v6] name = rs2.camp.bgp.wtf (IPv6) group = Camp [source.rs2-camp-v6.birdwatcher] timezone = UTC api = http://isw01.camp.bgp.wtf:3003/ type = single_table neighbors_refresh_timeout = 2 servertime = 2006-01-02T15:04:05Z servertime_short = 2006-01-02 15:04:05 servertime_ext = 2006-01-02 15:04:05 |||, }, }, }, ripeSync: kube.CronJob(ix.name("ripe-sync")) { metadata+: ix.metadata("ripe-sync"), spec+: { schedule: "*/5 * * * *", jobTemplate+: { spec+: { selector:: null, template+: { spec+: { containers_: { "ripe-sync": kube.Container(ix.name("ripe-sync")) { image: cfg.image, args: [ "/ix/ripe-sync.par", "$(PASSWORD)", ix.verifier.address, ], env_: { PASSWORD: { secretKeyRef: { name: ix.name("ripe-sync"), key: "password", }, }, }, }, }, }, }, }, }, }, }, ingress: kube.Ingress("ingress") { metadata+: ix.metadata("public") { annotations+: { "kubernetes.io/tls-acme": "true", "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", "nginx.ingress.kubernetes.io/proxy-body-size": "0", }, }, spec+: { tls: [ { hosts: [cfg.frontend.domain], secretName: "public-tls"} ], rules: [ { host: cfg.frontend.domain, http: { paths: [ { path: "/", backend: ix.frontend.svc.name_port }, ], }, }, ], }, }, aliceIngress: kube.Ingress("alice") { metadata+: ix.metadata("alice") { annotations+: { "kubernetes.io/tls-acme": "true", "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", "nginx.ingress.kubernetes.io/proxy-body-size": "0", }, }, spec+: { tls: [ { hosts: [cfg.alice.domain], secretName: "alice-tls"} ], rules: [ { host: cfg.alice.domain, http: { paths: [ { path: "/", backend: ix.alice.svc.name_port }, ], }, }, ], }, }, grpcIngress: kube.Ingress("grpc") { metadata+: ix.metadata("grpc") { annotations+: { "kubernetes.io/tls-acme": "true", "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", "kubernetes.io/ingress.class": "nginx", "nginx.ingress.kubernetes.io/ssl-redirect": "true", "nginx.ingress.kubernetes.io/backend-protocol": "GRPC", }, }, spec+: { tls: [ { hosts: [cfg.verifier.domain], secretName: "grpc-tls"} ], rules: [ { host: cfg.verifier.domain, http: { paths: [ { path: "/", backend: ix.verifier.svc.name_port }, ], }, }, ], }, }, }, }