GithubHelp home page GithubHelp logo

ciscodevnet / ftdansible Goto Github PK

View Code? Open in Web Editor NEW
37.0 28.0 20.0 1.62 MB

FTD Ansible module

License: GNU General Public License v3.0

Python 99.65% Dockerfile 0.35%
ansible-modules ftd-ansible ftd playbook sample-playbooks

ftdansible's Introduction

FTD Ansible Modules

A collection of Ansible modules that automate configuration management and execution of operational tasks on Cisco Firepower Threat Defense (FTD) devices using FTD REST API.

This file describes the development and testing aspects. In case you are looking for the user documentation, please check FTD Ansible docs on DevNet.

Installation Guide

The project contains four Ansible modules:

  • ftd_configuration.py - manages device configuration via REST API. The module configures virtual and physical devices by sending HTTPS calls formatted according to the REST API specification;
  • ftd_file_download.py - downloads files from FTD devices via HTTPS protocol;
  • ftd_file_upload.py - uploads files to FTD devices via HTTPS protocol;
  • ftd_install.py - installs FTD images on hardware devices. The module performs a complete reimage of the Firepower system by downloading the new software image and installing it.

Sample playbooks are located in the samples folder.

Running playbooks in Docker

  1. Build the default Docker image:

    docker build -t ftd-ansible .
    

    NOTE The default image is based on the release v0.1.0 of the FTD-Ansible and Python 3.6.

  2. You can build the custom Docker image:

    docker build -t ftd-ansible --build-arg PYTHON_VERSION=<2.7|3.5|3.6|3.7> --build-arg FTD_ANSIBLE_VERSION=<tag name | branch name> .
    
  3. Create an inventory file that tells Ansible what devices to run the tasks on. sample_hosts shows an example of inventory file.

  4. Run the playbook in Docker mounting playbook folder to /ftd-ansible/playbooks and inventory file to /etc/ansible/hosts:

    docker run -v $(pwd)/samples:/ftd-ansible/playbooks -v $(pwd)/inventory/sample_hosts:/etc/ansible/hosts ftd-ansible playbooks/network_object.yml
    

Running playbooks locally

  1. Create a virtual environment and activate it:
python3 -m venv venv
. venv/bin/activate
  1. Install dependencies: pip install -r requirements.txt

  2. Update Python path to include the project's directory:

export PYTHONPATH=.:$PYTHONPATH
  1. Run the playbook:
ansible-playbook samples/network_object.yml

Unit Tests

The project contains unit tests for Ansible modules, HTTP API plugin and util files. They can be found in test/unit directory. Ansible has many utils for mocking and running tests, so unit tests in this project also rely on them and including Ansible test module to the Python path is required.

Running unit tests in Docker

  1. Build the Docker image:
docker build -t ftd-ansible-test -f Dockerfile.tests . 

NOTE: Dockerfile uses Ansible version from requirements.txt. You can change it by replacing the version in requirements.txt and rebuilding the Docker image.

  1. Run unit tests with:
docker run ftd-ansible-test

To run a single test, specify the filename at the end of command:

docker run ftd-ansible-test test/unit/test_ftd_configuration.py

NOTE: You need to rebuild the Docker image on every change of the code.

Troubleshooting

import file mismatch:
imported module 'test.unit.module_utils.test_common' has this __file__ attribute: ...
which is not the same as the test file we want to collect:
  /ftd-ansible/test/unit/module_utils/test_common.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules

In case you experience the following error while running the tests in Docker, remove compiled bytecode files files with find . -name "*.pyc" -type f -delete command and try again.

Running unit tests locally

  1. Clone Ansible repository from GitHub;

  2. Install Ansible and test dependencies:

pip install $ANSIBLE_DIR/requirements.txt
pip install test-requirements.txt
  1. Add Ansible modules to the Python path:
export PYTHONPATH=$PYTHONPATH:$ANSIBLE_DIR/lib:$ANSIBLE_DIR/test
  1. Run unit tests:
pytest test/unit

Running tests with TOX

NOTE: To be able to run tests with the specific version of Python using tox you need to have this version of Python installed locally

Install tox locally:

pip install tox

Check the list of currently supported environments:

tox -l

NOTE: environments with -integration postfix preconfigured for integration tests:

Setup PYTHONPATH as described in the previous section Run unit tests in virtualenvs using tox:

tox -e py27,py35,py36,py37

Run integration tests in virtualenvs using tox:

export REPORTS_DIR=<path to the folder where JUnit reports will be stored>
tox -e py27-integration,py35-integration,py36-integration,py37-integration -- samples/network_object.yml -i inventory/sample_hosts

Running style check locally

  1. Install Flake8 locally:

    pip install flake8
    
  2. Run Flake8 check:

    flake8
    

Flake8 configuration is defined in the tox config file file.

Integration Tests

Integration tests are written in a form of playbooks and usually started with ansible-test command from Ansible repository. As this project is created outside Ansible, it does not have utils to run the tests. Thus, integration tests are written as sample playbooks with assertion and can be found in the samples folder. They start with test_ prefix and can be run as usual playbooks.

Debugging

  1. Add log_path with path to log file in ansible.cfg

  2. Run ansible-playbook with -vvvv

    $ ansible-playbook samples/network_object.yml -vvvv
    
  3. The log file will contain additional information (REST, etc.)

ftdansible's People

Contributors

119vik avatar alexandervorkov avatar annikulin avatar berezovskyi-oleksandr avatar costeanadrian avatar dependabot[bot] avatar eckelcu avatar jockdarock avatar kalinindenys avatar sdbrain avatar surbhibansal14 avatar veeratcisco avatar vitalii-kostenko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ftdansible's Issues

Sample configuration of route entry

Can a sample route entry playbook be provided? Also in the example should be multiple network objects to show proper syntax of that for networks and gateway (single object). I am working on building a playbook for it now but have run into a few issues. When I look at the required field for upsertStaticRouteEntry it requires 2 path parameters in addition to the data parameters.

Parameter Required Type Description
parentId True string ย 
objId True string

The parent ID makes some sense in terms of the StaticRouteEntryContainer exposed by the API (even though there is only one...assuming this is to easily accommodate multiple routing tables later?) however why would an objectid also be required for an upsert operation?

No module named 'module_utils'

Hello,

I am facing below issue, any idea what i am doing wrong here?

An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ModuleNotFoundError: No module named 'module_utils'
fatal: [sample_host]: FAILED! => {"msg": "Unexpected failure during module execution.", "stdout": ""}

Authentication error when running playbooks against FTD v 6.2.3

Hello,
I am unable to get the playbooks to work and get this error when running .

TASK [Gathering Facts]
FAILED! => {"msg": "Server returned an error during authentication request: {'code': 404, 'description': 'The server has not found anything matching the request URI', 'homeRef': '/', 'reasonPhrase': 'Not Found', 'uri'

Rest api has been enabled on the FTD.
Using connection: httpapi

Connection Error

An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: The API token path is incorrect. Please, check correctness of the ansible_httpapi_ftd_token_path variable in the inventory file.
fatal: [CiscoFTD]: FAILED! => {"changed": false, "module_stderr": "Traceback (most recent call last):\n File "/root/.ansible/tmp/ansible-local-50028_4cy9g2s/ansible-tmp-1676500739.3515654-50173-16394990195603/AnsiballZ_ftd_configuration.py", line 107, in \n _ansiballz_main()\n File "/root/.ansible/tmp/ansible-local-50028_4cy9g2s/ansible-tmp-1676500739.3515654-50173-16394990195603/AnsiballZ_ftd_configuration.py", line 99, in _ansiballz_main\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n File "/root/.ansible/tmp/ansible-local-50028_4cy9g2s/ansible-tmp-1676500739.3515654-50173-16394990195603/AnsiballZ_ftd_configuration.py", line 47, in invoke_module\n runpy.run_module(mod_name='ansible_collections.community.network.plugins.modules.ftd_configuration', init_globals=dict(_module_fqn='ansible_collections.community.network.plugins.modules.ftd_configuration', _modlib_path=modlib_path),\n File "/usr/lib/python3.10/runpy.py", line 224, in run_module\n return _run_module_code(code, init_globals, run_name, mod_spec)\n File "/usr/lib/python3.10/runpy.py", line 96, in _run_module_code\n _run_code(code, mod_globals, init_globals,\n File "/usr/lib/python3.10/runpy.py", line 86, in _run_code\n exec(code, run_globals)\n File "/tmp/ansible_ftd_configuration_payload_1tpbsnsk/ansible_ftd_configuration_payload.zip/ansible_collections/community/network/plugins/modules/ftd_configuration.py", line 135, in \n File "/tmp/ansible_ftd_configuration_payload_1tpbsnsk/ansible_ftd_configuration_payload.zip/ansible_collections/community/network/plugins/modules/ftd_configuration.py", line 116, in main\n File "/tmp/ansible_ftd_configuration_payload_1tpbsnsk/ansible_ftd_configuration_payload.zip/ansible_collections/community/network/plugins/module_utils/network/ftd/configuration.py", line 232, in execute_operation\n File "/tmp/ansible_ftd_configuration_payload_1tpbsnsk/ansible_ftd_configuration_payload.zip/ansible_collections/community/network/plugins/module_utils/network/ftd/configuration.py", line 245, in crud_operation\n File "/tmp/ansible_ftd_configuration_payload_1tpbsnsk/ansible_ftd_configuration_payload.zip/ansible_collections/community/network/plugins/module_utils/network/ftd/configuration.py", line 263, in get_operation_spec\n File "/tmp/ansible_ftd_configuration_payload_1tpbsnsk/ansible_ftd_configuration_payload.zip/ansible/module_utils/connection.py", line 200, in rpc\nansible.module_utils.connection.ConnectionError: The API token path is incorrect. Please, check correctness of the ansible_httpapi_ftd_token_path variable in the inventory file.\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

[hq_fw]
CiscoFTD ansible_host=fw.domain.com ansible_user=admin ansible_password=dsdsfsd% ansible_network_os=ftd ansible_httpapi_ftd_token_path=/etc/apidata/ftd/token

  GNU nano 6.2                                                                                                  hq-ftd-backup.yml
    ansible_httpapi_ftd_token_path: /api/fdm/latest/fdm/token
  tasks:
    - name: Get FTD API token
      uri:
        url: "https://fw.domain.com:8080{{ ansible_httpapi_ftd_token_path }}"
        method: POST
        body_format: json
        body:
          grant_type: password
          username: admin
          password: Password123
        validate_certs: false
        return_content: yes
      register: ftd_token

    - name: Save FTD API token to file
      copy:
        content: "{{ ftd_token.json.access_token }}"
        dest: "/etc/apidata/ftd/token"


    - name: Schedule an immediate backup
      ftd_configuration:
        operation: addBackupImmediate
        data:
          scheduleType: IMMEDIATE
          name: TestBackup
          backupLocation: DEFAULT
          type: backupimmediate
        query_params:
          access_token: "{{ ftd_token.json.access_token }}"
        register_as: backup

    - name: Wait till the backup job is completed
      ftd_configuration:
        operation: getJobHistoryBackup
        path_params:
          objId: "{{ backup.jobHistoryUuid }}"
        query_params:
          access_token: "{{ ftd_token.json.access_token }}"
        register_as: backup_job
      until: backup_job.status != 'QUEUED' and backup_job.status != 'IN_PROGRESS'
      retries: 100
      delay: 3

    - name: Stop the playbook if the backup failed
      fail:
        msg: 'Backup failed. Status: {{ backup_job.statusMessage }}'
      when: backup_job.status != 'SUCCESS'

    - name: Store the config to S3 bucket

xxxxxxxxxxxxxxxxxxxxxx

So basicly i cant figure out how to get this to work, its a endless loop of token related matters.

unsure how to proceed.

FTD Facts module

Are there any plans to create/release a facts module for Firepower facts module?

upsertSubInterface operation not working

When attempting to create and/or modify a SubInterface using the upsertSubInterface operation, I get the following error:

We're using version v0.3.1

The full traceback is:
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/modules/ftd_configuration.py", line 116, in main
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 230, in execute_operation
    return self.upsert_object(op_name, params)
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 498, in upsert_object
    existing_obj = self._find_object_matching_params(model_name, params)
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 359, in _find_object_matching_params
    for i, obj in enumerate(filtered_objs):
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 294, in <genexpr>
    return (i for i in item_generator if match_filters(filters, i))
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 557, in iterate_over_pageable_resource
    result = resource_func(params=params)
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 416, in send_general_request
    return self._send_request(url, method, data, path_params, query_params)
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 425, in _send_request
    raise_for_failure(response)
  File "/tmp/ansible_ftd_configuration_payload_q7nck6r0/ansible_ftd_configuration_payload.zip/ansible_collections/co
mmunity/network/plugins/module_utils/network/ftd/configuration.py", line 421, in raise_for_failure
    raise FtdServerError(resp[ResponseParams.RESPONSE], resp[ResponseParams.STATUS_CODE])
failed: [ftd.striveworks.us] (item={'name': 'att_wan_vlan_68', 'description': '', 'parent_interface_name': 'ether_1-
9', 'vlan_id': 68, 'ip_address': '00.000.00.00', 'network_prefix': 29}) => changed=false
  ansible_loop_var: item
  invocation:
    module_args:
      data:
        description: ''
        enabled: true
        hardwareName: Ethernet1/9.68
        ipv4:
          addressNull: false
          defaultRouteUsingDHCP: false
          dhcp: false
          dhcpRouteMetric: null
          ipAddress:
            ipAddress: 00.000.00.00 # REDACTED
            netmask: '29'
            standbyIpAddress: ''
            type: haipv4address
          ipType: STATIC
          type: interfaceipv4
        linkState: UP
        mode: ROUTED
        monitorInterface: true
        mtu: '1500'
        name: att_wan_vlan_68
        present: true
        subIntfId: '68'
        vlanId: '68'
      filters:
        name: att_wan_vlan_68
      operation: upsertSubInterface
      path_params:
        parentId: bb82d364-e99a-11ea-95c7-b79d7e7ef70c
      query_params: null
      register_as: null
  item:
    description: ''
    ip_address: 00.000.00.00 # REDACTED
    name: att_wan_vlan_68
    network_prefix: 29
    parent_interface_name: ether_1-9
    vlan_id: 68
  msg: 'Server returned an error trying to execute upsertSubInterface operation. Status code: 404. Server response: {''error'': {''severity'': ''ERROR'', ''key'': ''General'', ''messages'': [{''description'': ''The server has not found anything matching the request URI'', ''code'': None, ''location'': None}, {''description'': ''Not Found (404) - The server has not found anything matching the request URI'', ''code'': None, ''location'': None}]}}'

From looking at the API reference, I suspect that the code is either adding, or failing to add, the subinterface's object ID at the end of the URL during one of the API calls (e.g. a POST to /devices/default/interfaces/{parentId}/subinterfaces must not have the Object ID in the URL, but a PUT to /devices/default/interfaces/{parentId}/subinterfaces/{objId} must have the Object ID in the URL). That's just speculation, though; I haven't dived into the code yet.

Authentication failed

The module failed to authenticate against Firepower Thread Defense.
Tested out with both latest code on master branch and v0.3.0.

Device info
Model: Cisco Firepower Management Center 4500
Software Versions: 6.3.0.3

Here is ansible play

- hosts: ftd  
   connection: httpapi
   tasks:
     - name: Get existing networks
       ftd_configuration:
         operation: getNetworkObjectList
         register_as: my_networks

Here is inventory
[ftd] 192.XX.XXX.XXX ansible_network_os=ftd ansible_user="myusername" ansible_password="mypassword" ansible_httpapi_port=443 ansible_httpapi_use_ssl=True ansible_httpapi_validate_certs=False

Error message
fatal: [192.XX.XXX.XXX]: FAILED! => {"msg": "Ansible could not determine the API token path automatically. Please, specify the 'ansible_httpapi_ftd_token_path' variable in the inventory file."}

Since the above error, tried out the following by explicitly specifying FTD token path (with v1,v2 and v3).
Inventory file looked like below
[ftd] 192.XX.XXX.XXX ansible_network_os=ftd ansible_user="myusername" ansible_password="mypassword" ansible_httpapi_port=443 ansible_httpapi_use_ssl=True ansible_httpapi_validate_certs=False ansible_httpapi_ftd_token_path=/api/fdm/v2/fdm/token

Error message
fatal: [192.XX.XXX.XXX]: FAILED! => {"msg": "The API token path is incorrect. Please, check correctness of the 'ansible_httpapi_ftd_token_path' variable in the inventory file."}

'Invalid data provided': "'type'"

I'm encountering an issue when using the ftd_configuration module in Ansible to configure network objects on Cisco FTD devices. Despite following the documentation and using parameters that seem correct, I receive an error indicating 'Invalid data provided': "'type'". I'm trying to add a network object with specific details. I'm using Ansible version 2.14.6, Python 3.10.6, and the latest version of the community.network collection. Could anyone guide me on what might be wrong with my parameters or how to resolve this issue?

Need a function to remove DHCP servers from an interface

In order to configure/change an interface or subinterface IP address there needs to be a way/function to easily remove the default DHCP server (for instance on the inside interface) to be able to change or add ip addresses that do not reside within the configured DHCP server scope.

Perhaps a sample of how to properly do this would be helpful?

Cisco ftd_configuration module not idempotent

SUMMARY

Cisco ftd_configuration ansible module is not idempotent when tried with multiple references of the same object in array.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

ftd_configuration

ANSIBLE VERSION
2.7.5
CONFIGURATION

OS / ENVIRONMENT

mac os

STEPS TO REPRODUCE
- hosts: ftd
  connection: httpapi
  tasks:
- name: Create URL Object
  ftd_configuration:
    operation: upsertURLObject
    data:
      name: GoogleURL
      description: URL for Google
      url: www.google.com
      type: urlobject
      register_as: url_obj

- name: Find Security Intelligence URL Policy
  ftd_configuration:
    operation: getSecurityIntelligenceURLPolicyList
    register_as: policies

- name: Setup SecurityIntelligenceURLPolicy
  ftd_configuration:
    operation: editSecurityIntelligenceURLPolicy
   data:
     id: "{{ policies[0]['id'] }}"
    name: "{{ policies[0]['name'] }}"
    version: "{{ policies[0]['version'] }}"
    whitelist:
    - "{{ policies[0]['whitelist'] + [url_obj] }}"
    type: securityintelligenceurlpolicy
    path_params:
      objId: "{{ policies[0]['id'] }}" 
EXPECTED RESULTS

Play should be idempotent in consecutive runs.

ACTUAL RESULTS

Play is not idempotent in consecutive runs and shows as changed=True, every times the play runs.


Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.