diff --git a/.gitignore b/.gitignore index 485dee6..17f8e6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ .idea +.testrepository +.tox +*.sw[nop] +*.pyc diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 0000000..801646b --- /dev/null +++ b/.testr.conf @@ -0,0 +1,8 @@ +[DEFAULT] +test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ + OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ + OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ + ${PYTHON:-python} -m subunit.run discover -t ./ ./unit_tests $LISTOPT $IDOPTION + +test_id_option=--load-list $IDFILE +test_list_option=--list diff --git a/ceph/ceph.py b/ceph/ceph.py index 4b68e03..489ab8e 100644 --- a/ceph/ceph.py +++ b/ceph/ceph.py @@ -13,6 +13,7 @@ # limitations under the License. import ctypes import json +import socket import subprocess import time import os @@ -44,10 +45,6 @@ from charmhelpers.contrib.storage.linux.utils import ( is_block_device, zap_disk, is_device_mounted) -from utils import ( - get_unit_hostname, -) - LEADER = 'leader' PEON = 'peon' @@ -97,6 +94,11 @@ NETWORK_ADAPTER_SYSCTLS = { } +@cached +def get_unit_hostname(): + return socket.gethostname() + + def save_sysctls(sysctl_dict, save_location): """ Persist the sysctls to the hard drive. @@ -955,7 +957,15 @@ def get_upgrade_key(): return get_named_key('upgrade-osd', _upgrade_caps) -def get_named_key(name, caps=None): +def get_named_key(name, caps=None, pool_list=None): + # TODO: Replace me with ceph_api commands + """ + Retrieve a specific named cephx key + :param name: String Name of key to get. + :param pool_list: The list of pools to give access to + :param caps: dict of cephx capabilities + :return: Returns a cephx key + """ caps = caps or _default_caps cmd = [ "sudo", @@ -971,10 +981,17 @@ def get_named_key(name, caps=None): ] # Add capabilities for subsystem, subcaps in caps.iteritems(): + if subsystem == 'osd': + if pool_list: + # This will output a string similar to: + # "pool=rgw pool=rbd pool=something" + pools = " ".join(['pool={0}'.format(i) for i in pool_list]) + subcaps[0] = subcaps[0] + " " + pools cmd.extend([ subsystem, '; '.join(subcaps), ]) + log("Calling subprocess.check_output: {}".format(cmd), level=DEBUG) return parse_key(subprocess.check_output(cmd).strip()) # IGNORE:E1103 diff --git a/ceph/ceph_broker.py b/ceph/ceph_broker.py index da6c342..d55e570 100644 --- a/ceph/ceph_broker.py +++ b/ceph/ceph_broker.py @@ -22,7 +22,7 @@ from charmhelpers.core.hookenv import ( INFO, ERROR, ) -from charmhelpers.contrib.storage.linux.ceph import ( +from charmhelpers.contrib.storage.linux.ceph import ( create_erasure_profile, delete_pool, erasure_profile_exists, @@ -191,7 +191,7 @@ def handle_replicated_pool(request, service): replicas = request.get('replicas') quota = request.get('max-bytes') weight = request.get('weight') - + # Optional params pg_num = request.get('pg_num') if pg_num: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fbb6c11 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +# The order of packages is significant, because pip processes them in the order +# of appearance. Changing the order has an impact on the overall integration +# process, which may cause wedges in the gate later. +charmhelpers +netifaces diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..4faf254 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,9 @@ +# The order of packages is significant, because pip processes them in the order +# of appearance. Changing the order has an impact on the overall integration +# process, which may cause wedges in the gate later. +coverage>=3.6 +mock>=1.2 +flake8>=2.2.4,<=2.4.1 +os-testr>=0.4.1 +charm-tools>=2.0.0 +requests==2.6.0 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..c3ac854 --- /dev/null +++ b/tox.ini @@ -0,0 +1,28 @@ +[tox] +envlist = pep8,py27 +skipsdist = True + +[testenv] +setenv = VIRTUAL_ENV={envdir} + PYTHONHASHSEED=0 +install_command = + pip install --allow-unverified python-apt {opts} {packages} +commands = ostestr {posargs} +sitepackages = False + +[testenv:py27] +basepython = python2.7 +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt + +[testenv:pep8] +basepython = python2.7 +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt +commands = flake8 {posargs} ceph unit_tests + +[testenv:venv] +commands = {posargs} + +[flake8] +ignore = E402,E226 diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py index b34230b..2e4fe88 100644 --- a/unit_tests/__init__.py +++ b/unit_tests/__init__.py @@ -13,4 +13,5 @@ # limitations under the License. import sys -sys.path.append('ceph') \ No newline at end of file + +sys.path.append('ceph') diff --git a/unit_tests/test_ceph.py b/unit_tests/test_ceph.py new file mode 100644 index 0000000..74eea79 --- /dev/null +++ b/unit_tests/test_ceph.py @@ -0,0 +1,56 @@ +# 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 mock +import unittest + +import ceph.ceph as ceph + + +class CephTestCase(unittest.TestCase): + def setUp(self): + super(CephTestCase, self).setUp() + + def test_get_named_key_with_pool(self): + with mock.patch.object(ceph, "ceph_user", return_value="ceph"): + with mock.patch.object(ceph.subprocess, "check_output") \ + as subprocess: + with mock.patch.object(ceph, "get_unit_hostname", + return_value="osd001"): + ceph.get_named_key(name="rgw001", + pool_list=["rbd", "block"]) + subprocess.assert_called_with( + ['sudo', '-u', 'ceph', 'ceph', '--name', 'mon.', + '--keyring', + '/var/lib/ceph/mon/ceph-osd001/keyring', + 'auth', + 'get-or-create', 'client.rgw001', 'mon', 'allow rw', + 'osd', + 'allow rwx pool=rbd pool=block']) + + def test_get_named_key(self): + with mock.patch.object(ceph, "ceph_user", return_value="ceph"): + with mock.patch.object(ceph.subprocess, "check_output") \ + as subprocess: + with mock.patch.object(ceph, "get_unit_hostname", + return_value="osd001"): + ceph.get_named_key(name="rgw001") + subprocess.assert_called_with( + ['sudo', '-u', 'ceph', 'ceph', '--name', 'mon.', + '--keyring', + '/var/lib/ceph/mon/ceph-osd001/keyring', + 'auth', + 'get-or-create', 'client.rgw001', 'mon', 'allow rw', + 'osd', + 'allow rwx'])