def test_put_node_role_dimension(session): try: network_name = "n1" bf_set_network(network_name) dim_name = "d1" mapping = RoleDimensionMapping(regex="(regex)") dim = NodeRoleDimension(dim_name, roleDimensionMappings=[mapping]) bf_put_node_role_dimension(dim) assert bf_get_node_role_dimension(dim_name) == dim # put again to check for idempotence bf_put_node_role_dimension(dim) assert bf_get_node_role_dimension(dim_name) == dim finally: bf_delete_network(network_name)
def test_put_node_roles(): try: network_name = "n1" bf_set_network(network_name) mapping = RoleMapping( name="mapping", regex="(regex)", roleDimensionGroups={"dim1": [1]} ) node_roles = NodeRolesData( defaultDimension="dim1", roleDimensionOrder=["dim1"], roleMappings=[mapping] ) bf_put_node_roles(node_roles) assert bf_get_node_roles() == node_roles finally: bf_delete_network(network_name)
def test_get_snapshot_node_roles(network, roles_snapshot): bf_set_network(network) bf_set_snapshot(roles_snapshot) dimension_name = "dim1" mapping = RoleMapping(name="mapping", regex="regex", roleDimensionGroups={dimension_name: [1]}) node_roles = NodeRolesData(roleDimensionOrder=[dimension_name], roleMappings=[mapping]) bf_put_node_roles(node_roles) # there should be 1 role dimension snapshot_node_roles = bf_get_snapshot_node_roles() assert len(snapshot_node_roles.roleDimensionOrder) == 1 assert snapshot_node_roles.roleDimensionOrder[0] == dimension_name
def test_fork_snapshot(network, example_snapshot): """Run fork snapshot command with valid and invalid inputs.""" name = uuid.uuid4().hex bf_set_network(network) try: # Should succeed with existent base snapshot and valid name bf_fork_snapshot(base_name=example_snapshot, name=name) # Fail using existing snapshot name without specifying overwrite with pytest.raises(ValueError): bf_fork_snapshot(base_name=example_snapshot, name=name) finally: bf_delete_snapshot(name)
def init_bf(): bf_session.host = bf_host bf_set_network("nova_candidate") snapshots = bf_list_snapshots() pprint(snapshots) bf_init_snapshot(SNAPSHOT_DIR, name=SNAPSHOT_NAME, overwrite=True) bf_set_snapshot(SNAPSHOT_NAME) load_questions() print(bfq.initIssues().answer()) print( bfq.nodeProperties(properties="Configuration_Format").answer().frame())
def init_batfish(self): bf_session.host = self.host bf_session.coordinatorHost = self.host bf_set_network(self.NETWORK_NAME) # Initialize Batfish Snapshot bf_init_snapshot(self.snapshot_folder, name=self.NETWORK_NAME, overwrite=True) # Generate Dataplane bf_generate_dataplane() # Load Batfish Questions load_questions()
def test_add_node_roles_data(): try: network_name = "n1" bf_set_network(network_name) mappings = [ RoleMapping("mapping1", "(.*)-(.*)", { "type": [1], "index": [2] }, {}) ] roles_data = NodeRolesData(None, ["type", "index"], mappings) bf_put_node_roles(roles_data) assert bf_get_node_roles() == roles_data finally: bf_delete_network(network_name)
def test_delete_node_role_dimension(): try: network_name = 'n1' bf_set_network(network_name) dim_name = 'd1' dim = NodeRoleDimension(dim_name) bf_add_node_role_dimension(dim) # should not crash bf_get_node_role_dimension(dim_name) bf_delete_node_role_dimension(dim_name) # dimension should no longer exist with raises(HTTPError, match='404'): bf_get_node_role_dimension(dim_name) # second delete should fail with raises(HTTPError, match='404'): bf_delete_node_role_dimension(dim_name) finally: bf_delete_network(network_name)
def test_delete_node_role_dimension(session): try: network_name = "n1" bf_set_network(network_name) dim_name = "d1" mapping = RoleDimensionMapping(regex="(regex)") dim = NodeRoleDimension(name=dim_name, roleDimensionMappings=[mapping]) bf_add_node_role_dimension(dim) # should not crash bf_get_node_role_dimension(dim_name) bf_delete_node_role_dimension(dim_name) # dimension should no longer exist with raises(HTTPError, match="404"): bf_get_node_role_dimension(dim_name) # second delete should fail with raises(HTTPError, match="404"): bf_delete_node_role_dimension(dim_name) finally: bf_delete_network(network_name)
def Batfish_parses_config_files(intermediate_scenario_directory, DEBUG, NETWORK_NAME, SNAPSHOT_NAME): print( "NETWORK_NAME", NETWORK_NAME, "SNAPSHOT_NAME", SNAPSHOT_NAME, "intermediate_scenario_directory", intermediate_scenario_directory, ) bf_set_network(NETWORK_NAME) bf_init_snapshot(intermediate_scenario_directory, name=SNAPSHOT_NAME, overwrite=True) load_questions() pd.options.display.max_columns = 6 if DEBUG: print_debugging_info()
def auto_complete_tester(completion_types): try: name = bf_set_network() bf_init_snapshot(join(_this_dir, "snapshot")) for completion_type in completion_types: suggestions = bf_auto_complete(completion_type, ".*") # Not all completion types will have suggestions since this test snapshot only contains one empty config. # If a completion type is unsupported an error is thrown so this will test that no errors are thrown. if len(suggestions) > 0: assert isinstance(suggestions[0], AutoCompleteSuggestion) finally: bf_delete_network(name)
def test_fork_snapshot_deactivate(network, example_snapshot): """Use fork snapshot to deactivate and restore items.""" deactivate_name = uuid.uuid4().hex restore_name = uuid.uuid4().hex node = 'as2border1' interface = Interface(hostname='as1border1', interface='GigabitEthernet1/0') bf_set_network(network) try: # Should succeed with deactivations bf_fork_snapshot(base_name=example_snapshot, name=deactivate_name, deactivate_interfaces=[interface], deactivate_nodes=[node]) # Should succeed with valid restorations from snapshot with deactivation bf_fork_snapshot(base_name=deactivate_name, name=restore_name, restore_interfaces=[interface], restore_nodes=[node]) finally: bf_delete_snapshot(deactivate_name) bf_delete_snapshot(restore_name)
def set_network(self, network): bf_set_network(network)
def test_get_snapshot_inferred_node_roles(network, roles_snapshot): bf_set_network(network) bf_set_snapshot(roles_snapshot) # should not be empty assert len(bf_get_snapshot_inferred_node_roles().roleDimensions) > 0
def network(): name = bf_set_network() yield name # cleanup bf_delete_network(name)
def test_list_snapshots_empty(network): bf_set_network(network) assert not bf_list_snapshots() verbose = bf_list_snapshots(verbose=True) assert verbose == []
def test_get_snapshot_inferred_node_role_dimension(network, roles_snapshot): bf_set_network(network) bf_set_snapshot(roles_snapshot) # should not crash bf_get_snapshot_inferred_node_role_dimension('auto1')
def test_list_networks(): try: name = bf_set_network() assert name in bf_list_networks() finally: bf_delete_network(name)
def generate_code_for_question( question_data: Mapping[str, Any], question_class_map: Mapping[str, QuestionMeta]) -> List[NotebookNode]: """Generate notebook cells for a single question.""" question_type = question_data.get("type", "basic") if question_type == "skip": return [] cells: List[NotebookNode] = [] pybf_name = question_data["pybf_name"] if pybf_name not in question_class_map: raise KeyError(f"Unknown pybf question: {pybf_name}") q_class: QuestionMeta = question_class_map[pybf_name] snapshot_config = question_data.get("snapshot", _example_snapshot_config) # setting the network & snapshot here since we have to execute the query to get retrieve column meta-data bf_set_network(NETWORK_NAME) snapshot_name = snapshot_config["name"] bf_set_snapshot(snapshot_name) cells.append( nbformat.v4.new_code_cell(f"bf_set_network('{NETWORK_NAME}')", metadata=metadata_hide)) cells.append( nbformat.v4.new_code_cell(f"bf_set_snapshot('{snapshot_name}')", metadata=metadata_hide)) description, long_description, params = get_desc_and_params(q_class) # Section header which is the question name cells.append( nbformat.v4.new_markdown_cell(f"##### {question_data.get('name')}")) cells.append(nbformat.v4.new_markdown_cell(f"{description}")) cells.append(nbformat.v4.new_markdown_cell(f"{long_description}")) cells.append(nbformat.v4.new_markdown_cell("###### Inputs")) # generate table describing the input to the query cells.append( nbformat.v4.new_markdown_cell(gen_input_table(params, pybf_name))) cells.append(nbformat.v4.new_markdown_cell("###### Invocation")) parameters = question_data.get("parameters", []) param_str = ", ".join([f"{p['name']}={p['value']}" for p in parameters]) if question_type == "diff": reference_snapshot = question_data["reference_snapshot"]["name"] # TODO: line wrapping? expression = f"bfq.{pybf_name}({param_str}).answer(snapshot='{snapshot_name}',reference_snapshot='{reference_snapshot}')" else: expression = f"bfq.{pybf_name}({param_str}).answer()" # execute the question and get the column metadata. Hack. column_metadata = eval(expression).metadata.column_metadata # Code cell to execute question cells.append( nbformat.v4.new_code_cell("result = {}.frame()".format(expression))) cells.append(nbformat.v4.new_markdown_cell("###### Return Value")) # generate table describing the output of the query cells.append( nbformat.v4.new_markdown_cell( gen_output_table(column_metadata, pybf_name))) generate_result_examination(cells, question_type) return cells
def run_module(): # define the available arguments/parameters that a user can pass to # the module module_args = dict(base_name=dict(type='str', required=False, default=None), host=dict(type='str', required=False, default='localhost'), name=dict(type='str', required=True), network=dict(type='str', required=True), path=dict(type='str', required=True)) # seed the result dict in the object # we primarily care about changed and state # change is if this module effectively modified the target # state will include any data that you want your module to pass back # for consumption, for example, in a subsequent task result = dict( changed=False, name='', network='', result='', ) # the AnsibleModule object will be our abstraction working with Ansible # this includes instantiation, a couple of common attr would be the # args/params passed to the execution, as well as if the module # supports check mode module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) if not pybatfish_found: module.fail_json(msg='Python module Pybatfish is required') if module.check_mode: return result base_name = module.params['base_name'] name = module.params['name'] path = module.params['path'] try: bf_session.coordinatorHost = module.params['host'] network = bf_set_network(module.params['network']) except Exception as e: module.fail_json(msg='Failed to set network: {}'.format(e), **result) result['network'] = network try: if base_name is not None: name = bf_fork_snapshot(add_files=path, base_name=base_name, name=name, overwrite=True) result[ 'result'] = "Forked snapshot '{}' from '{}' adding files at '{}'".format( name, base_name, path) else: name = bf_init_snapshot(path, name, overwrite=True) result[ 'result'] = "Created snapshot '{}' from files at '{}'".format( name, path) except Exception as e: module.fail_json(msg='Failed to init snapshot: {}'.format(e), **result) result['name'] = name # manipulate or modify the state as needed (this is going to be the # part where your module will do what it needs to do) result['changed'] = True module.exit_json(**result)
def run_module(): # define the available arguments/parameters that a user can pass to # the module module_args = dict(action=dict(type='str', required=False, default='permit'), destination_ips=dict(type='str', required=False, default=None), destination_ports=dict(type='str', required=False, default=None), filters=dict(type='str', required=False, default=".*"), host=dict(type='str', required=False, default='localhost'), invert_search=dict(type='bool', required=False, default=False), ip_protocols=dict(type='list', required=False, default=None), network=dict(type='str', required=True), nodes=dict(type='str', required=False, default=".*"), reference_snapshot=dict(type='str', required=False, default=None), source_ips=dict(type='str', required=False, default=None), source_ports=dict(type='str', required=False, default=None), name=dict(type='str', required=True)) # seed the result dict in the object # we primarily care about changed and state # change is if this module effectively modified the target # state will include any data that you want your module to pass back # for consumption, for example, in a subsequent task result = dict( changed=False, result_verbose='', ) # the AnsibleModule object will be our abstraction working with Ansible # this includes instantiation, a couple of common attr would be the # args/params passed to the execution, as well as if the module # supports check mode module = AnsibleModule( argument_spec=module_args, supports_check_mode=True, mutually_exclusive=[['action', 'reference_snapshot']]) if not pybatfish_found: module.fail_json(msg='Python module Pybatfish is required') if module.check_mode: return result snapshot = module.params['name'] reference_snapshot = module.params['reference_snapshot'] try: bf_session.coordinatorHost = module.params['host'] network = bf_set_network(module.params['network']) except Exception as e: module.fail_json(msg='Failed to set network: {}'.format(e), **result) try: load_questions() except Exception as e: module.fail_json(msg='Failed to load questions: {}'.format(e), **result) try: headers = HeaderConstraints( srcIps=module.params['source_ips'], dstIps=module.params['destination_ips'], ipProtocols=module.params['ip_protocols'], srcPorts=module.params['source_ports'], dstPorts=module.params['destination_ports']) except Exception as e: module.fail_json( msg='Failed to create header constraint: {}'.format(e), **result) try: filters = module.params['filters'] nodes = module.params['nodes'] action = module.params['action'] invert_search = module.params['invert_search'] q = bfq.searchfilters(headers=headers, filters=filters, nodes=nodes, action=action, invertSearch=invert_search) q_name = q.get_name() answer_obj = q.answer(snapshot=snapshot, reference_snapshot=reference_snapshot) answer_dict = bf_get_answer(questionName=q_name, snapshot=snapshot, reference_snapshot=reference_snapshot) except Exception as e: module.fail_json(msg='Failed to answer question: {}'.format(e), **result) answer_element = answer_dict["answerElements"][0] result['result_verbose'] = answer_element[ "rows"] if "rows" in answer_element else [] module.exit_json(**result)
def test_network_validation(): with pytest.raises(ValueError): bf_set_network('foo/bar')
def run_module(): # define the available arguments/parameters that a user can pass to # the module module_args = dict(policy_name=dict(type='str', required=False, default=None), host=dict(type='str', required=False, default='localhost'), name=dict(type='str', required=True), network=dict(type='str', required=True), new=dict(type='bool', required=False, default=False), path=dict(type='str', required=False)) # seed the result dict in the object # we primarily care about changed and state # change is if this module effectively modified the target # state will include any data that you want your module to pass back # for consumption, for example, in a subsequent task result = dict(changed=False, result='', result_verbose='', summary='') # the AnsibleModule object will be our abstraction working with Ansible # this includes instantiation, a couple of common attr would be the # args/params passed to the execution, as well as if the module # supports check mode module = AnsibleModule( argument_spec=module_args, supports_check_mode=True, required_if=[["new", True, ["path", "policy_name"] ] # path and name are required if adding a new policy ]) if not pybatfish_found: module.fail_json(msg='Python module Pybatfish is required') if module.check_mode: return result snapshot_name = module.params['name'] policy_name = module.params['policy_name'] try: bf_session.coordinatorHost = module.params['host'] network = bf_set_network(module.params['network']) except Exception as e: module.fail_json(msg='Failed to set network: {}'.format(e), **result) try: if module.params['new']: bf_init_analysis(policy_name, module.params['path']) except Exception as e: module.fail_json(msg='Failed to initialize policy: {}'.format(e), **result) try: if policy_name is not None: policy_results = { policy_name: _run_policy(policy_name, snapshot_name) } else: policy_results = { a: _run_policy(a, snapshot_name) for a in bf_list_analyses() } except Exception as e: module.fail_json(msg='Failed to answer policy: {}'.format(e), **result) result['result'] = {} result['result_verbose'] = {} failure = False # If a check's summary.numFailed is 0, we assume the check PASSed for policy in policy_results: policy_result = policy_results[policy] result['result'][policy] = { k: PASS if policy_result[k]['summary']['numFailed'] == 0 else FAIL for k in policy_result } failure |= FAIL in result['result'][policy].values() result['result_verbose'][policy] = { k: policy_result[k]['answerElements'][0]['rows'] if 'rows' in policy_result[k]['answerElements'][0] else [] for k in policy_result } result['summary'] = FAIL if failure else PASS module.exit_json(**result)
def test_list_snapshots(network, example_snapshot): bf_set_network(network) assert bf_list_snapshots() == [example_snapshot] verbose = bf_list_snapshots(verbose=True) assert verbose.get('snapshotlist') is not None assert len(verbose.get('snapshotlist')) == 1