2015-06-02 12:26:32 +02:00
|
|
|
#!/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/>.
|
|
|
|
|
|
|
|
DOCUMENTATION = '''
|
|
|
|
---
|
|
|
|
module: proxmox_template
|
|
|
|
short_description: management of OS templates in Proxmox VE cluster
|
|
|
|
description:
|
2015-06-02 18:29:19 +02:00
|
|
|
- allows you to upload/delete templates in Proxmox VE cluster
|
2015-06-02 12:26:32 +02:00
|
|
|
version_added: "2.0"
|
|
|
|
options:
|
|
|
|
api_host:
|
|
|
|
description:
|
|
|
|
- the host of the Proxmox VE cluster
|
|
|
|
required: true
|
|
|
|
api_user:
|
|
|
|
description:
|
|
|
|
- the user to authenticate with
|
|
|
|
required: true
|
|
|
|
api_password:
|
|
|
|
description:
|
|
|
|
- the password to authenticate with
|
|
|
|
- you can use PROXMOX_PASSWORD environment variable
|
|
|
|
default: null
|
|
|
|
required: false
|
2015-06-02 18:26:32 +02:00
|
|
|
validate_certs:
|
2015-06-02 12:26:32 +02:00
|
|
|
description:
|
|
|
|
- enable / disable https certificate verification
|
|
|
|
default: false
|
|
|
|
required: false
|
|
|
|
type: boolean
|
|
|
|
node:
|
|
|
|
description:
|
|
|
|
- Proxmox VE node, when you will operate with template
|
|
|
|
default: null
|
|
|
|
required: true
|
|
|
|
src:
|
|
|
|
description:
|
|
|
|
- path to uploaded file
|
|
|
|
- required only for C(state=present)
|
|
|
|
default: null
|
|
|
|
required: false
|
|
|
|
aliases: ['path']
|
|
|
|
template:
|
|
|
|
description:
|
|
|
|
- the template name
|
|
|
|
- required only for states C(absent), C(info)
|
|
|
|
default: null
|
|
|
|
required: false
|
|
|
|
content_type:
|
|
|
|
description:
|
|
|
|
- content type
|
|
|
|
- required only for C(state=present)
|
|
|
|
default: 'vztmpl'
|
|
|
|
required: false
|
|
|
|
choices: ['vztmpl', 'iso']
|
|
|
|
storage:
|
|
|
|
description:
|
|
|
|
- target storage
|
|
|
|
default: 'local'
|
|
|
|
required: false
|
|
|
|
type: string
|
|
|
|
timeout:
|
|
|
|
description:
|
|
|
|
- timeout for operations
|
2015-06-02 18:29:19 +02:00
|
|
|
default: 30
|
2015-06-02 12:26:32 +02:00
|
|
|
required: false
|
|
|
|
type: integer
|
|
|
|
force:
|
|
|
|
description:
|
|
|
|
- can be used only with C(state=present), exists template will be overwritten
|
|
|
|
default: false
|
|
|
|
required: false
|
|
|
|
type: boolean
|
|
|
|
state:
|
|
|
|
description:
|
|
|
|
- Indicate desired state of the template
|
2015-06-02 18:29:19 +02:00
|
|
|
choices: ['present', 'absent']
|
2015-06-02 12:26:32 +02:00
|
|
|
default: present
|
|
|
|
notes:
|
|
|
|
- Requires proxmoxer and requests modules on host. This modules can be installed with pip.
|
|
|
|
requirements: [ "proxmoxer", "requests" ]
|
|
|
|
author: "Sergei Antipov @UnderGreen"
|
|
|
|
'''
|
|
|
|
|
|
|
|
EXAMPLES = '''
|
|
|
|
# Upload new openvz template with minimal options
|
|
|
|
- proxmox_template: node='uk-mc02' api_user='root@pam' api_password='1q2w3e' api_host='node1' src='~/ubuntu-14.04-x86_64.tar.gz'
|
|
|
|
|
|
|
|
# Upload new openvz template with minimal options use environment PROXMOX_PASSWORD variable(you should export it before)
|
|
|
|
- proxmox_template: node='uk-mc02' api_user='root@pam' api_host='node1' src='~/ubuntu-14.04-x86_64.tar.gz'
|
|
|
|
|
|
|
|
# Upload new openvz template with all options and force overwrite
|
|
|
|
- proxmox_template: node='uk-mc02' api_user='root@pam' api_password='1q2w3e' api_host='node1' storage='local' content_type='vztmpl' src='~/ubuntu-14.04-x86_64.tar.gz' force=yes
|
|
|
|
|
|
|
|
# Delete template with minimal options
|
|
|
|
- proxmox_template: node='uk-mc02' api_user='root@pam' api_password='1q2w3e' api_host='node1' template='ubuntu-14.04-x86_64.tar.gz' state=absent
|
|
|
|
'''
|
|
|
|
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
|
|
|
|
try:
|
|
|
|
from proxmoxer import ProxmoxAPI
|
|
|
|
HAS_PROXMOXER = True
|
|
|
|
except ImportError:
|
|
|
|
HAS_PROXMOXER = False
|
|
|
|
|
|
|
|
def get_template(proxmox, node, storage, content_type, template):
|
|
|
|
return [ True for tmpl in proxmox.nodes(node).storage(storage).content.get()
|
|
|
|
if tmpl['volid'] == '%s:%s/%s' % (storage, content_type, template) ]
|
|
|
|
|
2015-06-02 14:21:36 +02:00
|
|
|
def upload_template(module, proxmox, api_host, node, storage, content_type, realpath, timeout):
|
2015-06-02 12:26:32 +02:00
|
|
|
taskid = proxmox.nodes(node).storage(storage).upload.post(content=content_type, filename=open(realpath))
|
|
|
|
while timeout:
|
2015-06-02 14:21:36 +02:00
|
|
|
task_status = proxmox.nodes(api_host.split('.')[0]).tasks(taskid).status.get()
|
2015-06-02 12:26:32 +02:00
|
|
|
if task_status['status'] == 'stopped' and task_status['exitstatus'] == 'OK':
|
|
|
|
return True
|
|
|
|
timeout = timeout - 1
|
|
|
|
if timeout == 0:
|
|
|
|
module.fail_json(msg='Reached timeout while waiting for uploading template. Last line in task before timeout: %s'
|
|
|
|
% proxmox.node(node).tasks(taskid).log.get()[:1])
|
|
|
|
|
|
|
|
time.sleep(1)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def delete_template(module, proxmox, node, storage, content_type, template, timeout):
|
|
|
|
volid = '%s:%s/%s' % (storage, content_type, template)
|
|
|
|
proxmox.nodes(node).storage(storage).content.delete(volid)
|
|
|
|
while timeout:
|
|
|
|
if not get_template(proxmox, node, storage, content_type, template):
|
|
|
|
return True
|
|
|
|
timeout = timeout - 1
|
|
|
|
if timeout == 0:
|
|
|
|
module.fail_json(msg='Reached timeout while waiting for deleting template.')
|
|
|
|
|
|
|
|
time.sleep(1)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def main():
|
|
|
|
module = AnsibleModule(
|
|
|
|
argument_spec = dict(
|
|
|
|
api_host = dict(required=True),
|
|
|
|
api_user = dict(required=True),
|
|
|
|
api_password = dict(no_log=True),
|
2015-12-21 23:39:20 +01:00
|
|
|
validate_certs = dict(type='bool', default='no'),
|
2015-06-02 12:26:32 +02:00
|
|
|
node = dict(),
|
|
|
|
src = dict(),
|
|
|
|
template = dict(),
|
|
|
|
content_type = dict(default='vztmpl', choices=['vztmpl','iso']),
|
|
|
|
storage = dict(default='local'),
|
2015-06-02 18:29:19 +02:00
|
|
|
timeout = dict(type='int', default=30),
|
2015-12-21 23:39:20 +01:00
|
|
|
force = dict(type='bool', default='no'),
|
2015-06-02 18:29:19 +02:00
|
|
|
state = dict(default='present', choices=['present', 'absent']),
|
2015-06-02 12:26:32 +02:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
if not HAS_PROXMOXER:
|
|
|
|
module.fail_json(msg='proxmoxer required for this module')
|
|
|
|
|
|
|
|
state = module.params['state']
|
|
|
|
api_user = module.params['api_user']
|
|
|
|
api_host = module.params['api_host']
|
|
|
|
api_password = module.params['api_password']
|
2015-06-02 18:26:32 +02:00
|
|
|
validate_certs = module.params['validate_certs']
|
2015-06-02 12:26:32 +02:00
|
|
|
node = module.params['node']
|
|
|
|
storage = module.params['storage']
|
|
|
|
timeout = module.params['timeout']
|
|
|
|
|
|
|
|
# If password not set get it from PROXMOX_PASSWORD env
|
|
|
|
if not api_password:
|
|
|
|
try:
|
|
|
|
api_password = os.environ['PROXMOX_PASSWORD']
|
|
|
|
except KeyError, e:
|
|
|
|
module.fail_json(msg='You should set api_password param or use PROXMOX_PASSWORD environment variable')
|
|
|
|
|
|
|
|
try:
|
2015-06-02 18:26:32 +02:00
|
|
|
proxmox = ProxmoxAPI(api_host, user=api_user, password=api_password, verify_ssl=validate_certs)
|
2015-06-02 12:26:32 +02:00
|
|
|
except Exception, e:
|
|
|
|
module.fail_json(msg='authorization on proxmox cluster failed with exception: %s' % e)
|
|
|
|
|
|
|
|
if state == 'present':
|
|
|
|
try:
|
|
|
|
content_type = module.params['content_type']
|
|
|
|
src = module.params['src']
|
|
|
|
|
|
|
|
from ansible import utils
|
|
|
|
realpath = utils.path_dwim(None, src)
|
|
|
|
template = os.path.basename(realpath)
|
|
|
|
if get_template(proxmox, node, storage, content_type, template) and not module.params['force']:
|
|
|
|
module.exit_json(changed=False, msg='template with volid=%s:%s/%s is already exists' % (storage, content_type, template))
|
|
|
|
elif not src:
|
|
|
|
module.fail_json(msg='src param to uploading template file is mandatory')
|
|
|
|
elif not (os.path.exists(realpath) and os.path.isfile(realpath)):
|
|
|
|
module.fail_json(msg='template file on path %s not exists' % realpath)
|
|
|
|
|
2015-06-02 14:21:36 +02:00
|
|
|
if upload_template(module, proxmox, api_host, node, storage, content_type, realpath, timeout):
|
2015-06-02 12:26:32 +02:00
|
|
|
module.exit_json(changed=True, msg='template with volid=%s:%s/%s uploaded' % (storage, content_type, template))
|
|
|
|
except Exception, e:
|
|
|
|
module.fail_json(msg="uploading of template %s failed with exception: %s" % ( template, e ))
|
|
|
|
|
|
|
|
elif state == 'absent':
|
|
|
|
try:
|
|
|
|
content_type = module.params['content_type']
|
|
|
|
template = module.params['template']
|
|
|
|
|
|
|
|
if not template:
|
|
|
|
module.fail_json(msg='template param is mandatory')
|
|
|
|
elif not get_template(proxmox, node, storage, content_type, template):
|
|
|
|
module.exit_json(changed=False, msg='template with volid=%s:%s/%s is already deleted' % (storage, content_type, template))
|
|
|
|
|
|
|
|
if delete_template(module, proxmox, node, storage, content_type, template, timeout):
|
|
|
|
module.exit_json(changed=True, msg='template with volid=%s:%s/%s deleted' % (storage, content_type, template))
|
|
|
|
except Exception, e:
|
|
|
|
module.fail_json(msg="deleting of template %s failed with exception: %s" % ( template, e ))
|
|
|
|
|
|
|
|
# import module snippets
|
|
|
|
from ansible.module_utils.basic import *
|
|
|
|
main()
|