commit 79c265c408699d97166b2a42bf0afa9df3c48ed0 Author: Corey Bryant Date: Mon Nov 30 15:33:53 2015 +0000 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..0dbe1e4 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# Overview + +This interface layer handles the communication with MySQL via the `mysql-shared` +interface protocol. + +# Usage + +## Requires + +The interface layer will set the following states, as appropriate: + + * `{relation_name}.connected` The relation is established, but MySQL has not + been provided the database information. + * `{relation_name}.available` MySQL is ready for use. You can get the base + connection information via the following methods: + * `allowed_units()` + * `database()` + * `db_host()` + * `hostname()` + * `username()` + * `password()` + * `{relation_name}.available.access_network` MySQL access network is ready + for use. You can get this optional connection information via the following + method: + * `access_network()` + * `{relation_name}.available.ssl` MySQL ssl data is ready for use. You can + get this optional connection information via the following methods: + * `ssl_ca()` + * `ssl_cert()` + * `ssl_key()` + +For example: + +```python +from charmhelpers.core.hookenv import log, status_set, unit_get +from charms.reactive import when, when_not + + +@when('database.connected') +def setup_database(database): + host = unit_get('private-address') + database.configure('mydatabase', 'myusername', host, prefix="first") + database.configure('mydatabase2', 'myusername2', host, prefix="second") + +@when('database.available') +def use_database(database): + # base data provided by our charm layer + log("first_database=%s" % database.database("first")) + log("first_username=%s" % database.username("first")) + log("first_hostname=%s" % database.hostname("first")) + log("second_database=%s" % database.database("second")) + log("second_username=%s" % database.username("second")) + log("second_hostname=%s" % database.hostname("second")) + + # base data provided by mysql + log("db_host=%s" % database.db_host()) + log("first_password=%s" % database.password("first")) + log("first_allowed_units=%s" % database.allowed_units("first")) + log("second_password=%s" % database.password("second")) + log("second_allowed_units=%s" % database.allowed_units("second")) + +@when('database.available.access_network') +def use_database_access_network(database): + # optional data provided by mysql + log("access-network=%s" % database.access_network()) + +@when('database.available.ssl') +def use_database_ssl(database): + # optional data provided by mysql + log("ssl_ca=%s" % database.ssl_ca()) + log("ssl_cert=%s" % database.ssl_cert()) + log("ssl_key=%s" % database.ssl_key()) + +@when('database.connected') +@when_not('database.available') +def waiting_mysql(database): + status_set('waiting', 'Waiting for MySQL') + +@when('database.connected', 'database.available') +def unit_ready(database): + status_set('active', 'Unit is ready') +``` diff --git a/copyright b/copyright new file mode 100644 index 0000000..afa853f --- /dev/null +++ b/copyright @@ -0,0 +1,9 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0 + +Files: * +Copyright: 2015, Canonical Ltd. +License: GPL-3 + +License: GPL-3 + On Debian GNU/Linux system you can find the complete text of the + GPL-3 license in '/usr/share/common-licenses/GPL-3' diff --git a/interface.yaml b/interface.yaml new file mode 100644 index 0000000..bc67cac --- /dev/null +++ b/interface.yaml @@ -0,0 +1,3 @@ +name: mysql-shared +summary: Interface for intergrating with MySQL +maintainer: OpenStack Charmers diff --git a/peer.py b/peer.py new file mode 100644 index 0000000..e69de29 diff --git a/provides.py b/provides.py new file mode 100644 index 0000000..e69de29 diff --git a/requires.py b/requires.py new file mode 100644 index 0000000..c66769e --- /dev/null +++ b/requires.py @@ -0,0 +1,153 @@ +from charms.reactive import RelationBase +from charms.reactive import hook +from charms.reactive import scopes + + +class MySQLSharedRequires(RelationBase): + scope = scopes.GLOBAL + + # These remote data fields will be automatically mapped to accessors + # with a basic documentation string provided. + auto_accessors = ['access-network', 'db_host', + 'ssl_ca', 'ssl_cert', 'ssl_key'] + + @hook('{requires:mysql-shared}-relation-joined') + def joined(self): + self.set_state('{relation_name}.connected') + + @hook('{requires:mysql-shared}-relation-changed') + def changed(self): + if self.base_data_complete(): + self.set_state('{relation_name}.available') + if self.access_network_data_complete(): + self.set_state('{relation_name}.available.access_network') + if self.ssl_data_complete(): + self.set_state('{relation_name}.available.ssl') + + @hook('{requires:mysql-shared}-relation-{broken,departed}') + def departed(self): + self.remove_state('{relation_name}.connected') + self.remove_state('{relation_name}.available') + self.remove_state('{relation_name}.available.access_network') + self.remove_state('{relation_name}.available.ssl') + + def configure(self, database, username, hostname, prefix=None): + """ + Called by charm layer that uses this interface to configure a database. + """ + if prefix: + relation_info = { + prefix + '_database': database, + prefix + '_username': username, + prefix + '_hostname': hostname, + } + self.set_prefix(prefix) + else: + relation_info = { + 'database': database, + 'username': username, + 'hostname': hostname, + } + self.set_remote(**relation_info) + self.set_local(**relation_info) + + def set_prefix(self, prefix): + """ + Store all of the database prefixes in a list. + """ + prefixes = self.get_local('prefixes') + if prefixes: + if prefix not in prefixes: + self.set_local('prefixes', prefixes + [prefix]) + else: + self.set_local('prefixes', [prefix]) + + def get_prefixes(self): + """ + Return the list of saved prefixes. + """ + return self.get_local('prefixes') + + def database(self, prefix=None): + """ + Return a configured database name. + """ + if prefix: + return self.get_local(prefix + '_database') + return self.get_local('database') + + def username(self, prefix=None): + """ + Return a configured username. + """ + if prefix: + return self.get_local(prefix + '_username') + return self.get_local('username') + + def hostname(self, prefix=None): + """ + Return a configured hostname. + """ + if prefix: + return self.get_local(prefix + '_hostname') + return self.get_local('hostname') + + def password(self, prefix=None): + """ + Return a database password. + """ + if prefix: + return self.get_remote(prefix + '_password') + return self.get_remote('password') + + def allowed_units(self, prefix=None): + """ + Return a database's allowed_units. + """ + if prefix: + return self.get_remote(prefix + '_allowed_units') + return self.get_remote('allowed_units') + + def base_data_complete(self): + """ + Check if required base data is complete. + """ + data = { + 'db_host': self.db_host(), + } + if self.get_prefixes(): + suffixes = ['_password', '_allowed_units'] + for prefix in self.get_prefixes(): + for suffix in suffixes: + key = prefix + suffix + data[key] = self.get_remote(key) + else: + data['password'] = self.get_remote('password') + data['allowed_units'] = self.get_remote('allowed_units') + if all(data.values()): + return True + return False + + def access_network_data_complete(self): + """ + Check if optional access network data provided by mysql is complete. + """ + data = { + 'access-network': self.access_network(), + } + if all(data.values()): + return True + return False + + def ssl_data_complete(self): + """ + Check if optional ssl data provided by mysql is complete. + """ + # Note: ssl_ca can also be set but isn't required + data = { + 'ssl_cert': self.ssl_cert(), + 'ssl_key': self.ssl_key(), + } + if all(data.values()): + return True + return False