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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
from heat.common.i18n import _
|
from heat.common.i18n import _
|
||||||
from heat.engine import attributes
|
from heat.engine import attributes
|
||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
@ -31,9 +33,9 @@ class Node(resource.Resource):
|
|||||||
default_client_name = 'senlin'
|
default_client_name = 'senlin'
|
||||||
|
|
||||||
PROPERTIES = (
|
PROPERTIES = (
|
||||||
NAME, METADATA, PROFILE,
|
NAME, METADATA, PROFILE, CLUSTER
|
||||||
) = (
|
) = (
|
||||||
'name', 'metadata', 'profile',
|
'name', 'metadata', 'profile', 'cluster'
|
||||||
)
|
)
|
||||||
|
|
||||||
_NODE_STATUS = (
|
_NODE_STATUS = (
|
||||||
@ -69,6 +71,15 @@ class Node(resource.Resource):
|
|||||||
constraints.CustomConstraint('senlin.profile')
|
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 = {
|
attributes_schema = {
|
||||||
@ -88,6 +99,7 @@ class Node(resource.Resource):
|
|||||||
self.physical_resource_name()),
|
self.physical_resource_name()),
|
||||||
'metadata': self.properties[self.METADATA],
|
'metadata': self.properties[self.METADATA],
|
||||||
'profile_id': self.properties[self.PROFILE],
|
'profile_id': self.properties[self.PROFILE],
|
||||||
|
'cluster_id': self.properties[self.CLUSTER],
|
||||||
}
|
}
|
||||||
|
|
||||||
node = self.client().create_node(**params)
|
node = self.client().create_node(**params)
|
||||||
@ -120,21 +132,73 @@ class Node(resource.Resource):
|
|||||||
return node.to_dict()
|
return node.to_dict()
|
||||||
|
|
||||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||||
action_id = None
|
actions = []
|
||||||
if prop_diff:
|
if prop_diff:
|
||||||
|
old_cluster = None
|
||||||
|
new_cluster = None
|
||||||
if self.PROFILE in prop_diff:
|
if self.PROFILE in prop_diff:
|
||||||
prop_diff['profile_id'] = prop_diff.pop(self.PROFILE)
|
prop_diff['profile_id'] = prop_diff.pop(self.PROFILE)
|
||||||
node_obj = self.client().get_node(self.resource_id)
|
if self.CLUSTER in prop_diff:
|
||||||
node = self.client().update_node(
|
old_cluster = self.properties[self.CLUSTER]
|
||||||
node_obj, **prop_diff)
|
new_cluster = prop_diff.pop(self.CLUSTER)
|
||||||
action_id = node.location.split('/')[-1]
|
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):
|
def check_update_complete(self, actions):
|
||||||
if action_id is None:
|
update_complete = True
|
||||||
return True
|
for action in actions:
|
||||||
return self.client_plugin().check_action_status(action_id)
|
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):
|
def _resolve_attribute(self, name):
|
||||||
if self.resource_id is None:
|
if self.resource_id is None:
|
||||||
|
@ -37,6 +37,7 @@ resources:
|
|||||||
properties:
|
properties:
|
||||||
name: SenlinNode
|
name: SenlinNode
|
||||||
profile: fake_profile
|
profile: fake_profile
|
||||||
|
cluster: fake_cluster
|
||||||
metadata:
|
metadata:
|
||||||
foo: bar
|
foo: bar
|
||||||
"""
|
"""
|
||||||
@ -99,6 +100,7 @@ class SenlinNodeTest(common.HeatTestCase):
|
|||||||
'name': 'SenlinNode',
|
'name': 'SenlinNode',
|
||||||
'profile_id': 'fake_profile',
|
'profile_id': 'fake_profile',
|
||||||
'metadata': {'foo': 'bar'},
|
'metadata': {'foo': 'bar'},
|
||||||
|
'cluster_id': 'fake_cluster',
|
||||||
}
|
}
|
||||||
self.senlin_mock.create_node.assert_called_once_with(
|
self.senlin_mock.create_node.assert_called_once_with(
|
||||||
**expect_kwargs)
|
**expect_kwargs)
|
||||||
@ -150,9 +152,29 @@ class SenlinNodeTest(common.HeatTestCase):
|
|||||||
'name': 'new_name'
|
'name': 'new_name'
|
||||||
}
|
}
|
||||||
self.senlin_mock.update_node.assert_called_once_with(
|
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)
|
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):
|
def test_node_update_failed(self):
|
||||||
node = self._create_node()
|
node = self._create_node()
|
||||||
new_t = copy.deepcopy(self.t)
|
new_t = copy.deepcopy(self.t)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user