Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fortimanager/fmgr_provisioning.py #35743

Merged
merged 13 commits into from
Aug 30, 2018
372 changes: 372 additions & 0 deletions lib/ansible/modules/network/fortimanager/fmgr_provisioning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,372 @@
#!/usr/bin/python
#
# 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/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_provisioning
version_added: "2.7"
author: Andrew Welsh
short_description: Provision devices via FortiMananger
description:
- Add model devices on the FortiManager using jsonrpc API and have them pre-configured,
so when central management is configured, the configuration is pushed down to the
registering devices

options:
adom:
description:
- The administrative domain (admon) the configuration belongs to
required: true
vdom:
description:
- The virtual domain (vdom) the configuration belongs to
host:
description:
- The FortiManager's Address.
required: true
username:
description:
- The username to log into the FortiManager
required: true
password:
description:
- The password associated with the username account.
required: false

policy_package:
description:
- The name of the policy package to be assigned to the device.
required: True
name:
description:
- The name of the device to be provisioned.
required: True
group:
description:
- The name of the device group the provisioned device can belong to.
required: False
serial:
description:
- The serial number of the device that will be provisioned.
required: True
platform:
description:
- The platform of the device, such as model number or VM.
required: True
description:
description:
- Description of the device to be provisioned.
required: False
os_version:
description:
- The Fortinet OS version to be used for the device, such as 5.0 or 6.0.
required: True
minor_release:
description:
- The minor release number such as 6.X.1, as X being the minor release.
required: False
patch_release:
description:
- The patch release number such as 6.0.X, as X being the patch release.
required: False
os_type:
description:
- The Fortinet OS type to be pushed to the device, such as 'FOS' for FortiOS.
required: True
'''

EXAMPLES = '''
- name: Create Model Device
hosts: FortiManager
connection: local
gather_facts: False

tasks:

- name: Create FGT1 Model Device
fmgr_provision:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
adom: "root"
vdom: "root"
policy_package: "default"
name: "FGT1"
group: "Ansible"
serial: "FGVM000000117994"
platform: "FortiGate-VM64"
description: "Provisioned by Ansible"
os_version: '6.0'
minor_release: 0
patch_release: 0
os_type: 'fos'


- name: Create FGT2 Model Device
fmgr_provision:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
adom: "root"
vdom: "root"
policy_package: "test_pp"
name: "FGT2"
group: "Ansible"
serial: "FGVM000000117992"
platform: "FortiGate-VM64"
description: "Provisioned by Ansible"
os_version: '5.0'
minor_release: 6
patch_release: 0
os_type: 'fos'

'''

RETURN = """
api_result:
description: full API response, includes status code and message
returned: always
type: string
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortimanager.fortimanager import AnsibleFortiManager

# check for pyFMG lib
try:
from pyFMG.fortimgr import FortiManager
HAS_PYFMGR = True
except ImportError:
HAS_PYFMGR = False


def dev_group_exists(fmg, dev_grp_name, adom):
datagram = {
'adom': adom,
'name': dev_grp_name,
}

url = '/dvmdb/adom/{adom}/group/{dev_grp_name}'.format(adom=adom, dev_grp_name=dev_grp_name)
response = fmg.get(url, datagram)
return response


def prov_template_exists(fmg, prov_template, adom, vdom):
datagram = {
'name': prov_template,
'adom': adom,
}

url = '/pm/devprof/adom/{adom}/devprof/{name}'.format(adom=adom, name=prov_template)
response = fmg.get(url, datagram)
return response


def create_model_device(fmg, name, serial, group, platform, os_version,
os_type, minor_release, patch_release=0, adom='root'):
datagram = {
'adom': adom,
'flags': ['create_task', 'nonblocking'],
'groups': [{'name': group, 'vdom': 'root'}],
'device': {
'mr': minor_release,
'name': name,
'sn': serial,
'mgmt_mode': 'fmg',
'device action': 'add_model',
'platform_str': platform,
'os_ver': os_version,
'os_type': os_type,
'patch': patch_release,
'desc': 'Provisioned by Ansible',
}
}

url = '/dvm/cmd/add/device'
response = fmg.execute(url, datagram)
return response


def update_flags(fmg, name):
datagram = {
'flags': ['is_model', 'linked_to_model']
}
url = 'dvmdb/device/{name}'.format(name=name)
response = fmg.update(url, datagram)
return response


def assign_provision_template(fmg, template, adom, target):
datagram = {
'name': template,
'type': 'devprof',
'description': 'Provisioned by Ansible',
'scope member': [{'name': target}]
}
url = "/pm/devprof/adom/{adom}".format(adom=adom)
response = fmg.update(url, datagram)
return response


def set_devprof_scope(self, provisioning_template, adom, provision_targets):
"""
GET the DevProf (check to see if exists)
"""
fields = dict()
targets = []
fields["name"] = provisioning_template
fields["type"] = "devprof"
fields["description"] = "CreatedByAnsible"

for target in provision_targets.strip().split(","):
# split the host on the space to get the mask out
new_target = {"name": target}
targets.append(new_target)

fields["scope member"] = targets

body = {"method": "set", "params": [{"url": "/pm/devprof/adom/{adom}".format(adom=adom),
"data": fields, "session": self.session}]}
response = self.make_request(body).json()
return response


def assign_dev_grp(fmg, grp_name, device_name, vdom, adom):
datagram = {
'name': device_name,
'vdom': vdom,
}
url = "/dvmdb/adom/{adom}/group/{grp_name}/object member".format(adom=adom, grp_name=grp_name)
response = fmg.set(url, datagram)
return response


def update_install_target(fmg, device, pp='default', vdom='root', adom='root'):
datagram = {
'scope member': [{'name': device, 'vdom': vdom}],
'type': 'pkg'
}
url = '/pm/pkg/adom/{adom}/{pkg_name}'.format(adom=adom, pkg_name=pp)
response = fmg.update(url, datagram)
return response


def install_pp(fmg, device, pp='default', vdom='root', adom='root'):
datagram = {
'adom': adom,
'flags': 'nonblocking',
'pkg': pp,
'scope': [{'name': device, 'vdom': vdom}],
}
url = 'securityconsole/install/package'
response = fmg.execute(url, datagram)
return response


def main():

argument_spec = dict(
adom=dict(required=False, type="str"),
vdom=dict(required=False, type="str"),
host=dict(required=True, type="str"),
password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True),

policy_package=dict(required=False, type="str"),
name=dict(required=False, type="str"),
group=dict(required=False, type="str"),
serial=dict(required=True, type="str"),
platform=dict(required=True, type="str"),
description=dict(required=False, type="str"),
os_version=dict(required=True, type="str"),
minor_release=dict(required=False, type="str"),
patch_release=dict(required=False, type="str"),
os_type=dict(required=False, type="str"),

)

module = AnsibleModule(argument_spec, supports_check_mode=True, )

# check if params are set
if module.params["host"] is None or module.params["username"] is None:
module.fail_json(msg="Host and username are required for connection")

# check if login failed
fmg = AnsibleFortiManager(module, module.params["host"], module.params["username"], module.params["password"])
response = fmg.login()

if "FortiManager instance connnected" not in str(response):
module.fail_json(msg="Connection to FortiManager Failed")
else:

if module.params["policy_package"] is None:
module.params["policy_package"] = 'default'
if module.params["adom"] is None:
module.params["adom"] = 'root'
if module.params["vdom"] is None:
module.params["vdom"] = 'root'
if module.params["platform"] is None:
module.params["platform"] = 'FortiGate-VM64'
if module.params["os_type"] is None:
module.params["os_type"] = 'fos'

results = create_model_device(fmg,
module.params["name"],
module.params["serial"],
module.params["group"],
module.params["platform"],
module.params["os_ver"],
module.params["os_type"],
module.params["minor_release"],
module.params["patch_release"],
module.params["adom"])
if not results[0] == 0:
module.fail_json(msg="Create model failed", **results)

results = update_flags(fmg, module.params["name"])
if not results[0] == 0:
module.fail_json(msg="Update device flags failed", **results)

# results = assign_dev_grp(fmg, 'Ansible', 'FGVM000000117992', 'root', 'root')
# if not results[0] == 0:
# module.fail_json(msg="Setting device group failed", **results)

results = update_install_target(fmg, module.params["name"], module.params["policy_package"])
if not results[0] == 0:
module.fail_json(msg="Adding device target to package failed", **results)

results = install_pp(fmg, module.params["name"], module.params["policy_package"])
if not results[0] == 0:
module.fail_json(msg="Installing policy package failed", **results)

fmg.logout()

# results is returned as a tuple
return module.exit_json(**results[1])


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion test/runner/requirements/units.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ f5-icontrol-rest ; python_version >= '2.7'
deepdiff

# requirement for Fortinet specific modules
pyfmg
pyFMG

# requirement for aci_rest module
xmljson