Security Group support for Nova and Neutron
We have implemented the API and helpers for Nova and Neutron for the Security Group Resource and Link. Security Group is working just by using json requests. Change-Id: I15ce76a42caa75f158ac1a792aa44d2da8c7e404
This commit is contained in:
parent
647740eb9c
commit
ecf29929d7
|
@ -114,6 +114,13 @@ class BaseHelper(object):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.openstack_version = openstack_version
|
self.openstack_version = openstack_version
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def tenant_from_req(req):
|
||||||
|
try:
|
||||||
|
return req.environ["HTTP_X_PROJECT_ID"]
|
||||||
|
except KeyError:
|
||||||
|
raise exception.Forbidden(reason="Cannot find project ID")
|
||||||
|
|
||||||
def _get_req(self, req, method,
|
def _get_req(self, req, method,
|
||||||
path=None,
|
path=None,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
|
@ -198,17 +205,21 @@ class BaseHelper(object):
|
||||||
return self._get_req(req, path=path,
|
return self._get_req(req, path=path,
|
||||||
query_string=query_string, method="GET")
|
query_string=query_string, method="GET")
|
||||||
|
|
||||||
def _make_create_request(self, req, resource, parameters):
|
def _make_create_request(self, req, resource, parameters,
|
||||||
|
resource_object_name=None):
|
||||||
"""Create CREATE request
|
"""Create CREATE request
|
||||||
|
|
||||||
This method creates a CREATE Request instance
|
This method creates a CREATE Request instance
|
||||||
|
|
||||||
:param req: the incoming request
|
:param req: the incoming request
|
||||||
:param parameters: parameters with values
|
:param parameters: parameters with values
|
||||||
|
:param resource_object_name: in case resource name is different
|
||||||
|
to the response one.
|
||||||
"""
|
"""
|
||||||
path = "/%s" % resource
|
path = "/%s" % resource
|
||||||
single_resource = resource[:-1]
|
if not resource_object_name:
|
||||||
body = utils.make_body(single_resource, parameters)
|
resource_object_name = resource[:-1]
|
||||||
|
body = utils.make_body(resource_object_name, parameters)
|
||||||
return self._get_req(req, path=path,
|
return self._get_req(req, path=path,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
body=json.dumps(body), method="POST")
|
body=json.dumps(body), method="POST")
|
||||||
|
@ -245,13 +256,6 @@ class OpenStackHelper(BaseHelper):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def tenant_from_req(req):
|
|
||||||
try:
|
|
||||||
return req.environ["HTTP_X_PROJECT_ID"]
|
|
||||||
except KeyError:
|
|
||||||
raise exception.Forbidden(reason="Cannot find project ID")
|
|
||||||
|
|
||||||
def _get_index_req(self, req):
|
def _get_index_req(self, req):
|
||||||
tenant_id = self.tenant_from_req(req)
|
tenant_id = self.tenant_from_req(req)
|
||||||
path = "/%s/servers" % tenant_id
|
path = "/%s/servers" % tenant_id
|
||||||
|
@ -1009,3 +1013,237 @@ class OpenStackHelper(BaseHelper):
|
||||||
os_req = self._get_req(req, path=path, method="DELETE")
|
os_req = self._get_req(req, path=path, method="DELETE")
|
||||||
os_req.get_response(self.app)
|
os_req.get_response(self.app)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def _get_security_group(self, req, sec_id):
|
||||||
|
"""Retrieve info about a security group.
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
:param sec_id: security group id to show
|
||||||
|
"""
|
||||||
|
path = "os-security-groups"
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
path = "/%s/%s/%s" % (tenant_id, path, sec_id)
|
||||||
|
os_req = self._get_req(req, path=path,
|
||||||
|
method="GET")
|
||||||
|
response = os_req.get_response(self.app)
|
||||||
|
return self.get_from_response(response, "security_group", [])
|
||||||
|
|
||||||
|
def get_security_group_details(self, req, sec_id):
|
||||||
|
"""Get details about a security group.
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
:param sec_id: security group id to show
|
||||||
|
"""
|
||||||
|
net = self._get_security_group(req, sec_id)
|
||||||
|
ooi_sec = os_helpers.build_security_group_from_nova([net])
|
||||||
|
return ooi_sec[0]
|
||||||
|
|
||||||
|
def list_security_groups(self, req):
|
||||||
|
"""List security groups
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
"""
|
||||||
|
path = "os-security-groups"
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
path = "/%s/%s" % (tenant_id, path)
|
||||||
|
os_req = self._get_req(req, path=path,
|
||||||
|
method="GET")
|
||||||
|
response = os_req.get_response(self.app)
|
||||||
|
sec = self.get_from_response(response, "security_groups", [])
|
||||||
|
ooi_sec = os_helpers.build_security_group_from_nova(sec)
|
||||||
|
return ooi_sec
|
||||||
|
|
||||||
|
def create_security_group(self, req, name, description, rules):
|
||||||
|
"""Create security group
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
:param name: security group name
|
||||||
|
:param description: security group description
|
||||||
|
:param rules: security group rules
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
path = "os-security-groups"
|
||||||
|
path = "/%s/%s" % (tenant_id, path)
|
||||||
|
param_group = {
|
||||||
|
"description": description,
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
body = utils.make_body('security_group', param_group)
|
||||||
|
os_req = self._get_req(req,
|
||||||
|
path=path,
|
||||||
|
content_type="application/json",
|
||||||
|
body=json.dumps(body),
|
||||||
|
method="POST")
|
||||||
|
response_group = os_req.get_response(self.app)
|
||||||
|
secgroup = self.get_from_response(
|
||||||
|
response_group, "security_group", {})
|
||||||
|
sec_id = secgroup["id"]
|
||||||
|
secgroup["rules"] = []
|
||||||
|
for rule in rules:
|
||||||
|
port_min, port_max = os_helpers.security_group_rule_port(
|
||||||
|
rule["port"]
|
||||||
|
)
|
||||||
|
param_rules = {
|
||||||
|
"parent_group_id": sec_id,
|
||||||
|
"ip_protocol": rule["protocol"],
|
||||||
|
"from_port": port_min,
|
||||||
|
"to_port": port_max,
|
||||||
|
"cidr": rule.get("range", "0.0.0.0/0")
|
||||||
|
}
|
||||||
|
body_rules = utils.make_body('security_group_rule',
|
||||||
|
param_rules)
|
||||||
|
path = "/%s/os-security-group-rules" % (tenant_id)
|
||||||
|
os_req_rules = self._get_req(req,
|
||||||
|
path=path,
|
||||||
|
content_type="application/json",
|
||||||
|
body=json.dumps(body_rules),
|
||||||
|
method="POST")
|
||||||
|
response_rules = os_req_rules.get_response(self.app)
|
||||||
|
secrules = self.get_from_response(
|
||||||
|
response_rules, "security_group_rule", {})
|
||||||
|
secgroup["rules"].append(secrules)
|
||||||
|
ooi_sec = os_helpers.build_security_group_from_nova(
|
||||||
|
[secgroup]
|
||||||
|
)
|
||||||
|
return ooi_sec[0]
|
||||||
|
except Exception as ex:
|
||||||
|
raise ex
|
||||||
|
|
||||||
|
def delete_security_group(self, req, sec_id):
|
||||||
|
"""Delete info about a security group.
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
:param sec_id: security group id to delete
|
||||||
|
"""
|
||||||
|
path = "os-security-groups"
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
path = "/%s/%s/%s" % (tenant_id, path, sec_id)
|
||||||
|
os_req = self._get_req(req, path=path,
|
||||||
|
method="DELETE")
|
||||||
|
os_req.get_response(self.app)
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _get_server_security_group(self, req, server_id):
|
||||||
|
"""Get security group from a server
|
||||||
|
|
||||||
|
:param req: incoming request
|
||||||
|
:param server_id: server id
|
||||||
|
:return: information about the security group
|
||||||
|
"""
|
||||||
|
path = "os-security-groups"
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
path = "/%s/servers/%s/%s" % (tenant_id,
|
||||||
|
server_id,
|
||||||
|
path
|
||||||
|
)
|
||||||
|
os_req = self._get_req(req, path=path,
|
||||||
|
method="GET")
|
||||||
|
response = os_req.get_response(self.app)
|
||||||
|
sec = self.get_from_response(response,
|
||||||
|
"security_groups", [])
|
||||||
|
ooi_sec = os_helpers.build_security_group_from_nova(sec)
|
||||||
|
return ooi_sec
|
||||||
|
|
||||||
|
def list_server_security_groups(self, req,
|
||||||
|
server_id=None):
|
||||||
|
"""List security groups associated to a server
|
||||||
|
|
||||||
|
:param req: incoming request
|
||||||
|
:param server_id: server id
|
||||||
|
:return: security groups associated to servers
|
||||||
|
"""
|
||||||
|
return self._get_server_security_group(
|
||||||
|
req, server_id)
|
||||||
|
|
||||||
|
def list_server_security_links(self, req, server_id=None):
|
||||||
|
"""List security groups associated to servers
|
||||||
|
|
||||||
|
:param req: incoming request
|
||||||
|
:param server_id: server id
|
||||||
|
:return: security groups associated to servers
|
||||||
|
"""
|
||||||
|
link_list = []
|
||||||
|
if server_id:
|
||||||
|
compute_list = [self.get_server(req, server_id)]
|
||||||
|
else:
|
||||||
|
compute_list = self.index(req)
|
||||||
|
for c in compute_list:
|
||||||
|
server_id = c["id"]
|
||||||
|
server_secgroups = self._get_server_security_group(
|
||||||
|
req, server_id)
|
||||||
|
for sec in server_secgroups:
|
||||||
|
link = {
|
||||||
|
"compute_id": server_id,
|
||||||
|
"securitygroup": sec
|
||||||
|
}
|
||||||
|
link_list.append(link)
|
||||||
|
return link_list
|
||||||
|
|
||||||
|
def get_server_security_link(self, req, server_id,
|
||||||
|
securitygroup_id):
|
||||||
|
"""Show security group link from a server
|
||||||
|
|
||||||
|
:param req: incoming request
|
||||||
|
:param server_id: server id
|
||||||
|
:param securitygroup_id: security group id
|
||||||
|
:return: information about the link of security group
|
||||||
|
"""
|
||||||
|
ooi_sec = self._get_server_security_group(req, server_id)
|
||||||
|
for sg in ooi_sec:
|
||||||
|
if sg["id"] == securitygroup_id:
|
||||||
|
link = {"compute_id": server_id,
|
||||||
|
"securitygroup": sg
|
||||||
|
}
|
||||||
|
return [link]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def delete_server_security_link(self, req, server_id,
|
||||||
|
securitygroup_id):
|
||||||
|
"""Delete security group link from a server
|
||||||
|
|
||||||
|
:param req: incoming request
|
||||||
|
:param server_id: server id
|
||||||
|
:param securitygroup_id: segurity group id
|
||||||
|
:return: empty
|
||||||
|
"""
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
path = "/%s/servers/%s/action" % (tenant_id, server_id)
|
||||||
|
sg = self._get_security_group(req, securitygroup_id)
|
||||||
|
if "name" not in sg:
|
||||||
|
raise exception.NotFound("Security group %s not found."
|
||||||
|
% securitygroup_id)
|
||||||
|
param = {"name": sg["name"]}
|
||||||
|
body = utils.make_body('removeSecurityGroup', param)
|
||||||
|
os_req = self._get_req(req,
|
||||||
|
path=path,
|
||||||
|
content_type="application/json",
|
||||||
|
body=json.dumps(body),
|
||||||
|
method="POST")
|
||||||
|
os_req.get_response(self.app)
|
||||||
|
return []
|
||||||
|
|
||||||
|
def create_server_security_link(self, req, server_id,
|
||||||
|
securitygroup_id):
|
||||||
|
"""Create security group link in a server
|
||||||
|
|
||||||
|
:param req: incoming request
|
||||||
|
:param server_id: server id
|
||||||
|
:param securitygroup_id: segurity group id
|
||||||
|
:return: empty
|
||||||
|
"""
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
path = "/%s/servers/%s/action" % (tenant_id, server_id)
|
||||||
|
sg = self._get_security_group(req, securitygroup_id)
|
||||||
|
if "name" not in sg:
|
||||||
|
raise exception.NotFound("Security group %s not found."
|
||||||
|
% securitygroup_id)
|
||||||
|
param = {"name": sg["name"]}
|
||||||
|
body = utils.make_body('addSecurityGroup', param)
|
||||||
|
os_req = self._get_req(req,
|
||||||
|
path=path,
|
||||||
|
content_type="application/json",
|
||||||
|
body=json.dumps(body),
|
||||||
|
method="POST")
|
||||||
|
os_req.get_response(self.app)
|
||||||
|
return []
|
||||||
|
|
|
@ -539,3 +539,91 @@ class OpenStackNeutron(helpers.BaseHelper):
|
||||||
response = os_req.get_response()
|
response = os_req.get_response()
|
||||||
if response.status_int != 202:
|
if response.status_int != 202:
|
||||||
raise helpers.exception_from_response(response)
|
raise helpers.exception_from_response(response)
|
||||||
|
|
||||||
|
def get_security_group_details(self, req, sec_id):
|
||||||
|
"""Get info about a security group.
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
:param sec_id: security group id to show
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
secgroup = self.get_resource(req, 'security-groups', sec_id,
|
||||||
|
response_resource="security_group")
|
||||||
|
ooi_sec = os_helpers.build_security_group_from_neutron(
|
||||||
|
[secgroup]
|
||||||
|
)
|
||||||
|
return ooi_sec[0]
|
||||||
|
except Exception:
|
||||||
|
raise exception.NotFound()
|
||||||
|
|
||||||
|
def list_security_groups(self, req):
|
||||||
|
"""List security groups
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
secgroup = self.list_resources(req, 'security-groups',
|
||||||
|
response_resource="security_groups")
|
||||||
|
ooi_sec = os_helpers.build_security_group_from_neutron(
|
||||||
|
secgroup
|
||||||
|
)
|
||||||
|
return ooi_sec
|
||||||
|
except Exception:
|
||||||
|
raise exception.NotFound()
|
||||||
|
|
||||||
|
def create_security_group(self, req, name, description, rules):
|
||||||
|
"""Create security group
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
:param name: security group name
|
||||||
|
:param description: security group description
|
||||||
|
:param rules: security group rules
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
tenant_id = self.tenant_from_req(req)
|
||||||
|
param_group = {"tenant_id": tenant_id,
|
||||||
|
"description": description,
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
secgroup = self.create_resource(
|
||||||
|
req, 'security-groups', param_group,
|
||||||
|
response_resource="security_group")
|
||||||
|
sec_id = secgroup["id"]
|
||||||
|
secgroup["security_group_rules"] = []
|
||||||
|
for rule in rules:
|
||||||
|
port_min, port_max = os_helpers.security_group_rule_port(
|
||||||
|
rule["port"]
|
||||||
|
)
|
||||||
|
param_rule = {
|
||||||
|
"ethertype": rule.get("ipversion", "IPv4"),
|
||||||
|
"port_range_max": port_max,
|
||||||
|
"port_range_min": port_min,
|
||||||
|
"direction": os_helpers.security_group_rule_type(
|
||||||
|
rule["type"]),
|
||||||
|
"remote_ip_prefix": rule.get("range", "0.0.0.0/0"),
|
||||||
|
"protocol": rule["protocol"],
|
||||||
|
"security_group_id": sec_id,
|
||||||
|
}
|
||||||
|
secrule = self.create_resource(
|
||||||
|
req,
|
||||||
|
'security-group-rules', param_rule,
|
||||||
|
response_resource="security_group_rule")
|
||||||
|
secgroup["security_group_rules"].append(secrule)
|
||||||
|
ooi_sec = os_helpers.build_security_group_from_neutron(
|
||||||
|
[secgroup]
|
||||||
|
)
|
||||||
|
return ooi_sec[0]
|
||||||
|
except Exception as ex:
|
||||||
|
raise ex
|
||||||
|
|
||||||
|
def delete_security_group(self, req, sec_id):
|
||||||
|
"""Delete info about a security group.
|
||||||
|
|
||||||
|
:param req: the incoming request
|
||||||
|
:param sec_id: security group id to delete
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
secgroup = self.delete_resource(req, 'security-groups', sec_id)
|
||||||
|
return secgroup
|
||||||
|
except Exception:
|
||||||
|
raise exception.NotFound()
|
|
@ -0,0 +1,192 @@
|
||||||
|
# Copyright 2015 LIP - INDIGO-DataCloud
|
||||||
|
#
|
||||||
|
# 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 ooi.api import base
|
||||||
|
from ooi.api import helpers
|
||||||
|
from ooi.api import helpers_neutron
|
||||||
|
from ooi import exception
|
||||||
|
from ooi.occi.core import collection
|
||||||
|
from ooi.occi.infrastructure import securitygroup
|
||||||
|
from ooi.occi import validator as occi_validator
|
||||||
|
|
||||||
|
|
||||||
|
def parse_validate_schema(req, scheme=None,
|
||||||
|
required_attr=None):
|
||||||
|
"""Parse attributes and validate scheme
|
||||||
|
|
||||||
|
|
||||||
|
Returns attributes from request
|
||||||
|
If scheme is specified, it validates the OCCI scheme:
|
||||||
|
-Raises exception in case of being invalid
|
||||||
|
|
||||||
|
:param req: request
|
||||||
|
:param: scheme: scheme to validate
|
||||||
|
:param: required_attr: attributes required
|
||||||
|
"""
|
||||||
|
parser = req.get_parser()(req.headers, req.body.decode("utf8"))
|
||||||
|
if scheme:
|
||||||
|
attributes = parser.parse()
|
||||||
|
validator = occi_validator.Validator(attributes)
|
||||||
|
validator.validate(scheme)
|
||||||
|
validator.validate_attributes(required_attr)
|
||||||
|
else:
|
||||||
|
attributes = parser.parse_attributes(req.headers)
|
||||||
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
|
def process_parameters(req, scheme=None,
|
||||||
|
required_attr=None):
|
||||||
|
"""Get attributes from request parameters
|
||||||
|
|
||||||
|
:param req: request
|
||||||
|
:param scheme: scheme to validate
|
||||||
|
:param required_attr: attributes required
|
||||||
|
"""
|
||||||
|
parameters = parse_validate_schema(req, scheme, required_attr)
|
||||||
|
try:
|
||||||
|
attributes = {}
|
||||||
|
if 'X_PROJECT_ID' in req.headers:
|
||||||
|
attributes["X_PROJECT_ID"] = req.headers["X_PROJECT_ID"]
|
||||||
|
if "attributes" in parameters:
|
||||||
|
for k, v in parameters.get("attributes", None).items():
|
||||||
|
attributes[k.strip()] = v
|
||||||
|
if not attributes:
|
||||||
|
attributes = None
|
||||||
|
except Exception:
|
||||||
|
raise exception.Invalid
|
||||||
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
|
class Controller(base.Controller):
|
||||||
|
def __init__(self, app=None, openstack_version=None,
|
||||||
|
neutron_ooi_endpoint=None):
|
||||||
|
"""Security group controller initialization
|
||||||
|
|
||||||
|
:param app: application
|
||||||
|
:param: openstack_version: nova version
|
||||||
|
:param: neutron_ooi_endpoint: This parameter
|
||||||
|
indicates the Neutron endpoint to load the Neutron Helper.
|
||||||
|
If it is None, Nova api is used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
super(Controller, self).__init__(
|
||||||
|
app=app,
|
||||||
|
openstack_version=openstack_version)
|
||||||
|
if neutron_ooi_endpoint:
|
||||||
|
self.os_helper = helpers_neutron.OpenStackNeutron(
|
||||||
|
neutron_ooi_endpoint
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.os_helper = helpers.OpenStackHelper(
|
||||||
|
self.app,
|
||||||
|
self.openstack_version
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_security_group_resources(securitygroup_list):
|
||||||
|
"""Create OCCI security group instances from list
|
||||||
|
|
||||||
|
:param securitygroup_list: security group objects
|
||||||
|
provides by the cloud infrastructure
|
||||||
|
:return occi security group list
|
||||||
|
"""
|
||||||
|
occi_securitygroup_resources = []
|
||||||
|
if securitygroup_list:
|
||||||
|
for s in securitygroup_list:
|
||||||
|
s_rules = s['rules']
|
||||||
|
s_id = s["id"]
|
||||||
|
s_name = s["title"]
|
||||||
|
s_summary = s["summary"]
|
||||||
|
s = securitygroup.SecurityGroupResource(title=s_name,
|
||||||
|
id=s_id,
|
||||||
|
rules=s_rules,
|
||||||
|
summary=s_summary)
|
||||||
|
occi_securitygroup_resources.append(s)
|
||||||
|
return occi_securitygroup_resources
|
||||||
|
|
||||||
|
def index(self, req):
|
||||||
|
"""List security groups
|
||||||
|
|
||||||
|
:param req: request object
|
||||||
|
"""
|
||||||
|
occi_sc = self.os_helper.list_security_groups(req)
|
||||||
|
occi_sc_resources = self._get_security_group_resources(
|
||||||
|
occi_sc)
|
||||||
|
|
||||||
|
return collection.Collection(
|
||||||
|
resources=occi_sc_resources)
|
||||||
|
|
||||||
|
def show(self, req, id):
|
||||||
|
"""Get security group details
|
||||||
|
|
||||||
|
:param req: request object
|
||||||
|
:param id: security group identification
|
||||||
|
"""
|
||||||
|
resp = self.os_helper.get_security_group_details(req, id)
|
||||||
|
occi_sc_resources = self._get_security_group_resources(
|
||||||
|
[resp])
|
||||||
|
return occi_sc_resources[0]
|
||||||
|
|
||||||
|
def create(self, req, body=None):
|
||||||
|
"""Create a network instance in the cloud
|
||||||
|
|
||||||
|
:param req: request object
|
||||||
|
:param body: body request (not used)
|
||||||
|
"""
|
||||||
|
scheme = {
|
||||||
|
"category": securitygroup.SecurityGroupResource.kind,
|
||||||
|
}
|
||||||
|
required = ["occi.core.title",
|
||||||
|
"occi.securitygroup.rules"
|
||||||
|
]
|
||||||
|
attributes = process_parameters(req, scheme, required)
|
||||||
|
name = attributes.get('occi.core.title')
|
||||||
|
description = attributes.get("occi.core.summary", "")
|
||||||
|
try:
|
||||||
|
rules = attributes.get('occi.securitygroup.rules')
|
||||||
|
except Exception:
|
||||||
|
raise exception.Invalid(
|
||||||
|
"Bad JSON format for occi.securitygroup.rules: %s"
|
||||||
|
% attributes.get(
|
||||||
|
'occi.securitygroup.rules'))
|
||||||
|
sec = self.os_helper.create_security_group(
|
||||||
|
req, name, description, rules
|
||||||
|
)
|
||||||
|
occi_sec_resources = self._get_security_group_resources([sec])
|
||||||
|
return collection.Collection(
|
||||||
|
resources=occi_sec_resources)
|
||||||
|
|
||||||
|
def delete(self, req, id):
|
||||||
|
"""delete security groups which satisfy the parameters
|
||||||
|
|
||||||
|
:param req: current request
|
||||||
|
:param id: identification
|
||||||
|
"""
|
||||||
|
response = self.os_helper.delete_security_group(req, id)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def run_action(self, req, id, body):
|
||||||
|
"""Run action over the security group
|
||||||
|
|
||||||
|
:param req: current request
|
||||||
|
:param id: security group
|
||||||
|
:param body: body
|
||||||
|
"""
|
||||||
|
action = req.GET.get("action", None)
|
||||||
|
occi_actions = [a.term for a in
|
||||||
|
securitygroup.SecurityGroupResource.actions]
|
||||||
|
|
||||||
|
if action is None or action not in occi_actions:
|
||||||
|
raise exception.InvalidAction(action=action)
|
||||||
|
raise exception.NotImplemented("Security group actions are not implemented")
|
|
@ -0,0 +1,144 @@
|
||||||
|
# Copyright 2015 LIP - INDIGO-DataCloud
|
||||||
|
#
|
||||||
|
# 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 ooi.api import base
|
||||||
|
import ooi.api.helpers
|
||||||
|
from ooi import exception
|
||||||
|
from ooi.occi.core import collection
|
||||||
|
from ooi.occi.infrastructure import compute
|
||||||
|
from ooi.occi.infrastructure import securitygroup
|
||||||
|
from ooi.occi.infrastructure import securitygroup_link
|
||||||
|
from ooi.occi import validator as occi_validator
|
||||||
|
|
||||||
|
|
||||||
|
def _get_security_link_resources(link_list):
|
||||||
|
"""Create OCCI security group instances from a list
|
||||||
|
|
||||||
|
:param link_list: provides by the cloud infrastructure
|
||||||
|
"""
|
||||||
|
occi_secgropu_resources = []
|
||||||
|
if link_list:
|
||||||
|
for l in link_list:
|
||||||
|
compute_id = l['compute_id']
|
||||||
|
sec = l['securitygroup']
|
||||||
|
sec_id = sec.get("id")
|
||||||
|
sec_name = sec.get("title", "")
|
||||||
|
sec_rules = sec.get("rules", [])
|
||||||
|
s = securitygroup.SecurityGroupResource(title=sec_name,
|
||||||
|
id=sec_id,
|
||||||
|
rules=sec_rules)
|
||||||
|
c = compute.ComputeResource(title="Compute",
|
||||||
|
id=compute_id
|
||||||
|
)
|
||||||
|
link = securitygroup_link.SecurityGroupLink(source=c,
|
||||||
|
target=s)
|
||||||
|
occi_secgropu_resources.append(link)
|
||||||
|
return occi_secgropu_resources
|
||||||
|
|
||||||
|
|
||||||
|
class Controller(base.Controller):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(Controller, self).__init__(*args, **kwargs)
|
||||||
|
# TODO(jorgesece): add neutron controller to list securitygroups
|
||||||
|
self.os_helper = ooi.api.helpers.OpenStackHelper(
|
||||||
|
self.app,
|
||||||
|
self.openstack_version
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_attachment_from_id(self, req, attachment_id):
|
||||||
|
try:
|
||||||
|
server_id, security_id = attachment_id.split('_', 1)
|
||||||
|
return {"server_id": server_id,
|
||||||
|
"securitygroup_id": security_id}
|
||||||
|
except ValueError:
|
||||||
|
raise exception.LinkNotFound(link_id=attachment_id)
|
||||||
|
|
||||||
|
def index(self, req):
|
||||||
|
"""List security group links
|
||||||
|
|
||||||
|
:param req: request object
|
||||||
|
"""
|
||||||
|
link_list = self.os_helper.list_server_security_links(req)
|
||||||
|
occi_link_resources = _get_security_link_resources(link_list)
|
||||||
|
return collection.Collection(resources=occi_link_resources)
|
||||||
|
|
||||||
|
def show(self, req, id):
|
||||||
|
"""Get security group details
|
||||||
|
|
||||||
|
:param req: request object
|
||||||
|
:param id: security group identification
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
link_info = self._get_attachment_from_id(req, id)
|
||||||
|
server_id = link_info["server_id"]
|
||||||
|
security_name = link_info["securitygroup_id"]
|
||||||
|
link = self.os_helper.get_server_security_link(
|
||||||
|
req, server_id, security_name
|
||||||
|
)
|
||||||
|
occi_instance = _get_security_link_resources(
|
||||||
|
link
|
||||||
|
)[0]
|
||||||
|
return occi_instance
|
||||||
|
except Exception:
|
||||||
|
raise exception.LinkNotFound(link_id=id)
|
||||||
|
|
||||||
|
def create(self, req, body=None):
|
||||||
|
"""Create a security group link
|
||||||
|
|
||||||
|
Creates a link between a server and a securitygroup.
|
||||||
|
|
||||||
|
:param req: request object
|
||||||
|
:param body: body request (not used)
|
||||||
|
"""
|
||||||
|
parser = req.get_parser()(req.headers, req.body)
|
||||||
|
scheme = {
|
||||||
|
"category": securitygroup_link.SecurityGroupLink.kind,
|
||||||
|
}
|
||||||
|
obj = parser.parse()
|
||||||
|
validator = occi_validator.Validator(obj)
|
||||||
|
validator.validate(scheme)
|
||||||
|
attrs = obj.get("attributes", {})
|
||||||
|
_, securitygroup_id = ooi.api.helpers.get_id_with_kind(
|
||||||
|
req,
|
||||||
|
attrs.get("occi.core.target"),
|
||||||
|
securitygroup.SecurityGroupResource.kind)
|
||||||
|
_, server_id = ooi.api.helpers.get_id_with_kind(
|
||||||
|
req,
|
||||||
|
attrs.get("occi.core.source"),
|
||||||
|
compute.ComputeResource.kind)
|
||||||
|
self.os_helper.create_server_security_link(
|
||||||
|
req, server_id,
|
||||||
|
securitygroup_id)
|
||||||
|
link = {"compute_id": server_id,
|
||||||
|
"securitygroup": {"id": securitygroup_id}
|
||||||
|
}
|
||||||
|
occi_instance = _get_security_link_resources([link])
|
||||||
|
return collection.Collection(resources=occi_instance)
|
||||||
|
|
||||||
|
def delete(self, req, id):
|
||||||
|
"""Delete security group link
|
||||||
|
|
||||||
|
:param req: current request
|
||||||
|
:param id: identification
|
||||||
|
"""
|
||||||
|
link_info = self._get_attachment_from_id(req, id)
|
||||||
|
server_id = link_info["server_id"]
|
||||||
|
security_id = link_info["securitygroup_id"]
|
||||||
|
try:
|
||||||
|
self.os_helper.delete_server_security_link(
|
||||||
|
req, server_id, security_id)
|
||||||
|
except Exception:
|
||||||
|
raise exception.LinkNotFound(link_id=id)
|
||||||
|
return []
|
|
@ -46,3 +46,118 @@ def network_status(neutron_status):
|
||||||
return "active"
|
return "active"
|
||||||
else:
|
else:
|
||||||
return "inactive"
|
return "inactive"
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_rule_type(neutron_type):
|
||||||
|
"""Translate neutron rule type.
|
||||||
|
|
||||||
|
Translate to/from openstack - occi
|
||||||
|
|
||||||
|
:param neutron_type: neutron status
|
||||||
|
"""
|
||||||
|
if neutron_type == "ingress":
|
||||||
|
return "inbound"
|
||||||
|
elif neutron_type == "egress":
|
||||||
|
return "outbound"
|
||||||
|
elif neutron_type == "inbound":
|
||||||
|
return "ingress"
|
||||||
|
elif neutron_type == "outbound":
|
||||||
|
return "egress"
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_rule_port(os_port):
|
||||||
|
"""Translate openstack rule port
|
||||||
|
|
||||||
|
Translate to/from openstack - occi
|
||||||
|
|
||||||
|
:param neutron_type: neutron status
|
||||||
|
"""
|
||||||
|
ports = str(os_port).split('-')
|
||||||
|
if ports.__len__() == 1:
|
||||||
|
port_min = port_max = ports[0]
|
||||||
|
elif ports.__len__() == 2:
|
||||||
|
port_min, port_max = ports
|
||||||
|
else:
|
||||||
|
raise Exception("Port value")
|
||||||
|
return port_min, port_max
|
||||||
|
|
||||||
|
|
||||||
|
def build_security_group_from_neutron(sec_groups):
|
||||||
|
"""Translate neutron security group
|
||||||
|
|
||||||
|
Translate to the ooi a standard security group format.
|
||||||
|
|
||||||
|
:param sec_groups: array of security groups
|
||||||
|
"""
|
||||||
|
sec_list = []
|
||||||
|
for sec in sec_groups:
|
||||||
|
ooi_sec = {}
|
||||||
|
rules_list = []
|
||||||
|
ooi_sec["id"] = sec["id"]
|
||||||
|
ooi_sec["title"] = sec.get("name", None)
|
||||||
|
ooi_sec["summary"] = sec.get("description", "")
|
||||||
|
for rule in sec["security_group_rules"]:
|
||||||
|
ipversion = rule.get("ethertype", "IPv4")
|
||||||
|
rule_type = security_group_rule_type(
|
||||||
|
rule["direction"]
|
||||||
|
)
|
||||||
|
rule_protocol = rule.get("protocol", None)
|
||||||
|
port_min = rule["port_range_min"]
|
||||||
|
port_max = rule["port_range_max"]
|
||||||
|
if port_min and (port_min != port_max):
|
||||||
|
rule_port = "%s-%s" % (port_min,
|
||||||
|
port_max
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
rule_port = port_min
|
||||||
|
rule_range = str(rule["remote_ip_prefix"])
|
||||||
|
rules_list.append({"type": rule_type,
|
||||||
|
"protocol": rule_protocol,
|
||||||
|
"port": rule_port,
|
||||||
|
"range": rule_range,
|
||||||
|
"ipversion": ipversion}
|
||||||
|
)
|
||||||
|
ooi_sec["rules"] = rules_list
|
||||||
|
sec_list.append(ooi_sec)
|
||||||
|
return sec_list
|
||||||
|
|
||||||
|
|
||||||
|
def build_security_group_from_nova(sec_groups):
|
||||||
|
"""Translate nova security group
|
||||||
|
|
||||||
|
Translate to the ooi a standard security group format.
|
||||||
|
|
||||||
|
:param sec_groups: array of security groups
|
||||||
|
"""
|
||||||
|
sec_list = []
|
||||||
|
for sec in sec_groups:
|
||||||
|
ooi_sec = {}
|
||||||
|
rules_list = []
|
||||||
|
ooi_sec["id"] = sec["id"]
|
||||||
|
ooi_sec["title"] = sec.get("name", None)
|
||||||
|
ooi_sec["summary"] = sec.get("description", "")
|
||||||
|
for rule in sec["rules"]:
|
||||||
|
ipversion = "IPv4"
|
||||||
|
rule_protocol = rule.get("ip_protocol", None)
|
||||||
|
port_min = rule["from_port"]
|
||||||
|
port_max = rule["to_port"]
|
||||||
|
if port_min and (port_min != port_max):
|
||||||
|
rule_port = "%s-%s" % (port_min,
|
||||||
|
port_max
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
rule_port = port_min
|
||||||
|
rule_range = str(rule["ip_range"].get("cidr", ""))
|
||||||
|
# BUG(jorgesce): type is alwayns inbound because nova
|
||||||
|
# does not provide that information.
|
||||||
|
rules_list.append({"type": "inbound",
|
||||||
|
"protocol": rule_protocol,
|
||||||
|
"port": rule_port,
|
||||||
|
"range": rule_range,
|
||||||
|
"ipversion": ipversion}
|
||||||
|
)
|
||||||
|
ooi_sec["rules"] = rules_list
|
||||||
|
sec_list.append(ooi_sec)
|
||||||
|
return sec_list
|
|
@ -194,6 +194,10 @@ servers = {
|
||||||
"flavor": {"id": flavors[1]["id"]},
|
"flavor": {"id": flavors[1]["id"]},
|
||||||
"image": {"id": images["foo"]["id"]},
|
"image": {"id": images["foo"]["id"]},
|
||||||
"status": "ACTIVE",
|
"status": "ACTIVE",
|
||||||
|
"security_groups":[
|
||||||
|
{"name": "group1"},
|
||||||
|
{"name": "group2"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": uuid.uuid4().hex,
|
"id": uuid.uuid4().hex,
|
||||||
|
@ -201,6 +205,9 @@ servers = {
|
||||||
"flavor": {"id": flavors[2]["id"]},
|
"flavor": {"id": flavors[2]["id"]},
|
||||||
"image": {"id": images["bar"]["id"]},
|
"image": {"id": images["bar"]["id"]},
|
||||||
"status": "SHUTOFF",
|
"status": "SHUTOFF",
|
||||||
|
"security_groups":[
|
||||||
|
{"name": "group1"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": uuid.uuid4().hex,
|
"id": uuid.uuid4().hex,
|
||||||
|
@ -208,6 +215,9 @@ servers = {
|
||||||
"flavor": {"id": flavors[1]["id"]},
|
"flavor": {"id": flavors[1]["id"]},
|
||||||
"image": {"id": images["bar"]["id"]},
|
"image": {"id": images["bar"]["id"]},
|
||||||
"status": "ERROR",
|
"status": "ERROR",
|
||||||
|
"security_groups":[
|
||||||
|
{"name": "group2"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
tenants["bar"]["id"]: [],
|
tenants["bar"]["id"]: [],
|
||||||
|
@ -237,7 +247,10 @@ servers = {
|
||||||
"OS-EXT-IPS:type": "floating",
|
"OS-EXT-IPS:type": "floating",
|
||||||
"OS-EXT-IPS-MAC:mac_addr": "1234"},
|
"OS-EXT-IPS-MAC:mac_addr": "1234"},
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"security_groups":[
|
||||||
|
{"name": "group1"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -265,6 +278,54 @@ volumes[tenants["baz"]["id"]][1]["attachments"] = [{
|
||||||
"id": volumes[tenants["baz"]["id"]][0]["id"],
|
"id": volumes[tenants["baz"]["id"]][0]["id"],
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
security_groups = {
|
||||||
|
tenants["foo"]["id"]: [],
|
||||||
|
tenants["baz"]["id"]: [
|
||||||
|
{
|
||||||
|
"name": "group1",
|
||||||
|
"id": uuid.uuid4().hex,
|
||||||
|
"description": "group one",
|
||||||
|
"rules": [
|
||||||
|
{"from_port": 443,
|
||||||
|
"to_port": 443, "ip_range": {"cidr": "10.0.0.0/32"},
|
||||||
|
"ip_protocol": "tcp"},
|
||||||
|
{"from_port": "1000",
|
||||||
|
"to_port": 2000, "ip_range": {"cidr": "11.0.0.0/32"},
|
||||||
|
"ip_protocol": "udp"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "group2",
|
||||||
|
"id": uuid.uuid4().hex,
|
||||||
|
"description": "group two",
|
||||||
|
"rules": [
|
||||||
|
{"from_port": 80,
|
||||||
|
"to_port": 80, "ip_range": {"cidr": "10.0.0.0/32"},
|
||||||
|
"ip_protocol": "tcp"},
|
||||||
|
{"from_port": "4000",
|
||||||
|
"to_port": 7000, "ip_range": {"cidr": "13.0.0.0/32"},
|
||||||
|
"ip_protocol": "udp"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
tenants["bar"]["id"]: [
|
||||||
|
{
|
||||||
|
"name": "group3",
|
||||||
|
"id": uuid.uuid4().hex,
|
||||||
|
"description": "group three",
|
||||||
|
"rules": [
|
||||||
|
{"from_port": 443,
|
||||||
|
"to_port": 443, "ip_range": {"cidr": "10.0.0.0/32"},
|
||||||
|
"ip_protocol": "tcp"},
|
||||||
|
{"from_port": "1000",
|
||||||
|
"to_port": 2000, "ip_range": {"cidr": "11.0.0.0/32"},
|
||||||
|
"ip_protocol": "udp"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def fake_query_results():
|
def fake_query_results():
|
||||||
cats = []
|
cats = []
|
||||||
|
@ -485,8 +546,17 @@ class FakeApp(object):
|
||||||
"os-floating-ip-pools")
|
"os-floating-ip-pools")
|
||||||
self._populate(path, "floating_ip", floating_ips[tenant["id"]],
|
self._populate(path, "floating_ip", floating_ips[tenant["id"]],
|
||||||
"os-floating-ips")
|
"os-floating-ips")
|
||||||
self._populate_ports(path, servers[tenant["id"]],
|
self._populate_server_links(path, "os-interface",
|
||||||
|
"interfaceAttachments",
|
||||||
|
servers[tenant["id"]],
|
||||||
ports[tenant["id"]])
|
ports[tenant["id"]])
|
||||||
|
self._populate_server_links(path, "os-security-groups",
|
||||||
|
"security_groups",
|
||||||
|
servers[tenant["id"]],
|
||||||
|
security_groups[tenant["id"]])
|
||||||
|
self._populate(path, "security_group",
|
||||||
|
security_groups[tenant["id"]],
|
||||||
|
"os-security-groups")
|
||||||
# NOTE(aloga): dict_values un Py3 is not serializable in JSON
|
# NOTE(aloga): dict_values un Py3 is not serializable in JSON
|
||||||
self._populate(path, "image", list(images.values()))
|
self._populate(path, "image", list(images.values()))
|
||||||
self._populate(path, "flavor", list(flavors.values()))
|
self._populate(path, "flavor", list(flavors.values()))
|
||||||
|
@ -530,16 +600,20 @@ class FakeApp(object):
|
||||||
self.routes[obj_path] = create_fake_json_resp(
|
self.routes[obj_path] = create_fake_json_resp(
|
||||||
{"volumeAttachment": attach})
|
{"volumeAttachment": attach})
|
||||||
|
|
||||||
def _populate_ports(self, path, servers_list, ports_list):
|
def _populate_server_links(self, path, resource, obj,
|
||||||
|
servers_list, link_list):
|
||||||
if servers_list:
|
if servers_list:
|
||||||
for p in ports_list:
|
for s in servers_list:
|
||||||
|
list_obj = []
|
||||||
path_base = "%s/servers/%s/%s" % (
|
path_base = "%s/servers/%s/%s" % (
|
||||||
path,
|
path,
|
||||||
servers_list[0]["id"],
|
s["id"],
|
||||||
"os-interface"
|
resource
|
||||||
)
|
)
|
||||||
|
for l in link_list:
|
||||||
|
list_obj.append(l)
|
||||||
self.routes[path_base] = create_fake_json_resp(
|
self.routes[path_base] = create_fake_json_resp(
|
||||||
{"interfaceAttachments": [p]})
|
{obj: list_obj})
|
||||||
|
|
||||||
@webob.dec.wsgify()
|
@webob.dec.wsgify()
|
||||||
def __call__(self, req):
|
def __call__(self, req):
|
||||||
|
@ -619,7 +693,9 @@ class FakeApp(object):
|
||||||
body = req.json_body.copy()
|
body = req.json_body.copy()
|
||||||
action = body.popitem()
|
action = body.popitem()
|
||||||
if action[0] in ["os-start", "os-stop", "reboot",
|
if action[0] in ["os-start", "os-stop", "reboot",
|
||||||
"addFloatingIp", "removeFloatingIp"]:
|
"addFloatingIp", "removeFloatingIp",
|
||||||
|
"removeSecurityGroup",
|
||||||
|
"addSecurityGroup"]:
|
||||||
return self._get_from_routes(req)
|
return self._get_from_routes(req)
|
||||||
elif req.path_info.endswith("os-volume_attachments"):
|
elif req.path_info.endswith("os-volume_attachments"):
|
||||||
return self._do_create_attachment(req)
|
return self._do_create_attachment(req)
|
||||||
|
|
|
@ -29,6 +29,8 @@ application_url = "https://foo.example.org:8774/ooiv1"
|
||||||
tenants = {
|
tenants = {
|
||||||
"foo": {"id": uuid.uuid4().hex,
|
"foo": {"id": uuid.uuid4().hex,
|
||||||
"name": "foo"},
|
"name": "foo"},
|
||||||
|
"baz": {"id": uuid.uuid4().hex,
|
||||||
|
"name": "foo"},
|
||||||
"bar": {"id": uuid.uuid4().hex,
|
"bar": {"id": uuid.uuid4().hex,
|
||||||
"name": "bar"},
|
"name": "bar"},
|
||||||
"public": {"id": uuid.uuid4().hex,
|
"public": {"id": uuid.uuid4().hex,
|
||||||
|
@ -153,6 +155,40 @@ network_links = {
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
security_groups = {
|
||||||
|
tenants["bar"]["id"]: [],
|
||||||
|
tenants["foo"]["id"]: [],
|
||||||
|
tenants["baz"]["id"]: [
|
||||||
|
{
|
||||||
|
"name": "group1",
|
||||||
|
"id": uuid.uuid4().hex,
|
||||||
|
"description": "group one",
|
||||||
|
"security_group_rules": [
|
||||||
|
{"ethertype": "IPv4", "port_range_min": 443,
|
||||||
|
"port_range_max": 443, "remote_ip_prefix": "10.0.0.0/32",
|
||||||
|
"protocol": "tcp", "direction": "ingress"},
|
||||||
|
{"ethertype": "IPv4", "port_range_min": "8000",
|
||||||
|
"port_range_max": 9000, "remote_ip_prefix": "11.0.0.0/24",
|
||||||
|
"protocol": "udp", "direction": "egress"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "group2",
|
||||||
|
"id": uuid.uuid4().hex,
|
||||||
|
"description": "group two",
|
||||||
|
"security_group_rules": [
|
||||||
|
{"ethertype": "IPv4", "port_range_min": 80,
|
||||||
|
"port_range_max": 80, "remote_ip_prefix": "10.0.0.0/32",
|
||||||
|
"protocol": "tcp", "direction": "ingress"},
|
||||||
|
{"ethertype": "IPv4", "port_range_min": "5000",
|
||||||
|
"port_range_max": 6000, "remote_ip_prefix": "11.0.0.0/24",
|
||||||
|
"protocol": "udp", "direction": "egress"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def create_fake_json_resp(data, status=200):
|
def create_fake_json_resp(data, status=200):
|
||||||
r = webob.Response()
|
r = webob.Response()
|
||||||
|
@ -201,6 +237,22 @@ def create_header(params, schemes, project=None):
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
|
|
||||||
|
def create_req_json_occi(params, category, method="POST"):
|
||||||
|
headers = create_headers(category,
|
||||||
|
content_type="application/occi+json")
|
||||||
|
body = {}
|
||||||
|
for c in category:
|
||||||
|
body["kind"] = "%s%s" % (
|
||||||
|
c.scheme, c.term)
|
||||||
|
|
||||||
|
body["attributes"] = params
|
||||||
|
req = webob.Request.blank(path="")
|
||||||
|
req.headers = headers
|
||||||
|
req.method = method
|
||||||
|
req.body = json.dumps(body).encode("utf8")
|
||||||
|
return wsgi.Request(req.environ)
|
||||||
|
|
||||||
|
|
||||||
def create_req_test_occi(params, category):
|
def create_req_test_occi(params, category):
|
||||||
headers = create_header_occi(params, category)
|
headers = create_header_occi(params, category)
|
||||||
req = webob.Request.blank(path="")
|
req = webob.Request.blank(path="")
|
||||||
|
@ -209,7 +261,7 @@ def create_req_test_occi(params, category):
|
||||||
|
|
||||||
|
|
||||||
def create_header_occi(params, category, project=None):
|
def create_header_occi(params, category, project=None):
|
||||||
headers = {}
|
headers = create_headers(category, project)
|
||||||
att = ""
|
att = ""
|
||||||
if params is not None:
|
if params is not None:
|
||||||
for k, v in params.items():
|
for k, v in params.items():
|
||||||
|
@ -218,6 +270,13 @@ def create_header_occi(params, category, project=None):
|
||||||
else:
|
else:
|
||||||
att = "%s, %s=%s" % (att, k, v)
|
att = "%s, %s=%s" % (att, k, v)
|
||||||
headers["X_OCCI_Attribute"] = att
|
headers["X_OCCI_Attribute"] = att
|
||||||
|
|
||||||
|
return headers
|
||||||
|
|
||||||
|
|
||||||
|
def create_headers(category, content_type=None,
|
||||||
|
project=None):
|
||||||
|
headers = {}
|
||||||
if category is not None:
|
if category is not None:
|
||||||
cat = ""
|
cat = ""
|
||||||
for c in category:
|
for c in category:
|
||||||
|
@ -227,6 +286,8 @@ def create_header_occi(params, category, project=None):
|
||||||
headers['Category'] = cat[:-1]
|
headers['Category'] = cat[:-1]
|
||||||
if project is not None:
|
if project is not None:
|
||||||
headers['X_PROJECT_ID'] = project
|
headers['X_PROJECT_ID'] = project
|
||||||
|
if content_type is not None:
|
||||||
|
headers['Content-Type'] = content_type
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
|
|
||||||
|
@ -376,3 +437,35 @@ def build_occi_nova(network):
|
||||||
for l in links:
|
for l in links:
|
||||||
result.append(("Link", l))
|
result.append(("Link", l))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def build_occi_securitygroup(secgroup):
|
||||||
|
name = secgroup["title"]
|
||||||
|
secgroup_id = secgroup["id"]
|
||||||
|
rules = secgroup["rules"]
|
||||||
|
summary = secgroup["summary"]
|
||||||
|
app_url = application_url
|
||||||
|
cats = []
|
||||||
|
cats.append('securitygroup; '
|
||||||
|
'scheme='
|
||||||
|
'"http://schemas.ogf.org/occi/infrastructure#";'
|
||||||
|
' class="kind"; title="securitygroup resource";'
|
||||||
|
' rel='
|
||||||
|
'"http://schemas.ogf.org/occi/core#resource";'
|
||||||
|
' location="%s/securitygroup/"' % app_url)
|
||||||
|
links = []
|
||||||
|
|
||||||
|
attrs = [
|
||||||
|
'occi.core.id="%s"' % secgroup_id,
|
||||||
|
'occi.core.title="%s"' % name,
|
||||||
|
'occi.core.summary="%s"' % summary,
|
||||||
|
'occi.securitygroup.rules="%s"' % json.dumps(rules).replace('"', "'"),
|
||||||
|
]
|
||||||
|
result = []
|
||||||
|
for c in cats:
|
||||||
|
result.append(("Category", c))
|
||||||
|
for a in attrs:
|
||||||
|
result.append(("X-OCCI-Attribute", a))
|
||||||
|
for l in links:
|
||||||
|
result.append(("Link", l))
|
||||||
|
return result
|
|
@ -17,8 +17,10 @@ import uuid
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
from ooi.api import helpers
|
||||||
from ooi.api import helpers_neutron
|
from ooi.api import helpers_neutron
|
||||||
from ooi import exception
|
from ooi import exception
|
||||||
|
from ooi.openstack import helpers as openstack_helper
|
||||||
from ooi.tests import base
|
from ooi.tests import base
|
||||||
from ooi.tests import fakes_network as fakes
|
from ooi.tests import fakes_network as fakes
|
||||||
from ooi import utils
|
from ooi import utils
|
||||||
|
@ -593,3 +595,80 @@ class TestNetOpenStackHelper(base.TestCase):
|
||||||
self.helper.delete_port,
|
self.helper.delete_port,
|
||||||
None,
|
None,
|
||||||
iface)
|
iface)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "create_resource")
|
||||||
|
@mock.patch.object(helpers.BaseHelper, "tenant_from_req")
|
||||||
|
def test_create_security_groups(self, m_tenant, m_create):
|
||||||
|
tenant_id = fakes.tenants["baz"]["id"]
|
||||||
|
sec_group = fakes.security_groups[tenant_id][0]
|
||||||
|
expected = openstack_helper.build_security_group_from_neutron(
|
||||||
|
[sec_group])[0]
|
||||||
|
m_tenant.return_value = uuid.uuid4().hex
|
||||||
|
group_info = {"name": sec_group["name"], "id": sec_group["id"],
|
||||||
|
"description": sec_group["description"]}
|
||||||
|
rules_out_1 = sec_group["security_group_rules"][0]
|
||||||
|
rules_out_2 = sec_group["security_group_rules"][1]
|
||||||
|
m_create.side_effect = [group_info, rules_out_1, rules_out_2]
|
||||||
|
ret = self.helper.create_security_group(None, expected["title"],
|
||||||
|
expected["summary"],
|
||||||
|
expected["rules"])
|
||||||
|
self.assertEqual(expected, ret)
|
||||||
|
self.assertEqual(3, m_create.call_count)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "list_resources")
|
||||||
|
def test_list_security_group(self, m_list):
|
||||||
|
tenant_id = fakes.tenants["baz"]["id"]
|
||||||
|
sec_group = fakes.security_groups[tenant_id]
|
||||||
|
expected = openstack_helper.build_security_group_from_neutron(
|
||||||
|
sec_group)
|
||||||
|
m_list.return_value = sec_group
|
||||||
|
ret = self.helper.list_security_groups(None)
|
||||||
|
self.assertEqual(2, ret.__len__())
|
||||||
|
self.assertEqual(expected, ret)
|
||||||
|
m_list.assert_called_with(None, 'security-groups',
|
||||||
|
response_resource="security_groups")
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "list_resources")
|
||||||
|
def test_list_security_group_empty(self, m_list):
|
||||||
|
tenant_id = fakes.tenants["bar"]["id"]
|
||||||
|
m_list.return_value = fakes.security_groups[tenant_id]
|
||||||
|
ret = self.helper.list_security_groups(None)
|
||||||
|
self.assertEqual(0, ret.__len__())
|
||||||
|
m_list.assert_called_with(None, 'security-groups',
|
||||||
|
response_resource="security_groups")
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "get_resource")
|
||||||
|
def test_show_security_group(self, m_list):
|
||||||
|
tenant_id = fakes.tenants["baz"]["id"]
|
||||||
|
sec_group = fakes.security_groups[tenant_id][0]
|
||||||
|
expected = openstack_helper.build_security_group_from_neutron(
|
||||||
|
[sec_group])[0]
|
||||||
|
list_sec = sec_group
|
||||||
|
m_list.return_value = list_sec
|
||||||
|
ret = self.helper.get_security_group_details(None, None)
|
||||||
|
self.assertEqual(expected, ret)
|
||||||
|
m_list.assert_called_with(None, 'security-groups', None,
|
||||||
|
response_resource="security_group")
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "get_resource")
|
||||||
|
def test_show_security_group_not_found(self, m_list):
|
||||||
|
m_list.return_value = []
|
||||||
|
self.assertRaises(exception.NotFound,
|
||||||
|
self.helper.get_security_group_details,
|
||||||
|
None,
|
||||||
|
None)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "delete_resource")
|
||||||
|
def test_delete_security_group(self, m_list):
|
||||||
|
m_list.return_value = None
|
||||||
|
ret = self.helper.delete_security_group(None, None)
|
||||||
|
self.assertIsNone(ret)
|
||||||
|
m_list.assert_called_with(None, 'security-groups', None)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "delete_resource")
|
||||||
|
def test_delete_security_group_not_found(self, m_list):
|
||||||
|
m_list.side_effect = exception.OCCIException()
|
||||||
|
self.assertRaises(exception.NotFound,
|
||||||
|
self.helper.delete_security_group,
|
||||||
|
None,
|
||||||
|
None)
|
|
@ -18,8 +18,10 @@ import uuid
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from ooi.api import helpers
|
from ooi.api import helpers
|
||||||
|
from ooi.openstack import helpers as os_helpers
|
||||||
from ooi.tests import base
|
from ooi.tests import base
|
||||||
from ooi.tests import fakes_network as fakes
|
from ooi.tests import fakes as fakes_nova
|
||||||
|
from ooi.tests import fakes_network
|
||||||
from ooi import utils
|
from ooi import utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,10 +35,12 @@ class TestNovaNetOpenStackHelper(base.TestCase):
|
||||||
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
def test_list_networks_with_public(self, m_t, m_rq):
|
def test_list_networks_with_public(self, m_t, m_rq):
|
||||||
id = uuid.uuid4().hex
|
id = uuid.uuid4().hex
|
||||||
resp = fakes.create_fake_json_resp({"networks": [{"id": id}]}, 200)
|
resp = fakes_network.create_fake_json_resp(
|
||||||
|
{"networks": [{"id": id}]},
|
||||||
|
200)
|
||||||
req_mock = mock.MagicMock()
|
req_mock = mock.MagicMock()
|
||||||
req_mock.get_response.return_value = resp
|
req_mock.get_response.return_value = resp
|
||||||
resp_float = fakes.create_fake_json_resp(
|
resp_float = fakes_network.create_fake_json_resp(
|
||||||
{"floating_ip_pools": [{"id": id}]}, 200
|
{"floating_ip_pools": [{"id": id}]}, 200
|
||||||
)
|
)
|
||||||
req_mock_float = mock.MagicMock()
|
req_mock_float = mock.MagicMock()
|
||||||
|
@ -49,10 +53,11 @@ class TestNovaNetOpenStackHelper(base.TestCase):
|
||||||
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
def test_list_networks_with_no_public(self, m_t, m_rq):
|
def test_list_networks_with_no_public(self, m_t, m_rq):
|
||||||
id = uuid.uuid4().hex
|
id = uuid.uuid4().hex
|
||||||
resp = fakes.create_fake_json_resp({"networks": [{"id": id}]}, 200)
|
resp = fakes_network.create_fake_json_resp(
|
||||||
|
{"networks": [{"id": id}]}, 200)
|
||||||
req_mock = mock.MagicMock()
|
req_mock = mock.MagicMock()
|
||||||
req_mock.get_response.return_value = resp
|
req_mock.get_response.return_value = resp
|
||||||
resp_float = fakes.create_fake_json_resp(
|
resp_float = fakes_network.create_fake_json_resp(
|
||||||
{"floating_ip_pools": []}, 204
|
{"floating_ip_pools": []}, 204
|
||||||
)
|
)
|
||||||
req_mock_float = mock.MagicMock()
|
req_mock_float = mock.MagicMock()
|
||||||
|
@ -67,8 +72,9 @@ class TestNovaNetOpenStackHelper(base.TestCase):
|
||||||
id = uuid.uuid4().hex
|
id = uuid.uuid4().hex
|
||||||
tenant_id = uuid.uuid4().hex
|
tenant_id = uuid.uuid4().hex
|
||||||
m_t.return_value = tenant_id
|
m_t.return_value = tenant_id
|
||||||
resp = fakes.create_fake_json_resp({"networks": [{"id": id}]}, 200)
|
resp = fakes_network.create_fake_json_resp(
|
||||||
resp_float = fakes.create_fake_json_resp(
|
{"networks": [{"id": id}]}, 200)
|
||||||
|
resp_float = fakes_network.create_fake_json_resp(
|
||||||
{"floating_ip_pools": [{"id": id}]}, 200
|
{"floating_ip_pools": [{"id": id}]}, 200
|
||||||
)
|
)
|
||||||
req_mock = mock.MagicMock()
|
req_mock = mock.MagicMock()
|
||||||
|
@ -103,7 +109,7 @@ class TestNovaNetOpenStackHelper(base.TestCase):
|
||||||
label = "network11"
|
label = "network11"
|
||||||
tenant_id = uuid.uuid4().hex
|
tenant_id = uuid.uuid4().hex
|
||||||
m_t.return_value = tenant_id
|
m_t.return_value = tenant_id
|
||||||
resp = fakes.create_fake_json_resp(
|
resp = fakes_network.create_fake_json_resp(
|
||||||
{"network": {"id": id, "label": label,
|
{"network": {"id": id, "label": label,
|
||||||
"cidr": address,
|
"cidr": address,
|
||||||
"gateway": gateway}}, 200
|
"gateway": gateway}}, 200
|
||||||
|
@ -134,7 +140,7 @@ class TestNovaNetOpenStackHelper(base.TestCase):
|
||||||
"cidr": cidr,
|
"cidr": cidr,
|
||||||
"gateway": gateway
|
"gateway": gateway
|
||||||
}
|
}
|
||||||
resp = fakes.create_fake_json_resp(
|
resp = fakes_network.create_fake_json_resp(
|
||||||
{"network": {"id": net_id, "label": name,
|
{"network": {"id": net_id, "label": name,
|
||||||
"cidr": cidr,
|
"cidr": cidr,
|
||||||
"gateway": gateway}}, 200
|
"gateway": gateway}}, 200
|
||||||
|
@ -174,3 +180,249 @@ class TestNovaNetOpenStackHelper(base.TestCase):
|
||||||
None, method="DELETE",
|
None, method="DELETE",
|
||||||
path="/%s/os-networks/%s" % (tenant_id, net_id),
|
path="/%s/os-networks/%s" % (tenant_id, net_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_req")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
|
def test_list_security_groups(self, m_t, m_rq):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
m_t.return_value = tenant_id
|
||||||
|
sc_groups = fakes_nova.security_groups[tenant_id]
|
||||||
|
resp = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_groups": sc_groups}, 200)
|
||||||
|
req_mock = mock.MagicMock()
|
||||||
|
req_mock.get_response.return_value = resp
|
||||||
|
m_rq.side_effect = [req_mock]
|
||||||
|
ret = self.helper.list_security_groups(None)
|
||||||
|
cont = 0
|
||||||
|
for sc in sc_groups:
|
||||||
|
self.assertEqual(sc['id'], ret[cont]['id'])
|
||||||
|
cont = cont + 1
|
||||||
|
self.assertEqual(
|
||||||
|
{'method': 'GET',
|
||||||
|
'path': '/%s/os-security-groups' % (tenant_id)},
|
||||||
|
m_rq.call_args_list[0][1]
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_req")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
|
def test_delete_security_groups(self, m_t, m_rq):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
m_t.return_value = tenant_id
|
||||||
|
sc_id = fakes_nova.security_groups[tenant_id][0]['id']
|
||||||
|
req_mock = mock.MagicMock()
|
||||||
|
req_mock.get_response.return_value = []
|
||||||
|
m_rq.return_value = req_mock
|
||||||
|
ret = self.helper.delete_security_group(None, sc_id)
|
||||||
|
self.assertEqual(ret, [])
|
||||||
|
m_rq.assert_called_with(
|
||||||
|
None, method="DELETE",
|
||||||
|
path="/%s/os-security-groups/%s" % (tenant_id, sc_id),
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_req")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
|
def test_get_security_group(self, m_t, m_rq):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
m_t.return_value = tenant_id
|
||||||
|
sc_group = fakes_nova.security_groups[tenant_id][0]
|
||||||
|
id = sc_group['id']
|
||||||
|
m_t.return_value = tenant_id
|
||||||
|
resp = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_group": sc_group}, 200
|
||||||
|
)
|
||||||
|
req_mock = mock.MagicMock()
|
||||||
|
req_mock.get_response.return_value = resp
|
||||||
|
m_rq.return_value = req_mock
|
||||||
|
ret = self.helper.get_security_group_details(None, id)
|
||||||
|
self.assertEqual(sc_group['id'], ret["id"])
|
||||||
|
self.assertEqual(sc_group['description'], ret["summary"])
|
||||||
|
occi_os_group = os_helpers.build_security_group_from_nova(
|
||||||
|
fakes_nova.security_groups[tenant_id]
|
||||||
|
)[0]
|
||||||
|
cont = 0
|
||||||
|
for r in ret["rules"]:
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['protocol'], r["protocol"])
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['range'], r["range"])
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['port'], r["port"])
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['type'], r["type"])
|
||||||
|
cont += 1
|
||||||
|
|
||||||
|
m_rq.assert_called_with(
|
||||||
|
None, method="GET",
|
||||||
|
path="/%s/os-security-groups/%s" % (tenant_id, id),
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_req")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
|
def test_create_security_group(self, m_t, m_rq):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
m_t.return_value = tenant_id
|
||||||
|
sc_group = fakes_nova.security_groups[tenant_id][0]
|
||||||
|
occi_os_group = os_helpers.build_security_group_from_nova(
|
||||||
|
fakes_nova.security_groups[tenant_id]
|
||||||
|
)[0]
|
||||||
|
resp = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_group": sc_group}, 200
|
||||||
|
)
|
||||||
|
req_mock = mock.MagicMock()
|
||||||
|
req_mock.get_response.return_value = resp
|
||||||
|
resp_rule1 = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_group_rule": sc_group['rules'][0]}, 200
|
||||||
|
)
|
||||||
|
req_mock_rule1 = mock.MagicMock()
|
||||||
|
req_mock_rule1.get_response.return_value = resp_rule1
|
||||||
|
resp_rule2 = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_group_rule": sc_group['rules'][1]}, 200
|
||||||
|
)
|
||||||
|
req_mock_rule2 = mock.MagicMock()
|
||||||
|
req_mock_rule2.get_response.return_value = resp_rule2
|
||||||
|
m_rq.side_effect = [req_mock, req_mock_rule1, req_mock_rule2]
|
||||||
|
ret = self.helper.create_security_group(
|
||||||
|
None,
|
||||||
|
name=occi_os_group['title'],
|
||||||
|
description=occi_os_group['summary'],
|
||||||
|
rules=occi_os_group['rules']
|
||||||
|
)
|
||||||
|
cont = 0
|
||||||
|
for r in ret["rules"]:
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['protocol'], r["protocol"]
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['range'], r["range"]
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['port'], r["port"])
|
||||||
|
self.assertEqual(
|
||||||
|
occi_os_group['rules'][cont]['type'], r["type"])
|
||||||
|
cont += 1
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_req")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
|
def test_get_server_security_group(self, mock_tenant, mock_get):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
server_id = uuid.uuid4().hex
|
||||||
|
sc_group = fakes_nova.security_groups[tenant_id]
|
||||||
|
mock_tenant.return_value = tenant_id
|
||||||
|
resp = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_groups": sc_group}, 200
|
||||||
|
)
|
||||||
|
req_mock = mock.MagicMock()
|
||||||
|
req_mock.get_response.return_value = resp
|
||||||
|
mock_get.return_value = req_mock
|
||||||
|
ret = self.helper._get_server_security_group(None, server_id)
|
||||||
|
segroup = os_helpers.build_security_group_from_nova(
|
||||||
|
sc_group
|
||||||
|
)
|
||||||
|
cont = 0
|
||||||
|
for s in segroup:
|
||||||
|
self.assertEqual(s, ret[cont])
|
||||||
|
cont += 1
|
||||||
|
mock_get.assert_called_with(
|
||||||
|
None, method="GET",
|
||||||
|
path="/%s/servers/%s/os-security-groups" % (tenant_id,
|
||||||
|
server_id),
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "index")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_server_security_group")
|
||||||
|
def test_list_server_security_links(self, mock_get, mock_list):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
servers = fakes_nova.servers[tenant_id]
|
||||||
|
mock_list.return_value = servers
|
||||||
|
sg = fakes_nova.security_groups[tenant_id]
|
||||||
|
segroup = os_helpers.build_security_group_from_nova(sg)[0]
|
||||||
|
mock_get.return_value = [segroup]
|
||||||
|
ret = self.helper.list_server_security_links(None)
|
||||||
|
cont = 0
|
||||||
|
for server in servers:
|
||||||
|
self.assertEqual(server["id"],
|
||||||
|
ret[cont]['compute_id'])
|
||||||
|
self.assertEqual(segroup["title"],
|
||||||
|
ret[cont]['securitygroup']["title"])
|
||||||
|
|
||||||
|
cont += 1
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_server_security_group")
|
||||||
|
def test_get_server_security_link(self, mock_get):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
server_id = uuid.uuid4().hex
|
||||||
|
sg = fakes_nova.security_groups[tenant_id]
|
||||||
|
segroup = os_helpers.build_security_group_from_nova(sg)[0]
|
||||||
|
mock_get.return_value = [segroup]
|
||||||
|
ret = self.helper.get_server_security_link(None, server_id,
|
||||||
|
segroup["id"])
|
||||||
|
self.assertEqual(server_id,
|
||||||
|
ret[0]['compute_id'])
|
||||||
|
self.assertEqual(segroup["title"],
|
||||||
|
ret[0]['securitygroup']["title"])
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_req")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
|
def test_delete_server_security_link(self, mock_tenant, mock_req):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
server_id = uuid.uuid4().hex
|
||||||
|
sg_name = "baz"
|
||||||
|
mock_tenant.return_value = tenant_id
|
||||||
|
sc_group = fakes_nova.security_groups[tenant_id][0]
|
||||||
|
sg_name = sc_group["name"]
|
||||||
|
resp_get = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_group": sc_group}, 200
|
||||||
|
)
|
||||||
|
req_mock_get = mock.MagicMock()
|
||||||
|
req_mock_get.get_response.return_value = resp_get
|
||||||
|
resp_cre = fakes_network.create_fake_json_resp(
|
||||||
|
{}, 204
|
||||||
|
)
|
||||||
|
req_mock_del = mock.MagicMock()
|
||||||
|
req_mock_del.get_response.return_value = resp_cre
|
||||||
|
mock_req.side_effect = [req_mock_get, req_mock_del]
|
||||||
|
ret = self.helper.delete_server_security_link(None,
|
||||||
|
server_id,
|
||||||
|
sg_name)
|
||||||
|
self.assertEqual([], ret)
|
||||||
|
mock_req.assert_called_with(
|
||||||
|
None, method="POST",
|
||||||
|
path="/%s/servers/%s/action" % (tenant_id,
|
||||||
|
server_id),
|
||||||
|
body='{"removeSecurityGroup": {"name": "%s"}}' % sg_name,
|
||||||
|
content_type='application/json'
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "_get_req")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
|
||||||
|
def test_create_server_security_link(self, mock_tenant, mock_req):
|
||||||
|
tenant_id = fakes_nova.tenants["baz"]["id"]
|
||||||
|
server_id = uuid.uuid4().hex
|
||||||
|
sg_id = "baz"
|
||||||
|
mock_tenant.return_value = tenant_id
|
||||||
|
sc_group = fakes_nova.security_groups[tenant_id][0]
|
||||||
|
resp_get = fakes_network.create_fake_json_resp(
|
||||||
|
{"security_group": sc_group}, 200
|
||||||
|
)
|
||||||
|
req_mock_get = mock.MagicMock()
|
||||||
|
req_mock_get.get_response.return_value = resp_get
|
||||||
|
resp_create = fakes_network.create_fake_json_resp(
|
||||||
|
{}, 204
|
||||||
|
)
|
||||||
|
req_mock_cre = mock.MagicMock()
|
||||||
|
req_mock_cre.get_response.return_value = resp_create
|
||||||
|
mock_req.side_effect = [req_mock_get, req_mock_cre]
|
||||||
|
ret = self.helper.create_server_security_link(None,
|
||||||
|
server_id,
|
||||||
|
sg_id)
|
||||||
|
self.assertEqual([], ret)
|
||||||
|
sg_name = sc_group["name"]
|
||||||
|
mock_req.assert_called_with(
|
||||||
|
None, method="POST",
|
||||||
|
path="/%s/servers/%s/action" % (tenant_id,
|
||||||
|
server_id),
|
||||||
|
body='{"addSecurityGroup": {"name": "%s"}}' % sg_name,
|
||||||
|
content_type='application/json'
|
||||||
|
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
# Copyright 2015 LIP - INDIGO-DataCloud
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
from ooi.api import helpers_neutron
|
||||||
|
from ooi.api import securitygroup as security_group_api
|
||||||
|
from ooi import exception
|
||||||
|
from ooi.occi.infrastructure import securitygroup as occi_security_group
|
||||||
|
from ooi.openstack import helpers as openstack_helper
|
||||||
|
from ooi.tests import base
|
||||||
|
from ooi.tests import fakes_network as fakes
|
||||||
|
|
||||||
|
|
||||||
|
class TestSecurityGroupControllerNeutron(base.TestController):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSecurityGroupControllerNeutron, self).setUp()
|
||||||
|
self.controller = security_group_api.Controller(
|
||||||
|
neutron_ooi_endpoint="ff")
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron,
|
||||||
|
"list_security_groups")
|
||||||
|
def test_list_security_group(self, m_list):
|
||||||
|
tenant_id = fakes.tenants["baz"]["id"]
|
||||||
|
sec_group = openstack_helper.build_security_group_from_neutron(
|
||||||
|
fakes.security_groups[tenant_id]
|
||||||
|
)
|
||||||
|
req = fakes.create_req_test(None, None)
|
||||||
|
m_list.return_value = sec_group
|
||||||
|
result = self.controller.index(req)
|
||||||
|
expected = self.controller._get_security_group_resources(sec_group)
|
||||||
|
self.assertEqual(result.resources.__len__(),
|
||||||
|
expected.__len__())
|
||||||
|
for r in result.resources:
|
||||||
|
self.assertIsInstance(r, occi_security_group.SecurityGroupResource)
|
||||||
|
m_list.assert_called_with(req)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron,
|
||||||
|
"list_security_groups")
|
||||||
|
def test_list_security_group_empty(self, m_list):
|
||||||
|
tenant_id = fakes.tenants["foo"]["id"]
|
||||||
|
sec_group = openstack_helper.build_security_group_from_neutron(
|
||||||
|
fakes.security_groups[tenant_id]
|
||||||
|
)
|
||||||
|
req = fakes.create_req_test(None, None)
|
||||||
|
m_list.return_value = sec_group
|
||||||
|
result = self.controller.index(req)
|
||||||
|
self.assertEqual(result.resources.__len__(), 0)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron,
|
||||||
|
"get_security_group_details")
|
||||||
|
def test_show_security_group(self, m_list):
|
||||||
|
tenant_id = fakes.tenants["baz"]["id"]
|
||||||
|
sec_group = openstack_helper.build_security_group_from_neutron(
|
||||||
|
[fakes.security_groups[tenant_id][0]]
|
||||||
|
)
|
||||||
|
req = fakes.create_req_test(None, None)
|
||||||
|
m_list.return_value = sec_group[0]
|
||||||
|
result = self.controller.show(req, None)
|
||||||
|
expected = self.controller._get_security_group_resources(sec_group)[0]
|
||||||
|
self.assertIsInstance(
|
||||||
|
result,
|
||||||
|
occi_security_group.SecurityGroupResource)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
m_list.assert_called_with(req, None)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "get_resource")
|
||||||
|
def test_show_security_group_not_found(self, m_list):
|
||||||
|
tenant_id = fakes.tenants["baz"]["id"]
|
||||||
|
sec_group = openstack_helper.build_security_group_from_neutron(
|
||||||
|
fakes.security_groups[tenant_id]
|
||||||
|
)
|
||||||
|
m_list.return_value = sec_group
|
||||||
|
req = fakes.create_req_test(None, None)
|
||||||
|
self.assertRaises(exception.NotFound,
|
||||||
|
self.controller.show,
|
||||||
|
req,
|
||||||
|
None)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron, "delete_resource")
|
||||||
|
def test_delete_security_group(self, m_list):
|
||||||
|
m_list.return_value = None
|
||||||
|
ret = self.controller.delete(None, None)
|
||||||
|
self.assertIsNone(ret)
|
||||||
|
m_list.assert_called_with(None, 'security-groups', None)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron,
|
||||||
|
"delete_security_group")
|
||||||
|
def test_delete_security_group_not_found(self, m_list):
|
||||||
|
m_list.side_effect = exception.NotFound
|
||||||
|
req = fakes.create_req_test(None, None)
|
||||||
|
self.assertRaises(exception.NotFound,
|
||||||
|
self.controller.delete,
|
||||||
|
req,
|
||||||
|
None)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers_neutron.OpenStackNeutron,
|
||||||
|
"create_security_group")
|
||||||
|
def test_create_security_groups(self, m_create):
|
||||||
|
tenant_id = fakes.tenants["baz"]["id"]
|
||||||
|
sec_group = openstack_helper.build_security_group_from_neutron(
|
||||||
|
fakes.security_groups[tenant_id]
|
||||||
|
)[0]
|
||||||
|
params = {"occi.core.title": sec_group["title"],
|
||||||
|
"occi.securitygroup.rules": sec_group["rules"],
|
||||||
|
"occi.core.summary": sec_group["summary"]
|
||||||
|
}
|
||||||
|
categories = {occi_security_group.SecurityGroupResource.kind}
|
||||||
|
req = fakes.create_req_json_occi(params, categories)
|
||||||
|
m_create.return_value = sec_group
|
||||||
|
ret = self.controller.create(req, params)
|
||||||
|
expected = self.controller._get_security_group_resources(
|
||||||
|
[sec_group])
|
||||||
|
self.assertIsInstance(ret.resources[0],
|
||||||
|
occi_security_group.SecurityGroupResource)
|
||||||
|
self.assertEqual(expected[0], ret.resources[0])
|
||||||
|
m_create.assert_called_with(req, sec_group["title"],
|
||||||
|
sec_group["summary"],
|
||||||
|
sec_group["rules"])
|
||||||
|
|
||||||
|
def test_create_error(self):
|
||||||
|
test_networks = fakes.networks[fakes.tenants["foo"]["id"]]
|
||||||
|
schema1 = occi_security_group.SecurityGroupResource.kind.scheme
|
||||||
|
net = test_networks[0]
|
||||||
|
schemes = {schema1: net}
|
||||||
|
parameters = {"occi.core.title": "name"}
|
||||||
|
req = fakes.create_req_test(parameters, schemes)
|
||||||
|
|
||||||
|
self.assertRaises(exception.Invalid, self.controller.create, req)
|
||||||
|
|
||||||
|
def test_create_invalid_param_rule(self):
|
||||||
|
params = {"occi.core.title": "group",
|
||||||
|
"occi.securitygroup.rules": "{'wrong': 'value'}]"
|
||||||
|
}
|
||||||
|
categories = {occi_security_group.SecurityGroupResource.kind}
|
||||||
|
req = fakes.create_req_test_occi(params, categories)
|
||||||
|
self.assertRaises(exception.Invalid, self.controller.create, req)
|
|
@ -0,0 +1,104 @@
|
||||||
|
# Copyright 2015 Spanish National Research Council
|
||||||
|
# Copyright 2015 LIP - INDIGO-DataCloud
|
||||||
|
#
|
||||||
|
# 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 uuid
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from ooi.api import helpers
|
||||||
|
from ooi.api import securitygroup_link as securitygroup_link_api
|
||||||
|
from ooi.occi.core import collection
|
||||||
|
from ooi.occi.infrastructure import securitygroup_link
|
||||||
|
from ooi.openstack import helpers as os_helpers
|
||||||
|
from ooi.tests import base
|
||||||
|
from ooi.tests import fakes as fakes_nova
|
||||||
|
|
||||||
|
|
||||||
|
class TestNetworkLinkController(base.TestController):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNetworkLinkController, self).setUp()
|
||||||
|
self.controller = securitygroup_link_api.Controller(
|
||||||
|
mock.MagicMock(), None)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "list_server_security_links")
|
||||||
|
def test_index(self, mock_list):
|
||||||
|
tenant_id = fakes_nova.tenants['bar']["id"]
|
||||||
|
servers = fakes_nova.servers[tenant_id]
|
||||||
|
sg = fakes_nova.security_groups[tenant_id]
|
||||||
|
segroup = os_helpers.build_security_group_from_nova(sg)[0]
|
||||||
|
links = []
|
||||||
|
for server in servers:
|
||||||
|
link = {
|
||||||
|
"compute_id": server["id"],
|
||||||
|
"securitygroup": segroup
|
||||||
|
}
|
||||||
|
links.append(link)
|
||||||
|
mock_list.return_value = links
|
||||||
|
ret = self.controller.index(None)
|
||||||
|
self.assertIsInstance(ret, collection.Collection)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "get_server_security_link")
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "list_security_groups")
|
||||||
|
def test_show(self, mock_list, mock_get):
|
||||||
|
tenant_id = fakes_nova.tenants['baz']["id"]
|
||||||
|
server = fakes_nova.servers[tenant_id][0]
|
||||||
|
server_id = server['id']
|
||||||
|
secgroup_name = server['security_groups'][0]["name"]
|
||||||
|
link_id = '%s_%s' % (server_id, secgroup_name)
|
||||||
|
sec_group = os_helpers.build_security_group_from_nova(
|
||||||
|
fakes_nova.security_groups[tenant_id]
|
||||||
|
)
|
||||||
|
link = {
|
||||||
|
"compute_id": server_id,
|
||||||
|
"securitygroup": sec_group[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_get.return_value = [link]
|
||||||
|
mock_list.return_value = sec_group
|
||||||
|
ret = self.controller.show(None, link_id)
|
||||||
|
self.assertIsInstance(ret, securitygroup_link.SecurityGroupLink)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "delete_server_security_link")
|
||||||
|
def test_delete(self, mock_del):
|
||||||
|
tenant_id = fakes_nova.tenants['baz']["id"]
|
||||||
|
server = fakes_nova.servers[tenant_id][0]
|
||||||
|
server_id = server['id']
|
||||||
|
secgroup_name = server['security_groups'][0]["name"]
|
||||||
|
link_id = '%s_%s' % (server_id, secgroup_name)
|
||||||
|
mock_del.return_value = []
|
||||||
|
ret = self.controller.delete(None, link_id)
|
||||||
|
self.assertEqual([], ret)
|
||||||
|
|
||||||
|
@mock.patch.object(helpers.OpenStackHelper, "create_server_security_link")
|
||||||
|
@mock.patch("ooi.occi.validator.Validator")
|
||||||
|
@mock.patch("ooi.api.helpers.get_id_with_kind")
|
||||||
|
def test_create(self, m_get_id, m_validator, m_create):
|
||||||
|
compute_id = uuid.uuid4().hex
|
||||||
|
sec_id = uuid.uuid4().hex
|
||||||
|
obj = {
|
||||||
|
"attributes": {
|
||||||
|
"occi.core.target": sec_id,
|
||||||
|
"occi.core.source": compute_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req = self._build_req(uuid.uuid4().hex)
|
||||||
|
req.get_parser = mock.MagicMock()
|
||||||
|
req.get_parser.return_value.return_value.parse.return_value = obj
|
||||||
|
m_validator.validate.return_value = True
|
||||||
|
m_get_id.side_effect = [('', compute_id), ('', sec_id)]
|
||||||
|
m_create.return_value = []
|
||||||
|
ret = self.controller.create(req, None)
|
||||||
|
link = ret.resources.pop()
|
||||||
|
self.assertIsInstance(link, securitygroup_link.SecurityGroupLink)
|
Loading…
Reference in New Issue