diff --git a/Makefile b/Makefile
index bb6b19a1..8f5bdc72 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
images:
+ docker build images/horizon -t vexxhost/horizon:latest
docker build images/ceilometer --target ceilometer-agent-notification -t vexxhost/ceilometer-agent-notification:latest
docker build images/mcrouter -t vexxhost/mcrouter:latest
docker build images/mcrouter-exporter -t vexxhost/mcrouter-exporter:latest
diff --git a/chart/crds/dashboard.openstack.org_horizons.yaml b/chart/crds/dashboard.openstack.org_horizons.yaml
new file mode 100644
index 00000000..600b0fe3
--- /dev/null
+++ b/chart/crds/dashboard.openstack.org_horizons.yaml
@@ -0,0 +1,19 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: horizons.dashboard.openstack.org
+spec:
+ group: dashboard.openstack.org
+ names:
+ kind: Horizon
+ listKind: HorizonList
+ plural: horizons
+ singular: horizon
+ scope: Namespaced
+ version: v1alpha1
+ versions:
+ - name: v1alpha1
+ served: true
+ storage: true
diff --git a/chart/templates/clusterrole.yaml b/chart/templates/clusterrole.yaml
index 23314dad..0e70bb93 100644
--- a/chart/templates/clusterrole.yaml
+++ b/chart/templates/clusterrole.yaml
@@ -129,6 +129,26 @@ rules:
- get
- patch
- update
+- apiGroups:
+ - dashboard.openstack.org
+ resources:
+ - horizons
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - dashboard.openstack.org
+ resources:
+ - horizons/status
+ verbs:
+ - get
+ - patch
+ - update
- apiGroups:
- infrastructure.vexxhost.cloud
resources:
diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml
index 1bd8bc2e..adc30a43 100644
--- a/chart/templates/deployment.yaml
+++ b/chart/templates/deployment.yaml
@@ -29,6 +29,8 @@ spec:
args:
- run
- -m
+ - openstack_operator.horizon
+ - -m
- openstack_operator.mcrouter
- -m
- openstack_operator.memcached
diff --git a/config/samples/dashboard_v1alpha1_horizon.yaml b/config/samples/dashboard_v1alpha1_horizon.yaml
new file mode 100644
index 00000000..33a12120
--- /dev/null
+++ b/config/samples/dashboard_v1alpha1_horizon.yaml
@@ -0,0 +1,9 @@
+apiVersion: dashboard.openstack.org/v1alpha1
+kind: Horizon
+metadata:
+ name: sample
+ labels:
+ prometheus: helm
+spec:
+ ingress:
+ host: "horizon.vexxhost.com"
\ No newline at end of file
diff --git a/images/horizon/Dockerfile b/images/horizon/Dockerfile
new file mode 100644
index 00000000..bf44bc3e
--- /dev/null
+++ b/images/horizon/Dockerfile
@@ -0,0 +1,48 @@
+# Copyright (c) 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM docker.io/opendevorg/python-builder as builder
+COPY bindep.txt /tmp/src/bindep.txt
+RUN assemble horizon==18.3.1 \
+ python-memcached \
+ heat-dashboard==2.0.0 \
+ designate-dashboard==9.0.0 \
+ neutron-vpnaas-dashboard==1.6.0 \
+ octavia-dashboard==4.0.0 \
+ sahara-dashboard==11.0.0 \
+ magnum-ui==6.0.0
+
+FROM docker.io/opendevorg/uwsgi-base
+COPY --from=builder /output/ /output
+RUN /output/install-from-bindep
+WORKDIR /usr/local/lib/python3.7/site-packages/openstack_dashboard
+RUN ln -s /etc/horizon/local_settings.py local/local_settings.py && \
+ cp ../designatedashboard/enabled/*.py enabled/ && \
+ cp ../heat_dashboard/enabled/*.py enabled/ && \
+ cp ../magnum_ui/enabled/*.py enabled/ && \
+ cp ../neutron_vpnaas_dashboard/enabled/*.py enabled/ && \
+ cp ../octavia_dashboard/enabled/*.py enabled/ && \
+ cp ../sahara_dashboard/enabled/*.py enabled/
+COPY *.svg ../static/dashboard/img/
+COPY manage.py .
+RUN python manage.py collectstatic --no-input && \
+ python manage.py compress --force && \
+ chown 1001 -R local/ ../static
+EXPOSE 8000
+ENV UWSGI_HTTP_SOCKET=:8000 \
+ UWSGI_WSGI_FILE=/usr/local/lib/python3.7/site-packages/openstack_dashboard/wsgi/django.wsgi \
+ UWSGI_CHECK_STATIC=/usr/local/lib/python3.7/site-packages/static/ \
+ UWSGI_STATIC_MAP="/static=/usr/local/lib/python3.7/site-packages/static/" \
+ UWSGI_MIME_FILE="/etc/mime.types"
diff --git a/images/horizon/bindep.txt b/images/horizon/bindep.txt
new file mode 100644
index 00000000..118209ad
--- /dev/null
+++ b/images/horizon/bindep.txt
@@ -0,0 +1,3 @@
+gcc [compile]
+libc-dev [compile]
+mime-support
diff --git a/images/horizon/logo-splash.svg b/images/horizon/logo-splash.svg
new file mode 100644
index 00000000..dbb47724
--- /dev/null
+++ b/images/horizon/logo-splash.svg
@@ -0,0 +1,31 @@
+
\ No newline at end of file
diff --git a/images/horizon/logo.svg b/images/horizon/logo.svg
new file mode 100644
index 00000000..76872699
--- /dev/null
+++ b/images/horizon/logo.svg
@@ -0,0 +1,31 @@
+
\ No newline at end of file
diff --git a/images/horizon/manage.py b/images/horizon/manage.py
new file mode 100644
index 00000000..7894ec89
--- /dev/null
+++ b/images/horizon/manage.py
@@ -0,0 +1,9 @@
+import os
+import sys
+
+from django.core.management import execute_from_command_line
+
+if __name__ == "__main__":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE",
+ "openstack_dashboard.settings")
+ execute_from_command_line(sys.argv)
diff --git a/openstack_operator/horizon.py b/openstack_operator/horizon.py
new file mode 100644
index 00000000..1c944c4d
--- /dev/null
+++ b/openstack_operator/horizon.py
@@ -0,0 +1,81 @@
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""horizon Operator
+
+This module maintains the operator for Mcrouter, it takes care of creating
+the appropriate deployments, Mcrouter, pod monitors and Prometheus rules.
+"""
+
+import kopf
+
+from openstack_operator import utils
+
+
+@kopf.on.create('dashboard.openstack.org', 'v1alpha1', 'horizons')
+def create_secret(name, **_):
+ """Create a new horizon secret"""
+
+ utils.create_or_update('horizon/secret-secretkey.yml.j2',
+ name=name,
+ secret=utils.generate_password())
+
+
+@kopf.on.resume('dashboard.openstack.org', 'v1alpha1', 'horizons')
+@kopf.on.create('dashboard.openstack.org', 'v1alpha1', 'horizons')
+def create_or_resume(namespace, name, spec, **_):
+ """Create and re-sync a horizon instance
+
+ This function is called when a new resource is created but also when we
+ start the service up for the first time.
+ """
+
+ # Grab the secretkey secret
+ secret_key = utils.get_secret(namespace, "horizon-%s-secretkey" % name)
+ utils.create_or_update('horizon/secret-config.yml.j2',
+ name=name,
+ secret=secret_key['secret_key'])
+ conn = utils.get_openstack_connection()
+ auth_url = conn.config.auth["auth_url"]
+ config = utils.create_or_update('horizon/configmap.yml.j2',
+ name=name, spec=spec, auth_url=auth_url)
+ config_hash = utils.generate_hash(config.obj['data'])
+ utils.create_or_update('horizon/deployment.yml.j2',
+ config_hash=config_hash, name=name, spec=spec)
+ utils.create_or_update('horizon/service.yml.j2',
+ name=name, spec=spec)
+ utils.create_or_update('horizon/memcached.yml.j2',
+ name=name, spec=spec)
+ if "ingress" in spec:
+ utils.create_or_update('horizon/ingress.yml.j2',
+ name=name, spec=spec)
+
+
+@kopf.on.update('dashboard.openstack.org', 'v1alpha1', 'horizons')
+def update(name, spec, **_):
+ """Update a horizon
+
+ This function updates the deployment for horizon if there are any
+ changes that happen within it.
+ """
+ conn = utils.get_openstack_connection()
+ auth_url = conn.config.auth["auth_url"]
+ config = utils.create_or_update('horizon/configmap.yml.j2',
+ name=name, spec=spec, auth_url=auth_url)
+ config_hash = utils.generate_hash(config.obj['data'])
+ utils.create_or_update('horizon/deployment.yml.j2',
+ config_hash=config_hash, name=name, spec=spec)
+ if hasattr(spec, "ingress"):
+ utils.create_or_update('horizon/ingress.yml.j2',
+ name=name, spec=spec)
diff --git a/openstack_operator/objects.py b/openstack_operator/objects.py
index 4bcf3366..5f5fca73 100644
--- a/openstack_operator/objects.py
+++ b/openstack_operator/objects.py
@@ -24,8 +24,10 @@ from combinations of apiVersion and kind to the exact model.
from pykube.objects import ConfigMap
from pykube.objects import Deployment
+from pykube.objects import Ingress
from pykube.objects import NamespacedAPIObject
from pykube.objects import Pod
+from pykube.objects import Secret
from pykube.objects import Service
from pykube.objects import StatefulSet
@@ -38,6 +40,14 @@ class Mcrouter(NamespacedAPIObject):
kind = "Mcrouter"
+class Memcached(NamespacedAPIObject):
+ """Memcached Kubernetes object"""
+
+ version = "infrastructure.vexxhost.cloud/v1alpha1"
+ endpoint = "memcacheds"
+ kind = "Memcached"
+
+
class PodMonitor(NamespacedAPIObject):
"""PodMonitor Kubernetes object"""
@@ -58,14 +68,19 @@ MAPPING = {
"v1": {
"ConfigMap": ConfigMap,
"Pod": Pod,
+ "Secret": Secret,
"Service": Service,
},
"apps/v1": {
"Deployment": Deployment,
"StatefulSet": StatefulSet,
},
+ "extensions/v1beta1": {
+ "Ingress": Ingress
+ },
"infrastructure.vexxhost.cloud/v1alpha1": {
"Mcrouter": Mcrouter,
+ "Memcached": Memcached
},
"monitoring.coreos.com/v1": {
"PodMonitor": PodMonitor,
diff --git a/openstack_operator/templates/horizon/configmap.yml.j2 b/openstack_operator/templates/horizon/configmap.yml.j2
new file mode 100644
index 00000000..1fc6e5da
--- /dev/null
+++ b/openstack_operator/templates/horizon/configmap.yml.j2
@@ -0,0 +1,39 @@
+---
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: horizon-{{ name }}
+ namespace: default
+data:
+ local_settings.py: |
+ import os
+ from openstack_dashboard.settings import HORIZON_CONFIG
+
+ ALLOWED_HOSTS = ['*']
+
+ SECRET_KEY = os.getenv('SECRET_KEY')
+
+ CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+ 'LOCATION': 'mcrouter-memcached-horizon-{{ name }}:11211',
+ },
+ }
+
+ OPENSTACK_KEYSTONE_URL = '{{ auth_url }}'
+
+ OPENSTACK_NEUTRON_NETWORK['enable_ha_router'] = True
diff --git a/openstack_operator/templates/horizon/deployment.yml.j2 b/openstack_operator/templates/horizon/deployment.yml.j2
new file mode 100644
index 00000000..d7ce451b
--- /dev/null
+++ b/openstack_operator/templates/horizon/deployment.yml.j2
@@ -0,0 +1,79 @@
+---
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: horizon-{{ name }}
+ labels:
+ {{ labels("horizon", name) | indent(4) }}
+ annotations:
+ checksum/config: "{{ config_hash }}"
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ {{ labels("horizon", name) | indent(6) }}
+ template:
+ metadata:
+ labels:
+ {{ labels("horizon", name) | indent(8) }}
+ spec:
+ containers:
+ - name: horizon
+ image: vexxhost/horizon:latest
+ imagePullPolicy: Always
+ env:
+ - name: SECRET_KEY
+ valueFrom:
+ secretKeyRef:
+ key: secret_key
+ name: horizon-{{ name }}
+ ports:
+ - name: horizon
+ containerPort: 8000
+ livenessProbe:
+ tcpSocket:
+ port: horizon
+ readinessProbe:
+ tcpSocket:
+ port: horizon
+ resources:
+ limits:
+ cpu: 1000m
+ ephemeral-storage: 500M
+ memory: 256M
+ requests:
+ cpu: 500m
+ ephemeral-storage: 500M
+ memory: 128M
+ securityContext:
+ runAsUser: 1001
+ volumeMounts:
+ - mountPath: /etc/horizon
+ name: config
+ volumes:
+ - configMap:
+ defaultMode: 420
+ name: horizon-{{ name }}
+ name: config
+{% if 'nodeSelector' in spec %}
+ nodeSelector:
+ {{ spec.nodeSelector | to_yaml | indent(8) }}
+{% endif %}
+{% if 'tolerations' in spec %}
+ tolerations:
+ {{ spec.tolerations | to_yaml | indent(8) }}
+{% endif %}
diff --git a/openstack_operator/templates/horizon/ingress.yml.j2 b/openstack_operator/templates/horizon/ingress.yml.j2
new file mode 100644
index 00000000..ebb4dd35
--- /dev/null
+++ b/openstack_operator/templates/horizon/ingress.yml.j2
@@ -0,0 +1,28 @@
+---
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: horizon-{{ name }}
+spec:
+ rules:
+ - host: {{ spec.ingress.host }}
+ http:
+ paths:
+ - path: /
+ backend:
+ serviceName: horizon-{{ name }}
+ servicePort: 80
diff --git a/openstack_operator/templates/horizon/memcached.yml.j2 b/openstack_operator/templates/horizon/memcached.yml.j2
new file mode 100644
index 00000000..3cbebd94
--- /dev/null
+++ b/openstack_operator/templates/horizon/memcached.yml.j2
@@ -0,0 +1,23 @@
+---
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: infrastructure.vexxhost.cloud/v1alpha1
+kind: Memcached
+metadata:
+ name: horizon-{{ name }}
+ labels:
+ {{ labels("horizon", name) | indent(4) }}
+spec:
+ megabytes: 128
diff --git a/openstack_operator/templates/horizon/secret-config.yml.j2 b/openstack_operator/templates/horizon/secret-config.yml.j2
new file mode 100644
index 00000000..f947f7a0
--- /dev/null
+++ b/openstack_operator/templates/horizon/secret-config.yml.j2
@@ -0,0 +1,21 @@
+---
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: Secret
+metadata:
+ name: horizon-{{ name }}
+stringData:
+ secret_key: {{ secret }}
diff --git a/openstack_operator/templates/horizon/secret-secretkey.yml.j2 b/openstack_operator/templates/horizon/secret-secretkey.yml.j2
new file mode 100644
index 00000000..8453f65e
--- /dev/null
+++ b/openstack_operator/templates/horizon/secret-secretkey.yml.j2
@@ -0,0 +1,21 @@
+---
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: Secret
+metadata:
+ name: horizon-{{ name }}-secretkey
+stringData:
+ secret_key: {{ secret }}
diff --git a/openstack_operator/templates/horizon/service.yml.j2 b/openstack_operator/templates/horizon/service.yml.j2
new file mode 100644
index 00000000..782f1b21
--- /dev/null
+++ b/openstack_operator/templates/horizon/service.yml.j2
@@ -0,0 +1,28 @@
+---
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: horizon-{{ name }}
+spec:
+ type: ClusterIP
+ ports:
+ - name: horizon
+ port: 80
+ protocol: TCP
+ targetPort: horizon
+ selector:
+ {{ labels("horizon", name) | indent(4) }}
diff --git a/openstack_operator/tests/unit/base.py b/openstack_operator/tests/unit/base.py
index 28ebff31..739a0a55 100644
--- a/openstack_operator/tests/unit/base.py
+++ b/openstack_operator/tests/unit/base.py
@@ -34,7 +34,6 @@ class KubernetesObjectTestCase(testtools.TestCase):
SAMPLES_PATH = 'config/samples'
SAMPLE_FILE = ''
TEMPLATE_FILE = ''
-
@classmethod
def setUpClass(cls):
sample_path = "%s/%s" % (cls.SAMPLES_PATH, cls.SAMPLE_FILE)
diff --git a/openstack_operator/tests/unit/test_horizon.py b/openstack_operator/tests/unit/test_horizon.py
new file mode 100644
index 00000000..e3615c5a
--- /dev/null
+++ b/openstack_operator/tests/unit/test_horizon.py
@@ -0,0 +1,27 @@
+# Copyright 2020 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tests for Horizon Operator
+
+This module contains all the tests for the Horizon operator.
+"""
+
+from openstack_operator.tests.unit import base
+
+
+class HorizonDeploymentTestCase(base.DeploymentTestCase):
+ """Basic tests for the Deployment."""
+
+ SAMPLE_FILE = 'dashboard_v1alpha1_horizon.yaml'
+ TEMPLATE_FILE = 'horizon/deployment.yml.j2'
diff --git a/openstack_operator/utils.py b/openstack_operator/utils.py
index e7ae264f..3139346c 100644
--- a/openstack_operator/utils.py
+++ b/openstack_operator/utils.py
@@ -17,17 +17,19 @@
The module contains a few useful utilities which we refactor out in order
to be able to use them across all different operators.
"""
-
+import base64
import copy
import operator
import os
+import secrets
+import string
import jinja2
-import openstack
import kopf
from pbr import version
import pykube
import yaml
+import openstack
from openstack_operator import objects
@@ -41,6 +43,11 @@ def to_yaml(value):
return yaml.safe_dump(value)
+def to_dict(value):
+ """Return a dictionary from a YAML string"""
+ return yaml.safe_load(value)
+
+
def labels(app, instance, component=None):
"""Return standard labels for the operator."""
metadata = {
@@ -82,6 +89,8 @@ def create_or_update(template, **kwargs):
raise
resource.create()
+ return resource
+
def ensure_absent(template, **kwargs):
"""Ensure a Kubernetes resource bound to a template is deleted
@@ -156,3 +165,37 @@ def get_openstack_connection():
"""Get an instance of OpenStack SDK."""
return openstack.connect(cloud="envvars", app_name='openstack-operator',
app_version=VERSION)
+
+
+def generate_password(length=20):
+ """Generate a random password."""
+
+ alphabet = string.ascii_letters + string.digits
+ return ''.join(secrets.choice(alphabet) for i in range(length))
+
+
+def get_secret(namespace, name):
+ """Retrieve a secret from Kubernetes.
+
+ This function retrieves a Secret from Kubernetes, decodes it and passes
+ the value of the data
+ """
+
+ api = pykube.HTTPClient(pykube.KubeConfig.from_env())
+ secret = objects.Secret.objects(api).get(
+ namespace=namespace,
+ name=name
+ )
+
+ return {
+ k: base64.b64decode(v).decode('utf-8')
+ for k, v in secret.obj['data'].items()
+ }
+
+
+def generate_hash(dictionary):
+ """Generate a has from a dictionary, return None if dictionary is empty"""
+
+ if not dictionary:
+ return None
+ return hash(frozenset(dictionary.items()))
diff --git a/zuul.d/functional-jobs.yaml b/zuul.d/functional-jobs.yaml
index a3c1ca33..727a4618 100644
--- a/zuul.d/functional-jobs.yaml
+++ b/zuul.d/functional-jobs.yaml
@@ -20,33 +20,37 @@
jobs:
- openstack-operator:functional:
dependencies:
- - name: openstack-operator:images:build:ceilometer
+ - name: openstack-operator:images:build:mcrouter-exporter
+ soft: true
+ - name: openstack-operator:images:build:horizon
soft: true
- name: openstack-operator:images:build:rabbitmq
soft: true
+ - name: openstack-operator:images:build:ceilometer
+ soft: true
+ - name: openstack-operator:images:build:memcached-exporter
+ soft: true
- name: openstack-operator:images:build:memcached
soft: true
- name: openstack-operator:images:build:mcrouter
soft: true
- openstack-operator:images:build:openstack-operator
- - name: openstack-operator:images:build:mcrouter-exporter
- soft: true
- - name: openstack-operator:images:build:memcached-exporter
- soft: true
gate:
jobs:
- openstack-operator:functional:
dependencies:
- - name: openstack-operator:images:upload:ceilometer
+ - name: openstack-operator:images:upload:mcrouter-exporter
+ soft: true
+ - name: openstack-operator:images:upload:horizon
soft: true
- name: openstack-operator:images:upload:rabbitmq
soft: true
+ - name: openstack-operator:images:upload:ceilometer
+ soft: true
+ - name: openstack-operator:images:upload:memcached-exporter
+ soft: true
- name: openstack-operator:images:upload:memcached
soft: true
- name: openstack-operator:images:upload:mcrouter
soft: true
- openstack-operator:images:upload:openstack-operator
- - name: openstack-operator:images:upload:mcrouter-exporter
- soft: true
- - name: openstack-operator:images:upload:memcached-exporter
- soft: true
diff --git a/zuul.d/horizon-jobs.yaml b/zuul.d/horizon-jobs.yaml
new file mode 100644
index 00000000..2da2675f
--- /dev/null
+++ b/zuul.d/horizon-jobs.yaml
@@ -0,0 +1,31 @@
+- job:
+ name: openstack-operator:images:build:horizon
+ parent: vexxhost-build-docker-image
+ provides: openstack-operator:image:horizon
+ vars: &id001
+ docker_images:
+ - context: images/horizon
+ repository: vexxhost/horizon
+ files: &id002
+ - ^images/horizon/.*
+- job:
+ name: openstack-operator:images:upload:horizon
+ parent: vexxhost-upload-docker-image
+ provides: openstack-operator:image:horizon
+ vars: *id001
+ files: *id002
+- job:
+ name: openstack-operator:images:promote:horizon
+ parent: vexxhost-promote-docker-image
+ vars: *id001
+ files: *id002
+- project:
+ check:
+ jobs:
+ - openstack-operator:images:build:horizon
+ gate:
+ jobs:
+ - openstack-operator:images:upload:horizon
+ promote:
+ jobs:
+ - openstack-operator:images:promote:horizon