Skip to content

Commit b9cc376

Browse files
committed
Server IP resource
The server IP resource can only list. The Resource.list method needed to be overridden because: * The url path contains the server_id. * The output is a dict of networks rather than an array. Also in this change: * ServerIP objects have sufficient information to stand on their own because they contain the server_id and network_label. * An ips(session) convenience method has been added to the Server. * The list example has been updated to pass data to path_args so the list method and format the url. The path_args parameter to list may be convenient for other classes. I didn't add it to the Resource.list method because that isn't required for this change. Change-Id: Iac77aba144d2e5b4ca4cdbf97e534d83519066ef
1 parent fa5b9ff commit b9cc376

File tree

4 files changed

+181
-1
lines changed

4 files changed

+181
-1
lines changed

examples/list.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
def run_list(opts):
2020
sess = session.make_session(opts)
2121
cls = common.find_resource_cls(opts)
22-
for obj in cls.list(sess):
22+
path_args = None
23+
if opts.data:
24+
path_args = common.get_data_option(opts)
25+
for obj in cls.list(sess, path_args=path_args):
2326
print(str(obj))
2427
return
2528

openstack/compute/v2/server.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# under the License.
1212

1313
from openstack.compute import compute_service
14+
from openstack.compute.v2 import server_ip
1415
from openstack import resource
1516
from openstack import utils
1617

@@ -45,6 +46,11 @@ class Server(resource.Resource):
4546
updated = resource.prop('updated')
4647
user_id = resource.prop('user_id')
4748

49+
def ips(self, session):
50+
"""Get server IPs."""
51+
path_args = {'server_id': self.id}
52+
return server_ip.ServerIP.list(session, path_args=path_args)
53+
4854
def action(self, session, body):
4955
"""Preform server actions given the message body."""
5056
url = utils.urljoin(self.base_path, self.id, 'action')

openstack/compute/v2/server_ip.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
13+
import six
14+
15+
from openstack.compute import compute_service
16+
from openstack import resource
17+
18+
19+
class ServerIP(resource.Resource):
20+
resource_key = 'server_ip'
21+
resources_key = 'server_ips'
22+
base_path = '/servers/%(server_id)s/ips'
23+
service = compute_service.ComputeService()
24+
25+
# capabilities
26+
allow_list = True
27+
28+
# Properties
29+
addr = resource.prop('addr')
30+
network_label = resource.prop('network_label')
31+
server_id = resource.prop('server_id')
32+
version = resource.prop('version')
33+
34+
@property
35+
def id(self):
36+
try:
37+
val = self.addr
38+
except AttributeError:
39+
val = None
40+
return val
41+
42+
@classmethod
43+
def list(cls, session, path_args=None, **params):
44+
url = cls.base_path % path_args
45+
resp = session.get(url, service=cls.service, params=params)
46+
ray = []
47+
for network_label, addresses in six.iteritems(resp.body['addresses']):
48+
for address in addresses:
49+
record = {
50+
'server_id': path_args['server_id'],
51+
'network_label': network_label,
52+
'version': address['version'],
53+
'addr': address['addr'],
54+
}
55+
ray.append(cls.existing(**record))
56+
return ray
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
13+
import mock
14+
import testtools
15+
16+
from openstack.compute.v2 import server_ip
17+
18+
IDENTIFIER = 'IDENTIFIER'
19+
EXAMPLE = {
20+
'addr': '1',
21+
'network_label': '2',
22+
'server_id': '3',
23+
'version': '4',
24+
}
25+
BODY = {
26+
"addresses": {
27+
"public": [
28+
{
29+
"version": 4,
30+
"addr": "67.23.10.132"
31+
},
32+
{
33+
"version": 6,
34+
"addr": "::babe:67.23.10.132"
35+
},
36+
{
37+
"version": 4,
38+
"addr": "67.23.10.131"
39+
},
40+
{
41+
"version": 6,
42+
"addr": "::babe:4317:0A83"
43+
}
44+
],
45+
"private": [
46+
{
47+
"version": 4,
48+
"addr": "10.176.42.16"
49+
},
50+
{
51+
"version": 6,
52+
"addr": "::babe:10.176.42.16"
53+
}
54+
]
55+
}
56+
}
57+
58+
59+
class TestServerIP(testtools.TestCase):
60+
61+
def test_basic(self):
62+
sot = server_ip.ServerIP()
63+
self.assertEqual('server_ip', sot.resource_key)
64+
self.assertEqual('server_ips', sot.resources_key)
65+
self.assertEqual('/servers/%(server_id)s/ips', sot.base_path)
66+
self.assertEqual('compute', sot.service.service_type)
67+
self.assertFalse(sot.allow_create)
68+
self.assertFalse(sot.allow_retrieve)
69+
self.assertFalse(sot.allow_update)
70+
self.assertFalse(sot.allow_delete)
71+
self.assertTrue(sot.allow_list)
72+
73+
def test_make_it(self):
74+
sot = server_ip.ServerIP(EXAMPLE)
75+
self.assertEqual(EXAMPLE['addr'], sot.id)
76+
self.assertEqual(EXAMPLE['addr'], sot.addr)
77+
self.assertEqual(EXAMPLE['network_label'], sot.network_label)
78+
self.assertEqual(EXAMPLE['server_id'], sot.server_id)
79+
self.assertEqual(EXAMPLE['version'], sot.version)
80+
81+
def test_list(self):
82+
sess = mock.Mock()
83+
resp = mock.Mock()
84+
resp.body = BODY
85+
sess.get = mock.Mock(return_value=resp)
86+
path_args = {'server_id': IDENTIFIER}
87+
88+
caps = server_ip.ServerIP.list(sess, path_args=path_args)
89+
90+
caps = sorted(caps, key=lambda cap: cap.id)
91+
self.assertEqual(6, len(caps))
92+
self.assertEqual('10.176.42.16', caps[0].addr)
93+
self.assertEqual('private', caps[0].network_label)
94+
self.assertEqual(IDENTIFIER, caps[0].server_id)
95+
self.assertEqual(4, caps[0].version)
96+
self.assertEqual('67.23.10.131', caps[1].addr)
97+
self.assertEqual('public', caps[1].network_label)
98+
self.assertEqual(IDENTIFIER, caps[1].server_id)
99+
self.assertEqual(4, caps[1].version)
100+
self.assertEqual('67.23.10.132', caps[2].addr)
101+
self.assertEqual('public', caps[2].network_label)
102+
self.assertEqual(IDENTIFIER, caps[2].server_id)
103+
self.assertEqual(4, caps[2].version)
104+
self.assertEqual('::babe:10.176.42.16', caps[3].addr)
105+
self.assertEqual('private', caps[3].network_label)
106+
self.assertEqual(IDENTIFIER, caps[3].server_id)
107+
self.assertEqual(6, caps[3].version)
108+
self.assertEqual('::babe:4317:0A83', caps[4].addr)
109+
self.assertEqual('public', caps[4].network_label)
110+
self.assertEqual(IDENTIFIER, caps[4].server_id)
111+
self.assertEqual(6, caps[4].version)
112+
self.assertEqual('::babe:67.23.10.132', caps[5].addr)
113+
self.assertEqual('public', caps[5].network_label)
114+
self.assertEqual(IDENTIFIER, caps[5].server_id)
115+
self.assertEqual(6, caps[5].version)

0 commit comments

Comments
 (0)