Examples
Here are some examples that demonstrate how to use Ansible modules for common operations on FTD devices. Hopefully, they will make the process of creating your playbooks easier.
Make initial provisioning
Initially, the device is delivered in a locked state. To unlock the device and start using its API, the user needs to accept an end-user license agreement (EULA) and change the default password. Luckily, it can be done with Ansible.
The following tasks check the current state of device provisioning, displays the EULA text, and asks the user to accept it:
- name: Get provisioning info
ftd_configuration:
operation: getInitialProvision
path_params:
objId: default
register_as: provisionInfo
- name: Show EULA text
debug:
msg: 'EULA details: {{ provisionInfo.eulaText }}'
- name: Confirm EULA acceptance
pause:
prompt: Please confirm you want to accept EULA. Press Return to continue. To abort,
press Ctrl+C and then "A"
After getting familiar with the EULA details, this task sends a request to the device to reset the password and unlock it.
- name: Complete initial provisioning
ftd_configuration:
operation: addInitialProvision
data:
acceptEULA: true
eulaText: '{{ provisionInfo.eulaText }}'
type: initialprovision
currentPassword: '{{ ansible_password }}'
newPassword: '{{ ansible_password_temp }}'
vars:
ansible_command_timeout: 30
When the previous task is successfully accomplished, the device is unlocked and ready to be configured via API.
Create a NetworkObject
This example demonstrates how to create a simple entity representing a network -
NetworkObject
. The task creates a new object representing a fully qualified
domain name (FQDN) network for Cisco DevNet website.
After creation, the network object is stored as an Ansible fact and can be accessed
using networkobject_ciscodevnetnetwork
variable.
- name: Create an FQDN network for Cisco DevNet
ftd_configuration:
operation: upsertNetworkObject
data:
name: CiscoDevNetNetwork
subType: FQDN
value: developer.cisco.com
type: networkobject
dnsResolution: IPV4_AND_IPV6
Create a NetworkObjectGroup
NetworkObjectGroup
is a container object representing a group of networks.
The first task creates an auxiliary NetworkObject
for Cisco FTD. Then,
a NetworkObjectGroup
, consisting of two previously created networks,
is created in the second task.
Notice, that the second task, creating a NetworkObjectGroup
object, references previously
created NetworkObject
s. It is possible because every created object is stored as an Ansible fact.
By default, the fact name for a new object is constructed as $TYPE_$NAME
, but it can be reset by
adding a register_as
parameter to the task that creates the object.
- name: Create an FQDN network for Cisco FTD
ftd_configuration:
operation: upsertNetworkObject
data:
name: CiscoFtdNetwork
subType: FQDN
value: ftd.cisco.com
type: networkobject
dnsResolution: IPV4_AND_IPV6
- name: Create a Cisco network group
ftd_configuration:
operation: upsertNetworkObjectGroup
data:
name: CiscoNetworkGroup
type: networkobjectgroup
objects:
- '{{ networkobject_ciscodevnetnetwork }}'
- '{{ networkobject_ciscoftdnetwork }}'
Create an AccessRule
An AccessRule
permits or denies traffic based on different parameters, such as a protocol,
a source or destination IP address, network, etc.
The example shows how to create an AccessRule
allowing traffic from the previously created
CiscoDevNetNetwork
.
- name: Create an access rule allowing trafic from Cisco DevNet
ftd_configuration:
operation: upsertAccessRule
data:
name: AllowCiscoTraffic
type: accessrule
sourceNetworks:
- '{{ networkobject_ciscodevnetnetwork }}'
ruleAction: PERMIT
eventLogAction: LOG_BOTH
path_params:
parentId: default
Make a deployment
Changes made on the FTD device are applied only after they get deployed. This example demonstrates how to start a deployment job and make sure that it succeeds.
The first two tasks fetch a list of pending changes that are not in the deployed state yet and make sure that there are at least some changes that need to be deployed. Otherwise, the playbook execution stops.
- name: Fetch pending changes
ftd_configuration:
operation: getBaseEntityDiffList
register_as: pending_changes
- name: Complete playbook when nothing to deploy
meta: end_play
when: pending_changes | length == 0
Next, the playbook starts a new deployment job and registers returned DeploymentStatus
as a deployment_job
Ansible fact. The
following task polls the DeploymentStatus
every 3 seconds until the job is completed. The last part verifies that the deployment
is completed successfully. Otherwise, it stops the playbook with an error message.
- name: Start deployment
ftd_configuration:
operation: addDeployment
register_as: deployment_job
- name: Poll deployment status until the job is finished
ftd_configuration:
operation: getDeployment
path_params:
objId: '{{ deployment_job.id }}'
register_as: deployment_status
until: deployment_status.endTime != -1
retries: 100
delay: 3
- name: Stop the playbook if the deployment failed
fail:
msg: 'Deployment failed. Status: {{ deployment_status.statusMessages }}'
when: deployment_status.state != 'DEPLOYED'
Configure interfaces
To enable a physical interface and update its IPv4 address with a static configuration, check the following upsert
play.
Notice, that it has a filters
parameter to select an interface by hardware name. Usually, interfaces do not have names on fresh
devices, while hardware names are always set and cannot be changed, so filtering by hardware name is preferred.
- name: Setup Inside Interface with static IP
ftd_configuration:
operation: upsertPhysicalInterface
data:
name: inside
hardwareName: GigabitEthernet0/1
monitorInterface: true
ipv4:
addressNull: false
defaultRouteUsingDHCP: false
dhcp: false
ipAddress:
ipAddress: 192.168.20.2
netmask: 255.255.255.0
standbyIpAddress: 192.168.20.3
type: haipv4address
ipType: STATIC
type: interfaceipv4
mtu: 1500
enabled: true
mode: ROUTED
type: physicalinterface
filters:
hardwareName: GigabitEthernet0/1
Use host and group variables
Variables in Ansible allow making content of the playbook host- or group-specific. For example, to create a NetworkObject
specific for each device, you can use the following task template with network_type
and network_value
variables:
- name: Create a NetworkObject based on host variables
ftd_configuration:
operation: addNetworkObject
data:
name: HostSpecificNetwork
subType: '{{ network_type }}'
value: '{{ network_value }}'
isSystemDefined: false
type: networkobject
dnsResolution: IPV4_AND_IPV6
There are multiple ways to specify variables in Ansible. One option is to put them in the inventory file together with other host and group variables:
[vftd]
localhost ... network_value=127.0.0.1
10.89.21.213 ... network_value=130.51.181.225
[vftd:vars]
network_type=HOST
With the playbook and inventory shown above, Ansible will create a HOST
network pointing to 127.0.0.1
on the
localhost
device, and another network for IP address 130.51.181.225
on device 10.89.21.213
.
More information about variables in Ansible documentation.
More samples on GitHub
All playbook samples can be found on GitHub. We are constantly adding more examples there and highly appreciate all contributions too.