diff --git a/example/.gitkeep b/examples/.gitkeep
similarity index 100%
rename from example/.gitkeep
rename to examples/.gitkeep
diff --git a/examples/VINS.yaml b/examples/VINS.yaml
new file mode 100644
index 0000000..929bf96
--- /dev/null
+++ b/examples/VINS.yaml
@@ -0,0 +1,40 @@
+---
+#
+# 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://ds1.digitalenergy.online"
+ vins_name: "vins_created_by_decort_VINS_module"
+ state: present
+ rg_id: 198
+ ext_net_id: -1
+ ipcidr: "10.20.30.0/24"
+ mgmtaddr: "10.20.30.1"
+ custom_config: false
+ config_save: false
+ verify_ssl: false
+
+ register: managed_vins
+
+ - name: print VINS facter
+ debug:
+ msg: "{{managed_vins.facts.password}}"
+ when: managed_vins.facts.password is defined
diff --git a/example/affinity.yaml b/examples/affinity.yaml
similarity index 100%
rename from example/affinity.yaml
rename to examples/affinity.yaml
diff --git a/examples/annotations.yaml b/examples/annotations.yaml
new file mode 100644
index 0000000..6177f74
--- /dev/null
+++ b/examples/annotations.yaml
@@ -0,0 +1,40 @@
+---
+#
+# DECORT k8s module labels, taints, annotations 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: Create k8s cluster
+ decort_k8s:
+ authenticator: jwt
+ jwt: "{{ my_jwt.jwt }}"
+ controller_url: "https://mr4.digitalenergy.online"
+ name: "example_kubernetes"
+ rg_id: 199
+ k8ci_id: 4
+ state: present
+ workers:
+ - name: workgroup1
+ labels:
+ - disktype1=ssd1
+ - disktype2=ssd2
+ taints:
+ - key1=value1:NoSchedule
+ - key2=value2:NoSchedule
+ annotations:
+ - node.deckhouse.io/group1=g1
+ - node.deckhouse.io/group2=g2
+ register: kube
diff --git a/example/anti_affinity.yaml b/examples/anti_affinity.yaml
similarity index 100%
rename from example/anti_affinity.yaml
rename to examples/anti_affinity.yaml
diff --git a/examples/basicservices.yaml b/examples/basicservices.yaml
new file mode 100644
index 0000000..ae9a6b7
--- /dev/null
+++ b/examples/basicservices.yaml
@@ -0,0 +1,31 @@
+---
+#
+# DECORT bservice 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 bservice at RG
+ decort_bservice:
+ account_id: 98
+ verify_ssl: false
+ authenticator: jwt
+ jwt: "{{ my_jwt.jwt }}"
+ controller_url: "https://ds1.digitalenergy.online"
+ rg_id: 1629
+ state: present
+ name: databases
+ started: True
+ register: db_bservice
diff --git a/example/cloud_init-example.yaml b/examples/cloud-init.yaml
similarity index 100%
rename from example/cloud_init-example.yaml
rename to examples/cloud-init.yaml
diff --git a/examples/cloud_init.yaml b/examples/cloud_init.yaml
new file mode 100644
index 0000000..4163c0b
--- /dev/null
+++ b/examples/cloud_init.yaml
@@ -0,0 +1,38 @@
+#
+# DECORT kvmvm module example
+#
+- hosts: ansible_master
+ tasks:
+ - name: create a VM named cloud-init_example
+ decort_kvmvm:
+ annotation: "VM managed by decort_kvmvm module"
+ authenticator: oauth2
+ app_id: "" # Application id from SSO Digital Energy
+ app_secret: "" # API key from SSO Digital Energy
+ controller_url: "" #"https://mr4.digitalenergy.online"
+ name: cloud-init_example
+ cpu: 2
+ ram: 2048
+ boot_disk: 10
+ image_name: "DECS Ubuntu 18.04 v1.2.3" #Name of OS image
+ networks:
+ - type: VINS
+ id: #VINS id
+ tags: "Ansible cloud init example"
+ state: present
+ rg_id: #Resource group id
+ ci_user_data:
+ - packages:
+ - apache2
+ - write_files:
+ - content: |
+
+ Hello World!
+
+ owner: user:user
+ path: /var/www/html/index.html
+ - hostname: test-apache
+ - ssh_keys:
+ - rsa_public: ssh-rsa AAAAOasDmLxnD= user@pc
+ delegate_to: localhost
+ register: simple_vm
diff --git a/examples/create-osimage.yaml b/examples/create-osimage.yaml
new file mode 100644
index 0000000..ae616e4
--- /dev/null
+++ b/examples/create-osimage.yaml
@@ -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
diff --git a/examples/create-virtual-osimage.yaml b/examples/create-virtual-osimage.yaml
new file mode 100644
index 0000000..015c21e
--- /dev/null
+++ b/examples/create-virtual-osimage.yaml
@@ -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
+
diff --git a/examples/get-osimage.yaml b/examples/get-osimage.yaml
new file mode 100644
index 0000000..3e61612
--- /dev/null
+++ b/examples/get-osimage.yaml
@@ -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
diff --git a/example/kubernetes.yaml b/examples/kubernetes.yaml
similarity index 60%
rename from example/kubernetes.yaml
rename to examples/kubernetes.yaml
index 8e73050..065c5f8 100644
--- a/example/kubernetes.yaml
+++ b/examples/kubernetes.yaml
@@ -6,23 +6,23 @@
tasks:
- name: obtain JWT
decort_jwt:
- oauth2_url: "" #"https://sso.digitalenergy.online"
+ oauth2_url: "https://sso.digitalenergy.online"
validity: 1200
verify_ssl: false
register: token
delegate_to: localhost
- - name: create a VM named cloud-init_example
+ - name: create a VM named cluster-test
decort_k8s:
state: present
started: True
getConfig: True
authenticator: jwt
jwt: "{{ token.jwt }}"
- controller_url: "" #"https://mr4.digitalenergy.online"
+ controller_url: "https://ds1.digitalenergy.online"
name: "cluster-test"
- rg_id: # Resource group id
- k8ci_id: # k8s ci id
+ rg_id: 125
+ k8ci_id: 18
workers:
- name: wg1
ram: 1024
diff --git a/examples/rename-osimage.yaml b/examples/rename-osimage.yaml
new file mode 100644
index 0000000..eb13642
--- /dev/null
+++ b/examples/rename-osimage.yaml
@@ -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
+
diff --git a/library/decort_osimage.py b/library/decort_osimage.py
index 9c91b30..f09eee7 100644
--- a/library/decort_osimage.py
+++ b/library/decort_osimage.py
@@ -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
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.
- 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"
author:
- Sergey Shubin
@@ -68,8 +67,8 @@ options:
image_name:
description:
- 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
- no matching image is found.'
+ - 'The specified image name will be looked up in the target DECORT controller and error will be generated
+ - if no matching image is found.'
required: yes
jwt:
description:
@@ -109,10 +108,6 @@ options:
- '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.
required: no
- vdc_id:
- description:
- - ID of the VDC to limit the search of the OS image to.
- required: no
verify_ssl:
description:
- '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
that up-level orchestrator could match returned information to the its internal entities.'
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 = '''
-- name: locate OS image specified by its name, store result in image_to_use variable.
+ - name: create_osimage
+ 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@ssw0rd"
+ usernameDL: "testDL"
+ passwordDL: "p@ssw0rdDL"
+ architecture: "X86_64"
+ drivers: "KVM_X86"
+ delegate_to: localhost
+ 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
- app_id: "{{ MY_APP_ID }}"
- app_secret: "{{ MY_APP_SECRET }}"
controller_url: "https://ds1.digitalenergy.online"
- image_name: "Ubuntu 18.04 v1.2.5"
- account_name: "GreyseDevelopment"
+ image_name: "alpine_linux_3.14.0v2.0"
+ image_id: 54321
delegate_to: localhost
- register: image_to_use
+ register: osimage
+
+
+
'''
RETURN = '''
@@ -157,6 +276,7 @@ facts:
sample:
facts:
id: 100
+ linkto: 80
name: "Ubuntu 16.04 v1.0"
size: 3
sep_id: 1
@@ -171,94 +291,205 @@ from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import *
+class decort_osimage(DecortController):
+ def __init__(self,amodule):
+ super(decort_osimage, self).__init__(amodule)
-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
- dictionary will be returned to the upstream Ansible engine at the completion of the module run.
+ 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)
- @param arg_osimage_facts: dictionary with OS image facts as returned by API call to .../images/list
- @param arg_check_mode: boolean that tells if this Ansible module is run in check mode.
- @return: dictionary with OS image specs populated from arg_osimage_facts.
- """
+ 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")
- ret_dict = dict(id=0,
- name="none",
- size=0,
- type="none",
- state="CHECK_MODE",
- )
- if arg_check_mode:
- # in check mode return immediately with the default values
- return ret_dict
- if arg_osimage_facts is None:
- # if void facts provided - change state value to ABSENT and return
- ret_dict['state'] = "ABSENT"
- return ret_dict
+ 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
- ret_dict['id'] = arg_osimage_facts['id']
- ret_dict['name'] = arg_osimage_facts['name']
- ret_dict['size'] = arg_osimage_facts['size']
- ret_dict['type'] = arg_osimage_facts['type']
- # ret_dict['arch'] = arg_osimage_facts['architecture']
- ret_dict['sep_id'] = arg_osimage_facts['sepId']
- ret_dict['pool'] = arg_osimage_facts['pool']
- ret_dict['state'] = arg_osimage_facts['status']
-
- return ret_dict
-
-def decort_osimage_parameters():
- """Build and return a dictionary of parameters expected by decort_osimage module in a form accepted
- by AnsibleModule utility class."""
-
- return dict(
- app_id=dict(type='str',
- required=False,
- fallback=(env_fallback, ['DECORT_APP_ID'])),
- app_secret=dict(type='str',
- required=False,
- fallback=(env_fallback, ['DECORT_APP_SECRET']),
- no_log=True),
- authenticator=dict(type='str',
- required=True,
- choices=['legacy', 'oauth2', 'jwt']),
- controller_url=dict(type='str', required=True),
- image_name=dict(type='str', required=True),
- jwt=dict(type='str',
- required=False,
- fallback=(env_fallback, ['DECORT_JWT']),
- no_log=True),
- oauth2_url=dict(type='str',
+ 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):
+ """Package a dictionary of OS image according to the decort_osimage module specification. This
+ dictionary will be returned to the upstream Ansible engine at the completion of the module run.
+
+ @param arg_osimage_facts: dictionary with OS image facts as returned by API call to .../images/list
+ @param arg_check_mode: boolean that tells if this Ansible module is run in check mode.
+
+ @return: dictionary with OS image specs populated from arg_osimage_facts.
+ """
+
+ ret_dict = dict(id=0,
+ name="none",
+ size=0,
+ type="none",
+ state="CHECK_MODE", )
+
+ if arg_check_mode:
+ # in check mode return immediately with the default values
+ return ret_dict
+
+ if arg_osimage_facts is None:
+ # if void facts provided - change state value to ABSENT and return
+ ret_dict['state'] = "ABSENT"
+ return ret_dict
+
+ ret_dict['id'] = arg_osimage_facts['id']
+ ret_dict['name'] = arg_osimage_facts['name']
+ ret_dict['size'] = arg_osimage_facts['size']
+ ret_dict['type'] = arg_osimage_facts['type']
+ # ret_dict['arch'] = arg_osimage_facts['architecture']
+ ret_dict['sep_id'] = arg_osimage_facts['sepId']
+ ret_dict['pool'] = arg_osimage_facts['pool']
+ ret_dict['state'] = arg_osimage_facts['status']
+ ret_dict['linkto'] = arg_osimage_facts['linkTo']
+ return ret_dict
+
+
+ def decort_osimage_parameters():
+ """Build and return a dictionary of parameters expected by decort_osimage module in a form accepted
+ by AnsibleModule utility class."""
+
+ return dict(
+ app_id=dict(type='str',
required=False,
- fallback=(env_fallback, ['DECORT_OAUTH2_URL'])),
- password=dict(type='str',
+ fallback=(env_fallback, ['DECORT_APP_ID'])),
+ app_secret=dict(type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_APP_SECRET']),
+ no_log=True),
+ authenticator=dict(type='str',
+ required=True,
+ choices=['legacy', 'oauth2', 'jwt']),
+ controller_url=dict(type='str', required=True),
+ jwt=dict(type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_JWT']),
+ no_log=True),
+ oauth2_url=dict(type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_OAUTH2_URL'])),
+ password=dict(type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_PASSWORD']),
+ no_log=True),
+ pool=dict(type='str', required=False, default=""),
+ sep_id=dict(type='int', required=False, default=0),
+ account_name=dict(type='str', required=False),
+ account_Id=dict(type='int', required=False),
+ user=dict(type='str',
required=False,
- fallback=(env_fallback, ['DECORT_PASSWORD']),
- no_log=True),
- pool=dict(type='str', required=False, default=""),
- sep_id=dict(type='int', required=False, default=0),
- account_name=dict(type='str', required=True),
- user=dict(type='str',
- required=False,
- fallback=(env_fallback, ['DECORT_USER'])),
- vdc_id=dict(type='int', required=False, default=0),
- verify_ssl=dict(type='bool', required=False, default=True),
- workflow_callback=dict(type='str', required=False),
- workflow_context=dict(type='str', required=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
+ fallback=(env_fallback, ['DECORT_USER'])),
+ verify_ssl=dict(type='bool', required=False, default=True),
+ workflow_callback=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),
+ )
+
def main():
- module_parameters = decort_osimage_parameters()
+ module_parameters = decort_osimage.decort_osimage_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
@@ -273,30 +504,67 @@ def main():
],
)
- decon = DecortController(amodule)
+ decon = decort_osimage(amodule)
+
+ if amodule.params['image_name'] or amodule.params['image_id']:
+ image_id, image_facts = decort_osimage.decort_image_find(decon, amodule)
+ decon.validated_image_id = decort_osimage.decort_osimage_package_facts(image_facts)['id']
+ 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)
+
+ 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)
+
+
+ if decon.validated_image_id:
+ if decort_osimage.decort_osimage_package_facts(image_facts)['linkto'] != decon.validated_image_id:
+ 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)
- # we need account ID to locate OS images - find the account by the specified name and get its ID
- validated_account_id, _ = decon.account_find(amodule.params['account_name'])
- if validated_account_id == 0:
- # we failed either to find or access the specified account - fail the module
- decon.result['failed'] = True
- decon.result['changed'] = False
- decon.result['msg'] = ("Cannot find account '{}'").format(amodule.params['account_name'])
- 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,
- sepid=amodule.params['sep_id'],
- pool=amodule.params['pool'])
if decon.result['failed'] == True:
# we failed to find the specified image - fail the module
decon.result['changed'] = False
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)
-
+
if __name__ == "__main__":
main()
diff --git a/module_utils/decort_utils.py b/module_utils/decort_utils.py
index e86f6c8..bb378c4 100644
--- a/module_utils/decort_utils.py
+++ b/module_utils/decort_utils.py
@@ -1247,26 +1247,25 @@ class DecortController(object):
def image_find(self, image_id, image_name, account_id, rg_id=0, sepid=0, pool=""):
"""Locates 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 images in status CREATED are
+ optionally SEP ID and/or pool name. Also note that only images in status CREATED are
returned.
@param (string) image_id: ID of the OS image to find. If non-zero ID is specified, then
image_name is ignored.
@param (string) image_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,
+ @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
+ @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
+ @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
+ @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'], "image_find")
if image_id > 0:
@@ -1292,7 +1291,7 @@ class DecortController(object):
for image_record in images_list:
if image_record['name'] == image_name and image_record['status'] == "CREATED":
if sepid == 0 and pool == "":
- # if no filtering by SEP ID or pool name is requested, return the first match
+ # if no filtering by SEP ID or pool name is requested, return the first match
return image_record['id'], image_record
# if positive SEP ID and/or non-emtpy pool name are passed, match by them
full_match = True
@@ -1302,6 +1301,7 @@ class DecortController(object):
full_match = False
if full_match:
return image_record['id'], image_record
+ self.result['failed'] = False
self.result['failed'] = True
self.result['msg'] = ("Failed to find OS image by name '{}', SEP ID {}, pool '{}' for "
@@ -1310,6 +1310,136 @@ class DecortController(object):
account_id)
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
###################################