Upstream charm

Bring charm into alignment with other OpenStack charms.
Updates to requirements, tox, README and zuul.yaml.

Change-Id: I8a30200a2047146f94af0b45198c07d82f04a1fa
This commit is contained in:
David Ames 2019-10-16 14:06:58 -07:00
parent c1fbc3c86a
commit 1ad5a1a78e
13 changed files with 158 additions and 38 deletions

4
.gitreview Normal file
View File

@ -0,0 +1,4 @@
[gerrit]
host=review.opendev.org
port=29418
project=openstack/charm-mysql-innodb-cluster.git

5
.zuul.yaml Normal file
View File

@ -0,0 +1,5 @@
- project:
templates:
- python35-charm-jobs
- openstack-python3-train-jobs
- openstack-cover-jobs

View File

@ -1,6 +1,7 @@
# This file is managed centrally. If you find the need to modify this as a # This file is managed centrally by release-tools and should not be modified
# one-off, please don't. Intead, consult #openstack-charms and ask about # within individual charm repos. See the 'global' dir contents for available
# requirements management in charms via bot-control. Thank you. # choices of *requirements.txt files for OpenStack Charms:
# https://github.com/openstack-charmers/release-tools
# #
# Build requirements # Build requirements
charm-tools>=2.4.4 charm-tools>=2.4.4

View File

@ -4,7 +4,7 @@ This charm is developed as part of the OpenStack Charms project, and as such you
should refer to the [OpenStack Charm Development Guide](https://github.com/openstack/charm-guide) for details on how should refer to the [OpenStack Charm Development Guide](https://github.com/openstack/charm-guide) for details on how
to contribute to this charm. to contribute to this charm.
You can find its source code here: <https://github.com/openstack-charmers/charm-mysql-innodb-cluster>. You can find its source code here: <https://opendev.org/openstack/charm-mysql-innodb-cluster.git>.
# To Do # To Do

68
src/README.md Normal file
View File

@ -0,0 +1,68 @@
# Overview
This charm provides a MySQL 8 InnoDB clustered database.
Ubuntu 19.10 or above is required.
# Usage
The charm is intended for deploying a cluster and therefore does not deploy on a single unit.
## Cluster deployment
```
juju deploy -n 3 mysql-innodb-cluster
```
The charm is designed to be used with the
[db-router relation](https://github.com/openstack-charmers/charm-interface-mysql-router)
in conjunction with the [MySQL Router charm](https://github.com/openstack-charmers/charm-mysql-router):
```
juju add-relation mysql-innodb-cluster:db-router msyql-router:db-router
```
The charm can be related to existing charms that use the [shared-db relation](https://github.com/openstack/charm-interface-mysql-shared).
However, this relation should be considered deprecated:
```
juju add-relation mysql-innodb-cluster:shared-db keystone:shared-db
```
## Scale out Usage
Nodes can be added to the cluster as Read Only nodes:
```
juju add-unit mysql-innodb-cluster
```
## Known Limitations and Issues
> **Warning**: This charm is in preview state.
The charm is under active development and is not yet production ready. Its
current intended use is for validation of MySQL 8 InnoDB cluster for use with
OpenStack.
# Configuration
The name of the cluster can be customized at deploy time:
```
juju deploy -n 3 mysql-innodb-cluster --config cluster-name myCluster
```
# Contact Information
OpenStack Charmers <openstack-charmers@lists.ubuntu.com>
## Upstream MySQL
- [Upstream documentation](https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-userguide.html)
# Bugs
Please report bugs on [Launchpad](https://bugs.launchpad.net/charm-mysql-innodb-cluster/+filebug).
For general questions please refer to the OpenStack [Charm Guide](https://docs.openstack.org/charm-guide/latest/).

0
src/files/.gitkeep Normal file
View File

View File

@ -13,7 +13,7 @@ options:
mysql-shell: mysql-shell:
channel: edge channel: edge
devmode: True devmode: True
repo: https://github.com/openstack-charmers/charm-mysql-innodb-cluster repo: https://opendev.org/openstack/charm-mysql-innodb-cluster
config: config:
deletes: deletes:
- verbose - verbose

View File

@ -42,8 +42,10 @@ def non_leader_install():
packages. packages.
""" """
# Wait for leader to set mysql.passwd # Wait for leader to set mysql.passwd
with charm.provide_charm_instance() as instance: instance.install() with charm.provide_charm_instance() as instance:
reactive.set_flag("charm.installed") instance.assess_status() instance.install()
reactive.set_flag("charm.installed")
instance.assess_status()
@reactive.when('charm.installed') @reactive.when('charm.installed')
@ -86,7 +88,7 @@ def send_cluster_connection_info(cluster):
@reactive.when('cluster.available') @reactive.when('cluster.available')
def create_remote_cluster_user(cluster): def create_remote_cluster_user(cluster):
"""Create remote cluster user. """Create remote cluster user.
Create the remote cluster peer user and grant cluster permissions in the Create the remote cluster peer user and grant cluster permissions in the
MySQL DB. MySQL DB.

View File

@ -1,3 +1,8 @@
# zaza # This file is managed centrally by release-tools and should not be modified
# within individual charm repos. See the 'global' dir contents for available
# choices of *requirements.txt files for OpenStack Charms:
# https://github.com/openstack-charmers/release-tools
#
# Functional Test Requirements (let Zaza's dependencies solve all dependencies here!)
git+https://github.com/openstack-charmers/zaza.git#egg=zaza git+https://github.com/openstack-charmers/zaza.git#egg=zaza
git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack

View File

@ -1,12 +1,22 @@
# Source charm (with zaza): ./src/tox.ini
# This file is managed centrally by release-tools and should not be modified
# within individual charm repos. See the 'global' dir contents for available
# choices of tox.ini for OpenStack Charms:
# https://github.com/openstack-charmers/release-tools
[tox] [tox]
envlist = pep8 envlist = pep8
skipsdist = True skipsdist = True
# NOTE: Avoid build/test env pollution by not enabling sitepackages.
sitepackages = False
# NOTE: Avoid false positives by not skipping missing interpreters.
skip_missing_interpreters = False
[testenv] [testenv]
setenv = VIRTUAL_ENV={envdir} setenv = VIRTUAL_ENV={envdir}
PYTHONHASHSEED=0 PYTHONHASHSEED=0
whitelist_externals = juju whitelist_externals = juju
passenv = HOME TERM CS_API_* OS_* AMULET_* passenv = HOME TERM CS_* OS_* TEST_*
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
install_command = install_command =
pip install {opts} {packages} pip install {opts} {packages}
@ -19,7 +29,7 @@ commands = charm-proof
[testenv:func-noop] [testenv:func-noop]
basepython = python3 basepython = python3
commands = commands =
true functest-run-suite --help
[testenv:func] [testenv:func]
basepython = python3 basepython = python3
@ -31,10 +41,10 @@ basepython = python3
commands = commands =
functest-run-suite --keep-model --smoke functest-run-suite --keep-model --smoke
[testenv:func-dev] [testenv:func-target]
basepython = python3 basepython = python3
commands = commands =
functest-run-suite --keep-model --dev functest-run-suite --keep-model --bundle {posargs}
[testenv:venv] [testenv:venv]
commands = {posargs} commands = {posargs}

View File

@ -1,6 +1,7 @@
# This file is managed centrally. If you find the need to modify this as a # This file is managed centrally by release-tools and should not be modified
# one-off, please don't. Intead, consult #openstack-charms and ask about # within individual charm repos. See the 'global' dir contents for available
# requirements management in charms via bot-control. Thank you. # choices of *requirements.txt files for OpenStack Charms:
# https://github.com/openstack-charmers/release-tools
# #
# Lint and unit test requirements # Lint and unit test requirements
flake8>=2.2.4,<=2.4.1 flake8>=2.2.4,<=2.4.1
@ -10,5 +11,13 @@ charms.reactive
mock>=1.2 mock>=1.2
nose>=1.3.7 nose>=1.3.7
coverage>=3.6 coverage>=3.6
tenacity
git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack
#
# Revisit for removal / mock improvement:
netifaces # vault
psycopg2-binary # vault
tenacity # vault
pbr # vault
cryptography # vault, keystone-saml-mellon
lxml # keystone-saml-mellon
hvac # vault, barbican-vault

27
tox.ini
View File

@ -1,18 +1,25 @@
# Source charm: ./tox.ini # Source charm: ./tox.ini
# This file is managed centrally by release-tools and should not be modified # This file is managed centrally by release-tools and should not be modified
# within individual charm repos. # within individual charm repos. See the 'global' dir contents for available
# choices of tox.ini for OpenStack Charms:
# https://github.com/openstack-charmers/release-tools
[tox] [tox]
skipsdist = True skipsdist = True
envlist = pep8,py3 envlist = pep8,py3
# NOTE: Avoid build/test env pollution by not enabling sitepackages.
sitepackages = False
# NOTE: Avoid false positives by not skipping missing interpreters.
skip_missing_interpreters = False
[testenv] [testenv]
setenv = VIRTUAL_ENV={envdir} setenv = VIRTUAL_ENV={envdir}
PYTHONHASHSEED=0 PYTHONHASHSEED=0
TERM=linux TERM=linux
CHARM_LAYER_PATH={toxinidir}/layers LAYER_PATH={toxinidir}/layers
CHARM_INTERFACES_DIR={toxinidir}/interfaces INTERFACE_PATH={toxinidir}/interfaces
JUJU_REPOSITORY={toxinidir}/build JUJU_REPOSITORY={toxinidir}/build
passenv = http_proxy https_proxy OS_* passenv = http_proxy https_proxy INTERFACE_PATH LAYER_PATH JUJU_REPOSITORY
install_command = install_command =
pip install {opts} {packages} pip install {opts} {packages}
deps = deps =
@ -26,22 +33,22 @@ commands =
[testenv:py3] [testenv:py3]
basepython = python3 basepython = python3
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
commands = stestr run {posargs} commands = stestr run --slowest {posargs}
[testenv:py35] [testenv:py35]
basepython = python3.5 basepython = python3.5
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
commands = stestr run {posargs} commands = stestr run --slowest {posargs}
[testenv:py36] [testenv:py36]
basepython = python3.6 basepython = python3.6
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
commands = stestr run {posargs} commands = stestr run --slowest {posargs}
[testenv:py37] [testenv:py37]
basepython = python3.7 basepython = python3.7
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
commands = stestr run {posargs} commands = stestr run --slowest {posargs}
[testenv:pep8] [testenv:pep8]
basepython = python3 basepython = python3
@ -59,7 +66,7 @@ setenv =
PYTHON=coverage run PYTHON=coverage run
commands = commands =
coverage erase coverage erase
stestr run {posargs} stestr run --slowest {posargs}
coverage combine coverage combine
coverage html -d cover coverage html -d cover
coverage xml -o cover/coverage.xml coverage xml -o cover/coverage.xml
@ -82,4 +89,4 @@ commands = {posargs}
[flake8] [flake8]
# E402 ignore necessary for path append before sys module import in actions # E402 ignore necessary for path append before sys module import in actions
ignore = E402 ignore = E402,W504

View File

@ -402,7 +402,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
mock.call("GRANT GRANT OPTION ON *.* TO '{}'@'{}'" mock.call("GRANT GRANT OPTION ON *.* TO '{}'@'{}'"
.format(_user, _addr)), .format(_user, _addr)),
mock.call("flush privileges")] mock.call("flush privileges")]
_helper.execute.assert_has_calls(_calls) _helper.execute.assert_has_calls(
_calls, any_order=True)
# Local # Local
_localhost = "localhost" _localhost = "localhost"
@ -424,7 +425,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
mock.call("GRANT GRANT OPTION ON *.* TO '{}'@'{}'" mock.call("GRANT GRANT OPTION ON *.* TO '{}'@'{}'"
.format(_user, _localhost)), .format(_user, _localhost)),
mock.call("flush privileges")] mock.call("flush privileges")]
_helper.execute.assert_has_calls(_calls) _helper.execute.assert_has_calls(
_calls, any_order=True)
def test_configure_instance(self): def test_configure_instance(self):
_pass = "clusterpass" _pass = "clusterpass"
@ -482,7 +484,7 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
mock.call("leadership.set.cluster-created"), mock.call("leadership.set.cluster-created"),
mock.call("leadership.set.cluster-instance-configured-{}" mock.call("leadership.set.cluster-instance-configured-{}"
.format(_addr))] .format(_addr))]
self.is_flag_set.assert_has_calls(_is_flag_set_calls) self.is_flag_set.assert_has_calls(_is_flag_set_calls, any_order=True)
self.subprocess.check_output.assert_called_once_with( self.subprocess.check_output.assert_called_once_with(
[midbc.mysqlsh_bin, "--no-wizard", "-f", self.filename], [midbc.mysqlsh_bin, "--no-wizard", "-f", self.filename],
stderr=self.stdin) stderr=self.stdin)
@ -490,7 +492,7 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
_leader_set_calls = [ _leader_set_calls = [
mock.call({"cluster-instance-clustered-{}".format(_addr): True}), mock.call({"cluster-instance-clustered-{}".format(_addr): True}),
mock.call({"cluster-created": self.uuid_of_cluster})] mock.call({"cluster-created": self.uuid_of_cluster})]
self.leader_set.assert_has_calls(_leader_set_calls) self.leader_set.assert_has_calls(_leader_set_calls, any_order=True)
def test_add_instance_to_cluster(self): def test_add_instance_to_cluster(self):
_pass = "clusterpass" _pass = "clusterpass"
@ -585,7 +587,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
mock.call(self.nova_unit7_ip, "nova", "nova"), mock.call(self.nova_unit7_ip, "nova", "nova"),
mock.call(self.nova_unit7_ip, "nova_api", "nova"), mock.call(self.nova_unit7_ip, "nova_api", "nova"),
mock.call(self.nova_unit7_ip, "nova_cell0", "nova")] mock.call(self.nova_unit7_ip, "nova_cell0", "nova")]
midbc.configure_db_for_hosts.assert_has_calls(_configure_db_calls) midbc.configure_db_for_hosts.assert_has_calls(
_configure_db_calls, any_order=True)
_set_calls = [ _set_calls = [
mock.call( mock.call(
@ -608,7 +611,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
allowed_units=self._fake_get_allowed_units( allowed_units=self._fake_get_allowed_units(
None, None, self.nova_shared_db.relation_id), None, None, self.nova_shared_db.relation_id),
prefix="novacell0")] prefix="novacell0")]
self.interface.set_db_connection_info.assert_has_calls(_set_calls) self.interface.set_db_connection_info.assert_has_calls(
_set_calls, any_order=True)
def test_create_databases_and_users_db_router(self): def test_create_databases_and_users_db_router(self):
# The test setup is a bit convoluted and requires mimicking reactive, # The test setup is a bit convoluted and requires mimicking reactive,
@ -647,7 +651,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
mock.call(self.kmr_unit7_ip, "mysqlrouteruser"), mock.call(self.kmr_unit7_ip, "mysqlrouteruser"),
mock.call(self.nmr_unit5_ip, "mysqlrouteruser"), mock.call(self.nmr_unit5_ip, "mysqlrouteruser"),
mock.call(self.nmr_unit7_ip, "mysqlrouteruser")] mock.call(self.nmr_unit7_ip, "mysqlrouteruser")]
midbc.configure_db_router.assert_has_calls(_conigure_db_router_calls) midbc.configure_db_router.assert_has_calls(
_conigure_db_router_calls, any_order=True)
_configure_db_calls = [ _configure_db_calls = [
mock.call(self.kmr_unit5_ip, "keystone", "keystone"), mock.call(self.kmr_unit5_ip, "keystone", "keystone"),
@ -658,7 +663,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
mock.call(self.nmr_unit7_ip, "nova", "nova"), mock.call(self.nmr_unit7_ip, "nova", "nova"),
mock.call(self.nmr_unit7_ip, "nova_api", "nova"), mock.call(self.nmr_unit7_ip, "nova_api", "nova"),
mock.call(self.nmr_unit7_ip, "nova_cell0", "nova")] mock.call(self.nmr_unit7_ip, "nova_cell0", "nova")]
midbc.configure_db_for_hosts.assert_has_calls(_configure_db_calls) midbc.configure_db_for_hosts.assert_has_calls(
_configure_db_calls, any_order=True)
_set_calls = [ _set_calls = [
mock.call( mock.call(
@ -692,7 +698,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
allowed_units=" ".join( allowed_units=" ".join(
[x.unit_name for x in self.nmr_db_router.joined_units]), [x.unit_name for x in self.nmr_db_router.joined_units]),
prefix="mysqlrouter")] prefix="mysqlrouter")]
self.interface.set_db_connection_info.assert_has_calls(_set_calls) self.interface.set_db_connection_info.assert_has_calls(
_set_calls, any_order=True)
def test_configure_db_for_hosts(self): def test_configure_db_for_hosts(self):
_db = "db" _db = "db"
@ -722,7 +729,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
self.assertEqual( self.assertEqual(
_pass, _pass,
midbc.configure_db_for_hosts(_json_addrs, _db, _user)) midbc.configure_db_for_hosts(_json_addrs, _db, _user))
_helper.configure_db.assert_has_calls(_calls) _helper.configure_db.assert_has_calls(
_calls, any_order=True)
def test_configure_db_router(self): def test_configure_db_router(self):
_user = "user" _user = "user"
@ -751,7 +759,8 @@ class TestMySQLInnoDBClusterCharm(test_utils.PatchHelper):
self.assertEqual( self.assertEqual(
_pass, _pass,
midbc.configure_db_router(_json_addrs, _user)) midbc.configure_db_router(_json_addrs, _user))
_helper.configure_router.assert_has_calls(_calls) _helper.configure_router.assert_has_calls(
_calls, any_order=True)
def test_states_to_check(self): def test_states_to_check(self):
self.patch_object( self.patch_object(