Remove some CRs, and deploy at the startup of the operator
1. Keystone, heat, and horizon CRs are eliminated, and deploy automatically at the beginning. 2. Use a constant namespace "openstack" for the auto-deployed resources. 3. Adjust resource request. Depends-On: https://review.opendev.org/727868/ Change-Id: I75bc8b9e73035f3ca73f00612bc4c50f42473dc3
This commit is contained in:
parent
47e04dce93
commit
10f9be432a
@ -23,42 +23,8 @@ rules:
|
|||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
- configmaps
|
- configmaps
|
||||||
- services
|
- namespaces
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- delete
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- patch
|
|
||||||
- update
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- pods
|
- pods
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- delete
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- patch
|
|
||||||
- update
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- secrets
|
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- delete
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- patch
|
|
||||||
- update
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- secrets
|
- secrets
|
||||||
- services
|
- services
|
||||||
verbs:
|
verbs:
|
||||||
|
12
chart/templates/configmap.yaml
Normal file
12
chart/templates/configmap.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
name: operator-config
|
||||||
|
labels:
|
||||||
|
{{ include "openstack-operator.labels" . | indent 4 }}
|
||||||
|
data:
|
||||||
|
{{- with .Values.configMap }}
|
||||||
|
operator-config.yaml: |
|
||||||
|
{{ toYaml . | indent 4 }}
|
||||||
|
{{- end }}
|
@ -21,6 +21,11 @@ spec:
|
|||||||
- name: operator
|
- name: operator
|
||||||
image: vexxhost/openstack-operator:latest
|
image: vexxhost/openstack-operator:latest
|
||||||
command: ["/usr/local/bin/kopf"]
|
command: ["/usr/local/bin/kopf"]
|
||||||
|
env:
|
||||||
|
- name: OPERATOR_NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
{{- with .Values.secretName }}
|
{{- with .Values.secretName }}
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
@ -29,11 +34,7 @@ spec:
|
|||||||
args:
|
args:
|
||||||
- run
|
- run
|
||||||
- -m
|
- -m
|
||||||
- openstack_operator.heat
|
- openstack_operator.operator
|
||||||
- -m
|
|
||||||
- openstack_operator.horizon
|
|
||||||
- -m
|
|
||||||
- openstack_operator.keystone
|
|
||||||
- -m
|
- -m
|
||||||
- openstack_operator.mcrouter
|
- openstack_operator.mcrouter
|
||||||
- -m
|
- -m
|
||||||
|
@ -1,2 +1,10 @@
|
|||||||
---
|
---
|
||||||
secretName: devstack
|
secretName: devstack
|
||||||
|
configMap:
|
||||||
|
horizon:
|
||||||
|
ingress:
|
||||||
|
host: "horizon.vexxhost.com"
|
||||||
|
keystone:
|
||||||
|
configDir: /etc/keystone
|
||||||
|
heat:
|
||||||
|
configDir: /etc/heat
|
@ -1,3 +1,4 @@
|
|||||||
crd:
|
crd:
|
||||||
monitoring: true
|
monitoring: true
|
||||||
dns: true
|
dns: true
|
||||||
|
configMap: {}
|
||||||
|
@ -34,16 +34,27 @@ function kubernetes_rollout_status {
|
|||||||
kubectl rollout status deploy/$deployment
|
kubectl rollout status deploy/$deployment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function kubernetes_rollout_restart {
|
||||||
|
local deployment="$1"
|
||||||
|
|
||||||
|
for i in {1..30}; do
|
||||||
|
kubectl get deploy/$deployment && break || sleep 1;
|
||||||
|
done
|
||||||
|
|
||||||
|
kubectl rollout restart deploy/$deployment
|
||||||
|
}
|
||||||
|
|
||||||
function proxy_pass_to_kubernetes {
|
function proxy_pass_to_kubernetes {
|
||||||
local url=$1
|
local url=$1
|
||||||
local svc=$2
|
local svc=$2
|
||||||
|
local conf=$3
|
||||||
|
|
||||||
local ip=$(get_kubernetes_service_ip $svc)
|
local ip=$(get_kubernetes_service_ip $svc)
|
||||||
local apache_conf=$(apache_site_config_for $svc)
|
local apache_conf=$(apache_site_config_for $conf)
|
||||||
|
|
||||||
echo "ProxyPass \"${url}\" \"http://${ip}/\"" | sudo tee -a $apache_conf
|
echo "ProxyPass \"${url}\" \"http://${ip}/\"" | sudo tee -a $apache_conf
|
||||||
|
|
||||||
enable_apache_site $svc
|
enable_apache_site $conf
|
||||||
restart_apache_server
|
restart_apache_server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,18 +54,9 @@ export -f init_keystone
|
|||||||
# start_keystone() - Start running processes
|
# start_keystone() - Start running processes
|
||||||
function start_keystone {
|
function start_keystone {
|
||||||
|
|
||||||
# install keystone
|
|
||||||
cat <<EOF | kubectl apply -f-
|
|
||||||
---
|
|
||||||
apiVersion: identity.openstack.org/v1alpha1
|
|
||||||
kind: Keystone
|
|
||||||
metadata:
|
|
||||||
name: devstack
|
|
||||||
spec:
|
|
||||||
configDir: ${KEYSTONE_CONF_DIR}
|
|
||||||
EOF
|
|
||||||
# rollout keystone
|
# rollout keystone
|
||||||
kubernetes_rollout_status keystone-devstack
|
kubernetes_rollout_restart keystone
|
||||||
|
kubernetes_rollout_status keystone
|
||||||
|
|
||||||
# Get right service port for testing
|
# Get right service port for testing
|
||||||
local service_port=$KEYSTONE_SERVICE_PORT
|
local service_port=$KEYSTONE_SERVICE_PORT
|
||||||
@ -74,8 +65,7 @@ EOF
|
|||||||
service_port=$KEYSTONE_SERVICE_PORT_INT
|
service_port=$KEYSTONE_SERVICE_PORT_INT
|
||||||
auth_protocol="http"
|
auth_protocol="http"
|
||||||
fi
|
fi
|
||||||
|
proxy_pass_to_kubernetes /identity keystone keystone-devstack
|
||||||
proxy_pass_to_kubernetes /identity keystone-devstack
|
|
||||||
|
|
||||||
echo "Waiting for keystone to start..."
|
echo "Waiting for keystone to start..."
|
||||||
# Check that the keystone service is running. Even if the tls tunnel
|
# Check that the keystone service is running. Even if the tls tunnel
|
||||||
@ -96,7 +86,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# (re)start memcached to make sure we have a clean memcache.
|
# (re)start memcached to make sure we have a clean memcache.
|
||||||
kubectl rollout restart statefulset/memcached-devstack
|
kubectl rollout restart statefulset/memcached-devstack -n default
|
||||||
}
|
}
|
||||||
export -f start_keystone
|
export -f start_keystone
|
||||||
|
|
||||||
@ -111,7 +101,7 @@ export -f start_keystone
|
|||||||
# - ``KEYSTONE_SERVICE_HOST``
|
# - ``KEYSTONE_SERVICE_HOST``
|
||||||
# - ``KEYSTONE_SERVICE_PORT``
|
# - ``KEYSTONE_SERVICE_PORT``
|
||||||
function bootstrap_keystone {
|
function bootstrap_keystone {
|
||||||
kubectl exec deploy/keystone-devstack -- keystone-manage bootstrap \
|
kubectl exec deploy/keystone -- keystone-manage bootstrap \
|
||||||
--bootstrap-username admin \
|
--bootstrap-username admin \
|
||||||
--bootstrap-password "$ADMIN_PASSWORD" \
|
--bootstrap-password "$ADMIN_PASSWORD" \
|
||||||
--bootstrap-project-name admin \
|
--bootstrap-project-name admin \
|
||||||
|
@ -27,6 +27,8 @@ from openstack_operator import utils
|
|||||||
def create_secret(name, **_):
|
def create_secret(name, **_):
|
||||||
"""Create a new horizon secret"""
|
"""Create a new horizon secret"""
|
||||||
|
|
||||||
|
res = utils.get_secret("openstack", name)
|
||||||
|
if res is None:
|
||||||
utils.create_or_update('horizon/secret-secretkey.yml.j2',
|
utils.create_or_update('horizon/secret-secretkey.yml.j2',
|
||||||
name=name,
|
name=name,
|
||||||
secret=utils.generate_password())
|
secret=utils.generate_password())
|
||||||
@ -78,6 +80,6 @@ def update(name, spec, **_):
|
|||||||
utils.create_or_update('horizon/deployment.yml.j2',
|
utils.create_or_update('horizon/deployment.yml.j2',
|
||||||
config_hash=config_hash, name=name,
|
config_hash=config_hash, name=name,
|
||||||
spec=spec, env=env)
|
spec=spec, env=env)
|
||||||
if hasattr(spec, "ingress"):
|
if "ingress" in spec:
|
||||||
utils.create_or_update('horizon/ingress.yml.j2',
|
utils.create_or_update('horizon/ingress.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec)
|
||||||
|
@ -41,15 +41,15 @@ def create_or_resume(name, spec, **_):
|
|||||||
"""
|
"""
|
||||||
data = McrouterSpecEncoder().encode(spec)
|
data = McrouterSpecEncoder().encode(spec)
|
||||||
utils.create_or_update('mcrouter/configmap.yml.j2',
|
utils.create_or_update('mcrouter/configmap.yml.j2',
|
||||||
name=name, data=data)
|
name=name, data=data, adopt=True)
|
||||||
utils.create_or_update('mcrouter/deployment.yml.j2',
|
utils.create_or_update('mcrouter/deployment.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('mcrouter/service.yml.j2',
|
utils.create_or_update('mcrouter/service.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('mcrouter/podmonitor.yml.j2',
|
utils.create_or_update('mcrouter/podmonitor.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('mcrouter/prometheusrule.yml.j2',
|
utils.create_or_update('mcrouter/prometheusrule.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
|
|
||||||
|
|
||||||
@kopf.on.update('infrastructure.vexxhost.cloud', 'v1alpha1', 'mcrouters')
|
@kopf.on.update('infrastructure.vexxhost.cloud', 'v1alpha1', 'mcrouters')
|
||||||
@ -61,6 +61,6 @@ def update(name, spec, **_):
|
|||||||
"""
|
"""
|
||||||
data = McrouterSpecEncoder().encode(spec)
|
data = McrouterSpecEncoder().encode(spec)
|
||||||
utils.create_or_update('mcrouter/configmap.yml.j2',
|
utils.create_or_update('mcrouter/configmap.yml.j2',
|
||||||
name=name, data=data)
|
name=name, data=data, adopt=True)
|
||||||
utils.create_or_update('mcrouter/deployment.yml.j2',
|
utils.create_or_update('mcrouter/deployment.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
|
@ -33,15 +33,15 @@ def create_or_resume(name, spec, **_):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
utils.create_or_update('memcached/statefulset.yml.j2',
|
utils.create_or_update('memcached/statefulset.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('memcached/service.yml.j2',
|
utils.create_or_update('memcached/service.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('memcached/mcrouter.yml.j2',
|
utils.create_or_update('memcached/mcrouter.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('memcached/podmonitor.yml.j2',
|
utils.create_or_update('memcached/podmonitor.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('memcached/prometheusrule.yml.j2',
|
utils.create_or_update('memcached/prometheusrule.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
|
|
||||||
# NOTE(mnaser): We should remove this once all deployments are no longer
|
# NOTE(mnaser): We should remove this once all deployments are no longer
|
||||||
# using Deployment for Memcached.
|
# using Deployment for Memcached.
|
||||||
@ -58,4 +58,4 @@ def update(name, spec, **_):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
utils.create_or_update('memcached/statefulset.yml.j2',
|
utils.create_or_update('memcached/statefulset.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
|
@ -26,6 +26,7 @@ from pykube.objects import ConfigMap
|
|||||||
from pykube.objects import Deployment
|
from pykube.objects import Deployment
|
||||||
from pykube.objects import HorizontalPodAutoscaler
|
from pykube.objects import HorizontalPodAutoscaler
|
||||||
from pykube.objects import Ingress
|
from pykube.objects import Ingress
|
||||||
|
from pykube.objects import Namespace
|
||||||
from pykube.objects import NamespacedAPIObject
|
from pykube.objects import NamespacedAPIObject
|
||||||
from pykube.objects import Pod
|
from pykube.objects import Pod
|
||||||
from pykube.objects import Secret
|
from pykube.objects import Secret
|
||||||
@ -68,6 +69,7 @@ class PrometheusRule(NamespacedAPIObject):
|
|||||||
MAPPING = {
|
MAPPING = {
|
||||||
"v1": {
|
"v1": {
|
||||||
"ConfigMap": ConfigMap,
|
"ConfigMap": ConfigMap,
|
||||||
|
"Namespace": Namespace,
|
||||||
"Pod": Pod,
|
"Pod": Pod,
|
||||||
"Secret": Secret,
|
"Secret": Secret,
|
||||||
"Service": Service,
|
"Service": Service,
|
||||||
|
73
openstack_operator/operator.py
Normal file
73
openstack_operator/operator.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# 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.
|
||||||
|
# pylint: disable=W0613
|
||||||
|
"""Openstack Operator
|
||||||
|
|
||||||
|
This module maintains the operator startup, it takes care of creating
|
||||||
|
the appropriate deployments, an instance of Keystone, Heat and Horizon
|
||||||
|
for the installation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import kopf
|
||||||
|
|
||||||
|
from openstack_operator import heat
|
||||||
|
from openstack_operator import horizon
|
||||||
|
from openstack_operator import keystone
|
||||||
|
from openstack_operator import utils
|
||||||
|
|
||||||
|
|
||||||
|
OPERATOR_CONFIGMAP = "operator-config"
|
||||||
|
|
||||||
|
|
||||||
|
def _create_namespace():
|
||||||
|
"""Create a namespace for the operator
|
||||||
|
|
||||||
|
All resources which are managed by the operator would
|
||||||
|
be deployed on this namespace"""
|
||||||
|
|
||||||
|
utils.create_or_update('operator/namespace.yml.j2')
|
||||||
|
|
||||||
|
|
||||||
|
@kopf.on.startup()
|
||||||
|
async def startup_fn(logger, **kwargs):
|
||||||
|
"""Create several deployments at the startup of the operator
|
||||||
|
|
||||||
|
keystone, heat, and horizon
|
||||||
|
"""
|
||||||
|
|
||||||
|
namespace = os.getenv('OPERATOR_NAMESPACE')
|
||||||
|
config = utils.get_configmap(namespace, OPERATOR_CONFIGMAP)
|
||||||
|
config = utils.to_dict(config["operator-config.yaml"])
|
||||||
|
_create_namespace()
|
||||||
|
if "keystone" in config:
|
||||||
|
keystone.create_or_resume("keystone", config["keystone"])
|
||||||
|
if "horizon" in config:
|
||||||
|
horizon.create_secret("horizon")
|
||||||
|
horizon.create_or_resume("horizon", config["horizon"])
|
||||||
|
if "heat" in config:
|
||||||
|
heat.create_or_resume("heat", config["heat"])
|
||||||
|
|
||||||
|
|
||||||
|
@kopf.on.update('', 'v1', 'configmaps')
|
||||||
|
def update(name, namespace, new, **_):
|
||||||
|
"""Update the startup deployments when the operator configmap is changed
|
||||||
|
|
||||||
|
keystone, heat, and horizon
|
||||||
|
"""
|
||||||
|
if namespace == os.getenv('OPERATOR_NAMESPACE') \
|
||||||
|
and name == OPERATOR_CONFIGMAP:
|
||||||
|
config = utils.to_dict(new["data"]["operator-config.yaml"])
|
||||||
|
if "horizon" in config:
|
||||||
|
horizon.update("horizon", config["horizon"])
|
@ -33,13 +33,13 @@ def create_or_resume(name, spec, **_):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
utils.create_or_update('rabbitmq/deployment.yml.j2',
|
utils.create_or_update('rabbitmq/deployment.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('rabbitmq/service.yml.j2',
|
utils.create_or_update('rabbitmq/service.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('rabbitmq/podmonitor.yml.j2',
|
utils.create_or_update('rabbitmq/podmonitor.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
utils.create_or_update('rabbitmq/prometheusrule.yml.j2',
|
utils.create_or_update('rabbitmq/prometheusrule.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
|
|
||||||
|
|
||||||
@kopf.on.update('infrastructure.vexxhost.cloud', 'v1alpha1', 'rabbitmqs')
|
@kopf.on.update('infrastructure.vexxhost.cloud', 'v1alpha1', 'rabbitmqs')
|
||||||
@ -51,4 +51,4 @@ def update(name, spec, **_):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
utils.create_or_update('rabbitmq/deployment.yml.j2',
|
utils.create_or_update('rabbitmq/deployment.yml.j2',
|
||||||
name=name, spec=spec)
|
name=name, spec=spec, adopt=True)
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: heat-{{ name }}-{{ component }}
|
name: heat-{{ component }}
|
||||||
|
namespace: openstack
|
||||||
labels:
|
labels:
|
||||||
{{ labels("heat", name, component) | indent(4) }}
|
{{ labels("heat", name, component) | indent(4) }}
|
||||||
spec:
|
spec:
|
||||||
@ -59,7 +60,7 @@ spec:
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpu: 1000m
|
cpu: 500m
|
||||||
ephemeral-storage: 50M
|
ephemeral-storage: 50M
|
||||||
memory: 512M
|
memory: 512M
|
||||||
requests:
|
requests:
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: heat-{{ name }}-{{ component }}
|
name: heat-{{ component }}
|
||||||
|
namespace: openstack
|
||||||
spec:
|
spec:
|
||||||
serviceType: ClusterIP
|
serviceType: ClusterIP
|
||||||
ports:
|
ports:
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
|
namespace: openstack
|
||||||
data:
|
data:
|
||||||
local_settings.py: |
|
local_settings.py: |
|
||||||
import os
|
import os
|
||||||
@ -30,7 +31,7 @@ data:
|
|||||||
CACHES = {
|
CACHES = {
|
||||||
'default': {
|
'default': {
|
||||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||||
'LOCATION': 'mcrouter-memcached-horizon-{{ name }}:11211',
|
'LOCATION': 'mcrouter-memcached-horizon:11211',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
|
namespace: openstack
|
||||||
labels:
|
labels:
|
||||||
{{ labels("horizon", name) | indent(4) }}
|
{{ labels("horizon", name) | indent(4) }}
|
||||||
annotations:
|
annotations:
|
||||||
@ -44,7 +45,7 @@ spec:
|
|||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: secret_key
|
key: secret_key
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
ports:
|
ports:
|
||||||
- name: horizon
|
- name: horizon
|
||||||
containerPort: 8000
|
containerPort: 8000
|
||||||
@ -60,7 +61,7 @@ spec:
|
|||||||
ephemeral-storage: 500M
|
ephemeral-storage: 500M
|
||||||
memory: 256M
|
memory: 256M
|
||||||
requests:
|
requests:
|
||||||
cpu: 1000m
|
cpu: 200m
|
||||||
ephemeral-storage: 500M
|
ephemeral-storage: 500M
|
||||||
memory: 128M
|
memory: 128M
|
||||||
securityContext:
|
securityContext:
|
||||||
@ -71,7 +72,7 @@ spec:
|
|||||||
volumes:
|
volumes:
|
||||||
- configMap:
|
- configMap:
|
||||||
defaultMode: 420
|
defaultMode: 420
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
name: config
|
name: config
|
||||||
{% if 'nodeSelector' in spec %}
|
{% if 'nodeSelector' in spec %}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
|
@ -16,14 +16,15 @@
|
|||||||
apiVersion: autoscaling/v1
|
apiVersion: autoscaling/v1
|
||||||
kind: HorizontalPodAutoscaler
|
kind: HorizontalPodAutoscaler
|
||||||
metadata:
|
metadata:
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
|
namespace: openstack
|
||||||
labels:
|
labels:
|
||||||
{{ labels("horizon", name) | indent(4) }}
|
{{ labels("horizon", name) | indent(4) }}
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
minReplicas: 3
|
minReplicas: 2
|
||||||
maxReplicas: 10
|
maxReplicas: 10
|
||||||
targetCPUUtilizationPercentage: 90
|
targetCPUUtilizationPercentage: 90
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: extensions/v1beta1
|
apiVersion: extensions/v1beta1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
|
namespace: openstack
|
||||||
spec:
|
spec:
|
||||||
rules:
|
rules:
|
||||||
- host: {{ spec.ingress.host }}
|
- host: {{ spec.ingress.host }}
|
||||||
@ -24,5 +25,5 @@ spec:
|
|||||||
paths:
|
paths:
|
||||||
- path: /
|
- path: /
|
||||||
backend:
|
backend:
|
||||||
serviceName: horizon-{{ name }}
|
serviceName: horizon
|
||||||
servicePort: 80
|
servicePort: 80
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: infrastructure.vexxhost.cloud/v1alpha1
|
apiVersion: infrastructure.vexxhost.cloud/v1alpha1
|
||||||
kind: Memcached
|
kind: Memcached
|
||||||
metadata:
|
metadata:
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
|
namespace: openstack
|
||||||
labels:
|
labels:
|
||||||
{{ labels("horizon", name) | indent(4) }}
|
{{ labels("horizon", name) | indent(4) }}
|
||||||
spec:
|
spec:
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
|
namespace: openstack
|
||||||
stringData:
|
stringData:
|
||||||
secret_key: {{ secret }}
|
secret_key: {{ secret }}
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: horizon-{{ name }}
|
name: horizon
|
||||||
|
namespace: openstack
|
||||||
spec:
|
spec:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
ports:
|
ports:
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: keystone-{{ name }}
|
name: keystone
|
||||||
|
namespace: openstack
|
||||||
labels:
|
labels:
|
||||||
{{ labels("keystone", name) | indent(4) }}
|
{{ labels("keystone", name) | indent(4) }}
|
||||||
spec:
|
spec:
|
||||||
@ -55,7 +56,7 @@ spec:
|
|||||||
ephemeral-storage: 500M
|
ephemeral-storage: 500M
|
||||||
memory: 1024M
|
memory: 1024M
|
||||||
requests:
|
requests:
|
||||||
cpu: 1000m
|
cpu: 200m
|
||||||
ephemeral-storage: 500M
|
ephemeral-storage: 500M
|
||||||
memory: 512M
|
memory: 512M
|
||||||
securityContext:
|
securityContext:
|
||||||
|
@ -16,14 +16,15 @@
|
|||||||
apiVersion: autoscaling/v1
|
apiVersion: autoscaling/v1
|
||||||
kind: HorizontalPodAutoscaler
|
kind: HorizontalPodAutoscaler
|
||||||
metadata:
|
metadata:
|
||||||
name: keystone-{{ name }}
|
name: keystone
|
||||||
|
namespace: openstack
|
||||||
labels:
|
labels:
|
||||||
{{ labels("keystone", name) | indent(4) }}
|
{{ labels("keystone", name) | indent(4) }}
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
name: keystone-{{ name }}
|
name: keystone
|
||||||
minReplicas: 3
|
minReplicas: 2
|
||||||
maxReplicas: 10
|
maxReplicas: 10
|
||||||
targetCPUUtilizationPercentage: 90
|
targetCPUUtilizationPercentage: 90
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: keystone-{{ name }}
|
name: keystone
|
||||||
|
namespace: openstack
|
||||||
spec:
|
spec:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
ports:
|
ports:
|
||||||
|
24
openstack_operator/templates/operator/namespace.yml.j2
Normal file
24
openstack_operator/templates/operator/namespace.yml.j2
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# 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: Namespace
|
||||||
|
metadata:
|
||||||
|
name: openstack
|
||||||
|
labels:
|
||||||
|
{{ labels("operator", "openstack") | indent(4) }}
|
||||||
|
spec:
|
||||||
|
finalizers:
|
||||||
|
- kubernetes
|
@ -69,7 +69,7 @@ spec:
|
|||||||
ephemeral-storage: 1G
|
ephemeral-storage: 1G
|
||||||
memory: 1G
|
memory: 1G
|
||||||
requests:
|
requests:
|
||||||
cpu: 500m
|
cpu: 100m
|
||||||
ephemeral-storage: 500M
|
ephemeral-storage: 500M
|
||||||
memory: 512M
|
memory: 512M
|
||||||
securityContext:
|
securityContext:
|
||||||
|
@ -34,6 +34,7 @@ class KubernetesObjectTestCase(testtools.TestCase):
|
|||||||
SAMPLES_PATH = 'config/samples'
|
SAMPLES_PATH = 'config/samples'
|
||||||
SAMPLE_FILE = ''
|
SAMPLE_FILE = ''
|
||||||
TEMPLATE_FILE = ''
|
TEMPLATE_FILE = ''
|
||||||
|
NAMESPACE_CHECK = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
@ -48,6 +49,7 @@ class KubernetesObjectTestCase(testtools.TestCase):
|
|||||||
|
|
||||||
def test_metadata_has_no_namespace(self):
|
def test_metadata_has_no_namespace(self):
|
||||||
"""Ensure that the metadata does not specify the namespace."""
|
"""Ensure that the metadata does not specify the namespace."""
|
||||||
|
if self.NAMESPACE_CHECK:
|
||||||
self.assertNotIn("namespace", self.object["metadata"])
|
self.assertNotIn("namespace", self.object["metadata"])
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,3 +25,4 @@ class HeatAPIDeploymentTestCase(base.DeploymentTestCase):
|
|||||||
|
|
||||||
SAMPLE_FILE = 'orchestration_v1alpha1_heat.yaml'
|
SAMPLE_FILE = 'orchestration_v1alpha1_heat.yaml'
|
||||||
TEMPLATE_FILE = 'heat/deployment.yml.j2'
|
TEMPLATE_FILE = 'heat/deployment.yml.j2'
|
||||||
|
NAMESPACE_CHECK = False
|
||||||
|
@ -25,3 +25,4 @@ class HorizonDeploymentTestCase(base.DeploymentTestCase):
|
|||||||
|
|
||||||
SAMPLE_FILE = 'dashboard_v1alpha1_horizon.yaml'
|
SAMPLE_FILE = 'dashboard_v1alpha1_horizon.yaml'
|
||||||
TEMPLATE_FILE = 'horizon/deployment.yml.j2'
|
TEMPLATE_FILE = 'horizon/deployment.yml.j2'
|
||||||
|
NAMESPACE_CHECK = False
|
||||||
|
28
openstack_operator/tests/unit/test_keystone.py
Normal file
28
openstack_operator/tests/unit/test_keystone.py
Normal file
@ -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.
|
||||||
|
|
||||||
|
"""Tests for Keystone Operator
|
||||||
|
|
||||||
|
This module contains all the tests for the Keystone operator.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from openstack_operator.tests.unit import base
|
||||||
|
|
||||||
|
|
||||||
|
class KeystoneDeploymentTestCase(base.DeploymentTestCase):
|
||||||
|
"""Basic tests for the Deployment."""
|
||||||
|
|
||||||
|
SAMPLE_FILE = 'identity_v1alpha1_keystone.yaml'
|
||||||
|
TEMPLATE_FILE = 'keystone/deployment.yml.j2'
|
||||||
|
NAMESPACE_CHECK = False
|
@ -141,6 +141,8 @@ def generate_yaml(template, **kwargs):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
doc = render_template(template, **kwargs)
|
doc = render_template(template, **kwargs)
|
||||||
|
|
||||||
|
if "adopt" in kwargs and kwargs["adopt"]:
|
||||||
kopf.adopt(doc)
|
kopf.adopt(doc)
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
@ -201,9 +203,12 @@ def get_secret(namespace, name):
|
|||||||
|
|
||||||
api = pykube.HTTPClient(pykube.KubeConfig.from_env())
|
api = pykube.HTTPClient(pykube.KubeConfig.from_env())
|
||||||
|
|
||||||
|
try:
|
||||||
secret = objects.Secret.objects(api).filter(namespace=namespace).get(
|
secret = objects.Secret.objects(api).filter(namespace=namespace).get(
|
||||||
name=name
|
name=name
|
||||||
)
|
)
|
||||||
|
except pykube.exceptions.ObjectDoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
k: base64.b64decode(v).decode('utf-8')
|
k: base64.b64decode(v).decode('utf-8')
|
||||||
@ -225,3 +230,22 @@ def get_uwsgi_env():
|
|||||||
for key, value in UWSGI_SETTINGS.items():
|
for key, value in UWSGI_SETTINGS.items():
|
||||||
res.append({'name': key, 'value': value})
|
res.append({'name': key, 'value': value})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def get_configmap(namespace, name):
|
||||||
|
"""Retrieve a configmap from Kubernetes.
|
||||||
|
|
||||||
|
This function retrieves a configmap from Kubernetes, decodes it and passes
|
||||||
|
the value of the data
|
||||||
|
"""
|
||||||
|
|
||||||
|
api = pykube.HTTPClient(pykube.KubeConfig.from_env())
|
||||||
|
|
||||||
|
try:
|
||||||
|
config = objects.ConfigMap.objects(api).filter(
|
||||||
|
namespace=namespace
|
||||||
|
).get(name=name)
|
||||||
|
except pykube.exceptions.ObjectDoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return config.obj["data"]
|
||||||
|
@ -64,6 +64,9 @@
|
|||||||
# the devstack part of the job, so we keep devstack in the main play to
|
# the devstack part of the job, so we keep devstack in the main play to
|
||||||
# avoid zuul retrying on legitimate failures.
|
# avoid zuul retrying on legitimate failures.
|
||||||
- hosts: all
|
- hosts: all
|
||||||
|
pre_tasks:
|
||||||
|
- name: Set the context with openstack namespace
|
||||||
|
command: kubectl config set-context --current --namespace=openstack
|
||||||
roles:
|
roles:
|
||||||
- orchestrate-devstack
|
- orchestrate-devstack
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user