Browse Source

Add service CRD

This introduces a CRD for enabling/removing services from Keystone,
it also introduces a basic DevStack plugin framework so that we can
test things from it.  It also adds a framework for the operator to
setup SDK clients.

Change-Id: I183e560c6b32de2ce7adefeb1daa26def675bbe3
changes/83/723083/16
Mohammed Naser 1 year ago
parent
commit
f49b79fe40
20 changed files with 284 additions and 5 deletions
  1. +1
    -0
      .gitignore
  2. +2
    -0
      bindep.txt
  3. +24
    -0
      chart/crds/identity.openstack.org_services.yaml
  4. +20
    -0
      chart/templates/clusterrole.yaml
  5. +3
    -5
      chart/templates/crds.yaml
  6. +7
    -0
      chart/templates/deployment.yaml
  7. +2
    -0
      chart/test-values.yaml
  8. +8
    -0
      config/samples/identity_v1alpha1_services.yaml
  9. +31
    -0
      devstack/override-defaults
  10. +51
    -0
      devstack/plugin.sh
  11. +20
    -0
      devstack/settings
  12. +0
    -0
      openstack_operator/openstack/__init__.py
  13. +0
    -0
      openstack_operator/openstack/identity/__init__.py
  14. +79
    -0
      openstack_operator/openstack/identity/services.py
  15. +9
    -0
      openstack_operator/utils.py
  16. +3
    -0
      playbooks/functional/devstack.yaml
  17. +19
    -0
      playbooks/functional/run.yaml
  18. +1
    -0
      requirements.txt
  19. +2
    -0
      tox.ini
  20. +2
    -0
      zuul.d/functional-jobs.yaml

+ 1
- 0
.gitignore View File

@ -28,3 +28,4 @@ doc/build
__pycache__
*.egg*
.stestr
openrc

+ 2
- 0
bindep.txt View File

@ -0,0 +1,2 @@
gcc [compile]
libc-dev [compile]

+ 24
- 0
chart/crds/identity.openstack.org_services.yaml View File

@ -0,0 +1,24 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: services.identity.openstack.org
spec:
group: identity.openstack.org
names:
kind: Service
listKind: ServiceList
plural: services
singular: service
scope: Cluster
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

+ 20
- 0
chart/templates/clusterrole.yaml View File

@ -109,6 +109,26 @@ rules:
- get
- patch
- update
- apiGroups:
- identity.openstack.org
resources:
- services
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- identity.openstack.org
resources:
- services/status
verbs:
- get
- patch
- update
- apiGroups:
- infrastructure.vexxhost.cloud
resources:


+ 3
- 5
chart/templates/crds.yaml View File

@ -8,8 +8,6 @@
{{- end }}
{{- end -}}
{{- if .Values.crd.dns }}
{{- range $path, $bytes := .Files.Glob "crds/dns.openstack.org*.yaml" }}
{{ $.Files.Get $path }}
{{- end }}
{{- end -}}
{{- range $path, $bytes := .Files.Glob "crds/*.openstack.org_*.yaml" }}
{{ $.Files.Get $path }}
{{- end }}

+ 7
- 0
chart/templates/deployment.yaml View File

@ -21,6 +21,11 @@ spec:
- name: operator
image: vexxhost/openstack-operator:latest
command: ["/usr/local/bin/kopf"]
{{- with .Values.secretName }}
envFrom:
- secretRef:
name: {{ . }}
{{- end }}
args:
- run
- -m
@ -28,6 +33,8 @@ spec:
- -m
- openstack_operator.memcached
- -m
- openstack_operator.openstack.identity.services
- -m
- openstack_operator.rabbitmq
resources:
limits:


+ 2
- 0
chart/test-values.yaml View File

@ -0,0 +1,2 @@
---
secretName: devstack

+ 8
- 0
config/samples/identity_v1alpha1_services.yaml View File

@ -0,0 +1,8 @@
---
apiVersion: identity.openstack.org/v1alpha1
kind: Service
metadata:
name: heat
spec:
type: orchestration
description: Heat Orchestration Service

+ 31
- 0
devstack/override-defaults View File

@ -0,0 +1,31 @@
#!/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.
# Gets or creates service
# Usage: get_or_create_service <name> <type> <description>
function get_or_create_service {
cat <<EOF | kubectl apply -f-
---
apiVersion: identity.openstack.org/v1alpha1
kind: Service
metadata:
name: ${1//_/-}
spec:
type: $2
description: $3
EOF
}
export -f get_or_create_service

+ 51
- 0
devstack/plugin.sh View File

@ -0,0 +1,51 @@
#!/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 copy_minikube_config {
mkdir ~stack/.kube
sudo cp ~zuul/.kube/config ~stack/.kube/config
sudo cp ~zuul/.minikube/ca.crt ~stack/.kube/ca.crt
sudo cp ~zuul/.minikube/profiles/minikube/client.crt ~stack/.kube/client.crt
sudo cp ~zuul/.minikube/profiles/minikube/client.key ~stack/.kube/client.key
sudo chown -Rv stack:stack ~stack/.kube
sed -i s%/home/zuul/.minikube/profiles/minikube%/opt/stack/.kube% ~/.kube/config
sed -i s%/home/zuul/.minikube/ca.crt%/opt/stack/.kube/ca.crt% ~/.kube/config
kubectl cluster-info
}
if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
copy_minikube_config
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
:
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
:
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
:
fi
if [[ "$1" == "unstack" ]]; then
:
fi
if [[ "$1" == "clean" ]]; then
:
fi

+ 20
- 0
devstack/settings View File

@ -0,0 +1,20 @@
#!/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.
define_plugin openstack-operator
disable_service etcd3
disable_service rabbit

+ 0
- 0
openstack_operator/openstack/__init__.py View File


+ 0
- 0
openstack_operator/openstack/identity/__init__.py View File


+ 79
- 0
openstack_operator/openstack/identity/services.py View File

@ -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.
"""Services Operator
This operator helps manage the creation and removal of services inside
Keystone using custom resources.
"""
import kopf
from openstack_operator import utils
def _get_service(conn, name, service_type):
"""Get a service from Keystone
This method will retrieve the service from Keystone, raise an error if it
found more than one or return None if it couldn't find it
"""
services = conn.search_services(name_or_id=name,
filters={"type": service_type})
if len(services) > 1:
raise RuntimeError("Found multiple services with name and type")
if len(services) == 0:
return None
return services[0]
@kopf.on.resume('identity.openstack.org', 'v1alpha1', 'services')
@kopf.on.create('identity.openstack.org', 'v1alpha1', 'services')
def create_or_resume(name, spec, **_):
"""Create or resume controller
This function runs when a new resource is created or when the controller
is first started. It creates or updates the appropriate service.
"""
conn = utils.get_openstack_connection()
service = _get_service(conn, name, spec["type"])
if service:
service = conn.update_service(service.id, name=name,
type=spec["type"],
description=spec["description"])
return
service = conn.create_service(name=name, type=spec["type"],
description=spec["description"])
@kopf.on.delete('identity.openstack.org', 'v1alpha1', 'services')
def delete(name, spec, **_):
"""Delete a service
This function runs when the servce CR is deleted and removes the record
from Keystone.
"""
conn = utils.get_openstack_connection()
service = _get_service(conn, name, spec["type"])
if not service:
return
conn.delete_service(service)

+ 9
- 0
openstack_operator/utils.py View File

@ -23,7 +23,9 @@ import operator
import os
import jinja2
import openstack
import kopf
from pbr import version
import pykube
import yaml
@ -31,6 +33,7 @@ from openstack_operator import objects
DIR_PATH = os.path.dirname(os.path.realpath(__file__))
VERSION = version.VersionInfo('openstack_operator').version_string()
def to_yaml(value):
@ -147,3 +150,9 @@ def get_ready_pod_ips(namespace, selector):
servers = sorted([p.obj["status"]["podIP"] for p in ready_pods])
return servers
def get_openstack_connection():
"""Get an instance of OpenStack SDK."""
return openstack.connect(cloud="envvars", app_name='openstack-operator',
app_version=VERSION)

+ 3
- 0
playbooks/functional/devstack.yaml View File

@ -55,6 +55,9 @@
name: write-devstack-local-conf
vars:
devstack_localrc: "{{ _devstack_localrc | combine(_devstack_localrc_extra) }}"
- name: Copy Zuul repo into devstack working directory
become: true
command: rsync -av src/opendev.org/vexxhost/openstack-operator /opt/stack
# Changes that run through devstack-tempest are likely to have an impact on
# the devstack part of the job, so we keep devstack in the main play to


+ 19
- 0
playbooks/functional/run.yaml View File

@ -15,11 +15,30 @@
# limitations under the License.
- hosts: all
pre_tasks:
- name: Create secret for DevStack credentials
shell: |
cat <<EOF | kubectl apply -f-
apiVersion: v1
kind: Secret
metadata:
name: devstack
stringData:
OS_INSECURE: "true"
OS_AUTH_URL: http://{{ hostvars['controller']['nodepool']['private_ipv4'] }}/identity
OS_AUTH_TYPE: password
OS_PROJECT_DOMAIN_ID: default
OS_PROJECT_NAME: admin
OS_USER_DOMAIN_ID: default
OS_USERNAME: admin
OS_PASSWORD: secretadmin
EOF
roles:
- role: helm-template
vars:
helm_release_name: openstack-operator
helm_chart: ./chart
helm_values_file: ./chart/test-values.yaml
tasks:
# TODO(mnaser): Generate all manifests and ensure git is not dirty
- include_tasks: tests/memcached.yaml


+ 1
- 0
requirements.txt View File

@ -1,2 +1,3 @@
kopf
Jinja2
openstacksdk

+ 2
- 0
tox.ini View File

@ -4,6 +4,8 @@ envlist = py37
[testenv]
usedevelop = True
passenv =
OS_*
deps =
-rtest-requirements.txt
-rrequirements.txt


+ 2
- 0
zuul.d/functional-jobs.yaml View File

@ -10,6 +10,8 @@
devstack_services:
etcd3: false
rabbit: false
devstack_plugins:
openstack-operator: https://opendev.org/vexxhost/openstack-operator
docker_use_buildset_registry: true
minikube_dns_resolvers: [1.1.1.1, 8.8.8.8]


Loading…
Cancel
Save