Add cluster property to senlin node resource
When create a senlin node, using 'cluster' property to attach to a specific cluster. Change-Id: I3f6411c51b519bbabcdbf683f79de766af893751
This commit is contained in:
parent
af46280c8a
commit
843456301e
@ -11,6 +11,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from heat.common.i18n import _
|
||||
from heat.engine import attributes
|
||||
from heat.engine import constraints
|
||||
@ -31,9 +33,9 @@ class Node(resource.Resource):
|
||||
default_client_name = 'senlin'
|
||||
|
||||
PROPERTIES = (
|
||||
NAME, METADATA, PROFILE,
|
||||
NAME, METADATA, PROFILE, CLUSTER
|
||||
) = (
|
||||
'name', 'metadata', 'profile',
|
||||
'name', 'metadata', 'profile', 'cluster'
|
||||
)
|
||||
|
||||
_NODE_STATUS = (
|
||||
@ -69,6 +71,15 @@ class Node(resource.Resource):
|
||||
constraints.CustomConstraint('senlin.profile')
|
||||
]
|
||||
),
|
||||
CLUSTER: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('The name of senlin cluster to attach to.'),
|
||||
update_allowed=True,
|
||||
constraints=[
|
||||
constraints.CustomConstraint('senlin.cluster')
|
||||
],
|
||||
support_status=support.SupportStatus(version='8.0.0'),
|
||||
),
|
||||
}
|
||||
|
||||
attributes_schema = {
|
||||
@ -88,6 +99,7 @@ class Node(resource.Resource):
|
||||
self.physical_resource_name()),
|
||||
'metadata': self.properties[self.METADATA],
|
||||
'profile_id': self.properties[self.PROFILE],
|
||||
'cluster_id': self.properties[self.CLUSTER],
|
||||
}
|
||||
|
||||
node = self.client().create_node(**params)
|
||||
@ -120,21 +132,73 @@ class Node(resource.Resource):
|
||||
return node.to_dict()
|
||||
|
||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||
action_id = None
|
||||
actions = []
|
||||
if prop_diff:
|
||||
old_cluster = None
|
||||
new_cluster = None
|
||||
if self.PROFILE in prop_diff:
|
||||
prop_diff['profile_id'] = prop_diff.pop(self.PROFILE)
|
||||
node_obj = self.client().get_node(self.resource_id)
|
||||
node = self.client().update_node(
|
||||
node_obj, **prop_diff)
|
||||
action_id = node.location.split('/')[-1]
|
||||
if self.CLUSTER in prop_diff:
|
||||
old_cluster = self.properties[self.CLUSTER]
|
||||
new_cluster = prop_diff.pop(self.CLUSTER)
|
||||
if old_cluster:
|
||||
params = {
|
||||
'cluster': old_cluster,
|
||||
'nodes': [self.resource_id],
|
||||
}
|
||||
action = {
|
||||
'func': 'cluster_del_nodes',
|
||||
'action_id': None,
|
||||
'params': params,
|
||||
'done': False,
|
||||
}
|
||||
actions.append(action)
|
||||
if prop_diff:
|
||||
node = self.client().get_node(self.resource_id)
|
||||
params = copy.deepcopy(prop_diff)
|
||||
params['node'] = node
|
||||
action = {
|
||||
'func': 'update_node',
|
||||
'action_id': None,
|
||||
'params': params,
|
||||
'done': False,
|
||||
}
|
||||
actions.append(action)
|
||||
if new_cluster:
|
||||
params = {
|
||||
'cluster': new_cluster,
|
||||
'nodes': [self.resource_id],
|
||||
}
|
||||
action = {
|
||||
'func': 'cluster_add_nodes',
|
||||
'action_id': None,
|
||||
'params': params,
|
||||
'done': False,
|
||||
}
|
||||
actions.append(action)
|
||||
|
||||
return action_id
|
||||
return actions
|
||||
|
||||
def check_update_complete(self, action_id):
|
||||
if action_id is None:
|
||||
return True
|
||||
return self.client_plugin().check_action_status(action_id)
|
||||
def check_update_complete(self, actions):
|
||||
update_complete = True
|
||||
for action in actions:
|
||||
if action['done']:
|
||||
continue
|
||||
update_complete = False
|
||||
if action['action_id'] is None:
|
||||
func = getattr(self.client(), action['func'])
|
||||
ret = func(**action['params'])
|
||||
if isinstance(ret, dict):
|
||||
action['action_id'] = ret['action']
|
||||
else:
|
||||
action['action_id'] = ret.location.split('/')[-1]
|
||||
else:
|
||||
ret = self.client_plugin().check_action_status(
|
||||
action['action_id'])
|
||||
action['done'] = ret
|
||||
# Execute these actions one by one.
|
||||
break
|
||||
return update_complete
|
||||
|
||||
def _resolve_attribute(self, name):
|
||||
if self.resource_id is None:
|
||||
|
@ -37,6 +37,7 @@ resources:
|
||||
properties:
|
||||
name: SenlinNode
|
||||
profile: fake_profile
|
||||
cluster: fake_cluster
|
||||
metadata:
|
||||
foo: bar
|
||||
"""
|
||||
@ -99,6 +100,7 @@ class SenlinNodeTest(common.HeatTestCase):
|
||||
'name': 'SenlinNode',
|
||||
'profile_id': 'fake_profile',
|
||||
'metadata': {'foo': 'bar'},
|
||||
'cluster_id': 'fake_cluster',
|
||||
}
|
||||
self.senlin_mock.create_node.assert_called_once_with(
|
||||
**expect_kwargs)
|
||||
@ -150,9 +152,29 @@ class SenlinNodeTest(common.HeatTestCase):
|
||||
'name': 'new_name'
|
||||
}
|
||||
self.senlin_mock.update_node.assert_called_once_with(
|
||||
self.fake_node, **node_update_kwargs)
|
||||
node=self.fake_node, **node_update_kwargs)
|
||||
self.assertEqual(2, self.senlin_mock.get_action.call_count)
|
||||
|
||||
def test_node_update_cluster(self):
|
||||
node = self._create_node()
|
||||
new_t = copy.deepcopy(self.t)
|
||||
props = new_t['resources']['senlin-node']['properties']
|
||||
props['cluster'] = 'new_cluster'
|
||||
rsrc_defns = template.Template(new_t).resource_definitions(self.stack)
|
||||
new_node = rsrc_defns['senlin-node']
|
||||
self.senlin_mock.cluster_del_nodes.return_value = {
|
||||
'action': 'remove_node_from_cluster'
|
||||
}
|
||||
self.senlin_mock.cluster_add_nodes.return_value = {
|
||||
'action': 'add_node_to_cluster'
|
||||
}
|
||||
scheduler.TaskRunner(node.update, new_node)()
|
||||
self.assertEqual((node.UPDATE, node.COMPLETE), node.state)
|
||||
self.senlin_mock.cluster_del_nodes.assert_called_once_with(
|
||||
cluster='fake_cluster', nodes=[node.resource_id])
|
||||
self.senlin_mock.cluster_add_nodes.assert_called_once_with(
|
||||
cluster='new_cluster', nodes=[node.resource_id])
|
||||
|
||||
def test_node_update_failed(self):
|
||||
node = self._create_node()
|
||||
new_t = copy.deepcopy(self.t)
|
||||
|
Loading…
Reference in New Issue
Block a user