mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-08-03 04:34:24 -07:00
Added xen_orchestra module
This commit is contained in:
parent
1eba0958a8
commit
1e12684eb9
1 changed files with 312 additions and 232 deletions
|
@ -8,72 +8,97 @@ __metaclass__ = type
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
name: xen_orchestra
|
name: xen_orchestra
|
||||||
short_description: Xen Orchestra inventory source
|
short_description: Management of instances on Xen Orchestra
|
||||||
version_added: 4.1.0
|
version_added: 4.1.0
|
||||||
author:
|
author:
|
||||||
- Dom Del Nano (@ddelnano) <ddelnano@gmail.com>
|
- Samori Gorse (@shinuza) <samorigorse@gmail.com>
|
||||||
- Samori Gorse (@shinuza) <samorigorse@gmail.com>
|
|
||||||
requirements:
|
requirements:
|
||||||
- websocket-client >= 1.0.0
|
- websocket-client >= 1.0.0
|
||||||
description:
|
description:
|
||||||
- Get inventory hosts from a Xen Orchestra deployment.
|
- Allows you to create/delete/restart/stop instances on Xen Orchestra
|
||||||
- 'Uses a configuration file as an inventory source, it must end in C(.xen_orchestra.yml) or C(.xen_orchestra.yaml).'
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- constructed
|
|
||||||
- inventory_cache
|
|
||||||
options:
|
options:
|
||||||
plugin:
|
api_host:
|
||||||
description: The name of this plugin, it should always be set to V(community.general.xen_orchestra) for this plugin to recognize it as its own.
|
description: API host to XOA API.
|
||||||
required: true
|
type: str
|
||||||
choices: ['community.general.xen_orchestra']
|
user:
|
||||||
type: str
|
description: Xen Orchestra user.
|
||||||
api_host:
|
required: true
|
||||||
description:
|
type: str
|
||||||
- API host to XOA API.
|
password:
|
||||||
- If the value is not specified in the inventory configuration, the value of environment variable E(ANSIBLE_XO_HOST) will be used instead.
|
description: Xen Orchestra password.
|
||||||
type: str
|
required: true
|
||||||
env:
|
type: str
|
||||||
- name: ANSIBLE_XO_HOST
|
validate_certs:
|
||||||
user:
|
description: Verify TLS certificate if using HTTPS.
|
||||||
description:
|
type: boolean
|
||||||
- Xen Orchestra user.
|
default: true
|
||||||
- If the value is not specified in the inventory configuration, the value of environment variable E(ANSIBLE_XO_USER) will be used instead.
|
use_ssl:
|
||||||
required: true
|
description: Use wss when connecting to the Xen Orchestra API
|
||||||
type: str
|
type: boolean
|
||||||
env:
|
default: true
|
||||||
- name: ANSIBLE_XO_USER
|
state:
|
||||||
password:
|
description: State in which the Virtual Machine should be
|
||||||
description:
|
choices: ['present', 'started', 'absent', 'stopped', 'restarted']
|
||||||
- Xen Orchestra password.
|
default: present
|
||||||
- If the value is not specified in the inventory configuration, the value of environment variable E(ANSIBLE_XO_PASSWORD) will be used instead.
|
label:
|
||||||
required: true
|
description: Label of the Virtual Machine to create, can be used when O(state=present)
|
||||||
type: str
|
type: boolean
|
||||||
env:
|
default: false
|
||||||
- name: ANSIBLE_XO_PASSWORD
|
description:
|
||||||
validate_certs:
|
description: Description of the Virtual Machine to create, can be used when O(state=present)
|
||||||
description: Verify TLS certificate if using HTTPS.
|
type: boolean
|
||||||
type: boolean
|
default: false
|
||||||
default: true
|
boot_after_create:
|
||||||
use_ssl:
|
description: Boot Virtual Machine after creation, can be used when O(state=present)
|
||||||
description: Use wss when connecting to the Xen Orchestra API
|
type: boolean
|
||||||
type: boolean
|
default: false
|
||||||
default: true
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = r'''
|
||||||
# file must be named xen_orchestra.yaml or xen_orchestra.yml
|
- name: Create a new virtual machine
|
||||||
plugin: community.general.xen_orchestra
|
community.general.xen_orchestra:
|
||||||
api_host: 192.168.1.255
|
api_host: xen-orchestra.lab
|
||||||
user: xo
|
user: user
|
||||||
password: xo_pwd
|
password: passw0rd
|
||||||
validate_certs: true
|
validate_certs: no
|
||||||
use_ssl: true
|
state: present
|
||||||
groups:
|
template: 355ee47d-ff4c-4924-3db2-fd86ae629676-a3d70e4d-c5ac-4dfb-999b-30a0a7efe546
|
||||||
kube_nodes: "'kube_node' in tags"
|
label: This is a test from ansible
|
||||||
compose:
|
description: This is a test from ansible
|
||||||
ansible_port: 2222
|
boot_after_create: no
|
||||||
|
|
||||||
|
- name: Start an existing virtual machine
|
||||||
|
community.general.xen_orchestra:
|
||||||
|
api_host: xen-orchestra.lab
|
||||||
|
user: user
|
||||||
|
password: passw0rd
|
||||||
|
validate_certs: no
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Stop an existing virtual machine
|
||||||
|
community.general.xen_orchestra:
|
||||||
|
api_host: xen-orchestra.lab
|
||||||
|
user: user
|
||||||
|
password: passw0rd
|
||||||
|
validate_certs: no
|
||||||
|
state: stop
|
||||||
|
|
||||||
|
- name: Restart an existing virtual machine
|
||||||
|
community.general.xen_orchestra:
|
||||||
|
api_host: xen-orchestra.lab
|
||||||
|
user: user
|
||||||
|
password: passw0rd
|
||||||
|
validate_certs: no
|
||||||
|
state: stopped
|
||||||
|
|
||||||
|
- name: Delete a virtual machine
|
||||||
|
community.general.xen_orchestra:
|
||||||
|
api_host: xen-orchestra.lab
|
||||||
|
user: user
|
||||||
|
password: passw0rd
|
||||||
|
validate_certs: no
|
||||||
|
state: absent
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -96,18 +121,8 @@ try:
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
HAS_WEBSOCKET = False
|
HAS_WEBSOCKET = False
|
||||||
|
|
||||||
|
OBJECT_NOT_FOUND = 1
|
||||||
HALTED = 'Halted'
|
VM_STATE_ERROR = 13
|
||||||
PAUSED = 'Paused'
|
|
||||||
RUNNING = 'Running'
|
|
||||||
SUSPENDED = 'Suspended'
|
|
||||||
POWER_STATES = [RUNNING, HALTED, SUSPENDED, PAUSED]
|
|
||||||
HOST_GROUP = 'xo_hosts'
|
|
||||||
POOL_GROUP = 'xo_pools'
|
|
||||||
|
|
||||||
|
|
||||||
def clean_group_name(label):
|
|
||||||
return label.lower().replace(' ', '-').replace('-', '_')
|
|
||||||
|
|
||||||
|
|
||||||
class XenOrchestra(object):
|
class XenOrchestra(object):
|
||||||
|
@ -115,7 +130,7 @@ class XenOrchestra(object):
|
||||||
|
|
||||||
NAME = 'community.general.xen_orchestra'
|
NAME = 'community.general.xen_orchestra'
|
||||||
CALL_TIMEOUT = 100
|
CALL_TIMEOUT = 100
|
||||||
"""Number of 1/10ths of a second to wait before method call times out."""
|
'''Number of 1/10ths of a second to wait before method call times out.'''
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
|
@ -124,8 +139,8 @@ class XenOrchestra(object):
|
||||||
self.con = None
|
self.con = None
|
||||||
self.module = module
|
self.module = module
|
||||||
|
|
||||||
self.create_connection(module['api_host'])
|
self.create_connection(module.params['api_host'])
|
||||||
self.login(module['user'], module['password'])
|
self.login(module.params['user'], module.params['password'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pointer(self):
|
def pointer(self):
|
||||||
|
@ -133,8 +148,8 @@ class XenOrchestra(object):
|
||||||
return self.counter
|
return self.counter
|
||||||
|
|
||||||
def create_connection(self, xoa_api_host):
|
def create_connection(self, xoa_api_host):
|
||||||
validate_certs = self.module['validate_certs']
|
validate_certs = self.module.params['validate_certs']
|
||||||
use_ssl = self.module['use_ssl']
|
use_ssl = self.module.params['use_ssl']
|
||||||
proto = 'wss' if use_ssl else 'ws'
|
proto = 'wss' if use_ssl else 'ws'
|
||||||
|
|
||||||
sslopt = None if validate_certs else {'cert_reqs': ssl.CERT_NONE}
|
sslopt = None if validate_certs else {'cert_reqs': ssl.CERT_NONE}
|
||||||
|
@ -142,7 +157,7 @@ class XenOrchestra(object):
|
||||||
'{0}://{1}/api/'.format(proto, xoa_api_host), sslopt=sslopt)
|
'{0}://{1}/api/'.format(proto, xoa_api_host), sslopt=sslopt)
|
||||||
|
|
||||||
def call(self, method, params):
|
def call(self, method, params):
|
||||||
"""Calls a method on the XO server with the provided parameters."""
|
'''Calls a method on the XO server with the provided parameters.'''
|
||||||
id = self.pointer
|
id = self.pointer
|
||||||
self.conn.send(json.dumps({
|
self.conn.send(json.dumps({
|
||||||
'id': id,
|
'id': id,
|
||||||
|
@ -169,15 +184,48 @@ class XenOrchestra(object):
|
||||||
})
|
})
|
||||||
|
|
||||||
if 'error' in answer:
|
if 'error' in answer:
|
||||||
raise AnsibleError(
|
raise self.module.fail_json(
|
||||||
'Could not connect: {0}'.format(answer['error']))
|
'Could not connect: {0}'.format(answer['error']))
|
||||||
|
|
||||||
def stop_vm(self, vm_uid):
|
return answer['result']
|
||||||
answer = self.call('vm.stop', {'id': vm_uid})
|
|
||||||
|
def create_vm(self):
|
||||||
|
params = {
|
||||||
|
'template': self.module.params['template'],
|
||||||
|
'name_label': self.module.params['label'],
|
||||||
|
'bootAfterCreate': self.module.params.get('boot_after_create', False)
|
||||||
|
}
|
||||||
|
|
||||||
|
description = self.module.params.get('description')
|
||||||
|
if description:
|
||||||
|
params['name_description'] = description
|
||||||
|
|
||||||
|
answer = self.call('vm.create', params)
|
||||||
|
|
||||||
if 'error' in answer:
|
if 'error' in answer:
|
||||||
raise AnsibleError(
|
raise self.module.fail_json(
|
||||||
'Could not request: {0}'.format(answer['error']))
|
'Could not create vm: {0}'.format(answer['error']))
|
||||||
|
|
||||||
|
return answer['result']
|
||||||
|
|
||||||
|
def restart_vm(self, vm_uid):
|
||||||
|
answer = self.call('vm.restart', {'id': vm_uid, 'force': True })
|
||||||
|
|
||||||
|
if 'error' in answer:
|
||||||
|
raise self.module.fail_json(
|
||||||
|
'Could not restart vm: {0}'.format(answer['error']))
|
||||||
|
|
||||||
|
return answer['result']
|
||||||
|
|
||||||
|
def stop_vm(self, vm_uid):
|
||||||
|
answer = self.call('vm.stop', {'id': vm_uid, 'force': True})
|
||||||
|
|
||||||
|
if 'error' in answer:
|
||||||
|
# VM is not paused, suspended or running
|
||||||
|
if answer['error']['code'] == VM_STATE_ERROR:
|
||||||
|
return False
|
||||||
|
raise self.module.fail_json(
|
||||||
|
'Could not stop vm: {0}'.format(answer['error']))
|
||||||
|
|
||||||
return answer['result']
|
return answer['result']
|
||||||
|
|
||||||
|
@ -185,22 +233,30 @@ class XenOrchestra(object):
|
||||||
answer = self.call('vm.start', {'id': vm_uid})
|
answer = self.call('vm.start', {'id': vm_uid})
|
||||||
|
|
||||||
if 'error' in answer:
|
if 'error' in answer:
|
||||||
raise AnsibleError(
|
# VM is already started, nothing to do
|
||||||
'Could not request: {0}'.format(answer['error']))
|
if answer['error']['code'] == VM_STATE_ERROR:
|
||||||
|
return False
|
||||||
|
raise self.module.fail_json(
|
||||||
|
'Could not start vm: {0}'.format(answer['error']))
|
||||||
|
|
||||||
return answer['result']
|
return answer['result']
|
||||||
|
|
||||||
def get_object(self, name):
|
def delete_vm(self, vm_uid):
|
||||||
answer = self.call('xo.getAllObjects', {'filter': {'type': name}})
|
answer = self.call('vm.delete', {'id': vm_uid})
|
||||||
|
|
||||||
if 'error' in answer:
|
if 'error' in answer:
|
||||||
raise AnsibleError(
|
if answer['error']['code'] == OBJECT_NOT_FOUND:
|
||||||
'Could not request: {0}'.format(answer['error']))
|
return False
|
||||||
|
raise self.module.fail_json(
|
||||||
|
'Could not delete vm: {0}'.format(answer['error']))
|
||||||
|
|
||||||
return answer['result']
|
return answer['result']
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
if not HAS_WEBSOCKET:
|
||||||
|
raise AnsibleError('This module requires websocket-client 1.0.0 or higher: '
|
||||||
|
'https://github.com/websocket-client/websocket-client.')
|
||||||
|
|
||||||
module_args = dict(
|
module_args = dict(
|
||||||
api_host=dict(type='str', required=True),
|
api_host=dict(type='str', required=True),
|
||||||
user=dict(type='str', required=True),
|
user=dict(type='str', required=True),
|
||||||
|
@ -208,25 +264,49 @@ def main():
|
||||||
validate_certs=dict(type='bool', default=True),
|
validate_certs=dict(type='bool', default=True),
|
||||||
use_ssl=dict(type='bool', default=True),
|
use_ssl=dict(type='bool', default=True),
|
||||||
vm_uid=dict(type='str'),
|
vm_uid=dict(type='str'),
|
||||||
state=dict(default='present', choices=['absent', 'stopped', 'started', 'restarted']),
|
template=dict(type='str'),
|
||||||
|
label=dict(type='str'),
|
||||||
|
description=dict(type='str'),
|
||||||
|
boot_after_create=dict(type='bool', default=False),
|
||||||
|
state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted']),
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
xen_orchestra = XenOrchestra()
|
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=module_args,
|
argument_spec=module_args,
|
||||||
required_one_of=[('api_password', 'api_token_id')],
|
required_if=[
|
||||||
|
('state', 'present', ['template', 'label']),
|
||||||
|
('state', 'absent', ('vm_uid')),
|
||||||
|
('state', 'started', ('vm_uid')),
|
||||||
|
('state', 'restarted', ('vm_uid')),
|
||||||
|
('state', 'stopped', ('vm_uid')),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
xen_orchestra = XenOrchestra(module)
|
||||||
|
|
||||||
state = module.params['state']
|
state = module.params['state']
|
||||||
vm_uid = module.params['vm_uid']
|
vm_uid = module.params['vm_uid']
|
||||||
|
|
||||||
if state == 'stopped':
|
if state == 'stopped':
|
||||||
xen_orchestra.stop_vm(vm_uid)
|
result = xen_orchestra.stop_vm(vm_uid)
|
||||||
module.exit_json(changed=True)
|
module.exit_json(changed=result)
|
||||||
|
|
||||||
if state == 'started':
|
if state == 'started':
|
||||||
xen_orchestra.start_vm(vm_uid)
|
result = xen_orchestra.start_vm(vm_uid)
|
||||||
module.exit_json(changed=True)
|
module.exit_json(changed=result)
|
||||||
|
|
||||||
|
if state == 'restarted':
|
||||||
|
result = xen_orchestra.restart_vm(vm_uid)
|
||||||
|
module.exit_json(changed=result)
|
||||||
|
|
||||||
|
if state == 'absent':
|
||||||
|
result = xen_orchestra.delete_vm(vm_uid)
|
||||||
|
module.exit_json(changed=result)
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
result = xen_orchestra.create_vm()
|
||||||
|
module.exit_json(changed=True, vm_uid=result)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue