Implement neutron network protection plugin

Closes-Bug: 1572006

Change-Id: I304db6de21d16e8dbff695ffa2c76c8f8cc373ee
This commit is contained in:
chenhuayi2 2017-02-02 19:07:14 -08:00
parent 5f5680fcb2
commit d92876f7fa
6 changed files with 951 additions and 13 deletions

View File

@ -29,6 +29,21 @@ OPERATION_TYPES = (
# plugin type
PLUGIN_BANK = 'bank'
# supported network resource types
NETWORK_RESOURCE_TYPES = (NET_RESOURCE_TYPE,
SUBNET_RESOURCE_TYPE,
ROUTER_RESOURCE_TYPE,
ROUTERINTERFACE_RESOURCE_TYPE,
PORT_RESOURCE_TYPE,
SECURITYGROUP_RESOURCE_TYPE,
) = ('OS::Neutron::Net',
'OS::Neutron::Subnet',
'OS::Neutron::Router',
'OS::Neutron::RouterInterface',
'OS::Neutron::Port',
'OS::Neutron::SecurityGroup',
)
# supported resource types
RESOURCE_TYPES = (PROJECT_RESOURCE_TYPE,
SERVER_RESOURCE_TYPE,

View File

@ -383,3 +383,8 @@ class CheckpointNotAvailable(KarborException):
class CheckpointNotBeDeleted(KarborException):
message = _("The checkpoint %(checkpoint_id)s can not be deleted.")
class GetProtectionNetworkSubResourceFailed(KarborException):
message = _("Get protection network sub-resources of type %(type)s failed:"
" %(reason)s")

View File

@ -0,0 +1,38 @@
# 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.
OPTIONS_SCHEMA = {
"title": "Network Protection Options",
"type": "object",
"properties": {},
"required": []
}
RESTORE_SCHEMA = {
"title": "Network Protection Restore",
"type": "object",
"properties": {
"restore_name": {
"type": "string",
"title": "Restore Network Name",
"description": "The name of the restore network",
},
},
"required": ["restore_name"]
}
SAVED_INFO_SCHEMA = {
"title": "Network Protection Saved Info",
"type": "object",
"properties": {},
"required": []
}

View File

@ -9,35 +9,556 @@
# 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 six
from karbor.common import constants
from karbor import exception
from karbor.services.protection.client_factory import ClientFactory
from karbor.services.protection import protection_plugin
from karbor.services.protection.protection_plugins.network \
import network_plugin_schemas
from karbor.services.protection.restore_heat import HeatResource
from oslo_log import log as logging
from uuid import uuid4
LOG = logging.getLogger(__name__)
def get_network_id(cntxt):
network_id = cntxt.project_id
return network_id
class ProtectOperation(protection_plugin.Operation):
_SUPPORT_RESOURCE_TYPES = [constants.NETWORK_RESOURCE_TYPE]
def _get_resources_by_network(self, cntxt, neutron_client):
try:
networks = neutron_client.list_networks().get('networks')
networks_metadata = {}
allowed_keys = [
'id',
'admin_state_up',
'availability_zone_hints',
'description',
'ipv4_address_scope',
'ipv6_address_scope',
'mtu',
'name',
'port_security_enabled',
'router:external',
'shared',
'status',
'subnets',
'tags',
'tenant_id'
]
for network in networks:
network_metadata = {
k: network[k] for k in network if k in allowed_keys}
networks_metadata[network["id"]] = network_metadata
return networks_metadata
except Exception as e:
LOG.exception("List all summary networks from neutron failed.")
raise exception.GetProtectionNetworkSubResourceFailed(
type=self._SUPPORT_RESOURCE_TYPES,
reason=six.text_type(e))
else:
return []
def _get_resources_by_subnet(self, cntxt, neutron_client):
try:
subnets = neutron_client.list_subnets().get('subnets')
subnets_metadata = {}
allowed_keys = [
'cidr',
'allocation_pools',
'description',
'dns_nameservers',
'enable_dhcp',
'gateway_ip',
'host_routes',
'id',
'ip_version',
'ipv6_address_mode',
'ipv6_ra_mode',
'name',
'network_id',
'subnetpool_id',
'tenant_id'
]
for subnet in subnets:
subnet_metadata = {
k: subnet[k] for k in subnet if k in allowed_keys}
subnets_metadata[subnet["id"]] = subnet_metadata
return subnets_metadata
except Exception as e:
LOG.exception("List all summary subnets from neutron failed.")
raise exception.GetProtectionNetworkSubResourceFailed(
type=self._SUPPORT_RESOURCE_TYPES,
reason=six.text_type(e))
else:
return []
def _get_resources_by_port(self, cntxt, neutron_client):
try:
ports = neutron_client.list_ports().get('ports')
ports_metadata = {}
allowed_keys = [
'admin_state_up',
'allowed_address_pairs',
'description',
'device_id',
'device_owner',
'extra_dhcp_opts',
'fixed_ips',
'id',
'mac_address',
'name',
'network_id',
'port_security_enabled',
'security_groups',
'status',
'tenant_id'
]
for port in ports:
port_metadata = {
k: port[k] for k in port if k in allowed_keys}
ports_metadata[port["id"]] = port_metadata
return ports_metadata
except Exception as e:
LOG.exception("List all summary ports from neutron failed.")
raise exception.GetProtectionNetworkSubResourceFailed(
type=self._SUPPORT_RESOURCE_TYPES,
reason=six.text_type(e))
else:
return []
def _get_resources_by_router(self, cntxt, neutron_client):
try:
routers = neutron_client.list_routers().get('routers')
routers_metadata = {}
allowed_keys = [
'admin_state_u',
'availability_zone_hints',
'description',
'external_gateway_info',
'id',
'name',
'routes',
'status'
]
for router in routers:
router_metadata = {
k: router[k] for k in router if k in allowed_keys}
routers_metadata[router["id"]] = router_metadata
return routers_metadata
except Exception as e:
LOG.exception("List all summary routers from neutron failed.")
raise exception.GetProtectionNetworkSubResourceFailed(
type=self._SUPPORT_RESOURCE_TYPES,
reason=six.text_type(e))
else:
return []
def _get_resources_by_security_group(self, cntxt, neutron_client):
try:
sgs = neutron_client.list_security_groups().get('security_groups')
sgs_metadata = {}
allowed_keys = [
'id',
'description',
'name',
'security_group_rules',
'tenant_id'
]
for sg in sgs:
sg_metadata = {k: sg[k] for k in sg if k in allowed_keys}
sgs_metadata[sg["id"]] = sg_metadata
return sgs_metadata
except Exception as e:
LOG.exception("List all summary security_groups from neutron "
"failed.")
raise exception.GetProtectionNetworkSubResourceFailed(
type=self._SUPPORT_RESOURCE_TYPES,
reason=six.text_type(e))
else:
return []
def on_main(self, checkpoint, resource, context, parameters, **kwargs):
network_id = get_network_id(context)
backup_name = kwargs.get("backup_name", "karbor network backup")
bank_section = checkpoint.get_resource_bank_section(network_id)
neutron_client = ClientFactory.create_client("neutron", context)
resource_definition = {"resource_id": network_id}
resource_definition["backup_name"] = backup_name
resource_definition["network_metadata"] = (
self._get_resources_by_network(context, neutron_client))
resource_definition["subnet_metadata"] = (
self._get_resources_by_subnet(context, neutron_client))
resource_definition["port_metadata"] = (
self._get_resources_by_port(context, neutron_client))
resource_definition["router_metadata"] = (
self._get_resources_by_router(context, neutron_client))
resource_definition["security-group_metadata"] = (
self._get_resources_by_security_group(context, neutron_client))
try:
bank_section.update_object("status",
constants.RESOURCE_STATUS_PROTECTING)
# write resource_definition in bank
bank_section.update_object("metadata", resource_definition)
# update resource_definition backup_status
bank_section.update_object("status",
constants.CHECKPOINT_STATUS_AVAILABLE)
LOG.info("finish backup network, network_id: %s.", network_id)
except Exception as err:
# update resource_definition backup_status
LOG.error("create backup failed, network_id: %s.", network_id)
bank_section.update_object("status",
constants.CHECKPOINT_STATUS_ERROR)
raise exception.CreateBackupFailed(
reason=err,
resource_id=network_id,
resource_type=self._SUPPORT_RESOURCE_TYPES)
class RestoreOperation(protection_plugin.Operation):
def _heat_restore_networks(self, heat_template, nets_meta):
for net_meta in nets_meta:
net_data = nets_meta[net_meta]
if net_data["router:external"]:
continue
heat_resource_id = net_data["name"]
net_heat_resource = HeatResource(heat_resource_id,
constants.NET_RESOURCE_TYPE)
properties = {}
properties["admin_state_up"] = net_data["admin_state_up"]
properties["port_security_enabled"] = (
net_data["port_security_enabled"])
properties["shared"] = net_data["shared"]
properties["name"] = net_data["name"]
for key, value in properties.items():
net_heat_resource.set_property(key, value)
heat_template.put_resource(heat_resource_id, net_heat_resource)
def _get_dependent_net(self, network_id, nets_meta):
for net_meta in nets_meta:
net_data = nets_meta[net_meta]
if network_id == net_data["id"]:
return net_data["name"]
def _is_external_subnet(self, network_id, nets_meta):
for net_meta in nets_meta:
net_data = nets_meta[net_meta]
if network_id == net_data["id"]:
return net_data["router:external"]
def _heat_restore_subnets(self, heat_template, nets_meta, subs_meta):
for sub_meta in subs_meta:
sub_data = subs_meta[sub_meta]
is_ext_subnet = self._is_external_subnet(sub_data["network_id"],
nets_meta)
if is_ext_subnet:
continue
heat_resource_id = sub_data["name"]
sub_heat_resource = HeatResource(heat_resource_id,
constants.SUBNET_RESOURCE_TYPE)
properties = {}
properties["cidr"] = sub_data["cidr"]
properties["allocation_pools"] = sub_data["allocation_pools"]
properties["dns_nameservers"] = sub_data["dns_nameservers"]
properties["enable_dhcp"] = sub_data["enable_dhcp"]
properties["gateway_ip"] = sub_data["gateway_ip"]
properties["host_routes"] = sub_data["host_routes"]
properties["name"] = sub_data["name"]
properties["ip_version"] = sub_data["ip_version"]
net_name = self._get_dependent_net(sub_data["network_id"],
nets_meta)
properties["network_id"] = (
heat_template.get_resource_reference(net_name))
properties["tenant_id"] = sub_data["tenant_id"]
for key, value in properties.items():
sub_heat_resource.set_property(key, value)
heat_template.put_resource(heat_resource_id, sub_heat_resource)
def _get_subnet_by_subnetid(self, subnet_id, subs_meta):
for sub_meta in subs_meta:
sub_data = subs_meta[sub_meta]
if subnet_id == sub_data["id"]:
return sub_data["name"]
return ""
def _get_new_fixed_ips(self, heat_template, subs_meta, fixed_ips_meta):
new_fixed_ips = []
for fixed_ip in fixed_ips_meta:
properties = {}
properties["ip_address"] = fixed_ip["ip_address"]
subnet_name = self._get_subnet_by_subnetid(fixed_ip["subnet_id"],
subs_meta)
properties["subnet_id"] = (
heat_template.get_resource_reference(subnet_name))
new_fixed_ips.append(properties)
return new_fixed_ips
def _heat_restore_ports(self, heat_template,
nets_meta, subs_meta, ports_meta):
for port_meta in ports_meta:
port_data = ports_meta[port_meta]
heat_resource_id = port_data["name"]
port_heat_resource = HeatResource(heat_resource_id,
constants.PORT_RESOURCE_TYPE)
if (port_data["device_owner"] == "network:router_interface") or (
port_data["device_owner"] == "network:router_gateway") or (
port_data["device_owner"] == "network:dhcp") or (
port_data["device_owner"] == "network:floatingip"):
continue
properties = {}
properties["admin_state_up"] = port_data["admin_state_up"]
properties["allowed_address_pairs"] = (
port_data["allowed_address_pairs"])
properties["device_id"] = port_data["device_id"]
properties["device_owner"] = port_data["device_owner"]
new_fixed_ips = self._get_new_fixed_ips(heat_template,
subs_meta,
port_data["fixed_ips"])
properties["fixed_ips"] = new_fixed_ips
properties["mac_address"] = port_data["mac_address"]
properties["name"] = port_data["name"]
net_name = self._get_dependent_net(port_data["network_id"],
nets_meta)
properties["network_id"] = (
heat_template.get_resource_reference(net_name))
properties["port_security_enabled"] = (
port_data["port_security_enabled"])
properties["security_groups"] = port_data["security_groups"]
for key, value in properties.items():
port_heat_resource.set_property(key, value)
heat_template.put_resource(heat_resource_id, port_heat_resource)
def _get_new_external_gateway(self, public_network_id,
gateway_info, subs_meta, neutron_client):
new_ext_gw = {}
# get public network id
if not public_network_id:
networks = neutron_client.list_networks().get('networks')
for network in networks:
if network['router:external'] is True:
public_network_id = network['id']
break
new_ext_gw["network"] = public_network_id
new_ext_gw["enable_snat"] = gateway_info["enable_snat"]
return new_ext_gw
def _heat_restore_routers(self, public_network_id, heat_template,
subs_meta, routers_meta, neutron_client):
for router_meta in routers_meta:
router_data = routers_meta[router_meta]
heat_resource_id = router_data["name"]
router_heat_resource = HeatResource(heat_resource_id,
constants.ROUTER_RESOURCE_TYPE)
properties = {}
org_external_gateway = router_data["external_gateway_info"]
new_external_gateway = (
self._get_new_external_gateway(public_network_id,
org_external_gateway,
subs_meta,
neutron_client))
properties["external_gateway_info"] = new_external_gateway
properties["name"] = router_data["name"]
for key, value in properties.items():
router_heat_resource.set_property(key, value)
heat_template.put_resource(heat_resource_id, router_heat_resource)
def _get_router_name(self, device_id, routers_meta):
for router_meta in routers_meta:
router_data = routers_meta[router_meta]
if device_id == router_data["id"]:
return router_data["name"]
return ""
def _get_subnet_name_by_fixed_ips(self, fixed_ips, subs_meta):
subnet_id = fixed_ips[0]["subnet_id"]
for sub_meta in subs_meta:
sub_data = subs_meta[sub_meta]
if subnet_id == sub_data["id"]:
return sub_data["name"]
return ""
def _heat_restore_routerinterfaces(self, heat_template,
subs_meta, routers_meta, ports_meta):
for port_meta in ports_meta:
port_data = ports_meta[port_meta]
heat_resource_id = str(uuid4())
port_heat_resource = (
HeatResource(heat_resource_id,
constants.ROUTERINTERFACE_RESOURCE_TYPE))
if port_data["device_owner"] != "network:router_interface":
continue
properties = {}
router_name = self._get_router_name(port_data["device_id"],
routers_meta)
properties["router"] = (
heat_template.get_resource_reference(router_name))
subnet_name = (
self._get_subnet_name_by_fixed_ips(port_data["fixed_ips"],
subs_meta))
properties["subnet"] = (
heat_template.get_resource_reference(subnet_name))
for key, value in properties.items():
port_heat_resource.set_property(key, value)
heat_template.put_resource(heat_resource_id, port_heat_resource)
def _get_security_group_rules(self, security_group_rules):
new_security_group_rules = []
for sg in security_group_rules:
if sg["remote_ip_prefix"] is None:
continue
security_group_rule = {}
security_group_rule["direction"] = sg["direction"]
security_group_rule["ethertype"] = sg["ethertype"]
security_group_rule["port_range_max"] = sg["port_range_max"]
security_group_rule["port_range_min"] = sg["port_range_min"]
security_group_rule["protocol"] = sg["protocol"]
security_group_rule["remote_group_id"] = sg["remote_group_id"]
security_group_rule["remote_ip_prefix"] = sg["remote_ip_prefix"]
if "remote_mode" in sg:
security_group_rule["remote_mode"] = sg["remote_mode"]
new_security_group_rules.append(security_group_rule)
return new_security_group_rules
def _heat_restore_securitygroups(self, heat_template, sgs_meta):
for sg_meta in sgs_meta:
sg_data = sgs_meta[sg_meta]
# Skip the default securitygroups
if sg_data["name"] == "default":
continue
heat_resource_id = sg_data["name"]
sg_heat_resource = (
HeatResource(heat_resource_id,
constants.SECURITYGROUP_RESOURCE_TYPE))
properties = {}
sg_rules = sg_data["security_group_rules"]
properties["description"] = sg_data["description"]
properties["name"] = sg_data["name"]
properties["rules"] = self._get_security_group_rules(sg_rules)
for key, value in properties.items():
sg_heat_resource.set_property(key, value)
heat_template.put_resource(heat_resource_id, sg_heat_resource)
def on_main(self, checkpoint, resource, context,
parameters, heat_template, **kwargs):
neutron_client = ClientFactory.create_client("neutron", context)
network_id = get_network_id(context)
public_network_id = parameters.get("public_network_id")
bank_section = checkpoint.get_resource_bank_section(network_id)
try:
resource_definition = bank_section.get_object("metadata")
# Config Net
if "network_metadata" in resource_definition:
nets_meta = resource_definition["network_metadata"]
self._heat_restore_networks(heat_template, nets_meta)
# Config Subnet
if "subnet_metadata" in resource_definition:
subs_meta = resource_definition["subnet_metadata"]
self._heat_restore_subnets(heat_template, nets_meta, subs_meta)
# Config Port
if "port_metadata" in resource_definition:
ports_meta = resource_definition["port_metadata"]
self._heat_restore_ports(heat_template, nets_meta,
subs_meta, ports_meta)
# Config Router
if "router_metadata" in resource_definition:
routers_meta = resource_definition["router_metadata"]
self._heat_restore_routers(public_network_id,
heat_template,
subs_meta,
routers_meta,
neutron_client)
# Config RouterInterface
if [subs_meta is not None] and (
[routers_meta is not None] and [ports_meta is not None]):
self._heat_restore_routerinterfaces(heat_template, subs_meta,
routers_meta, ports_meta)
# Config Securiy-group
if "security-group_metadata" in resource_definition:
sgs_meta = resource_definition["security-group_metadata"]
self._heat_restore_securitygroups(heat_template, sgs_meta)
except Exception as e:
LOG.error("restore network backup failed, network_id: %s.",
network_id)
raise exception.RestoreBackupFailed(
reason=six.text_type(e),
resource_id=network_id,
resource_type=constants.NETWORK_RESOURCE_TYPE
)
class NeutronProtectionPlugin(protection_plugin.ProtectionPlugin):
_SUPPORT_RESOURCE_TYPES = [constants.NETWORK_RESOURCE_TYPE]
def __init__(self, config=None):
super(NeutronProtectionPlugin, self).__init__(config)
@classmethod
def get_supported_resources_types(self):
return self._SUPPORT_RESOURCE_TYPES
@classmethod
def get_options_schema(self, resources_type):
# TODO(chenhuayi)
pass
return network_plugin_schemas.OPTIONS_SCHEMA
@classmethod
def get_restore_schema(self, resources_type):
# TODO(chenhuayi)
pass
return network_plugin_schemas.RESTORE_SCHEMA
@classmethod
def get_saved_info_schema(self, resources_type):
# TODO(chenhuayi)
pass
return network_plugin_schemas.SAVED_INFO_SCHEMA
@classmethod
def get_saved_info(self, metadata_store, resource):
@ -45,12 +566,10 @@ class NeutronProtectionPlugin(protection_plugin.ProtectionPlugin):
pass
def get_protect_operation(self, resource):
# TODO(chenhuayi)
pass
return ProtectOperation()
def get_restore_operation(self, resource):
# TODO(chenhuayi)
pass
return RestoreOperation()
def get_delete_operation(self, resource):
# TODO(chenhuayi)

View File

@ -170,6 +170,25 @@ class RestoresTest(karbor_base.KarborBaseTest):
self.assertEqual(1, len(item.resources_status))
self._store(item.resources_status)
def test_restore_network_resources(self):
network = self.store(objects.Network())
network.create()
plan = self.store(objects.Plan())
plan.create(self.provider_id_os, [network, ])
checkpoint = self.store(objects.Checkpoint())
checkpoint.create(self.provider_id_os, plan.id)
network.close()
restore_target = self.get_restore_target(self.keystone_endpoint)
restore = self.store(objects.Restore())
restore.create(self.provider_id_os, checkpoint.id,
restore_target, self.parameters, self.restore_auth)
item = self.karbor_client.restores.get(restore.id)
self.assertEqual(constants.RESTORE_STATUS_SUCCESS,
item.status)
self._store(item.resources_status)
def test_restore_resources_with_fs_bank(self):
volume = self.store(objects.Volume())
volume.create(1)

View File

@ -0,0 +1,342 @@
# 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 collections
from karbor.common import constants
from karbor.context import RequestContext
from karbor.resource import Resource
from karbor.services.protection.bank_plugin import Bank
from karbor.services.protection.bank_plugin import BankPlugin
from karbor.services.protection.bank_plugin import BankSection
from karbor.services.protection import client_factory
from karbor.services.protection.protection_plugins.network \
import network_plugin_schemas
from karbor.services.protection.protection_plugins.network. \
neutron_protection_plugin import NeutronProtectionPlugin
from karbor.tests import base
import mock
from oslo_config import cfg
FakeNetworks = {'networks': [
{u'status': u'ACTIVE',
u'router:external': False,
u'availability_zone_hints': [],
u'availability_zones': [u'nova'],
u'ipv4_address_scope': None,
u'description': u'',
u'provider:physical_network': None,
u'subnets': [u'129f1bc5-4282-4f9d-ae60-4db1e1cac22d',
u'0b42e051-5a33-4ac4-9a4f-691d0891d760'],
u'updated_at': u'2016-04-23T05:07:06',
u'tenant_id': u'f6f6d0b2591f41acb8257656d70029fc',
u'created_at': u'2016-04-23T05:07:06',
u'tags': [],
u'ipv6_address_scope': None,
u'provider:segmentation_id': 1057,
u'provider:network_type': u'vxlan',
u'port_security_enabled': True,
u'admin_state_up': True,
u'shared': False,
u'mtu': 1450,
u'id': u'9b68fb64-39d4-4d41-8cc9-f27846c6e5f5',
u'name': u'private'},
{u'provider:physical_network': None,
u'ipv6_address_scope': None,
u'port_security_enabled': True,
u'provider:network_type': u'local',
u'id': u'49ef013d-9bb2-4b8f-9eea-e45563efc420',
u'router:external': True,
u'availability_zone_hints': [],
u'availability_zones': [u'nova'],
u'ipv4_address_scope': None,
u'shared': False,
u'status': u'ACTIVE',
u'subnets': [u'808c3b3f-3d79-4c5b-a5b6-95dd07abeb2d'],
u'description': u'',
u'tags': [],
u'updated_at': u'2016-04-25T07:14:53',
u'is_default': False,
u'provider:segmentation_id': None,
u'name': u'ext_net',
u'admin_state_up': True,
u'tenant_id': u'f6f6d0b2591f41acb8257656d70029fc',
u'created_at': u'2016-04-25T07:14:53',
u'mtu': 1500}
]}
FakeSubnets = {'subnets': [
{u'description': u'',
u'enable_dhcp': True,
u'network_id': u'49ef013d-9bb2-4b8f-9eea-e45563efc420',
u'tenant_id': u'f6f6d0b2591f41acb8257656d70029fc',
u'created_at': u'2016-04-25T07:15:25',
u'dns_nameservers': [],
u'updated_at': u'2016-04-25T07:15:25',
u'ipv6_ra_mode': None,
u'allocation_pools': [{u'start': u'192.168.21.2',
u'end': u'192.168.21.254'}],
u'gateway_ip': u'192.168.21.1',
u'ipv6_address_mode': None,
u'ip_version': 4,
u'host_routes': [],
u'cidr': u'192.168.21.0/24',
u'id': u'808c3b3f-3d79-4c5b-a5b6-95dd07abeb2d',
u'subnetpool_id': None,
u'name': u'ext_subnet'},
]}
FakePorts = {'ports': [
{u'allowed_address_pairs': [],
u'extra_dhcp_opts': [],
u'updated_at': u'2016-04-25T07:15:59',
u'device_owner':
u'network:router_gateway',
u'port_security_enabled': False,
u'binding:profile': {},
u'fixed_ips': [{u'subnet_id': u'808c3b3f-3d79-4c5b-a5b6-95dd07abeb2d',
u'ip_address': u'192.168.21.3'}],
u'id': u'2b34c97a-4ccc-44c0-bc50-b7bbfc3508eb',
u'security_groups': [],
u'binding:vif_details': {},
u'binding:vif_type': u'unbound',
u'mac_address': u'fa:16:3e:00:47:f2',
u'status': u'DOWN',
u'binding:host_id': u'',
u'description': u'',
u'device_id': u'7fc86d4b-4c0e-4ed8-8d39-e27b7c1b7ae8',
u'name': u'',
u'admin_state_up': True,
u'network_id': u'49ef013d-9bb2-4b8f-9eea-e45563efc420',
u'dns_name': None,
u'created_at': u'2016-04-25T07:15:59',
u'binding:vnic_type': u'normal',
u'tenant_id': u''},
]}
FakeRoutes = {'routers': [
{u'status': u'ACTIVE',
u'external_gateway_info':
{u'network_id': u'49ef013d-9bb2-4b8f-9eea-e45563efc420',
u'enable_snat': True,
u'external_fixed_ips':
[{u'subnet_id': u'808c3b3f-3d79-4c5b-a5b6-95dd07abeb2d',
u'ip_address': u'192.168.21.3'}
]},
u'availability_zone_hints': [],
u'availability_zones': [],
u'description': u'',
u'admin_state_up': True,
u'tenant_id': u'f6f6d0b2591f41acb8257656d70029fc',
u'distributed': False,
u'routes': [],
u'ha': False,
u'id': u'7fc86d4b-4c0e-4ed8-8d39-e27b7c1b7ae8',
u'name': u'provider_route'}
]}
FakeSecGroup = {'security_groups': [
{u'tenant_id': u'23b119d06168447c8dbb4483d9567bd8',
u'name': u'default',
u'id': u'97910ed4-1dcb-4704-8814-3ddca818ac16',
u'description': u'Default security group',
u'security_group_rules': [
{u'remote_group_id': u'ac4a6134-0176-44db-abab-559d284c4cdc',
u'direction': u'ingress',
u'protocol': None,
u'description': u'',
u'ethertype': u'IPv4',
u'remote_ip_prefix': None,
u'port_range_max': None,
u'security_group_id': u'ac4a6134-0176-44db-abab-559d284c4cdc',
u'port_range_min': None,
u'tenant_id': u'23b119d06168447c8dbb4483d9567bd8',
u'id': u'21416a24-6a7a-4830-bbec-1426b21e085a'},
{u'remote_group_id': u'ac4a6134-0176-44db-abab-559d284c4cdc',
u'direction': u'ingress',
u'protocol': None,
u'description': u'',
u'ethertype': u'IPv6',
u'remote_ip_prefix': None,
u'port_range_max': None,
u'security_group_id': u'ac4a6134-0176-44db-abab-559d284c4cdc',
u'port_range_min': None,
u'tenant_id': u'23b119d06168447c8dbb4483d9567bd8',
u'id': u'47f67d6a-4e73-465a-9f4d-d9b850f85f22'},
{u'remote_group_id': None,
u'direction': u'egress',
u'protocol': None,
u'description': u'',
u'ethertype': u'IPv6',
u'remote_ip_prefix': None,
u'port_range_max': None,
u'security_group_id': u'ac4a6134-0176-44db-abab-559d284c4cdc',
u'port_range_min': None,
u'tenant_id': u'23b119d06168447c8dbb4483d9567bd8',
u'id': u'c24e7148-820c-4147-9032-6fcdb96db6f7'}]},
]}
def call_hooks(operation, checkpoint, resource, context, parameters, **kwargs):
def noop(*args, **kwargs):
pass
hooks = (
'on_prepare_begin',
'on_prepare_finish',
'on_main',
'on_complete',
)
for hook_name in hooks:
hook = getattr(operation, hook_name, noop)
hook(checkpoint, resource, context, parameters, **kwargs)
class FakeNeutronClient(object):
def list_networks(self):
return FakeNetworks
def list_subnets(self):
return FakeSubnets
def list_ports(self):
return FakePorts
def list_routers(self):
return FakeRoutes
def list_security_groups(self):
return FakeSecGroup
class FakeBankPlugin(BankPlugin):
def __init__(self):
self._objects = {}
def create_object(self, key, value):
self._objects[key] = value
def update_object(self, key, value):
self._objects[key] = value
def get_object(self, key):
value = self._objects.get(key, None)
if value is None:
raise Exception
return value
def list_objects(self, prefix=None, limit=None, marker=None):
objects_name = []
if prefix is not None:
for key, value in self._objects.items():
if key.find(prefix) == 0:
objects_name.append(key.lstrip(prefix))
else:
objects_name = self._objects.keys()
return objects_name
def delete_object(self, key):
self._objects.pop(key)
def get_owner_id(self):
return
fake_checkpointid = "checkpoint_id"
fake_project_id = "abcd"
fake_bank = Bank(FakeBankPlugin())
fake_bank_section = BankSection(bank=fake_bank, section="fake")
ResourceNode = collections.namedtuple(
"ResourceNode",
["value"]
)
class CheckpointCollection(object):
def __init__(self):
self.bank_section = fake_bank_section
def get_resource_bank_section(self, resource_id):
return self.bank_section
class NeutronProtectionPluginTest(base.TestCase):
def setUp(self):
super(NeutronProtectionPluginTest, self).setUp()
self.plugin = NeutronProtectionPlugin()
cfg.CONF.set_default('neutron_endpoint',
'http://127.0.0.1:9696',
'neutron_client')
self.cntxt = RequestContext(user_id='admin',
project_id='abcd',
auth_token='efgh')
self.neutron_client = client_factory.ClientFactory.create_client(
"neutron", self.cntxt)
self.checkpoint = CheckpointCollection()
def test_get_options_schema(self):
options_schema = self.plugin.get_options_schema(
'OS::Neutron::Network')
self.assertEqual(options_schema,
network_plugin_schemas.OPTIONS_SCHEMA)
def test_get_restore_schema(self):
options_schema = self.plugin.get_restore_schema(
'OS::Neutron::Network')
self.assertEqual(options_schema,
network_plugin_schemas.RESTORE_SCHEMA)
def test_get_saved_info_schema(self):
options_schema = self.plugin.get_saved_info_schema(
'OS::Neutron::Network')
self.assertEqual(options_schema,
network_plugin_schemas.SAVED_INFO_SCHEMA)
def test_get_supported_resources_types(self):
types = self.plugin.get_supported_resources_types()
self.assertEqual(types,
[constants.NETWORK_RESOURCE_TYPE])
@mock.patch('karbor.services.protection.clients.neutron.create')
def test_create_backup(self, mock_neutron_create):
resource = Resource(id="network_id_1",
type=constants.NETWORK_RESOURCE_TYPE,
name="test")
fake_bank_section.update_object = mock.MagicMock()
protect_operation = self.plugin.get_protect_operation(resource)
mock_neutron_create.return_value = self.neutron_client
self.neutron_client.list_networks = mock.MagicMock()
self.neutron_client.list_networks.return_value = FakeNetworks
self.neutron_client.list_subnets = mock.MagicMock()
self.neutron_client.list_subnets.return_value = FakeSubnets
self.neutron_client.list_ports = mock.MagicMock()
self.neutron_client.list_ports.return_value = FakePorts
self.neutron_client.list_routers = mock.MagicMock()
self.neutron_client.list_routers.return_value = FakeRoutes
self.neutron_client.list_security_groups = mock.MagicMock()
self.neutron_client.list_security_groups.return_value = FakeSecGroup
call_hooks(protect_operation, self.checkpoint, resource, self.cntxt,
{})