Add support for network Flavor

There is an existing feature in neutron for creating
flavors for networks.

Partially-Implements: blueprint neutron-client-flavors

Change-Id: I57ad6a26cf70f314c594a8440da9418f29395e27
This commit is contained in:
Ankur Gupta 2016-09-19 19:11:00 -05:00 committed by Ankur
parent 809f2fac73
commit ef225f9caf
7 changed files with 271 additions and 0 deletions

View File

@ -8,6 +8,7 @@ Network Resources
v2/agent
v2/availability_zone
v2/extension
v2/flavor
v2/floating_ip
v2/health_monitor
v2/listener

View File

@ -0,0 +1,12 @@
openstack.network.v2.flavor
===========================
.. automodule:: openstack.network.v2.flavor
The Flavor Class
----------------
The ``Flavor`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.network.v2.flavor.Flavor
:members:

View File

@ -14,6 +14,7 @@ from openstack.network.v2 import address_scope as _address_scope
from openstack.network.v2 import agent as _agent
from openstack.network.v2 import availability_zone
from openstack.network.v2 import extension
from openstack.network.v2 import flavor as _flavor
from openstack.network.v2 import floating_ip as _floating_ip
from openstack.network.v2 import health_monitor as _health_monitor
from openstack.network.v2 import listener as _listener
@ -822,6 +823,86 @@ class Proxy(proxy.BaseProxy):
"""
return self._update(_network.Network, network, **attrs)
def create_flavor(self, **attrs):
"""Create a new network service flavor from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.network.v2.flavor.Flavor`,
comprised of the properties on the Flavor class.
:returns: The results of flavor creation
:rtype: :class:`~openstack.network.v2.flavor.Flavor`
"""
return self._create(_flavor.Flavor, **attrs)
def delete_flavor(self, flavor, ignore_missing=True):
"""Delete a network service flavor
:param flavor:
The value can be either the ID of a flavor or a
:class:`~openstack.network.v2.flavor.Flavor` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the flavor does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent flavor.
:returns: ``None``
"""
self._delete(_flavor.Flavor, flavor, ignore_missing=ignore_missing)
def find_flavor(self, name_or_id, ignore_missing=True):
"""Find a single network service flavor
:param name_or_id: The name or ID of a flavor.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.network.v2.flavor.Flavor` or None
"""
return self._find(_flavor.Flavor, name_or_id,
ignore_missing=ignore_missing)
def get_flavor(self, flavor):
"""Get a single network service flavor
:param flavor:
The value can be the ID of a flavor or a
:class:`~openstack.network.v2.flavor.Flavor` instance.
:returns: One :class:`~openstack.network.v2.flavor.Flavor`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
return self._get(_flavor.Flavor, flavor)
def update_flavor(self, flavor, **attrs):
"""Update a network service flavor
:param flavor:
Either the id of a flavor or a
:class:`~openstack.network.v2.flavor.Flavor` instance.
:attrs kwargs: The attributes to update on the flavor represented
by ``value``.
:returns: The updated flavor
:rtype: :class:`~openstack.network.v2.flavor.Flavor`
"""
return self._update(_flavor.Flavor, flavor, **attrs)
def flavors(self, **query):
"""Return a generator of network service flavors
:param kwargs \*\*query: Optional query parameters to be sent to limit
the resources being returned.
:returns: A generator of flavor objects
:rtype: :class:`~openstack.network.v2.flavor.Flavor`
"""
return self._list(_flavor.Flavor, paginated=True, **query)
def find_network_ip_availability(self, name_or_id, ignore_missing=True):
"""Find IP availability of a network

View File

@ -0,0 +1,40 @@
# 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 openstack.network import network_service
from openstack import resource
class Flavor(resource.Resource):
resource_key = 'flavor'
resources_key = 'flavors'
base_path = '/flavors'
service = network_service.NetworkService()
# capabilities
allow_create = True
allow_retrieve = True
allow_update = True
allow_delete = True
allow_list = True
# properties
#: description for the flavor
description = resource.prop('description')
#: Sets enabled flag
is_enabled = resource.prop('enabled', type=bool)
#: The name of the flavor
name = resource.prop('name')
#: The owner project ID
project_id = resource.prop('tenant_id')
#: Service type to which the flavor applies
service_type = resource.prop('service_type')

View File

@ -0,0 +1,58 @@
# 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 openstack.network.v2 import flavor
from openstack.tests.functional import base
class TestFlavor(base.BaseFunctionalTest):
FLAVOR_NAME = uuid.uuid4().hex
UPDATE_NAME = "UPDATED-NAME"
SERVICE_TYPE = "FLAVORS"
ID = None
@classmethod
def setUpClass(cls):
super(TestFlavor, cls).setUpClass()
flavors = cls.conn.network.create_flavor(name=cls.FLAVOR_NAME,
service_type=cls.SERVICE_TYPE)
assert isinstance(flavors, flavor.Flavor)
cls.assertIs(cls.FLAVOR_NAME, flavors.name)
cls.assertIs(cls.SERVICE_TYPE, flavors.service_type)
cls.ID = flavors.id
@classmethod
def tearDownClass(cls):
flavors = cls.conn.network.delete_flavor(cls.ID, ignore_missing=True)
cls.assertIs(None, flavors)
def test_find(self):
flavors = self.conn.network.find_flavor(self.FLAVOR_NAME)
self.assertEqual(self.ID, flavors.id)
def test_get(self):
flavors = self.conn.network.get_flavor(self.ID)
self.assertEqual(self.FLAVOR_NAME, flavors.name)
self.assertEqual(self.ID, flavors.id)
def test_list(self):
names = [f.name for f in self.conn.network.flavors()]
self.assertIn(self.FLAVOR_NAME, names)
def test_update(self):
flavor = self.conn.network.update_flavor(self.ID,
name=self.UPDATE_NAME)
self.assertEqual(self.UPDATE_NAME, flavor.name)

View File

@ -0,0 +1,59 @@
# 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 testtools
from openstack.network.v2 import flavor
IDENTIFIER = 'IDENTIFIER'
EXAMPLE_WITH_OPTIONAL = {
'name': 'test-flavor',
'service_type': 'VPN',
'tenant_id': '5',
'description': 'VPN flavor',
'enabled': True,
}
EXAMPLE = {
'name': 'test-flavor',
'service_type': 'VPN',
}
class TestFlavor(testtools.TestCase):
def test_basic(self):
flavors = flavor.Flavor()
self.assertEqual('flavor', flavors.resource_key)
self.assertEqual('flavors', flavors.resources_key)
self.assertEqual('/flavors', flavors.base_path)
self.assertEqual('network', flavors.service.service_type)
self.assertTrue(flavors.allow_create)
self.assertTrue(flavors.allow_retrieve)
self.assertTrue(flavors.allow_update)
self.assertTrue(flavors.allow_delete)
self.assertTrue(flavors.allow_list)
def test_make_it(self):
flavors = flavor.Flavor(EXAMPLE)
self.assertEqual(EXAMPLE['name'], flavors.name)
self.assertEqual(EXAMPLE['service_type'], flavors.service_type)
def test_make_it_with_optional(self):
flavors = flavor.Flavor(EXAMPLE_WITH_OPTIONAL)
self.assertEqual(EXAMPLE_WITH_OPTIONAL['name'], flavors.name)
self.assertEqual(EXAMPLE_WITH_OPTIONAL['service_type'],
flavors.service_type)
self.assertEqual(EXAMPLE_WITH_OPTIONAL['tenant_id'],
flavors.tenant_id)
self.assertEqual(EXAMPLE_WITH_OPTIONAL['description'],
flavors.description)
self.assertEqual(EXAMPLE_WITH_OPTIONAL['enabled'], flavors.is_enabled)

View File

@ -18,6 +18,7 @@ from openstack.network.v2 import address_scope
from openstack.network.v2 import agent
from openstack.network.v2 import availability_zone
from openstack.network.v2 import extension
from openstack.network.v2 import flavor
from openstack.network.v2 import floating_ip
from openstack.network.v2 import health_monitor
from openstack.network.v2 import listener
@ -297,6 +298,25 @@ class TestNetworkProxy(test_proxy_base.TestProxyBase):
def test_network_update(self):
self.verify_update(self.proxy.update_network, network.Network)
def test_flavor_create_attrs(self):
self.verify_create(self.proxy.create_flavor, flavor.Flavor)
def test_flavor_delete(self):
self.verify_delete(self.proxy.delete_flavor, flavor.Flavor, True)
def test_flavor_find(self):
self.verify_find(self.proxy.find_flavor, flavor.Flavor)
def test_flavor_get(self):
self.verify_get(self.proxy.get_flavor, flavor.Flavor)
def test_flavor_update(self):
self.verify_update(self.proxy.update_flavor, flavor.Flavor)
def test_flavors(self):
self.verify_list(self.proxy.flavors, flavor.Flavor,
paginated=True)
def test_network_ip_availability_find(self):
self.verify_find(self.proxy.find_network_ip_availability,
network_ip_availability.NetworkIPAvailability)