commit b3ae62ceba1cfb8fb8b719cb0d5f5859cfa88d65
Author: narindergupta <narinder.gupta@canonical.com>
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 <openstack-charmers@lists.ubuntu.com>
+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)])