def test_group_list(self): dgm = DeploymentGroupManager(yaml.safe_load(GROUPS_YAML), node_lookup) assert len(dgm.group_list()) == 7 group_names = [] for group in dgm.group_list(): group_names.append(group.name) assert group_names == dgm._group_order
def test_fail_unsuccessful_nodes(self): dgm = DeploymentGroupManager(yaml.safe_load(GROUPS_YAML), node_lookup) group = dgm._all_groups.get('control-nodes') dgm.fail_unsuccessful_nodes(group, []) assert not dgm.evaluate_group_succ_criteria('control-nodes', Stage.DEPLOYED) assert group.stage == Stage.FAILED
def test_deduplication(self): """all-compute-nodes is a duplicate of things it's dependent on, it should have no actionable nodes""" dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) acn = dgm._all_groups['all-compute-nodes'] assert len(acn.actionable_nodes) == 0 assert len(acn.full_nodes) == 6
def test_cycle_error(self): with pytest.raises(DeploymentGroupCycleError) as ce: DeploymentGroupManager(yaml.safe_load(_CYCLE_GROUPS_YAML), node_lookup) assert 'The following are involved' in str(ce) for g in ['group-a', 'group-c', 'group-d']: assert g in str(ce) assert 'group-b' not in str(ce)
def _get_deployment_group_manager(groups_dict_list, node_lookup): """Return a DeploymentGroupManager suitable for managing this deployment :param groups_dict_list: the list of group dictionaries to use :param node_lookup: a NodeLookup object that will be used by this DeploymentGroupManager """ return DeploymentGroupManager(groups_dict_list, node_lookup)
def test_get_group_failures_for_stage(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) dgm._all_nodes = {'node%d' % x: Stage.DEPLOYED for x in range(1, 13)} for group_name in dgm._all_groups: assert not dgm.get_group_failures_for_stage( group_name, Stage.DEPLOYED) assert not dgm.get_group_failures_for_stage( group_name, Stage.PREPARED) dgm._all_nodes = {'node%d' % x: Stage.PREPARED for x in range(1, 13)} for group_name in dgm._all_groups: assert not dgm.get_group_failures_for_stage( group_name, Stage.PREPARED) for group_name in [ 'compute-nodes-1', 'monitoring-nodes', 'compute-nodes-2', 'control-nodes', 'ntp-node' ]: # assert that these have a failure assert dgm.get_group_failures_for_stage(group_name, Stage.DEPLOYED) dgm._all_nodes = { 'node1': Stage.FAILED, 'node2': Stage.PREPARED, 'node3': Stage.FAILED, 'node4': Stage.PREPARED, 'node5': Stage.FAILED, 'node6': Stage.PREPARED, 'node7': Stage.FAILED, 'node8': Stage.PREPARED, 'node9': Stage.FAILED, 'node10': Stage.PREPARED, 'node11': Stage.FAILED, 'node12': Stage.PREPARED, } for group_name in dgm._all_groups: scf = dgm.get_group_failures_for_stage(group_name, Stage.PREPARED) if group_name == 'monitoring-nodes': assert scf[0] == { 'criteria': 'minimum_successful_nodes', 'needed': 3, 'actual': 2 } if group_name == 'control-nodes': assert scf[0] == { 'criteria': 'percent_successful_nodes', 'needed': 100, 'actual': 50.0 } if group_name == 'ntp-node': assert scf[0] == { 'criteria': 'minimum_successful_nodes', 'needed': 1, 'actual': 0 }
def test_dgm(self): all_yaml_dict = yaml.safe_load(INPUT_YAML) group_dict_list = all_yaml_dict['data']['groups'] dgm = DeploymentGroupManager(group_dict_list, node_lookup) assert dgm is not None # topological sort doesn't guarantee a specific order. assert dgm.get_next_group(Stage.PREPARED).name == 'masters' assert len(dgm._all_groups) == 4 assert len(dgm._all_nodes) == 6
def test_process_deployment_groups(self): """Test the core processing loop of the drydock_nodes module""" dgm = DeploymentGroupManager(yaml.safe_load(tdgm.GROUPS_YAML), node_lookup) _process_deployment_groups( dgm, _gen_pe_func('all-success', stand_alone=True), _gen_pe_func('all-success', stand_alone=True)) assert not dgm.critical_groups_failed() for group in dgm.group_list(): assert dgm.evaluate_group_succ_criteria(group.name, Stage.DEPLOYED)
def test_basic_class(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) assert dgm is not None # topological sort doesn't guarantee a specific order. assert dgm.get_next_group(Stage.PREPARED).name in ['ntp-node', 'monitoring-nodes'] assert len(dgm._all_groups) == 7 assert len(dgm._all_nodes) == 12 for name, group in dgm._all_groups.items(): assert name == group.name
def test_process_deployment_groups_prep_fail(self): """Test the core processing loop of the drydock_nodes module""" dgm = DeploymentGroupManager(yaml.safe_load(tdgm.GROUPS_YAML), node_lookup) _process_deployment_groups( dgm, _gen_pe_func('all-fail', stand_alone=True), _gen_pe_func('all-success', stand_alone=True)) assert dgm.critical_groups_failed() for group in dgm.group_list(): assert group.stage == Stage.FAILED dgm.report_group_summary() dgm.report_node_summary()
def do_validate(self): groups = self.doc_dict['groups'] try: DeploymentGroupManager(groups, _get_node_lookup(self.revision)) except DeploymentGroupCycleError as dgce: self.val_msg_list.append( self.val_msg( name=dgce.__class__.__name__, error=True, level="Error", message=( "The deployment groups specified in the Deployment " "Strategy have groups that form a " "cycle."), diagnostic=str(dgce))) self.error_status = True except InvalidDeploymentGroupError as idge: self.val_msg_list.append( self.val_msg( name=idge.__class__.__name__, error=True, level="Error", message=("A deployment group specified in the Deployment " "Strategy is invalid"), diagnostic=str(idge))) self.error_status = True except InvalidDeploymentGroupNodeLookupError as idgnle: self.val_msg_list.append( self.val_msg( name=idgnle.__class__.__name__, error=True, level="Error", message=("Shipyard does not have a valid node lookup to " "validate the deployment strategy"), diagnostic=str(idgnle))) self.error_status = True except Exception as ex: # all other exceptions are an error self.val_msg_list.append( self.val_msg( name="DocumentValidationProcessingError", error=True, level="Error", message=("Shipyard has encountered an unexpected error " "while processing document validations"), diagnostic=str(ex))) self.error_status = True
def test_evaluate_group_succ_criteria(self): dgm = DeploymentGroupManager(yaml.safe_load(GROUPS_YAML), node_lookup) group = dgm._all_groups.get('control-nodes') nodes = ["node{}".format(i) for i in range(1, 12)] for node in nodes: dgm.mark_node_prepared(node) dgm.fail_unsuccessful_nodes(group, nodes) assert dgm.evaluate_group_succ_criteria('control-nodes', Stage.PREPARED) assert group.stage == Stage.PREPARED for node in nodes: dgm.mark_node_deployed(node) assert dgm.evaluate_group_succ_criteria('control-nodes', Stage.DEPLOYED) assert group.stage == Stage.DEPLOYED
def test_reports(self, caplog): dgm = DeploymentGroupManager(yaml.safe_load(GROUPS_YAML), node_lookup) dgm.mark_node_deployed('node1') dgm.mark_node_prepared('node2') dgm.mark_node_failed('node3') dgm.mark_group_prepared('control-nodes') dgm.mark_group_deployed('control-nodes') dgm.mark_group_prepared('compute-nodes-1') dgm.mark_group_failed('compute-nodes-2') dgm.report_group_summary() assert "===== Group Summary =====" in caplog.text assert ("Group ntp-node [Critical] ended with stage: " "Stage.NOT_STARTED") in caplog.text caplog.clear() dgm.report_node_summary() assert "Nodes Stage.PREPARED: node2" in caplog.text assert "Nodes Stage.FAILED: node3" in caplog.text assert "===== End Node Summary =====" in caplog.text assert "It was the best of times" not in caplog.text
def test_ordering_stages_flow_failure(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) group = dgm.get_next_group(Stage.PREPARED) if group.name == 'monitoring-nodes': dgm.mark_group_prepared(group.name) dgm.mark_group_deployed(group.name) group = dgm.get_next_group(Stage.PREPARED) if group.name == 'ntp-node': dgm.mark_group_failed(group.name) group = dgm.get_next_group(Stage.PREPARED) if group and group.name == 'monitoring-nodes': dgm.mark_group_prepared(group.name) dgm.mark_group_deployed(group.name) group = dgm.get_next_group(Stage.PREPARED) # all remaining groups should be failed, so no more to prepare for name, grp in dgm._all_groups.items(): if (name == 'monitoring-nodes'): assert grp.stage == Stage.DEPLOYED else: assert grp.stage == Stage.FAILED assert group is None
def test_no_next_group(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) assert dgm.get_next_group(Stage.DEPLOYED) is None
def test_critical_groups_failed(self): dgm = DeploymentGroupManager(yaml.safe_load(GROUPS_YAML), node_lookup) assert not dgm.critical_groups_failed() dgm.mark_group_failed('control-nodes') assert dgm.critical_groups_failed()
def test_get_nodes_all(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) assert set(dgm.get_nodes()) == set( ['node1', 'node2', 'node3', 'node4', 'node5', 'node6', 'node7', 'node8', 'node9', 'node10', 'node11', 'node12'] )
def test_mark_node_failed_unknown(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) with pytest.raises(UnknownNodeError): dgm.mark_node_failed('not_node')
def test_mark_node_failed(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) dgm.mark_node_failed('node1') assert dgm.get_nodes(Stage.FAILED) == ['node1']
def test_get_group_failures_for_stage_bad_input(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) with pytest.raises(DeploymentGroupStageError): dgm.get_group_failures_for_stage('group1', Stage.FAILED)
def test_bad_group_name_lookup(self): dgm = DeploymentGroupManager(yaml.safe_load(_GROUPS_YAML), node_lookup) with pytest.raises(UnknownDeploymentGroupError) as udge: dgm.mark_group_prepared('Limburger Cheese') assert "Group name Limburger Cheese does not refer" in str(udge)
def test_mark_node_prepared(self): dgm = DeploymentGroupManager(yaml.safe_load(GROUPS_YAML), node_lookup) dgm.mark_node_prepared('node1') assert dgm.get_nodes(Stage.PREPARED) == ['node1']
def _get_deployment_group_manager(groups, revision_id): """Retrieves the deployment group manager""" return DeploymentGroupManager(groups, _get_node_lookup(revision_id))