From aef4259b77168e06aedc8e5a71f83cea946b2167 Mon Sep 17 00:00:00 2001 From: sousaedu Date: Wed, 20 Jan 2021 16:09:48 +0000 Subject: [PATCH] Adding MongoDB charm Change-Id: I23d491617525601587633d8338e09bcb9473f542 Signed-off-by: sousaedu --- installers/charm/mongodb-k8s/.gitignore | 24 ++ installers/charm/mongodb-k8s/.yamllint.yaml | 34 ++ installers/charm/mongodb-k8s/README.md | 175 ++++++++ installers/charm/mongodb-k8s/actions.yaml | 48 +++ installers/charm/mongodb-k8s/actions/backup | 46 ++ .../charm/mongodb-k8s/actions/is-primary | 25 ++ .../charm/mongodb-k8s/actions/remove-backup | 25 ++ installers/charm/mongodb-k8s/actions/restore | 25 ++ installers/charm/mongodb-k8s/config.yaml | 58 +++ installers/charm/mongodb-k8s/icon.svg | 395 ++++++++++++++++++ installers/charm/mongodb-k8s/layer.yaml | 29 ++ installers/charm/mongodb-k8s/metadata.yaml | 41 ++ .../charm/mongodb-k8s/reactive/mongo.py | 128 ++++++ .../mongodb-k8s/reactive/spec_template.yaml | 49 +++ .../reactive/spec_template_ha.yaml | 63 +++ .../charm/mongodb-k8s/test-requirements.txt | 23 + .../mongodb-k8s/tests/basic_deployment.py | 122 ++++++ .../mongodb-k8s/tests/bundles/mongodb-ha.yaml | 32 ++ .../mongodb-k8s/tests/bundles/mongodb.yaml | 29 ++ installers/charm/mongodb-k8s/tests/tests.yaml | 27 ++ installers/charm/mongodb-k8s/tox.ini | 91 ++++ 21 files changed, 1489 insertions(+) create mode 100644 installers/charm/mongodb-k8s/.gitignore create mode 100644 installers/charm/mongodb-k8s/.yamllint.yaml create mode 100755 installers/charm/mongodb-k8s/README.md create mode 100644 installers/charm/mongodb-k8s/actions.yaml create mode 100755 installers/charm/mongodb-k8s/actions/backup create mode 100755 installers/charm/mongodb-k8s/actions/is-primary create mode 100755 installers/charm/mongodb-k8s/actions/remove-backup create mode 100755 installers/charm/mongodb-k8s/actions/restore create mode 100755 installers/charm/mongodb-k8s/config.yaml create mode 100644 installers/charm/mongodb-k8s/icon.svg create mode 100644 installers/charm/mongodb-k8s/layer.yaml create mode 100755 installers/charm/mongodb-k8s/metadata.yaml create mode 100644 installers/charm/mongodb-k8s/reactive/mongo.py create mode 100644 installers/charm/mongodb-k8s/reactive/spec_template.yaml create mode 100644 installers/charm/mongodb-k8s/reactive/spec_template_ha.yaml create mode 100644 installers/charm/mongodb-k8s/test-requirements.txt create mode 100644 installers/charm/mongodb-k8s/tests/basic_deployment.py create mode 100644 installers/charm/mongodb-k8s/tests/bundles/mongodb-ha.yaml create mode 100644 installers/charm/mongodb-k8s/tests/bundles/mongodb.yaml create mode 100644 installers/charm/mongodb-k8s/tests/tests.yaml create mode 100644 installers/charm/mongodb-k8s/tox.ini diff --git a/installers/charm/mongodb-k8s/.gitignore b/installers/charm/mongodb-k8s/.gitignore new file mode 100644 index 00000000..712eb963 --- /dev/null +++ b/installers/charm/mongodb-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/mongodb-k8s/.yamllint.yaml b/installers/charm/mongodb-k8s/.yamllint.yaml new file mode 100644 index 00000000..21b95b5b --- /dev/null +++ b/installers/charm/mongodb-k8s/.yamllint.yaml @@ -0,0 +1,34 @@ +# 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 +rules: + line-length: disable +yaml-files: + - '*.yaml' + - '*.yml' + - '.yamllint' +ignore: | + reactive/ + .tox + release/ diff --git a/installers/charm/mongodb-k8s/README.md b/installers/charm/mongodb-k8s/README.md new file mode 100755 index 00000000..ce976d62 --- /dev/null +++ b/installers/charm/mongodb-k8s/README.md @@ -0,0 +1,175 @@ + + +# Overview + +Mongo for Juju CAAS + +## Actions + +### Backup + +Execute the following steps to do a backup. + +```bash +$ juju run-action mongodb-k8s/0 backup --wait +unit-mongodb-k8s-0: + UnitId: mongodb-k8s/0 + id: "7" + results: + Stderr: "2020-02-26T14:13:56.448+0000\twriting admin.system.version to archive + '/data/backup.archive'\n2020-02-26T14:13:56.451+0000\tdone dumping admin.system.version + (1 document)\n" + copy: + cmd: kubectl cp mongo-ha/mongodb-k8s-0:/data/backup.archive backup.archive + restore: + cmd: kubectl cp backup.archive mongo-ha/mongodb-k8s-0:/data/backup.archive + juju: juju action mongodb-k8s/0 restore --wait + status: completed + timing: + completed: 2020-02-26 14:13:57 +0000 UTC + enqueued: 2020-02-26 14:13:55 +0000 UTC + started: 2020-02-26 14:13:56 +0000 UTC +$ kubectl cp mongo-ha/mongodb-k8s-0:/data/backup.archive backup.archive +``` + +> 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.archive mongo-ha/mongodb-k8s-0:/data/backup.archive +Defaulting container name to mongodb-k8s. +$ juju run-action mongodb-k8s/0 restore --wait +unit-mongodb-k8s-0: + UnitId: mongodb-k8s/0 + id: "8" + results: + Stderr: "2020-02-26T14:17:00.300+0000\tpreparing collections to restore from\n2020-02-26T14:17:00.312+0000\t0 + document(s) restored successfully. 0 document(s) failed to restore.\n" + status: completed + timing: + completed: 2020-02-26 14:17:01 +0000 UTC + enqueued: 2020-02-26 14:16:57 +0000 UTC + started: 2020-02-26 14:17:00 +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 mongodb-k8s/0 remove-backup --wait +unit-mongodb-k8s-0: + UnitId: mongodb-k8s/0 + id: "4" + results: + Stdout: | + Backup successfully removed! + status: completed + timing: + completed: 2020-02-26 16:31:11 +0000 UTC + enqueued: 2020-02-26 16:31:08 +0000 UTC + started: 2020-02-26 16:31:10 +0000 UTC +``` + +### Is primary? + +To check if the unit is primary: + +```bash +$ juju run-action mongodb-k8s/0 is-primary --wait +unit-mongodb-k8s-0: + UnitId: mongodb-k8s/0 + id: "5" + results: + unit: + ip: 10.1.31.92 + primary: "true" + status: completed + timing: + completed: 2020-02-26 16:32:10 +0000 UTC + enqueued: 2020-02-26 16:32:08 +0000 UTC + started: 2020-02-26 16:32:09 +0000 UTC +$ juju run-action mongodb-k8s/1 is-primary --wait +unit-mongodb-k8s-1: + UnitId: mongodb-k8s/1 + id: "6" + results: + unit: + ip: 10.1.31.93 + primary: "false" + status: completed + timing: + completed: 2020-02-26 16:32:34 +0000 UTC + enqueued: 2020-02-26 16:32:32 +0000 UTC + started: 2020-02-26 16:32:33 +0000 UTC +``` + +## Backup remotely + +If we want to perform a backup remotely, follow the next steps: + +```bash +$ sudo apt install mongo-tools-y +$ juju status mongodb-k8s +Model Controller Cloud/Region Version SLA Timestamp +mongo-ha microk8s-localhost microk8s/localhost 2.7.2 unsupported 16:26:02+01:00 + +App Version Status Scale Charm Store Rev OS Address Notes +mongodb-k8s mongo:latest active 2 mongodb-k8s local 0 kubernetes 10.152.183.90 + +Unit Workload Agent Address Ports Message +mongodb-k8s/0* active idle 10.1.31.75 27017/TCP ready +mongodb-k8s/1 active idle 10.1.31.76 27017/TCP ready +$ mongodump --host 10.152.183.90 --port 27017 --gzip --archive=backup.archive --forceTableScan +2020-02-26T16:41:23.777+0100 writing admin.system.version to archive 'backup.archive' +2020-02-26T16:41:23.779+0100 done dumping admin.system.version (1 document) +$ mongorestore --host 10.152.183.90 --port 27017 --gzip --archive=backup.archive +``` + +## 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 dashboard 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/mongodb-k8s/actions.yaml b/installers/charm/mongodb-k8s/actions.yaml new file mode 100644 index 00000000..b8572421 --- /dev/null +++ b/installers/charm/mongodb-k8s/actions.yaml @@ -0,0 +1,48 @@ +# 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: + target: + description: "The unit in which it should be performed the action. (ANY, PRIMARY, SECONDARY)" + type: string + default: "ANY" + path: + description: "Path for the backup inside the unit" + type: string + default: "/data" +restore: + description: "Restore from a MongoDB Backup" + params: + path: + description: "Path for the backup inside the unit" + type: string + default: "/data" +remove-backup: + description: "Remove backup from unit" + params: + path: + description: "Path for the backup inside the unit" + type: string + default: "/data" +is-primary: + description: "Check if the unit is the primary" diff --git a/installers/charm/mongodb-k8s/actions/backup b/installers/charm/mongodb-k8s/actions/backup new file mode 100755 index 00000000..bd51d03b --- /dev/null +++ b/installers/charm/mongodb-k8s/actions/backup @@ -0,0 +1,46 @@ +#!/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 +## + +MASTER=`mongo --quiet --eval "d=db.isMaster(); print( d['ismaster'] );"` + +TARGET=`action-get target` +DB_BACKUP_PATH=`action-get path` + +mkdir -p $DB_BACKUP_PATH + +if [ "$TARGET" == "SECONDARY" ]; then + if [ "$MASTER" == "true" ]; then + action-fail "This action should be run in a Secondary" + exit + fi +elif [ "$TARGET" == "PRIMARY" ]; then + if [ "$MASTER" == "false" ]; then + action-fail "This action should be run in a Primary" + exit + fi +fi + +mongodump --gzip --archive=$DB_BACKUP_PATH/backup.archive +action-set copy.cmd="kubectl cp $JUJU_MODEL_NAME/$HOSTNAME:$DB_BACKUP_PATH/backup.archive backup.archive" +action-set restore.cmd="kubectl cp backup.archive $JUJU_MODEL_NAME/$HOSTNAME:$DB_BACKUP_PATH/backup.archive" +action-set restore.juju="juju run-action $JUJU_UNIT_NAME restore --wait" + diff --git a/installers/charm/mongodb-k8s/actions/is-primary b/installers/charm/mongodb-k8s/actions/is-primary new file mode 100755 index 00000000..2e8477b5 --- /dev/null +++ b/installers/charm/mongodb-k8s/actions/is-primary @@ -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 +## + +MASTER=`mongo --quiet --eval "d=db.isMaster(); print( d['ismaster'] );"` +action-set unit.primary=$MASTER +action-set unit.ip=`network-get mongo --bind-address` \ No newline at end of file diff --git a/installers/charm/mongodb-k8s/actions/remove-backup b/installers/charm/mongodb-k8s/actions/remove-backup new file mode 100755 index 00000000..71918ed6 --- /dev/null +++ b/installers/charm/mongodb-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.archive || exit +echo Backup successfully removed! diff --git a/installers/charm/mongodb-k8s/actions/restore b/installers/charm/mongodb-k8s/actions/restore new file mode 100755 index 00000000..8ce7c3a1 --- /dev/null +++ b/installers/charm/mongodb-k8s/actions/restore @@ -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` +mongorestore --gzip --archive=$DB_BACKUP_PATH/backup.archive + diff --git a/installers/charm/mongodb-k8s/config.yaml b/installers/charm/mongodb-k8s/config.yaml new file mode 100755 index 00000000..74e3fc21 --- /dev/null +++ b/installers/charm/mongodb-k8s/config.yaml @@ -0,0 +1,58 @@ +# 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: + advertised-hostname: + description: MongoDB Hostname + type: string + default: mongodb-k8s + advertised-port: + description: MongoDB port + type: int + default: 27017 + replica-set: + description: Mongo Replica-set name + type: string + default: rs0 + namespace: + description: Kubernetes namespace + type: string + default: osm + service-name: + description: Headless service name + type: string + default: mongodb-k8s-endpoints + cluster-domain: + description: Cluster domain + type: string + default: cluster.local + enable-sidecar: + description: Enable sidecar + type: boolean + default: false + mongodb-image: + type: string + description: OCI image + default: rocks.canonical.com:443/mongo:latest + sidecar-image: + type: string + description: OCI image + default: rocks.canonical.com:443/cvallance/mongo-k8s-sidecar:latest diff --git a/installers/charm/mongodb-k8s/icon.svg b/installers/charm/mongodb-k8s/icon.svg new file mode 100644 index 00000000..811be4f8 --- /dev/null +++ b/installers/charm/mongodb-k8s/icon.svg @@ -0,0 +1,395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/installers/charm/mongodb-k8s/layer.yaml b/installers/charm/mongodb-k8s/layer.yaml new file mode 100644 index 00000000..3ffabb97 --- /dev/null +++ b/installers/charm/mongodb-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:mongodb' + +repo: https://code.launchpad.net/osm-k8s-bundle diff --git a/installers/charm/mongodb-k8s/metadata.yaml b/installers/charm/mongodb-k8s/metadata.yaml new file mode 100755 index 00000000..4e279069 --- /dev/null +++ b/installers/charm/mongodb-k8s/metadata.yaml @@ -0,0 +1,41 @@ +# 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: "mongodb-k8s" +summary: "MongoDB charm for Kubernetes." +maintainers: + - "SolutionsQA " +description: | + A CAAS charm to deploy MongoDB. +tags: + - "application" +series: + - "kubernetes" +provides: + mongo: + interface: mongodb +storage: + database: + type: filesystem + location: /data/db +deployment: + type: stateful + service: cluster diff --git a/installers/charm/mongodb-k8s/reactive/mongo.py b/installers/charm/mongodb-k8s/reactive/mongo.py new file mode 100644 index 00000000..026f5ed0 --- /dev/null +++ b/installers/charm/mongodb-k8s/reactive/mongo.py @@ -0,0 +1,128 @@ +# 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 endpoint_from_flag +from charms.reactive import when, when_not, hook +from charms.reactive.flags import set_flag, clear_flag +from charmhelpers.core.hookenv import log, metadata, config, goal_state +from charms import layer + + +@hook("upgrade-charm") +@when("leadership.is_leader") +def upgrade(): + clear_flag("mongodb-k8s.configured") + + +@when("config.changed") +@when("leadership.is_leader") +def restart(): + clear_flag("mongodb-k8s.configured") + + +@when_not("mongodb-k8s.configured") +@when("leadership.is_leader") +def configure(): + layer.status.maintenance("Configuring MongoDB container") + try: + spec = make_pod_spec() + log("set pod spec:\n{}".format(spec)) + pod_spec_set(spec) + set_flag("mongodb-k8s.configured") + except Exception as e: + layer.status.blocked("k8s spec failed to deploy: {}".format(e)) + + +@when("mongodb-k8s.configured") +def set_mongodb_active(): + layer.status.active("ready") + + +@when_not("leadership.is_leader") +def non_leaders_active(): + layer.status.active("ready") + + +@when("mongodb-k8s.configured", "mongo.joined") +def send_config(): + layer.status.maintenance("Sending mongo configuration") + try: + mongo = endpoint_from_flag("mongo.joined") + if mongo: + cfg = config() + mongo_uri = "mongodb://" + for i, unit in enumerate(goal_state()["units"]): + pod_base_name = unit.split("/")[0] + service_name = cfg.get("service-name") + pod_name = "{}-{}".format(pod_base_name, i) + if i: + mongo_uri += "," + mongo_uri += "{}.{}:{}".format( + pod_name, service_name, get_mongodb_port() + ) + if cfg.get("enable-sidecar"): + mongo_uri += "/?replicaSet={}".format(get_mongodb_replset()) + log("Mongo URI: {}".format(mongo_uri)) + mongo.send_connection_string(mongo_uri) + clear_flag("mongo.joined") + except Exception as e: + log("Exception sending config: {}".format(e)) + clear_flag("mongo.joined") + + +def make_pod_spec(): + """Make pod specification for Kubernetes + + Returns: + pod_spec: Pod specification for Kubernetes + """ + md = metadata() + cfg = config() + + if cfg.get("enable-sidecar"): + with open("reactive/spec_template_ha.yaml") as spec_file: + pod_spec_template = spec_file.read() + else: + with open("reactive/spec_template.yaml") as spec_file: + pod_spec_template = spec_file.read() + + data = { + "name": md.get("name"), + "docker_image": cfg.get("mongodb-image"), + "sc_docker_image": cfg.get("sidecar-image"), + "pod_labels": "juju-app={}".format(cfg.get("advertised-hostname")), + } + + data.update(cfg) + return pod_spec_template % data + + +def get_mongodb_port(): + """Returns MongoDB port""" + cfg = config() + return cfg.get("advertised-port") + + +def get_mongodb_replset(): + """Returns MongoDB port""" + cfg = config() + return cfg.get("replica-set") diff --git a/installers/charm/mongodb-k8s/reactive/spec_template.yaml b/installers/charm/mongodb-k8s/reactive/spec_template.yaml new file mode 100644 index 00000000..035e9fb1 --- /dev/null +++ b/installers/charm/mongodb-k8s/reactive/spec_template.yaml @@ -0,0 +1,49 @@ +# 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 + command: + - mongod + - "--bind_ip" + - "0.0.0.0" + ports: + - containerPort: %(advertised-port)s + protocol: TCP + config: + ALLOW_ANONYMOUS_LOGIN: 'yes' + kubernetes: + readinessProbe: + tcpSocket: + port: %(advertised-port)s + timeoutSeconds: 5 + periodSeconds: 5 + initialDelaySeconds: 10 + livenessProbe: + exec: + command: + - /bin/sh + - -c + - mongo --port %(advertised-port)s --eval "rs.status()" | grep -vq "REMOVED" + initialDelaySeconds: 45 + timeoutSeconds: 5 diff --git a/installers/charm/mongodb-k8s/reactive/spec_template_ha.yaml b/installers/charm/mongodb-k8s/reactive/spec_template_ha.yaml new file mode 100644 index 00000000..60c44d4a --- /dev/null +++ b/installers/charm/mongodb-k8s/reactive/spec_template_ha.yaml @@ -0,0 +1,63 @@ +# 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 +serviceAccount: + rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["list"] +containers: + - name: %(name)s + image: %(docker_image)s + command: + - mongod + - "--replSet" + - %(replica-set)s + - "--bind_ip" + - "0.0.0.0" + ports: + - containerPort: %(advertised-port)s + protocol: TCP + config: + ALLOW_ANONYMOUS_LOGIN: 'yes' + kubernetes: + readinessProbe: + tcpSocket: + port: %(advertised-port)s + timeoutSeconds: 5 + periodSeconds: 5 + initialDelaySeconds: 10 + livenessProbe: + exec: + command: + - /bin/sh + - -c + - mongo --port %(advertised-port)s --eval "rs.status()" | grep -vq "REMOVED" + initialDelaySeconds: 45 + timeoutSeconds: 5 + - name: 'mongodb-sidecar-k8s' + image: %(sc_docker_image)s + config: + KUBERNETES_MONGO_SERVICE_NAME: %(service-name)s + KUBE_NAMESPACE: %(namespace)s + MONGO_SIDECAR_POD_LABELS: %(pod_labels)s + KUBERNETES_CLUSTER_DOMAIN: %(cluster-domain)s \ No newline at end of file diff --git a/installers/charm/mongodb-k8s/test-requirements.txt b/installers/charm/mongodb-k8s/test-requirements.txt new file mode 100644 index 00000000..4aac56da --- /dev/null +++ b/installers/charm/mongodb-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 +pymongo \ No newline at end of file diff --git a/installers/charm/mongodb-k8s/tests/basic_deployment.py b/installers/charm/mongodb-k8s/tests/basic_deployment.py new file mode 100644 index 00000000..3a8e9a35 --- /dev/null +++ b/installers/charm/mongodb-k8s/tests/basic_deployment.py @@ -0,0 +1,122 @@ +#!/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 +from pymongo import MongoClient + + +def get_mongo_uri(): + mongo_uri = "mongodb://" + mongo_units = model.get_status().applications["mongodb-k8s"]["units"] + for i, unit_name in enumerate(mongo_units.keys()): + if i: + mongo_uri += "," + unit_ip = mongo_units[unit_name]["address"] + unit_port = mongo_units[unit_name]["opened-ports"][0].split("/")[0] + mongo_uri += "{}:{}".format(unit_ip, unit_port) + + return mongo_uri + + +class BasicDeployment(unittest.TestCase): + def test_get_mongo_uri(self): + get_mongo_uri() + + def test_mongodb_connection(self): + mongo_uri = get_mongo_uri() + client = MongoClient(mongo_uri) + client.server_info() + + def test_mongodb_create_empty_database_collection(self): + mongo_uri = get_mongo_uri() + client = MongoClient(mongo_uri) + DB_NAME = "test_database" + COLLECTION_NAME = "test_collection" + + db = client[DB_NAME] + _ = client.list_database_names() + + collection = db[COLLECTION_NAME] + _ = db.list_collection_names() + + data = {} + + id = collection.insert_one(data) + + for x in collection.find({"_id": id.inserted_id}): + self.assertEqual(id.inserted_id, x["_id"]) + + def test_mongodb_insert_one(self): + mongo_uri = get_mongo_uri() + client = MongoClient(mongo_uri) + DB_NAME = "test_database" + COLLECTION_NAME = "test_collection" + + db = client[DB_NAME] + _ = client.list_database_names() + + collection = db[COLLECTION_NAME] + _ = db.list_collection_names() + + data = { + "name": "Canonical LTD", + "address": "5th Floor of the Blue Fin Building", + } + + id = collection.insert_one(data) + + for x in collection.find({"_id": id.inserted_id}): + self.assertEqual(id.inserted_id, x["_id"]) + + def test_mongodb_insert_many(self): + mongo_uri = get_mongo_uri() + client = MongoClient(mongo_uri) + DB_NAME = "test_database" + COLLECTION_NAME = "test_collection" + + db = client[DB_NAME] + _ = client.list_database_names() + + collection = db[COLLECTION_NAME] + _ = db.list_collection_names() + + data = [ + {"name": "Amy", "address": "Apple st 652"}, + {"name": "Hannah", "address": "Mountain 21"}, + {"name": "Michael", "address": "Valley 345"}, + {"name": "Sandy", "address": "Ocean blvd 2"}, + {"name": "Betty", "address": "Green Grass 1"}, + {"name": "Richard", "address": "Sky st 331"}, + {"name": "Susan", "address": "One way 98"}, + {"name": "Vicky", "address": "Yellow Garden 2"}, + {"name": "Ben", "address": "Park Lane 38"}, + {"name": "William", "address": "Central st 954"}, + {"name": "Chuck", "address": "Main Road 989"}, + {"name": "Viola", "address": "Sideway 1633"}, + ] + + ids = collection.insert_many(data) + + for id in ids.inserted_ids: + x = collection.find_one({"_id": id}) + self.assertEqual(x["_id"], id) diff --git a/installers/charm/mongodb-k8s/tests/bundles/mongodb-ha.yaml b/installers/charm/mongodb-k8s/tests/bundles/mongodb-ha.yaml new file mode 100644 index 00000000..d08352bd --- /dev/null +++ b/installers/charm/mongodb-k8s/tests/bundles/mongodb-ha.yaml @@ -0,0 +1,32 @@ +# 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: + mongodb-k8s: + charm: '../../release/' + scale: 2 + options: + enable-sidecar: true + namespace: mongo-ha + series: kubernetes + storage: + database: 50M diff --git a/installers/charm/mongodb-k8s/tests/bundles/mongodb.yaml b/installers/charm/mongodb-k8s/tests/bundles/mongodb.yaml new file mode 100644 index 00000000..0f2cb1ab --- /dev/null +++ b/installers/charm/mongodb-k8s/tests/bundles/mongodb.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 +## + +bundle: kubernetes +applications: + mongodb-k8s: + charm: '../../release/' + scale: 1 + series: kubernetes + storage: + database: 50M diff --git a/installers/charm/mongodb-k8s/tests/tests.yaml b/installers/charm/mongodb-k8s/tests/tests.yaml new file mode 100644 index 00000000..f9a56072 --- /dev/null +++ b/installers/charm/mongodb-k8s/tests/tests.yaml @@ -0,0 +1,27 @@ +# 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: + - mongodb +smoke_bundles: + - mongodb +tests: + - tests.basic_deployment.BasicDeployment diff --git a/installers/charm/mongodb-k8s/tox.ini b/installers/charm/mongodb-k8s/tox.ini new file mode 100644 index 00000000..354632fd --- /dev/null +++ b/installers/charm/mongodb-k8s/tox.ini @@ -0,0 +1,91 @@ +# 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 + git clone https://git.launchpad.net/interface-mongodb /tmp/canonical-osm/charms/interfaces/mongodb + charm build . --build-dir /tmp + mv /tmp/mongodb-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 + functest-prepare -m mongo-ha + juju switch mongo-ha + functest-deploy -m mongo-ha -b ./tests/bundles/mongodb-ha.yaml + ; functest-test -m mongo-ha + functest-destroy -m mongo-ha + + +[testenv:func-smoke] +basepython = python3 +commands = functest-run-suite --keep-model --smoke + +[testenv:venv] +commands = {posargs} -- 2.17.1