From 958cf65b0f744ddacee2c2d1173b9a9be722661b Mon Sep 17 00:00:00 2001 From: sousaedu Date: Wed, 20 Jan 2021 16:14:58 +0000 Subject: [PATCH] Adding MariaDB charm Change-Id: I7b3290ca9d9fdb0c3b9521f8d12c4ba76ddcbbcb Signed-off-by: sousaedu --- installers/charm/mariadb-k8s/.gitignore | 24 ++ installers/charm/mariadb-k8s/.yamllint.yaml | 33 ++ installers/charm/mariadb-k8s/README.md | 164 +++++++++ installers/charm/mariadb-k8s/actions.yaml | 42 +++ installers/charm/mariadb-k8s/actions/backup | 30 ++ .../charm/mariadb-k8s/actions/remove-backup | 25 ++ installers/charm/mariadb-k8s/actions/restore | 26 ++ installers/charm/mariadb-k8s/config.yaml | 66 ++++ installers/charm/mariadb-k8s/icon.svg | 335 ++++++++++++++++++ installers/charm/mariadb-k8s/layer.yaml | 29 ++ installers/charm/mariadb-k8s/metadata.yaml | 45 +++ .../charm/mariadb-k8s/reactive/mariadb.py | 141 ++++++++ .../mariadb-k8s/reactive/spec_template.yaml | 51 +++ .../reactive/spec_template_ha.yaml | 97 +++++ .../charm/mariadb-k8s/test-requirements.txt | 23 ++ .../mariadb-k8s/tests/basic_deployment.py | 136 +++++++ .../mariadb-k8s/tests/bundles/mariadb-ha.yaml | 39 ++ .../mariadb-k8s/tests/bundles/mariadb.yaml | 38 ++ installers/charm/mariadb-k8s/tests/tests.yaml | 28 ++ installers/charm/mariadb-k8s/tox.ini | 84 +++++ 20 files changed, 1456 insertions(+) create mode 100644 installers/charm/mariadb-k8s/.gitignore create mode 100644 installers/charm/mariadb-k8s/.yamllint.yaml create mode 100755 installers/charm/mariadb-k8s/README.md create mode 100644 installers/charm/mariadb-k8s/actions.yaml create mode 100755 installers/charm/mariadb-k8s/actions/backup create mode 100755 installers/charm/mariadb-k8s/actions/remove-backup create mode 100755 installers/charm/mariadb-k8s/actions/restore create mode 100755 installers/charm/mariadb-k8s/config.yaml create mode 100644 installers/charm/mariadb-k8s/icon.svg create mode 100644 installers/charm/mariadb-k8s/layer.yaml create mode 100755 installers/charm/mariadb-k8s/metadata.yaml create mode 100644 installers/charm/mariadb-k8s/reactive/mariadb.py create mode 100644 installers/charm/mariadb-k8s/reactive/spec_template.yaml create mode 100644 installers/charm/mariadb-k8s/reactive/spec_template_ha.yaml create mode 100644 installers/charm/mariadb-k8s/test-requirements.txt create mode 100644 installers/charm/mariadb-k8s/tests/basic_deployment.py create mode 100644 installers/charm/mariadb-k8s/tests/bundles/mariadb-ha.yaml create mode 100644 installers/charm/mariadb-k8s/tests/bundles/mariadb.yaml create mode 100644 installers/charm/mariadb-k8s/tests/tests.yaml create mode 100644 installers/charm/mariadb-k8s/tox.ini diff --git a/installers/charm/mariadb-k8s/.gitignore b/installers/charm/mariadb-k8s/.gitignore new file mode 100644 index 00000000..712eb963 --- /dev/null +++ b/installers/charm/mariadb-k8s/.gitignore @@ -0,0 +1,24 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +release/ +__pycache__ +.tox diff --git a/installers/charm/mariadb-k8s/.yamllint.yaml b/installers/charm/mariadb-k8s/.yamllint.yaml new file mode 100644 index 00000000..567eb5fe --- /dev/null +++ b/installers/charm/mariadb-k8s/.yamllint.yaml @@ -0,0 +1,33 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +--- + +extends: default + +yaml-files: + - '*.yaml' + - '*.yml' + - '.yamllint' +ignore: | + reactive/ + .tox + release/ diff --git a/installers/charm/mariadb-k8s/README.md b/installers/charm/mariadb-k8s/README.md new file mode 100755 index 00000000..a427fd4e --- /dev/null +++ b/installers/charm/mariadb-k8s/README.md @@ -0,0 +1,164 @@ + + +# Overview + +mysql for Kubernetes + +# Usage + +You must specify key configuration attributes when deploying, +or else arbitary defaults will be used. The attributes which +should be set are: +- user +- password +- database +- root_password + +eg + +$ juju deploy mysql \ +    --config user=fred \ +    --config password=secret \ +    --config database=test \ +    --config root_password=admin + +These values may also be in a config.yaml file, eg + +$ juju deploy mysql --config config.yaml + + +## Actions + +### Backup + +Execute the following steps to do a backup. + +```bash +$ juju run-action mariadb-k8s/0 backup --wait +unit-mariadb-k8s-0: + UnitId: mariadb-k8s/0 + id: "1" + results: + copy: + cmd: kubectl cp zaza-9769f2bf245e/mariadb-k8s-0:/var/lib/mysql/backup.sql.gz + backup.sql.gz + restore: + cmd: kubectl cp backup.sql.gz zaza-9769f2bf245e/mariadb-k8s-0:/var/lib/mysql/backup.sql.gz + juju: juju run-action mariadb-k8s/0 restore --wait + status: completed + timing: + completed: 2020-02-27 14:16:09 +0000 UTC + enqueued: 2020-02-27 14:16:08 +0000 UTC + started: 2020-02-27 14:16:09 +0000 UTC +$ kubectl cp zaza-9769f2bf245e/mariadb-k8s-0:/var/lib/mysql/backup.sql.gz backup.sql.gz +``` + +> Additional note: You can add `--string-args target=PRIMARY|SECONDARY` if you want this action to be run in a specific mongo unit. If `SECONDARY` is set, but the mongo unit isn't the `SECONDARY`, the action will fail. + +### Restore + +When the backup function is executed, you will see the commands you need to execute for restoring from a backup. + +```bash +$ kubectl cp backup.sql.gz zaza-9769f2bf245e/mariadb-k8s-0:/var/lib/mysql/backup.sql.gz +$ juju run-action mariadb-k8s/0 restore --wait +unit-mariadb-k8s-0: + UnitId: mariadb-k8s/0 + id: "2" + results: + message: Backup restored successfully + status: completed + timing: + completed: 2020-02-27 14:18:17 +0000 UTC + enqueued: 2020-02-27 14:18:07 +0000 UTC + started: 2020-02-27 14:18:11 +0000 UTC +``` + +### Remove backup + +When a backup is made, it is stored in the unit. To easily remove the backup, execute this action: + +```bash +$ juju run-action mariadb-k8s/0 remove-backup --wait +unit-mariadb-k8s-0: + UnitId: mariadb-k8s/0 + id: "3" + results: + Stdout: | + Backup successfully removed! + status: completed + timing: + completed: 2020-02-27 14:18:41 +0000 UTC + enqueued: 2020-02-27 14:18:36 +0000 UTC + started: 2020-02-27 14:18:41 +0000 UTC +``` + +## Backup remotely + +If we want to perform a backup remotely, follow the next steps: + +```bash +$ sudo apt install mariadb-client-10.1 -y +$ juju status mariadb-k8s +Model Controller Cloud/Region Version SLA Timestamp +zaza-9769f2bf245e microk8s-localhost microk8s/localhost 2.7.2 unsupported 15:20:42+01:00 + +App Version Status Scale Charm Store Rev OS Address Notes +mariadb-k8s rocks.canonical... active 2 mariadb-k8s local 0 kubernetes 10.152.183.109 + +Unit Workload Agent Address Ports Message +mariadb-k8s/0* active idle 10.1.31.185 3306/TCP,4444/TCP,4567/TCP,4568/TCP ready +mariadb-k8s/1 active idle 10.1.31.186 3306/TCP,4444/TCP,4567/TCP,4568/TCP ready +$ mysqldump -uroot -posm4u --single-transaction \ + --databases database \ + --host 10.152.183.109 \ + --port 3306 | gzip > backup.sql.gz +$ gunzip -c backup.sql.gz | mysql -uroot -posm4u --host 10.152.183.109 --port 3306 +``` + +> Note: The remote backups should be done for each database. If `--all-databases` is step, when restoring from a database, you will see this error: `ERROR 1556 (HY000) at line 825: You can't use locks with log tables` + +## Testing + +The tests of this charm are done using tox and Zaza. + +### Prepare environment + +The machine in which the tests are run needs access to a juju k8s controller. The easiest way to approach this is by executing the following commands: + +```bash +sudo apt install tox -y +sudo snap install microk8s --classic +sudo snap install juju + +microk8s.status --wait-ready +microk8s.enable storage dns + +juju bootstrap microk8s k8s-cloud +``` + +### Test charm with Tox + +```bash +tox -e black # Check syntax +tox -e build # Build the charm +tox -e func # Test charm +``` diff --git a/installers/charm/mariadb-k8s/actions.yaml b/installers/charm/mariadb-k8s/actions.yaml new file mode 100644 index 00000000..0f11a292 --- /dev/null +++ b/installers/charm/mariadb-k8s/actions.yaml @@ -0,0 +1,42 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +backup: + description: "Do a mongodb backup" + params: + path: + description: "Path for the backup inside the unit" + type: string + default: "/var/lib/mysql" +restore: + description: "Restore from a MongoDB Backup" + params: + path: + description: "Path for the backup inside the unit" + type: string + default: "/var/lib/mysql" +remove-backup: + description: "Remove backup from unit" + params: + path: + description: "Path for the backup inside the unit" + type: string + default: "/var/lib/mysql" diff --git a/installers/charm/mariadb-k8s/actions/backup b/installers/charm/mariadb-k8s/actions/backup new file mode 100755 index 00000000..7bfb5e4c --- /dev/null +++ b/installers/charm/mariadb-k8s/actions/backup @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +DB_BACKUP_PATH=`action-get path` +mkdir -p $DB_BACKUP_PATH +ROOT_PASSWORD=`config-get root_password` +mysqldump -u root -p$ROOT_PASSWORD --single-transaction --all-databases | gzip > $DB_BACKUP_PATH/backup.sql.gz || action-fail "Backup failed" +action-set copy.cmd="kubectl cp $JUJU_MODEL_NAME/$HOSTNAME:$DB_BACKUP_PATH/backup.sql.gz backup.sql.gz" +action-set restore.cmd="kubectl cp backup.sql.gz $JUJU_MODEL_NAME/$HOSTNAME:$DB_BACKUP_PATH/backup.sql.gz" +action-set restore.juju="juju run-action $JUJU_UNIT_NAME restore --wait" + diff --git a/installers/charm/mariadb-k8s/actions/remove-backup b/installers/charm/mariadb-k8s/actions/remove-backup new file mode 100755 index 00000000..f3043337 --- /dev/null +++ b/installers/charm/mariadb-k8s/actions/remove-backup @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +DB_BACKUP_PATH=`action-get path` +rm $DB_BACKUP_PATH/backup.sql.gz || exit +echo Backup successfully removed! diff --git a/installers/charm/mariadb-k8s/actions/restore b/installers/charm/mariadb-k8s/actions/restore new file mode 100755 index 00000000..768e68e1 --- /dev/null +++ b/installers/charm/mariadb-k8s/actions/restore @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +DB_BACKUP_PATH=`action-get path` +ROOT_PASSWORD=`config-get root_password` +gunzip -c $DB_BACKUP_PATH/backup.sql.gz | mysql -uroot -p$ROOT_PASSWORD || action-fail "Restore failed" +action-set message="Backup restored successfully" \ No newline at end of file diff --git a/installers/charm/mariadb-k8s/config.yaml b/installers/charm/mariadb-k8s/config.yaml new file mode 100755 index 00000000..8a606a4c --- /dev/null +++ b/installers/charm/mariadb-k8s/config.yaml @@ -0,0 +1,66 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +options: + user: + type: string + description: 'The database user name.' + default: 'mysql' + password: + type: string + description: 'The database user password.' + default: 'password' + database: + type: string + description: 'The database name.' + default: 'database' + root_password: + type: string + description: 'The database root password.' + default: 'root' + mysql_port: + type: string + description: 'The mysql port' + default: '3306' + query-cache-type: + default: "OFF" + type: string + description: "Query cache is usually a good idea, \ + but can hurt concurrency. \ + Valid values are \"OFF\", \"ON\", or \"DEMAND\"." + query-cache-size: + default: !!int "0" + type: int + description: "Override the computed version from dataset-size. \ + Still works if query-cache-type is \"OFF\" since sessions \ + can override the cache type setting on their own." + ha-mode: + type: boolean + description: Indicates if the charm should have the capabilities to scale + default: false + image: + type: string + description: OCI image + default: rocks.canonical.com:443/mariadb/server:10.3 + ha-image: + type: string + description: OCI image + default: rocks.canonical.com:443/canonicalosm/galera-mysql:latest diff --git a/installers/charm/mariadb-k8s/icon.svg b/installers/charm/mariadb-k8s/icon.svg new file mode 100644 index 00000000..286fa17f --- /dev/null +++ b/installers/charm/mariadb-k8s/icon.svg @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/installers/charm/mariadb-k8s/layer.yaml b/installers/charm/mariadb-k8s/layer.yaml new file mode 100644 index 00000000..f9b5dd94 --- /dev/null +++ b/installers/charm/mariadb-k8s/layer.yaml @@ -0,0 +1,29 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +includes: + - "layer:caas-base" + - 'layer:status' + - 'layer:leadership' + - "layer:osm-common" + - 'interface:juju-relation-mysql' + +repo: https://github.com/wallyworld/caas.git diff --git a/installers/charm/mariadb-k8s/metadata.yaml b/installers/charm/mariadb-k8s/metadata.yaml new file mode 100755 index 00000000..1b263a46 --- /dev/null +++ b/installers/charm/mariadb-k8s/metadata.yaml @@ -0,0 +1,45 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +name: mariadb-k8s +summary: MySQL is a fast, stable and multi-user, multi-threaded SQL database +maintainers: + - Juju Developers +description: | + MySQL is a fast, stable and true multi-user, multi-threaded SQL database + server. SQL (Structured Query Language) is the most popular database query + language in the world. The main goals of MySQL are speed, robustness and + ease of use. +tags: + - database + - openstack +provides: + mysql: + interface: mysql +series: + - kubernetes +storage: + database: + type: filesystem + location: /var/lib/mysql +deployment: + type: stateful + service: cluster diff --git a/installers/charm/mariadb-k8s/reactive/mariadb.py b/installers/charm/mariadb-k8s/reactive/mariadb.py new file mode 100644 index 00000000..4eedcfbc --- /dev/null +++ b/installers/charm/mariadb-k8s/reactive/mariadb.py @@ -0,0 +1,141 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +from charms.layer.caas_base import pod_spec_set +from charms.reactive import when, when_not, hook +from charms.reactive import endpoint_from_flag +from charms.reactive.flags import set_flag, get_state, clear_flag + +from charmhelpers.core.hookenv import ( + log, + metadata, + config, + application_name, +) +from charms import layer +from charms.osm.k8s import is_pod_up, get_service_ip + + +@hook("upgrade-charm") +@when("leadership.is_leader") +def upgrade(): + clear_flag("mariadb-k8s.configured") + + +@when("config.changed") +@when("leadership.is_leader") +def restart(): + clear_flag("mariadb-k8s.configured") + + +@when_not("mariadb-k8s.configured") +@when("leadership.is_leader") +def configure(): + layer.status.maintenance("Configuring mariadb-k8s container") + + spec = make_pod_spec() + log("set pod spec:\n{}".format(spec)) + pod_spec_set(spec) + + set_flag("mariadb-k8s.configured") + + +@when("mariadb-k8s.configured") +def set_mariadb_active(): + layer.status.active("ready") + + +@when_not("leadership.is_leader") +def non_leaders_active(): + layer.status.active("ready") + + +@when("mariadb-k8s.configured", "mysql.database.requested") +def provide_database(): + mysql = endpoint_from_flag("mysql.database.requested") + + if not is_pod_up("mysql"): + log("The pod is not ready.") + return + + for request, application in mysql.database_requests().items(): + try: + + log("request -> {0} for app -> {1}".format(request, application)) + user = get_state("user") + password = get_state("password") + database_name = get_state("database") + root_password = get_state("root_password") + + log("db params: {0}:{1}@{2}".format(user, password, database_name)) + + service_ip = get_service_ip("mysql") + if service_ip: + mysql.provide_database( + request_id=request, + host=service_ip, + port=3306, + database_name=database_name, + user=user, + password=password, + root_password=root_password, + ) + mysql.mark_complete() + except Exception as e: + log("Exception while providing database: {}".format(e)) + + +def make_pod_spec(): + """Make pod specification for Kubernetes + + Returns: + pod_spec: Pod specification for Kubernetes + """ + if config().get("ha-mode"): + with open("reactive/spec_template_ha.yaml") as spec_file: + pod_spec_template = spec_file.read() + image = config().get("ha-image") + else: + with open("reactive/spec_template.yaml") as spec_file: + pod_spec_template = spec_file.read() + image = config().get("image") + + md = metadata() + cfg = config() + + user = cfg.get("user") + password = cfg.get("password") + database = cfg.get("database") + root_password = cfg.get("root_password") + app_name = application_name() + + set_flag("user", user) + set_flag("password", password) + set_flag("database", database) + set_flag("root_password", root_password) + + data = { + "name": md.get("name"), + "docker_image": image, + "application_name": app_name, + } + data.update(cfg) + return pod_spec_template % data diff --git a/installers/charm/mariadb-k8s/reactive/spec_template.yaml b/installers/charm/mariadb-k8s/reactive/spec_template.yaml new file mode 100644 index 00000000..0a1faccb --- /dev/null +++ b/installers/charm/mariadb-k8s/reactive/spec_template.yaml @@ -0,0 +1,51 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +version: 2 +containers: + - name: %(name)s + image: %(docker_image)s + ports: + - containerPort: %(mysql_port)s + protocol: TCP + name: main + config: + MARIADB_ROOT_PASSWORD: %(root_password)s + MARIADB_USER: %(user)s + MARIADB_PASSWORD: %(password)s + MARIADB_DATABASE: %(database)s + kubernetes: + readinessProbe: + tcpSocket: + port: %(mysql_port)s + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + livenessProbe: + tcpSocket: + port: %(mysql_port)s + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 diff --git a/installers/charm/mariadb-k8s/reactive/spec_template_ha.yaml b/installers/charm/mariadb-k8s/reactive/spec_template_ha.yaml new file mode 100644 index 00000000..f5ebf20a --- /dev/null +++ b/installers/charm/mariadb-k8s/reactive/spec_template_ha.yaml @@ -0,0 +1,97 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +version: 2 +service: + scalePolicy: serial + annotations: + service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" +containers: + - name: %(name)s + image: %(docker_image)s + kubernetes: + readinessProbe: + tcpSocket: + port: %(mysql_port)s + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + livenessProbe: + exec: + command: ["bash", "-c", "mysql -uroot -p\"${MYSQL_ROOT_PASSWORD}\" -e 'show databases;'"] + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + ports: + - containerPort: %(mysql_port)s + protocol: TCP + name: main + - containerPort: 4444 + name: sst + - containerPort: 4567 + name: replication + - containerPort: 4568 + name: ist + config: + MYSQL_ROOT_PASSWORD: %(root_password)s + APPLICATION_NAME: %(application_name)s + MYSQL_USER: %(user)s + MYSQL_PASSWORD: %(password)s + MYSQL_DATABASE: %(database)s + files: + - name: configurations + mountPath: /etc/mysqlconfiguration + files: + galera.cnf: | + [galera] + user = mysql + bind-address = 0.0.0.0 + + default_storage_engine = InnoDB + binlog_format = ROW + innodb_autoinc_lock_mode = 2 + innodb_flush_log_at_trx_commit = 0 + query_cache_size = 0 + host_cache_size = 0 + query_cache_type = 0 + + # MariaDB Galera settings + wsrep_on=ON + wsrep_provider=/usr/lib/galera/libgalera_smm.so + wsrep_sst_method=rsync + + # Cluster settings (automatically updated) + wsrep_cluster_address=gcomm:// + wsrep_cluster_name=vimdb_cluser + wsrep_node_address=127.0.0.1 + mariadb.cnf: | + [client] + default-character-set = utf8 + [mysqld] + character-set-server = utf8 + collation-server = utf8_general_ci + plugin_load_add = feedbackx# + # InnoDB tuning + innodb_log_file_size = 50M diff --git a/installers/charm/mariadb-k8s/test-requirements.txt b/installers/charm/mariadb-k8s/test-requirements.txt new file mode 100644 index 00000000..04f2d768 --- /dev/null +++ b/installers/charm/mariadb-k8s/test-requirements.txt @@ -0,0 +1,23 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +git+https://github.com/davigar15/zaza.git#egg=zaza +mysql.connector \ No newline at end of file diff --git a/installers/charm/mariadb-k8s/tests/basic_deployment.py b/installers/charm/mariadb-k8s/tests/basic_deployment.py new file mode 100644 index 00000000..fd6520fe --- /dev/null +++ b/installers/charm/mariadb-k8s/tests/basic_deployment.py @@ -0,0 +1,136 @@ +#!/usr/bin/python3 +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +import unittest +import zaza.model as model + +import mysql.connector as mysql + +# from mysql.connector import errorcode + +APPLICATION_NAME = "mariadb-k8s" +UNIT_NAME = "mariadb-k8s/0" +ROOT_USER = "root" +ROOT_PASSWORD = "osm4u" +USER = "mano" +PASSWORD = "manopw" +ACTION_SUCCESS_STATUS = "completed" + + +def create_database(cnx, database_name): + try: + if not database_exists(cnx, database_name): + cursor = cnx.cursor() + cursor.execute( + "CREATE DATABASE {} DEFAULT CHARACTER SET 'utf8'".format(database_name) + ) + return database_exists(cnx, database_name) + else: + return True + except mysql.Error as err: + print("Failed creating database {}: {}".format(database_name, err)) + + +def delete_database(cnx, database_name): + try: + if database_exists(cnx, database_name): + cursor = cnx.cursor() + cursor.execute("DROP DATABASE {}".format(database_name)) + return not database_exists(cnx, database_name) + else: + return True + except mysql.Error as err: + print("Failed deleting database {}: {}".format(database_name, err)) + + +def database_exists(cnx, database_name): + try: + cursor = cnx.cursor() + cursor.execute("SHOW DATABASES") + databases = cursor.fetchall() + exists = False + for database in databases: + if database[0] == database_name: + exists = True + cursor.close() + return exists + except mysql.Error as err: + print("Failed deleting database {}: {}".format(database_name, err)) + return False + + +class BasicDeployment(unittest.TestCase): + def setUp(self): + super().setUp() + self.ip = model.get_status().applications[APPLICATION_NAME]["public-address"] + try: + self.cnx = mysql.connect( + user=ROOT_USER, password=ROOT_PASSWORD, host=self.ip + ) + except mysql.Error as err: + print("Couldn't connect to mariadb-k8s : {}".format(err)) + + def tearDown(self): + super().tearDown() + self.cnx.close() + + def test_mariadb_connection_root(self): + pass + + def test_mariadb_connection_user(self): + try: + cnx = mysql.connect(user=USER, password=PASSWORD, host=self.ip) + cnx.close() + except mysql.Error as err: + print("Couldn't connect to mariadb-k8s with user creds: {}".format(err)) + + def test_mariadb_create_database(self): + created = create_database(self.cnx, "test_database") + self.failIf(not created) + + def test_mariadb_backup_action(self, db_name="test_backup"): + created = create_database(self.cnx, db_name) + self.failIf(not created) + try: + action = model.run_action(UNIT_NAME, "backup", raise_on_failure=True) + self.assertEqual(action.status, ACTION_SUCCESS_STATUS) + except model.ActionFailed as err: + print("Action failed: {}".format(err)) + + def test_mariadb_remove_backup_action(self): + self.test_mariadb_backup_action(db_name="test_remove_backup") + try: + action = model.run_action(UNIT_NAME, "remove-backup", raise_on_failure=True) + self.assertEqual(action.status, ACTION_SUCCESS_STATUS) + except model.ActionFailed as err: + print("Action failed: {}".format(err)) + + def test_mariadb_restore_action(self): + self.test_mariadb_backup_action(db_name="test_restore") + deleted = delete_database(self.cnx, "test_restore") + self.failIf(not deleted) + try: + action = model.run_action(UNIT_NAME, "restore", raise_on_failure=True) + self.assertEqual(action.status, "completed") + self.assertTrue(database_exists(self.cnx, "test_restore")) + except model.ActionFailed as err: + print("Action failed: {}".format(err)) diff --git a/installers/charm/mariadb-k8s/tests/bundles/mariadb-ha.yaml b/installers/charm/mariadb-k8s/tests/bundles/mariadb-ha.yaml new file mode 100644 index 00000000..7692bd53 --- /dev/null +++ b/installers/charm/mariadb-k8s/tests/bundles/mariadb-ha.yaml @@ -0,0 +1,39 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +bundle: kubernetes +applications: + mariadb-k8s: + charm: '../../release/' + scale: 2 + options: + password: manopw + root_password: osm4u + user: mano + database: database + mysql_port: "3306" + query-cache-type: "OFF" + query-cache-size: 0 + ha-mode: true + image: 'rocks.canonical.com:443/canonicalosm/galera-mysql:latest' + series: kubernetes + storage: + database: 50M diff --git a/installers/charm/mariadb-k8s/tests/bundles/mariadb.yaml b/installers/charm/mariadb-k8s/tests/bundles/mariadb.yaml new file mode 100644 index 00000000..e3e3aa31 --- /dev/null +++ b/installers/charm/mariadb-k8s/tests/bundles/mariadb.yaml @@ -0,0 +1,38 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +bundle: kubernetes +applications: + mariadb-k8s: + charm: '../../release/' + scale: 1 + options: + password: manopw + root_password: osm4u + user: mano + database: database + mysql_port: "3306" + query-cache-type: "OFF" + query-cache-size: 0 + ha-mode: false + series: kubernetes + storage: + database: 50M diff --git a/installers/charm/mariadb-k8s/tests/tests.yaml b/installers/charm/mariadb-k8s/tests/tests.yaml new file mode 100644 index 00000000..df2b59ce --- /dev/null +++ b/installers/charm/mariadb-k8s/tests/tests.yaml @@ -0,0 +1,28 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +gate_bundles: + - mariadb + - mariadb-ha +smoke_bundles: + - mariadb +tests: + - tests.basic_deployment.BasicDeployment diff --git a/installers/charm/mariadb-k8s/tox.ini b/installers/charm/mariadb-k8s/tox.ini new file mode 100644 index 00000000..28d60be9 --- /dev/null +++ b/installers/charm/mariadb-k8s/tox.ini @@ -0,0 +1,84 @@ +# Copyright 2021 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +## + +[tox] +envlist = pep8 +skipsdist = True + +[testenv] +setenv = VIRTUAL_ENV={envdir} + PYTHONHASHSEED=0 +whitelist_externals = juju +passenv = HOME TERM CS_API_* OS_* AMULET_* +deps = -r{toxinidir}/test-requirements.txt +install_command = + pip install {opts} {packages} + +[testenv:build] +basepython = python3 +passenv=HTTP_PROXY HTTPS_PROXY NO_PROXY +setenv = CHARM_LAYERS_DIR = /tmp + CHARM_INTERFACES_DIR = /tmp/canonical-osm/charms/interfaces/ +whitelist_externals = git + charm + rm + mv +commands = + rm -rf /tmp/canonical-osm /tmp/osm-common + rm -rf release + git clone https://git.launchpad.net/canonical-osm /tmp/canonical-osm + git clone https://git.launchpad.net/charm-osm-common /tmp/osm-common + charm build . --build-dir /tmp + mv /tmp/mariadb-k8s/ release/ + +[testenv:black] +basepython = python3 +deps = + black + yamllint + flake8 +commands = + black --check --diff . + yamllint . + flake8 reactive/ --max-line-length=88 + flake8 tests/ --max-line-length=88 + +[testenv:pep8] +basepython = python3 +deps=charm-tools +commands = charm-proof + +[testenv:func-noop] +basepython = python3 +commands = + true + +[testenv:func] +basepython = python3 +commands = functest-run-suite + + +[testenv:func-smoke] +basepython = python3 +commands = functest-run-suite --keep-model --smoke + +[testenv:venv] +commands = {posargs} -- 2.25.1