add osimages, add ViNS management

rc-5.2
Aleksandr Malyavin 3 years ago
parent ba8165bcf9
commit a4800cd041

@ -1,6 +1,6 @@
--- ---
# #
# DECORT vins module example # DECORT bservice module example
# #
- hosts: localhost - hosts: localhost

@ -0,0 +1,27 @@
---
#
# DECORT osimage module example
#
- hosts: localhost
tasks:
- name: create
decort_osimage:
authenticator: oauth2
verify_ssl: False
controller_url: "https://ds1.digitalenergy.online"
state: present
image_name: "alpine_linux3.14.0"
account_Id: 12345
url: "https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-virt-3.14.0-x86_64.iso"
boottype: "uefi"
imagetype: "linux"
hotresize: False
image_username: "test"
image_password: "p@ssword"
usernameDL: "testDL"
passwordDL: "p@sswordDL"
architecture: "X86_64"
drivers: "KVM_X86"
delegate_to: localhost
register: simple_vm

@ -0,0 +1,15 @@
---
#
# DECORT osimage module example
#
- hosts: localhost
tasks:
- name: create_virtual_osimage
decort_osimage:
authenticator: oauth2
controller_url: "https://ds1.digitalenergy.online"
image_name: "alpine_linux_3.14.0"
virt_name: "alpine_last"
delegate_to: localhost
register: osimage

@ -0,0 +1,14 @@
---
#
# DECORT osimage module example
#
- hosts: localhost
tasks:
- name: get_osimage
decort_osimage:
authenticator: oauth2
controller_url: "https://ds1.digitalenergy.online"
image_name: "alpine_linux_3.14.0"
account_Id: 79349
delegate_to: localhost
register: simple_vm

@ -6,23 +6,23 @@
tasks: tasks:
- name: obtain JWT - name: obtain JWT
decort_jwt: decort_jwt:
oauth2_url: "" #"https://sso.digitalenergy.online" oauth2_url: "https://sso.digitalenergy.online"
validity: 1200 validity: 1200
verify_ssl: false verify_ssl: false
register: token register: token
delegate_to: localhost delegate_to: localhost
- name: create a VM named cloud-init_example - name: create a VM named cluster-test
decort_k8s: decort_k8s:
state: present state: present
started: True started: True
getConfig: True getConfig: True
authenticator: jwt authenticator: jwt
jwt: "{{ token.jwt }}" jwt: "{{ token.jwt }}"
controller_url: "" #"https://mr4.digitalenergy.online" controller_url: "https://ds1.digitalenergy.online"
name: "cluster-test" name: "cluster-test"
rg_id: # Resource group id rg_id: 125
k8ci_id: # k8s ci id k8ci_id: 18
workers: workers:
- name: wg1 - name: wg1
ram: 1024 ram: 1024

@ -0,0 +1,15 @@
---
#
# DECORT osimage module example
#
- hosts: localhost
tasks:
- name: rename_osimage
decort_osimage:
authenticator: oauth2
controller_url: "https://ds1.digitalenergy.online"
image_name: "alpine_linux_3.14.0v2.0"
image_id: 54321
delegate_to: localhost
register: osimage

@ -0,0 +1,42 @@
---
#
# DECORT vins module example
#
- hosts: localhost
tasks:
- name: obtain JWT
decort_jwt:
oauth2_url: "https://sso.digitalenergy.online"
validity: 1200
register: my_jwt
delegate_to: localhost
- name: print out JWT
debug:
var: my_jwt.jwt
delegate_to: localhost
- name: Manage ViNS at resource group level
decort_vins:
authenticator: jwt
jwt: "{{ my_jwt.jwt }}"
controller_url: "https://cloud.digitalenergy.online"
vins_name: "vins_connected_by_decort_vins_module"
state: present
rg_id: 98
connect_to:
- type: VINS
id: 864
ipaddr: 192.168.5.66
netmask: 24
- type: VINS
id: 196
ipaddr: 192.168.9.133
netmask: 24
register: managed_vins
- name: print VINS facter
debug:
msg: "{{managed_vins.facts.password}}"
when: managed_vins.facts.password is defined

@ -794,7 +794,7 @@ class decort_kvmvm(DecortController):
affinity_label=dict(type='str', required=False), affinity_label=dict(type='str', required=False),
aff_rule=dict(type='list', required=False), aff_rule=dict(type='list', required=False),
aaff_rule=dict(type='list', required=False), aaff_rule=dict(type='list', required=False),
ci_user_data=dict(type='list', required=False), ci_user_data=dict(type='list',elements='dict', required=False),
state=dict(type='str', state=dict(type='str',
default='present', default='present',
choices=['absent', 'paused', 'poweredoff', 'halted', 'poweredon', 'present', 'check']), choices=['absent', 'paused', 'poweredoff', 'halted', 'poweredon', 'present', 'check']),

@ -22,8 +22,7 @@ description: >
This module can be used to obtain image ID of an OS image in DECORT cloud to use with subsequent calls to This module can be used to obtain image ID of an OS image in DECORT cloud to use with subsequent calls to
decort_vm module for batch VM provisioning. It will speed up VM creation and save a bunch of extra calls to decort_vm module for batch VM provisioning. It will speed up VM creation and save a bunch of extra calls to
DECORT cloud controller on each VM creation act. DECORT cloud controller on each VM creation act.
Note that this module is effectively an information provisioner. It is not designed to and does not manage
nor change state of OS image (or any other) objects in DECORT cloud.
version_added: "2.2" version_added: "2.2"
author: author:
- Sergey Shubin <sergey.shubin@digitalenergy.online> - Sergey Shubin <sergey.shubin@digitalenergy.online>
@ -68,8 +67,8 @@ options:
image_name: image_name:
description: description:
- Name of the OS image to use. Module will return the ID of this image. - Name of the OS image to use. Module will return the ID of this image.
- 'The specified image name will be looked up in the target DECORT controller and error will be generated if - 'The specified image name will be looked up in the target DECORT controller and error will be generated
no matching image is found.' - if no matching image is found.'
required: yes required: yes
jwt: jwt:
description: description:
@ -109,10 +108,6 @@ options:
- 'This parameter is required when I(authenticator=legacy) and ignored for other authentication modes.' - 'This parameter is required when I(authenticator=legacy) and ignored for other authentication modes.'
- If not specified in the playbook, the value will be taken from DECORT_USER environment variable. - If not specified in the playbook, the value will be taken from DECORT_USER environment variable.
required: no required: no
vdc_id:
description:
- ID of the VDC to limit the search of the OS image to.
required: no
verify_ssl: verify_ssl:
description: description:
- 'Controls SSL verification mode when making API calls to DECORT controller. Set it to False if you - 'Controls SSL verification mode when making API calls to DECORT controller. Set it to False if you
@ -134,19 +129,143 @@ options:
- 'This context data is expected to uniquely identify the task carried out by this module invocation so - 'This context data is expected to uniquely identify the task carried out by this module invocation so
that up-level orchestrator could match returned information to the its internal entities.' that up-level orchestrator could match returned information to the its internal entities.'
required: no required: no
account_name:
description:
- 'Account name. Used to get a unique integer account ID.'
required: no
virt_id:
description:
- 'A unique integer identifier for the virtual image.'
- 'Can be used to obtain information about a virtual image, as well as to create a virtual image and
- bind another operating system image to it.'
required: no
virt_name:
description:
- 'Name of the virtual image. Used to get the `virt_id`, and later information about the virtual image,
- as well as to create a virtual image and bind another operating system image to it.'
required: no
state:
description:
- 'The state of the images. If set to present, operating system images will be created to which
- the account specified in `account_Id` or `account_name` is bound. If set to absent, they will be removed.
required: no
drivers:
description:
- 'A list of compute types (eg virtual servers) that are appropriate for the operating system image.
- Note: `KVM_X86`. Used when creating an operating system image.'
required: no
architecture:
description:
- 'Binary architecture of the image. Note. `X86_64` or `PPC64_LE`. Used when creating
-an operating system image.'
required: no
imagetype:
description:
- 'Image type. `linux`, `windows` or `other`. The default is `linux`. Used when creating
- an operating system image.'
required: no
boottype:
description:
- 'Image upload type. `bios` or `uefi`. The default is `uefi`. Used when creating an operating
-system image.'
required: no
url:
description:
- 'Uniform resource locator (URL) pointing to the iso image of the operating system. Used when
-creating an operating system image.'
required: no
sepId:
description:
- 'The unique integer ID of the storage provider endpoint. Specified in pair with `poolName`.
- Used when creating an operating system image.'
required: no
poolName:
description:
- 'The pool in which the image will be created. Specified in pair with `sepId`. Used when creating
- an operating system image.'
required: no
hotresize:
description:
- 'Whether the image supports "hot" resizing. The default is `false`. Used when creating an operating
- system image.'
required: no
image_username:
description:
- 'An optional username for the image. Used when creating an operating system image.'
required: no
image_password:
description:
- 'An optional password for the image. Used when creating an operating system image. Used when creating
- an operating system image.'
required: no
usernameDL:
description:
- 'The username for loading the binary media. Used in conjunction with `passwordDL`. Used when creating
- an operating system image'
required: no
passwordDL:
description:
- 'The password for loading the binary media. Used in conjunction with `usernameDL`. Used when creating
- an operating system image.'
required: no
permanently:
description:
- 'Whether to permanently delete the image. Used when deleting an image. The default is false.'
required: no
''' '''
EXAMPLES = ''' EXAMPLES = '''
- name: locate OS image specified by its name, store result in image_to_use variable. - name: create_osimage
decort_osimage: decort_osimage:
authenticator: oauth2 authenticator: oauth2
app_id: "{{ MY_APP_ID }}" verify_ssl: False
app_secret: "{{ MY_APP_SECRET }}"
controller_url: "https://ds1.digitalenergy.online" controller_url: "https://ds1.digitalenergy.online"
image_name: "Ubuntu 18.04 v1.2.5" state: present
account_name: "GreyseDevelopment" image_name: "alpine_linux3.14.0"
account_Id: 12345
url: "https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-virt-3.14.0-x86_64.iso"
boottype: "uefi"
imagetype: "linux"
hotresize: False
image_username: "test"
image_password: "p@ssw0rd"
usernameDL: "testDL"
passwordDL: "p@ssw0rdDL"
architecture: "X86_64"
drivers: "KVM_X86"
delegate_to: localhost delegate_to: localhost
register: image_to_use register: osimage
- name: get_osimage
decort_osimage:
authenticator: oauth2
controller_url: "https://ds1.digitalenergy.online"
image_name: "alpine_linux_3.14.0"
account_Id: 12345
delegate_to: localhost
register: osimage
- name: create_virtual_osimage
decort_osimage:
authenticator: oauth2
controller_url: "https://ds1.digitalenergy.online"
image_name: "alpine_linux_3.14.0"
virt_name: "alpine_last"
delegate_to: localhost
register: osimage
- name: rename_osimage
decort_osimage:
authenticator: oauth2
controller_url: "https://ds1.digitalenergy.online"
image_name: "alpine_linux_3.14.0v2.0"
image_id: 54321
delegate_to: localhost
register: osimage
''' '''
RETURN = ''' RETURN = '''
@ -157,6 +276,7 @@ facts:
sample: sample:
facts: facts:
id: 100 id: 100
linkto: 80
name: "Ubuntu 16.04 v1.0" name: "Ubuntu 16.04 v1.0"
size: 3 size: 3
sep_id: 1 sep_id: 1
@ -171,6 +291,104 @@ from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import * from ansible.module_utils.decort_utils import *
class decort_osimage(DecortController):
def __init__(self,amodule):
super(decort_osimage, self).__init__(amodule)
self.validated_image_id = 0
self.validated_virt_image_id = 0
self.validated_image_name = amodule.params['image_name']
self.validated_virt_image_name = None
self.validated_virt_image_id = amodule.params['virt_id']
if amodule.params['account_name']:
self.validated_account_id, _ = self.account_find(amodule.params['account_name'])
else:
self.validated_account_id = amodule.params['account_Id']
if self.validated_account_id == 0:
# we failed either to find or access the specified account - fail the module
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = ("Cannot find account '{}'").format(amodule.params['account_name'])
amodule.fail_json(**self.result)
if amodule.params['image_id'] != 0 and amodule.params['image_name']:
self.validated_image_id = amodule.params['image_id']
if amodule.params['image_name']:
decort_osimage.decort_image_rename(self,amodule)
self.result['msg'] = ("Image renamed successfully")
def decort_image_find(self, amodule):
# function that finds the OS image
image_id, image_facts = self.image_find(image_id=amodule.params['image_id'], image_name=self.validated_image_name,
account_id=self.validated_account_id, rg_id=0,
sepid=amodule.params['sep_id'],
pool=amodule.params['pool'])
return image_id, image_facts
def decort_virt_image_find(self, amodule):
# function that finds a virtual image
image_id, image_facts = self.virt_image_find(image_id=amodule.params['virt_id'],
account_id=self.validated_account_id, rg_id=0,
sepid=amodule.params['sep_id'],
virt_name=amodule.params['virt_name'],
pool=amodule.params['pool'])
return image_id, image_facts
def decort_image_create(self,amodule):
# function that creates OS image
image_facts = self.image_create(img_name=self.validated_image_name,
url=amodule.params['url'],
gid=amodule.params['gid'],
boottype=amodule.params['boottype'],
imagetype=amodule.params['imagetype'],
hotresize=amodule.params['hotresize'],
username=amodule.params['image_username'],
password=amodule.params['image_password'],
account_Id=amodule.params['account_Id'],
usernameDL=amodule.params['usernameDL'],
passwordDL=amodule.params['passwordDL'],
sepId=amodule.params['sepId'],
poolName=amodule.params['poolName'],
architecture=amodule.params['architecture'],
drivers=amodule.params['drivers'])
self.result['changed'] = True
return image_facts
def decort_virt_image_link(self,amodule):
# function that links an OS image to a virtual one
self.virt_image_link(imageId=self.validated_virt_image_id, targetId=self.validated_image_id)
image_id, image_facts = decort_osimage.decort_virt_image_find(self, amodule)
self.result['facts'] = decort_osimage.decort_osimage_package_facts(image_facts, amodule.check_mode)
self.result['msg'] = ("Image '{}' linked to virtual image '{}'").format(self.validated_image_id,
decort_osimage.decort_osimage_package_facts(image_facts)['id'],)
return image_id, image_facts
def decort_image_delete(self,amodule):
# function that removes an image
self.image_delete(imageId=amodule.image_id_delete, permanently=amodule.params['permanently'])
self.result['changed'] = True
self.result['msg'] = ("Image '{}' deleted").format(amodule.image_id_delete)
def decort_virt_image_create(self,amodule):
# function that creates a virtual image
image_facts = self.virt_image_create(name=amodule.params['virt_name'], targetId=self.validated_image_id)
image_id, image_facts = decort_osimage.decort_virt_image_find(self, amodule)
self.result['facts'] = decort_osimage.decort_osimage_package_facts(image_facts, amodule.check_mode)
return image_id, image_facts
def decort_image_rename(self,amodule):
# image renaming function
image_facts = self.image_rename(imageId=self.validated_image_id, name=amodule.params['image_name'])
self.result['msg'] = ("Image renamed successfully")
image_id, image_facts = decort_osimage.decort_image_find(self, amodule)
return image_id, image_facts
def decort_osimage_package_facts(arg_osimage_facts, arg_check_mode=False): def decort_osimage_package_facts(arg_osimage_facts, arg_check_mode=False):
"""Package a dictionary of OS image according to the decort_osimage module specification. This """Package a dictionary of OS image according to the decort_osimage module specification. This
@ -186,8 +404,7 @@ def decort_osimage_package_facts(arg_osimage_facts, arg_check_mode=False):
name="none", name="none",
size=0, size=0,
type="none", type="none",
state="CHECK_MODE", state="CHECK_MODE", )
)
if arg_check_mode: if arg_check_mode:
# in check mode return immediately with the default values # in check mode return immediately with the default values
@ -206,9 +423,10 @@ def decort_osimage_package_facts(arg_osimage_facts, arg_check_mode=False):
ret_dict['sep_id'] = arg_osimage_facts['sepId'] ret_dict['sep_id'] = arg_osimage_facts['sepId']
ret_dict['pool'] = arg_osimage_facts['pool'] ret_dict['pool'] = arg_osimage_facts['pool']
ret_dict['state'] = arg_osimage_facts['status'] ret_dict['state'] = arg_osimage_facts['status']
ret_dict['linkto'] = arg_osimage_facts['linkTo']
return ret_dict return ret_dict
def decort_osimage_parameters(): def decort_osimage_parameters():
"""Build and return a dictionary of parameters expected by decort_osimage module in a form accepted """Build and return a dictionary of parameters expected by decort_osimage module in a form accepted
by AnsibleModule utility class.""" by AnsibleModule utility class."""
@ -225,7 +443,6 @@ def decort_osimage_parameters():
required=True, required=True,
choices=['legacy', 'oauth2', 'jwt']), choices=['legacy', 'oauth2', 'jwt']),
controller_url=dict(type='str', required=True), controller_url=dict(type='str', required=True),
image_name=dict(type='str', required=True),
jwt=dict(type='str', jwt=dict(type='str',
required=False, required=False,
fallback=(env_fallback, ['DECORT_JWT']), fallback=(env_fallback, ['DECORT_JWT']),
@ -239,26 +456,40 @@ def decort_osimage_parameters():
no_log=True), no_log=True),
pool=dict(type='str', required=False, default=""), pool=dict(type='str', required=False, default=""),
sep_id=dict(type='int', required=False, default=0), sep_id=dict(type='int', required=False, default=0),
account_name=dict(type='str', required=True), account_name=dict(type='str', required=False),
account_Id=dict(type='int', required=False),
user=dict(type='str', user=dict(type='str',
required=False, required=False,
fallback=(env_fallback, ['DECORT_USER'])), fallback=(env_fallback, ['DECORT_USER'])),
vdc_id=dict(type='int', required=False, default=0),
verify_ssl=dict(type='bool', required=False, default=True), verify_ssl=dict(type='bool', required=False, default=True),
workflow_callback=dict(type='str', required=False), workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False), workflow_context=dict(type='str', required=False),
image_name=dict(type='str', required=False),
image_id=dict(type='int', required=False,default=0),
virt_id=dict(type='int', required=False, default=0),
virt_name=dict(type='str', required=False),
state=dict(type='str',
default='present',
choices=['absent', 'present']),
drivers=dict(type='str', required=False, default="KVM_X86"),
architecture=dict(type='str', required=False, default="X86_64"),
imagetype=dict(type='str', required=False, default="linux"),
boottype=dict(type='str', required=False, default="uefi"),
url=dict(type='str', required=False),
gid=dict(type='int', required=False, default=0),
sepId=dict(type='int', required=False, default=0),
poolName=dict(type='str', required=False),
hotresize=dict(type='bool', required=False, default=False),
image_username=dict(type='str', required=False),
image_password=dict(type='str', required=False),
usernameDL=dict(type='str', required=False),
passwordDL=dict(type='str', required=False),
permanently=dict(type='bool', required=False, default=False),
) )
# Workflow digest:
# 1) authenticate to DECORT controller & validate authentication by issuing API call - done when
# creating DecortController
# 2) obtain a list of OS images accessible to the specified account (and optionally - within
# the specified VDC)
# 3) match specified OS image by its name - if image is not found abort the module
# 5) report result to Ansible
def main(): def main():
module_parameters = decort_osimage_parameters() module_parameters = decort_osimage.decort_osimage_parameters()
amodule = AnsibleModule(argument_spec=module_parameters, amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True, supports_check_mode=True,
@ -273,28 +504,65 @@ def main():
], ],
) )
decon = DecortController(amodule) decon = decort_osimage(amodule)
# we need account ID to locate OS images - find the account by the specified name and get its ID if amodule.params['image_name'] or amodule.params['image_id']:
validated_account_id, _ = decon.account_find(amodule.params['account_name']) image_id, image_facts = decort_osimage.decort_image_find(decon, amodule)
if validated_account_id == 0: decon.validated_image_id = decort_osimage.decort_osimage_package_facts(image_facts)['id']
# we failed either to find or access the specified account - fail the module if decort_osimage.decort_osimage_package_facts(image_facts)['id'] > 0:
decon.result['failed'] = True decon.result['facts'] = decort_osimage.decort_osimage_package_facts(image_facts, amodule.check_mode)
decon.result['changed'] = False
decon.result['msg'] = ("Cannot find account '{}'").format(amodule.params['account_name']) if amodule.params['state'] == "present" and decon.validated_image_id == 0 and amodule.params['image_name'] and amodule.params['url']:
decort_osimage.decort_image_create(decon,amodule)
decon.result['changed'] = True
image_id, image_facts = decort_osimage.decort_image_find(decon, amodule)
decon.result['msg'] = ("OS image '{}' created").format(decort_osimage.decort_osimage_package_facts(image_facts)['id'])
decon.result['facts'] = decort_osimage.decort_osimage_package_facts(image_facts, amodule.check_mode)
decon.validated_image_id = decort_osimage.decort_osimage_package_facts(image_facts)['id']
elif amodule.params['state'] == "absent" and amodule.params['image_name'] or amodule.params['image_id'] and decort_osimage.decort_osimage_package_facts(image_facts)['accountId'] == amodule.params['account_Id']:
amodule.image_id_delete = decon.validated_image_id
decort_osimage.decort_image_delete(decon,amodule)
if amodule.params['virt_name'] or amodule.params['virt_id']:
image_id, image_facts = decort_osimage.decort_virt_image_find(decon, amodule)
if decort_osimage.decort_osimage_package_facts(image_facts)['id'] > 0:
decon.result['facts'] = decort_osimage.decort_osimage_package_facts(image_facts, amodule.check_mode)
decon.validated_virt_image_id = decort_osimage.decort_osimage_package_facts(image_facts)['id']
decon.validated_virt_image_name = decort_osimage.decort_osimage_package_facts(image_facts)['name']
if decort_osimage.decort_osimage_package_facts(image_facts)['id'] == 0 and amodule.params['state'] == "present" and decon.validated_image_id > 0:
image_id, image_facts = decort_osimage.decort_virt_image_create(decon,amodule)
decon.result['msg'] = ("Virtual image '{}' created").format(decort_osimage.decort_osimage_package_facts(image_facts)['id'])
decon.result['changed'] = True
elif decort_osimage.decort_osimage_package_facts(image_facts)['id'] == 0 and amodule.params['state'] == "present" and decon.validated_image_id == 0:
decon.result['msg'] = ("Cannot find OS image")
amodule.fail_json(**decon.result) amodule.fail_json(**decon.result)
image_id, image_facts = decon.image_find(image_id=0, image_name=amodule.params['image_name'],
account_id=validated_account_id, rg_id=0, if decon.validated_image_id:
sepid=amodule.params['sep_id'], if decort_osimage.decort_osimage_package_facts(image_facts)['linkto'] != decon.validated_image_id:
pool=amodule.params['pool']) decort_osimage.decort_virt_image_link(decon,amodule)
decon.result['changed'] = True
amodule.exit_json(**decon.result)
if decon.validated_virt_image_id > 0 and amodule.params['state'] == "absent":
decon.result['msg'] = ("Osimage module cannot delete virtual images.")
decon.result['failed'] = True
amodule.exit_json(**decon.result)
if decon.result['failed'] == True: if decon.result['failed'] == True:
# we failed to find the specified image - fail the module # we failed to find the specified image - fail the module
decon.result['changed'] = False decon.result['changed'] = False
amodule.fail_json(**decon.result) amodule.fail_json(**decon.result)
decon.result['facts'] = decort_osimage_package_facts(image_facts, amodule.check_mode)
decon.result['changed'] = False # decort_osimage is a read-only module - make sure the 'changed' flag is set to False
amodule.exit_json(**decon.result) amodule.exit_json(**decon.result)

@ -320,6 +320,7 @@ def decort_vins_parameters():
mgmtaddr=dict(type='str',required=False, default=''), mgmtaddr=dict(type='str',required=False, default=''),
custom_config=dict(type='bool',required=False, default=False), custom_config=dict(type='bool',required=False, default=False),
config_save=dict(type='bool',required=False, default=False), config_save=dict(type='bool',required=False, default=False),
connect_to=dict(type='list', default=[], required=False),
jwt=dict(type='str', jwt=dict(type='str',
required=False, required=False,
fallback=(env_fallback, ['DECORT_JWT']), fallback=(env_fallback, ['DECORT_JWT']),
@ -496,8 +497,16 @@ def main():
# update ViNS # update ViNS
decon.vins_update(vins_facts, decon.vins_update(vins_facts,
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'], amodule.params['ext_net_id'], amodule.params['ext_ip_addr'],
)
decon.vins_update_mgmt(
vins_facts,
amodule.params['mgmtaddr'], amodule.params['mgmtaddr'],
) )
decon.vins_update_ifaces(
vins_facts,
amodule.params['connect_to'],
)
elif amodule.params['state'] == 'disabled': elif amodule.params['state'] == 'disabled':
# disable and update ViNS # disable and update ViNS
decon.vins_state(vins_facts, 'disabled') decon.vins_state(vins_facts, 'disabled')

@ -1266,7 +1266,6 @@ class DecortController(object):
@return: image ID and dictionary with image specs. If no matching image found, 0 for ID and None for @return: image ID and dictionary with image specs. If no matching image found, 0 for ID and None for
dictionary are returned, and self.result['failed']=True. dictionary are returned, and self.result['failed']=True.
""" """
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "image_find") self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "image_find")
if image_id > 0: if image_id > 0:
@ -1302,6 +1301,7 @@ class DecortController(object):
full_match = False full_match = False
if full_match: if full_match:
return image_record['id'], image_record return image_record['id'], image_record
self.result['failed'] = False
self.result['failed'] = True self.result['failed'] = True
self.result['msg'] = ("Failed to find OS image by name '{}', SEP ID {}, pool '{}' for " self.result['msg'] = ("Failed to find OS image by name '{}', SEP ID {}, pool '{}' for "
@ -1310,6 +1310,136 @@ class DecortController(object):
account_id) account_id)
return 0, None return 0, None
def virt_image_find(self, image_id, virt_name, account_id, rg_id=0, sepid=0, pool=""):
"""Locates virtual image specified by name and returns its facts as dictionary.
Primary use of this function is to obtain the ID of the image identified by its name and,
optionally SEP ID and/or pool name. Also note that only virtual images in status CREATED are
returned.
@param (string) image_id: ID of the OS image to find. If non-zero ID is specified, then
virt_name is ignored.
@param (string) virt_name: name of the OS image to find. This argument is ignored if non-zero
image ID is passed.
@param (int) account_id: ID of the account for which the image will be looked up. If set to 0,
the account ID will be obtained from the specified RG ID.
@param (int) rg_id: ID of the RG to use as a reference when listing OS images. This argument is
ignored if non-zero image id and/or non-zero account_id are specified.
@param (int) sepid: ID of the SEP where the image should be present. If set to 0, there will be no
filtering by SEP ID and the first matching image will be returned.
@param (string) pool: name of the pool where the image should be present. If set to empty string, there
will be no filtering by pool name and first matching image will be returned.
@return: image ID and dictionary with image specs. If no matching image found, 0 for ID and None for
dictionary are returned, and self.result['failed']=True.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "virt_image_find")
if image_id > 0:
ret_image_id, ret_image_dict = self._image_get_by_id(image_id)
if (ret_image_id and
(sepid == 0 or sepid == ret_image_dict['sepId']) and
(pool == "" or pool == ret_image_dict['pool'])):
return ret_image_id, ret_image_dict
else:
validated_acc_id = account_id
if account_id == 0:
validated_rg_id, rg_facts = self._rg_get_by_id(rg_id)
if not validated_rg_id:
self.result['failed'] = True
self.result['msg'] = ("Failed to find RG ID {}, and account ID is zero.").format(rg_id)
return 0, None
validated_acc_id = rg_facts['accountId']
api_params = dict(accountId=validated_acc_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/image/list", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
images_list = json.loads(api_resp.content.decode('utf8'))
for image_record in images_list:
if image_record['name'] == virt_name and image_record['status'] == "CREATED" and image_record['type'] == "virtual":
if sepid == 0 and pool == "":
# if no filtering by SEP ID or pool name is requested, return the first match
return image_record['id'], image_record
full_match = True
if full_match:
return image_record['id'], image_record
self.result['failed'] = True
self.result['msg'] = ("Failed to find virtual OS image by name '{}', SEP ID {}, pool '{}' for "
"account ID '{}'.").format(virt_name,
sepid, pool,
account_id)
return 0, None
def virt_image_create(self, name, targetId):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "virt_image_create")
api_params = dict(name=name, targetId=targetId,)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/image/createVirtual", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
virt_image_dict = json.loads(api_resp.content.decode('utf8'))
self.result['failed'] = False
self.result['changed'] = True
return 0, None
def image_delete(self, imageId, permanently):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "image_delete")
api_params = dict(imageId=imageId, permanently=permanently,)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/image/delete", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
image_dict = json.loads(api_resp.content.decode('utf8'))
self.result['changed'] = True
return 0, None
def image_create(self,img_name,url,gid,boottype,imagetype,architecture,drivers,hotresize,username,password,account_Id,usernameDL,passwordDL,sepId,poolName):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "image_create")
api_params = dict(name=img_name, url=url,
gid=gid, boottype=boottype,
imagetype=imagetype, architecture=architecture,
drivers=drivers, accountId=account_Id,
hotresize=hotresize, username=username,
password=password, usernameDL=usernameDL,
passwordDL=passwordDL, sepId=sepId,
poolName=poolName,
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/image/create", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
virt_image_dict = json.loads(api_resp.content.decode('utf8'))
self.result['failed'] = False
self.result['changed'] = True
return 0, None
def virt_image_link(self, imageId, targetId):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "virt_image_link")
api_params = dict(imageId=imageId, targetId=targetId,)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/image/link", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
link_image_dict = json.loads(api_resp.content.decode('utf8'))
self.result['failed'] = False
self.result['changed'] = True
return 0, None
def image_rename(self, imageId, name):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "image_rename")
api_params = dict(imageId=imageId, name=name,)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/image/rename", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
link_image_dict = json.loads(api_resp.content.decode('utf8'))
self.result['failed'] = False
self.result['changed'] = True
################################### ###################################
# Resource Group (RG) manipulation methods # Resource Group (RG) manipulation methods
################################### ###################################
@ -2166,7 +2296,7 @@ class DecortController(object):
desired_state) desired_state)
return return
def vins_update(self, vins_dict, ext_net_id, ext_ip_addr="", mgmtaddr=""): def vins_update(self, vins_dict, ext_net_id, ext_ip_addr=""):
"""Update ViNS. Currently only updates to the external network connection settings and """Update ViNS. Currently only updates to the external network connection settings and
external IP address assignment are implemented. external IP address assignment are implemented.
Note that as ViNS created at account level cannot have external connections, attempt Note that as ViNS created at account level cannot have external connections, attempt
@ -2191,11 +2321,6 @@ class DecortController(object):
self.result['msg'] = ("vins_update() in check mode: updating ViNS ID {}, name '{}' " self.result['msg'] = ("vins_update() in check mode: updating ViNS ID {}, name '{}' "
"was requested.").format(vins_dict['id'], vins_dict['name']) "was requested.").format(vins_dict['id'], vins_dict['name'])
return return
if self.amodule.params['config_save'] and vins_dict['VNFDev']['customPrecfg']:
# only save config,no other modifictaion
self.result['changed'] = True
self._vins_vnf_config_save(vins_dict['VNFDev']['id'])
return
if not vins_dict['rgId']: if not vins_dict['rgId']:
# this ViNS exists at account level - no updates are possible # this ViNS exists at account level - no updates are possible
@ -2247,24 +2372,117 @@ class DecortController(object):
"no reconnection to default network will be done.").format(vins_dict['id'], "no reconnection to default network will be done.").format(vins_dict['id'],
gw_config[ gw_config[
'ext_net_id']) 'ext_net_id'])
return
def vins_update_mgmt(self, vins_dict, mgmtaddr=""):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_update_mgmt")
if self.amodule.params['config_save'] and vins_dict['VNFDev']['customPrecfg']:
# only save config,no other modifictaion
self.result['changed'] = True
self._vins_vnf_config_save(vins_dict['VNFDev']['id'])
self.result['changed'] = True
self.result['failed'] = False
return
for iface in vins_dict['VNFDev']['interfaces']: for iface in vins_dict['VNFDev']['interfaces']:
if iface['ipAddress'] == mgmtaddr: if iface['ipAddress'] == mgmtaddr:
if not iface['listenSsh']: if not iface['listenSsh']:
self._vins_vnf_addmgmtaddr(vins_dict['VNFDev']['id'],mgmtaddr) self._vins_vnf_addmgmtaddr(vins_dict['VNFDev']['id'],mgmtaddr)
self.result['changed'] = True
self.result['failed'] = False
elif mgmtaddr =="": elif mgmtaddr =="":
if iface['listenSsh'] and iface['name'] != "ens9": if iface['listenSsh'] and iface['name'] != "ens9":
self._vins_vnf_delmgmtaddr(vins_dict['VNFDev']['id'],iface['ipAddress']) self._vins_vnf_delmgmtaddr(vins_dict['VNFDev']['id'],iface['ipAddress'])
self.result['changed'] = True
self.result['failed'] = False
if self.amodule.params['custom_config']: if self.amodule.params['custom_config']:
if not vins_dict['VNFDev']['customPrecfg']: if not vins_dict['VNFDev']['customPrecfg']:
self._vins_vnf_config_save(vins_dict['VNFDev']['id']) self._vins_vnf_config_save(vins_dict['VNFDev']['id'])
self._vins_vnf_customconfig_set(vins_dict['VNFDev']['id']) self._vins_vnf_customconfig_set(vins_dict['VNFDev']['id'])
self.result['changed'] = True
self.result['failed'] = False
else: else:
if vins_dict['VNFDev']['customPrecfg']: if vins_dict['VNFDev']['customPrecfg']:
self._vins_vnf_customconfig_set(vins_dict['VNFDev']['id'],False) self._vins_vnf_customconfig_set(vins_dict['VNFDev']['id'],False)
self.result['changed'] = True
self.result['failed'] = False
return
def vins_update_ifaces(self,vins_dict,vinses=""):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_update_ifaces")
existed_conn_ip = []
#vnf_dict = self._get_vnf_by_id(vins_dict['VNFDev']['id'])
list_account_vins = self._get_all_account_vinses(vins_dict['VNFDev']['accountId'])
list_account_vinsid = [rec['id'] for rec in list_account_vins]
list_ifaces_ip = [rec['ipaddr'] for rec in vinses]
vins_inner = [rec['id'] for rec in vinses]
vins_outer = [rec['id'] for rec in list_account_vins]
for iface in vins_dict['VNFDev']['interfaces']:
if iface['connType'] == "VXLAN" and iface['type'] == "CUSTOM":
if iface['ipAddress'] not in list_ifaces_ip:
self._vnf_iface_remove(vins_dict['VNFDev']['id'],iface['name'])
self.result['changed'] = True
self.result['failed'] = False
else:
existed_conn_ip.append(iface['ipAddress'])
for vins in vinses:
if vins['id'] in list_account_vinsid:
_,v_dict = self._vins_get_by_id(vins['id'])
if vins['ipaddr'] not in existed_conn_ip:
self._vnf_iface_add(vins_dict['VNFDev']['id'],v_dict['vxlanId'],vins['ipaddr'],vins['netmask'])
self.result['changed'] = True
self.result['failed'] = False
return return
def _vnf_iface_add(self,arg_devid,arg_vxlanid,arg_ipaddr,arg_netmask="24",arg_defgw=""):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "_vnf_iface_add")
api_params = dict(
devId=arg_devid,
ifType="CUSTOM",
connType="VXLAN",
connId=arg_vxlanid,
ipAddr=arg_ipaddr,
netMask=arg_netmask,
defGw=arg_defgw
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/ifaceAdd", api_params)
conn_dict = json.loads(api_resp.content.decode('utf8'))
return
def _vnf_iface_remove(self,arg_devid,arg_iface_name):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "_vnf_iface_add")
api_params = dict(
devId=arg_devid,
name=arg_iface_name,
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/ifaceRemove", api_params)
return
def _get_vnf_by_id(self,vnf_id):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "get_vnf_by_id")
api_params = dict(devId=vnf_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/get", api_params)
if api_resp.status_code == 200:
ret_vnf_dict = json.loads(api_resp.content.decode('utf8'))
else:
self.result['warning'] = ("get_all_account_vinses(): failed to configuration of the specified VNF device ID{}. HTTP code {}, "
"response {}.").format(vnf_id, api_resp.status_code, api_resp.reason)
return ret_vnf_dict
def _get_all_account_vinses(self,acc_id):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "get_all_account_vinses")
api_params = dict(accountId=acc_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/listVins", api_params)
if api_resp.status_code == 200:
ret_listvins_dict = json.loads(api_resp.content.decode('utf8'))
else:
self.result['warning'] = ("get_all_account_vinses(): failed to get list VINS in Account ID {}. HTTP code {}, "
"response {}.").format(acc_id, api_resp.status_code, api_resp.reason)
return ret_listvins_dict
def _vins_vnf_addmgmtaddr(self,dev_id,mgmtip): def _vins_vnf_addmgmtaddr(self,dev_id,mgmtip):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_vnf_addmgmtaddr") self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_vnf_addmgmtaddr")
@ -2649,8 +2867,8 @@ class DecortController(object):
iface_ipaddr = iface['ipAddress'] iface_ipaddr = iface['ipAddress']
break break
else: else:
decon.result['failed'] = True self.result['failed'] = True
decon.result['msg'] = "Compute ID {} is not connected to ViNS ID {}.".format(comp_facts['id'], self.result['msg'] = "Compute ID {} is not connected to ViNS ID {}.".format(comp_facts['id'],
vins_facts['id']) vins_facts['id'])
return ret_rules return ret_rules

Loading…
Cancel
Save