kube: standardize on a `local ns` convention

A convention is introduced to specify the kube.Namespace object in a deployment as a `local ns` instead of an `ns:` or a `namespace:` for these reasons:

- non-cluster admins cannot create new namespaces, and we've been moving in the direction of specifying objects that require cluster admin permissions to apply (policies, role bindings) in //cluster/kube/k0 instead of in the app jsonnet
- namespace admins CAN delete the namespace, making `kubecfg delete` unexpectedly dangerous (especially if a namespace contains more than just the contents of the file being applied - common with personal namespaces)
- `.Contain()` is a common operation, and it shows up in lines that are pretty long, so `ns.Contain()` is preferable to `app.ns.Contain()` or `service.namespace.Contain()`

Change-Id: Ie4ea825376dbf6faa175179054f3ee3de2253ae0
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1804
Reviewed-by: q3k <q3k@hackerspace.pl>
diff --git a/app/inventory/prod.jsonnet b/app/inventory/prod.jsonnet
index 5648692..984d610 100644
--- a/app/inventory/prod.jsonnet
+++ b/app/inventory/prod.jsonnet
@@ -26,8 +26,9 @@
     oauth: { secretKeyRef: { name: cfg.name, key: 'oauth_secret' } },
   },
 
-  ns: kube.Namespace(cfg.namespace),
-  deployment: top.ns.Contain(kube.Deployment(cfg.name)) {
+  local ns = kube.Namespace(cfg.namespace),
+
+  deployment: ns.Contain(kube.Deployment(cfg.name)) {
     spec+: {
       template+: {
         spec+: {
@@ -64,7 +65,7 @@
     },
   },
 
-  media: top.ns.Contain(kube.PersistentVolumeClaim(cfg.name)) {
+  media: ns.Contain(kube.PersistentVolumeClaim(cfg.name)) {
     storage:: '20Gi',
     storageClass:: cfg.storageClassName,
   },
@@ -83,11 +84,11 @@
     bouncer: {},
   },
 
-  service: top.ns.Contain(kube.Service(cfg.name)) {
+  service: ns.Contain(kube.Service(cfg.name)) {
     target:: top.deployment,
   },
 
-  ingress: top.ns.Contain(kube.SimpleIngress(cfg.name)) {
+  ingress: ns.Contain(kube.SimpleIngress(cfg.name)) {
     hosts:: [cfg.domain],
     target_service:: top.service,
   },
diff --git a/app/mailman-web/kube/mailman.libsonnet b/app/mailman-web/kube/mailman.libsonnet
index c75e3b0..a4297cb 100644
--- a/app/mailman-web/kube/mailman.libsonnet
+++ b/app/mailman-web/kube/mailman.libsonnet
@@ -55,9 +55,7 @@
 
     },
 
-    namespace: kube.Namespace(cfg.namespace),
-    local ns = self.namespace,
-
+    local ns = kube.Namespace(cfg.namespace),
 
     web: ns.Contain(kube.Deployment("web")) {
         spec+: {
diff --git a/app/mastodon/kube/mastodon.libsonnet b/app/mastodon/kube/mastodon.libsonnet
index 025eef8..4de7766 100644
--- a/app/mastodon/kube/mastodon.libsonnet
+++ b/app/mastodon/kube/mastodon.libsonnet
@@ -113,8 +113,8 @@
         OIDC_JWKS_URI: "https://sso.hackerspace.pl/.well-known/jwks.json",
     },
 
-    namespace: kube.Namespace(cfg.namespace),
-    local ns = self.namespace,
+    local ns = kube.Namespace(cfg.namespace),
+    namespace:: ns, // used by dumper.jsonnet
 
     # there used to be a nonversioned postgres (10.4) here
     # at time of writing it exists in prod, scaled down to 0, to preserve the PVC
diff --git a/app/matrix/lib/cas.libsonnet b/app/matrix/lib/cas.libsonnet
index f1de4fe..4c70b45 100644
--- a/app/matrix/lib/cas.libsonnet
+++ b/app/matrix/lib/cas.libsonnet
@@ -13,8 +13,9 @@
     },
 
     ns:: error "ns needs to be a kube.Namespace object",
+    local ns = app.ns,
 
-    deployment: app.ns.Contain(kube.Deployment("oauth2-cas-proxy")) {
+    deployment: ns.Contain(kube.Deployment("oauth2-cas-proxy")) {
         spec+: {
             replicas: 1,
             template+: {
@@ -42,7 +43,7 @@
         },
     },
 
-    svc: app.ns.Contain(kube.Service("oauth2-cas-proxy")) {
+    svc: ns.Contain(kube.Service("oauth2-cas-proxy")) {
         target:: app.deployment,
     },
 }
diff --git a/app/matrix/lib/coturn.libsonnet b/app/matrix/lib/coturn.libsonnet
index f1b127b..cfb5024 100644
--- a/app/matrix/lib/coturn.libsonnet
+++ b/app/matrix/lib/coturn.libsonnet
@@ -15,8 +15,9 @@
     },
 
     ns:: error "ns needs to be provided",
+    local ns = app.ns,
 
-    configMap: app.ns.Contain(kube.ConfigMap("coturn")) {
+    configMap: ns.Contain(kube.ConfigMap("coturn")) {
         data: {
             "coturn.conf": |||
                 # VoIP traffic is all UDP. There is no reason to let users connect to arbitrary TCP endpoints via the relay.
@@ -59,12 +60,12 @@
         },
     },
 
-    dataVolume: app.ns.Contain(kube.PersistentVolumeClaim("coturn-data")) {
+    dataVolume: ns.Contain(kube.PersistentVolumeClaim("coturn-data")) {
         storage:: "10Gi",
         storageClass:: cfg.storageClassName,
     },
 
-    deployment: app.ns.Contain(kube.Deployment("coturn")) {
+    deployment: ns.Contain(kube.Deployment("coturn")) {
         spec+: {
             replicas: 1,
             template+: {
@@ -129,7 +130,7 @@
         },
     },
 
-    svcTCP: app.ns.Contain(kube.Service("coturn-tcp")) {
+    svcTCP: ns.Contain(kube.Service("coturn-tcp")) {
         target:: app.deployment,
         metadata+: {
             annotations+: {
@@ -149,7 +150,7 @@
         },
     },
 
-    svcUDP: app.ns.Contain(kube.Service("coturn-udp")) {
+    svcUDP: ns.Contain(kube.Service("coturn-udp")) {
         target:: app.deployment,
         metadata+: {
             annotations+: {
diff --git a/app/matrix/lib/matrix-ng.libsonnet b/app/matrix/lib/matrix-ng.libsonnet
index 18120f0..620a8d5 100644
--- a/app/matrix/lib/matrix-ng.libsonnet
+++ b/app/matrix/lib/matrix-ng.libsonnet
@@ -243,7 +243,7 @@
         },
     },
 
-    namespace: kube.Namespace(cfg.namespace),
+    local ns = kube.Namespace(cfg.namespace),
 
     postgres3: if cfg.postgres.enable then postgres {
         local psql = self,
@@ -282,7 +282,7 @@
     },
 
     riot: riot {
-        ns: app.namespace,
+        ns: ns,
         cfg+: {
             webDomain: cfg.webDomain,
             serverName: cfg.serverName,
@@ -292,7 +292,7 @@
 
     cas: if cfg.cas.enable && cfg.oidc.enable then error "cfg.cas.enable and cfg.oidc.enable options are exclusive"
         else if cfg.cas.enable then cas {
-        ns: app.namespace,
+        ns: ns,
         cfg+: {
             image: cfg.images.casProxy,
             webDomain: cfg.webDomain,
@@ -301,7 +301,7 @@
     },
 
     wellKnown: if cfg.wellKnown then wellKnown {
-        ns: app.namespace,
+        ns: ns,
         cfg+: {
             image: cfg.images.wellKnown,
             webDomain: cfg.webDomain,
@@ -309,7 +309,7 @@
     } else {},
 
     mediaRepo: if cfg.mediaRepo.enable then mediaRepo {
-        ns: app.namespace,
+        ns: ns,
         cfg+: {
             image: cfg.images.mediaRepo,
 
@@ -324,7 +324,7 @@
     } else {},
 
     coturn: if cfg.coturn.enable then coturn {
-        ns: app.namespace,
+        ns: ns,
         cfg+: {
             storageClassName: cfg.storageClassName,
             image: cfg.images.coturn,
@@ -335,7 +335,7 @@
     } else null,
 
     synapse: synapse {
-        ns: app.namespace,
+        ns: ns,
         postgres: if cfg.postgres.enable then app.postgres3 else {
             # If not using on-cluster postgres, pass the config postgres object
             # as the postgres object into the synapse lib. It's a bit ugly (we
diff --git a/app/matrix/lib/matrix.libsonnet b/app/matrix/lib/matrix.libsonnet
index 29cdaf5..fef0bd8 100644
--- a/app/matrix/lib/matrix.libsonnet
+++ b/app/matrix/lib/matrix.libsonnet
@@ -80,7 +80,7 @@
         },
     },
 
-    namespace: kube.Namespace(cfg.namespace),
+    local ns = kube.Namespace(cfg.namespace),
 
     postgres3: postgres {
         cfg+: {
diff --git a/app/matrix/lib/media-repo.libsonnet b/app/matrix/lib/media-repo.libsonnet
index 4b079d8..275be24 100644
--- a/app/matrix/lib/media-repo.libsonnet
+++ b/app/matrix/lib/media-repo.libsonnet
@@ -27,6 +27,7 @@
     },
 
     ns:: error "ns needs to be a kube.Namespace object",
+    local ns = app.ns,
 
     config:: {
         repo: {
@@ -60,13 +61,13 @@
         ],
     },
 
-    configSecret: app.ns.Contain(kube.Secret("media-repo-config")) {
+    configSecret: ns.Contain(kube.Secret("media-repo-config")) {
         data_: {
             "config.yaml": std.manifestJsonEx(app.config, ""),
         },
     },
 
-    deployment: app.ns.Contain(kube.Deployment("media-repo")) {
+    deployment: ns.Contain(kube.Deployment("media-repo")) {
         spec+: {
             replicas: 1,
             template+: {
@@ -132,7 +133,7 @@
         local prefix = "https://",
         local downstreamHost = std.substr(homeserver.csApi, std.length(prefix), std.length(homeserver.csApi)-std.length(prefix)),
 
-        deployment: app.ns.Contain(kube.Deployment("media-repo-proxy")) {
+        deployment: ns.Contain(kube.Deployment("media-repo-proxy")) {
             spec+: {
                 template+: {
                     spec+: {
@@ -157,11 +158,11 @@
         },
     } else {},
 
-    internalSvc: app.ns.Contain(kube.Service("media-repo-internal")) {
+    internalSvc: ns.Contain(kube.Service("media-repo-internal")) {
         target:: app.deployment,
     },
 
-    svc: if std.length(needProxying) > 0 then app.ns.Contain(kube.Service("media-repo")) {
+    svc: if std.length(needProxying) > 0 then ns.Contain(kube.Service("media-repo")) {
         target:: app.proxies.deployment,
     } else app.internalSvc,
 }
diff --git a/app/matrix/lib/riot.libsonnet b/app/matrix/lib/riot.libsonnet
index 23273f9..3d0dbdf 100644
--- a/app/matrix/lib/riot.libsonnet
+++ b/app/matrix/lib/riot.libsonnet
@@ -12,6 +12,7 @@
     },
 
     ns:: error "ns needs to be a kube.Namespace object",
+    local ns = app.ns,
 
     config:: {
         "default_hs_url": "https://%s" % [cfg.webDomain],
@@ -43,7 +44,7 @@
         }
     },
 
-    configMap: app.ns.Contain(kube.ConfigMap("riot-web-config")) {
+    configMap: ns.Contain(kube.ConfigMap("riot-web-config")) {
         data: {
             "config.json": std.manifestJsonEx(app.config, ""),
             // Standard nginx.conf, made to work when running as unprivileged user.
@@ -51,7 +52,7 @@
         },
     },
 
-    deployment: app.ns.Contain(kube.Deployment("riot-web")) {
+    deployment: ns.Contain(kube.Deployment("riot-web")) {
         spec+: {
             replicas: 1,
             template+: {
@@ -89,7 +90,7 @@
         },
     },
 
-    svc: app.ns.Contain(kube.Service("riot-web")) {
+    svc: ns.Contain(kube.Service("riot-web")) {
         target:: app.deployment,
     },
 }
diff --git a/app/matrix/lib/synapse.libsonnet b/app/matrix/lib/synapse.libsonnet
index 07656da..c9a03e7 100644
--- a/app/matrix/lib/synapse.libsonnet
+++ b/app/matrix/lib/synapse.libsonnet
@@ -24,13 +24,14 @@
     },
 
     ns:: error "ns needs to be provided",
+    local ns = app.ns,
     postgres:: error "postgres needs to be provided",
     redis:: error "redis needs to be provided",
 
     // See matrix-ng.libsonnet for description
     appservices:: error "appservices need to be provided",
 
-    dataVolume: app.ns.Contain(kube.PersistentVolumeClaim("synapse-data-waw3")) {
+    dataVolume: ns.Contain(kube.PersistentVolumeClaim("synapse-data-waw3")) {
         storage:: "50Gi",
         storageClass:: cfg.storageClassName,
     },
@@ -71,7 +72,7 @@
         turn_allow_guests: true,
     } else {}),
 
-    configMap: app.ns.Contain(kube.ConfigMap("synapse")) {
+    configMap: ns.Contain(kube.ConfigMap("synapse")) {
         data: {
             "homeserver.yaml": std.manifestYamlDoc(app.config),
             "log.config": importstr "synapse/log.config",
@@ -92,7 +93,7 @@
     } else {}),
 
     # Synapse process Deployment/StatefulSet base resource.
-    SynapseWorker(name, workerType, builder):: app.ns.Contain(builder(name)) {
+    SynapseWorker(name, workerType, builder):: ns.Contain(builder(name)) {
         local worker = self,
         cfg:: {
             # Configuration customization. Can contain environment substitution
@@ -229,10 +230,10 @@
                 },
             },
         },
-        svc: app.ns.Contain(kube.Service("synapse")) {
+        svc: ns.Contain(kube.Service("synapse")) {
             target:: app.main.deployment,
         },
-        replicationSvc: app.ns.Contain(kube.Service("synapse-replication-master")) {
+        replicationSvc: ns.Contain(kube.Service("synapse-replication-master")) {
             target:: app.main.deployment,
             spec+: {
                 ports: [
@@ -261,7 +262,7 @@
                 },
             },
         },
-        svc: app.ns.Contain(kube.Service("synapse-generic")) {
+        svc: ns.Contain(kube.Service("synapse-generic")) {
             target:: app.genericWorker.deployment,
         },
 
@@ -385,7 +386,7 @@
                 },
             },
         },
-        svc: app.ns.Contain(kube.Service("synapse-media")) {
+        svc: ns.Contain(kube.Service("synapse-media")) {
             target:: app.mediaWorker.deployment,
         },
     },
diff --git a/app/matrix/lib/wellknown.libsonnet b/app/matrix/lib/wellknown.libsonnet
index 509b83c..1760e01 100644
--- a/app/matrix/lib/wellknown.libsonnet
+++ b/app/matrix/lib/wellknown.libsonnet
@@ -11,8 +11,9 @@
     },
 
     ns:: error "ns needs to be a kube.Namespace object",
+    local ns = app.ns,
 
-    deployment: app.ns.Contain(kube.Deployment("wellknown")) {
+    deployment: ns.Contain(kube.Deployment("wellknown")) {
         spec+: {
             replicas: 1,
             template+: {
@@ -35,7 +36,7 @@
             },
         },
     },
-    svc: app.ns.Contain(kube.Service("wellknown")) {
+    svc: ns.Contain(kube.Service("wellknown")) {
         target:: app.deployment,
     },
 }
diff --git a/app/onlyoffice/prod.jsonnet b/app/onlyoffice/prod.jsonnet
index dcb8036..eafde30 100644
--- a/app/onlyoffice/prod.jsonnet
+++ b/app/onlyoffice/prod.jsonnet
@@ -16,14 +16,14 @@
             domain: error "cfg.domain must be set",
         },
 
-        ns: kube.Namespace(cfg.namespace),
+        local ns = kube.Namespace(cfg.namespace),
 
-        pvc: oo.ns.Contain(kube.PersistentVolumeClaim("documentserver")) {
+        pvc: ns.Contain(kube.PersistentVolumeClaim("documentserver")) {
             storage:: "10Gi",
             storageClass:: cfg.storageClassName,
         },
 
-        deploy: oo.ns.Contain(kube.Deployment("documentserver")) {
+        deploy: ns.Contain(kube.Deployment("documentserver")) {
             spec+: {
                 template+: {
                     spec+: {
@@ -65,11 +65,11 @@
             },
         },
 
-        svc: oo.ns.Contain(kube.Service("documentserver")) {
+        svc: ns.Contain(kube.Service("documentserver")) {
             target:: oo.deploy,
         },
 
-        ingress: oo.ns.Contain(kube.SimpleIngress("office")) {
+        ingress: ns.Contain(kube.SimpleIngress("office")) {
             hosts:: [cfg.domain],
             target_service:: oo.svc,
         },
diff --git a/app/walne/prod.jsonnet b/app/walne/prod.jsonnet
index 0a23d96..70dae12 100644
--- a/app/walne/prod.jsonnet
+++ b/app/walne/prod.jsonnet
@@ -19,8 +19,9 @@
         nextAuth: { secretKeyRef: { name: cfg.name, key: 'next_auth_secret' } },
     },
 
-    ns: kube.Namespace(cfg.namespace),
-    deployment: top.ns.Contain(kube.Deployment(cfg.name)) {
+    local ns = kube.Namespace(cfg.namespace),
+
+    deployment: ns.Contain(kube.Deployment(cfg.name)) {
         spec+: {
             template+: {
                 spec+: {
@@ -46,11 +47,11 @@
         },
     },
 
-    service: top.ns.Contain(kube.Service(cfg.name)) {
+    service: ns.Contain(kube.Service(cfg.name)) {
         target:: top.deployment,
     },
 
-    ingress: top.ns.Contain(kube.SimpleIngress(cfg.name)) {
+    ingress: ns.Contain(kube.SimpleIngress(cfg.name)) {
         hosts:: [cfg.domain],
         target_service:: top.service,
     },