diff --git a/lib/ansible/modules/network/fortimanager/fmgr_provisioning.py b/lib/ansible/modules/network/fortimanager/fmgr_provisioning.py
new file mode 100644
index 00000000000..8231527d33c
--- /dev/null
+++ b/lib/ansible/modules/network/fortimanager/fmgr_provisioning.py
@@ -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 .
+#
+
+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()
diff --git a/test/runner/requirements/units.txt b/test/runner/requirements/units.txt
index d412d4383ea..83f89d76dee 100644
--- a/test/runner/requirements/units.txt
+++ b/test/runner/requirements/units.txt
@@ -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
diff --git a/test/units/modules/network/fortimanager/test_fmgr_provisioning.py b/test/units/modules/network/fortimanager/test_fmgr_provisioning.py
new file mode 100644
index 00000000000..b774bb223cf
--- /dev/null
+++ b/test/units/modules/network/fortimanager/test_fmgr_provisioning.py
@@ -0,0 +1,63 @@
+# (c) 2016 Red Hat Inc.
+#
+# 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 .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from nose.plugins.skip import SkipTest
+
+try:
+ from ansible.modules.network.fortimanager import fmgr_provisioning
+ from .fortimanager_module import TestFortimanagerModule
+ from units.modules.utils import set_module_args
+except ImportError:
+ raise SkipTest("Could not load required modules for testing")
+
+try:
+ from pyFMG.fortimgr import FortiManager
+except ImportError:
+ raise SkipTest("FortiManager tests require pyFMG package")
+
+
+class TestFmgrProvisioningModule(TestFortimanagerModule):
+
+ module = fmgr_provisioning
+
+ def test_fmg_script_fail_connect(self):
+ set_module_args(dict(host='1.1.1.1', username='admin', password='admin', adom='root',
+ vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992',
+ platform='FortiGate-VM64', os_version='5.0', minor_release='6',
+ patch_release='0', os_type='fos'))
+ result = self.execute_module(failed=True)
+ self.assertEqual(result['msg'], 'Connection to FortiManager Failed')
+
+ def test_fmg_script_login_fail_host(self):
+ set_module_args(dict(username='admin', password='admin', adom='root',
+ vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992',
+ platform='FortiGate-VM64', os_version='5.0', minor_release='6',
+ patch_release='0', os_type='fos'))
+ result = self.execute_module(failed=True)
+ self.assertEqual(result['msg'], 'missing required arguments: host')
+
+ def test_fmg_script_login_fail_username(self):
+ set_module_args(dict(host='1.1.1.1', password='admin', adom='root',
+ vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992',
+ platform='FortiGate-VM64', os_version='5.0', minor_release='6',
+ patch_release='0', os_type='fos'))
+ result = self.execute_module(failed=True)
+ self.assertEqual(result['msg'], 'Host and username are required for connection')