Manila-infinidat charm
- basic functionality and configuration - unit-tests
This commit is contained in:
parent
6c45de0fbe
commit
c8f1cd90bd
10
README.md
10
README.md
@ -1,17 +1,17 @@
|
||||
infinidat Storage Backend for Cinder
|
||||
-------------------------------
|
||||
Infinidat Storage Backend for Manila
|
||||
------------------------------------
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
This charm provides a infinidat storage backend for use with the Cinder
|
||||
This charm provides Infinidat storage backend for use with the Manila
|
||||
charm.
|
||||
|
||||
To use:
|
||||
|
||||
juju deploy cinder
|
||||
juju deploy manila
|
||||
juju deploy manila-infinidat
|
||||
juju add-relation manila-infinidat cinder
|
||||
juju add-relation manila-infinidat manila
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
53
config.yaml
53
config.yaml
@ -11,16 +11,19 @@ options:
|
||||
description: >
|
||||
The status of service-affecting packages will be set to this
|
||||
value in the dpkg database. Valid values are "install" and "hold".
|
||||
source:
|
||||
description: >
|
||||
List of extra apt sources, per charm-helpers standard
|
||||
format (a yaml list of strings encoded as a string). Each source
|
||||
may be either a line that can be added directly to
|
||||
sources.list(5), or in the form ppa:<user>/<ppa-name> for adding
|
||||
Personal Package Archives, or a distribution component to enable.
|
||||
install_sources:
|
||||
description: |
|
||||
Optional configuration to support use of additional sources such as:
|
||||
- ppa:myteam/ppa
|
||||
- cloud:trusty-proposed/kilo
|
||||
- http://my.archive.com/ubuntu main
|
||||
The last option should be used in conjunction with the key configuration
|
||||
option. See https://repo.infinidat.com/home/main-stable for details.
|
||||
The charm also supports templating of the distribution codename via
|
||||
automatic expansion of {distrib_codename} depending on the host system
|
||||
default: "deb https://repo.infinidat.com/packages/main-stable/apt/linux-ubuntu {distrib_codename} main"
|
||||
type: string
|
||||
default: ""
|
||||
key:
|
||||
install_keys:
|
||||
description: >
|
||||
List of signing keys for install_sources package sources, per
|
||||
charmhelpers standard format (a yaml list of strings encoded as
|
||||
@ -32,7 +35,25 @@ options:
|
||||
sources where the package signing key is securely retrieved from
|
||||
Launchpad.
|
||||
type: string
|
||||
default: ""
|
||||
default: |
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.11 (GNU/Linux)
|
||||
|
||||
mQENBFESDRIBCADMR7MQMbH4GdCQqfrOMt35MhBwwH4wv9kb1WRSTxa0CmuzYaBB
|
||||
1nJ0nLaMAwHsEr9CytPWDpMngm/3nt+4F2hJcsOEkQkqeJ31gScJewM+AOUV3DEl
|
||||
qOeXXYLcP+jUY6pPjlZpOw0p7moUQPXHn+7amVrk7cXGQ8O3B+5a5wjN86LT2hlX
|
||||
DlBlV5bX/DYluiPUbvQLOknmwO53KpaeDeZc4a8iIOCYWu2ntuAMddBkTps0El5n
|
||||
JJZMTf6os2ZzngWMZRMDiVJgqVRi2b+8SgFQlQy0cAmne/mpgPrRq0ZMX3DokGG5
|
||||
hnIg1mF82laTxd+9qtiOxupzJqf8mncQHdaTABEBAAG0IWFwcF9yZXBvIChDb21t
|
||||
ZW50KSA8bm9AZW1haWwuY29tPokBOAQTAQIAIgUCURINEgIbLwYLCQgHAwIGFQgC
|
||||
CQoLBBYCAwECHgECF4AACgkQem2D/j05RYSrcggAsCc4KppV/SZX5XI/CWFXIAXw
|
||||
+HaNsh2EwYKf9DhtoGbTOuwePvrPGcgFYM3Tu+m+rziPnnFl0bs0xwQyNEVQ9yDw
|
||||
t465pSgmXwEHbBkoISV1e4WYtZAsnTNne9ieJ49Ob/WY4w3AkdPRK/41UP5Ct6lR
|
||||
HHRXrSWJYHVq5Rh6BakRuMJyJLz/KvcJAaPkA4U6VrPD7PFtSecMTaONPjGCcomq
|
||||
b7q84G5ZfeJWb742PWBTS8fJdC+Jd4y5fFdJS9fQwIo52Ff9In2QBpJt5Wdc02SI
|
||||
fvQnuh37D2P8OcIfMxMfoFXpAMWjrMYc5veyQY1GXD/EOkfjjLne6qWPLfNojA==
|
||||
=w5Os
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
debug:
|
||||
default: !!bool false
|
||||
type: boolean
|
||||
@ -65,8 +86,18 @@ options:
|
||||
thin-provision:
|
||||
type: boolean
|
||||
description: Choose whether to thin provision
|
||||
default: !!bool true
|
||||
default: !!bool "true"
|
||||
share-backend-name:
|
||||
type: string
|
||||
description: Manila backend name
|
||||
default: __app__
|
||||
use-ssl:
|
||||
type: boolean
|
||||
description: >
|
||||
Configures SSL support for Infinidat management API
|
||||
default: !!bool "false"
|
||||
suppress-ssl-warnings:
|
||||
type: boolean
|
||||
description: >
|
||||
Configures SSL warnings suppression
|
||||
default: !!bool "false"
|
||||
|
102
src/charm.py
102
src/charm.py
@ -15,9 +15,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from typing import OrderedDict
|
||||
import ops_openstack.adapters
|
||||
from ops_openstack.plugins.classes import CinderStoragePluginCharm
|
||||
from ops_openstack.core import charm_class, get_charm_class_for_release, OSBaseCharm
|
||||
from ops_openstack.core import OSBaseCharm
|
||||
from ops.main import main
|
||||
|
||||
from ops.model import (
|
||||
@ -45,19 +43,25 @@ import logging
|
||||
|
||||
RELATION_NAME = 'manila-plugin'
|
||||
|
||||
|
||||
class ManilaInfinidatPluginCharm(OSBaseCharm):
|
||||
|
||||
PACKAGES = ['infinisdk', 'infinishell']
|
||||
PACKAGES = ['python3-infinisdk', 'infinishell']
|
||||
|
||||
REQUIRED_RELATIONS = [RELATION_NAME]
|
||||
|
||||
SHARE_DRIVER = 'manila.share.drivers.infinidat.infinibox.InfiniboxShareDriver'
|
||||
SHARE_DRIVER = \
|
||||
'manila.share.drivers.infinidat.infinibox.InfiniboxShareDriver'
|
||||
|
||||
active_active = True
|
||||
MANDATORY_CONFIG = ['infinibox-ip', 'infinibox-login',
|
||||
'infinibox-password', 'pool-name']
|
||||
|
||||
DEFAULT_REPO_BASEURL = \
|
||||
'https://repo.infinidat.com/packages/main-stable/apt/linux-ubuntu'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.framework.observe(
|
||||
self.on.config_changed,
|
||||
self.on_config)
|
||||
@ -69,14 +73,16 @@ class ManilaInfinidatPluginCharm(OSBaseCharm):
|
||||
def on_config(self, event):
|
||||
self.on_manila_plugin(event)
|
||||
self.set_started(started=True)
|
||||
if self.framework.model.relations.get(RELATION_NAME):
|
||||
self.send_backend_config()
|
||||
self.unit.status = ActiveStatus('Unit is ready')
|
||||
|
||||
def on_manila_plugin(self, event):
|
||||
logging.error("Relation changed")
|
||||
def send_backend_config(self):
|
||||
config = dict(self.framework.model.config)
|
||||
manila_backends = self.manila_configuration(config)
|
||||
for relation in self.framework.model.relations.get(RELATION_NAME):
|
||||
relation.data[self.unit]['_name'] = ','.join(manila_backends.keys())
|
||||
relation.data[self.unit]['_name'] = \
|
||||
','.join(manila_backends.keys())
|
||||
rendered_config = render(
|
||||
source="parts/backends",
|
||||
template_loader=os_templating.get_loader(
|
||||
@ -90,12 +96,15 @@ class ManilaInfinidatPluginCharm(OSBaseCharm):
|
||||
}
|
||||
})
|
||||
|
||||
def on_manila_plugin(self, event):
|
||||
self.send_backend_config()
|
||||
|
||||
def manila_configuration(self, config):
|
||||
"""
|
||||
See https://docs.openstack.org/manila/latest/configuration/shared-file-systems/drivers/infinidat-share-driver.html # noqa: E501
|
||||
"""
|
||||
# Return the configuration to be set by the principal.
|
||||
|
||||
|
||||
backends = OrderedDict()
|
||||
|
||||
backend_name = config.get('share-backend-name')
|
||||
@ -103,6 +112,7 @@ class ManilaInfinidatPluginCharm(OSBaseCharm):
|
||||
# backend name selection logic
|
||||
if config.get('nas-network-space-name'):
|
||||
backend_names = filter(
|
||||
None,
|
||||
map(
|
||||
str.strip,
|
||||
config.get('nas-network-space-name').split(',')
|
||||
@ -115,66 +125,60 @@ class ManilaInfinidatPluginCharm(OSBaseCharm):
|
||||
|
||||
for backend_name in backend_names:
|
||||
|
||||
backends[backend_name] = (
|
||||
backends[backend_name] = [
|
||||
('share_driver', self.SHARE_DRIVER),
|
||||
('share_backend_name', backend_name),
|
||||
|
||||
('infinibox_hostname', config.get('infinibox-ip')),
|
||||
('infinibox_login', config.get('infinibox-login')),
|
||||
('infinibox_password', config.get('infinibox-password')),
|
||||
|
||||
('infinidat_nas_network_space_name', backend_name), #TODO: mapping to nas-network-space-name
|
||||
('driver_handles_share_servers', 'false'),
|
||||
|
||||
('infinidat_nas_network_space_name', backend_name),
|
||||
|
||||
('infinidat_pool_name', config.get('pool-name')),
|
||||
('infinidat_thin_provision', config.get('thin-provision')),
|
||||
)
|
||||
|
||||
('infinidat_use_ssl', config.get('use-ssl', False)),
|
||||
|
||||
('infinidat_suppress_ssl_warnings',
|
||||
config.get('suppress-ssl-warnings', True)),
|
||||
]
|
||||
|
||||
if config.get('infinibox-ip') and config.get('infinibox-login') \
|
||||
and config.get('infinibox-password'):
|
||||
|
||||
backends[backend_name].extend([
|
||||
('infinibox_hostname', config.get('infinibox-ip')),
|
||||
('infinibox_login', config.get('infinibox-login')),
|
||||
('infinibox_password', config.get('infinibox-password')),
|
||||
])
|
||||
|
||||
if config.get('pool-name'):
|
||||
backends[backend_name].append(
|
||||
('infinidat_pool_name', config.get('pool-name'))
|
||||
),
|
||||
|
||||
if not backends:
|
||||
self.unit.status = BlockedStatus("No backends configured")
|
||||
|
||||
return backends
|
||||
|
||||
@property
|
||||
def stateless(self):
|
||||
"""Indicate whether the charm is stateless.
|
||||
|
||||
For more information, see: https://cinderlib.readthedocs.io/en/v0.2.1/topics/serialization.html
|
||||
|
||||
:returns: A boolean value indicating statefulness.
|
||||
:rtype: bool
|
||||
""" # noqa
|
||||
return False
|
||||
|
||||
@property
|
||||
def active_active(self):
|
||||
"""Indicate active-active support in the charm.
|
||||
|
||||
For more information, see: https://specs.openstack.org/openstack/cinder-specs/specs/mitaka/cinder-volume-active-active-support.html
|
||||
|
||||
:returns: A boolean indicating active-active support.
|
||||
:rtype: bool
|
||||
""" # noqa
|
||||
return False
|
||||
|
||||
def install_pkgs(self):
|
||||
logging.info("Installing packages")
|
||||
|
||||
# value of 'source' param is defined like this:
|
||||
# deb https://repo.infinidat.com/packages/main-stable/apt/linux-ubuntu $codename main
|
||||
if self.model.config.get('source'):
|
||||
# we implement $codename expansion here
|
||||
# see the default value for 'source' in config.yaml
|
||||
if self.model.config.get('install_sources'):
|
||||
distrib_codename = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
add_source(
|
||||
self.model.config['source'] \
|
||||
.replace('$codename',
|
||||
lsb_release()['DISTRIB_CODENAME'].lower()),
|
||||
self.model.config.get('key'))
|
||||
self.model.config['install_sources']
|
||||
.format(distrib_codename=distrib_codename),
|
||||
self.model.config.get('install_keys'))
|
||||
apt_update(fatal=True)
|
||||
apt_install(self.PACKAGES, fatal=True)
|
||||
self.update_status()
|
||||
|
||||
def on_install(self, event):
|
||||
self.install_pkgs()
|
||||
|
||||
self.update_status()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(ManilaInfinidatPluginCharm)
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% for backend_name in backends %}
|
||||
[{{ backend_name }}]
|
||||
{% for key, value in backends[backend_name] -%}
|
||||
{% for key, value in backends[backend_name] %}
|
||||
{{ key }} = {{ value }}
|
||||
{%- endfor %}
|
||||
{% endfor %}
|
@ -13,17 +13,136 @@
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
from src.charm import CinderCharmBase
|
||||
from ops.model import ActiveStatus
|
||||
from src.charm import ManilaInfinidatPluginCharm
|
||||
from ops.testing import Harness
|
||||
|
||||
from unittest import mock
|
||||
|
||||
class TestManilainfinidatCharm(unittest.TestCase):
|
||||
from charmhelpers.core.host_factory.ubuntu import UBUNTU_RELEASES
|
||||
|
||||
SOURCE = "deb https://repo.infinidat.com/packages/main-stable/apt/linux-ubuntu focal main" # noqa: E501
|
||||
KEY = """\
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.11 (GNU/Linux)
|
||||
|
||||
mQENBFESDRIBCADMR7MQMbH4GdCQqfrOMt35MhBwwH4wv9kb1WRSTxa0CmuzYaBB
|
||||
1nJ0nLaMAwHsEr9CytPWDpMngm/3nt+4F2hJcsOEkQkqeJ31gScJewM+AOUV3DEl
|
||||
qOeXXYLcP+jUY6pPjlZpOw0p7moUQPXHn+7amVrk7cXGQ8O3B+5a5wjN86LT2hlX
|
||||
DlBlV5bX/DYluiPUbvQLOknmwO53KpaeDeZc4a8iIOCYWu2ntuAMddBkTps0El5n
|
||||
JJZMTf6os2ZzngWMZRMDiVJgqVRi2b+8SgFQlQy0cAmne/mpgPrRq0ZMX3DokGG5
|
||||
hnIg1mF82laTxd+9qtiOxupzJqf8mncQHdaTABEBAAG0IWFwcF9yZXBvIChDb21t
|
||||
ZW50KSA8bm9AZW1haWwuY29tPokBOAQTAQIAIgUCURINEgIbLwYLCQgHAwIGFQgC
|
||||
CQoLBBYCAwECHgECF4AACgkQem2D/j05RYSrcggAsCc4KppV/SZX5XI/CWFXIAXw
|
||||
+HaNsh2EwYKf9DhtoGbTOuwePvrPGcgFYM3Tu+m+rziPnnFl0bs0xwQyNEVQ9yDw
|
||||
t465pSgmXwEHbBkoISV1e4WYtZAsnTNne9ieJ49Ob/WY4w3AkdPRK/41UP5Ct6lR
|
||||
HHRXrSWJYHVq5Rh6BakRuMJyJLz/KvcJAaPkA4U6VrPD7PFtSecMTaONPjGCcomq
|
||||
b7q84G5ZfeJWb742PWBTS8fJdC+Jd4y5fFdJS9fQwIo52Ff9In2QBpJt5Wdc02SI
|
||||
fvQnuh37D2P8OcIfMxMfoFXpAMWjrMYc5veyQY1GXD/EOkfjjLne6qWPLfNojA==
|
||||
=w5Os
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
"""
|
||||
|
||||
|
||||
class TestManilaInfinidatCharm(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.harness = Harness(CinderCharmBase)
|
||||
self.harness = Harness(ManilaInfinidatPluginCharm)
|
||||
self.addCleanup(self.harness.cleanup)
|
||||
self.harness.begin()
|
||||
self.harness.set_leader(True)
|
||||
backend = self.harness.add_relation('manila-plugin', 'manila')
|
||||
self.harness.add_relation_unit(backend, 'manila/0')
|
||||
|
||||
def _get_partial_config_sample(self):
|
||||
"""
|
||||
A config with all mandatory params set
|
||||
"""
|
||||
return {
|
||||
'infinibox-ip': '123.123.123.123',
|
||||
'infinibox-login': 'login',
|
||||
'infinibox-password': 'password',
|
||||
'pool-name': 'test',
|
||||
}
|
||||
|
||||
def _get_valid_config_sample(self):
|
||||
"""
|
||||
A minimal config that would transition the charm to ActiveState
|
||||
"""
|
||||
partial_config = self._get_partial_config_sample()
|
||||
partial_config.update({
|
||||
'nas-network-space-name': 'A,B',
|
||||
})
|
||||
return partial_config
|
||||
|
||||
def _get_source(self, codename, pocket, baseurl=None):
|
||||
if baseurl is None:
|
||||
baseurl = self.harness.charm.DEFAULT_REPO_BASEURL
|
||||
return ' '.join((
|
||||
'deb',
|
||||
baseurl,
|
||||
codename,
|
||||
pocket))
|
||||
|
||||
def test_update_config(self):
|
||||
self.harness.update_config({
|
||||
"infinibox-ip": "172.27.12.151",
|
||||
"infinibox-login": "admin",
|
||||
"infinibox-password": "123456",
|
||||
"nas-network-space-name": "iscsi",
|
||||
"package_status": "install",
|
||||
"pool-name": "manila",
|
||||
"share-backend-name": "__app__",
|
||||
"suppress-ssl-warnings": True,
|
||||
"thin-provision": True,
|
||||
"use-ssl": True,
|
||||
"verbose": False,
|
||||
})
|
||||
|
||||
@mock.patch('src.charm.add_source')
|
||||
@mock.patch('src.charm.apt_update')
|
||||
@mock.patch('src.charm.apt_install')
|
||||
@mock.patch('src.charm.lsb_release')
|
||||
def test_repo_management(self, lsb_release,
|
||||
apt_install, apt_update, add_source):
|
||||
|
||||
add_source.return_value = None
|
||||
apt_install.return_value = None
|
||||
apt_update.return_value = None
|
||||
|
||||
# we'll need the config the charm considers valid
|
||||
# in order to test repo management:
|
||||
cfg = self._get_valid_config_sample()
|
||||
|
||||
dynamic_source = self._get_source('{distrib_codename}', 'main')
|
||||
|
||||
# generate test data for both 'source' values that need substituion
|
||||
# and for the static ones
|
||||
|
||||
test_data = []
|
||||
|
||||
for release in UBUNTU_RELEASES:
|
||||
static_source = self._get_source(release, 'main')
|
||||
test_data.append(
|
||||
(dynamic_source, release,
|
||||
self._get_source(release, 'main')),
|
||||
)
|
||||
test_data.append(
|
||||
(static_source, release, static_source),
|
||||
)
|
||||
|
||||
for i in test_data:
|
||||
# distro codename the charm runs on
|
||||
lsb_release.return_value = {'DISTRIB_CODENAME': i[1]}
|
||||
|
||||
# configure to use specific repo version
|
||||
cfg['install_sources'] = i[0]
|
||||
cfg['install_keys'] = KEY
|
||||
|
||||
# on_config calls package installation
|
||||
self.harness.update_config(cfg)
|
||||
self.harness.charm.on.install.emit()
|
||||
|
||||
# make sure the repo management calls were correct
|
||||
add_source.assert_called_with(i[2], KEY)
|
||||
apt_install.assert_called_with(self.harness.charm.PACKAGES,
|
||||
fatal=True)
|
||||
|
Loading…
Reference in New Issue
Block a user