Add 'fuel2 env remove nodes' command
Release new 'env remove nodes' command in fuel2
to support remove nodes procedure from specific
environment (cluster):
fuel2 env remove nodes [-h] -e ENV
(-n NODES [NODES ...] | --nodes-all)
DocImpact
Closes-Bug: 1603440
Change-Id: Ibc14966996ae046307299348f62f758980d31ace
(cherry picked from commit a245303ef5)
This commit is contained in:
@@ -193,6 +193,43 @@ class EnvAddNodes(EnvMixIn, base.BaseCommand):
|
||||
r=parsed_args.roles))
|
||||
|
||||
|
||||
class EnvRemoveNodes(EnvMixIn, base.BaseCommand):
|
||||
"""Removes nodes from an environment."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
|
||||
parser = super(EnvRemoveNodes, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('-e',
|
||||
'--env',
|
||||
type=int,
|
||||
required=True,
|
||||
help='Id of the environment to remove nodes from')
|
||||
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('-n',
|
||||
'--nodes',
|
||||
type=int,
|
||||
nargs='+',
|
||||
help='Ids of the nodes to remove.')
|
||||
|
||||
group.add_argument('--nodes-all',
|
||||
action='store_true',
|
||||
help='Remove all nodes from environment')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
nodes = None if parsed_args.nodes_all else parsed_args.nodes
|
||||
self.client.remove_nodes(environment_id=parsed_args.env,
|
||||
nodes=nodes)
|
||||
|
||||
msg = 'Nodes were removed from the environment with id={e}\n'.format(
|
||||
e=parsed_args.env)
|
||||
|
||||
self.app.stdout.write(msg)
|
||||
|
||||
|
||||
class EnvDeploy(EnvMixIn, base.BaseCommand):
|
||||
"""Deploys changes on the specified environment."""
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ class Environment(BaseObject):
|
||||
self.connection.get_request(
|
||||
"nodes/?cluster_id={0}".format(self.id)
|
||||
)
|
||||
), key=attrgetter)
|
||||
), key=attrgetter('id'))
|
||||
|
||||
def unassign_all(self):
|
||||
nodes = self.get_all_nodes()
|
||||
|
||||
@@ -158,6 +158,22 @@ class TestEnvCommand(test_engine.BaseCLITest):
|
||||
roles=['compute',
|
||||
'cinder'])
|
||||
|
||||
def test_env_remove_nodes_by_id(self):
|
||||
args = 'env remove nodes -e 42 -n 24 25'
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('environment', mock.ANY)
|
||||
self.m_client.remove_nodes.assert_called_once_with(environment_id=42,
|
||||
nodes=[24, 25])
|
||||
|
||||
def test_env_remove_nodes_all(self):
|
||||
args = 'env remove nodes -e 42 --nodes-all'
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('environment', mock.ANY)
|
||||
self.m_client.remove_nodes.assert_called_once_with(environment_id=42,
|
||||
nodes=None)
|
||||
|
||||
def test_env_update(self):
|
||||
self.m_client._updatable_attributes = \
|
||||
environment.EnvironmentClient._updatable_attributes
|
||||
|
||||
@@ -212,3 +212,51 @@ class TestEnvFacade(test_api.BaseLibTest):
|
||||
self.client.spawn_vms(env_id)
|
||||
|
||||
self.assertTrue(matcher.called)
|
||||
|
||||
def test_env_remove_nodes_by_id(self):
|
||||
nodes = [25, 26]
|
||||
env_id = 42
|
||||
|
||||
expected_body = []
|
||||
for n in nodes:
|
||||
expected_body.append({'id': n})
|
||||
|
||||
expected_uri = self.get_object_uri(self.res_uri,
|
||||
env_id, '/unassignment/')
|
||||
|
||||
matcher = self.m_request.post(expected_uri, json={})
|
||||
|
||||
self.client.remove_nodes(env_id, nodes=nodes)
|
||||
|
||||
self.assertTrue(matcher.called)
|
||||
|
||||
for unassignment in matcher.last_request.json():
|
||||
# Check whether all unassignments are expected
|
||||
self.assertIn(unassignment, expected_body)
|
||||
|
||||
def test_env_remove_nodes_all(self):
|
||||
nodes = [24, 25, 26]
|
||||
env_id = 42
|
||||
|
||||
expected_body = []
|
||||
for n in nodes:
|
||||
expected_body.append({'id': n})
|
||||
|
||||
fake_nodes = [utils.get_fake_node(node_name='node_' + str(n),
|
||||
node_id=n,
|
||||
cluster=env_id) for n in nodes]
|
||||
|
||||
expected_uri = self.get_object_uri(self.res_uri,
|
||||
env_id, '/unassignment/')
|
||||
matcher_get = self.m_request.get(
|
||||
'/api/v1/nodes/?cluster_id={}'.format(env_id),
|
||||
json=fake_nodes
|
||||
)
|
||||
matcher_post = self.m_request.post(expected_uri, json={})
|
||||
self.client.remove_nodes(env_id)
|
||||
self.assertTrue(matcher_get.called)
|
||||
self.assertTrue(matcher_post.called)
|
||||
|
||||
for unassignment in matcher_post.last_request.json():
|
||||
# Check whether all unassignments are expected
|
||||
self.assertIn(unassignment, expected_body)
|
||||
|
||||
@@ -65,6 +65,21 @@ class EnvironmentClient(base_v1.BaseV1Client):
|
||||
|
||||
env.assign(nodes, roles)
|
||||
|
||||
def remove_nodes(self, environment_id, nodes=None):
|
||||
"""Remove nodes from environment. If nodes are empty list then
|
||||
all nodes will be removed
|
||||
|
||||
:param environment_id: Id of specific environment (cluster)
|
||||
:type environment_id: int
|
||||
:param nodes: List of node ids that should be removed
|
||||
:type nodes: list
|
||||
"""
|
||||
env = self._entity_wrapper(obj_id=environment_id)
|
||||
if nodes is not None:
|
||||
env.unassign(nodes)
|
||||
else:
|
||||
env.unassign_all()
|
||||
|
||||
def deploy_changes(self, environment_id, dry_run=False):
|
||||
env = self._entity_wrapper(obj_id=environment_id)
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ fuelclient =
|
||||
env_deploy=fuelclient.commands.environment:EnvDeploy
|
||||
env_list=fuelclient.commands.environment:EnvList
|
||||
env_redeploy=fuelclient.commands.environment:EnvRedeploy
|
||||
env_remove_nodes=fuelclient.commands.environment:EnvRemoveNodes
|
||||
env_show=fuelclient.commands.environment:EnvShow
|
||||
env_spawn-vms=fuelclient.commands.environment:EnvSpawnVms
|
||||
env_update=fuelclient.commands.environment:EnvUpdate
|
||||
|
||||
Reference in New Issue
Block a user