-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Module to manage template in content library from virtual machine. Signed-off-by: Ondra Machacek <[email protected]>
- Loading branch information
1 parent
6b28899
commit c0723a2
Showing
8 changed files
with
432 additions
and
300 deletions.
There are no files selected for viewing
2 changes: 2 additions & 0 deletions
2
changelogs/fragments/23-new-module-content-create-template.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
minor_changes: | ||
- content_template - Add new module to manage templates in content library |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
|
||
# Copyright: (c) 2019, Ansible Project | ||
# Copyright: (c) 2019, Pavan Bidkar <[email protected]> | ||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
from __future__ import absolute_import, division, print_function | ||
__metaclass__ = type | ||
|
||
|
||
DOCUMENTATION = r''' | ||
--- | ||
module: content_template | ||
short_description: Manage template in content library from virtual machine. | ||
description: | ||
- Module to manage template in content library from virtual machine. | ||
- Content Library feature is introduced in vSphere 6.0 version. | ||
- This module does not work with vSphere version older than 67U2. | ||
author: | ||
- Ansible Cloud Team (@ansible-collections) | ||
requirements: | ||
- vSphere Automation SDK | ||
options: | ||
template: | ||
description: | ||
- The name of template to manage. | ||
type: str | ||
required: true | ||
library: | ||
description: | ||
- The name of the content library where the template will be created. | ||
type: str | ||
required: true | ||
vm_name: | ||
description: | ||
- The name of the VM to be used to create template. | ||
type: str | ||
required: true | ||
host: | ||
description: | ||
- Host onto which the virtual machine template should be placed. | ||
- If O(host) and O(resource_pool) are both specified, O(resource_pool) | ||
must belong to O(host). | ||
- If O(host) and O(cluster) are both specified, O(host) must be a member of O(cluster). | ||
- This attribute was added in vSphere API 6.8. | ||
type: str | ||
resource_pool: | ||
description: | ||
- Resource pool into which the virtual machine template should be placed. | ||
- This attribute was added in vSphere API 6.8. | ||
- If not specified, the system will attempt to choose a suitable resource pool | ||
for the virtual machine template; if a resource pool cannot be | ||
chosen, the library item creation operation will fail. | ||
type: str | ||
cluster: | ||
description: | ||
- Cluster onto which the virtual machine template should be placed. | ||
- If O(cluster) and O(resource_pool) are both specified, | ||
O(resource_pool) must belong to O(cluster). | ||
- If O(cluster) and O(host) are both specified, O(host) must be a member of O(cluster). | ||
- This attribute was added in vSphere API 6.8. | ||
type: str | ||
folder: | ||
description: | ||
- Virtual machine folder into which the virtual machine template should be placed. | ||
- This attribute was added in vSphere API 6.8. | ||
- If not specified, the virtual machine template will be placed in the same | ||
folder as the source virtual machine. | ||
type: str | ||
state: | ||
description: | ||
- State of the template in content library. | ||
- If C(present), the template will be created in content library. | ||
- If C(absent), the template will be deleted from content library. | ||
type: str | ||
default: present | ||
choices: | ||
- present | ||
- absent | ||
extends_documentation_fragment: | ||
- vmware.vmware.vmware_rest_client.documentation | ||
''' | ||
|
||
EXAMPLES = r''' | ||
- name: Create template in content library from Virtual Machine | ||
vmware.vmware.content_template: | ||
hostname: '{{ vcenter_hostname }}' | ||
username: '{{ vcenter_username }}' | ||
password: '{{ vcenter_password }}' | ||
template: mytemplate | ||
library: mylibrary | ||
vm_name: myvm | ||
host: myhost | ||
''' | ||
|
||
RETURN = r''' | ||
template_info: | ||
description: Template creation message and template_id | ||
returned: on success | ||
type: dict | ||
sample: { | ||
"msg": "Template 'mytemplate'.", | ||
"template_id": "template-1009" | ||
} | ||
''' | ||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
from ansible_collections.vmware.vmware.plugins.module_utils.vmware_rest_client import VmwareRestClient | ||
from ansible.module_utils._text import to_native | ||
|
||
HAS_VAUTOMATION_PYTHON_SDK = False | ||
try: | ||
from com.vmware.vcenter.vm_template_client import LibraryItems | ||
from com.vmware.vapi.std.errors_client import Error | ||
HAS_VAUTOMATION_PYTHON_SDK = True | ||
except ImportError: | ||
pass | ||
|
||
|
||
class VmwareContentTemplate(VmwareRestClient): | ||
def __init__(self, module): | ||
"""Constructor.""" | ||
super(VmwareContentTemplate, self).__init__(module) | ||
|
||
# Initialize member variables | ||
self.module = module | ||
self._template_service = self.api_client.vcenter.vm_template.LibraryItems | ||
self.result = {'changed': False} | ||
|
||
# Get parameters | ||
self.template = self.params.get('template') | ||
self.host = self.params.get('host') | ||
self.cluster = self.params.get('cluster') | ||
self.resource_pool = self.params.get('resource_pool') | ||
self.library = self.params.get('library') | ||
self.folder = self.params.get('folder') | ||
self.vm_name = self.params.get('vm_name') | ||
|
||
def create_template_from_vm(self): | ||
template = self.get_library_item_from_content_library_name(self.template, self.library) | ||
if template: | ||
self.result['template_info'] = dict( | ||
msg="Template '%s' already exists." % self.template, | ||
template_id=template, | ||
) | ||
return | ||
|
||
# Create template placement specs | ||
placement_spec = LibraryItems.CreatePlacementSpec() | ||
placement_spec.host = self.get_host_by_name(self.host) | ||
placement_spec.resource_pool = self.get_resource_pool_by_name(self.resource_pool) | ||
placement_spec.cluster = self.get_cluster_by_name(self.cluster) | ||
placement_spec.folder = self.get_folder_by_name(self.folder) | ||
create_spec = LibraryItems.CreateSpec( | ||
name=self.template, | ||
placement=placement_spec, | ||
library=self.get_library_by_name(self.library), | ||
source_vm=self.get_vm_by_name(self.vm_name), | ||
) | ||
template_id = '' | ||
try: | ||
template_id = self._template_service.create(create_spec) | ||
except Error as error: | ||
self.module.fail_json(msg="%s" % self.get_error_message(error)) | ||
except Exception as err: | ||
self.module.fail_json(msg="%s" % to_native(err)) | ||
|
||
if not template_id: | ||
self.result['template_info'] = dict( | ||
msg="Template creation failed", | ||
) | ||
self.module.fail_json(**self.result) | ||
self.result['changed'] = True | ||
self.result['template_info'] = dict( | ||
msg="Template '%s'." % self.template, | ||
template_id=template_id, | ||
) | ||
|
||
def delete_template(self): | ||
template = self.get_library_item_from_content_library_name(self.template, self.library) | ||
if template is None: | ||
self.result['template_info'] = dict( | ||
msg="Template '%s' doesn't exists." % self.template, | ||
) | ||
return | ||
|
||
try: | ||
self.api_client.content.library.Item.delete(template) | ||
except Exception as err: | ||
self.module.fail_json(msg="%s" % to_native(err)) | ||
|
||
self.result['changed'] = True | ||
self.result['template_info'] = dict( | ||
msg="Template '%s' has been deleted." % self.template, | ||
template_id=template, | ||
) | ||
|
||
def main(): | ||
argument_spec = VmwareRestClient.vmware_client_argument_spec() | ||
argument_spec.update( | ||
template=dict(type='str', required=True), | ||
library=dict(type='str', required=True), | ||
vm_name=dict(type='str', required=True), | ||
host=dict(type='str'), | ||
cluster=dict(type='str'), | ||
resource_pool=dict(type='str'), | ||
folder=dict(type='str'), | ||
state=dict(type='str', default='present', choices=['present', 'absent']), | ||
) | ||
module = AnsibleModule( | ||
argument_spec=argument_spec, | ||
supports_check_mode=True, | ||
required_one_of=[('host', 'resource_pool', 'cluster')], | ||
) | ||
|
||
result = {'failed': False, 'changed': False} | ||
vmware_contentlib = VmwareContentTemplate(module) | ||
if module.check_mode: | ||
result.update( | ||
vm_name=module.params['name'], | ||
changed=True, | ||
desired_operation='{} template'.format(module.params.get('state')), | ||
) | ||
module.exit_json(**result) | ||
if module.params.get('state') == 'present': | ||
vmware_contentlib.create_template_from_vm() | ||
else: | ||
vmware_contentlib.delete_template() | ||
module.exit_json(**vmware_contentlib.result) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
74 changes: 74 additions & 0 deletions
74
tests/integration/targets/content_create_template/mock.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
[ | ||
{ | ||
"httpRequest": { | ||
"method": "POST", | ||
"path": "/rest/com/vmware/cis/session" | ||
}, | ||
"httpResponse": { | ||
"statusCode": 200, | ||
"body": {"value": "72300ca9ff16c5743fa0a6328c8570ce"} | ||
} | ||
}, | ||
{ | ||
"httpRequest": { | ||
"method": "POST", | ||
"path": "/api" | ||
}, | ||
"httpResponse": { | ||
"statusCode": 200, | ||
"headers": { | ||
"Content-Type": "application/json" | ||
}, | ||
"body": {"jsonrpc": "2.0", "result": {"output": 0}, "id": "0"} | ||
} | ||
}, | ||
{ | ||
"httpRequest": { | ||
"method": "POST", | ||
"path": "/api", | ||
"body": { | ||
"type": "JSON", | ||
"matchType": "PARTIAL", | ||
"json": "{\"params\":{\"serviceId\":\"com.vmware.content.library\",\"operationId\":\"find\"}}" | ||
} | ||
}, | ||
"httpResponseTemplate": { | ||
"template": "{\"statusCode\": 200, \"headers\": {\"Content-type\": \"application/json\"}, \"body\": {\"jsonrpc\": \"2.0\", \"result\": {\"output\":[\"11d399c9-92f6-49cd-abaf-ad7e4fdceb49\"]}, 'id': '${json.parse($!request.body)['id']}'}}", | ||
"templateType": "VELOCITY" | ||
}, | ||
"priority": 1 | ||
}, | ||
{ | ||
"httpRequest": { | ||
"method": "POST", | ||
"path": "/api", | ||
"body": { | ||
"type": "JSON", | ||
"matchType": "PARTIAL", | ||
"json": "{\"params\":{\"serviceId\":\"com.vmware.content.library.item\",\"operationId\":\"find\"}}" | ||
} | ||
}, | ||
"httpResponseTemplate": { | ||
"template": "{\"statusCode\": 200, \"headers\": {\"Content-type\": \"application/json\"}, \"body\": {\"jsonrpc\": \"2.0\", \"result\": {\"output\":[\"11d399c9-92f6-49cd-abaf-ad7e4fdceb49\"]}, 'id': '${json.parse($!request.body)['id']}'}}", | ||
"templateType": "VELOCITY" | ||
}, | ||
"priority": 1 | ||
}, | ||
{ | ||
"httpRequest": { | ||
"method": "POST", | ||
"path": "/api", | ||
"body": { | ||
"params" : { | ||
"serviceId" : "com.vmware.cis.session", | ||
"operationId" : "delete" | ||
} | ||
} | ||
}, | ||
"httpResponseTemplate": { | ||
"template": "{\"statusCode\": 200, \"headers\": {\"Content-type\": \"application/json\"}, \"body\": {\"jsonrpc\": \"2.0\", \"result\": {\"output\": 0}, \"id\": '${json.parse($!request.body)['id']}'}}", | ||
"templateType": "VELOCITY" | ||
}, | ||
"priority": 1 | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
- hosts: localhost | ||
gather_facts: no | ||
vars_files: | ||
- vars.yml | ||
tasks: | ||
- name: Prepare rest | ||
ansible.builtin.import_role: | ||
name: prepare_rest | ||
|
||
- name: Import content_create_template role | ||
ansible.builtin.import_role: | ||
name: content_create_template |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env bash | ||
source ../init.sh | ||
exec ansible-playbook run.yml |
19 changes: 19 additions & 0 deletions
19
tests/integration/targets/content_create_template/tasks/main.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
--- | ||
- name: Create template from vm in content library | ||
vmware.vmware.content_create_template: | ||
validate_certs: false | ||
hostname: "{{ vcenter_hostname }}" | ||
username: "{{ vcenter_username }}" | ||
password: "{{ vcenter_password }}" | ||
port: "{{ vcenter_port }}" | ||
template: mytemplate | ||
library: templates | ||
vm_name: test | ||
host: 1.2.3.4. | ||
register: __res | ||
|
||
- name: Assert values | ||
ansible.builtin.assert: | ||
that: | ||
- __res.changed == False | ||
- __res.template_create_info.msg == "Template 'mytemplate' already exists." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
vcenter_hostname: "127.0.0.1" | ||
vcenter_username: "user" | ||
vcenter_password: "pass" | ||
vcenter_port: 1080 | ||
|
||
mock_file: "content_create_template" |