diff --git a/chart/test-values.yaml b/chart/test-values.yaml index 9454ee40..b7e832ec 100644 --- a/chart/test-values.yaml +++ b/chart/test-values.yaml @@ -5,6 +5,7 @@ configMap: ceilometer: dbUri: "sqlite:///:memory:" glance: {} + placement: {} horizon: hostAliases: - hostnames: diff --git a/config/samples/operator-config.yaml b/config/samples/operator-config.yaml index 940dcce4..3cb7b9a4 100644 --- a/config/samples/operator-config.yaml +++ b/config/samples/operator-config.yaml @@ -14,6 +14,7 @@ data: heat: {} magnum: {} chronyd: {} + placement: {} backup: secretName: aws-backup url: s3://backups/ diff --git a/devstack/lib/placement b/devstack/lib/placement new file mode 100644 index 00000000..3ef9ff41 --- /dev/null +++ b/devstack/lib/placement @@ -0,0 +1,72 @@ +#!/bin/bash +# +# 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. + +function cleanup_placement { + echo noop +} +export -f cleanup_placement + +function create_placement_conf { + iniset $PLACEMENT_CONF DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL" + iniset $PLACEMENT_CONF api auth_strategy $PLACEMENT_AUTH_STRATEGY + + kubernetes_ensure_resource secret/placement-mysql + PLACEMENT_DATABASE_USER=$(get_data_from_secret placement-mysql openstack USER) + PLACEMENT_DATABASE_PASSWORD=$(get_data_from_secret placement-mysql openstack PASSWORD) + PLACEMENT_DATABASE_NAME=$(get_data_from_secret placement-mysql openstack DATABASE) + iniset $PLACEMENT_CONF placement_database connection "mysql+pymysql://$PLACEMENT_DATABASE_USER:$PLACEMENT_DATABASE_PASSWORD@placement-mysql-master/$PLACEMENT_DATABASE_NAME?charset=utf8" + + kubernetes_ensure_resource secret/placement-application-credential + PLACEMENT_APPLICATION_CREDENTIAL_SECRET=$(get_data_from_secret placement-application-credential openstack secret) + PLACEMENT_APPLICATION_CREDENTIAL_ID=$(get_data_from_secret placement-application-credential openstack id) + iniset $PLACEMENT_CONF keystone_authtoken auth_url $KEYSTONE_AUTH_URI_V3 + iniset $PLACEMENT_CONF keystone_authtoken auth_type v3applicationcredential + iniset $PLACEMENT_CONF keystone_authtoken application_credential_id $PLACEMENT_APPLICATION_CREDENTIAL_ID + iniset $PLACEMENT_CONF keystone_authtoken application_credential_secret $PLACEMENT_APPLICATION_CREDENTIAL_SECRET +} +export -f create_placement_conf + +function configure_placement { + sudo install -d -o $STACK_USER $PLACEMENT_CONF_DIR + create_placement_conf + kubectl create secret generic placement-config --from-file=${PLACEMENT_CONF} -n openstack + + proxy_pass_to_kubernetes /placement placement placement-api +} +export -f configure_placement + +function init_placement { + # NOTE(mnaser): For some reason, DevStack configures Nova to actually + # use the placement service user to talk to it. Let's + # create the user for now and drop it later. + create_service_user "placement" "admin" +} +export -f init_placement + +function install_placement { + echo noop +} +export -f install_placement + +function start_placement { + echo noop +} +export -f start_placement + +function stop_placement { + echo noop +} +export -f stop_placement diff --git a/devstack/settings b/devstack/settings index 4efc6d03..d7165ebb 100644 --- a/devstack/settings +++ b/devstack/settings @@ -21,4 +21,5 @@ source $DEST/openstack-operator/devstack/lib/barbican source $DEST/openstack-operator/devstack/lib/glance source $DEST/openstack-operator/devstack/lib/horizon source $DEST/openstack-operator/devstack/lib/keystone +source $DEST/openstack-operator/devstack/lib/placement source $DEST/openstack-operator/devstack/lib/rpc_backend diff --git a/images/placement/Dockerfile b/images/placement/Dockerfile new file mode 100644 index 00000000..fe683b46 --- /dev/null +++ b/images/placement/Dockerfile @@ -0,0 +1,21 @@ +# 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 vexxhost/python-builder as builder +FROM vexxhost/python-base AS placement +COPY placement-api /usr/local/bin/placement-api +EXPOSE 8780 +ENV UWSGI_HTTP_SOCKET=:8780 UWSGI_WSGI_FILE=/usr/local/bin/placement-api +CMD ["/usr/local/bin/uwsgi", "--ini", "/etc/uwsgi/uwsgi.ini"] diff --git a/images/placement/bindep.txt b/images/placement/bindep.txt new file mode 100644 index 00000000..64b038ba --- /dev/null +++ b/images/placement/bindep.txt @@ -0,0 +1,2 @@ +gcc [compile] +libc-dev [compile] diff --git a/images/placement/constraints.txt b/images/placement/constraints.txt new file mode 100644 index 00000000..e483a913 --- /dev/null +++ b/images/placement/constraints.txt @@ -0,0 +1 @@ +--constraint https://releases.openstack.org/constraints/upper/ussuri diff --git a/images/placement/placement-api b/images/placement/placement-api new file mode 100755 index 00000000..8dcd0d26 --- /dev/null +++ b/images/placement/placement-api @@ -0,0 +1,32 @@ +#!/usr/local/bin/python +# 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. + +import pkg_resources + +import sentry_sdk + +from placement.wsgi import init_application +from sentry_sdk.integrations import wsgi + +VERSION = pkg_resources.get_distribution("openstack-placement").version + +sentry_sdk.init( + release="placement@%s" % VERSION, + traces_sample_rate=0.1 +) + +application = init_application() +application = wsgi.SentryWsgiMiddleware(application) diff --git a/images/placement/requirements.txt b/images/placement/requirements.txt new file mode 100644 index 00000000..8bd79711 --- /dev/null +++ b/images/placement/requirements.txt @@ -0,0 +1,5 @@ +uWSGI +PyMySQL +python-memcached +sentry-sdk +git+https://opendev.org/openstack/placement@stable/ussuri diff --git a/openstack_operator/operator.py b/openstack_operator/operator.py index 8523ca9e..9ac97e77 100644 --- a/openstack_operator/operator.py +++ b/openstack_operator/operator.py @@ -35,6 +35,7 @@ from openstack_operator import horizon from openstack_operator import keystone from openstack_operator import libvirtd_exporter from openstack_operator import magnum +from openstack_operator import placement from openstack_operator import utils @@ -91,6 +92,9 @@ def deploy(name, namespace, new, **_): if "keystone" in config: spec = set_service_config(config, "keystone") keystone.create_or_resume("keystone", spec) + if "placement" in config: + spec = set_service_config(config, "placement") + placement.create_or_resume("placement", spec) if "horizon" in config: spec = set_service_config(config, "horizon") horizon.create_or_resume("horizon", spec) diff --git a/openstack_operator/placement.py b/openstack_operator/placement.py new file mode 100644 index 00000000..8a4a6619 --- /dev/null +++ b/openstack_operator/placement.py @@ -0,0 +1,70 @@ +# 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. + +""" +Placement service + +This code takes care of doing the operations of the OpenStack Placement API +service. +""" + +from openstack_operator import database +from openstack_operator import identity +from openstack_operator import utils + +MEMCACHED = True + + +def create_or_resume(name, spec, **_): + """Create and re-sync a placement instance + + This function is called when a new resource is created but also when we + start the service up for the first time. + """ + + # deploy mysql for placement + if "mysql" not in spec: + database.ensure_mysql_cluster("placement", {}) + else: + database.ensure_mysql_cluster("placement", spec["mysql"]) + + # deploy placement api + utils.create_or_update('placement/daemonset.yml.j2', spec=spec) + utils.create_or_update('placement/service.yml.j2', spec=spec) + + # Create application credential + identity.ensure_application_credential(name="placement") + + url = None + if "ingress" in spec: + utils.create_or_update('placement/ingress.yml.j2', + name=name, spec=spec) + url = spec["ingress"]["host"] + + if "endpoint" not in spec: + spec["endpoint"] = True + if spec["endpoint"]: + identity.ensure_service(name="placement", service_type="placement", + url=url, desc="Placement Service") + + +def update(name, spec, **_): + """Update a placement + + This function updates the deployment for placement if there are any + changes that happen within it. + """ + if "ingress" in spec: + utils.create_or_update('placement/ingress.yml.j2', + name=name, spec=spec) diff --git a/openstack_operator/templates/placement/daemonset.yml.j2 b/openstack_operator/templates/placement/daemonset.yml.j2 new file mode 100644 index 00000000..d3043069 --- /dev/null +++ b/openstack_operator/templates/placement/daemonset.yml.j2 @@ -0,0 +1,95 @@ +--- +# 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: DaemonSet +metadata: + name: placement + namespace: openstack + labels: + {{ labels("placement") | indent(4) }} +spec: + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + {{ labels("placement") | indent(6) }} + template: + metadata: + labels: + {{ labels("placement") | indent(8) }} + spec: + automountServiceAccountToken: false + initContainers: + - name: db-sync + image: vexxhost/placement:latest + imagePullPolicy: Always + command: + - placement-manage + - db + - sync + volumeMounts: + - mountPath: /etc/placement + name: config + containers: + - name: placement + image: vexxhost/placement:latest + imagePullPolicy: Always + env: + {% if 'sentryDSN' in spec %} + - name: SENTRY_DSN + value: {{ spec.sentryDSN }} + {% endif %} + ports: + - name: placement + protocol: TCP + containerPort: 8780 + livenessProbe: + tcpSocket: + port: placement + readinessProbe: + tcpSocket: + port: placement + securityContext: + runAsUser: 1001 + volumeMounts: + - name: ceph + mountPath: /etc/ceph + - name: config + mountPath: /etc/placement + - name: uwsgi-config + mountPath: /etc/uwsgi + volumes: + - name: ceph + secret: + secretName: ceph-config + - name: config + secret: + secretName: placement-config + - name: uwsgi-config + configMap: + defaultMode: 420 + name: uwsgi-default + nodeSelector: + node-role.kubernetes.io/master: "" + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule +{% if 'hostAliases' in spec %} + hostAliases: + {{ spec.hostAliases | to_yaml | indent(8) }} +{% endif %} diff --git a/openstack_operator/templates/placement/ingress.yml.j2 b/openstack_operator/templates/placement/ingress.yml.j2 new file mode 100644 index 00000000..d3f9fc4f --- /dev/null +++ b/openstack_operator/templates/placement/ingress.yml.j2 @@ -0,0 +1,55 @@ +--- +# 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: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: placement + namespace: openstack + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + certmanager.k8s.io/cluster-issuer: "letsencrypt-prod" +spec: +{% if spec.ingress.host is defined %} + rules: + - host: {{ spec.ingress.host }} + http: + paths: + - path: / + backend: + serviceName: placement + servicePort: 80 + tls: + - hosts: + - {{ spec.ingress.host }} + secretName: placement-tls +{% else %} + rules: + {% for v in spec.ingress %} + - host: {{ v.host }} + http: + paths: + - path: / + backend: + serviceName: placement + servicePort: 80 + {% endfor %} + tls: + - hosts: + {% for v in spec.ingress %} + - {{ v.host }} + {% endfor %} + secretName: placement-tls +{% endif %} diff --git a/openstack_operator/templates/placement/service.yml.j2 b/openstack_operator/templates/placement/service.yml.j2 new file mode 100644 index 00000000..4537a9b8 --- /dev/null +++ b/openstack_operator/templates/placement/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: placement + namespace: openstack +spec: + ports: + - name: placement + port: 80 + protocol: TCP + targetPort: placement + selector: + {{ labels("placement") | indent(4) }} diff --git a/zuul.d/functional-jobs.yaml b/zuul.d/functional-jobs.yaml index 7bad9ae1..2a54257f 100644 --- a/zuul.d/functional-jobs.yaml +++ b/zuul.d/functional-jobs.yaml @@ -60,57 +60,61 @@ jobs: - openstack-operator:functional: dependencies: - - name: openstack-operator:images:build:mcrouter-exporter + - name: openstack-operator:images:build:heat soft: true - - name: openstack-operator:images:build:horizon - soft: true - - name: openstack-operator:images:build:magnum - soft: true - - name: openstack-operator:images:build:glance - soft: true - - name: openstack-operator:images:build:rabbitmq + - name: openstack-operator:images:build:barbican 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 + - name: openstack-operator:images:build:rabbitmq soft: true - name: openstack-operator:images:build:keystone soft: true + - name: openstack-operator:images:build:horizon + 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:barbican + - name: openstack-operator:images:build:glance soft: true - - name: openstack-operator:images:build:heat + - name: openstack-operator:images:build:mcrouter-exporter + soft: true + - name: openstack-operator:images:build:memcached-exporter + soft: true + - name: openstack-operator:images:build:magnum + soft: true + - name: openstack-operator:images:build:placement soft: true gate: jobs: - openstack-operator:functional: dependencies: - - name: openstack-operator:images:upload:mcrouter-exporter + - name: openstack-operator:images:upload:heat soft: true - - name: openstack-operator:images:upload:horizon - soft: true - - name: openstack-operator:images:upload:magnum - soft: true - - name: openstack-operator:images:upload:glance - soft: true - - name: openstack-operator:images:upload:rabbitmq + - name: openstack-operator:images:upload:barbican 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 + - name: openstack-operator:images:upload:rabbitmq soft: true - name: openstack-operator:images:upload:keystone soft: true + - name: openstack-operator:images:upload:horizon + 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:barbican + - name: openstack-operator:images:upload:glance soft: true - - name: openstack-operator:images:upload:heat + - name: openstack-operator:images:upload:mcrouter-exporter + soft: true + - name: openstack-operator:images:upload:memcached-exporter + soft: true + - name: openstack-operator:images:upload:magnum + soft: true + - name: openstack-operator:images:upload:placement soft: true diff --git a/zuul.d/placement-jobs.yaml b/zuul.d/placement-jobs.yaml new file mode 100644 index 00000000..b387412e --- /dev/null +++ b/zuul.d/placement-jobs.yaml @@ -0,0 +1,42 @@ +- job: + name: openstack-operator:images:build:placement + parent: vexxhost-build-docker-image + provides: openstack-operator:image:placement + nodeset: &id001 + nodes: + - name: ubuntu-bionic + label: ubuntu-bionic-vexxhost + vars: &id002 + docker_images: + - context: images/placement + repository: vexxhost/placement + target: placement + dependencies: + - openstack-operator:images:build:openstack-operator + files: &id003 + - ^images/placement/.* +- job: + name: openstack-operator:images:upload:placement + parent: vexxhost-upload-docker-image + provides: openstack-operator:image:placement + nodeset: *id001 + vars: *id002 + dependencies: + - openstack-operator:images:upload:openstack-operator + files: *id003 +- job: + name: openstack-operator:images:promote:placement + parent: vexxhost-promote-docker-image + nodeset: *id001 + vars: *id002 + files: *id003 +- project: + check: + jobs: + - openstack-operator:images:build:placement + gate: + jobs: + - openstack-operator:images:upload:placement + promote: + jobs: + - openstack-operator:images:promote:placement