[Manila] Add security-services context

Add possibility to create "security-services" on-fly
and attach them to "share-networks".

Note that, it is not added to benchmarks as it cannot be tested in CI
because requires appropriate services be set up and running.

Change-Id: I64aa960f3109bfb576da2c2260b017925d4c7c68
This commit is contained in:
Valeriy Ponomaryov 2015-10-05 19:18:46 +03:00
parent 8a1672f293
commit a3da693878
7 changed files with 384 additions and 2 deletions

View File

@ -14,3 +14,4 @@
# under the License.
SHARE_NETWORKS_CONTEXT_NAME = "manila_share_networks"
SECURITY_SERVICES_CONTEXT_NAME = "manila_security_services"

View File

@ -0,0 +1,88 @@
# Copyright 2015 Mirantis Inc.
# All Rights Reserved.
#
# 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.
from oslo_config import cfg
from rally.common.i18n import _
from rally.common import logging
from rally.common import utils
from rally import consts as rally_consts
from rally.plugins.openstack.cleanup import manager as resource_manager
from rally.plugins.openstack.context.manila import consts
from rally.plugins.openstack.scenarios.manila import utils as manila_utils
from rally.task import context
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
CONTEXT_NAME = consts.SECURITY_SERVICES_CONTEXT_NAME
@context.configure(name=CONTEXT_NAME, order=445)
class SecurityServices(context.Context):
"""This context creates 'security services' for Manila project."""
CONFIG_SCHEMA = {
"type": "object",
"$schema": rally_consts.JSON_SCHEMA,
"properties": {
# NOTE(vponomaryov): context arg 'security_services' is expected
# to be list of dicts with data for creation of security services.
# Example:
# security_services = [
# {'type': 'LDAP', 'dns_ip': 'foo_ip', 'server': 'bar_ip',
# 'domain': 'quuz_domain', 'user': 'ololo',
# 'password': 'fake_password'}
# ]
# Where 'type' is required key and should have one of following
# values: 'active_directory', 'kerberos' or 'ldap'.
# This context arg is used only if share networks are used and
# autocreated.
"security_services": {"type": "array"},
},
"additionalProperties": False
}
DEFAULT_CONFIG = {
"security_services": [],
}
@logging.log_task_wrapper(
LOG.info, _("Enter context: `%s`") % CONTEXT_NAME)
def setup(self):
for user, tenant_id in (utils.iterate_per_tenants(
self.context.get("users", []))):
self.context["tenants"][tenant_id][CONTEXT_NAME] = {
"security_services": [],
}
if self.config["security_services"]:
manila_scenario = manila_utils.ManilaScenario({
"task": self.task,
"user": user,
"config": {
"api_versions": self.context["config"].get(
"api_versions", [])}
})
for ss in self.config["security_services"]:
inst = manila_scenario._create_security_service(
**ss).to_dict()
self.context["tenants"][tenant_id][CONTEXT_NAME][
"security_services"].append(inst)
@logging.log_task_wrapper(LOG.info, _("Exit context: `%s`") % CONTEXT_NAME)
def cleanup(self):
resource_manager.cleanup(
names=["manila.security_services"],
users=self.context.get("users", []),
)

View File

@ -153,6 +153,11 @@ class ShareNetworks(context.Context):
**data).to_dict()
self.context["tenants"][tenant_id][CONTEXT_NAME][
"share_networks"].append(share_network)
for ss in self.context["tenants"][tenant_id].get(
consts.SECURITY_SERVICES_CONTEXT_NAME, {}).get(
"security_services", []):
manila_scenario._add_security_service_to_share_network(
share_network["id"], ss["id"])
if networks:
for network in networks:

View File

@ -1,3 +1,4 @@
{% set use_security_services = use_security_services or False %}
{
"ManilaShares.create_and_delete_share": [
{
@ -32,6 +33,28 @@
"manila_share_networks": {
"use_share_networks": true
}
{% if use_security_services %}
,
"manila_security_services": {
"security_services": [
{"security_service_type": "ldap",
"server": "LDAP server address",
"user": "User that will be used",
"password": "Password for specified user"},
{"security_service_type": "kerberos",
"dns_ip": "IP address of DNS service to be used",
"server": "Kerberos server address",
"domain": "Kerberos realm",
"user": "User that will be used",
"password": "Password for specified user"},
{"security_service_type": "active_directory",
"dns_ip": "IP address of DNS service to be used",
"domain": "Domain from 'Active Directory'",
"user": "User from 'Active Directory'",
"password": "password for specified user"}
]
}
{% endif %}
}
}
]

View File

@ -1,3 +1,4 @@
{% set use_security_services = use_security_services or False %}
---
ManilaShares.create_and_delete_share:
-
@ -25,3 +26,23 @@
start_cidr: "99.0.0.0/24"
manila_share_networks:
use_share_networks: True
{% if use_security_services %}
manila_security_services:
security_services: [
{"security_service_type": "ldap",
"server": "LDAP server address",
"user": "User that will be used",
"password": "Password for specified user"},
{"security_service_type": "kerberos",
"dns_ip": "IP address of DNS service to be used",
"server": "Kerberos server address",
"domain": "Kerberos realm",
"user": "User that will be used",
"password": "Password for specified user"},
{"security_service_type": "active_directory",
"dns_ip": "IP address of DNS service to be used",
"domain": "Domain from 'Active Directory'",
"user": "User from 'Active Directory'",
"password": "password for specified user"},
]
{% endif %}

View File

@ -0,0 +1,172 @@
# Copyright 2015 Mirantis Inc.
# All Rights Reserved.
#
# 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 ddt
import mock
import six
from rally import consts as rally_consts
from rally.plugins.openstack.context.manila import consts
from rally.plugins.openstack.context.manila import manila_security_services
from tests.unit import test
CONTEXT_NAME = consts.SECURITY_SERVICES_CONTEXT_NAME
@ddt.ddt
class SecurityServicesTestCase(test.ScenarioTestCase):
TENANTS_AMOUNT = 3
USERS_PER_TENANT = 4
SECURITY_SERVICES = [
{"security_service_type": ss_type,
"dns_ip": "fake_dns_ip_%s" % ss_type,
"server": "fake_server_%s" % ss_type,
"domain": "fake_domain_%s" % ss_type,
"user": "fake_user_%s" % ss_type,
"password": "fake_password_%s" % ss_type}
for ss_type in ("ldap", "kerberos", "active_directory")
]
def _get_context(self, security_services=None, networks_per_tenant=2,
neutron_network_provider=True):
if security_services is None:
security_services = self.SECURITY_SERVICES
tenants = {}
for t_id in range(self.TENANTS_AMOUNT):
tenants[six.text_type(t_id)] = {"name": six.text_type(t_id)}
tenants[six.text_type(t_id)]["networks"] = []
for i in range(networks_per_tenant):
network = {"id": "fake_net_id_%s" % i}
if neutron_network_provider:
network["subnets"] = ["fake_subnet_id_of_net_%s" % i]
else:
network["cidr"] = "101.0.5.0/24"
tenants[six.text_type(t_id)]["networks"].append(network)
users = []
for t_id in tenants.keys():
for i in range(self.USERS_PER_TENANT):
users.append({"id": i, "tenant_id": t_id, "endpoint": "fake"})
context = {
"config": {
"users": {
"tenants": self.TENANTS_AMOUNT,
"users_per_tenant": self.USERS_PER_TENANT,
},
CONTEXT_NAME: {
"security_services": security_services,
},
},
"admin": {
"endpoint": mock.MagicMock(),
},
"task": mock.MagicMock(),
"users": users,
"tenants": tenants,
}
return context
def test_init(self):
context = {
"task": mock.MagicMock(),
"config": {
CONTEXT_NAME: {"foo": "bar"},
"not_manila": {"not_manila_key": "not_manila_value"},
}
}
inst = manila_security_services.SecurityServices(context)
self.assertEqual(inst.config.get("foo"), "bar")
self.assertFalse(inst.config.get("security_services"))
self.assertIn(
rally_consts.JSON_SCHEMA, inst.CONFIG_SCHEMA.get("$schema"))
self.assertEqual(False, inst.CONFIG_SCHEMA.get("additionalProperties"))
self.assertEqual("object", inst.CONFIG_SCHEMA.get("type"))
props = inst.CONFIG_SCHEMA.get("properties", {})
self.assertEqual({"type": "array"}, props.get("security_services"))
self.assertEqual(445, inst.get_order())
self.assertEqual(CONTEXT_NAME, inst.get_name())
@mock.patch.object(manila_security_services.manila_utils, "ManilaScenario")
@ddt.data(True, False)
def test_setup_security_services_set(self, neutron_network_provider,
mock_manila_scenario):
ctxt = self._get_context(
neutron_network_provider=neutron_network_provider)
inst = manila_security_services.SecurityServices(ctxt)
inst.setup()
self.assertEqual(
self.TENANTS_AMOUNT, mock_manila_scenario.call_count)
self.assertEqual(
mock_manila_scenario.call_args_list,
[mock.call({
"task": inst.task,
"config": {"api_versions": []},
"user": user})
for user in inst.context["users"] if user["id"] == 0]
)
mock_create_security_service = (
mock_manila_scenario.return_value._create_security_service)
expected_calls = []
for ss in self.SECURITY_SERVICES:
expected_calls.extend([mock.call(**ss), mock.call().to_dict()])
mock_create_security_service.assert_has_calls(expected_calls)
self.assertEqual(
self.TENANTS_AMOUNT * len(self.SECURITY_SERVICES),
mock_create_security_service.call_count)
self.assertEqual(
self.TENANTS_AMOUNT,
len(inst.context["config"][CONTEXT_NAME]["security_services"]))
for tenant in inst.context["tenants"]:
self.assertEqual(
self.TENANTS_AMOUNT,
len(inst.context["tenants"][tenant][CONTEXT_NAME][
"security_services"])
)
@mock.patch.object(manila_security_services.manila_utils, "ManilaScenario")
def test_setup_security_services_not_set(self, mock_manila_scenario):
ctxt = self._get_context(security_services=[])
inst = manila_security_services.SecurityServices(ctxt)
inst.setup()
self.assertFalse(mock_manila_scenario.called)
self.assertFalse(
mock_manila_scenario.return_value._create_security_service.called)
self.assertIn(CONTEXT_NAME, inst.context["config"])
self.assertIn(
"security_services", inst.context["config"][CONTEXT_NAME])
self.assertEqual(
0,
len(inst.context["config"][CONTEXT_NAME]["security_services"]))
for tenant in inst.context["tenants"]:
self.assertEqual(
0,
len(inst.context["tenants"][tenant][CONTEXT_NAME][
"security_services"])
)
@mock.patch.object(manila_security_services, "resource_manager")
def test_cleanup_security_services_enabled(self, mock_resource_manager):
ctxt = self._get_context()
inst = manila_security_services.SecurityServices(ctxt)
inst.cleanup()
mock_resource_manager.cleanup.assert_called_once_with(
names=["manila.security_services"], users=ctxt["users"])

View File

@ -56,7 +56,7 @@ class ShareNetworksTestCase(test.TestCase):
for ss_type in ("ldap", "kerberos", "active_directory")
]
def _get_context(self, networks_per_tenant=2,
def _get_context(self, use_security_services=False, networks_per_tenant=2,
neutron_network_provider=True):
tenants = {}
for t_id in range(self.TENANTS_AMOUNT):
@ -85,6 +85,11 @@ class ShareNetworksTestCase(test.TestCase):
"use_share_networks": True,
"share_networks": [],
},
consts.SECURITY_SERVICES_CONTEXT_NAME: {
"security_services": (
self.SECURITY_SERVICES
if use_security_services else [])
},
"network": {
"networks_per_tenant": networks_per_tenant,
"start_cidr": "101.0.5.0/24",
@ -242,6 +247,64 @@ class ShareNetworksTestCase(test.TestCase):
self.assertRaises(exceptions.ContextSetupFailure, inst.setup)
@ddt.data(True, False)
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_create_share_network")
@mock.patch(MANILA_UTILS_PATH + "_add_security_service_to_share_network")
def test_setup_autocreate_share_networks_with_security_services(
self,
neutron,
mock_manila_scenario__add_security_service_to_share_network,
mock_manila_scenario__create_share_network,
mock_clients):
networks_per_tenant = 2
ctxt = self._get_context(
networks_per_tenant=networks_per_tenant,
neutron_network_provider=neutron,
use_security_services=True,
)
inst = manila_share_networks.ShareNetworks(ctxt)
for tenant_id in list(ctxt["tenants"].keys()):
inst.context["tenants"][tenant_id][
consts.SECURITY_SERVICES_CONTEXT_NAME] = {
"security_services": [
Fake(id="fake_id").to_dict() for i in (1, 2, 3)
]
}
inst.setup()
self.assertEqual(ctxt["task"], inst.context.get("task"))
self.assertEqual(ctxt["config"], inst.context.get("config"))
self.assertEqual(ctxt["users"], inst.context.get("users"))
self.assertEqual(ctxt["tenants"], inst.context.get("tenants"))
mock_add_security_service_to_share_network = (
mock_manila_scenario__add_security_service_to_share_network)
mock_add_security_service_to_share_network.assert_has_calls([
mock.call(mock.ANY, mock.ANY)
for i in range(
self.TENANTS_AMOUNT *
networks_per_tenant *
len(self.SECURITY_SERVICES))])
if neutron:
sn_args = {
"neutron_net_id": mock.ANY,
"neutron_subnet_id": mock.ANY,
}
else:
sn_args = {"nova_net_id": mock.ANY}
expected_calls = [
mock.call(**sn_args),
mock.call().to_dict(),
mock.ANY,
mock.ANY,
mock.ANY,
]
mock_manila_scenario__create_share_network.assert_has_calls(
expected_calls * (self.TENANTS_AMOUNT * networks_per_tenant))
mock_clients.assert_has_calls([
mock.call("fake", {}) for i in range(self.TENANTS_AMOUNT)])
@ddt.data(True, False)
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_create_share_network")
@ -329,6 +392,7 @@ class ShareNetworksTestCase(test.TestCase):
self.assertIn(mock.call(user["credential"], {}),
mock_clients.mock_calls)
@ddt.data(True, False)
@mock.patch("rally.task.utils.wait_for_status")
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_delete_share_network")
@ -336,7 +400,7 @@ class ShareNetworksTestCase(test.TestCase):
@mock.patch(MANILA_UTILS_PATH + "_add_security_service_to_share_network")
@mock.patch(MANILA_UTILS_PATH + "_list_share_servers")
def test_cleanup_autocreated_share_networks(
self,
self, use_security_services,
mock_manila_scenario__list_share_servers,
mock_manila_scenario__add_security_service_to_share_network,
mock_manila_scenario__create_share_network,
@ -349,8 +413,16 @@ class ShareNetworksTestCase(test.TestCase):
networks_per_tenant = 2
ctxt = self._get_context(
networks_per_tenant=networks_per_tenant,
use_security_services=use_security_services,
)
inst = manila_share_networks.ShareNetworks(ctxt)
for tenant_id in list(ctxt["tenants"].keys()):
inst.context["tenants"][tenant_id][
consts.SECURITY_SERVICES_CONTEXT_NAME] = {
"security_services": [
Fake(id="fake_id").to_dict() for i in (1, 2, 3)
]
}
inst.setup()
mock_clients.assert_has_calls([