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)
Exemple #5
0
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())
Exemple #6
0
    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()
Exemple #7
0
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)
Exemple #12
0
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)
Exemple #13
0
 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)
Exemple #21
0
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)
Exemple #22
0
def test_network_validation():
    with pytest.raises(ValueError):
        bf_set_network('foo/bar')
Exemple #23
0
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)
Exemple #24
0
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