From 84e4d66134adfa528b102ff231d951499fa9d93a Mon Sep 17 00:00:00 2001 From: Enol Fernandez Date: Tue, 7 Jun 2016 14:17:41 +0200 Subject: [PATCH] Adapt attributes definition to OCCI 1.2 Introduces new properties for the attribute definition and adapts every OCCI entity to it. Adds new attributes (e.g. occi.*.state.message) and removes the ones no longer existing (occi.compute.speed). New dependency on enum34 for python < 3.4 introduced. Change-Id: I17b91af74c47f0b2dc3ffa68933c68e21b22b491 Partially-Implements: blueprint occi-1-2-core --- ooi/occi/core/attribute.py | 37 +++++++++- ooi/occi/core/entity.py | 16 +++-- ooi/occi/core/link.py | 17 +++-- ooi/occi/core/resource.py | 9 ++- ooi/occi/infrastructure/compute.py | 71 ++++++++++++------- ooi/occi/infrastructure/network.py | 59 ++++++++++----- ooi/occi/infrastructure/network_link.py | 57 +++++++++++---- ooi/occi/infrastructure/storage.py | 31 ++++++-- ooi/occi/infrastructure/storage_link.py | 40 ++++++++--- ooi/openstack/contextualization.py | 5 +- ooi/openstack/network.py | 65 +++++++++-------- ooi/tests/unit/occi/test_occi_core.py | 44 ++++++++++++ .../unit/occi/test_occi_infrastructure.py | 40 ++++++++--- requirements.txt | 1 + 14 files changed, 361 insertions(+), 131 deletions(-) diff --git a/ooi/occi/core/attribute.py b/ooi/occi/core/attribute.py index 324f489..c3b5edc 100644 --- a/ooi/occi/core/attribute.py +++ b/ooi/occi/core/attribute.py @@ -18,14 +18,42 @@ import abc import collections import copy +import enum import six +class AttributeType(enum.Enum): + object_type = 1 + list_type = 2 + hash_type = 3 + + def __init__(self, attr_type): + self.attr_type = attr_type + + def check_type(self, value): + if self.attr_type == AttributeType.list_type.value: + if not isinstance(value, list): + raise TypeError("Expecting list value") + elif self.attr_type == AttributeType.hash_type.value: + if not isinstance(value, dict): + raise TypeError("Expecting hash value") + + @six.add_metaclass(abc.ABCMeta) class Attribute(object): - def __init__(self, name, value): + def __init__(self, name, value=None, required=False, default=None, + description=None, attr_type=None): self._name = name self._value = value + self.required = required + self.default = default + self.description = description + if not attr_type: + self.attr_type = AttributeType.object_type + elif not isinstance(attr_type, AttributeType): + raise TypeError("Unexpected attribute type") + else: + self.attr_type = attr_type @property def name(self): @@ -39,11 +67,16 @@ class Attribute(object): class MutableAttribute(Attribute): @Attribute.value.setter def value(self, value): + self.attr_type.check_type(value) self._value = value class InmutableAttribute(Attribute): - pass + @classmethod + def from_attr(cls, attr, value=None): + return cls(attr.name, value=value, required=attr.required, + default=attr.default, description=attr.description, + attr_type=attr.attr_type) class AttributeCollection(object): diff --git a/ooi/occi/core/entity.py b/ooi/occi/core/entity.py index 35fb778..0815306 100644 --- a/ooi/occi/core/entity.py +++ b/ooi/occi/core/entity.py @@ -58,8 +58,12 @@ class Entity(object): sub-type of Entity is identified by a unique Kind instance """ - attributes = attribute.AttributeCollection(["occi.core.id", - "occi.core.title"]) + attributes = attribute.AttributeCollection({ + "occi.core.id": attribute.InmutableAttribute( + "occi.core.id", description="A unique identifier"), + "occi.core.title": attribute.MutableAttribute( + "occi.core.title", description="The display name of the instance"), + }) kind = kind.Kind(helpers.build_scheme('core'), 'entity', 'entity', attributes, 'entity/') @@ -76,10 +80,10 @@ class Entity(object): if id is None: id = uuid.uuid4().hex - self.attributes["occi.core.id"] = attribute.InmutableAttribute( - "occi.core.id", id) - self.attributes["occi.core.title"] = attribute.MutableAttribute( - "occi.core.title", title) + self.attributes["occi.core.id"] = ( + attribute.InmutableAttribute.from_attr( + self.attributes["occi.core.id"], id)) + self.title = title @property def id(self): diff --git a/ooi/occi/core/link.py b/ooi/occi/core/link.py index 7750684..4bd7a37 100644 --- a/ooi/occi/core/link.py +++ b/ooi/occi/core/link.py @@ -27,18 +27,23 @@ class Link(entity.Entity): Resource instance with another. """ - attributes = attribute.AttributeCollection(["occi.core.source", - "occi.core.target"]) + attributes = attribute.AttributeCollection({ + "occi.core.source": attribute.MutableAttribute( + "occi.core.source", required=True, + description="The Resource instance the link originates from"), + "occi.core.target": attribute.MutableAttribute( + "occi.core.target", required=True, + description=("The unique identifier of an Object this Link " + "instance points to")), + }) kind = kind.Kind(helpers.build_scheme("core"), 'link', 'link', attributes, 'link/') def __init__(self, title, mixins, source, target, id=None): super(Link, self).__init__(title, mixins, id) - self.attributes["occi.core.source"] = attribute.MutableAttribute( - "occi.core.source", source) - self.attributes["occi.core.target"] = attribute.MutableAttribute( - "occi.core.target", target) + self.source = source + self.target = target @property def source(self): diff --git a/ooi/occi/core/resource.py b/ooi/occi/core/resource.py index c603cd9..2f984e1 100644 --- a/ooi/occi/core/resource.py +++ b/ooi/occi/core/resource.py @@ -33,7 +33,11 @@ class Resource(entity.Entity): attributes that Link sub-types inherit. """ - attributes = attribute.AttributeCollection(["occi.core.summary"]) + attributes = attribute.AttributeCollection({ + "occi.core.summary": attribute.MutableAttribute( + "occi.core.summary", description=("A summarizing description of " + "the resource instance.")) + }) kind = kind.Kind(helpers.build_scheme('core'), 'resource', 'resource', attributes, 'resource/', @@ -41,8 +45,7 @@ class Resource(entity.Entity): def __init__(self, title, mixins, id=None, summary=None): super(Resource, self).__init__(title, mixins, id=id) - self.attributes["occi.core.summary"] = attribute.MutableAttribute( - "occi.core.summary", summary) + self.summary = summary self._links = [] def __eq__(self, other): diff --git a/ooi/occi/infrastructure/compute.py b/ooi/occi/infrastructure/compute.py index 7903d5e..38f40ae 100644 --- a/ooi/occi/infrastructure/compute.py +++ b/ooi/occi/infrastructure/compute.py @@ -34,12 +34,30 @@ suspend = action.Action(helpers.build_scheme('infrastructure/compute/action'), class ComputeResource(resource.Resource): - attributes = attr.AttributeCollection(["occi.compute.architecture", - "occi.compute.cores", - "occi.compute.hostname", - "occi.compute.speed", - "occi.compute.memory", - "occi.compute.state"]) + attributes = attr.AttributeCollection({ + "occi.compute.architecture": attr.MutableAttribute( + "occi.compute.architecture", + description="CPU architecture of the instance"), + "occi.compute.cores": attr.MutableAttribute( + "occi.compute.cores", + description="Number of virtual cores assigned to the instance"), + "occi.compute.hostname": attr.MutableAttribute( + "occi.compute.hostname", + description="Fully Qualified DNS hostname for the instance"), + "occi.compute.share": attr.MutableAttribute( + "occi.compute.share", + description="Relative number of CPU shares for the instance"), + "occi.compute.memory": attr.MutableAttribute( + "occi.compute.memory", + description="Maximum RAM in gigabytes allocated to the instance"), + "occi.compute.state": attr.InmutableAttribute( + "occi.compute.state", description="Current state of the instance"), + "occi.compute.state.message": attr.InmutableAttribute( + "occi.compute.state.message", + description=("Human-readable explanation of the current instance " + "state")), + }) + actions = (start, stop, restart, suspend) kind = kind.Kind(helpers.build_scheme('infrastructure'), 'compute', 'compute resource', attributes, 'compute/', @@ -47,24 +65,23 @@ class ComputeResource(resource.Resource): parent=resource.Resource.kind) def __init__(self, title, summary=None, id=None, architecture=None, - cores=None, hostname=None, speed=None, memory=None, - state=None, mixins=[]): + cores=None, hostname=None, share=None, memory=None, + state=None, message=None, mixins=[]): super(ComputeResource, self).__init__(title, mixins, summary=summary, id=id) - self.attributes["occi.compute.architecture"] = attr.MutableAttribute( - "occi.compute.architecture", architecture) - self.attributes["occi.compute.cores"] = attr.MutableAttribute( - "occi.compute.cores", cores) - self.attributes["occi.compute.hostname"] = attr.MutableAttribute( - "occi.compute.hostname", hostname) - self.attributes["occi.compute.speed"] = attr.MutableAttribute( - "occi.compute.speed", speed) - self.attributes["occi.compute.memory"] = attr.MutableAttribute( - "occi.compute.memory", memory) - self.attributes["occi.compute.state"] = attr.InmutableAttribute( - "occi.compute.state", state) + self.architecture = architecture + self.cores = cores + self.hostname = hostname + self.share = share + self.memory = memory + self.attributes["occi.compute.state"] = ( + attr.InmutableAttribute.from_attr( + self.attributes["occi.compute.state"], state)) + self.attributes["occi.compute.state.message"] = ( + attr.InmutableAttribute( + self.attributes["occi.compute.state.message"], message)) @property def architecture(self): @@ -91,12 +108,12 @@ class ComputeResource(resource.Resource): self.attributes["occi.compute.hostname"].value = value @property - def speed(self): - return self.attributes["occi.compute.speed"].value + def share(self): + return self.attributes["occi.compute.share"].value - @speed.setter - def speed(self, value): - self.attributes["occi.compute.speed"].value = value + @share.setter + def share(self, value): + self.attributes["occi.compute.share"].value = value @property def memory(self): @@ -109,3 +126,7 @@ class ComputeResource(resource.Resource): @property def state(self): return self.attributes["occi.compute.state"].value + + @property + def message(self): + return self.attributes["occi.compute.state.message"].value diff --git a/ooi/occi/infrastructure/network.py b/ooi/occi/infrastructure/network.py index 8b10684..5899599 100644 --- a/ooi/occi/infrastructure/network.py +++ b/ooi/occi/infrastructure/network.py @@ -29,9 +29,19 @@ down = action.Action(helpers.build_scheme('infrastructure/network/action'), class NetworkResource(resource.Resource): - attributes = attr.AttributeCollection(["occi.network.vlan", - "occi.network.label", - "occi.network.state"]) + attributes = attr.AttributeCollection({ + "occi.network.vlan": attr.MutableAttribute( + "occi.network.vlan", description="802.1q VLAN identifier"), + "occi.network.label": attr.MutableAttribute( + "occi.network.label", description="Tag based VLANs"), + "occi.network.state": attr.InmutableAttribute( + "occi.network.state", description="Current state of the instance"), + "occi.network.state.message": attr.InmutableAttribute( + "occi.network.state.message", + description=("Human-readable explanation of the current instance " + "state")), + }) + actions = (up, down) kind = kind.Kind(helpers.build_scheme('infrastructure'), 'network', 'network resource', attributes, 'network/', @@ -39,15 +49,17 @@ class NetworkResource(resource.Resource): parent=resource.Resource.kind) def __init__(self, title, summary=None, id=None, vlan=None, label=None, - state=None, mixins=[]): + state=None, message=None, mixins=[]): super(NetworkResource, self).__init__(title, mixins, summary=summary, id=id) - self.attributes["occi.network.vlan"] = attr.MutableAttribute( - "occi.network.vlan", vlan) - self.attributes["occi.network.label"] = attr.MutableAttribute( - "occi.network.label", label) - self.attributes["occi.network.state"] = attr.InmutableAttribute( - "occi.network.state", state) + self.vlan = vlan + self.label = label + self.attributes["occi.network.state"] = ( + attr.InmutableAttribute.from_attr( + self.attributes["occi.network.state"], state)) + self.attributes["occi.network.state.message"] = ( + attr.InmutableAttribute( + self.attributes["occi.network.state.message"], message)) @property def vlan(self): @@ -69,11 +81,24 @@ class NetworkResource(resource.Resource): def state(self): return self.attributes["occi.network.state"].value + @property + def message(self): + return self.attributes["occi.network.state.message"].value -ip_network = mixin.Mixin(helpers.build_scheme("infrastructure/network"), - "ipnetwork", "IP Networking Mixin", - attributes=attr.AttributeCollection([ - "occi.network.address", - "occi.network.gateway", - "occi.network.allocation"]), - applies=[NetworkResource.kind]) + +ip_network = mixin.Mixin( + helpers.build_scheme("infrastructure/network"), + "ipnetwork", "IP Networking Mixin", + attributes=attr.AttributeCollection({ + "occi.network.address": attr.MutableAttribute( + "occi.network.address", + description="Internet Protocol (IP) network address"), + "occi.network.gateway": attr.MutableAttribute( + "occi.network.gateway", + description="Internet Protocol (IP) network address"), + "occi.network.allocation": attr.MutableAttribute( + "occi.network.allocation", + description="Address allocation mechanism: dynamic, static", + ), + }), + applies=[NetworkResource.kind]) diff --git a/ooi/occi/infrastructure/network_link.py b/ooi/occi/infrastructure/network_link.py index eac7f29..860e8a1 100644 --- a/ooi/occi/infrastructure/network_link.py +++ b/ooi/occi/infrastructure/network_link.py @@ -22,27 +22,46 @@ from ooi.occi import helpers class NetworkInterface(link.Link): - attributes = attr.AttributeCollection(["occi.networkinterface.interface", - "occi.networkinterface.mac", - "occi.networkinterface.state"]) + attributes = attr.AttributeCollection({ + "occi.networkinterface.interface": attr.InmutableAttribute( + "occi.networkinterface.interface", + description=("Identifier that relates the link to the link's " + "device interface.")), + "occi.networkinterface.mac": attr.MutableAttribute( + "occi.networkinterface.mac", + description=("MAC address associated with the link's device " + "interface.")), + "occi.networkinterface.state": attr.InmutableAttribute( + "occi.networkinterface.state", + description="Current state of the instance"), + "occi.networkinterface.state.message": attr.InmutableAttribute( + "occi.networkinterface.state.message", + description=("Human-readable explanation of the current instance " + "state")), + }) + kind = kind.Kind(helpers.build_scheme('infrastructure'), 'networkinterface', 'network link resource', attributes, 'networklink/', parent=link.Link.kind) def __init__(self, mixins, source, target, id=None, interface=None, - mac=None, state=None): + mac=None, state=None, message=None): super(NetworkInterface, self).__init__(None, mixins, source, target, id) self.attributes["occi.networkinterface.interface"] = ( - attr.InmutableAttribute("occi.networkinterface.interface", - interface)) - self.attributes["occi.networkinterface.mac"] = attr.MutableAttribute( - "occi.networkinterface.mac", mac) + attr.InmutableAttribute.from_attr( + self.attributes["occi.networkinterface.interface"], interface)) + self.mac = mac self.attributes["occi.networkinterface.state"] = ( - attr.InmutableAttribute("occi.networkinterface.state", state)) + attr.InmutableAttribute.from_attr( + self.attributes["occi.networkinterface.state"], state)) + self.attributes["occi.networkinterface.state.message"] = ( + attr.InmutableAttribute.from_attr( + self.attributes["occi.networkinterface.state.message"], + message)) @property def interface(self): @@ -60,11 +79,23 @@ class NetworkInterface(link.Link): def state(self): return self.attributes["occi.networkinterface.state"].value + @property + def message(self): + return self.attributes["occi.networkinterface.state.message"].value + ip_network_interface = mixin.Mixin( helpers.build_scheme("infrastructure/networkinterface"), "ipnetworkinterface", "IP Network interface Mixin", - attributes=attr.AttributeCollection([ - "occi.networkinterface.address", - "occi.networkinterface.gateway", - "occi.networkinterface.allocation"]), + attributes=attr.AttributeCollection({ + "occi.networkinterface.address": attr.MutableAttribute( + "occi.networkinterface.address", + description="Internet Protocol (IP) network address of the link"), + "occi.networkinterface.gateway": attr.MutableAttribute( + "occi.networkinterface.gateway", + description="Internet Protocol (IP) network address"), + "occi.networkinterface.allocation": attr.MutableAttribute( + "occi.networkinterface.allocation", + description="Address allocation mechanism: dynamic, static", + ), + }), applies=[NetworkInterface.kind]) diff --git a/ooi/occi/infrastructure/storage.py b/ooi/occi/infrastructure/storage.py index cd2cafc..8d5239d 100644 --- a/ooi/occi/infrastructure/storage.py +++ b/ooi/occi/infrastructure/storage.py @@ -37,22 +37,35 @@ resize = action.Action(helpers.build_scheme('infrastructure/storage/action'), class StorageResource(resource.Resource): - attributes = attr.AttributeCollection(["occi.storage.size", - "occi.storage.state"]) + attributes = attr.AttributeCollection({ + "occi.storage.size": attr.MutableAttribute( + "occi.storage.size", required=True, + description="Storage size of the instance in gigabytes"), + "occi.storage.state": attr.InmutableAttribute( + "occi.storage.state", description="Current state of the instance"), + "occi.storage.state.message": attr.InmutableAttribute( + "occi.storage.state.message", + description=("Human-readable explanation of the current instance " + "state")), + }) actions = (online, offline, backup, snapshot, resize) kind = kind.Kind(helpers.build_scheme('infrastructure'), 'storage', 'storage resource', attributes, 'storage/', actions=actions, parent=resource.Resource.kind) - def __init__(self, title, summary=None, id=None, size=None, state=None): + def __init__(self, title, summary=None, id=None, size=None, state=None, + message=None): mixins = [] super(StorageResource, self).__init__(title, mixins, summary=summary, id=id) - self.attributes["occi.storage.size"] = attr.MutableAttribute( - "occi.storage.size", size) - self.attributes["occi.storage.state"] = attr.InmutableAttribute( - "occi.storage.state", state) + self.size = size + self.attributes["occi.storage.state"] = ( + attr.InmutableAttribute.from_attr( + self.attributes["occi.storage.state"], state)) + self.attributes["occi.storage.state.message"] = ( + attr.InmutableAttribute.from_attr( + self.attributes["occi.storage.state.message"], message)) @property def size(self): @@ -65,3 +78,7 @@ class StorageResource(resource.Resource): @property def state(self): return self.attributes["occi.storage.state"].value + + @property + def message(self): + return self.attributes["occi.storage.state.message"].value diff --git a/ooi/occi/infrastructure/storage_link.py b/ooi/occi/infrastructure/storage_link.py index 6a439f7..dc6394f 100644 --- a/ooi/occi/infrastructure/storage_link.py +++ b/ooi/occi/infrastructure/storage_link.py @@ -21,26 +21,42 @@ from ooi.occi import helpers class StorageLink(link.Link): - attributes = attr.AttributeCollection(["occi.storagelink.deviceid", - "occi.storagelink.mountpoint", - "occi.storagelink.state"]) + attributes = attr.AttributeCollection({ + "occi.storagelink.deviceid": attr.MutableAttribute( + "occi.storagelink.deviceid", + description=("Device identifier as defined by the OCCI service " + "provider")), + "occi.storagelink.mountpoint": attr.MutableAttribute( + "occi.storagelink.mountpoint", + description=("Point to where the storage is mounted " + "in the guest OS")), + "occi.storagelink.state": attr.InmutableAttribute( + "occi.storagelink.state", + description="Current state of the instance"), + "occi.storagelink.state.message": attr.InmutableAttribute( + "occi.storagelink.state.message", + description=("Human-readable explanation of the current instance " + "state")), + }) kind = kind.Kind(helpers.build_scheme('infrastructure'), 'storagelink', 'storage link resource', attributes, 'storagelink/', parent=link.Link.kind) def __init__(self, source, target, deviceid=None, mountpoint=None, - state=None): + state=None, message=None): # TODO(enolfc): is this a valid link id? link_id = '_'.join([source.id, target.id]) super(StorageLink, self).__init__(None, [], source, target, link_id) - self.attributes["occi.storagelink.deviceid"] = attr.MutableAttribute( - "occi.storagelink.deviceid", deviceid) - self.attributes["occi.storagelink.mountpoint"] = attr.MutableAttribute( - "occi.storagelink.mountpoint", mountpoint) - self.attributes["occi.storagelink.state"] = attr.InmutableAttribute( - "occi.storagelink.state", state) + self.deviceid = deviceid + self.mountpoint = mountpoint + self.attributes["occi.storagelink.state"] = ( + attr.InmutableAttribute.from_attr( + self.attributes["occi.storagelink.state"], state)) + self.attributes["occi.storagelink.state.message"] = ( + attr.InmutableAttribute.from_attr( + self.attributes["occi.storagelink.state.message"], message)) @property def deviceid(self): @@ -61,3 +77,7 @@ class StorageLink(link.Link): @property def state(self): return self.attributes["occi.storagelink.state"].value + + @property + def message(self): + return self.attributes["occi.storagelink.state.message"].value diff --git a/ooi/openstack/contextualization.py b/ooi/openstack/contextualization.py index 23fa114..13a2d4e 100644 --- a/ooi/openstack/contextualization.py +++ b/ooi/openstack/contextualization.py @@ -26,7 +26,7 @@ class OpenStackUserData(mixin.Mixin): def __init__(self, user_data=None): attrs = [ attribute.InmutableAttribute("org.openstack.compute.user_data", - user_data), + user_data, required=True), ] attrs = attribute.AttributeCollection({a.name: a for a in attrs}) @@ -50,7 +50,8 @@ class OpenStackPublicKey(mixin.Mixin): attribute.InmutableAttribute( "org.openstack.credentials.publickey.name", name), attribute.InmutableAttribute( - "org.openstack.credentials.publickey.data", data), + "org.openstack.credentials.publickey.data", data, + required=True), ] attrs = attribute.AttributeCollection({a.name: a for a in attrs}) diff --git a/ooi/openstack/network.py b/ooi/openstack/network.py index ee5da42..d48e9f6 100644 --- a/ooi/openstack/network.py +++ b/ooi/openstack/network.py @@ -30,9 +30,19 @@ class OSFloatingIPPool(mixin.Mixin): class OSNetworkInterface(network_link.NetworkInterface): - attributes = attr.AttributeCollection(["occi.networkinterface.address", - "occi.networkinterface.gateway", - "occi.networkinterface.allocation"]) + # TODO(enolfc): these are duplicated in the ipnetwork_interface mixin + attributes = attr.AttributeCollection({ + "occi.networkinterface.address": attr.MutableAttribute( + "occi.networkinterface.address", + description="Internet Protocol (IP) network address of the link"), + "occi.networkinterface.gateway": attr.MutableAttribute( + "occi.networkinterface.gateway", + description="Internet Protocol (IP) network address"), + "occi.networkinterface.allocation": attr.MutableAttribute( + "occi.networkinterface.allocation", + description="Address allocation mechanism: dynamic, static", + ), + }) def __init__(self, source, target, mac, address, ip_id=None, pool=None, state='active'): @@ -44,13 +54,9 @@ class OSNetworkInterface(network_link.NetworkInterface): link_id, "eth0", mac, state) self.ip_id = ip_id - self.attributes["occi.networkinterface.address"] = ( - attr.MutableAttribute("occi.networkinterface.address", address)) - self.attributes["occi.networkinterface.gateway"] = ( - attr.MutableAttribute("occi.networkinterface.gateway", None)) - self.attributes["occi.networkinterface.allocation"] = ( - attr.MutableAttribute("occi.networkinterface.allocation", - "dynamic")) + self.address = address + self.gateway = None + self.allocation = "dynamic" @property def address(self): @@ -98,13 +104,22 @@ os_network = OSNetwork() class OSNetworkResource(network.NetworkResource): - - attributes = attr.AttributeCollection([ - "org.openstack.network.ip_version", - "occi.network.address", - "occi.network.gateway", - "occi.network.allocation", - ]) + # TODO(enolfc): most of these are duplicated in the ipnetwork mixin + attributes = attr.AttributeCollection({ + "occi.network.address": attr.MutableAttribute( + "occi.network.address", required=True, + description="Internet Protocol (IP) network address"), + "occi.network.gateway": attr.MutableAttribute( + "occi.network.gateway", + description="Internet Protocol (IP) network address"), + "occi.network.allocation": attr.MutableAttribute( + "occi.network.allocation", + description="Address allocation mechanism: dynamic, static", + ), + "org.openstack.network.ip_version": attr.MutableAttribute( + "org.openstack.network.ip_version", + description="Internet Protocol (IP) version"), + }) def __init__(self, title=None, summary=None, id=None, vlan=None, label=None, state=None, @@ -116,18 +131,10 @@ class OSNetworkResource(network.NetworkResource): label=label, state=state, mixins=[network.ip_network, OSNetwork()]) # subnet - self.attributes["org.openstack.network.ip_version"] = ( - attr.MutableAttribute( - "org.openstack.network.ip_version", ip_version)) - self.attributes["occi.network.address"] = ( - attr.MutableAttribute( - "occi.network.address", address)) - self.attributes["occi.network.gateway"] = ( - attr.MutableAttribute( - "occi.network.gateway", gateway)) - self.attributes["occi.network.allocation"] = ( - attr.MutableAttribute( - "occi.network.allocation", allocation)) + self.address = address + self.gateway = gateway + self.ip_version = ip_version + self.allocation = allocation @property def ip_version(self): diff --git a/ooi/tests/unit/occi/test_occi_core.py b/ooi/tests/unit/occi/test_occi_core.py index ca1a13a..7c5d0e1 100644 --- a/ooi/tests/unit/occi/test_occi_core.py +++ b/ooi/tests/unit/occi/test_occi_core.py @@ -32,6 +32,22 @@ class TestAttributes(base.TestCase): attr = attribute.Attribute("occi.foo.bar", "bar") self.assertEqual("bar", attr.value) self.assertEqual("occi.foo.bar", attr.name) + self.assertEqual(False, attr.required) + self.assertEqual(None, attr.default) + self.assertEqual(None, attr.description) + + def test_default_value(self): + attr = attribute.Attribute("occi.foo.bar", default="bar") + self.assertEqual(None, attr.value) + self.assertEqual("bar", attr.default) + + def test_required(self): + attr = attribute.Attribute("occi.foo.bar", required=True) + self.assertEqual(True, attr.required) + + def test_description(self): + attr = attribute.Attribute("occi.foo.bar", description="foo") + self.assertEqual("foo", attr.description) def test_mutable(self): attr = attribute.MutableAttribute("occi.foo.bar", "bar") @@ -46,6 +62,34 @@ class TestAttributes(base.TestCase): self.assertRaises(AttributeError, set_val) + def test_attribute_type_list(self): + attr = attribute.MutableAttribute( + "occi.foo.bar", "bar", attr_type=attribute.AttributeType.list_type) + attr.value = ['2'] + + def set_object_val(): + attr.value = "object" + + def set_hash_val(): + attr.value = {} + + self.assertRaises(TypeError, set_object_val) + self.assertRaises(TypeError, set_hash_val) + + def test_attribute_type_hash(self): + attr = attribute.MutableAttribute( + "occi.foo.bar", "bar", attr_type=attribute.AttributeType.hash_type) + attr.value = {'foo': 'bar'} + + def set_object_val(): + attr.value = "object" + + def set_list_val(): + attr.value = [] + + self.assertRaises(TypeError, set_object_val) + self.assertRaises(TypeError, set_list_val) + class TestAttributeCollection(base.TestCase): def test_collection(self): diff --git a/ooi/tests/unit/occi/test_occi_infrastructure.py b/ooi/tests/unit/occi/test_occi_infrastructure.py index 8e7ca29..76be570 100644 --- a/ooi/tests/unit/occi/test_occi_infrastructure.py +++ b/ooi/tests/unit/occi/test_occi_infrastructure.py @@ -42,8 +42,9 @@ class TestOCCICompute(base.TestCase): self.assertIn("occi.compute.cores", c.attributes) self.assertIn("occi.compute.hostname", c.attributes) self.assertIn("occi.compute.memory", c.attributes) - self.assertIn("occi.compute.speed", c.attributes) + self.assertIn("occi.compute.share", c.attributes) self.assertIn("occi.compute.state", c.attributes) + self.assertIn("occi.compute.state.message", c.attributes) self.assertEqual(resource.Resource.kind, c.kind.parent) self.assertEqual(c.kind.location, "compute/") # TODO(aloga): We need to check that the attributes are actually set @@ -62,7 +63,8 @@ class TestOCCICompute(base.TestCase): self.assertIsNone(c.cores) self.assertIsNone(c.hostname) self.assertIsNone(c.memory) - self.assertIsNone(c.speed) + self.assertIsNone(c.share) + self.assertIsNone(c.message) def test_setters(self): c = compute.ComputeResource("foo") @@ -73,22 +75,23 @@ class TestOCCICompute(base.TestCase): self.assertEqual(5, c.attributes["occi.compute.cores"].value) c.hostname = "foobar" self.assertEqual("foobar", c.attributes["occi.compute.hostname"].value) - c.speed = 8 - self.assertEqual(8, c.attributes["occi.compute.speed"].value) + c.share = 8 + self.assertEqual(8, c.attributes["occi.compute.share"].value) c.memory = 4 self.assertEqual(4, c.attributes["occi.compute.memory"].value) def test_getters(self): - c = compute.ComputeResource("foo", state="baz") + c = compute.ComputeResource("foo", state="baz", message="msg") self.assertEqual("baz", c.state) + self.assertEqual("msg", c.message) c.attributes["occi.compute.architecture"].value = "bar" self.assertEqual("bar", c.architecture) c.attributes["occi.compute.cores"].value = 5 self.assertEqual(5, c.cores) c.attributes["occi.compute.hostname"].value = "foobar" self.assertEqual("foobar", c.hostname) - c.attributes["occi.compute.speed"].value = 8 - self.assertEqual(8, c.speed) + c.attributes["occi.compute.share"].value = 8 + self.assertEqual(8, c.share) c.attributes["occi.compute.memory"].value = 9 self.assertEqual(9, c.memory) @@ -106,6 +109,7 @@ class TestOCCIStorage(base.TestCase): self.assertIn("occi.core.title", s.attributes) self.assertIn("occi.storage.size", s.attributes) self.assertIn("occi.storage.state", s.attributes) + self.assertIn("occi.storage.state.message", s.attributes) self.assertEqual(resource.Resource.kind, s.kind.parent) self.assertEqual(s.kind.location, "storage/") # TODO(aloga): We need to check that the attributes are actually set @@ -122,6 +126,7 @@ class TestOCCIStorage(base.TestCase): self.assertEqual("This is a summary", s.summary) self.assertIsNone(s.size) self.assertIsNone(s.state) + self.assertIsNone(s.message) def test_setters(self): s = storage.StorageResource("foo") @@ -129,9 +134,11 @@ class TestOCCIStorage(base.TestCase): self.assertEqual(3, s.attributes["occi.storage.size"].value) def test_getters(self): - s = storage.StorageResource("foo", size=5, state="foobar") + s = storage.StorageResource("foo", size=5, state="foobar", + message="msg") self.assertEqual(5, s.size) self.assertEqual("foobar", s.state) + self.assertEqual("msg", s.message) class TestOCCIStorageLink(base.TestCase): @@ -144,6 +151,7 @@ class TestOCCIStorageLink(base.TestCase): self.assertIn("occi.storagelink.mountpoint", s.attributes) self.assertIn("occi.storagelink.deviceid", s.attributes) self.assertIn("occi.storagelink.state", s.attributes) + self.assertIn("occi.storagelink.state.message", s.attributes) self.assertEqual(link.Link.kind, s.kind.parent) self.assertEqual(s.kind.location, "storagelink/") @@ -162,6 +170,7 @@ class TestOCCIStorageLink(base.TestCase): self.assertIsNone(l.deviceid) self.assertIsNone(l.mountpoint) self.assertIsNone(l.state) + self.assertIsNone(l.message) def test_setters(self): c = compute.ComputeResource("foo", @@ -186,10 +195,12 @@ class TestOCCIStorageLink(base.TestCase): summary="This is a summary", id=uuid.uuid4().hex) l = storage_link.StorageLink(c, s, deviceid="/dev/vdc", - mountpoint="/mnt", state="foobar") + mountpoint="/mnt", state="foobar", + message="msg") self.assertEqual("/dev/vdc", l.deviceid) self.assertEqual("/mnt", l.mountpoint) self.assertEqual("foobar", l.state) + self.assertEqual("msg", l.message) class TestTemplates(base.TestCase): @@ -217,6 +228,7 @@ class TestOCCINetwork(base.TestCase): self.assertIn("occi.network.vlan", n.attributes) self.assertIn("occi.network.label", n.attributes) self.assertIn("occi.network.state", n.attributes) + self.assertIn("occi.network.state.message", n.attributes) self.assertEqual(resource.Resource.kind, n.kind.parent) self.assertEqual(n.kind.location, "network/") # TODO(aloga): We need to check that the attributes are actually set @@ -234,6 +246,7 @@ class TestOCCINetwork(base.TestCase): self.assertIsNone(n.vlan) self.assertIsNone(n.label) self.assertIsNone(n.state) + self.assertIsNone(n.message) def test_setters(self): n = network.NetworkResource("foo") @@ -244,10 +257,11 @@ class TestOCCINetwork(base.TestCase): def test_getters(self): n = network.NetworkResource("foo", vlan="bar", label="baz", - state="foobar") + state="foobar", message="msg") self.assertEqual("bar", n.vlan) self.assertEqual("baz", n.label) self.assertEqual("foobar", n.state) + self.assertEqual("msg", n.message) class TestNetworkMixins(base.TestCase): @@ -283,6 +297,7 @@ class TestOCCINetworkInterface(base.TestCase): self.assertIn("occi.networkinterface.interface", l.attributes) self.assertIn("occi.networkinterface.mac", l.attributes) self.assertIn("occi.networkinterface.state", l.attributes) + self.assertIn("occi.networkinterface.state.message", l.attributes) self.assertEqual(link.Link.kind, l.kind.parent) self.assertEqual(l.kind.location, "networklink/") @@ -299,6 +314,7 @@ class TestOCCINetworkInterface(base.TestCase): self.assertIsNone(l.interface) self.assertIsNone(l.mac) self.assertIsNone(l.state) + self.assertIsNone(l.message) def test_setters(self): c = compute.ComputeResource("foo", @@ -320,7 +336,9 @@ class TestOCCINetworkInterface(base.TestCase): summary="This is a summary", id=uuid.uuid4().hex) l = network_link.NetworkInterface([], c, n, interface="eth1", - mac="00:01:02:03:04:05", state="foo") + mac="00:01:02:03:04:05", state="foo", + message="msg") self.assertEqual("eth1", l.interface) self.assertEqual("00:01:02:03:04:05", l.mac) self.assertEqual("foo", l.state) + self.assertEqual("msg", l.message) diff --git a/requirements.txt b/requirements.txt index 531c7d6..4597338 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ oslo.log oslo.config routes WebOb +enum34