Implement network agents
This commit adds api support for network agents. Change-Id: I9755637f76787d5fac8ff295ae273b308fcb98d0 Implements: blueprint implement-network-agents
This commit is contained in:
parent
13e94f55e9
commit
83aef9c8a0
@ -76,6 +76,19 @@ provide external network access for servers on project networks.
|
||||
|
||||
Full example: `network resource list`_
|
||||
|
||||
List Network Agents
|
||||
------------
|
||||
|
||||
A **network agent** is a plugin that handles various tasks used to
|
||||
implement virtual networks. These agents include neutron-dhcp-agent,
|
||||
neutron-l3-agent, neutron-metering-agent, and neutron-lbaas-agent,
|
||||
among others.
|
||||
|
||||
.. literalinclude:: ../examples/network/list.py
|
||||
:pyobject: list_network_agents
|
||||
|
||||
Full example: `network resource list`_
|
||||
|
||||
Create Network
|
||||
--------------
|
||||
|
||||
@ -100,4 +113,4 @@ Full example: `network resource delete`_
|
||||
|
||||
.. _network resource create: http://git.openstack.org/cgit/openstack/python-openstacksdk/tree/examples/network/create.py
|
||||
.. _network resource delete: http://git.openstack.org/cgit/openstack/python-openstacksdk/tree/examples/network/delete.py
|
||||
.. _network resource list: http://git.openstack.org/cgit/openstack/python-openstacksdk/tree/examples/network/list.py
|
||||
.. _network resource list: http://git.openstack.org/cgit/openstack/python-openstacksdk/tree/examples/network/list.py
|
||||
|
@ -5,6 +5,7 @@ Network Resources
|
||||
:maxdepth: 1
|
||||
|
||||
v2/address_scope
|
||||
v2/agent
|
||||
v2/availability_zone
|
||||
v2/extension
|
||||
v2/floating_ip
|
||||
|
12
doc/source/users/resources/network/v2/agent.rst
Normal file
12
doc/source/users/resources/network/v2/agent.rst
Normal file
@ -0,0 +1,12 @@
|
||||
openstack.network.v2.network
|
||||
============================
|
||||
|
||||
.. automodule:: openstack.network.v2.agent
|
||||
|
||||
The Agent Class
|
||||
-----------------
|
||||
|
||||
The ``Agent`` class inherits from :class:`~openstack.resource.Resource`.
|
||||
|
||||
.. autoclass:: openstack.network.v2.agent.Agent
|
||||
:members:
|
@ -50,3 +50,10 @@ def list_routers(conn):
|
||||
|
||||
for router in conn.network.routers():
|
||||
print(router)
|
||||
|
||||
|
||||
def list_network_agents(conn):
|
||||
print("List Network Agents:")
|
||||
|
||||
for agent in conn.network.agents():
|
||||
print(agent)
|
||||
|
@ -11,6 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
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 floating_ip as _floating_ip
|
||||
@ -122,6 +123,59 @@ class Proxy(proxy.BaseProxy):
|
||||
address_scope,
|
||||
**attrs)
|
||||
|
||||
def agents(self, **query):
|
||||
"""Return a generator of network agents
|
||||
|
||||
:param kwargs \*\*query: Optional query parameters to be sent to limit
|
||||
the resources being returned.
|
||||
|
||||
:returns: A generator of agents
|
||||
:rtype: :class:`~openstack.network.v2.agent.Agent`
|
||||
"""
|
||||
return self._list(_agent.Agent, paginated=False, **query)
|
||||
|
||||
def delete_agent(self, agent, ignore_missing=True):
|
||||
"""Delete a network agent
|
||||
|
||||
:param agent: The value can be the ID of a agent or a
|
||||
:class:`~openstack.network.v2.agent.Agent` instance.
|
||||
:param bool ignore_missing: When set to ``False``
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be
|
||||
raised when the agent does not exist.
|
||||
When set to ``True``, no exception will be set when
|
||||
attempting to delete a nonexistent agent.
|
||||
|
||||
:returns: ``None``
|
||||
"""
|
||||
self._delete(_agent.Agent, agent,
|
||||
ignore_missing=ignore_missing)
|
||||
|
||||
def get_agent(self, agent, ignore_missing=True):
|
||||
"""Get a single network agent
|
||||
|
||||
:param agent: The value can be the ID of a agent or a
|
||||
:class:`~openstack.network.v2.agent.Agent` instance.
|
||||
|
||||
:returns: One :class:`~openstack.network.v2.agent.Agent`
|
||||
:rtype: :class:`~openstack.network.v2.agent.Agent`
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound`
|
||||
when no resource can be found.
|
||||
"""
|
||||
return self._get(_agent.Agent, agent)
|
||||
|
||||
def update_agent(self, agent, **attrs):
|
||||
"""Update a network agent
|
||||
|
||||
:param agent: The value can be the ID of a agent or a
|
||||
:class:`~openstack.network.v2.agent.Agent` instance.
|
||||
:attrs kwargs: The attributes to update on the agent represented
|
||||
by ``value``.
|
||||
|
||||
:returns: One :class:`~openstack.network.v2.agent.Agent`
|
||||
:rtype: :class:`~openstack.network.v2.agent.Agent`
|
||||
"""
|
||||
return self._update(_agent.Agent, agent, **attrs)
|
||||
|
||||
def availability_zones(self):
|
||||
"""Return a generator of availability zones
|
||||
|
||||
|
61
openstack/network/v2/agent.py
Normal file
61
openstack/network/v2/agent.py
Normal file
@ -0,0 +1,61 @@
|
||||
# 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 import format
|
||||
from openstack.network import network_service
|
||||
from openstack import resource
|
||||
|
||||
|
||||
class Agent(resource.Resource):
|
||||
resource_key = 'agent'
|
||||
resources_key = 'agents'
|
||||
base_path = '/agents'
|
||||
service = network_service.NetworkService()
|
||||
|
||||
# capabilities
|
||||
allow_create = False
|
||||
allow_retrieve = True
|
||||
allow_update = True
|
||||
allow_delete = True
|
||||
allow_list = True
|
||||
|
||||
# Properties
|
||||
#: The type of network agent.
|
||||
agent_type = resource.prop('agent_type')
|
||||
#: Availability zone for the network agent.
|
||||
availability_zone = resource.prop('availability_zone')
|
||||
#: The name of the network agent's application binary.
|
||||
binary = resource.prop('binary')
|
||||
#: Network agent configuration data specific to the agent_type.
|
||||
configuration = resource.prop('configurations')
|
||||
#: Timestamp when the network agent was created.
|
||||
#: *Type: datetime object parsed from ISO 8601 formatted string*
|
||||
created_at = resource.prop('created_at', type=format.ISO8601)
|
||||
#: The network agent description.
|
||||
description = resource.prop('description')
|
||||
#: Timestamp when the network agent's heartbeat was last seen.
|
||||
#: *Type: datetime object parsed from ISO 8601 formatted string*
|
||||
last_heartbeat_at = resource.prop('heartbeat_timestamp',
|
||||
type=format.ISO8601)
|
||||
#: The host the agent is running on.
|
||||
host = resource.prop('host')
|
||||
#: The administrative state of the network agent, which is up
|
||||
#: ``True`` or down ``False``. *Type: bool*
|
||||
is_admin_state_up = resource.prop('admin_state_up', type=bool)
|
||||
#: Whether or not the network agent is alive.
|
||||
#: *Type: bool*
|
||||
is_alive = resource.prop('alive', type=bool)
|
||||
#: Timestamp when the network agent was last started.
|
||||
#: *Type: datetime object parsed from ISO 8601 formatted string*
|
||||
started_at = resource.prop('started_at', type=format.ISO8601)
|
||||
#: The messaging queue topic the network agent subscribes to.
|
||||
topic = resource.prop('topic')
|
51
openstack/tests/functional/network/v2/test_agent.py
Normal file
51
openstack/tests/functional/network/v2/test_agent.py
Normal file
@ -0,0 +1,51 @@
|
||||
# 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 agent
|
||||
from openstack.tests.functional import base
|
||||
|
||||
|
||||
class TestAgent(base.BaseFunctionalTest):
|
||||
|
||||
AGENT = None
|
||||
DESC = 'test descrition'
|
||||
|
||||
def validate_uuid(self, s):
|
||||
try:
|
||||
uuid.UUID(s)
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestAgent, cls).setUpClass()
|
||||
agent_list = list(cls.conn.network.agents())
|
||||
cls.AGENT = agent_list[0]
|
||||
assert isinstance(cls.AGENT, agent.Agent)
|
||||
|
||||
def test_list(self):
|
||||
agent_list = list(self.conn.network.agents())
|
||||
self.AGENT = agent_list[0]
|
||||
assert isinstance(self.AGENT, agent.Agent)
|
||||
self.assertTrue(self.validate_uuid(self.AGENT.id))
|
||||
|
||||
def test_get(self):
|
||||
sot = self.conn.network.get_agent(self.AGENT.id)
|
||||
self.assertEqual(self.AGENT.id, sot.id)
|
||||
|
||||
def test_update(self):
|
||||
sot = self.conn.network.update_agent(self.AGENT.id,
|
||||
description=self.DESC)
|
||||
self.assertEqual(self.DESC, sot.description)
|
73
openstack/tests/unit/network/v2/test_agent.py
Normal file
73
openstack/tests/unit/network/v2/test_agent.py
Normal file
@ -0,0 +1,73 @@
|
||||
# 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 datetime
|
||||
|
||||
import testtools
|
||||
|
||||
from openstack.network.v2 import agent
|
||||
|
||||
IDENTIFIER = 'IDENTIFIER'
|
||||
EXAMPLE = {
|
||||
'admin_state_up': True,
|
||||
'agent_type': 'Test Agent',
|
||||
'alive': True,
|
||||
'availability_zone': 'az1',
|
||||
'binary': 'test-binary',
|
||||
'configurations': {'attr1': 'value1', 'attr2': 'value2'},
|
||||
'created_at': '2016-03-09T12:14:57.233772',
|
||||
'description': 'test description',
|
||||
'heartbeat_timestamp': '2016-08-09T12:14:57.233772',
|
||||
'host': 'test-host',
|
||||
'id': IDENTIFIER,
|
||||
'started_at': '2016-07-09T12:14:57.233772',
|
||||
'topic': 'test-topic'
|
||||
}
|
||||
|
||||
|
||||
class TestAgent(testtools.TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
sot = agent.Agent()
|
||||
self.assertEqual('agent', sot.resource_key)
|
||||
self.assertEqual('agents', sot.resources_key)
|
||||
self.assertEqual('/agents', sot.base_path)
|
||||
self.assertEqual('network', sot.service.service_type)
|
||||
self.assertFalse(sot.allow_create)
|
||||
self.assertTrue(sot.allow_retrieve)
|
||||
self.assertTrue(sot.allow_update)
|
||||
self.assertTrue(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = agent.Agent(EXAMPLE)
|
||||
self.assertTrue(sot.is_admin_state_up)
|
||||
self.assertEqual(EXAMPLE['agent_type'], sot.agent_type)
|
||||
self.assertTrue(sot.is_alive)
|
||||
self.assertEqual(EXAMPLE['availability_zone'],
|
||||
sot.availability_zone)
|
||||
self.assertEqual(EXAMPLE['binary'], sot.binary)
|
||||
self.assertEqual(EXAMPLE['configurations'], sot.configuration)
|
||||
dt = datetime.datetime(2016, 3, 9, 12, 14, 57, 233772).replace(
|
||||
tzinfo=None)
|
||||
self.assertEqual(dt, sot.created_at.replace(tzinfo=None))
|
||||
self.assertEqual(EXAMPLE['description'], sot.description)
|
||||
dt = datetime.datetime(2016, 8, 9, 12, 14, 57, 233772).replace(
|
||||
tzinfo=None)
|
||||
self.assertEqual(dt,
|
||||
sot.last_heartbeat_at.replace(tzinfo=None))
|
||||
self.assertEqual(EXAMPLE['host'], sot.host)
|
||||
self.assertEqual(EXAMPLE['id'], sot.id)
|
||||
dt = datetime.datetime(2016, 7, 9, 12, 14, 57, 233772).replace(
|
||||
tzinfo=None)
|
||||
self.assertEqual(dt, sot.started_at.replace(tzinfo=None))
|
||||
self.assertEqual(EXAMPLE['topic'], sot.topic)
|
@ -14,6 +14,7 @@ import mock
|
||||
|
||||
from openstack.network.v2 import _proxy
|
||||
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 floating_ip
|
||||
@ -73,6 +74,19 @@ class TestNetworkProxy(test_proxy_base.TestProxyBase):
|
||||
self.verify_update(self.proxy.update_address_scope,
|
||||
address_scope.AddressScope)
|
||||
|
||||
def test_agent_delete(self):
|
||||
self.verify_delete(self.proxy.delete_agent, agent.Agent, True)
|
||||
|
||||
def test_agent_get(self):
|
||||
self.verify_get(self.proxy.get_agent, agent.Agent)
|
||||
|
||||
def test_agents(self):
|
||||
self.verify_list(self.proxy.agents, agent.Agent,
|
||||
paginated=False)
|
||||
|
||||
def test_agent_update(self):
|
||||
self.verify_update(self.proxy.update_agent, agent.Agent)
|
||||
|
||||
def test_availability_zones(self):
|
||||
self.verify_list_no_kwargs(self.proxy.availability_zones,
|
||||
availability_zone.AvailabilityZone,
|
||||
|
Loading…
Reference in New Issue
Block a user