Included OCCI IPReservation support

This is a complete change in which we have add the OCCI IPRESERVATION
class with the features provided by CESNET. We include: the controller,
the occi class, middleware changes, and tests to control it.
In addition, we have modified networklink to support this feature,
now networklink is identified by using only compute id and ipreservation
ip. Last, we add the documentation relate to its usage.

Change-Id: I52f80a9a7a39e00d1d7487001863586a551edf5f
This commit is contained in:
Jorge Sevilla 2017-01-26 21:50:55 +01:00 committed by Alvaro Lopez Garcia
parent ddbe190568
commit 7566dce6af
21 changed files with 1014 additions and 152 deletions

View File

@ -291,6 +291,60 @@ It deletes a network::
It returns a 204 empty response.
IPReservation
**************
OOI allows to manage public IPs by using IPReservation resources. This resource is a special network to provide public access.
It allocates and releases IPs from public network pools.
List IPReservations
-------------------
It list IPReservation resources::
curl -H "X-Auth-token: "$OS_TOKEN http://127.0.0.1:8787/occi1.1/ipreservation
It returns a HTTP 200 with output::
X-OCCI-Location: http://127.0.0.1:8787/occi1.1/ipreservation/3318c3af-ce57-41ef-a9c1-9a5ecfbe0526
Show IPReservation
------------------
It shows the IPReservation details::
curl -H "X-Auth-token: "$OS_TOKEN http://127.0.0.1:8787/occi1.1/ipreservation/3318c3af-ce57-41ef-a9c1-9a5ecfbe0526
It returns a HTTP 200 with output::
Category: ipreservation; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"; title="IPReservation"; rel="http://schemas.ogf.org/occi/infrastructure#network"; location="http://127.0.0.1:8787/occi1.1/ipreservation/"
X-OCCI-Attribute: occi.core.title="external-net"
X-OCCI-Attribute: occi.core.summary=[]
X-OCCI-Attribute: occi.core.id="3318c3af-ce57-41ef-a9c1-9a5ecfbe0526"
X-OCCI-Attribute: occi.ipreservation.address="193.136.75.90"
X-OCCI-Attribute: occi.ipreservation.used="true"
Link: <http://127.0.0.1:8787/occi1.1/ipreservation/3318c3af-ce57-41ef-a9c1-9a5ecfbe0526?action=up>; rel="http://schemas.ogf.org/occi/infrastructure/network/action#up"
Link: <http://127.0.0.1:8787/occi1.1/ipreservation/3318c3af-ce57-41ef-a9c1-9a5ecfbe0526?action=down>; rel="http://schemas.ogf.org/occi/infrastructure/network/action#down"
Create IPReservation
--------------------
It creates a IPReservation resource::
curl -X POST http://127.0.0.1:8787/occi1.1/ipreservation -H 'X-Auth-token: '$OS_TOKEN \
-H 'Category: ipreshemas.ogf.org/occi/infrastructure#"; class="kind",' \
'external-net; scheme="http://schemas.openstack.org/network/floatingippool#"; class="mixin"' \
-H 'Content-Type: text/occi'
It returns a HTTP 200 with output::
X-OCCI-Location: http://127.0.0.1:8787/occi1.1/ipreservation/3318c3af-ce57-41ef-a9c1-9a5ecfbe0526
Delete IPReservation
--------------------
It deletes IPReservation resources::
curl -X DELETE -H "X-Auth-token: "$OS_TOKEN http://127.0.0.1:8787/occi1.1/ipreservation/3318c3af-ce57-41ef-a9c1-9a5ecfbe0526
It returns a 204 empty response.
Network Link
************

View File

@ -22,6 +22,7 @@ from ooi import exception
from ooi.occi.core import collection
from ooi.occi.infrastructure import compute
from ooi.occi.infrastructure import contextualization
from ooi.occi.infrastructure import ip_reservation
from ooi.occi.infrastructure import network
from ooi.occi.infrastructure import storage
from ooi.occi.infrastructure import storage_link
@ -32,8 +33,13 @@ from ooi.openstack import network as os_network
from ooi.openstack import templates
def _create_network_link(addr, comp, net_id):
net = network.NetworkResource(title="network", id=net_id)
def _create_network_link(addr, comp, net_id, type_ip):
if type_ip == "floating":
net = ip_reservation.IPReservation(title="network",
address=None,
id=net_id)
else:
net = network.NetworkResource(title="network", id=net_id)
return os_network.OSNetworkInterface(comp, net,
addr["OS-EXT-IPS-MAC:mac_addr"],
addr["addr"])
@ -278,7 +284,9 @@ class Controller(ooi.api.base.Controller):
for addr in addr_set:
# TODO(jorgesece): add pool information
if addr["OS-EXT-IPS:type"] == "floating":
net_id = helpers.PUBLIC_NETWORK
net_id = self.os_helper.get_floatingip_id(
req, addr['addr']
)
else:
try:
net_id = self.os_helper.get_network_id(
@ -286,7 +294,9 @@ class Controller(ooi.api.base.Controller):
)
except webob.exc.HTTPNotFound:
net_id = "FIXED"
comp.add_link(_create_network_link(addr, comp, net_id))
comp.add_link(_create_network_link(
addr, comp, net_id,
addr["OS-EXT-IPS:type"]))
return comp
@ -310,7 +320,6 @@ class Controller(ooi.api.base.Controller):
if server_ip == ip["ip"]:
self.os_helper.remove_floating_ip(req, server_id,
ip["ip"])
self.os_helper.release_floating_ip(req, ip["id"])
def _delete(self, req, server_ids):
for server_id in server_ids:

View File

@ -534,6 +534,19 @@ class OpenStackHelper(BaseHelper):
response = req.get_response(self.app)
return self.get_from_response(response, "floating_ips", [])
def get_floating_ip(self, req, floating_id):
"""Get information about a floating IP.
:param req: the incoming request
:param floating_id: floating ip id to get info from
"""
tenant_id = self.tenant_from_req(req)
path = "/%s/os-floating-ips/%s" % (tenant_id,
floating_id)
req = self._make_get_request(req, path)
response = req.get_response(self.app)
return self.get_from_response(response, "floating_ip", [])
def _get_floating_ip_pools_req(self, req):
tenant_id = self.tenant_from_req(req)
path = "/%s/os-floating-ip-pools" % tenant_id
@ -708,7 +721,7 @@ class OpenStackHelper(BaseHelper):
@staticmethod
def _build_link(net_id, compute_id, ip, ip_id=None, mac=None, pool=None,
state='ACTIVE'):
state='ACTIVE', public_ip=False):
link = {}
link['mac'] = mac
link['pool'] = pool
@ -717,6 +730,7 @@ class OpenStackHelper(BaseHelper):
link['ip'] = ip
link['ip_id'] = ip_id
link['state'] = os_helpers.vm_state(state)
link['public_ip'] = public_ip
return link
def _get_ports(self, req, compute_id):
@ -732,48 +746,55 @@ class OpenStackHelper(BaseHelper):
LOG.exception("Interfaces can not be shown: " + e.explanation)
return result
def get_compute_net_link(self, req, compute_id, network_id,
address):
def get_compute_net_link(self, req, compute_id, address):
"""Get a specific network/server link
It shows a specific link (either private or public ip)
:param req: the incoming request
:param compute_id: server id
:param network_id: network id
:param address: ip connected
"""
s = self.get_server(req, compute_id)
pool = None
ip_id = None
server_addrs = s.get("addresses", {})
compute = self.get_server(req, compute_id)
server_addrs = compute.get("addresses", {})
compute_id = compute["id"]
ports = self._get_ports(req, compute_id)
floating_ips = self.get_floating_ips(
req
)
for addr_set in server_addrs.values():
for addr in addr_set:
if addr["addr"] == address:
public_ip = False
pool = None
ip_id = None
mac = addr["OS-EXT-IPS-MAC:mac_addr"]
if network_id == os_helpers.PUBLIC_NETWORK:
floating_ips = self.get_floating_ips(
req
)
for ip in floating_ips:
if address == ip['ip']:
pool = ip['pool']
ip_id = ip['id']
else:
ports = self._get_ports(req, compute_id)
ip_type = addr["OS-EXT-IPS:type"]
if ip_type == "fixed":
network_id = "FIXED"
for p in ports:
if p["net_id"] == network_id:
for ip in p["fixed_ips"]:
if ip['ip_address'] == address:
ip_id = p['port_id']
return self._build_link(network_id,
compute_id,
address,
mac=mac,
pool=pool,
ip_id=ip_id
)
if p['mac_addr'] == mac:
ip_id = str(p['port_id'])
network_id = str(p['net_id'])
break
else:
network_id = "PUBLIC"
for fp in floating_ips:
if compute_id == fp['instance_id']:
pool = fp['pool']
ip_id = str(fp['id'])
network_id = str(fp['id'])
public_ip = True
break
return self._build_link(
network_id,
compute_id,
address,
mac=mac,
pool=pool,
ip_id=ip_id,
public_ip=public_ip
)
raise exception.NotFound()
def list_compute_net_links(self, req):
@ -781,45 +802,48 @@ class OpenStackHelper(BaseHelper):
:param req: the incoming request
"""
floating_ips = self.get_floating_ips(req)
float_list = {}
for ip in floating_ips:
if ip["instance_id"]:
float_list.update({ip['fixed_ip']: ip})
servers = self.index(req)
link_list = []
for s in servers:
ports = self._get_ports(req, s['id'])
for p in ports:
for ip in p["fixed_ips"]:
mac = p['mac_addr']
state = p["port_state"]
link = self._build_link(p["net_id"],
s['id'],
ip['ip_address'],
ip_id=p["port_id"],
mac=mac,
state=state)
link_list.append(link)
float_ip = float_list.get(ip['ip_address'], None)
if float_ip:
link = self._build_link(p["net_id"],
float_ip['instance_id'],
float_ip['ip'],
ip_id=float_ip["id"],
mac=mac,
pool=float_ip["pool"]
)
link_list.append(link)
if not link_list:
for ip in floating_ips:
if ip["instance_id"]:
link = self._build_link(os_helpers.PUBLIC_NETWORK,
ip['instance_id'],
ip['ip'],
ip_id=ip["id"],
pool=ip["pool"]
)
compute_list = self.index(req)
floating_ips = self.get_floating_ips(
req
)
for c in compute_list:
compute_id = c["id"]
compute = self.get_server(req, compute_id)
ports = self._get_ports(req, compute_id)
server_addrs = compute.get("addresses", {})
for addr_set in server_addrs.values():
for addr in addr_set:
public_ip = False
pool = None
network_id = "fixed"
mac = addr["OS-EXT-IPS-MAC:mac_addr"]
ip_type = addr["OS-EXT-IPS:type"]
address = addr['addr']
ip_id = None
if ip_type == "fixed":
for p in ports:
if p['mac_addr'] == mac:
ip_id = p['port_id']
network_id = p["net_id"]
break
else:
for fp in floating_ips:
if address == fp['ip']:
pool = fp['pool']
ip_id = fp['id']
network_id = fp['id']
public_ip = True
break
link = self._build_link(
network_id,
compute_id,
address,
mac=mac,
pool=pool,
ip_id=ip_id,
public_ip=public_ip
)
link_list.append(link)
return link_list
@ -886,8 +910,43 @@ class OpenStackHelper(BaseHelper):
raise webob.exc.HTTPNotFound
def assign_floating_ip(self, req, network_id, device_id,
pool=None):
def get_floatingip_id(self, req, address):
"""Get the floating IP ID
:param req: the incoming network
:param address: floating ip address
"""
floating_ips = self.get_floating_ips(req)
for fp in floating_ips:
if address == fp['ip']:
return str(fp['id'])
raise webob.exc.HTTPNotFound
def assign_floating_ip(self, req, floatingip_id, device_id):
"""assign floating ip to a server
:param req: the incoming request
:param floatingip_id: floating ip id
:param device_id: device id
"""
ip = self.get_floating_ip(req, floatingip_id)
self.associate_floating_ip(req, device_id, ip['ip'])
try:
link_public = self._build_link(
floatingip_id,
device_id,
ip['ip'],
ip_id=floatingip_id,
public_ip=True
)
except Exception:
raise exception.OCCIInvalidSchema()
return link_public
def assign_floating_ip_deprecated(self, req, network_id, device_id,
pool=None):
"""assign floating ip to a server
:param req: the incoming request

131
ooi/api/ip_reservation.py Normal file
View File

@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
# 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 import exception
from ooi.occi.core import collection
from ooi.occi.infrastructure import ip_reservation
from ooi.occi import validator as occi_validator
from ooi.openstack import network as os_network
class Controller(base.Controller):
def __init__(self, app=None, openstack_version=None):
"""IP reservation controller initialization
:param app: application
:param: openstack_version: nova version
"""
super(Controller, self).__init__(
app=app,
openstack_version=openstack_version)
self.os_helper = helpers.OpenStackHelper(
self.app,
self.openstack_version
)
@staticmethod
def _get_ipreservation_resources(ipreservation_list):
"""Create network instances from ip reservations in json format
:param ipreservation_list: ip reservation objects provides by
the cloud infrastructure
"""
occi_ipreservation_resources = []
if ipreservation_list:
for s in ipreservation_list:
n_id = str(s["id"]) # some versions retrieve int.
n_name = s["pool"]
n_address = s["ip"]
n_used = False
if s["instance_id"]:
n_used = True
s = ip_reservation.IPReservation(title=n_name,
id=n_id,
address=n_address,
used=n_used
)
occi_ipreservation_resources.append(s)
return occi_ipreservation_resources
def index(self, req):
"""List ip reservations
:param req: request object
"""
occi_ipreservation = self.os_helper.get_floating_ips(req)
occi_ipreservation_resources = self._get_ipreservation_resources(
occi_ipreservation)
return collection.Collection(
resources=occi_ipreservation_resources)
def show(self, req, id):
"""Get ip reservation details
:param req: request object
:param id: ip reservation identification
"""
resp = self.os_helper.get_floating_ip(req, id)
occi_network_resources = self._get_ipreservation_resources(
[resp])
return occi_network_resources[0]
def create(self, req, body=None):
"""Create an ip reservation instance in the cloud
:param req: request object
:param body: body request (not used)
"""
parser = req.get_parser()(req.headers, req.body)
scheme = {
"category": ip_reservation.IPReservation.kind,
"optional_mixins": [
os_network.OSFloatingIPPool,
]
}
obj = parser.parse()
validator = occi_validator.Validator(obj)
validator.validate(scheme)
pool = None
if os_network.OSFloatingIPPool.scheme in obj["schemes"]:
pool = (
obj["schemes"][os_network.OSFloatingIPPool.scheme][0]
)
resp = self.os_helper.allocate_floating_ip(req, pool)
occi_network_resources = self._get_ipreservation_resources(
[resp])
return collection.Collection(resources=occi_network_resources)
def delete(self, req, id):
"""delete an ip reservation instance
:param req: current request
:param id: identification
"""
self.os_helper.release_floating_ip(req, id)
return []
def run_action(self, req, id, body):
"""Run action over the network
:param req: current request
:param id: ip reservation identification
:param body: body
"""
raise exception.NotImplemented()

View File

@ -18,6 +18,7 @@ from ooi.api import helpers
from ooi import exception
from ooi.occi.core import collection
from ooi.occi.infrastructure import compute
from ooi.occi.infrastructure import ip_reservation
from ooi.occi.infrastructure import network
from ooi.occi.infrastructure import network_link
from ooi.occi import validator as occi_validator
@ -40,8 +41,14 @@ def _get_network_link_resources(link_list):
state = l.get('state', None)
ip_id = l.get('ip_id', None)
net_id = l['network_id']
n = network.NetworkResource(title="network",
id=net_id)
public_ip = l['public_ip']
if public_ip:
n = ip_reservation.IPReservation(title="network",
address=ip,
id=net_id)
else:
n = network.NetworkResource(title="network",
id=net_id)
c = compute.ComputeResource(title="Compute",
id=compute_id
)
@ -77,14 +84,13 @@ class Controller(base.Controller):
:param id: network link identification
"""
try:
server_id, network_id, server_addr = id.split('_', 2)
server_id, server_addr = id.split('_', 1)
except ValueError:
raise exception.LinkNotFound(link_id=id)
try:
link = self.os_helper.get_compute_net_link(
req,
server_id,
network_id,
server_addr)
occi_instance = _get_network_link_resources([link])[0]
except Exception:
@ -122,28 +128,42 @@ class Controller(base.Controller):
validator.validate(scheme)
attrs = obj.get("attributes", {})
_, net_id = helpers.get_id_with_kind(
req,
attrs.get("occi.core.target"),
network.NetworkResource.kind)
_, server_id = helpers.get_id_with_kind(
req,
attrs.get("occi.core.source"),
compute.ComputeResource.kind)
pool = None
if os_network.OSFloatingIPPool.scheme in obj["schemes"]:
pool = (
obj["schemes"][os_network.OSFloatingIPPool.scheme][0]
)
# Allocate public IP and associate it ot the server
if net_id == os_helpers.PUBLIC_NETWORK:
if (ip_reservation.IPReservation.kind.location in
attrs.get("occi.core.target")):
_, net_id = helpers.get_id_with_kind(
req,
attrs.get("occi.core.target"),
ip_reservation.IPReservation.kind)
os_link = self.os_helper.assign_floating_ip(
req, net_id, server_id, pool
req, net_id, server_id
)
else:
# Allocate private network
os_link = self.os_helper.create_port(
req, net_id, server_id)
_, net_id = helpers.get_id_with_kind(
req,
attrs.get("occi.core.target"),
network.NetworkResource.kind)
# TODO(jorgesece): DEPRECATION
# Delete this method for linking public network.
if net_id == os_helpers.PUBLIC_NETWORK:
pool = None
if os_network.OSFloatingIPPool.scheme in obj["schemes"]:
pool = (
obj["schemes"][os_network.OSFloatingIPPool.scheme][0]
)
# Allocate public IP and associate it on the server
os_link = self.os_helper.assign_floating_ip_deprecated(
req, net_id, server_id, pool
)
# END DEPRECATION
else:
# Allocate private network
os_link = self.os_helper.create_port(
req, net_id, server_id)
occi_link = _get_network_link_resources([os_link])
return collection.Collection(resources=occi_link)
@ -155,6 +175,7 @@ class Controller(base.Controller):
"""
iface = self._get_interface_from_id(req, id)
server = iface.source.id
# TODO(jorgesece): DEPRECATION
if iface.target.id == os_helpers.PUBLIC_NETWORK:
# remove floating IP
self.os_helper.remove_floating_ip(req, server,
@ -163,7 +184,13 @@ class Controller(base.Controller):
# release IP
self.os_helper.release_floating_ip(req,
iface.ip_id)
# END DEPRECATION
else:
self.os_helper.delete_port(
req, server, iface.ip_id)
if isinstance(iface.target,
ip_reservation.IPReservation):
self.os_helper.remove_floating_ip(req, server,
iface.address)
else:
self.os_helper.delete_port(
req, server, iface.ip_id)
return []

View File

@ -21,6 +21,7 @@ from ooi.occi.core import link
from ooi.occi.core import resource
from ooi.occi.infrastructure import compute
from ooi.occi.infrastructure import contextualization
from ooi.occi.infrastructure import ip_reservation
from ooi.occi.infrastructure import network
from ooi.occi.infrastructure import network_link
from ooi.occi.infrastructure import storage
@ -99,6 +100,7 @@ class Controller(base.Controller):
mixins.append(network.ip_network)
kinds.append(network_link.NetworkInterface.kind)
mixins.append(network_link.ip_network_interface)
kinds.append(ip_reservation.IPReservation.kind)
# OCCI infra compute mixins
mixins.append(infra_templates.os_tpl)

View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# 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.occi.core import attribute as attr
from ooi.occi.core import kind
from ooi.occi import helpers
from ooi.occi.infrastructure import network
class IPReservation(network.NetworkResource):
attributes = attr.AttributeCollection({
"occi.ipreservation.address": attr.MutableAttribute(
"occi.ipreservation.address",
description="Internet Protocol(IP) network"
" address re-served for Compute instances"
" linking with this IPReservation instance",
attr_type=attr.AttributeType.string_type),
"occi.ipreservation.used": attr.InmutableAttribute(
"occi.ipreservation.used",
description="Indication whether"
" the reserved address is currently in use.",
attr_type=attr.AttributeType.boolean_type),
"occi.ipreservation.state": attr.InmutableAttribute(
"occi.ipreservation.state",
description="Indicates the state of the resource.",
attr_type=attr.AttributeType.string_type),
})
kind = kind.Kind(helpers.build_scheme('infrastructure'), 'ipreservation',
'IPReservation', attributes, 'ipreservation/',
parent=network.NetworkResource.kind)
def __init__(self, title, address, id=None, used=False,
state=None, mixins=[]):
super(IPReservation, self).__init__(title, id=id,
mixins=mixins)
self.address = address
self.attributes["occi.ipreservation.used"] = (
attr.InmutableAttribute.from_attr(
self.attributes["occi.ipreservation.used"], used))
self.attributes["occi.ipreservation.state"] = (
attr.InmutableAttribute.from_attr(
self.attributes["occi.ipreservation.state"], state))
@property
def address(self):
return self.attributes["occi.ipreservation.address"].value
@address.setter
def address(self, value):
self.attributes["occi.ipreservation.address"].value = value
@property
def used(self):
return self.attributes["occi.ipreservation.used"].value
@property
def state(self):
return self.attributes["occi.ipreservation.state"].value

View File

@ -46,7 +46,7 @@ class OSNetworkInterface(network_link.NetworkInterface):
def __init__(self, source, target, mac, address, ip_id=None,
pool=None, state='active'):
link_id = '_'.join([source.id, target.id, address])
link_id = '_'.join([source.id, address])
mixins = [network_link.ip_network_interface]
if pool:
mixins.append(OSFloatingIPPool(pool))

View File

@ -125,8 +125,12 @@ pools = {
}
linked_vm_id = uuid.uuid4().hex
linked_vm_id_2 = uuid.uuid4().hex
allocated_ip = "192.168.253.23"
allocated_ip = {"ip": "192.168.253.23",
"id": 1,
"pool": uuid.uuid4().hex,
"instance_id": None}
floating_ips = {
tenants["foo"]["id"]: [],
@ -182,6 +186,16 @@ ports = {
"net_id": uuid.uuid4().hex,
"server_id": linked_vm_id
},
{
"port_id": uuid.uuid4().hex,
"fixed_ips": [
{"ip_address": "192.168.253.2"}
],
"mac_addr": uuid.uuid4().hex,
"port_state": "ACTIVE",
"net_id": uuid.uuid4().hex,
"server_id": linked_vm_id_2
},
],
}
@ -251,6 +265,32 @@ servers = {
"security_groups":[
{"name": "group1"}
]
},
{
"id": linked_vm_id_2,
"name": "withvolume",
"flavor": {"id": flavors[1]["id"]},
"image": {"id": images["bar"]["id"]},
"status": "ACTIVE",
"os-extended-volumes:volumes_attached": [
{"id": volumes[tenants["baz"]["id"]][0]["id"]}
],
"addresses": {
"private": [
{"addr": (
(ports[tenants["baz"]["id"]]
[1]["fixed_ips"][0]["ip_address"])
),
"OS-EXT-IPS:type": "fixed",
"OS-EXT-IPS-MAC:mac_addr": (
ports[tenants["baz"]["id"]][1]["mac_addr"]
)
},
{"addr": floating_ips[tenants["baz"]["id"]][0]["ip"],
"OS-EXT-IPS:type": "floating",
"OS-EXT-IPS-MAC:mac_addr": "1234"},
]
}
}
],
}
@ -441,6 +481,12 @@ def fake_query_results():
'scheme="http://schemas.ogf.org/occi/infrastructure/'
'networkinterface#"; '
'class="mixin"; title="IP Network interface Mixin"')
cats.append(
'ipreservation; '
'scheme="http://schemas.ogf.org/occi/infrastructure#"; '
'class="kind"; title="IPReservation"; '
'rel="http://schemas.ogf.org/occi/infrastructure#network"; '
'location="%s/ipreservation/"' % application_url)
# OCCI Infrastructure Storage
cats.append(
@ -615,6 +661,20 @@ class FakeApp(object):
self.routes[path_base] = create_fake_json_resp(
{obj: list_obj})
def _populate_ports(self, path, servers_list, ports_list):
for s in servers_list:
p_list = []
path_base = "%s/servers/%s/%s" % (
path,
s["id"],
"os-interface"
)
for p in ports_list:
if p["server_id"] == s["id"]:
p_list.append(p)
self.routes[path_base] = create_fake_json_resp(
{"interfaceAttachments": p_list})
@webob.dec.wsgify()
def __call__(self, req):
if req.method == "GET":
@ -660,7 +720,7 @@ class FakeApp(object):
else:
exc = webob.exc.HTTPNotFound()
return FakeOpenStackFault(exc)
ip = {"floating_ip": {"ip": allocated_ip, "id": 1}}
ip = {"floating_ip": allocated_ip}
return create_fake_json_resp(ip, 202)
def _do_create_port(self, req):
@ -673,10 +733,9 @@ class FakeApp(object):
p = {"interfaceAttachment": {
"port_id": uuid.uuid4().hex,
"fixed_ips":
[{"ip_address":
port[0]["fixed_ips"]
[0]["ip_address"]
}],
[{
"ip_address": port[0]["fixed_ips"][0]["ip_address"]
}],
"mac_addr": port[0]["mac_addr"],
"port_state": "DOWN",
"net_id": net,

View File

@ -292,7 +292,7 @@ def create_headers(category, content_type=None,
def fake_build_link(net_id, compute_id, ip, mac=None,
pool=None, state='active'):
pool=None, state='active', public_ip=False):
link = {}
link['mac'] = mac
link['pool'] = pool
@ -300,6 +300,7 @@ def fake_build_link(net_id, compute_id, ip, mac=None,
link['compute_id'] = compute_id
link['ip'] = ip
link['state'] = state
link['public_ip'] = public_ip
return link

View File

@ -424,12 +424,21 @@ class TestComputeController(test_middleware.TestMiddleware):
for addr in addr_set:
ip = addr["addr"]
if addr["OS-EXT-IPS:type"] == "fixed":
net_id = fakes.ports[tenant["id"]][0]["net_id"]
for p in fakes.ports[tenant["id"]]:
if (p["mac_addr"] ==
addr["OS-EXT-IPS-MAC:mac_addr"]):
net_id = p["net_id"]
break
target = utils.join_url(self.application_url + "/",
"network/%s" % net_id)
else:
net_id = "PUBLIC"
link_id = '_'.join([server["id"], net_id, ip])
target = utils.join_url(self.application_url + "/",
"network/%s" % net_id)
for floating_ip in fakes.floating_ips[tenant["id"]]:
if floating_ip["ip"] == ip:
net_id = floating_ip['id']
break
target = utils.join_url(self.application_url + "/",
"ipreservation/%s" % net_id)
link_id = '_'.join([server["id"], ip])
self.assertResultIncludesLink(link_id, source, target,
resp)

View File

@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
# 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
from ooi.tests import fakes
from ooi.tests.functional.middleware import test_middleware
from ooi import utils
def build_occi_ip_reservation(ip, application_url):
name = ip["pool"]
network_id = ip["id"]
address = ip["ip"]
if ip["instance_id"]:
used = str(True).lower()
else:
used = str(False).lower()
cats = []
cats.append('ipreservation; '
'scheme='
'"http://schemas.ogf.org/occi/infrastructure#";'
' class="kind"; title="IPReservation"; rel='
'"http://schemas.ogf.org/occi/infrastructure#network";'
' location="%s/ipreservation/"' % application_url)
links = []
links.append('<%s/ipreservation/%s?action=up>; '
'rel="http://schemas.ogf.org/occi/'
'infrastructure/network/action#up"' %
(application_url, network_id))
links.append('<%s/ipreservation/%s?action=down>; '
'rel="http://schemas.ogf.org/occi/'
'infrastructure/network/action#down"' %
(application_url, network_id))
attrs = [
'occi.core.title="%s"' % name,
'occi.core.id="%s"' % network_id,
'occi.ipreservation.address="%s"' % address,
'occi.ipreservation.used="%s"' % used,
]
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
class TestNetIPReservationController(test_middleware.TestMiddleware):
"""Test OCCI IP Reservation controller."""
def setUp(self):
super(TestNetIPReservationController, self).setUp()
self.application_url = fakes.application_url
self.app = self.get_app()
def test_list_empty(self):
tenant = fakes.tenants["bar"]
for url in ("/ipreservation/", "/ipreservation"):
req = self._build_req(url, tenant["id"], method="GET")
req.environ["HTTP_X_PROJECT_ID"] = tenant["id"]
resp = req.get_response(self.app)
expected_result = ""
self.assertContentType(resp)
self.assertExpectedResult(expected_result, resp)
self.assertEqual(204, resp.status_code)
def test_list(self):
tenant = fakes.tenants["baz"]
for url in ("/ipreservation/", "/ipreservation"):
req = self._build_req(url, tenant["id"], method="GET")
resp = req.get_response(self.app)
self.assertEqual(200, resp.status_code)
expected = []
for ip in fakes.floating_ips[tenant["id"]]:
expected.append(
("X-OCCI-Location",
utils.join_url(self.application_url + "/",
"ipreservation/%s" % ip["id"]))
)
self.assertExpectedResult(expected, resp)
def test_show(self):
tenant = fakes.tenants["baz"]
for ip in fakes.floating_ips[tenant["id"]]:
ip_id = ip["id"]
req = self._build_req("/ipreservation/%s" % ip_id,
tenant["id"], method="GET")
resp = req.get_response(self.app)
self.assertContentType(resp)
self.assertEqual(200, resp.status_code)
expected = build_occi_ip_reservation(
ip,
self.application_url)
self.assertExpectedResult(expected, resp)
def test_show_invalid_id(self):
tenant = fakes.tenants["foo"]
link_id = uuid.uuid4().hex
req = self._build_req("/ipreservation/%s" % link_id,
tenant["id"], method="GET")
resp = req.get_response(self.app)
self.assertEqual(404, resp.status_code)
def test_delete(self):
tenant = fakes.tenants["foo"]
link_id = uuid.uuid4().hex
req = self._build_req("/ipreservation/%s" % link_id,
tenant["id"], method="DELETE")
resp = req.get_response(self.app)
self.assertEqual(204, resp.status_code)
def test_create(self):
tenant = fakes.tenants["baz"]
ip_id = fakes.allocated_ip["id"]
headers = {
'Category': 'ipreservation;'
' scheme='
'"http://schemas.ogf.org/occi/infrastructure#";'
'class="kind",'
}
req = self._build_req("/ipreservation/",
tenant["id"],
method="POST",
headers=headers)
resp = req.get_response(self.app)
expected = [("X-OCCI-Location",
utils.join_url(self.application_url + "/",
"ipreservation/%s" % ip_id))]
self.assertEqual(200, resp.status_code)
self.assertExpectedResult(expected, resp)
def test_create_with_pool(self):
tenant = fakes.tenants["baz"]
ip_id = fakes.allocated_ip["id"]
pool_name = "public"
headers = {
'Category': ('ipreservation;'
' scheme='
'"http://schemas.ogf.org/occi/infrastructure#";'
'class="kind",'
'%s;'
'scheme="http://schemas.openstack.org/network/'
'floatingippool#"; class="mixin"') % pool_name,
}
req = self._build_req("/ipreservation/",
tenant["id"],
method="POST",
headers=headers)
resp = req.get_response(self.app)
expected = [("X-OCCI-Location",
utils.join_url(self.application_url + "/",
"ipreservation/%s" % ip_id))]
self.assertEqual(200, resp.status_code)
self.assertExpectedResult(expected, resp)

View File

@ -52,42 +52,29 @@ class TestNetInterfaceController(test_middleware.TestMiddleware):
resp = req.get_response(self.app)
self.assertEqual(200, resp.status_code)
servers = fakes.servers[tenant["id"]]
expected = []
float_list = {}
for floating_ip in fakes.floating_ips[tenant["id"]]:
if floating_ip["instance_id"]:
float_list.update({floating_ip['fixed_ip']: floating_ip})
instance_vm = fakes.linked_vm_id
for p in fakes.ports[tenant["id"]]:
for ip in p["fixed_ips"]:
link_id = '_'.join([instance_vm,
p["net_id"],
ip["ip_address"]])
expected.append(
("X-OCCI-Location",
utils.join_url(self.application_url + "/",
"networklink/%s" % link_id))
)
float_ip = float_list.get(ip['ip_address'], None)
if float_ip:
for server in servers:
server_addrs = server.get("addresses", {})
instance_vm = server["id"]
for addr_set in server_addrs.values():
for addr in addr_set:
address = addr['addr']
link_id = '_'.join([instance_vm,
"PUBLIC",
float_ip["ip"]])
address])
expected.append(
("X-OCCI-Location",
utils.join_url(self.application_url + "/",
"networklink/%s" % link_id))
)
"networklink/%s" % link_id)))
self.assertExpectedResult(expected, resp)
def test_show_iface(self):
tenant = fakes.tenants["baz"]
instance_vm = fakes.linked_vm_id
for p in fakes.ports[tenant["id"]]:
for ip in p["fixed_ips"]:
instance_vm = p["server_id"]
link_id = '_'.join([instance_vm,
p["net_id"],
ip["ip_address"]]
)
req = self._build_req("/networklink/%s" % link_id,
@ -178,7 +165,6 @@ class TestNetInterfaceController(test_middleware.TestMiddleware):
resp = req.get_response(self.app)
link_id = '_'.join([link_info['server_id'],
link_info['net_id'],
link_info['fixed_ips'][0]
["ip_address"]])
expected = [("X-OCCI-Location",
@ -188,6 +174,28 @@ class TestNetInterfaceController(test_middleware.TestMiddleware):
self.assertExpectedResult(expected, resp)
self.assertDefaults(resp)
def test_create_link_ipreservation(self):
tenant = fakes.tenants["baz"]
net_id = fakes.floating_ips[tenant['id']][0]['id']
occi_compute_id = utils.join_url(
self.application_url + "/",
"compute/%s" % fakes.linked_vm_id)
occi_net_id = utils.join_url(self.application_url + "/",
"ipreservation/%s" % net_id)
headers = {
'Category': (
'networkinterface;'
'scheme="http://schemas.ogf.org/occi/infrastructure#";'
'class="kind"'),
'X-OCCI-Attribute': ('occi.core.source="%s", '
'occi.core.target="%s"'
) % (occi_compute_id, occi_net_id)
}
req = self._build_req("/networklink", tenant["id"], method="POST",
headers=headers)
resp = req.get_response(self.app)
self.assertEqual(200, resp.status_code)
def test_delete_fixed(self):
tenant = fakes.tenants["baz"]
@ -195,7 +203,6 @@ class TestNetInterfaceController(test_middleware.TestMiddleware):
if n["net_id"] != "PUBLIC":
if n["server_id"]:
link_id = '_'.join([n["server_id"],
n["net_id"],
n["fixed_ips"]
[0]["ip_address"]])
req = self._build_req(
@ -210,7 +217,18 @@ class TestNetInterfaceController(test_middleware.TestMiddleware):
for n in fakes.floating_ips[tenant["id"]]:
if n["instance_id"]:
link_id = '_'.join([n["instance_id"],
"PUBLIC",
n["ip"]])
req = self._build_req("/networklink/%s" % link_id,
tenant["id"], method="DELETE")
resp = req.get_response(self.app)
self.assertContentType(resp)
self.assertEqual(204, resp.status_code)
def test_delete_ipreservation(self):
tenant = fakes.tenants["baz"]
for n in fakes.floating_ips[tenant["id"]]:
if n["instance_id"]:
link_id = '_'.join([n["instance_id"],
n["ip"]])
req = self._build_req("/networklink/%s" % link_id,
tenant["id"], method="DELETE")

View File

@ -86,8 +86,7 @@ class TestComputeController(base.TestController):
@mock.patch.object(compute.Controller, "_get_server_floating_ips")
@mock.patch.object(helpers.OpenStackHelper, "get_floating_ips")
@mock.patch.object(helpers.OpenStackHelper, "remove_floating_ip")
@mock.patch.object(helpers.OpenStackHelper, "release_floating_ip")
def test_release_floating_ips(self, mock_release, mock_remove,
def test_release_floating_ips(self, mock_remove,
mock_get_floating,
mock_server_floating):
mock_server_floating.return_value = ["1.2.3.4", "5.6.7.8"]
@ -100,8 +99,6 @@ class TestComputeController(base.TestController):
mock_get_floating.assert_called_with(None)
mock_remove.assert_has_calls([mock.call(None, "foo", "1.2.3.4"),
mock.call(None, "foo", "5.6.7.8")])
mock_release.assert_has_calls([mock.call(None, "bar"),
mock.call(None, "baz")])
@mock.patch.object(compute.Controller, "_delete")
def test_delete(self, mock_delete):
@ -179,7 +176,8 @@ class TestComputeController(base.TestController):
@mock.patch.object(helpers.OpenStackHelper, "get_flavor")
@mock.patch.object(helpers.OpenStackHelper, "get_server")
@mock.patch.object(helpers.OpenStackHelper, "get_network_id")
def test_show(self, m_net_id, m_server, m_flavor, m_image, m_vol):
@mock.patch.object(helpers.OpenStackHelper, "get_floatingip_id")
def test_show(self, m_ipr, m_net_id, m_server, m_flavor, m_image, m_vol):
for tenant in fakes.tenants.values():
servers = fakes.servers[tenant["id"]]
for server in servers:
@ -194,6 +192,11 @@ class TestComputeController(base.TestController):
net_id = fakes.networks.get(tenant["id"], [])
if net_id:
net_id = net_id[0]['id']
floatip_ip = fakes.floating_ips.get(tenant["id"], [])
floatip_id = 0
if floatip_ip.__len__() > 0:
floatip_id = floatip_ip[0]['id']
m_ipr.return_value = floatip_id
m_net_id.return_value = net_id
m_server.return_value = server
m_flavor.return_value = flavor
@ -207,13 +210,17 @@ class TestComputeController(base.TestController):
m_flavor.assert_called_with(None, flavor["id"])
m_image.assert_called_with(None, image["id"])
m_vol.assert_called_with(None, server["id"])
if floatip_ip:
m_ipr.assert_called_with(None, floatip_ip[0]["ip"])
@mock.patch.object(helpers.OpenStackHelper, "get_server_volumes_link")
@mock.patch.object(helpers.OpenStackHelper, "get_image")
@mock.patch.object(helpers.OpenStackHelper, "get_flavor")
@mock.patch.object(helpers.OpenStackHelper, "get_server")
@mock.patch.object(helpers.OpenStackHelper, "get_network_id")
def test_show_no_image(self, m_net_id, m_server, m_flavor, m_image, m_vol):
@mock.patch.object(helpers.OpenStackHelper, "get_floatingip_id")
def test_show_no_image(self, m_ipr, m_net_id, m_server, m_flavor,
m_image, m_vol):
for tenant in fakes.tenants.values():
servers = fakes.servers[tenant["id"]]
for server in servers:
@ -225,6 +232,11 @@ class TestComputeController(base.TestController):
net_id = fakes.networks.get(tenant["id"], [])
if net_id:
net_id = net_id[0]['id']
floatip_ip = fakes.floating_ips.get(tenant["id"], [])
floatip_id = 0
if floatip_ip:
floatip_id = floatip_ip[0]['id']
m_ipr.return_value = floatip_id
m_net_id.return_value = net_id
m_server.return_value = server
m_flavor.return_value = flavor
@ -238,6 +250,8 @@ class TestComputeController(base.TestController):
m_flavor.assert_called_with(None, flavor["id"])
m_image.assert_called_with(None, image["id"])
m_vol.assert_called_with(None, server["id"])
if floatip_ip:
m_ipr.assert_called_with(None, floatip_ip[0]["ip"])
@mock.patch.object(helpers.OpenStackHelper, "create_server")
@mock.patch.object(compute.Controller, "_get_network_from_req")

View File

@ -1403,4 +1403,33 @@ class TestOpenStackHelperReqs(TestBaseHelper):
self.assertEqual(net_id, ret['network_id'])
self.assertEqual(device_id, ret['compute_id'])
self.assertEqual(ip, ret['ip'])
@mock.patch.object(helpers.OpenStackHelper,
"_get_req")
@mock.patch.object(helpers.OpenStackHelper, "tenant_from_req")
def test_associate_floating_ip_deprecated(self, m_ten, m_req):
m_ten.return_value = uuid.uuid4().hex
net_id = uuid.uuid4().hex
device_id = uuid.uuid4().hex
ip = uuid.uuid4().hex
ip_id = uuid.uuid4().hex
pool = uuid.uuid4().hex
resp = fakes.create_fake_json_resp(
{"floating_ip": {"ip": ip, "pool": pool, 'id': ip_id}},
202
)
req_all = mock.MagicMock()
req_all.get_response.return_value = resp
resp_ass = fakes.create_fake_json_resp({}, 202)
req_ass = mock.MagicMock()
req_ass.get_response.return_value = resp_ass
m_req.side_effect = [req_all,
req_ass]
ret = self.helper.assign_floating_ip_deprecated(None,
net_id,
device_id)
self.assertIsNotNone(ret)
self.assertEqual(net_id, ret['network_id'])
self.assertEqual(device_id, ret['compute_id'])
self.assertEqual(ip, ret['ip'])
self.assertEqual(pool, ret['pool'])

View File

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
# 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
from ooi.api import ip_reservation as ip_reservation_control
from ooi.occi.infrastructure import ip_reservation
from ooi.openstack import network as os_network
from ooi.tests import base
from ooi.tests import fakes
from ooi.tests import fakes_network as fake_nets
class TestIPReservationController(base.TestController):
def setUp(self):
super(TestIPReservationController, self).setUp()
self.controller = ip_reservation_control.Controller(
mock.MagicMock(), None
)
@mock.patch.object(helpers.OpenStackHelper, "get_floating_ips")
def test_index_empty(self, m_iplist):
tenant = fakes.tenants["foo"]
floating_list = fakes.floating_ips[tenant["id"]]
m_iplist.return_value = floating_list
result = self.controller.index(None)
expected = self.controller._get_ipreservation_resources(floating_list)
self.assertEqual(expected, result.resources)
self.assertEqual([], result.resources)
m_iplist.assert_called_with(None)
@mock.patch.object(helpers.OpenStackHelper, "get_floating_ips")
def test_index(self, m_iplist):
tenant = fakes.tenants["baz"]
floating_list = fakes.floating_ips[tenant["id"]]
m_iplist.return_value = floating_list
result = self.controller.index(None)
expected = self.controller._get_ipreservation_resources(floating_list)
self.assertEqual(expected, result.resources)
m_iplist.assert_called_with(None)
@mock.patch.object(helpers.OpenStackHelper, "get_floating_ip")
def test_show(self, m_ip):
tenant = fakes.tenants["baz"]
floating_ip = fakes.floating_ips[tenant["id"]][0]
m_ip.return_value = floating_ip
result = self.controller.show(None, floating_ip["id"])
expected = self.controller._get_ipreservation_resources(
[floating_ip])[0]
self.assertIsInstance(result, ip_reservation.IPReservation)
self.assertEqual(expected, result)
m_ip.assert_called_with(None, floating_ip["id"])
@mock.patch.object(helpers.OpenStackHelper,
"release_floating_ip")
def test_delete(self, mock_release):
tenant = fakes.tenants["baz"]
floating_ip = fakes.floating_ips[tenant["id"]][0]
mock_release.return_value = []
self.controller.delete(None, floating_ip["id"])
mock_release.assert_called_with(None, floating_ip["id"])
@mock.patch.object(helpers.OpenStackHelper,
"allocate_floating_ip")
def test_create(self, mock_allocate):
tenant = fakes.tenants["baz"]
floating_list = fakes.floating_ips[tenant["id"]][0]
mock_allocate.return_value = floating_list
parameters = {}
categories = {ip_reservation.IPReservation.kind}
req = fake_nets.create_req_test_occi(parameters, categories)
result = self.controller.create(req)
expected = self.controller._get_ipreservation_resources(
[floating_list])
self.assertEqual(expected, result.resources)
mock_allocate.assert_called_with(req, None)
@mock.patch.object(helpers.OpenStackHelper, "allocate_floating_ip")
@mock.patch("ooi.occi.validator.Validator")
def test_create_pool(self, mock_validator, mock_allocate):
tenant = fakes.tenants["baz"]
floating_list = fakes.floating_ips[tenant["id"]][0]
mock_allocate.return_value = floating_list
pool_name = "public"
obj = {
"attributes": {},
"schemes": {
os_network.OSFloatingIPPool.scheme: [pool_name],
}
}
parameters = {}
categories = {ip_reservation.IPReservation.kind}
req = fake_nets.create_req_test_occi(parameters, categories)
req.get_parser = mock.MagicMock()
req.get_parser.return_value.return_value.parse.return_value = obj
mock_validator.validate.return_value = True
result = self.controller.create(req)
expected = self.controller._get_ipreservation_resources(
[floating_list])
self.assertEqual(expected, result.resources)
mock_allocate.assert_called_with(req, pool_name)

View File

@ -22,6 +22,7 @@ from ooi.api import network_link as network_link_api
from ooi import exception
from ooi.occi.core import collection
from ooi.occi.infrastructure import compute
from ooi.occi.infrastructure import ip_reservation
from ooi.occi.infrastructure import network
from ooi.occi.infrastructure import network_link
from ooi.openstack import network as os_network
@ -133,16 +134,14 @@ class TestNetworkLinkController(base.TestController):
os_link['network_id'], os_link['instance_id'], os_link['ip'],
mac=None, pool=os_link['pool'], state=os_link['status']
)
link_id = '%s_%s_%s' % (
link_id = '%s_%s' % (
os_link['instance_id'],
os_link['network_id'],
os_link['ip'])
ret = self.controller.show(None, link_id)
self.assertIsInstance(ret, os_network.OSNetworkInterface)
self.assertEqual(os_link["ip"], ret.address)
mock_get.assert_called_with(None, str(os_link['instance_id']),
os_link['network_id'],
os_link['ip'])
@mock.patch.object(network_link_api.Controller, "_get_interface_from_id")
@ -173,13 +172,13 @@ class TestNetworkLinkController(base.TestController):
server_id = uuid.uuid4().hex
net_id = uuid.uuid4().hex
server_addr = "1.1.1.1"
link_id = "%s_%s_%s" % (server_id, net_id, server_addr)
link_id = "%s_%s" % (server_id, server_addr)
mock_get_server.return_value = fake_nets.fake_build_link(
net_id, server_id, server_addr
)
ret = self.controller.show(None, link_id)
self.assertIsInstance(ret, os_network.OSNetworkInterface)
mock_get_server.assert_called_with(None, server_id, net_id,
mock_get_server.assert_called_with(None, server_id,
server_addr)
def test_get_network_link_resources_fixed(self):
@ -228,7 +227,8 @@ class TestNetworkLinkController(base.TestController):
ret = network_link_api._get_network_link_resources(None)
self.assertEqual(ret.__len__(), 0)
@mock.patch.object(helpers.OpenStackHelper, "assign_floating_ip")
@mock.patch.object(helpers.OpenStackHelper,
"assign_floating_ip_deprecated")
@mock.patch("ooi.api.helpers.get_id_with_kind")
def test_create_public(self, mock_get_id, mock_assign):
server_id = uuid.uuid4().hex
@ -243,7 +243,7 @@ class TestNetworkLinkController(base.TestController):
mock_assign.return_value = fake_nets.fake_build_link(
net_id, server_id, ip
)
mock_get_id.side_effect = [('', net_id), ('', server_id)]
mock_get_id.side_effect = [('', server_id), ('', net_id)]
ret = self.controller.create(req)
self.assertIsNotNone(ret)
link = ret.resources.pop()
@ -254,12 +254,39 @@ class TestNetworkLinkController(base.TestController):
self.assertEqual(server_id, link.source.id)
mock_assign.assert_called_with(mock.ANY, net_id, server_id, None)
@mock.patch.object(helpers.OpenStackHelper, "assign_floating_ip")
@mock.patch("ooi.api.helpers.get_id_with_kind")
def test_create_ipreservation(self, mock_get_id, mock_assign):
server_id = uuid.uuid4().hex
net_id = "foo/ipreservation/%s" % uuid.uuid4().hex
ip = '8.0.0.0'
parameters = {
"occi.core.target": net_id,
"occi.core.source": server_id,
}
categories = {network_link.NetworkInterface.kind}
req = fake_nets.create_req_test_occi(parameters, categories)
mock_assign.return_value = fake_nets.fake_build_link(
net_id, server_id, ip, public_ip=True
)
mock_get_id.side_effect = [('', server_id), ('', net_id)]
ret = self.controller.create(req)
self.assertIsNotNone(ret)
link = ret.resources.pop()
self.assertIsInstance(link, os_network.OSNetworkInterface)
self.assertIsInstance(link.source, compute.ComputeResource)
self.assertIsInstance(link.target, network.NetworkResource)
self.assertIsInstance(link.target, ip_reservation.IPReservation)
self.assertEqual(net_id, link.target.id)
self.assertEqual(server_id, link.source.id)
mock_assign.assert_called_with(mock.ANY, net_id, server_id)
@mock.patch.object(helpers.OpenStackHelper, "create_port")
@mock.patch("ooi.api.helpers.get_id_with_kind")
def test_create_fixed(self, mock_get_id, mock_cre_port):
server_id = uuid.uuid4().hex
net_id = uuid.uuid4().hex
mock_get_id.side_effect = [('', net_id), ('', server_id)]
mock_get_id.side_effect = [('', server_id), ('', net_id)]
ip = '8.0.0.0'
parameters = {
"occi.core.target": net_id,
@ -327,7 +354,7 @@ class TestNetworkLinkController(base.TestController):
mock_validator.validate.return_value = True
mock_allocate.return_value = ip
mock_associate.return_value = None
mock_get_id.side_effect = [('', net_id), ('', server_id)]
mock_get_id.side_effect = [('', server_id), ('', net_id)]
ret = self.controller.create(req, None)
link = ret.resources.pop()
@ -368,7 +395,7 @@ class TestNetworkLinkController(base.TestController):
mock_validator.validate.return_value = True
mock_allocate.return_value = ip
mock_associate.return_value = None
mock_get_id.side_effect = [('', net_id), ('', server_id)]
mock_get_id.side_effect = [('', server_id), ('', net_id)]
ret = self.controller.create(req, None)
link = ret.resources.pop()

View File

@ -21,6 +21,7 @@ from ooi.occi.core import link
from ooi.occi.core import resource
from ooi.occi.infrastructure import compute
from ooi.occi.infrastructure import contextualization
from ooi.occi.infrastructure import ip_reservation
from ooi.occi.infrastructure import network
from ooi.occi.infrastructure import network_link
from ooi.occi.infrastructure import storage
@ -65,6 +66,7 @@ class TestQueryController(base.TestController):
storage_link.StorageLink.kind,
network.NetworkResource.kind,
network_link.NetworkInterface.kind,
ip_reservation.IPReservation.kind,
]
expected_mixins = [
@ -133,6 +135,7 @@ class TestQueryController(base.TestController):
storage_link.StorageLink.kind,
network.NetworkResource.kind,
network_link.NetworkInterface.kind,
ip_reservation.IPReservation.kind,
]
expected_mixins = [

View File

@ -19,6 +19,7 @@ from ooi.occi.core import mixin
from ooi.occi.core import resource
from ooi.occi.infrastructure import compute
from ooi.occi.infrastructure import contextualization
from ooi.occi.infrastructure import ip_reservation
from ooi.occi.infrastructure import network
from ooi.occi.infrastructure import network_link
from ooi.occi.infrastructure import securitygroup
@ -439,3 +440,45 @@ class TestOCCISecurityGroupLink(base.TestCase):
id=uuid.uuid4().hex)
l = securitygroup_link.SecurityGroupLink(c, s, state="foobar")
self.assertEqual("foobar", l.state)
class TestOCCIIPReservation(base.TestCase):
def test_ipreservation_class(self):
ir = ip_reservation.IPReservation
self.assertIn(network.up, ir.actions)
self.assertIn(network.down, ir.actions)
self.assertIn("occi.ipreservation.address", ir.attributes)
self.assertIn("occi.ipreservation.used", ir.attributes)
self.assertIn("occi.ipreservation.state", ir.attributes)
self.assertEqual(network.NetworkResource.kind, ir.kind.parent)
self.assertEqual(ir.kind.location, "ipreservation/")
def test_ip_reservation(self):
id = uuid.uuid4().hex
ir = ip_reservation.IPReservation("foo",
address="xx",
id=id)
self.assertEqual("foo", ir.title)
self.assertEqual(id, ir.id)
self.assertEqual("xx", ir.address)
self.assertEqual(False, ir.used)
self.assertIsNone(ir.state)
def test_setters(self):
ir = ip_reservation.IPReservation("foo", address="xx")
ir.address = "zzz"
self.assertEqual(
"zzz",
ir.attributes["occi.ipreservation.address"].value)
def test_getters(self):
id_ip = uuid.uuid4().hex
ir = ip_reservation.IPReservation("foo",
address="xx",
state="active",
used=True,
id=id_ip)
self.assertEqual("active", ir.state)
self.assertEqual("xx", ir.address)
self.assertEqual(True, ir.used)
self.assertEqual(id_ip, ir.id)

View File

@ -118,7 +118,7 @@ class TestOSNetworkInterface(base.TestCase):
id=uuid.uuid4().hex)
i = os_network.OSNetworkInterface(c, n, "00:01:02:03:04:05",
"127.0.0.1", pool="foo")
self.assertEqual('_'.join([c.id, n.id, "127.0.0.1"]), i.id)
self.assertEqual('_'.join([c.id, "127.0.0.1"]), i.id)
self.assertEqual(i.address, "127.0.0.1")
self.assertEqual(i.interface, "eth0")
self.assertEqual(i.mac, "00:01:02:03:04:05")

View File

@ -20,6 +20,7 @@ import routes.middleware
import webob.dec
import ooi.api.compute
import ooi.api.ip_reservation
import ooi.api.network
import ooi.api.network_link
from ooi.api import query
@ -257,6 +258,11 @@ class OCCIMiddleware(object):
self._setup_resource_routes("network",
self.resources["network"])
self.resources["ipreservation"] = self._create_resource(
ooi.api.ip_reservation.Controller)
self._setup_resource_routes("ipreservation",
self.resources["ipreservation"])
@webob.dec.wsgify(RequestClass=Request)
def __call__(self, req):
response = self.process_request(req)