summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorIvan Bojer <ivanbojer@users.noreply.github.com>2017-08-15 13:24:15 -0700
committerSam Doran <sdoran@ansible.com>2017-08-15 16:24:15 -0400
commit8b617aaef564052d05c41e033f7d166570d660b1 (patch)
treecf20f4ab219bdfdd670360b69b31cc54619ad375 /lib
parent08767946cb4441bdb3386cf848d80618529f2c4a (diff)
downloadansible-8b617aaef564052d05c41e033f7d166570d660b1.tar.gz
Panos object (#28028)
* - deprecated panos_address and panos_service in lieu of common panos_object * - deprecated/removed panos_address and panos_service in lieu for panos_object * squash! - deprecated/removed panos_address and panos_service in lieu for panos_object * - fixed PEP8 issues * - ansible_metadata requires metadata_version instead of just version key in 2.4 * add > to multi line descriptions * update version string to 2.4 * Update legacy-files.txt
Diffstat (limited to 'lib')
-rwxr-xr-xlib/ansible/modules/network/panos/panos_address.py216
-rw-r--r--lib/ansible/modules/network/panos/panos_object.py463
-rw-r--r--lib/ansible/modules/network/panos/panos_service.py178
3 files changed, 463 insertions, 394 deletions
diff --git a/lib/ansible/modules/network/panos/panos_address.py b/lib/ansible/modules/network/panos/panos_address.py
deleted file mode 100755
index 9accff085b..0000000000
--- a/lib/ansible/modules/network/panos/panos_address.py
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Ansible module to manage PaloAltoNetworks Firewall
-# (c) 2016, techbizdev <techbizdev@paloaltonetworks.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-ANSIBLE_METADATA = {'metadata_version': '1.0',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: panos_address
-short_description: Create address service object on PanOS devices
-description:
- - Create address service object of different types [IP Range, FQDN, or IP Netmask].
-author: "Luigi Mori (@jtschichold), Ken Celenza (@itdependsnetworks), Ivan Bojer (@ivanbojer)"
-version_added: "2.3"
-requirements:
- - pan-python can be obtained from PyPi U(https://pypi.python.org/pypi/pan-python)
-options:
- ip_address:
- description:
- - IP address (or hostname) of PAN-OS device being configured.
- required: true
- username:
- description:
- - Username credentials to use for authentication.
- default: "admin"
- password:
- description:
- - Password credentials to use for authentication.
- required: true
- address:
- description:
- - IP address with or without mask, range, or FQDN.
- required: true
- default: None
- address_name:
- description:
- - Human readable name of the address.
- required: true
- default: None
- type:
- description:
- - This is the type of the object created.
- default: ip-nemask
- choices: [ 'ip-netmask', 'fqdn', 'ip-range' ]
- description:
- description:
- - Description of the address object.
- default: None
- tag:
- description:
- - Tag of the address object.
- default: None
- commit:
- description:
- - Commit configuration to the Firewall if it is changed.
- default: true
-'''
-
-EXAMPLES = '''
-- name: create IP-Netmask Object
- panos_address:
- ip_address: "192.168.1.1"
- password: 'admin'
- address_name: 'google_dns'
- address: '8.8.8.8/32'
- description: 'Google DNS'
- tag: 'Outbound'
- commit: False
-
-- name: create IP-Range Object
- panos_address:
- ip_address: "192.168.1.1"
- password: 'admin'
- type: 'ip-range'
- address_name: 'apple-range'
- address: '17.0.0.0-17.255.255.255'
- commit: False
-
-- name: create FQDN Object
- panos_address:
- ip_address: "192.168.1.1"
- password: 'admin'
- type: 'fqdn'
- address_name: 'google.com'
- address: 'www.google.com'
-'''
-
-RETURN = '''
-# Default return values
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import get_exception
-
-try:
- import pan.xapi
- from pan.xapi import PanXapiError
-
- HAS_LIB = True
-except ImportError:
- HAS_LIB = False
-
-_ADDRESS_XPATH = "/config/devices/entry[@name='localhost.localdomain']" + \
- "/vsys/entry[@name='vsys1']" + \
- "/address/entry[@name='%s']"
-
-
-def address_exists(xapi, address_name):
- xapi.get(_ADDRESS_XPATH % address_name)
- e = xapi.element_root.find('.//entry')
- if e is None:
- return False
- return True
-
-
-def add_address(xapi, module, address, address_name, description, type, tag):
- if address_exists(xapi, address_name):
- return False
-
- exml = []
- exml.append('<%s>' % type)
- exml.append('%s' % address)
- exml.append('</%s>' % type)
-
- if description:
- exml.append('<description>')
- exml.append('%s' % description)
- exml.append('</description>')
-
- if tag:
- exml.append('<tag>')
- exml.append('<member>%s</member>' % tag)
- exml.append('</tag>')
-
- exml = ''.join(exml)
-
- xapi.set(xpath=_ADDRESS_XPATH % address_name, element=exml)
-
- return True
-
-
-def main():
- argument_spec = dict(
- ip_address=dict(required=True),
- password=dict(required=True, no_log=True),
- username=dict(default='admin'),
- address_name=dict(required=True),
- address=dict(),
- description=dict(),
- tag=dict(),
- type=dict(default='ip-netmask', choices=['ip-netmask', 'ip-range', 'fqdn']),
- commit=dict(type='bool', default=True)
- )
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
-
- if not HAS_LIB:
- module.fail_json(msg='pan-python required for this module')
-
- ip_address = module.params["ip_address"]
- password = module.params["password"]
- username = module.params['username']
-
- xapi = pan.xapi.PanXapi(
- hostname=ip_address,
- api_username=username,
- api_password=password
- )
-
- address_name = module.params['address_name']
- address = module.params['address']
- commit = module.params['commit']
-
- description = module.params['description']
- tag = module.params['tag']
- type = module.params['type']
-
- changed = False
- try:
- changed = add_address(xapi, module,
- address,
- address_name,
- description,
- type,
- tag)
- except PanXapiError:
- exc = get_exception()
- module.fail_json(msg=exc.message)
-
- if changed and commit:
- xapi.commit(cmd="<commit></commit>", sync=True, interval=1)
-
- module.exit_json(changed=changed, msg="okey dokey")
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/panos/panos_object.py b/lib/ansible/modules/network/panos/panos_object.py
new file mode 100644
index 0000000000..1ffadc5352
--- /dev/null
+++ b/lib/ansible/modules/network/panos/panos_object.py
@@ -0,0 +1,463 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Ansible module to manage PaloAltoNetworks Firewall
+# (c) 2016, techbizdev <techbizdev@paloaltonetworks.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+# limitations under the License.
+
+ANSIBLE_METADATA = {'status': ['preview'],
+ 'supported_by': 'community',
+ 'metadata_version': '1.0'}
+
+DOCUMENTATION = '''
+---
+module: panos_object
+short_description: create/read/update/delete object in PAN-OS or Panorama
+description: >
+ - Policy objects form the match criteria for policy rules and many other functions in PAN-OS. These may include
+ address object, address groups, service objects, service groups, and tag.
+author: "Bob Hagen (@rnh556)"
+version_added: "2.4"
+requirements:
+ - pan-python can be obtained from PyPi U(https://pypi.python.org/pypi/pan-python)
+ - pandevice can be obtained from PyPi U(https://pypi.python.org/pypi/pandevice)
+notes:
+ - Checkmode is not supported.
+ - Panorama is supported.
+options:
+ ip_address:
+ description:
+ - IP address (or hostname) of PAN-OS device or Panorama management console being configured.
+ required: true
+ username:
+ description:
+ - Username credentials to use for authentication.
+ required: false
+ default: "admin"
+ password:
+ description:
+ - Password credentials to use for authentication.
+ required: true
+ api_key:
+ description:
+ - API key that can be used instead of I(username)/I(password) credentials.
+ operation:
+ description:
+ - The operation to be performed. Supported values are I(add)/I(delete)/I(find).
+ required: true
+ addressobject:
+ description:
+ - The name of the address object.
+ address:
+ description:
+ - The IP address of the host or network in CIDR notation.
+ address_type:
+ description:
+ - The type of address object definition. Valid types are I(ip-netmask) and I(ip-range).
+ addressgroup:
+ description:
+ - A static group of address objects or dynamic address group.
+ static_value:
+ description:
+ - A group of address objects to be used in an addressgroup definition.
+ dynamic_value:
+ description:
+ - The filter match criteria to be used in a dynamic addressgroup definition.
+ serviceobject:
+ description:
+ - The name of the service object.
+ source_port:
+ description:
+ - The source port to be used in a service object definition.
+ destination_port:
+ description:
+ - The destination port to be used in a service object definition.
+ protocol:
+ description:
+ - The IP protocol to be used in a service object definition. Valid values are I(tcp) or I(udp).
+ servicegroup:
+ description:
+ - A group of service objects.
+ services:
+ description:
+ - The group of service objects used in a servicegroup definition.
+ description:
+ description:
+ - The description of the object.
+ tag_name:
+ description:
+ - The name of an object or rule tag.
+ color:
+ description: >
+ - The color of the tag object. Valid values are I(red, green, blue, yellow, copper, orange, purple, gray,
+ light green, cyan, light gray, blue gray, lime, black, gold, and brown).
+ devicegroup:
+ description: >
+ - The name of the Panorama device group. The group must exist on Panorama. If device group is not defined it
+ is assumed that we are contacting a firewall.
+ required: false
+ default: None
+'''
+
+EXAMPLES = '''
+- name: search for shared address object
+ panos_object:
+ ip_address: '{{ ip_address }}'
+ username: '{{ username }}'
+ password: '{{ password }}'
+ operation: 'find'
+ address: 'DevNet'
+
+- name: create an address group in devicegroup using API key
+ panos_object:
+ ip_address: '{{ ip_address }}'
+ api_key: '{{ api_key }}'
+ operation: 'add'
+ addressgroup: 'Prod_DB_Svrs'
+ static_value: ['prod-db1', 'prod-db2', 'prod-db3']
+ description: 'Production DMZ database servers'
+ tag_name: 'DMZ'
+ devicegroup: 'DMZ Firewalls'
+
+- name: create a global service for TCP 3306
+ panos_object:
+ ip_address: '{{ ip_address }}'
+ api_key: '{{ api_key }}'
+ operation: 'add'
+ serviceobject: 'mysql-3306'
+ destination_port: '3306'
+ protocol: 'tcp'
+ description: 'MySQL on tcp/3306'
+
+- name: create a global tag
+ panos_object:
+ ip_address: '{{ ip_address }}'
+ username: '{{ username }}'
+ password: '{{ password }}'
+ operation: 'add'
+ tag_name: 'ProjectX'
+ color: 'yellow'
+ description: 'Associated with Project X'
+
+- name: delete an address object from a devicegroup using API key
+ panos_object:
+ ip_address: '{{ ip_address }}'
+ api_key: '{{ api_key }}'
+ operation: 'delete'
+ addressobject: 'Win2K test'
+'''
+
+RETURN = '''
+# Default return values
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.basic import get_exception
+
+try:
+ import pan.xapi
+ from pan.xapi import PanXapiError
+ import pandevice
+ from pandevice import base
+ from pandevice import firewall
+ from pandevice import panorama
+ from pandevice import objects
+ import xmltodict
+ import json
+
+ HAS_LIB = True
+except ImportError:
+ HAS_LIB = False
+
+
+def get_devicegroup(device, devicegroup):
+ dg_list = device.refresh_devices()
+ for group in dg_list:
+ if isinstance(group, pandevice.panorama.DeviceGroup):
+ if group.name == devicegroup:
+ return group
+ return False
+
+
+def find_object(device, dev_group, obj_name, obj_type):
+ # Get the firewall objects
+ obj_type.refreshall(device)
+ if isinstance(device, pandevice.firewall.Firewall):
+ addr = device.find(obj_name, obj_type)
+ return addr
+ elif isinstance(device, pandevice.panorama.Panorama):
+ addr = device.find(obj_name, obj_type)
+ if addr is None:
+ if dev_group:
+ device.add(dev_group)
+ obj_type.refreshall(dev_group)
+ addr = dev_group.find(obj_name, obj_type)
+ return addr
+ else:
+ return False
+
+
+def create_object(**kwargs):
+ if kwargs['addressobject']:
+ newobject = objects.AddressObject(
+ name=kwargs['addressobject'],
+ value=kwargs['address'],
+ type=kwargs['address_type'],
+ description=kwargs['description'],
+ tag=kwargs['tag_name']
+ )
+ if newobject.type and newobject.value:
+ return newobject
+ else:
+ return False
+ elif kwargs['addressgroup']:
+ newobject = objects.AddressGroup(
+ name=kwargs['addressgroup'],
+ static_value=kwargs['static_value'],
+ dynamic_value=kwargs['dynamic_value'],
+ description=kwargs['description'],
+ tag=kwargs['tag_name']
+ )
+ if newobject.static_value or newobject.dynamic_value:
+ return newobject
+ else:
+ return False
+ elif kwargs['serviceobject']:
+ newobject = objects.ServiceObject(
+ name=kwargs['serviceobject'],
+ protocol=kwargs['protocol'],
+ source_port=kwargs['source_port'],
+ destination_port=kwargs['destination_port'],
+ tag=kwargs['tag_name']
+ )
+ if newobject.protocol and newobject.destination_port:
+ return newobject
+ else:
+ return False
+ elif kwargs['servicegroup']:
+ newobject = objects.ServiceGroup(
+ name=kwargs['servicegroup'],
+ value=kwargs['services'],
+ tag=kwargs['tag_name']
+ )
+ if newobject.value:
+ return newobject
+ else:
+ return False
+ elif kwargs['tag_name']:
+ newobject = objects.Tag(
+ name=kwargs['tag_name'],
+ color=kwargs['color'],
+ comments=kwargs['description']
+ )
+ if newobject.name:
+ return newobject
+ else:
+ return False
+ else:
+ return False
+
+
+def add_object(device, dev_group, new_object):
+ if dev_group:
+ dev_group.add(new_object)
+ else:
+ device.add(new_object)
+ new_object.create()
+ return True
+
+
+def main():
+ argument_spec = dict(
+ ip_address=dict(required=True),
+ password=dict(no_log=True),
+ username=dict(default='admin'),
+ api_key=dict(no_log=True),
+ operation=dict(required=True, choices=['add', 'update', 'delete', 'find']),
+ addressobject=dict(default=None),
+ addressgroup=dict(default=None),
+ serviceobject=dict(default=None),
+ servicegroup=dict(default=None),
+ address=dict(default=None),
+ address_type=dict(default='ip-netmask', choices=['ip-netmask', 'ip-range', 'fqdn']),
+ static_value=dict(type='list', default=None),
+ dynamic_value=dict(default=None),
+ protocol=dict(default=None, choices=['tcp', 'udp']),
+ source_port=dict(default=None),
+ destination_port=dict(default=None),
+ services=dict(type='list', default=None),
+ description=dict(default=None),
+ tag_name=dict(default=None),
+ color=dict(default=None, choices=['red', 'green', 'blue', 'yellow', 'copper', 'orange', 'purple',
+ 'gray', 'light green', 'cyan', 'light gray', 'blue gray',
+ 'lime', 'black', 'gold', 'brown']),
+ devicegroup=dict(default=None)
+ )
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False,
+ required_one_of=[['api_key', 'password']],
+ mutually_exclusive=[['addressobject', 'addressgroup',
+ 'serviceobject', 'servicegroup',
+ 'tag_name']]
+ )
+ if not HAS_LIB:
+ module.fail_json(msg='Missing required libraries.')
+
+ ip_address = module.params["ip_address"]
+ password = module.params["password"]
+ username = module.params['username']
+ api_key = module.params['api_key']
+ operation = module.params['operation']
+ addressobject = module.params['addressobject']
+ addressgroup = module.params['addressgroup']
+ serviceobject = module.params['serviceobject']
+ servicegroup = module.params['servicegroup']
+ address = module.params['address']
+ address_type = module.params['address_type']
+ static_value = module.params['static_value']
+ dynamic_value = module.params['dynamic_value']
+ protocol = module.params['protocol']
+ source_port = module.params['source_port']
+ destination_port = module.params['destination_port']
+ services = module.params['services']
+ description = module.params['description']
+ tag_name = module.params['tag_name']
+ color = module.params['color']
+ devicegroup = module.params['devicegroup']
+
+ # Create the device with the appropriate pandevice type
+ device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key)
+
+ # If Panorama, validate the devicegroup
+ dev_group = None
+ if devicegroup and isinstance(device, panorama.Panorama):
+ dev_group = get_devicegroup(device, devicegroup)
+ if dev_group:
+ device.add(dev_group)
+ else:
+ module.fail_json(msg='\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup)
+
+ # What type of object are we talking about?
+ if addressobject:
+ obj_name = addressobject
+ obj_type = objects.AddressObject
+ elif addressgroup:
+ obj_name = addressgroup
+ obj_type = objects.AddressGroup
+ elif serviceobject:
+ obj_name = serviceobject
+ obj_type = objects.ServiceObject
+ elif servicegroup:
+ obj_name = servicegroup
+ obj_type = objects.ServiceGroup
+ elif tag_name:
+ obj_name = tag_name
+ obj_type = objects.Tag
+ else:
+ module.fail_json(msg='No object type defined!')
+
+ # Which operation shall we perform on the object?
+ if operation == "find":
+ # Search for the object
+ match = find_object(device, dev_group, obj_name, obj_type)
+
+ # If found, format and return the result
+ if match:
+ match_dict = xmltodict.parse(match.element_str())
+ module.exit_json(
+ stdout_lines=json.dumps(match_dict, indent=2),
+ msg='Object matched'
+ )
+ else:
+ module.fail_json(msg='Object \'%s\' not found. Is the name correct?' % obj_name)
+ elif operation == "delete":
+ # Search for the object
+ match = find_object(device, dev_group, obj_name, obj_type)
+
+ # If found, delete it
+ if match:
+ try:
+ match.delete()
+ except PanXapiError:
+ exc = get_exception()
+ module.fail_json(msg=exc.message)
+
+ module.exit_json(changed=True, msg='Object \'%s\' successfully deleted' % obj_name)
+ else:
+ module.fail_json(msg='Object \'%s\' not found. Is the name correct?' % obj_name)
+ elif operation == "add":
+ # Search for the object. Fail if found.
+ match = find_object(device, dev_group, obj_name, obj_type)
+ if match:
+ module.fail_json(msg='Object \'%s\' already exists. Use operation: \'update\' to change it.' % obj_name)
+ else:
+ try:
+ new_object = create_object(
+ addressobject=addressobject,
+ addressgroup=addressgroup,
+ serviceobject=serviceobject,
+ servicegroup=servicegroup,
+ address=address,
+ address_type=address_type,
+ static_value=static_value,
+ dynamic_value=dynamic_value,
+ protocol=protocol,
+ source_port=source_port,
+ destination_port=destination_port,
+ services=services,
+ description=description,
+ tag_name=tag_name,
+ color=color
+ )
+ changed = add_object(device, dev_group, new_object)
+ except PanXapiError:
+ exc = get_exception()
+ module.fail_json(msg=exc.message)
+ module.exit_json(changed=changed, msg='Object \'%s\' successfully added' % obj_name)
+ elif operation == "update":
+ # Search for the object. Update if found.
+ match = find_object(device, dev_group, obj_name, obj_type)
+ if match:
+ try:
+ new_object = create_object(
+ addressobject=addressobject,
+ addressgroup=addressgroup,
+ serviceobject=serviceobject,
+ servicegroup=servicegroup,
+ address=address,
+ address_type=address_type,
+ static_value=static_value,
+ dynamic_value=dynamic_value,
+ protocol=protocol,
+ source_port=source_port,
+ destination_port=destination_port,
+ services=services,
+ description=description,
+ tag_name=tag_name,
+ color=color
+ )
+ changed = add_object(device, dev_group, new_object)
+ except PanXapiError:
+ exc = get_exception()
+ module.fail_json(msg=exc.message)
+ module.exit_json(changed=changed, msg='Object \'%s\' successfully updated.' % obj_name)
+ else:
+ module.fail_json(msg='Object \'%s\' does not exist. Use operation: \'add\' to add it.' % obj_name)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/ansible/modules/network/panos/panos_service.py b/lib/ansible/modules/network/panos/panos_service.py
deleted file mode 100644
index 0c22785034..0000000000
--- a/lib/ansible/modules/network/panos/panos_service.py
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Ansible module to manage PaloAltoNetworks Firewall
-# (c) 2016, techbizdev <techbizdev@paloaltonetworks.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-DOCUMENTATION = '''
----
-module: panos_service
-short_description: create a service object
-description:
- - Create a service object. Service objects are fundamental representation of the applications given src/dst ports and protocol
-author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)"
-version_added: "2.3"
-requirements:
- - pan-python
-options:
- ip_address:
- description:
- - IP address (or hostname) of PAN-OS device
- required: true
- password:
- description:
- - password for authentication
- required: true
- username:
- description:
- - username for authentication
- required: false
- default: "admin"
- service_name:
- description:
- - name of the service
- required: true
- protocol:
- description:
- - protocol for the service, should be tcp or udp
- required: true
- port:
- description:
- - destination port
- required: true
- source_port:
- description:
- - source port
- required: false
- default: None
- commit:
- description:
- - commit if changed
- required: false
- default: true
-'''
-
-EXAMPLES = '''
-# Creates service for port 22
- - name: create SSH service
- panos_service:
- ip_address: "192.168.1.1"
- password: "admin"
- service_name: "service-tcp-22"
- protocol: "tcp"
- port: "22"
-'''
-
-RETURN='''
-# Default return values
-'''
-
-ANSIBLE_METADATA = {'metadata_version': '1.0',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import get_exception
-
-try:
- import pan.xapi
- from pan.xapi import PanXapiError
- HAS_LIB = True
-except ImportError:
- HAS_LIB = False
-
-_SERVICE_XPATH = "/config/devices/entry[@name='localhost.localdomain']" +\
- "/vsys/entry[@name='vsys1']" +\
- "/service/entry[@name='%s']"
-
-
-def service_exists(xapi, service_name):
- xapi.get(_SERVICE_XPATH % service_name)
- e = xapi.element_root.find('.//entry')
- if e is None:
- return False
- return True
-
-
-def add_service(xapi, module, service_name, protocol, port, source_port):
- if service_exists(xapi, service_name):
- return False
-
- exml = ['<protocol>']
- exml.append('<%s>' % protocol)
- exml.append('<port>%s</port>' % port)
- if source_port:
- exml.append('<source-port>%s</source-port>' % source_port)
- exml.append('</%s>' % protocol)
- exml.append('</protocol>')
-
- exml = ''.join(exml)
-
- xapi.set(xpath=_SERVICE_XPATH % service_name, element=exml)
-
- return True
-
-
-def main():
- argument_spec = dict(
- ip_address=dict(required=True),
- password=dict(required=True, no_log=True),
- username=dict(default='admin'),
- service_name=dict(required=True),
- protocol=dict(required=True, choices=['tcp', 'udp']),
- port=dict(required=True),
- source_port=dict(),
- commit=dict(type='bool', default=True)
- )
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
- if not HAS_LIB:
- module.fail_json(msg='pan-python is required for this module')
-
- ip_address = module.params["ip_address"]
- password = module.params["password"]
- username = module.params['username']
- service_name = module.params['service_name']
- protocol = module.params['protocol']
- port = module.params['port']
- source_port = module.params['source_port']
- commit = module.params['commit']
-
- xapi = pan.xapi.PanXapi(
- hostname=ip_address,
- api_username=username,
- api_password=password
- )
-
- try:
- changed = add_service(xapi, module,
- service_name,
- protocol,
- port,
- source_port)
- if changed and commit:
- xapi.commit(cmd="<commit></commit>", sync=True, interval=1)
- except PanXapiError:
- exc = get_exception()
- module.fail_json(msg=exc.message)
-
- module.exit_json(changed=changed, msg="okey dokey")
-
-if __name__ == '__main__':
- main()