commit b3ae62ceba1cfb8fb8b719cb0d5f5859cfa88d65 Author: narindergupta Date: Wed Aug 19 06:13:26 2020 -0500 First draft diff --git a/.stestr.conf b/.stestr.conf new file mode 100644 index 0000000..5fcccac --- /dev/null +++ b/.stestr.conf @@ -0,0 +1,3 @@ +[DEFAULT] +test_path=./unit_tests +top_dir=./ diff --git a/.zuul.yaml b/.zuul.yaml new file mode 100644 index 0000000..b3037e9 --- /dev/null +++ b/.zuul.yaml @@ -0,0 +1,5 @@ +- project: + templates: + - python35-charm-jobs + - openstack-python3-ussuri-jobs + - openstack-cover-jobs diff --git a/README.md b/README.md new file mode 100644 index 0000000..d44e306 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Overview + +This is a "source" charm, which is intended to be strictly the top +layer of a built charm. This structure declares that any included +layer assets are not intended to be consumed as a layer from a +functional or design standpoint. + +# Test and Build + +Building, pushing and publishing to the charm store is automated +by CI to ensure consistent flow. Manually building is useful for +development and testing, however. + +``` +tox -e pep8 +tox -e py35 # or py36 +tox -e build +``` + +# Contact Information + +Freenode IRC: #openstack-charms diff --git a/rebuild b/rebuild new file mode 100644 index 0000000..f0cbd7c --- /dev/null +++ b/rebuild @@ -0,0 +1,5 @@ +# This file is used to trigger rebuilds +# when dependencies of the charm change, +# but nothing in the charm needs to. +# simply change the uuid to something new +d9b38a7c-d02c-11ea-a4c2-3fba95671dc4 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5f2fff3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +# 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 +# +# Build requirements +charm-tools>=2.4.4 +# importlib-resources 1.1.0 removed Python 3.5 support +importlib-resources<1.1.0 +simplejson diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..6a9e395 --- /dev/null +++ b/src/README.md @@ -0,0 +1,19 @@ +netapp Storage Backend for Cinder +------------------------------- + +Overview +======== + +This charm provides a netapp storage backend for use with the Cinder +charm. + +To use: + + juju deploy cinder + juju deploy cinder-netapp + juju add-relation cinder-netapp cinder + +Configuration +============= + +See config.yaml for details of configuration options. diff --git a/src/config.yaml b/src/config.yaml new file mode 100644 index 0000000..a54da99 --- /dev/null +++ b/src/config.yaml @@ -0,0 +1 @@ +options: diff --git a/src/layer.yaml b/src/layer.yaml new file mode 100644 index 0000000..2ff600a --- /dev/null +++ b/src/layer.yaml @@ -0,0 +1,12 @@ +includes: ['layer:openstack', 'interface:cinder-backend'] +config: + deletes: + - debug + - verbose + - use-syslog + - use-internal-endpoints + - ssl_ca +options: + basic: + use_venv: True +repo: https://github.com/openstack-charmers/cinder-storage-backend-template diff --git a/src/lib/charm/openstack/cinder_netapp.py b/src/lib/charm/openstack/cinder_netapp.py new file mode 100644 index 0000000..4e58dc5 --- /dev/null +++ b/src/lib/charm/openstack/cinder_netapp.py @@ -0,0 +1,52 @@ +import charms_openstack.charm + +charms_openstack.charm.use_defaults('charm.default-select-release') + + +class CindernetappCharm( + charms_openstack.charm.CinderStoragePluginCharm): + + name = 'cinder_netapp' + release = 'stein' + stateless = True + version_package = 'cinder-common' + packages = [] + # Specify any config that the user *must* set. + mandatory_config = [ + 'netapp_storage_family', 'netapp_storage_protocol', 'netapp_server_hostname', + 'volume-backend-name'] + + def cinder_configuration(self): + service = self.config.get('volume-backend-name') + volumedriver = 'cinder.volume.drivers.netapp.common.NetAppDriver' + driver_options_extension = [] + driver_options_common = [ + ('netapp_storage_family', self.config.get('netapp-storage-family')), + ('netapp_storage_protocol', self.config.get('netapp-storage-protocol')), + ('netapp_vserver', self.config.get('netapp-vserver')), + ('netapp_server_hostname', self.config.get('netapp-server-hostname')), + ('netapp_server_port', self.config.get('netapp-vserver-port')), + ('netapp_login', self.config.get('netapp-login')), + ('netapp_password', self.config.get('netapp-password')), + ('netapp_lun_space_reservation', self.config.get('netapp-lun-space-reservation')), + ('netapp_transport_type', self.config.get('netapp-transport-type')), + ('volume_driver', volumedriver), + ('volume_backend_name', service)] + + if self.config.get('netapp-storage-family') == "eseries": + driver_options_extension = [ + ('netapp_controller_ips', self.config.get('netapp-controller-ips')), + ('netapp_sa_password', self.config.get('netapp-array-password')), + ('netapp_storage_pools', self.config.get('netapp-storage-pools')), + ('use_multipath_for_image_xfer', self.config.get('use-multipath'))] + + return driver_options_common + driver_options_extension + + +class CindernetappCharmRocky(CindernetappCharm): + + # Rocky needs py3 packages. + release = 'rocky' + version_package = 'cinder-common' + packages = [] + diff --git a/src/metadata.yaml b/src/metadata.yaml new file mode 100644 index 0000000..e3fa195 --- /dev/null +++ b/src/metadata.yaml @@ -0,0 +1,24 @@ +name: cinder-netapp +summary: netapp integration for OpenStack Block Storage +maintainer: OpenStack Charmers +description: | + Cinder is the block storage service for the Openstack project. + . + This charm provides a netapp backend for Cinder +tags: + - openstack + - storage + - file-servers + - misc +series: + - xenial + - bionic +subordinate: true +provides: + storage-backend: + interface: cinder-backend + scope: container +requires: + juju-info: + interface: juju-info + scope: container diff --git a/src/reactive/cinder_netapp_handlers.py b/src/reactive/cinder_netapp_handlers.py new file mode 100644 index 0000000..c503fa2 --- /dev/null +++ b/src/reactive/cinder_netapp_handlers.py @@ -0,0 +1,35 @@ +# Copyright 2019 +# +# 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. + +import charms_openstack.charm +import charms.reactive + +# This charm's library contains all of the handler code associated with +# this charm -- we will use the auto-discovery feature of charms.openstack +# to get the definitions for the charm. +import charms_openstack.bus +charms_openstack.bus.discover() + +charms_openstack.charm.use_defaults( + 'charm.installed', + 'update-status', + 'upgrade-charm', + 'storage-backend.connected', +) + + +@charms.reactive.when('config.changed.driver-source') +def reinstall(): + with charms_openstack.charm.provide_charm_instance() as charm: + charm.install() diff --git a/src/test-requirements.txt b/src/test-requirements.txt new file mode 100644 index 0000000..f2912ba --- /dev/null +++ b/src/test-requirements.txt @@ -0,0 +1,3 @@ +# zaza +git+https://github.com/openstack-charmers/zaza.git#egg=zaza +git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack diff --git a/src/tests/bundles/xenial-stein.yaml b/src/tests/bundles/xenial-stein.yaml new file mode 100644 index 0000000..601c666 --- /dev/null +++ b/src/tests/bundles/xenial-stein.yaml @@ -0,0 +1,50 @@ +series: xenial +comment: +- 'machines section to decide order of deployment. database sooner = faster' +machines: + '0': + constraints: mem=3072M + '1': + '2': + '3': +relations: +- - keystone:shared-db + - mysql:shared-db +- - cinder:shared-db + - mysql:shared-db +- - cinder:identity-service + - keystone:identity-service +- - cinder:amqp + - rabbitmq-server:amqp +- - cinder:storage-backend + - cinder-netapp:storage-backend +applications: + mysql: + charm: cs:~openstack-charmers-next/percona-cluster + num_units: 1 + to: + - '0' + keystone: + charm: cs:~openstack-charmers-next/keystone + num_units: 1 + options: + openstack-origin: cloud:xenial-stein + to: + - '1' + cinder: + charm: cs:~openstack-charmers-next/cinder + num_units: 1 + options: + openstack-origin: cloud:xenial-stein + to: + - '2' + cinder-netapp: + series: xenial + charm: cinder-netapp + options: +# Add config options here + rabbitmq-server: + charm: cs:~openstack-charmers-next/rabbitmq-server + num_units: 1 + to: + - '3' diff --git a/src/tests/tests.yaml b/src/tests/tests.yaml new file mode 100644 index 0000000..eceaa01 --- /dev/null +++ b/src/tests/tests.yaml @@ -0,0 +1,9 @@ +charm_name: cinder-netapp +tests: + - tests.tests_cinder_netapp.CindernetappTest +configure: + - zaza.openstack.charm_tests.keystone.setup.add_demo_user +gate_bundles: + - xenial-stein +smoke_bundles: + - xenial-stein diff --git a/src/tests/tests_cinder_netapp.py b/src/tests/tests_cinder_netapp.py new file mode 100644 index 0000000..d96a860 --- /dev/null +++ b/src/tests/tests_cinder_netapp.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +# Copyright 2019 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. + +"""Encapsulate cinder-netapp testing.""" + +import logging +import uuid + +import zaza.model +import zaza.openstack.charm_tests.test_utils as test_utils +import zaza.openstack.utilities.openstack as openstack_utils + + +class CindernetappTest(test_utils.OpenStackBaseTest): + """Encapsulate netapp tests.""" + + @classmethod + def setUpClass(cls): + """Run class setup for running tests.""" + super(CindernetappTest, cls).setUpClass() + cls.keystone_session = openstack_utils.get_overcloud_keystone_session() + cls.model_name = zaza.model.get_juju_model() + cls.cinder_client = openstack_utils.get_cinder_session_client( + cls.keystone_session) + + def test_cinder_config(self): + logging.info('netapp') + expected_contents = { + 'cinder-netapp': { + 'iscsi_helper': ['tgtadm'], + 'volume_dd_blocksize': ['512']}} + + zaza.model.run_on_leader( + 'cinder', + 'sudo cp /etc/cinder/cinder.conf /tmp/', + model_name=self.model_name) + zaza.model.block_until_oslo_config_entries_match( + 'cinder', + '/tmp/cinder.conf', + expected_contents, + model_name=self.model_name, + timeout=2) + + def test_create_volume(self): + test_vol_name = "zaza{}".format(uuid.uuid1().fields[0]) + vol_new = self.cinder_client.volumes.create( + name=test_vol_name, + size=2) + openstack_utils.resource_reaches_status( + self.cinder_client.volumes, + vol_new.id, + expected_status='available') + test_vol = self.cinder_client.volumes.find(name=test_vol_name) + self.assertEqual( + getattr(test_vol, 'os-vol-host-attr:host').split('#')[0], + 'cinder@cinder-netapp') + self.cinder_client.volumes.delete(vol_new) diff --git a/src/tox.ini b/src/tox.ini new file mode 100644 index 0000000..ce45106 --- /dev/null +++ b/src/tox.ini @@ -0,0 +1,35 @@ +[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:pep8] +basepython = python3 +deps=charm-tools +commands = charm-proof + +[testenv:func-noop] +basepython = python3 +commands = + true + +[testenv:func] +basepython = python3 +commands = + functest-run-suite --keep-model + +[testenv:func-smoke] +basepython = python3 +commands = + functest-run-suite --keep-model --smoke + +[testenv:venv] +commands = {posargs} diff --git a/src/wheelhouse.txt b/src/wheelhouse.txt new file mode 100644 index 0000000..ebd9154 --- /dev/null +++ b/src/wheelhouse.txt @@ -0,0 +1,2 @@ +#layer-basic uses wheelhouse to install python dependencies +psutil \ No newline at end of file diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..0ab97f6 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,23 @@ +# 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 +# +# Lint and unit test requirements +flake8>=2.2.4,<=2.4.1 +stestr>=2.2.0 +requests>=2.18.4 +charms.reactive +mock>=1.2 +nose>=1.3.7 +coverage>=3.6 +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 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..afd48f0 --- /dev/null +++ b/tox.ini @@ -0,0 +1,97 @@ +# Source charm: ./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] +skipsdist = True +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] +setenv = VIRTUAL_ENV={envdir} + PYTHONHASHSEED=0 + TERM=linux + LAYER_PATH={toxinidir}/layers + INTERFACE_PATH={toxinidir}/interfaces + JUJU_REPOSITORY={toxinidir}/build +passenv = http_proxy https_proxy INTERFACE_PATH LAYER_PATH JUJU_REPOSITORY +install_command = + pip install {opts} {packages} +deps = + -r{toxinidir}/requirements.txt + +[testenv:build] +basepython = python3 +commands = + charm-build --log-level DEBUG -o {toxinidir}/build src {posargs} + +[testenv:py3] +basepython = python3 +deps = -r{toxinidir}/test-requirements.txt +commands = stestr run --slowest {posargs} + +[testenv:py35] +basepython = python3.5 +deps = -r{toxinidir}/test-requirements.txt +commands = stestr run --slowest {posargs} + +[testenv:py36] +basepython = python3.6 +deps = -r{toxinidir}/test-requirements.txt +commands = stestr run --slowest {posargs} + +[testenv:py37] +basepython = python3.7 +deps = -r{toxinidir}/test-requirements.txt +commands = stestr run --slowest {posargs} + +[testenv:py38] +basepython = python3.8 +deps = -r{toxinidir}/test-requirements.txt +commands = stestr run --slowest {posargs} + +[testenv:pep8] +basepython = python3 +deps = -r{toxinidir}/test-requirements.txt +commands = flake8 {posargs} src unit_tests + +[testenv:cover] +# Technique based heavily upon +# https://github.com/openstack/nova/blob/master/tox.ini +basepython = python3 +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt +setenv = + {[testenv]setenv} + PYTHON=coverage run +commands = + coverage erase + stestr run --slowest {posargs} + coverage combine + coverage html -d cover + coverage xml -o cover/coverage.xml + coverage report + +[coverage:run] +branch = True +concurrency = multiprocessing +parallel = True +source = + . +omit = + .tox/* + */charmhelpers/* + unit_tests/* + +[testenv:venv] +basepython = python3 +commands = {posargs} + +[flake8] +# E402 ignore necessary for path append before sys module import in actions +ignore = E402,W504 diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py new file mode 100644 index 0000000..3a5e9a3 --- /dev/null +++ b/unit_tests/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2016 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. + +import sys + +sys.path.append('src') +sys.path.append('src/lib') + +# Mock out charmhelpers so that we can test without it. +import charms_openstack.test_mocks # noqa +charms_openstack.test_mocks.mock_charmhelpers() diff --git a/unit_tests/test_lib_charm_openstack_cinder_netapp.py b/unit_tests/test_lib_charm_openstack_cinder_netapp.py new file mode 100644 index 0000000..2f5cda9 --- /dev/null +++ b/unit_tests/test_lib_charm_openstack_cinder_netapp.py @@ -0,0 +1,48 @@ +# Copyright 2016 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. + +import charmhelpers + +import charm.openstack.cinder_netapp as cinder_netapp + +import charms_openstack.test_utils as test_utils + + +class TestCindernetappCharm(test_utils.PatchHelper): + + def _patch_config_and_charm(self, config): + self.patch_object(charmhelpers.core.hookenv, 'config') + + def cf(key=None): + if key is not None: + return config[key] + return config + + self.config.side_effect = cf + c = cinder_netapp.CindernetappCharm() + return c + + def test_cinder_base(self): + charm = self._patch_config_and_charm({}) + self.assertEqual(charm.name, 'cinder_netapp') + + def test_cinder_configuration(self): + charm = self._patch_config_and_charm({'a': 'b'}) + config = charm.cinder_configuration() + # Add check here that configuration is as expected. + self.assertEqual(config, [('netapp_hostname', None), + ('netapp_login', None), + ('netapp_password', None), + ('volume_driver', None), + ('volume_backend_name', None)])