diff --git a/src/layer.yaml b/src/layer.yaml index db0b838..cbfbced 100644 --- a/src/layer.yaml +++ b/src/layer.yaml @@ -3,6 +3,7 @@ includes: - layer:snap - interface:nrpe-external-master - interface:pgsql + - interface:mysql-shared options: basic: packages: diff --git a/src/metadata.yaml b/src/metadata.yaml index 442afbc..2cd1bd5 100644 --- a/src/metadata.yaml +++ b/src/metadata.yaml @@ -19,6 +19,8 @@ tags: requires: db: interface: pgsql + shared-db: + interface: mysql-shared provides: nrpe-external-master: interface: nrpe-external-master diff --git a/src/reactive/vault.py b/src/reactive/vault.py index 1ae50a0..fe2859c 100644 --- a/src/reactive/vault.py +++ b/src/reactive/vault.py @@ -55,17 +55,9 @@ def ssl_available(config): return True -@when('snap.installed.vault') -@when_not('configured') -@when('db.master.available') -@when('vault.schema.created') -@when('vault.ssl.configured') -def configure_vault(psql): - context = { - 'db_conn': psql.master, - 'disable_mlock': config()['disable-mlock'], - 'ssl_available': is_state('vault.ssl.available'), - } +def configure_vault(context): + context['disable_mlock'] = config()['disable-mlock'] + context['ssl_available'] = is_state('vault.ssl.available') status_set('maintenance', 'creating vault config') render( 'vault.hcl.j2', @@ -91,6 +83,31 @@ def configure_vault(psql): status_set('active', '=^_^=') +@when('snap.installed.vault') +@when_not('configured') +@when('db.master.available') +@when('vault.schema.created') +@when('vault.ssl.configured') +def configure_vault_psql(psql): + context = { + 'storage_name': 'psql', + 'psql_db_conn': psql.master, + } + configure_vault(context) + + +@when('snap.installed.vault') +@when_not('configured') +@when('shared-db.available') +@when('vault.ssl.configured') +def configure_vault_mysql(mysql): + context = { + 'storage_name': 'mysql', + 'mysql_db_relation': mysql, + } + configure_vault(context) + + @when('config.changed.disable-mlock') def disable_mlock_changed(): remove_state('configured') @@ -108,6 +125,17 @@ def request_db(pgsql): pgsql.set_database('vault') +@when('shared-db.connected') +def mysql_setup(database): + """Handle the default database connection setup + """ + db = { + 'database': 'vault', + 'username': 'vault', + } + database.configure(**db) + + @when('db.master.available') @when_not('vault.schema.created') def create_vault_table(pgsql): @@ -144,10 +172,10 @@ def configure_ssl(): ssl_cert = ssl_cert + base64.decodestring(c['ssl-chain'].encode()) write_file('/var/snap/vault/common/vault.crt', ssl_cert, perms=0o600) set_state('vault.ssl.available') - status_set('active', 'SSL key and cert installed') else: remove_state('vault.ssl.available') set_state('vault.ssl.configured') + status_set('active', 'SSL key and cert installed') remove_state('configured') diff --git a/src/templates/vault.hcl.j2 b/src/templates/vault.hcl.j2 index 03686c2..1102415 100644 --- a/src/templates/vault.hcl.j2 +++ b/src/templates/vault.hcl.j2 @@ -1,9 +1,16 @@ {%- if disable_mlock %} disable_mlock = true {%- endif %} -{%- if db_conn %} +{%- if storage_name == 'psql' %} storage "postgresql" { - connection_url = "{{ db_conn.uri }}" + connection_url = "{{ psql_db_conn.uri }}" +} +{% elif storage_name == 'mysql' %} +storage "mysql" { + username = "{{ mysql_db_relation.username() }}" + password = "{{ mysql_db_relation.password() }}" + database = "{{ mysql_db_relation.database() }}" + address = "{{ mysql_db_relation.db_host() }}:3306" } {%- endif %} listener "tcp" { diff --git a/src/tests/bundles/xenial-mysql.yaml b/src/tests/bundles/xenial-mysql.yaml new file mode 100644 index 0000000..1a81223 --- /dev/null +++ b/src/tests/bundles/xenial-mysql.yaml @@ -0,0 +1,12 @@ +series: xenial +services: + vault: + num_units: 1 + series: xenial + charm: ../../../vault + mysql: + charm: cs:mysql + num_units: 1 +relations: +- - vault:shared-db + - mysql:shared-db diff --git a/src/tests/bundles/xenial.yaml b/src/tests/bundles/xenial-postgres.yaml similarity index 100% rename from src/tests/bundles/xenial.yaml rename to src/tests/bundles/xenial-postgres.yaml diff --git a/src/tests/tests.yaml b/src/tests/tests.yaml index 00c2058..4f2ea5b 100644 --- a/src/tests/tests.yaml +++ b/src/tests/tests.yaml @@ -4,6 +4,9 @@ tests: configure: - zaza.charm_tests.vault.setup.basic_setup gate_bundles: - - xenial + - xenial-postgres + - xenial-mysql +smoke_bundles: + - xenial-mysql dev_bundles: - bionic diff --git a/src/tox.ini b/src/tox.ini index 1f17f39..6f7622b 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -29,7 +29,7 @@ commands = [testenv:func-smoke] basepython = python3 commands = - functest-run-suite --keep-model + functest-run-suite --keep-model --smoke [testenv:venv] commands = {posargs} diff --git a/unit_tests/test_vault.py b/unit_tests/test_vault.py index d46955c..ba2a162 100644 --- a/unit_tests/test_vault.py +++ b/unit_tests/test_vault.py @@ -41,12 +41,13 @@ class TestHandlers(unittest.TestCase): service_start, open_port, config, is_state): config.return_value = {'disable-mlock': False} is_state.return_value = True - psql = mock.MagicMock() - psql = mock.MagicMock() - psql.master = 'myuri' - handlers.configure_vault(psql) + db_context = { + 'storage_name': 'psql', + 'psql_db_conn': 'myuri'} + handlers.configure_vault(db_context) expected_context = { - 'db_conn': 'myuri', + 'storage_name': 'psql', + 'psql_db_conn': 'myuri', 'disable_mlock': False, 'ssl_available': True, } @@ -76,7 +77,7 @@ class TestHandlers(unittest.TestCase): # Check flipping disable-mlock makes it to the context config.return_value = {'disable-mlock': True} expected_context['disable_mlock'] = True - handlers.configure_vault(psql) + handlers.configure_vault(db_context) render_calls = [ mock.call( 'vault.hcl.j2', @@ -91,6 +92,23 @@ class TestHandlers(unittest.TestCase): ] render.assert_has_calls(render_calls) + @patch.object(handlers, 'configure_vault') + def test_configure_vault_psql(self, configure_vault): + psql = mock.MagicMock() + psql.master = 'myuri' + handlers.configure_vault_psql(psql) + configure_vault.assert_called_once_with({ + 'storage_name': 'psql', + 'psql_db_conn': 'myuri'}) + + @patch.object(handlers, 'configure_vault') + def test_configure_vault_msql(self, configure_vault): + mysql = mock.MagicMock() + handlers.configure_vault_mysql(mysql) + configure_vault.assert_called_once_with({ + 'storage_name': 'mysql', + 'mysql_db_relation': mysql}) + @patch.object(handlers, 'remove_state') def test_disable_mlock_changed(self, remove_state): handlers.disable_mlock_changed()