Skip to content

Commit 38d568c

Browse files
authored
Merge pull request #247 from Cloudify-PS/host_aggregate_add_remove_compute
Compute node add and remove operations for host aggregate
2 parents 3de89f0 + 4d8eee4 commit 38d568c

File tree

3 files changed

+205
-56
lines changed

3 files changed

+205
-56
lines changed

nova_plugin/host_aggregate.py

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
is_external_resource,
2323
use_external_resource,
2424
delete_resource_and_runtime_properties,
25+
delete_runtime_properties,
2526
create_object_dict,
2627
add_list_to_runtime_properties,
2728
set_openstack_runtime_properties,
@@ -33,9 +34,7 @@
3334
RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS
3435

3536

36-
def _add_hosts(ctx, nova_client, host_aggregate, kwargs):
37-
hosts = get_property(ctx, HOSTS_PROPERTY, kwargs, [])
38-
37+
def _add_hosts(ctx, nova_client, host_aggregate, hosts):
3938
for host in hosts:
4039
ctx.logger.debug(
4140
'Adding host {0} to aggregate {1}'
@@ -44,6 +43,11 @@ def _add_hosts(ctx, nova_client, host_aggregate, kwargs):
4443

4544
nova_client.aggregates.add_host(host_aggregate, host)
4645

46+
if HOSTS_PROPERTY in ctx.instance.runtime_properties:
47+
hosts = list(
48+
set(hosts + ctx.instance.runtime_properties[HOSTS_PROPERTY])
49+
)
50+
4751
ctx.instance.runtime_properties[HOSTS_PROPERTY] = hosts
4852

4953

@@ -52,25 +56,31 @@ def _set_metadata(ctx, nova_client, host_aggregate, kwargs):
5256

5357
if metadata:
5458
ctx.logger.debug(
55-
'Adding metadata {0} to aggregate {1}'
59+
'Setting metadata {0} for aggregate {1}'
5660
.format(metadata, host_aggregate)
5761
)
5862

5963
nova_client.aggregates.set_metadata(host_aggregate, metadata)
6064

6165

62-
def _remove_hosts(ctx, nova_client, host_aggregate_id, kwargs):
63-
hosts = ctx.instance.runtime_properties.get(HOSTS_PROPERTY, [])
64-
66+
def _remove_hosts(ctx, nova_client, host_aggregate_id, hosts):
6567
for host in hosts:
6668
ctx.logger.debug(
6769
'Removing host {0} from aggregate {1}'
6870
.format(host, host_aggregate_id)
6971
)
70-
7172
nova_client.aggregates.remove_host(host_aggregate_id, host)
7273

73-
ctx.instance.runtime_properties.pop(HOSTS_PROPERTY, None)
74+
current_hosts = [
75+
host
76+
for host in ctx.instance.runtime_properties.get(HOSTS_PROPERTY, [])
77+
if host not in hosts
78+
]
79+
80+
if current_hosts:
81+
ctx.instance.runtime_properties[HOSTS_PROPERTY] = current_hosts
82+
else:
83+
delete_runtime_properties(ctx, HOSTS_PROPERTY)
7484

7585

7686
@operation
@@ -86,8 +96,9 @@ def create(nova_client, args, **kwargs):
8696
)
8797

8898
host_aggregate = nova_client.aggregates.create(**host_aggregate_dict)
89-
_add_hosts(ctx, nova_client, host_aggregate, kwargs)
90-
_set_metadata(ctx, nova_client, host_aggregate, kwargs)
99+
hosts = get_property(ctx, HOSTS_PROPERTY, args, [])
100+
_add_hosts(ctx, nova_client, host_aggregate, hosts)
101+
_set_metadata(ctx, nova_client, host_aggregate, args)
91102

92103
set_openstack_runtime_properties(
93104
ctx,
@@ -100,7 +111,16 @@ def create(nova_client, args, **kwargs):
100111
@with_nova_client
101112
def delete(nova_client, **kwargs):
102113
if not is_external_resource(ctx):
103-
_remove_hosts(ctx, nova_client, get_openstack_id(ctx), kwargs)
114+
host_aggregate = nova_client.aggregates.get(get_openstack_id(ctx))
115+
_remove_hosts(
116+
ctx,
117+
nova_client,
118+
get_openstack_id(ctx),
119+
host_aggregate.hosts
120+
)
121+
122+
if HOSTS_PROPERTY in ctx.instance.runtime_properties:
123+
ctx.instance.runtime_properties.pop(HOSTS_PROPERTY, None)
104124

105125
delete_resource_and_runtime_properties(
106126
ctx,
@@ -112,27 +132,22 @@ def delete(nova_client, **kwargs):
112132
@operation
113133
@with_nova_client
114134
def update(nova_client, args, **kwargs):
115-
host_aggregate_dict = create_object_dict(
116-
ctx,
117-
HOST_AGGREGATE_OPENSTACK_TYPE,
118-
args
119-
)
135+
if HOST_AGGREGATE_OPENSTACK_TYPE in args:
136+
host_aggregate = nova_client.aggregates.update(
137+
get_openstack_id(ctx),
138+
args.get(HOST_AGGREGATE_OPENSTACK_TYPE)
139+
)
120140

121-
_remove_hosts(ctx, nova_client, get_openstack_id(ctx), kwargs)
122-
host_aggregate = nova_client.aggregates.update(
123-
get_openstack_id(ctx),
124-
host_aggregate_dict
125-
)
126-
_add_hosts(ctx, nova_client, host_aggregate, kwargs)
127-
_set_metadata(ctx, nova_client, host_aggregate, kwargs)
141+
set_openstack_runtime_properties(
142+
ctx,
143+
host_aggregate,
144+
HOST_AGGREGATE_OPENSTACK_TYPE
145+
)
128146

129-
set_openstack_runtime_properties(
130-
ctx,
131-
host_aggregate,
132-
HOST_AGGREGATE_OPENSTACK_TYPE
133-
)
147+
_set_metadata(ctx, nova_client, get_openstack_id(ctx), args)
134148

135149

150+
@operation
136151
@with_nova_client
137152
def list_host_aggregates(nova_client, **kwargs):
138153
host_aggregates_list = nova_client.aggregates.list()
@@ -142,3 +157,15 @@ def list_host_aggregates(nova_client, **kwargs):
142157
HOST_AGGREGATE_OPENSTACK_TYPE,
143158
host_aggregates_list
144159
)
160+
161+
162+
@operation
163+
@with_nova_client
164+
def add_hosts(nova_client, hosts, **kwargs):
165+
_add_hosts(ctx, nova_client, get_openstack_id(ctx), hosts)
166+
167+
168+
@operation
169+
@with_nova_client
170+
def remove_hosts(nova_client, hosts, **kwargs):
171+
_remove_hosts(ctx, nova_client, get_openstack_id(ctx), hosts)

nova_plugin/tests/test_host_aggregate.py

Lines changed: 129 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ class TestHostAggregate(unittest.TestCase):
2929
test_deployment_id = 'test-deployment-id'
3030

3131
class MockHostAggregateOS:
32-
def __init__(self, id, name):
32+
def __init__(self, id, name, hosts=None):
3333
self._id = id
3434
self._name = name
35+
self._hosts = hosts
3536

3637
@property
3738
def id(self):
@@ -41,6 +42,10 @@ def id(self):
4142
def name(self):
4243
return self._name
4344

45+
@property
46+
def hosts(self):
47+
return self._hosts or []
48+
4449
def to_dict(self):
4550
return {'name': self.name, 'id': self.id}
4651

@@ -50,6 +55,7 @@ def mock_nova_client(self,
5055
nova_client = mock.MagicMock()
5156

5257
nova_client.aggregates.create.return_value = mock_host_aggregate
58+
nova_client.aggregates.get.return_value = mock_host_aggregate
5359
nova_client.aggregates.list.return_value = [mock_host_aggregate]
5460
nova_client.aggregates.find.return_value = mock.MagicMock(
5561
id=self.test_name
@@ -89,14 +95,118 @@ def mock_ctx(self,
8995

9096
return ctx
9197

98+
@mock.patch(
99+
'openstack_plugin_common._handle_kw',
100+
autospec=True,
101+
return_value=None
102+
)
92103
def test_add_hosts(self, *_):
93-
pass
104+
# given
105+
test_vars_host1 = 'cf4301'
106+
test_vars_host2 = 'openstack-kilo-t2.novalocal'
107+
test_vars_host3 = 'openstack-kilo-t2.novalocal-2'
108+
test_vars_hosts_initial = [test_vars_host1]
109+
test_vars_hosts_to_add = [test_vars_host2, test_vars_host3]
110+
test_vars_hosts_expected = [
111+
test_vars_host1, test_vars_host2, test_vars_host3
112+
]
113+
114+
test_vars = {
115+
'aggregate': {
116+
'name': self.test_name,
117+
'availability_zone': 'internal'
118+
},
119+
'hosts': test_vars_hosts_initial,
120+
'metadata': {},
121+
'resource_id': ''
122+
}
123+
124+
ctx = self.mock_ctx(
125+
test_vars,
126+
self.test_id,
127+
self.test_deployment_id,
128+
{
129+
OPENSTACK_ID_PROPERTY: self.test_id,
130+
OPENSTACK_NAME_PROPERTY: self.test_name,
131+
OPENSTACK_TYPE_PROPERTY: HOST_AGGREGATE_OPENSTACK_TYPE,
132+
HOSTS_PROPERTY: test_vars_hosts_initial
133+
}
134+
)
135+
nova_plugin.host_aggregate.ctx = ctx
136+
137+
mocked_host_aggregate = self.MockHostAggregateOS(
138+
self.test_id,
139+
self.test_name
140+
)
141+
nova_client = self.mock_nova_client(mocked_host_aggregate)
142+
143+
# when
144+
nova_plugin.host_aggregate.add_hosts(
145+
nova_client,
146+
test_vars_hosts_to_add
147+
)
94148

95-
def test_set_metadata(self, *_):
96-
pass
149+
# then
150+
self.assertEqual(
151+
set(test_vars_hosts_expected),
152+
set(ctx.instance.runtime_properties[HOSTS_PROPERTY])
153+
)
97154

155+
@mock.patch(
156+
'openstack_plugin_common._handle_kw',
157+
autospec=True,
158+
return_value=None
159+
)
98160
def test_remove_hosts(self, *_):
99-
pass
161+
# given
162+
test_vars_host1 = 'cf4301'
163+
test_vars_host2 = 'openstack-kilo-t2.novalocal'
164+
test_vars_host3 = 'openstack-kilo-t2.novalocal-2'
165+
test_vars_hosts_initial = [
166+
test_vars_host1, test_vars_host2, test_vars_host3
167+
]
168+
test_vars_hosts_to_remove = [test_vars_host2, test_vars_host3]
169+
test_vars_hosts_expected = [test_vars_host1]
170+
171+
test_vars = {
172+
'aggregate': {
173+
'name': self.test_name,
174+
'availability_zone': 'internal'
175+
},
176+
'hosts': test_vars_hosts_initial,
177+
'metadata': {},
178+
'resource_id': ''
179+
}
180+
181+
ctx = self.mock_ctx(
182+
test_vars,
183+
self.test_id,
184+
self.test_deployment_id,
185+
{
186+
OPENSTACK_ID_PROPERTY: self.test_id,
187+
OPENSTACK_NAME_PROPERTY: self.test_name,
188+
OPENSTACK_TYPE_PROPERTY: HOST_AGGREGATE_OPENSTACK_TYPE,
189+
HOSTS_PROPERTY: test_vars_hosts_initial
190+
}
191+
)
192+
nova_plugin.host_aggregate.ctx = ctx
193+
194+
mocked_host_aggregate = self.MockHostAggregateOS(
195+
self.test_id,
196+
self.test_name
197+
)
198+
nova_client = self.mock_nova_client(mocked_host_aggregate)
199+
200+
# when
201+
nova_plugin.host_aggregate.remove_hosts(
202+
nova_client, test_vars_hosts_to_remove
203+
)
204+
205+
# then
206+
self.assertEqual(
207+
set(test_vars_hosts_expected),
208+
set(ctx.instance.runtime_properties[HOSTS_PROPERTY])
209+
)
100210

101211
@mock.patch(
102212
'openstack_plugin_common._handle_kw',
@@ -126,7 +236,8 @@ def test_create_and_delete(self, *_):
126236

127237
mocked_host_aggregate = self.MockHostAggregateOS(
128238
self.test_id,
129-
self.test_name
239+
self.test_name,
240+
test_vars_hosts
130241
)
131242
nova_client = self.mock_nova_client(mocked_host_aggregate)
132243

@@ -187,6 +298,10 @@ def test_create_and_delete(self, *_):
187298
OPENSTACK_TYPE_PROPERTY,
188299
ctx.instance.runtime_properties
189300
)
301+
self.assertNotIn(
302+
HOSTS_PROPERTY,
303+
ctx.instance.runtime_properties
304+
)
190305

191306
@mock.patch(
192307
'openstack_plugin_common._handle_kw',
@@ -260,11 +375,7 @@ def test_create_and_delete_external_resource(self, *_):
260375
)
261376
def test_update(self, *_):
262377
# given
263-
test_vars_host1 = 'cf4301'
264-
test_vars_host2 = 'openstack-kilo-t2.novalocal'
265-
test_vars_host3 = 'new_host'
266-
test_vars_old_hosts = [test_vars_host1, test_vars_host2]
267-
test_vars_new_hosts = [test_vars_host3]
378+
test_vars_hosts = ['cf4301', 'openstack-kilo-t2.novalocal']
268379
test_vars_metadata = {
269380
'test': 'value1'
270381
}
@@ -273,7 +384,7 @@ def test_update(self, *_):
273384
'name': self.test_name,
274385
'availability_zone': 'internal'
275386
},
276-
'hosts': test_vars_old_hosts,
387+
'hosts': test_vars_hosts,
277388
'metadata': test_vars_metadata,
278389
'resource_id': ''
279390
}
@@ -286,7 +397,7 @@ def test_update(self, *_):
286397
OPENSTACK_ID_PROPERTY: self.test_id,
287398
OPENSTACK_NAME_PROPERTY: self.test_name,
288399
OPENSTACK_TYPE_PROPERTY: HOST_AGGREGATE_OPENSTACK_TYPE,
289-
HOSTS_PROPERTY: test_vars_old_hosts
400+
HOSTS_PROPERTY: test_vars_hosts
290401
}
291402
)
292403
nova_plugin.host_aggregate.ctx = ctx
@@ -306,8 +417,7 @@ def test_update(self, *_):
306417
# when
307418
nova_plugin.host_aggregate.update(
308419
nova_client,
309-
{},
310-
hosts=test_vars_new_hosts
420+
{'aggregate': mocked_updated_host_aggregate.to_dict()}
311421
)
312422

313423
# then
@@ -324,23 +434,15 @@ def test_update(self, *_):
324434
ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY]
325435
)
326436
self.assertEqual(
327-
test_vars_new_hosts,
437+
test_vars_hosts,
328438
ctx.instance.runtime_properties[HOSTS_PROPERTY]
329439
)
330-
nova_client.aggregates.remove_host.assert_any_call(
331-
self.test_id,
332-
test_vars_host1
333-
)
334-
nova_client.aggregates.remove_host.assert_any_call(
440+
nova_client.aggregates.update.assert_called_once_with(
335441
self.test_id,
336-
test_vars_host2
337-
)
338-
nova_client.aggregates.add_host.assert_any_call(
339-
mocked_updated_host_aggregate,
340-
test_vars_host3
442+
mocked_updated_host_aggregate.to_dict()
341443
)
342444
nova_client.aggregates.set_metadata.assert_called_once_with(
343-
mocked_updated_host_aggregate,
445+
self.test_id,
344446
test_vars_metadata
345447
)
346448

0 commit comments

Comments
 (0)