diff --git a/.gitignore b/.gitignore index 452c6f1..54339fb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ build/ .tox/ func-results.json test-charm/ +.project +.pydevproject diff --git a/src/config.yaml b/src/config.yaml deleted file mode 100644 index 7fc91a3..0000000 --- a/src/config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -options: - os-data-network: - type: string - default: - description: | - The IP address and netmask of the OpenStack Data network (e.g., - 192.168.0.0/24) - . - This network will be used for tenant network traffic in overlay - networks. \ No newline at end of file diff --git a/src/layer.yaml b/src/layer.yaml index a71fc3a..fba2cf6 100644 --- a/src/layer.yaml +++ b/src/layer.yaml @@ -1,5 +1,5 @@ -includes: ['layer:openstack-api'] +includes: ['layer:openstack-api', 'interface:ceph-client'] options: basic: use_venv: True - include_system_packages: True \ No newline at end of file + include_system_packages: True diff --git a/src/lib/charm/openstack/gnocchi.py b/src/lib/charm/openstack/gnocchi.py index f080888..954b5f4 100644 --- a/src/lib/charm/openstack/gnocchi.py +++ b/src/lib/charm/openstack/gnocchi.py @@ -1,16 +1,61 @@ +import os import collections -import socket import subprocess import charmhelpers.core.hookenv as hookenv +import charmhelpers.core.host as host + import charms_openstack.charm +import charms_openstack.adapters as adapters import charms_openstack.ip as os_ip -# import charms_openstack.sdn.odl as odl -# import charms_openstack.sdn.ovs as ovs + +GNOCCHI_DIR = '/etc/gnocchi' +GNOCCHI_CONF = os.path.join(GNOCCHI_DIR, 'gnocchi.conf') +GNOCCHI_APACHE_SITE = 'gnocchi-api' +GNOCCHI_WSGI_CONF = '/etc/apache2/sites-available/{}.conf'.format(GNOCCHI_APACHE_SITE) + +CEPH_CONF = '/etc/ceph/ceph.conf' + +CEPH_POOL_NAME = 'gnocchi' + + +class StorageCephRelationAdapter(adapters.OpenStackRelationAdapter): + """ + Adapter for the CephClientRequires relation interface. + """ + + interface_type = "ceph-client" + + @property + def monitors(self): + """ + Comma separated list of hosts that should be used + to access Ceph. + """ + hosts = self.relation.mon_hosts() + if len(hosts) > 1: + return ','.join(hosts) + else: + return None + + +class GnocchiCharmRelationAdapaters(adapters.OpenStackAPIRelationAdapters): + """ + Adapters collection to append ceph-client adapter for Gnocchi + """ + + relation_adapters = { + 'storage_ceph': StorageCephRelationAdapter, + 'shared_db': adapters.DatabaseRelationAdapter, + 'cluster': adapters.PeerHARelationAdapter, + } class GnocchiCharm(charms_openstack.charm.HAOpenStackCharm): + """ + Charm for Juju deployment of Gnocchi + """ # Internal name of charm service_name = name = 'gnocchi' @@ -19,26 +64,30 @@ class GnocchiCharm(charms_openstack.charm.HAOpenStackCharm): release = 'mitaka' # List of packages to install for this charm - packages = ['gnocchi-api', 'gnocchi-metricd', 'python-apt'] + packages = ['gnocchi-api', 'gnocchi-metricd', 'python-apt', + 'ceph-common', 'python-rados', 'python-keystonemiddleware', + 'apache2', 'libapache2-mod-wsgi'] api_ports = { - 'apache2': { + 'gnocchi-api': { os_ip.PUBLIC: 8041, os_ip.ADMIN: 8041, os_ip.INTERNAL: 8041, } } - service_type = 'gnocchi' - default_service = 'apache2' - services = ['haproxy', 'apache2 gnocchi-metricd', 'apache2'] + default_service = 'gnocchi-api' - # Note that the hsm interface is optional - defined in config.yaml - required_relations = ['shared-db', 'amqp', 'identity-service'] + service_type = 'gnocchi' + + services = ['gnocchi-metricd', 'apache2'] + + required_relations = ['shared-db', 'identity-service', 'storage-ceph'] restart_map = { - - '/etc/gnocchi/gnocchi.conf': services, + GNOCCHI_CONF: services, + GNOCCHI_WSGI_CONF: ['apache2'], + CEPH_CONF: services, } ha_resources = ['vips', 'haproxy'] @@ -49,15 +98,32 @@ class GnocchiCharm(charms_openstack.charm.HAOpenStackCharm): 'gnocchi-common': collections.OrderedDict([ ('2', 'mitaka'), ('3', 'newton'), - ('4', 'ocata'), + ('4', 'pike'), ]), } sync_cmd = ['gnocchi-upgrade'] - def get_amqp_credentials(self): - return ('gnocchi', 'gnocchi') + adapters_class = GnocchiCharmRelationAdapaters + + def install(self): + super(GnocchiCharm, self).install() + # NOTE(jamespage): always pause gnocchi-api service as we force + # execution with Apache2+mod_wsgi + host.service_pause('gnocchi-api') + + def enable_apache2_site(self): + """Enable Gnocchi API apache2 site if rendered or installed""" + if os.path.exists(GNOCCHI_WSGI_CONF): + check_enabled = subprocess.call( + ['a2query', '-s', GNOCCHI_APACHE_SITE] + ) + if check_enabled != 0: + subprocess.check_call(['a2ensite', + GNOCCHI_APACHE_SITE]) + host.service_reload('apache2', + restart_on_failure=True) def get_database_setup(self): return [{ diff --git a/src/metadata.yaml b/src/metadata.yaml index b86e572..8ce0dde 100644 --- a/src/metadata.yaml +++ b/src/metadata.yaml @@ -1,11 +1,19 @@ name: gnocchi -maintainer: example@example.com -summary: Short summary of charm +maintainer: OpenStack Charmers +summary: Multi-tenant timeseries, metrics and resources database description: | - Longline summary of charm + Gnocchi is an open-source, multi-tenant timeseries, metrics + and resources database. It provides an HTTP REST interface + to create and manipulate the data. It is designed to store + metrics at a very large scale while providing access to + metrics and resources information and history. tags: - openstack series: - xenial - trusty - - yakkety \ No newline at end of file + - yakkety + - zesty +requires: + storage-ceph: + interface: ceph-client diff --git a/src/reactive/gnocchi_handlers.py b/src/reactive/gnocchi_handlers.py index 00a5483..79e697f 100644 --- a/src/reactive/gnocchi_handlers.py +++ b/src/reactive/gnocchi_handlers.py @@ -15,41 +15,61 @@ import charms_openstack.charm as charm import charms.reactive as reactive -# This charm's library contains all of the handler code associated with -# sdn_charm import charm.openstack.gnocchi as gnocchi # noqa +import charmhelpers.contrib.storage.linux.ceph as ceph_helper +import charmhelpers.core.hookenv as hookenv + charm.use_defaults( 'charm.installed', - 'amqp.connected', 'shared-db.connected', 'identity-service.connected', 'identity-service.available', # enables SSL support 'config.changed', 'update-status') + @reactive.when('shared-db.available') @reactive.when('identity-service.available') -@reactive.when('amqp.available') +@reactive.when('storage-ceph.available') +@reactive.when('storage-ceph.pools.available') def render_config(*args): """Render the configuration for charm when all the interfaces are available. """ with charm.provide_charm_instance() as charm_class: - charm_class.upgrade_if_available(args) charm_class.render_with_interfaces(args) + charm_class.enable_apache2_site() charm_class.assess_status() reactive.set_state('config.rendered') + # db_sync checks if sync has been done so rerunning is a noop @reactive.when('config.rendered') def init_db(): with charm.provide_charm_instance() as charm_class: charm_class.db_sync() + @reactive.when('ha.connected') def cluster_connected(hacluster): """Configure HA resources in corosync""" with charm.provide_charm_instance() as charm_class: charm_class.configure_ha_resources(hacluster) - charm_class.assess_status() \ No newline at end of file + charm_class.assess_status() + + +@reactive.when('storage-ceph.connected') +def storage_ceph_connected(ceph): + ceph.create_pool(gnocchi.CEPH_POOL_NAME) + + +@reactive.when('storage-ceph.available') +def configure_ceph(ceph): + ceph_helper.create_keyring(hookenv.service_name(), + ceph.key()) + + +@reactive.when_not('storage-ceph.connected') +def storage_ceph_disconnected(): + ceph_helper.delete_keyring(hookenv.service_name()) diff --git a/src/templates/ceph.conf b/src/templates/ceph.conf new file mode 100644 index 0000000..13e5b0a --- /dev/null +++ b/src/templates/ceph.conf @@ -0,0 +1,10 @@ +############################################################################### +# [ WARNING ] +# configuration file maintained by Juju +# local changes will be overwritten. +############################################################################### +[global] +{% if storage_ceph.auth -%} +auth_supported = {{ storage_ceph.auth }} +mon host = {{ storage_ceph.monitors }} +{% endif -%} diff --git a/src/templates/gnocchi-api.conf b/src/templates/gnocchi-api.conf new file mode 100644 index 0000000..cca75e7 --- /dev/null +++ b/src/templates/gnocchi-api.conf @@ -0,0 +1,25 @@ +############################################################################### +# [ WARNING ] +# configuration file maintained by Juju +# local changes will be overwritten. +############################################################################### + +Listen {{ options.service_listen_info.gnocchi_api.public_port }} + + + WSGIDaemonProcess gnocchi-api processes=2 threads=10 user=gnocchi display-name=%{GROUP} + WSGIProcessGroup gnocchi-api + WSGIScriptAlias / /usr/lib/python2.7/dist-packages/gnocchi/rest/app.wsgi + WSGIApplicationGroup %{GLOBAL} + + = 2.4> + Require all granted + + + Order allow,deny + Allow from all + + + ErrorLog /var/log/apache2/gnocchi_error.log + CustomLog /var/log/apache2/gnocchi_access.log combined + diff --git a/src/templates/gnocchi.conf b/src/templates/gnocchi.conf new file mode 100644 index 0000000..48f68c7 --- /dev/null +++ b/src/templates/gnocchi.conf @@ -0,0 +1,28 @@ +############################################################################### +# [ WARNING ] +# configuration file maintained by Juju +# local changes will be overwritten. +############################################################################### +[DEFAULT] +debug = {{ options.debug }} +use_syslog = {{ options.use_syslog }} +log_file = /var/log/gnocchi/gnocchi-api.log + +[api] +auth_mode = keystone + +[indexer] +{% if shared_db.uri -%} +url = {{ shared_db.uri }} +{%- endif %} + +[storage] +{% if storage_ceph.key -%} +driver = ceph +ceph_pool = gnocchi +ceph_username = {{ options.service_name }} +ceph_secret = {{ storage_ceph.key }} +ceph_conffile = /etc/ceph/ceph.conf +{%- endif %} + +{% include "parts/section-keystone-authtoken" %} diff --git a/src/templates/liberty/.keep b/src/templates/liberty/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/templates/mitaka/.keep b/src/templates/mitaka/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/templates/newton/gnocchi-api.conf b/src/templates/newton/gnocchi-api.conf new file mode 100644 index 0000000..a5c42ad --- /dev/null +++ b/src/templates/newton/gnocchi-api.conf @@ -0,0 +1,25 @@ +############################################################################### +# [ WARNING ] +# configuration file maintained by Juju +# local changes will be overwritten. +############################################################################### + +Listen {{ options.service_listen_info.gnocchi_api.public_port }} + + + WSGIDaemonProcess gnocchi-api processes=2 threads=10 user=gnocchi display-name=%{GROUP} + WSGIProcessGroup gnocchi-api + WSGIScriptAlias / /usr/bin/gnocchi-api + WSGIApplicationGroup %{GLOBAL} + + = 2.4> + Require all granted + + + Order allow,deny + Allow from all + + + ErrorLog /var/log/apache2/gnocchi_error.log + CustomLog /var/log/apache2/gnocchi_access.log combined +