commit 29d6d050adbcbc5f974ba1e759018100cf88120a Author: Liam Young Date: Mon Jun 25 12:44:12 2018 +0000 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98c9c5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +build +.tox +layers +interfaces +trusty +.testrepository +__pycache__ +.stestr diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..96d5c76 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +charm-tools +simplejson diff --git a/src/config.yaml b/src/config.yaml new file mode 100644 index 0000000..1639ef3 --- /dev/null +++ b/src/config.yaml @@ -0,0 +1,93 @@ +options: + debug: + type: boolean + default: False + description: Enable debug logging. + verbose: + type: boolean + default: False + description: Enable verbose logging. + use-syslog: + type: boolean + default: False + description: | + Setting this to True will allow supporting services to log to syslog. + openstack-origin: + type: string + default: distro + description: | + Repository from which to install. May be one of the following: + distro (default), ppa:somecustom/ppa, a deb url sources entry, + or a supported Ubuntu Cloud Archive e.g. + . + cloud:- + cloud:-/updates + cloud:-/staging + cloud:-/proposed + . + See https://wiki.ubuntu.com/OpenStack/CloudArchive for info on which + cloud archives are available and supported. + . + NOTE: updating this setting to a source that is known to provide + a later version of OpenStack will trigger a software upgrade unless + action-managed-upgrade is set to True. + harden: + type: string + default: + description: | + Apply system hardening. Supports a space-delimited list of modules + to run. Supported modules currently include os, ssh, apache and mysql. + nova-alchemy-flags: + type: string + default: + description: | + Comma-separated list of key=value sqlalchemy related config flags to be + set in nova.conf [database] section. + network-manager: + type: string + default: FlatDHCPManager + description: | + Network manager for the cloud; supports the following options: + . + FlatDHCPManager (nova-network) (default) + FlatManager (nova-network) + Neutron (Full SDN solution) + . + When using the Neutron option you will most likely want to use + the neutron-gateway charm to provide L3 routing and DHCP Services. + config-flags: + type: string + default: + description: | + Comma-separated list of key=value config flags. These values will be + placed in the nova.conf [DEFAULT] section. + region: + type: string + default: RegionOne + description: OpenStack Region + # Monitoring config + nagios_context: + type: string + default: "juju" + description: | + Used by the nrpe-external-master subordinate charm. + A string that will be prepended to instance name to set the host name + in nagios. So for instance the hostname would be something like: + . + juju-myservice-0 + . + If you're running multiple environments with the same services in them + this allows you to differentiate between them. + nagios_servicegroups: + type: string + default: "" + description: | + A comma-separated list of nagios servicegroups. If left empty, the + nagios_context will be used as the servicegroup. + cell-name: + type: string + default: + description: | + Name of the compute cell this controller is associated with. If this is + left unset or set to api then it is assumed that this controller will be + the top level api and cell0 controller. diff --git a/src/layer.yaml b/src/layer.yaml new file mode 100644 index 0000000..506143b --- /dev/null +++ b/src/layer.yaml @@ -0,0 +1,10 @@ +includes: + - layer:openstack-api + - interface:mysql-shared + - interface:rabbitmq + - interface:nova-compute + - interface:nova-cell +options: + basic: + use_venv: true + include_system_packages: true diff --git a/src/lib/charm/openstack/__init__.py b/src/lib/charm/openstack/__init__.py new file mode 100644 index 0000000..9b088de --- /dev/null +++ b/src/lib/charm/openstack/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2016 Canonical Ltd +# +# 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. diff --git a/src/lib/charm/openstack/nova_cell_controller.py b/src/lib/charm/openstack/nova_cell_controller.py new file mode 100644 index 0000000..c7b9d7a --- /dev/null +++ b/src/lib/charm/openstack/nova_cell_controller.py @@ -0,0 +1,113 @@ +# Copyright 2016 Canonical Ltd +# +# 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. +# The nova_cell_controller handlers class + +# bare functions are provided to the reactive handlers to perform the functions +# needed on the class. +from __future__ import absolute_import + +import collections +import subprocess + +import charmhelpers.core.hookenv as hookenv + +import charms_openstack.charm +import charms_openstack.adapters +import charms_openstack.ip as os_ip + +PACKAGES = ['nova-conductor'] +NOVA_DIR = '/etc/nova/' +NOVA_CONF = NOVA_DIR + "nova.conf" + +OPENSTACK_RELEASE_KEY = 'nova-charm.openstack-release-version' + + +# select the default release function +charms_openstack.charm.use_defaults('charm.default-select-release') + + +class NovaCellControllerCharm(charms_openstack.charm.HAOpenStackCharm): + """NovaCellControllerCharm provides the specialisation of the OpenStackCharm + functionality to manage a nova_cell_controller unit. + """ + + release = 'mitaka' + name = 'nova-cell-controller' + packages = PACKAGES + service_type = 'nova-cell-controller' + default_service = 'nova-conductor' + services = ['nova-conductor'] + + # Note that the hsm interface is optional - defined in config.yaml + required_relations = ['shared-db', 'amqp'] + + restart_map = { + NOVA_CONF: services, + } + + # Package for release version detection + release_pkg = 'nova-common' + + # Package codename map for nova-common + package_codenames = { + 'nova-common': collections.OrderedDict([ + ('13', 'mitaka'), + ('14', 'newton'), + ('15', 'ocata'), + ('16', 'pike'), + ('17', 'queens'), + ('18', 'rocky'), + ]), + } + + sync_cmd = ['nova-manage', 'db', 'sync' ,'--local_cell'] + + def get_amqp_credentials(self): + """Provide the default amqp username and vhost as a tuple. + + :returns (username, host): two strings to send to the amqp provider. + """ + return ('nova', 'openstack') + + def get_database_setup(self): + """Provide the default database credentials as a list of 3-tuples + + returns a structure of: + [ + {'database': , + 'username': , + 'hostname': + 'prefix': , }, + ] + + :returns [{'database': ...}, ...]: credentials for multiple databases + """ + return [{'username': 'nova', 'database': 'nova'}] + + + def states_to_check(self, required_relations=None): + """Override the default states_to_check() for the assess_status + functionality so that, if we have to have an HSM relation, then enforce + it on the assess_status() call. + + If param required_relations is not None then it overrides the + instance/class variable self.required_relations. + + :param required_relations: [list of state names] + :returns: [states{} as per parent method] + """ + if required_relations is None: + required_relations = self.required_relations + return super(NovaCellControllerCharm, self).states_to_check( + required_relations=required_relations) diff --git a/src/metadata.yaml b/src/metadata.yaml new file mode 100644 index 0000000..0703f59 --- /dev/null +++ b/src/metadata.yaml @@ -0,0 +1,45 @@ +name: nova-cell-controller +summary: OpenStack Compute - Nova cloud controller for a cell. +maintainer: OpenStack Charmers +description: | + OpenStack is a reliable cloud infrastructure. Its mission is to produce + the ubiquitous cloud computing platform that will meet the needs of public + and private cloud providers regardless of size, by being simple to implement + and massively scalable. + . + OpenStack Compute, codenamed Nova, is a cloud computing fabric controller. In + addition to its "native" API (the OpenStack API), it also supports the Amazon + EC2 API. + . + This charm provides the cloud controller service for OpenStack Nova cell + and includes nova-conductor service. +tags: + - openstack +series: + - xenial + - bionic + - artful + - trusty +extra-bindings: + public: + admin: + internal: +provides: + nrpe-external-master: + interface: nrpe-external-master + scope: container + cloud-controller: + interface: nova +requires: + shared-db: + interface: mysql-shared + amqp: + interface: rabbitmq + cloud-compute: + interface: nova-compute + nova-cell-compute: + interface: nova-cell +peers: + cluster: + interface: nova-ha + diff --git a/src/reactive/__init__.py b/src/reactive/__init__.py new file mode 100644 index 0000000..9b088de --- /dev/null +++ b/src/reactive/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2016 Canonical Ltd +# +# 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. diff --git a/src/reactive/nova_cell_controller_handlers.py b/src/reactive/nova_cell_controller_handlers.py new file mode 100644 index 0000000..1ceb4af --- /dev/null +++ b/src/reactive/nova_cell_controller_handlers.py @@ -0,0 +1,107 @@ +# Copyright 2018 Canonical Ltd +# +# 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. + +# this is just for the reactive handlers and calls into the charm. +from __future__ import absolute_import + +import charms.reactive as reactive +import charmhelpers.core.hookenv as hookenv + +import charms_openstack.charm as charm + +from charms.reactive.relations import ( + endpoint_from_flag, +) + +from charms.reactive.flags import ( + is_flag_set, + set_flag, + clear_flag, +) + +# This charm's library contains all of the handler code associated with +# nova_cell_controller -- we need to import it to get the definitions for the +# charm. +import charm.openstack.nova_cell_controller as nova_cell_controller # noqa + + +# Use the charms.openstack defaults for common states and hooks +charm.use_defaults( + 'charm.installed', + 'amqp.connected', + 'shared-db.connected', + 'config.changed', + 'update-status') + + +# Note that because of the way reactive.when works, (which is to 'find' the +# __code__ segment of the decorated function, it's very, very difficult to add +# other kinds of decorators here. This rules out adding other things into the +# charm args list. It is also CPython dependent. +@reactive.when('shared-db.available') +@reactive.when('amqp.available') +def render_stuff(*args): + """Render the configuration for Nova cell controller when all the interfaces + are available. + + """ + hookenv.log("about to call the render_configs with {}".format(args)) + with charm.provide_charm_instance() as nova_cell_controller_charm: + nova_cell_controller_charm.render_with_interfaces(args) + nova_cell_controller_charm.assess_status() + set_flag('config.rendered') + + +@reactive.when_not('shared-db.synced') +@reactive.when('config.rendered') +def db_setup(*args): + with charm.provide_charm_instance() as cell_charm: + cell_charm.db_sync() + cell_charm.restart_all() + set_flag('shared-db.synced') + + +@reactive.when('endpoint.nova-cell-compute.changed') +@reactive.when('endpoint.cloud-compute.joined') +def send_compute_data(): + nc = endpoint_from_flag('endpoint.cloud-compute.joined') + ncc_ep = endpoint_from_flag('endpoint.nova-cell-compute.changed') + ncc_console_data = ncc_ep.get_console_data() + ncc_network_data = ncc_ep.get_network_data() + nc.set_network_data( + ncc_network_data['quantum_url'], + neutron_plugin=ncc_network_data['quantum_plugin'], + network_manager=ncc_network_data['network_manager'], + enable_security_groups=ncc_network_data['quantum_security_groups']) + nc.set_console_data( + serial_console_base_url=ncc_console_data['serial_console_base_url'], + enable_serial_console=ncc_console_data['enable_serial_console']) + nc.set_region(ncc_ep.get_region()['region']) + nc.set_volume_data(ncc_ep.get_volume_data()['volume_service']) + nc.set_ec2_data(ncc_ep.get_ec2_data()['ec2_host']) + +@reactive.when('shared-db.available') +@reactive.when('amqp.available') +@reactive.when('endpoint.nova-cell-compute.joined') +def send_cell_data(): + ncc_ep = endpoint_from_flag('endpoint.nova-cell-compute.joined') + amqp_conv = endpoint_from_flag('amqp.available').conversation() + # Push this calculation of service names down into the interfaces + amqp_service_names = [u.split('/')[0] for u in amqp_conv.units if u] + db_conv = endpoint_from_flag('shared-db.available').conversation() + db_service_names = [u.split('/')[0] for u in db_conv.units if u] + ncc_ep.send_cell_data( + hookenv.config('cell-name'), + amqp_service_names[0], + db_service_names[0]) diff --git a/src/templates/mitaka/nova.conf b/src/templates/mitaka/nova.conf new file mode 100644 index 0000000..5ef0626 --- /dev/null +++ b/src/templates/mitaka/nova.conf @@ -0,0 +1,18 @@ +# mitaka +############################################################################### +# [ WARNING ] +# Configuration file maintained by Juju. Local changes may be overwritten. +############################################################################### +[DEFAULT] +verbose={{ options.verbose }} +debug={{ options.debug }} +logdir=/var/log/nova +state_path=/var/lib/nova +root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf + +{% include "parts/database" %} + +[conductor] +workers = {{ options.workers }} + +{% include "parts/section-rabbitmq-oslo" %} diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..744d2df --- /dev/null +++ b/tox.ini @@ -0,0 +1,54 @@ +# Source charm: ./tox.ini +# This file is managed centrally by release-tools and should not be modified +# within individual charm repos. +[tox] +skipsdist = True +envlist = pep8,py34,py35 +skip_missing_interpreters = True + +[testenv] +setenv = VIRTUAL_ENV={envdir} + PYTHONHASHSEED=0 + TERM=linux + LAYER_PATH={toxinidir}/layers + JUJU_REPOSITORY={toxinidir}/build +passenv = http_proxy https_proxy INTERFACE_PATH +install_command = + pip install {opts} {packages} +deps = + -r{toxinidir}/requirements.txt + +[testenv:build] +basepython = python2.7 +commands = + charm-build --log-level DEBUG -o {toxinidir}/build src {posargs} + +[testenv:py27] +basepython = python2.7 +# Reactive source charms are Python3-only, but a py27 unit test target +# is required by OpenStack Governance. Remove this shim as soon as +# permitted. http://governance.openstack.org/reference/cti/python_cti.html +whitelist_externals = true +commands = true + +[testenv:py34] +basepython = python3.4 +deps = -r{toxinidir}/test-requirements.txt +commands = ostestr {posargs} + +[testenv:py35] +basepython = python3.5 +deps = -r{toxinidir}/test-requirements.txt +commands = ostestr {posargs} + +[testenv:pep8] +basepython = python3.5 +deps = -r{toxinidir}/test-requirements.txt +commands = flake8 {posargs} src unit_tests + +[testenv:venv] +commands = {posargs} + +[flake8] +# E402 ignore necessary for path append before sys module import in actions +ignore = E402