cluster/rook: bump to 1.1.9

This bumps Rook/Ceph. The new resources (mostly RBAC) come from
following https://rook.io/docs/rook/v1.1/ceph-upgrade.html .

It's already deployed on production. The new CSI driver has not been
tested, but the old flexvolume-based provisioners still work. We'll
migrate when Rook offers a nice solution for this.

We've hit a kubecfg bug that does not allow controlling the CephCluster
CRD directly anymore (I had to apply it via kubecfg show / kubectl apply
-f instead). This might be due to our bazel/prod k8s version mismatch,
or it might be related to https://github.com/bitnami/kubecfg/issues/259.

Change-Id: Icd69974b294b823e60b8619a656d4834bd6520fd
diff --git a/kube/kube.libsonnet b/kube/kube.libsonnet
index 202b41b..fc21962 100644
--- a/kube/kube.libsonnet
+++ b/kube/kube.libsonnet
@@ -24,4 +24,76 @@
         // secure way.
         secret_name:: "rook-ceph-object-user-%s-%s" % [user.spec.store, user.spec.displayName],
     },
+
+    // Make OpenAPI v3 schema specification less painful.
+    OpenAPI:: {
+        Validation(obj):: {
+            openAPIV3Schema: obj.render,
+        },
+
+        Dict:: {
+            local dict = self,
+            required:: false,
+
+            local requiredList = [
+                k for k in std.filter(function(k) dict[k].required, std.objectFields(dict))
+            ],
+
+            render:: {
+                properties: {
+                    [k]: dict[k].render
+                    for k in std.objectFields(dict)
+                },
+            } + (if std.length(requiredList) > 0 then {
+                required: requiredList,
+            } else {}),
+        },
+
+        Array(items):: {
+            required:: false,
+            render:: {
+                type: "array",
+                items: items.render,
+            },
+        },
+
+        Integer:: {
+            local integer = self,
+            required:: false,
+            render:: {
+                type: "integer",
+            } + (if integer.minimum != null then {
+                minimum: integer.minimum,
+            } else {}) + (if integer.maximum != null then {
+                maximum: integer.maximum,
+            } else {}),
+
+            minimum:: null,
+            maximum:: null,
+        },
+
+        String:: {
+            local string = self,
+            required:: false,
+            render:: {
+                type: "string",
+            } + (if string.pattern != null then {
+                pattern: string.pattern,
+            } else {}),
+
+            pattern:: null,
+        },
+
+        Boolean:: {
+            required:: false,
+            render:: {
+                type: "boolean",
+            },
+        },
+
+        Any:: {
+            required:: false,
+            render:: {},
+        },
+    },
 }