Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
|
e537eadda6 | 5 days ago |
|
5f3df12742 | 2 months ago |
|
6b102946de | 2 months ago |
|
45355b3dd3 | 2 months ago |
|
54c306b13b | 2 months ago |
@ -1,36 +0,0 @@
|
|||||||
---
|
|
||||||
#
|
|
||||||
# DECORT kvmvm module example
|
|
||||||
#
|
|
||||||
- hosts: ansible_master
|
|
||||||
tasks:
|
|
||||||
- name: create a VM named cloud-init_example
|
|
||||||
decort_kvmvm:
|
|
||||||
name: affinity_example
|
|
||||||
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"
|
|
||||||
rg_id: # Resource group id
|
|
||||||
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"
|
|
||||||
aff_lable: "Affinity lable"
|
|
||||||
tag:
|
|
||||||
- key: bd
|
|
||||||
value: main
|
|
||||||
aff_rule:
|
|
||||||
- key: app
|
|
||||||
value: main
|
|
||||||
topology: compute
|
|
||||||
policy: REQUIRED
|
|
||||||
mode: EQ
|
|
||||||
state: present
|
|
||||||
delegate_to: localhost
|
|
||||||
register: simple_vm
|
|
@ -1,36 +0,0 @@
|
|||||||
---
|
|
||||||
#
|
|
||||||
# DECORT kvmvm module example
|
|
||||||
#
|
|
||||||
- hosts: ansible_master
|
|
||||||
tasks:
|
|
||||||
- name: create a VM named cloud-init_example
|
|
||||||
decort_kvmvm:
|
|
||||||
name: anti-affinity_example
|
|
||||||
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"
|
|
||||||
rg_id: # Resource group id
|
|
||||||
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"
|
|
||||||
aff_lable: "Anti affinity lable"
|
|
||||||
tag:
|
|
||||||
- key: bd
|
|
||||||
value: main
|
|
||||||
aaff_rule:
|
|
||||||
- key: app
|
|
||||||
value: main
|
|
||||||
topology: compute
|
|
||||||
policy: REQUIRED
|
|
||||||
mode: ANY
|
|
||||||
state: present
|
|
||||||
delegate_to: localhost
|
|
||||||
register: simple_vm
|
|
@ -1,38 +0,0 @@
|
|||||||
#
|
|
||||||
# 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: |
|
|
||||||
<div>
|
|
||||||
Hello World!
|
|
||||||
</div>
|
|
||||||
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
|
|
@ -1,157 +1,38 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
#
|
|
||||||
# Digital Enegry Cloud Orchestration Technology (DECORT) modules for Ansible
|
|
||||||
# Copyright: (c) 2018-2021 Digital Energy Cloud Solutions LLC
|
|
||||||
#
|
|
||||||
# Apache License 2.0 (see http://www.apache.org/licenses/LICENSE-2.0.txt)
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
DOCUMENTATION = r'''
|
||||||
# Author: Sergey Shubin (sergey.shubin@digitalenergy.online)
|
|
||||||
#
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
---
|
||||||
module: decort_jwt
|
module: decort_jwt
|
||||||
short_description: Obtain access token to be used for authentication to DECORT cloud controller
|
|
||||||
description:
|
|
||||||
- Obtain JWT (JSON Web Token) from the specified Oauth2 provider. This JWT can be used in subsequent DECS modules'
|
|
||||||
invocations to authenticate them to the DECS cloud controller.
|
|
||||||
version_added: "2.4"
|
|
||||||
author: "Sergey Shubin (sergey.shubin@digitalenergy.online)"
|
|
||||||
notes:
|
|
||||||
- Environment variables can be used to pass parameters to the module (see options below for details).
|
|
||||||
- Specified Oauth2 provider must be trusted by the DECORT cloud controller on which JWT will be used.
|
|
||||||
- 'If you register module output as I(my_jwt), the JWT value is accessed as I(my_jwt.jwt)'
|
|
||||||
requirements:
|
|
||||||
- python >= 2.6
|
|
||||||
- PyJWT module
|
|
||||||
- requests module
|
|
||||||
- decort_utils utility library (module)
|
|
||||||
- DECORT cloud platform version 3.6.1 or higher
|
|
||||||
options:
|
|
||||||
app_id:
|
|
||||||
description:
|
|
||||||
- 'Application ID for authenticating to the Oauth2 provider specified in I(oauth2_url).'
|
|
||||||
- 'If not found in the playbook or command line arguments, the value will be taken from DECORT_APP_ID
|
|
||||||
environment variable.'
|
|
||||||
required: no
|
|
||||||
app_secret:
|
|
||||||
description:
|
|
||||||
- 'Application API secret used for authenticating to the Oauth2 provider specified in I(oauth2_url).'
|
|
||||||
- 'If not found in the playbook or command line arguments, the value will be taken from DECORT_APP_SECRET
|
|
||||||
environment variable.'
|
|
||||||
required: no
|
|
||||||
oauth2_url:
|
|
||||||
description:
|
|
||||||
- 'URL of the oauth2 authentication provider to obtain JWT from.'
|
|
||||||
- If not specified in the playbook, the value will be taken from DECORT_OAUTH2_URL environment variable.
|
|
||||||
validity:
|
|
||||||
description:
|
|
||||||
- Validity of the JWT in seconds. Default value is 3600 (one hour).
|
|
||||||
required: no
|
|
||||||
verify_ssl:
|
|
||||||
description:
|
|
||||||
- 'Controls SSL verification mode when making API calls to DECS controller. Set it to False if you
|
|
||||||
want to disable SSL certificate verification.'
|
|
||||||
- `Intended use case is when you run module in a trusted environment that uses self-signed certificates.
|
|
||||||
Note that disabling SSL verification in any other scenario can lead to security issues, so please use
|
|
||||||
with caution.'
|
|
||||||
default: True
|
|
||||||
required: no
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
- name: Obtain JWT and store it as my_jwt for authenticating subsequent task to DECORT cloud controller
|
|
||||||
decort_jwt:
|
|
||||||
app_id: "{{ my_app_id }}"
|
|
||||||
app_secret: "{{ my_app_secret }}"
|
|
||||||
oauth2_url: https://sso.decs.online
|
|
||||||
delegate_to: localhost
|
|
||||||
register: my_jwt
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home).
|
||||||
jwt:
|
|
||||||
description: JSON Web Token that can be used to access DECS cloud controller
|
|
||||||
returned: always
|
|
||||||
type: string
|
|
||||||
sample: None
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils.basic import env_fallback
|
from ansible.module_utils.decort_utils import DecortController
|
||||||
|
|
||||||
def decort_jwt_parameters():
|
|
||||||
"""Build and return a dictionary of parameters expected by decort_jwt module in a form accepted
|
|
||||||
by AnsibleModule utility class"""
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
app_id=dict(type='str',
|
|
||||||
required=True,
|
|
||||||
fallback=(env_fallback, ['DECORT_APP_ID'])),
|
|
||||||
app_secret=dict(type='str',
|
|
||||||
required=True,
|
|
||||||
fallback=(env_fallback, ['DECORT_APP_SECRET']),
|
|
||||||
no_log=True),
|
|
||||||
oauth2_url=dict(type='str',
|
|
||||||
required=True,
|
|
||||||
fallback=(env_fallback, ['DECORT_OAUTH2_URL'])),
|
|
||||||
validity=dict(type='int',
|
|
||||||
required=False,
|
|
||||||
default=3600),
|
|
||||||
verify_ssl=dict(type='bool', required=False, default=True),
|
|
||||||
workflow_callback=dict(type='str', required=False),
|
|
||||||
workflow_context=dict(type='str', required=False),
|
|
||||||
)
|
|
||||||
|
|
||||||
def main():
|
class DecortJWT(DecortController):
|
||||||
module_parameters = decort_jwt_parameters()
|
def __init__(self):
|
||||||
|
super().__init__(AnsibleModule(**self.amodule_init_args))
|
||||||
|
|
||||||
amodule = AnsibleModule(argument_spec=module_parameters,
|
@property
|
||||||
supports_check_mode=True,)
|
def amodule_init_args(self) -> dict:
|
||||||
|
amodule_init_args = self.common_amodule_init_args
|
||||||
|
amodule_argument_spec = amodule_init_args['argument_spec']
|
||||||
|
del amodule_argument_spec['controller_url']
|
||||||
|
del amodule_argument_spec['jwt']
|
||||||
|
amodule_argument_spec['authenticator']['choices'].remove('jwt')
|
||||||
|
|
||||||
result = {'failed': False, 'changed': False}
|
return amodule_init_args
|
||||||
|
|
||||||
token_get_url = amodule.params['oauth2_url'] + "/v1/oauth/access_token"
|
def run(self):
|
||||||
req_data = dict(grant_type="client_credentials",
|
self.result['jwt'] = self.jwt
|
||||||
client_id=amodule.params['app_id'],
|
self.amodule.exit_json(**self.result)
|
||||||
client_secret=amodule.params['app_secret'],
|
|
||||||
response_type="id_token",
|
|
||||||
validity=amodule.params['validity'],)
|
|
||||||
# TODO: Need standard code snippet to handle server timeouts gracefully
|
|
||||||
# Consider a few retries before giving up or use requests.Session & requests.HTTPAdapter
|
|
||||||
# see https://stackoverflow.com/questions/15431044/can-i-set-max-retries-for-requests-request
|
|
||||||
|
|
||||||
# catch requests.exceptions.ConnectionError to handle incorrect oauth2_url case
|
|
||||||
try:
|
|
||||||
token_get_resp = requests.post(token_get_url, data=req_data, verify=amodule.params['verify_ssl'])
|
|
||||||
except requests.exceptions.ConnectionError as errco:
|
|
||||||
result.update(failed=True)
|
|
||||||
result['msg'] = "Failed to connect to {}: {}".format(token_get_url, errco)
|
|
||||||
amodule.fail_json(**result)
|
|
||||||
except requests.exceptions.Timeout as errti:
|
|
||||||
result.update(failed=True)
|
|
||||||
result['msg'] = "Timeout when trying to connect to {}: {}".format(token_get_url, errti)
|
|
||||||
amodule.fail_json(**result)
|
|
||||||
|
|
||||||
# alternative -- if resp == requests.codes.ok
|
def main():
|
||||||
if token_get_resp.status_code != 200:
|
DecortJWT().run()
|
||||||
result.update(failed=True)
|
|
||||||
result['msg'] = "Failed to obtain JWT access token from oauth2_url {} for app_id {}: {} {}".format(
|
|
||||||
token_get_url, amodule.params['app_id'],
|
|
||||||
token_get_resp.status_code, token_get_resp.reason)
|
|
||||||
amodule.fail_json(**result)
|
|
||||||
|
|
||||||
# Common return values: https://docs.ansible.com/ansible/2.3/common_return_values.html
|
|
||||||
result['jwt'] = token_get_resp.content.decode('utf8')
|
|
||||||
amodule.exit_json(**result)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,157 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: decort_snapshot
|
||||||
|
|
||||||
|
description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home).
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.decort_utils import DecortController
|
||||||
|
|
||||||
|
|
||||||
|
class DecortSnapshot(DecortController):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(AnsibleModule(**self.amodule_init_args))
|
||||||
|
self.check_amodule_args()
|
||||||
|
|
||||||
|
self.aparams_label = self.aparams['label']
|
||||||
|
self.aparams_vm_id = self.aparams['vm_id']
|
||||||
|
|
||||||
|
vm_id, vm_facts, _ = self._compute_get_by_id(
|
||||||
|
comp_id=self.aparams_vm_id,
|
||||||
|
)
|
||||||
|
if not vm_id:
|
||||||
|
self.message(f'VM {self.aparams_vm_id} not found')
|
||||||
|
self.exit(fail=True)
|
||||||
|
|
||||||
|
self.vm_name = vm_facts['name']
|
||||||
|
self.vm_snapshots = vm_facts['snapSets']
|
||||||
|
self.vm_snapshot_labels = [
|
||||||
|
snapshot['label'] for snapshot in self.vm_snapshots
|
||||||
|
]
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.aparams_label is not None
|
||||||
|
and self.aparams_label not in self.vm_snapshot_labels
|
||||||
|
and self.aparams['state'] is None
|
||||||
|
):
|
||||||
|
self.message(
|
||||||
|
f'Snapshot {self.aparams_label} '
|
||||||
|
f'not found for VM {self.aparams_vm_id}'
|
||||||
|
)
|
||||||
|
self.exit(fail=True)
|
||||||
|
|
||||||
|
self.new_snapshot_label = None
|
||||||
|
if self.aparams['state'] == 'present':
|
||||||
|
if self.aparams_label is None:
|
||||||
|
self.new_snapshot_label = (
|
||||||
|
f'{self.vm_name}_{self.sec_to_dt_str(time.time())}'
|
||||||
|
)
|
||||||
|
elif self.aparams_label not in self.vm_snapshot_labels:
|
||||||
|
self.new_snapshot_label = self.aparams_label
|
||||||
|
|
||||||
|
@property
|
||||||
|
def amodule_init_args(self) -> dict:
|
||||||
|
return self.pack_amodule_init_args(
|
||||||
|
argument_spec=dict(
|
||||||
|
label=dict(
|
||||||
|
type='str',
|
||||||
|
),
|
||||||
|
state=dict(
|
||||||
|
type='str',
|
||||||
|
choices=(
|
||||||
|
'absent',
|
||||||
|
'present',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
usage=dict(
|
||||||
|
type='bool',
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
vm_id=dict(
|
||||||
|
type='int',
|
||||||
|
required=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
required_if=[
|
||||||
|
('state', 'absent', ('label',)),
|
||||||
|
],
|
||||||
|
required_one_of=[
|
||||||
|
('label', 'state'),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def check_amodule_args(self):
|
||||||
|
check_error = False
|
||||||
|
if (
|
||||||
|
self.aparams['state'] == 'absent'
|
||||||
|
and self.aparams['usage']
|
||||||
|
):
|
||||||
|
self.message(
|
||||||
|
'Parameter "usage" is not supported when deleting snapshot'
|
||||||
|
)
|
||||||
|
check_error = True
|
||||||
|
|
||||||
|
if check_error:
|
||||||
|
self.exit(fail=True)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.get_info(first_run=True)
|
||||||
|
self.change()
|
||||||
|
self.exit()
|
||||||
|
|
||||||
|
def get_info(self, first_run: bool = False):
|
||||||
|
if not first_run:
|
||||||
|
self.vm_snapshots = self.snapshot_list(
|
||||||
|
compute_id=self.aparams_vm_id,
|
||||||
|
)
|
||||||
|
label = self.new_snapshot_label or self.aparams_label
|
||||||
|
for snapshot in self.vm_snapshots:
|
||||||
|
if snapshot['label'] == label:
|
||||||
|
self.facts = snapshot
|
||||||
|
if self.aparams['usage']:
|
||||||
|
self.facts['stored'] = self.get_snapshot_usage()
|
||||||
|
self.facts['vm_id'] = self.aparams_vm_id
|
||||||
|
break
|
||||||
|
|
||||||
|
def change(self):
|
||||||
|
match self.aparams['state']:
|
||||||
|
case 'present':
|
||||||
|
if self.new_snapshot_label:
|
||||||
|
self.create()
|
||||||
|
case 'absent':
|
||||||
|
if self.aparams_label in self.vm_snapshot_labels:
|
||||||
|
self.delete()
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
self.snapshot_create(
|
||||||
|
compute_id=self.aparams_vm_id,
|
||||||
|
label=self.new_snapshot_label,
|
||||||
|
)
|
||||||
|
self.get_info()
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
self.snapshot_delete(
|
||||||
|
compute_id=self.aparams_vm_id,
|
||||||
|
label=self.aparams_label,
|
||||||
|
)
|
||||||
|
self.facts = {}
|
||||||
|
|
||||||
|
def get_snapshot_usage(self) -> int:
|
||||||
|
label = self.new_snapshot_label or self.aparams_label
|
||||||
|
common_snapshots_usage_info, _ = self.snapshot_usage(
|
||||||
|
compute_id=self.aparams_vm_id,
|
||||||
|
label=label,
|
||||||
|
)
|
||||||
|
return common_snapshots_usage_info['stored']
|
||||||
|
|
||||||
|
def main():
|
||||||
|
DecortSnapshot().run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue