This commit is contained in:
2024-12-26 12:37:38 +03:00
parent 6b102946de
commit 5f3df12742
36 changed files with 11025 additions and 1259 deletions

View File

@@ -13,8 +13,9 @@ from ansible.module_utils.decort_utils import *
class decort_bservice(DecortController):
def __init__(self,arg_amodule):
super(decort_bservice, self).__init__(arg_amodule)
def __init__(self):
super(decort_bservice, self).__init__(AnsibleModule(**self.amodule_init_args))
arg_amodule = self.amodule
validated_acc_id = 0
validated_rg_id = 0
@@ -147,70 +148,66 @@ class decort_bservice(DecortController):
ret_dict['account_id'] = self.bservice_info['accountId']
ret_dict['groups'] = self.bservice_info['groups']
return ret_dict
@staticmethod
def build_parameters():
return dict(
account_id=dict(type='int', required=False),
account_name=dict(type='str', required=False, default=''),
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),
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),
state=dict(type='str',
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
),
account_name=dict(
type='str',
default='',
),
state=dict(
type='str',
default='present',
choices=['absent', 'disabled', 'enabled', 'present','check']),
started=dict(type='bool', required=False, default=True),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
name=dict(type='str', required=False, default=''),
sshuser=dict(type='str', required=False,default=None),
sshkey=dict(type='str', required=False,default=None),
id=dict(type='int', required=False, default=0),
rg_id=dict(type='int', default=0),
rg_name=dict(type='str',default=""),
verify_ssl=dict(type='bool', required=False, default=True),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),)
choices=[
'absent',
'disabled',
'enabled',
'present',
'check',
],
),
started=dict(
type='bool',
default=True,
),
name=dict(
type='str',
default='',
),
sshuser=dict(
type='str',
),
sshkey=dict(
type='str',
),
id=dict(
type='int',
default=0,
),
rg_id=dict(
type='int',
default=0,
),
rg_name=dict(
type='str',
default='',
),
),
supports_check_mode=True,
required_one_of=[
('id', 'name'),
('rg_id', 'rg_name'),
],
)
def main():
module_parameters = decort_bservice.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
required_one_of=[
['id', 'name'],
['rg_id','rg_name']
],
)
subj = decort_bservice(amodule)
subj = decort_bservice()
amodule = subj.amodule
if amodule.params['state'] == 'check':
subj.result['changed'] = False

View File

@@ -14,8 +14,9 @@ from ansible.module_utils.decort_utils import *
class decort_disk(DecortController):
def __init__(self,arg_amodule):
super(decort_disk, self).__init__(arg_amodule)
def __init__(self):
super(decort_disk, self).__init__(AnsibleModule(**self.amodule_init_args))
arg_amodule = self.amodule
validated_acc_id = 0
validated_acc_info = None
@@ -176,98 +177,136 @@ class decort_disk(DecortController):
ret_dict['iotune'] = self.disk_info['iotune']
return ret_dict
@staticmethod
def build_parameters():
"""Build and return a dictionary of parameters expected by decort_disk module in a form accepted
by AnsibleModule utility class."""
return dict(
account_id=dict(type='int', required=False, default=0),
account_name=dict(type='str', required=False, default=''),
description=dict(type='str', required=False, default='Disk by decort_disk'),
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),
id=dict(type='int', required=False, default=0),
name=dict(type='str', required=False),
force_detach=dict(type='bool', required=False, default=False),
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),
place_with=dict(type='int', default=0),
pool=dict(type='str', default=''),
sep_id=dict(type='int', default=0),
size=dict(type='int'),
type=dict(type='str',
required=False,
default="D",
choices=['B', 'D', 'T']),
iops=dict(type='int',required=False,default=2000),
limitIO=dict(type='dict',
options=dict(
total_bytes_sec=dict(required=False,type='int'),
read_bytes_sec=dict(required=False,type='int'),
write_bytes_sec=dict(required=False,type='int'),
total_iops_sec=dict(required=False,type='int'),
read_iops_sec=dict(required=False,type='int'),
write_iops_sec=dict(required=False,type='int'),
total_bytes_sec_max=dict(required=False,type='int'),
read_bytes_sec_max=dict(required=False,type='int'),
write_bytes_sec_max=dict(required=False,type='int'),
total_iops_sec_max=dict(required=False,type='int'),
read_iops_sec_max=dict(required=False,type='int'),
write_iops_sec_max=dict(required=False,type='int'),
size_iops_sec=dict(required=False,type='int'),)),
permanently=dict(type='bool', required=False, default=False),
shareable=dict(type='bool', required=False, default=False),
reason=dict(type='str', required=False,default='Managed by Ansible decort_disk'),
state=dict(type='str',
default='present',
choices=['absent', 'present']),
user=dict(type='str',
required=False,
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),
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
default=0,
),
account_name=dict(
type='str',
default='',
),
description=dict(
type='str',
default='Disk by decort_disk',
),
id=dict(
type='int',
default=0,
),
name=dict(
type='str',
),
force_detach=dict(
type='bool',
default=False,
),
place_with=dict(
type='int',
default=0,
),
pool=dict(
type='str',
default='',
),
sep_id=dict(
type='int',
default=0,
),
size=dict(
type='int',
),
type=dict(
type='str',
default='D',
choices=[
'B',
'D',
'T',
],
),
iops=dict(
type='int',
default=2000,
),
limitIO=dict(
type='dict',
options=dict(
total_bytes_sec=dict(
type='int',
),
read_bytes_sec=dict(
type='int',
),
write_bytes_sec=dict(
type='int',
),
total_iops_sec=dict(
type='int',
),
read_iops_sec=dict(
type='int',
),
write_iops_sec=dict(
type='int',
),
total_bytes_sec_max=dict(
type='int',
),
read_bytes_sec_max=dict(
type='int',
),
write_bytes_sec_max=dict(
type='int',
),
total_iops_sec_max=dict(
type='int',
),
read_iops_sec_max=dict(
type='int',
),
write_iops_sec_max=dict(
type='int',
),
size_iops_sec=dict(
type='int',
),
),
),
permanently=dict(
type='bool',
default=False,
),
shareable=dict(
type='bool',
default=False,
),
reason=dict(
type='str',
default='Managed by Ansible decort_disk',
),
state=dict(
type='str',
default='present',
choices=[
'absent',
'present',
],
),
),
supports_check_mode=True,
required_one_of=[
('id', 'name'),
],
)
def main():
module_parameters = decort_disk.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
required_one_of=[
['id', 'name'],
],
)
decon = decort_disk(amodule)
decon = decort_disk()
amodule = decon.amodule
#
#Full range of Disk status is as follows:
#

View File

@@ -13,8 +13,10 @@ from ansible.module_utils.decort_utils import *
class decort_group(DecortController):
def __init__(self,arg_amodule):
super(decort_group, self).__init__(arg_amodule)
def __init__(self):
super(decort_group, self).__init__(AnsibleModule(**self.amodule_init_args))
arg_amodule = self.amodule
self.group_should_exist = False
validated_bservice_id = None
#find and validate B-Service
@@ -169,95 +171,106 @@ class decort_group(DecortController):
ret_dict['state'] = self.group_info['status']
ret_dict['Computes'] = self.group_info['computes']
return ret_dict
@staticmethod
def build_parameters():
return dict(
account_id=dict(type='int', required=False),
account_name=dict(type='str', required=False, default=''),
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),
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),
state=dict(type='str',
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
),
account_name=dict(
type='str',
default='',
),
state=dict(
type='str',
default='present',
choices=['absent', 'started', 'stopped', 'present','check']),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
name=dict(type='str'),
id=dict(type='int', required=False),
image_id=dict(type='int', required=False),
image_name=dict(type='str', required=False),
driver=dict(type='str', required=False, choices=['KVM_X86', 'SVA_KVM_X86'], default="KVM_X86"),
boot_disk=dict(type='int', required=False),
bservice_id=dict(type='int', required=True),
count=dict(type='int'),
timeoutStart=dict(type='int', required=False),
role=dict(type='str', required=False),
cpu=dict(type='int', required=False),
ram=dict(type='int', required=False),
networks=dict(
type='list', elements='dict',
options=dict(
type=dict(
type='str',
required=True,
choices=['VINS', 'EXTNET']
),
id=dict(
type='int',
required=True
choices=[
'absent',
'started',
'stopped',
'present',
'check',
],
),
name=dict(
type='str',
),
id=dict(
type='int',
),
image_id=dict(
type='int',
),
image_name=dict(
type='str',
),
driver=dict(
type='str',
choices=[
'KVM_X86',
'SVA_KVM_X86',
],
default='KVM_X86',
),
boot_disk=dict(
type='int',
),
bservice_id=dict(
type='int',
required=True,
),
count=dict(
type='int',
),
timeoutStart=dict(
type='int',
),
role=dict(
type='str',
),
cpu=dict(
type='int',
),
ram=dict(
type='int',
),
networks=dict(
type='list',
elements='dict',
options=dict(
type=dict(
type='str',
required=True,
choices=[
'VINS',
'EXTNET',
]
),
id=dict(
type='int',
required=True,
)
)
)
),
),
verify_ssl=dict(type='bool', required=False, default=True),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),)
supports_check_mode=True,
required_one_of=[
('id', 'name'),
('id', 'networks'),
('id', 'count'),
('id', 'cpu'),
('id', 'ram'),
('id', 'boot_disk'),
('id', 'image_id'),
('id', 'driver'),
],
)
def main():
module_parameters = decort_group.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
required_one_of=[
['id', 'name'],
['id', 'networks'],
['id', 'count'],
['id', 'cpu'],
['id', 'ram'],
['id', 'boot_disk'],
['id', 'image_id'],
['id', 'driver'],
],
)
subj = decort_group(amodule)
subj = decort_group()
amodule = subj.amodule
if amodule.params['state'] == 'check':
subj.result['changed'] = False

View File

@@ -7,76 +7,32 @@ module: decort_jwt
description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home).
'''
import requests
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"""
class DecortJWT(DecortController):
def __init__(self):
super().__init__(AnsibleModule(**self.amodule_init_args))
@property
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')
return amodule_init_args
def run(self):
self.result['jwt'] = self.jwt
self.amodule.exit_json(**self.result)
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():
module_parameters = decort_jwt_parameters()
DecortJWT().run()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,)
result = {'failed': False, 'changed': False}
token_get_url = amodule.params['oauth2_url'] + "/v1/oauth/access_token"
req_data = dict(grant_type="client_credentials",
client_id=amodule.params['app_id'],
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
if token_get_resp.status_code != 200:
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__':
main()

View File

@@ -14,8 +14,9 @@ from copy import deepcopy
class decort_k8s(DecortController):
def __init__(self,arg_amodule):
super(decort_k8s, self).__init__(arg_amodule)
def __init__(self):
super(decort_k8s, self).__init__(AnsibleModule(**self.amodule_init_args))
arg_amodule = self.amodule
validated_acc_id = 0
validated_rg_id = 0
@@ -253,146 +254,196 @@ class decort_k8s(DecortController):
return
@staticmethod
def build_parameters():
return dict(
account_id=dict(type='int', required=False),
account_name=dict(type='str', required=False, default=''),
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),
# datacenter=dict(type='str', required=False, default=''),
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),
quotas=dict(type='dict', required=False),
state=dict(type='str',
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
),
account_name=dict(
type='str',
default='',
),
quotas=dict(
type='dict',
),
state=dict(
type='str',
default='present',
choices=['absent', 'disabled', 'enabled', 'present','check']),
permanent=dict(type='bool', default=False),
started=dict(type='bool', default=True),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
name=dict(type='str', required=False, default=""),
id=dict(type='int', required=False),
getConfig=dict(type='bool',required=False, default=False),
rg_id=dict(type='int', default=0),
rg_name=dict(type='str',default=""),
vins_id=dict(type='int', required=False,default=None),
k8ci_id=dict(type='int'),
network_plugin=dict(type='str',required=False,default="flannel"),
master_count=dict(type='int', default=1),
master_cpu=dict(type='int', default=2),
master_ram=dict(type='int', default=2048),
master_disk=dict(type='int', default=10),
master_sepid=dict(type='int', required=False, default=None),
master_pool=dict(type='str', required=False, default=None),
workers=dict(
type='list',
elements='dict',
options=dict(
name=dict(
type='str',
required=True,
),
num=dict(
type='int',
),
cpu=dict(
type='int',
),
ram=dict(
type='int',
),
disk=dict(
type='int',
),
sep_id=dict(
type='int',
),
pool=dict(
type='str',
),
annotations=dict(
type='list',
elements='str',
),
ci_user_data=dict(
type='dict',
),
labels=dict(
type='list',
elements='str',
),
taints=dict(
type='list',
elements='str',
),
chipset=dict(
type='str',
choices=['Q35', 'i440fx'],
choices=[
'absent',
'disabled',
'enabled',
'present',
'check',
],
),
permanent=dict(
type='bool',
default=False,
),
started=dict(
type='bool',
default=True,
),
name=dict(
type='str',
default='',
),
id=dict(
type='int',
),
getConfig=dict(
type='bool',
default=False,
),
rg_id=dict(
type='int',
default=0,
),
rg_name=dict(
type='str',
default='',
),
vins_id=dict(
type='int',
),
k8ci_id=dict(
type='int',
),
network_plugin=dict(
type='str',
default='flannel',
),
master_count=dict(
type='int',
default=1,
),
master_cpu=dict(
type='int',
default=2,
),
master_ram=dict(
type='int',
default=2048,
),
master_disk=dict(
type='int',
default=10,
),
master_sepid=dict(
type='int',
),
master_pool=dict(
type='str',
),
workers=dict(
type='list',
elements='dict',
options=dict(
name=dict(
type='str',
required=True,
),
num=dict(
type='int',
),
cpu=dict(
type='int',
),
ram=dict(
type='int',
),
disk=dict(
type='int',
),
sep_id=dict(
type='int',
),
pool=dict(
type='str',
),
annotations=dict(
type='list',
elements='str',
),
ci_user_data=dict(
type='dict',
),
labels=dict(
type='list',
elements='str',
),
taints=dict(
type='list',
elements='str',
),
chipset=dict(
type='str',
choices=['Q35', 'i440fx'],
),
),
),
workers_metadata=dict(
type='bool',
default=False,
),
extnet_id=dict(
type='int',
default=0,
),
description=dict(
type='str',
default='Created by decort ansible module',
),
with_lb=dict(
type='bool',
default=True,
),
ha_lb=dict(
type='bool',
default=False,
),
extnet_only=dict(
type='bool',
default=False,
),
additionalSANs=dict(
type='list',
),
init_conf=dict(
type='dict',
),
cluster_conf=dict(
type='dict',
),
kublet_conf=dict(
type='dict',
),
kubeproxy_conf=dict(
type='dict',
),
join_conf=dict(
type='dict',
),
oidc_cert=dict(
type='raw',
),
master_chipset=dict(
type='str',
choices=['Q35', 'i440fx'],
),
),
workers_metadata=dict(type='bool',required=False,default=False),
extnet_id=dict(type='int', default=0),
description=dict(type='str', default="Created by decort ansible module"),
with_lb=dict(type='bool', default=True),
ha_lb=dict(type='bool', default=False),
extnet_only=dict(type='bool', default=False),
additionalSANs=dict(type='list',required=False, default=None),
init_conf=dict(type='dict', required=False, default=None),
cluster_conf=dict(type='dict', required=False, default=None),
kublet_conf=dict(type='dict', required=False, default=None),
kubeproxy_conf=dict(type='dict', required=False, default=None),
join_conf=dict(type='dict', required=False, default=None),
oidc_cert=dict(type='raw',required=False,default=None),
verify_ssl=dict(type='bool', required=False, default=True),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
master_chipset=dict(
type='str',
choices=['Q35', 'i440fx'],
),
supports_check_mode=True,
required_one_of=[
('id', 'name'),
],
)
def main():
module_parameters = decort_k8s.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
required_one_of=[
['id', 'name'],
],
)
subj = decort_k8s(amodule)
subj = decort_k8s()
amodule = subj.amodule
if amodule.params['state'] == 'check':
subj.result['changed'] = False

View File

@@ -13,9 +13,10 @@ from ansible.module_utils.decort_utils import *
class decort_kvmvm(DecortController):
def __init__(self, arg_amodule):
def __init__(self):
# call superclass constructor first
super(decort_kvmvm, self).__init__(arg_amodule)
super(decort_kvmvm, self).__init__(AnsibleModule(**self.amodule_init_args))
arg_amodule = self.amodule
self.check_amodule_args()
@@ -27,6 +28,7 @@ class decort_kvmvm(DecortController):
self.comp_info = None
self.acc_id = 0
self.rg_id = 0
self.aparam_image = None
validated_acc_id =0
validated_rg_id = 0
@@ -122,17 +124,36 @@ class decort_kvmvm(DecortController):
cannot be implemented using Ansible Argument spec.
"""
# Check parameter "networks" for DPDK type
# Check parameter "networks"
aparam_nets = self.aparams['networks']
if aparam_nets:
check_error = False
net_types = {net['type'] for net in aparam_nets}
DPDK = 'DPDK'
if DPDK in net_types and not net_types.issubset({'DPDK', 'EMPTY'}):
self.message(
'Check for parameter "networks" failed: a compute cannot'
' be connected to a DPDK network and a network of another'
' type at the same time.'
)
# DPDK and other networks
if self.VMNetType.DPDK.value in net_types:
if not net_types.issubset(
{self.VMNetType.DPDK.value, self.VMNetType.EMPTY.value}
):
check_error = True
self.message(
'Check for parameter "networks" failed:'
' a compute cannot be connected to a DPDK network and'
' a network of another type at the same time.'
)
# MTU for non-DPDK networks
for net in aparam_nets:
if (
net['type'] != self.VMNetType.DPDK.value
and net['mtu'] is not None
):
check_error = True
self.message(
'Check for parameter "networks" failed:'
' MTU can be specifed only for DPDK network'
' (remove parameter "mtu" for network'
f' {net["type"]} with ID {net["id"]}).'
)
if check_error:
self.exit(fail=True)
aparam_custom_fields = self.aparams['custom_fields']
@@ -197,17 +218,7 @@ class decort_kvmvm(DecortController):
validated_bdisk_size = self.amodule.params['boot_disk'] or 0
image_id, image_facts = None, None
if (
self.amodule.params['image_id'] is None
and self.amodule.params['image_name'] is None
):
if self.amodule.params['state'] not in ('poweredoff', 'halted'):
self.result['msg'] = (
'"state" parameter for a blank Compute must be either '
'"poweredoff" or "halted".'
)
self.exit(fail=True)
else:
if self.aparam_image:
# either image_name or image_id must be present
if (
self.check_amodule_argument('image_id', abort=False)
@@ -242,7 +253,7 @@ class decort_kvmvm(DecortController):
#
# Once this "feature" is fixed, make sure VM is created according to the actual desired state
#
start_compute = False # change this once a workaround for the aforementioned libvirt "feature" is implemented
start_compute = False # change this once a workaround for the aforementioned libvirt "feature" is implemented
if self.amodule.params['state'] in ('halted', 'poweredoff'):
start_compute = False
@@ -331,8 +342,9 @@ class decort_kvmvm(DecortController):
self.amodule.params['aaff_rule'],
label=self.amodule.params['affinity_label'],)
# NOTE: see NOTE above regarding libvirt "feature" and new VMs created in HALTED state
if self.amodule.params['state'] not in ('halted', 'poweredoff'):
self.compute_powerstate(self.comp_info, 'started')
if self.aparam_image:
if self.amodule.params['state'] not in ('halted', 'poweredoff'):
self.compute_powerstate(self.comp_info, 'started')
if self.aparams['custom_fields'] is None:
custom_fields_disable = True
@@ -352,7 +364,13 @@ class decort_kvmvm(DecortController):
need_custom_fields=True,
)
self.skip_final_get = True
if self.compute_update_args:
self.compute_update(
compute_id=self.comp_info['id'],
**self.compute_update_args,
)
else:
self.skip_final_get = True
return
@@ -446,6 +464,7 @@ class decort_kvmvm(DecortController):
'hp_backed': 'hpBacked',
'numa_affinity': 'numaAffinity',
'description': 'desc',
'auto_start': 'autoStart',
}
for param_name, comp_field_name in params_to_check.items():
aparam_value = self.amodule.params[param_name]
@@ -457,7 +476,6 @@ class decort_kvmvm(DecortController):
return result_args
def package_facts(self, check_mode=False):
"""Package a dictionary of KVM VM facts according to the decort_kvmvm module specification.
This dictionary will be returned to the upstream Ansible engine at the completion of decort_kvmvm
@@ -492,6 +510,7 @@ class decort_kvmvm(DecortController):
hp_backed="",
numa_affinity="",
custom_fields={},
vnc_password="",
)
if check_mode or self.comp_info is None:
@@ -554,14 +573,36 @@ class decort_kvmvm(DecortController):
ret_dict['custom_fields'] = self.comp_info['custom_fields']
ret_dict['vnc_password'] = self.comp_info['vncPasswd']
ret_dict['auto_start'] = self.comp_info['autoStart']
return ret_dict
def check_amodule_args_for_create(self):
# Check for unacceptable parameters for a blank Compute
if (
self.aparams['image_id'] is None
and self.aparams['image_name'] is None
self.aparams['image_id'] is not None
or self.aparams['image_name'] is not None
):
self.aparam_image = True
else:
self.aparam_image = False
if (
self.aparams['state'] is not None
and self.aparams['state'] not in (
'present',
'poweredoff',
'halted',
)
):
self.message(
'Check for parameter "state" failed: '
'state for a blank Compute must be either '
'"present", "poweredoff" or "halted".'
)
self.exit(fail=True)
for parameter in (
'ssh_key',
'ssh_key_user',
@@ -586,130 +627,175 @@ class decort_kvmvm(DecortController):
)
self.exit(fail=True)
@staticmethod
def build_parameters():
"""Build and return a dictionary of parameters expected by decort_kvmvm module in a form
accepted by AnsibleModule utility class.
This dictionary is then used y AnsibleModule class instance to parse and validate parameters
passed to the module from the playbook.
"""
return dict(
account_id=dict(type='int', required=False, default=0),
account_name=dict(type='str', required=False, default=''),
description=dict(type='str', required=False),
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']),
boot_disk=dict(type='int', required=False),
sep_id=dict(type='int', required=False),
pool=dict(type='str', required=False),
controller_url=dict(type='str', required=True),
# count=dict(type='int', required=False, default=1),
cpu=dict(type='int', required=False),
# datacenter=dict(type='str', required=False, default=''),
data_disks=dict(type='list', required=False), # list of integer disk IDs
id=dict(type='int', required=False, default=0),
image_id=dict(type='int', required=False),
image_name=dict(type='str', required=False),
jwt=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_JWT']),
no_log=True),
name=dict(type='str'),
networks=dict(
type='list',
elements='dict',
options=dict(
type=dict(
type='str',
required=True,
choices=[
'VINS',
'EXTNET',
'VFNIC',
'DPDK',
'EMPTY',
],
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
default=0,
),
account_name=dict(
type='str',
default='',
),
description=dict(
type='str',
),
boot_disk=dict(
type='int',
),
sep_id=dict(
type='int',
),
pool=dict(
type='str',
),
controller_url=dict(
type='str',
required=True,
),
cpu=dict(
type='int',
),
data_disks=dict( # list of integer disk IDs
type='list',
),
id=dict(
type='int',
default=0,
),
image_id=dict(
type='int',
),
image_name=dict(
type='str',
),
name=dict(
type='str',
),
networks=dict(
type='list',
elements='dict',
options=dict(
type=dict(
type='str',
required=True,
choices=[
'VINS',
'EXTNET',
'VFNIC',
'DPDK',
'EMPTY',
],
),
id=dict(
type='int',
),
ip_addr=dict(
type='str',
),
mtu=dict(
type='int',
),
),
id=dict(
type='int',
),
ip_addr=dict(
type='str',
),
),
required_if=[
('type', 'VINS', ('id',)),
('type', 'EXTNET', ('id',)),
('type', 'VFNIC', ('id',)),
('type', 'DPDK', ('id',)),
],
),
network_order_changing=dict(
type='bool',
default=False,
),
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),
ram=dict(type='int', required=False),
rg_id=dict(type='int', default=0),
rg_name=dict(type='str', default=""),
ssh_key=dict(type='str', required=False),
ssh_key_user=dict(type='str', required=False),
tag=dict(type='dict', required=False),
affinity_label=dict(type='str', required=False),
aff_rule=dict(type='list', required=False),
aaff_rule=dict(type='list', required=False),
ci_user_data=dict(type='dict', required=False),
state=dict(type='str',
default='present',
choices=['absent', 'paused', 'poweredoff', 'halted', 'poweredon', 'present', 'check']),
tags=dict(type='str', required=False),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
verify_ssl=dict(type='bool', required=False, default=True),
# wait_for_ip_address=dict(type='bool', required=False, default=False),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
chipset=dict(
type='str',
choices=['Q35', 'i440fx']
),
cpu_pin=dict(
type='bool',
),
hp_backed=dict(
type='bool',
),
numa_affinity=dict(
type='str',
choices=['strict', 'loose', 'none'],
),
custom_fields=dict(
type='dict',
options=dict(
fields=dict(
type='dict',
),
disable=dict(
type='bool',
required_if=[
('type', 'VINS', ('id',)),
('type', 'EXTNET', ('id',)),
('type', 'VFNIC', ('id',)),
('type', 'DPDK', ('id',)),
],
),
network_order_changing=dict(
type='bool',
default=False,
),
ram=dict(
type='int',
),
rg_id=dict(
type='int',
default=0,
),
rg_name=dict(
type='str',
default='',
),
ssh_key=dict(
type='str',
),
ssh_key_user=dict(
type='str',
),
tag=dict(
type='dict',
),
affinity_label=dict(
type='str',
),
aff_rule=dict(
type='list',
),
aaff_rule=dict(
type='list',
),
ci_user_data=dict(
type='dict',
),
state=dict(
type='str',
choices=[
'absent',
'paused',
'poweredoff',
'halted',
'poweredon',
'present',
],
),
tags=dict(
type='str',
),
chipset=dict(
type='str',
choices=[
'Q35',
'i440fx',
]
),
cpu_pin=dict(
type='bool',
),
hp_backed=dict(
type='bool',
),
numa_affinity=dict(
type='str',
choices=[
'strict',
'loose',
'none',
],
),
custom_fields=dict(
type='dict',
options=dict(
fields=dict(
type='dict',
),
disable=dict(
type='bool',
),
),
),
auto_start=dict(
type='bool',
)
),
supports_check_mode=True,
required_one_of=[
('id', 'name'),
],
)
def check_amodule_args_for_change(self):
@@ -734,6 +820,17 @@ class decort_kvmvm(DecortController):
)
self.exit(fail=True)
if (
not self.comp_info['imageId']
and self.amodule.params['state'] in ('poweredon', 'paused')
):
self.message(
'Check for parameter "state" failed: '
'state for a blank Compute can not be "poweredon" or "paused".'
)
self.exit(fail=True)
# Workflow digest:
# 1) authenticate to DECORT controller & validate authentication by issuing API call - done when creating DECSController
# 2) check if the VM with the specified id or rg_name:name exists
@@ -747,49 +844,10 @@ class decort_kvmvm(DecortController):
# 6) report result to Ansible
def main():
module_parameters = decort_kvmvm.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
required_one_of=[
['id', 'name'],
],
)
# Initialize DECORT KVM VM instance object
# This object does not necessarily represent an existing KVM VM
subj = decort_kvmvm(amodule)
# handle state=check before any other logic
if amodule.params['state'] == 'check':
subj.result['changed'] = False
if subj.comp_id:
# Compute is found - package facts and report success to Ansible
subj.result['failed'] = False
# _, subj.comp_info, _ = subj.compute_find(comp_id=subj.comp_id)
# _, rg_facts = subj.rg_find(arg_account_id=0, arg_rg_id=subj.rg_id)
subj.result['facts'] = subj.package_facts(amodule.check_mode)
amodule.exit_json(**subj.result)
# we exit the module at this point
else:
subj.result['failed'] = True
subj.result['msg'] = ("Cannot locate Compute name '{}'. Other arguments are: Compute ID {}, "
"RG name '{}', RG ID {}, Account '{}'.").format(amodule.params['name'],
amodule.params['id'],
amodule.params['rg_name'],
amodule.params['rg_id'],
amodule.params['account_name'])
amodule.fail_json(**subj.result)
pass
subj = decort_kvmvm()
amodule = subj.amodule
if subj.comp_id:
subj.check_amodule_args_for_change()
@@ -800,8 +858,14 @@ def main():
elif subj.comp_info['status'] in ("ENABLED", "DISABLED"):
if amodule.params['state'] == 'absent':
subj.destroy()
elif amodule.params['state'] in ('present', 'paused', 'poweredon', 'poweredoff', 'halted'):
subj.compute_powerstate(subj.comp_info, amodule.params['state'])
else:
if amodule.params['state'] in (
'paused', 'poweredon', 'poweredoff', 'halted'
):
subj.compute_powerstate(
comp_facts=subj.comp_info,
target_state=amodule.params['state'],
)
subj.modify(arg_wait_cycles=7)
elif subj.comp_info['status'] == "DELETED":
if amodule.params['state'] in ('present', 'poweredon'):
@@ -830,13 +894,16 @@ def main():
else:
subj.check_amodule_args_for_create()
state = amodule.params['state']
if state is None:
state = 'present'
# Preexisting Compute of specified identity was not found.
# If requested state is 'absent' - nothing to do
if amodule.params['state'] == 'absent':
if state == 'absent':
subj.nop()
elif amodule.params['state'] in ('present', 'poweredon', 'poweredoff', 'halted'):
elif state in ('present', 'poweredon', 'poweredoff', 'halted'):
subj.create() # this call will also handle data disk & network connection
elif amodule.params['state'] == 'paused':
elif state == 'paused':
subj.error()
if subj.result['failed']:

View File

@@ -13,8 +13,9 @@ from ansible.module_utils.decort_utils import *
class decort_lb(DecortController):
def __init__(self,arg_amodule) -> None:
super(decort_lb,self).__init__(arg_amodule)
def __init__(self) -> None:
super(decort_lb,self).__init__(AnsibleModule(**self.amodule_init_args))
arg_amodule = self.amodule
self.lb_id = 0
self.lb_facts = None
@@ -216,83 +217,93 @@ class decort_lb(DecortController):
ret_dict['backends'] = self.lb_facts['backends']
ret_dict['frontends'] = self.lb_facts['frontends']
return ret_dict
@staticmethod
def build_parameters():
"""Build and return a dictionary of parameters expected by decort_vins module in a form accepted
by AnsibleModule utility class."""
return dict(
account_id=dict(type='int', required=False),
account_name=dict(type='str', required=False, default=''),
description=dict(type='str', required=False, default='Managed by Ansible module decort_lb'),
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),
# datacenter=dict(type='str', required=False, default=''),
ext_net_id=dict(type='int', required=False, default=-1),
ext_ip_addr=dict(type='str', required=False, default=''),
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),
state=dict(type='str',
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
),
account_name=dict(
type='str',
default='',
),
description=dict(
type='str',
default='Managed by Ansible module decort_lb',
),
ext_net_id=dict(
type='int',
default=-1,
),
ext_ip_addr=dict(
type='str',
default='',
),
state=dict(
type='str',
default='present',
choices=['absent', 'disabled', 'enabled', 'present','restart']),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
rg_id=dict(type='int', required=False, default=0),
rg_name=dict(type='str', required=False, default=''),
vins_name=dict(type='str', required=False, default=''),
vins_id=dict(type='int', required=False, default=0),
verify_ssl=dict(type='bool', required=False, default=True),
lb_id=dict(type='int', required=False, default=0),
lb_name=dict(type='str'),
ha_lb=dict(type='bool', required=False, default=False),
backends=dict(type='list',required=False),
frontends=dict(type='list',required=False),
servers=dict(type='list',required=False),
permanently=dict(type='bool', required=False, default=False),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
choices=[
'absent',
'disabled',
'enabled',
'present',
'restart',
],
),
rg_id=dict(
type='int',
default=0,
),
rg_name=dict(
type='str',
default='',
),
vins_name=dict(
type='str',
default='',
),
vins_id=dict(
type='int',
default=0,
),
lb_id=dict(
type='int',
default=0,
),
lb_name=dict(
type='str',
),
ha_lb=dict(
type='bool',
default=False,
),
backends=dict(
type='list',
),
frontends=dict(
type='list',
),
servers=dict(
type='list',
),
permanently=dict(
type='bool',
default=False,
),
),
supports_check_mode=True,
required_one_of=[
('rg_id', 'rg_name'),
('lb_id', 'lb_name'),
('vins_id', 'vins_name'),
],
)
def main():
module_parameters = decort_lb.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password']
],
required_one_of=[
['rg_id','rg_name'],
['lb_id','lb_name'],
['vins_id','vins_name']
]
)
decon = decort_lb(amodule)
decon = decort_lb()
amodule = decon.amodule
if decon.lb_id:
if decon.lb_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING","DESTROYING","RESTORING"]:
decon.result['failed'] = True

View File

@@ -14,8 +14,9 @@ from ansible.module_utils.decort_utils import *
class decort_osimage(DecortController):
def __init__(self,amodule):
super(decort_osimage, self).__init__(amodule)
def __init__(self):
super(decort_osimage, self).__init__(AnsibleModule(**self.amodule_init_args))
amodule = self.amodule
self.validated_image_id = 0
self.validated_virt_image_id = 0
@@ -26,7 +27,7 @@ class decort_osimage(DecortController):
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
@@ -72,9 +73,9 @@ class decort_osimage(DecortController):
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'],
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'],
@@ -97,7 +98,7 @@ class decort_osimage(DecortController):
self.result['msg'] = ("Image '{}' linked to virtual image '{}'").format(self.target_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)
@@ -110,7 +111,7 @@ class decort_osimage(DecortController):
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'])
@@ -149,7 +150,7 @@ class decort_osimage(DecortController):
# 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']
@@ -162,84 +163,95 @@ class decort_osimage(DecortController):
ret_dict['accountId'] = arg_osimage_facts['accountId']
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),
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_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"),
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),
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
pool=dict(
type='str',
default='',
),
sep_id=dict(
type='int',
default=0,
),
account_name=dict(
type='str',
),
account_Id=dict(
type='int',
),
image_name=dict(
type='str',
),
image_id=dict(
type='int',
default=0,
),
virt_id=dict(
type='int',
default=0,
),
virt_name=dict(
type='str',
),
state=dict(
type='str',
default='present',
choices=[
'absent',
'present',
],
),
drivers=dict(
type='str',
default='KVM_X86',
),
imagetype=dict(
type='str',
default='linux',
),
boottype=dict(
type='str',
default='uefi',
),
url=dict(
type='str',
),
gid=dict(
type='int',
default=0,
),
sepId=dict(
type='int',
default=0,
),
poolName=dict(
type='str',
),
hotresize=dict(
type='bool',
default=False,
),
image_username=dict(
type='str',
),
image_password=dict(
type='str',
),
usernameDL=dict(
type='str',
),
passwordDL=dict(
type='str',
),
),
supports_check_mode=True,
)
def main():
module_parameters = decort_osimage.decort_osimage_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
)
decon = decort_osimage(amodule)
decon = decort_osimage()
amodule = decon.amodule
if amodule.params['virt_name'] or amodule.params['virt_id']:
image_id, image_facts = decort_osimage.decort_virt_image_find(decon, amodule)

View File

@@ -8,106 +8,87 @@ description: See L(Module Documentation,https://repository.basistech.ru/BASIS/de
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import *
def decort_pfw_package_facts(comp_facts, vins_facts, pfw_facts, check_mode=False):
"""Package a dictionary of PFW rules facts according to the decort_pfw module specification.
This dictionary will be returned to the upstream Ansible engine at the completion of
the module run.
class decort_pfw(DecortController):
def __init__(self):
super(decort_pfw, self).__init__(AnsibleModule(**self.amodule_init_args))
@param (dict) pfw_facts: dictionary with PFW facts as returned by API call to .../???/get
@param (bool) check_mode: boolean that tells if this Ansible module is run in check mode
"""
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
compute_id=dict(
type='int',
required=True,
),
rules=dict(
type='list',
),
state=dict(
type='str',
default='present',
choices=[
'absent',
'present',
],
),
vins_id=dict(
type='int',
required=True,
),
),
supports_check_mode=True,
)
ret_dict = dict(state="CHECK_MODE",
compute_id=0,
public_ip="",
rules=[],
vins_id=0,
)
def decort_pfw_package_facts(self, comp_facts, vins_facts, pfw_facts, check_mode=False):
"""Package a dictionary of PFW rules facts according to the decort_pfw module specification.
This dictionary will be returned to the upstream Ansible engine at the completion of
the module run.
@param (dict) pfw_facts: dictionary with PFW facts as returned by API call to .../???/get
@param (bool) check_mode: boolean that tells if this Ansible module is run in check mode
"""
ret_dict = dict(state="CHECK_MODE",
compute_id=0,
public_ip="",
rules=[],
vins_id=0,
)
if check_mode:
# in check mode return immediately with the default values
return ret_dict
if pfw_facts is None:
# if void facts provided - change state value to ABSENT and return
ret_dict['state'] = "ABSENT"
return ret_dict
ret_dict['compute_id'] = comp_facts['id']
ret_dict['vins_id'] = vins_facts['id']
ret_dict['public_ip'] = vins_facts['vnfs']['GW']['config']['ext_net_ip']
if len(pfw_facts) != 0:
ret_dict['state'] = 'PRESENT'
ret_dict['rules'] = pfw_facts
else:
ret_dict['state'] = 'ABSENT'
if check_mode:
# in check mode return immediately with the default values
return ret_dict
if pfw_facts is None:
# if void facts provided - change state value to ABSENT and return
ret_dict['state'] = "ABSENT"
return ret_dict
def decort_pfw_parameters(self):
"""Build and return a dictionary of parameters expected by decort_pfw module in a form accepted
by AnsibleModule utility class."""
ret_dict['compute_id'] = comp_facts['id']
ret_dict['vins_id'] = vins_facts['id']
ret_dict['public_ip'] = vins_facts['vnfs']['GW']['config']['ext_net_ip']
if len(pfw_facts) != 0:
ret_dict['state'] = 'PRESENT'
ret_dict['rules'] = pfw_facts
else:
ret_dict['state'] = 'ABSENT'
return ret_dict
def decort_pfw_parameters():
"""Build and return a dictionary of parameters expected by decort_pfw 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']),
compute_id=dict(type='int', required=True),
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),
rules=dict(type='list', required=False),
state=dict(type='str',
default='present',
choices=['absent', 'present']),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
verify_ssl=dict(type='bool', required=False, default=True),
vins_id=dict(type='int', required=True),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
)
return
def main():
module_parameters = decort_pfw_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
)
decon = DecortController(amodule)
decon = decort_pfw()
amodule = decon.amodule
pfw_facts = None # will hold PFW facts as returned by pfw_configure
@@ -157,7 +138,7 @@ def main():
amodule.fail_json(**decon.result)
else:
# prepare PFW facts to be returned as part of decon.result and then call exit_json(...)
decon.result['facts'] = decort_pfw_package_facts(comp_facts, vins_facts, pfw_facts, amodule.check_mode)
decon.result['facts'] = decon.decort_pfw_package_facts(comp_facts, vins_facts, pfw_facts, amodule.check_mode)
amodule.exit_json(**decon.result)
if __name__ == "__main__":

View File

@@ -14,8 +14,9 @@ from ansible.module_utils.decort_utils import *
class decort_rg(DecortController):
def __init__(self,amodule):
super(decort_rg, self).__init__(amodule)
def __init__(self):
super(decort_rg, self).__init__(AnsibleModule(**self.amodule_init_args))
amodule = self.amodule
self.validated_acc_id = 0
self.validated_rg_id = 0
@@ -237,81 +238,105 @@ class decort_rg(DecortController):
return ret_dict
def parameters():
"""Build and return a dictionary of parameters expected by decort_rg module in a form accepted
by AnsibleModule utility class."""
return dict(
account_id=dict(type='int', required=False),
account_name=dict(type='str', required=False, default=''),
access=dict(type='dict'),
description=dict(type='str', required=False, default=''),
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),
# datacenter=dict(type='str', required=False, default=''),
def_netType=dict(type='str', choices=['PRIVATE','PUBLIC', 'NONE'], default='PRIVATE'),
def_netId=dict(type='int'),
extNetId=dict(type='int', default=0),
extNetIp=dict(type='str', default=""),
owner=dict(type='str', default=""),
ipcidr=dict(type='str', default=""),
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'])),
rename=dict(type='str', default=""),
password=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_PASSWORD']),
no_log=True),
quotas=dict(type='dict', required=False),
resType=dict(type='list'),
state=dict(type='str',
default='present',
choices=['absent', 'disabled', 'enabled', 'present']),
permanently=dict(type='bool',
default='False'),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
rg_name=dict(type='str', required=False,),
rg_id=dict(type='int', required=False),
verify_ssl=dict(type='bool', required=False, default=True),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
sep_pools=dict(
type='list',
elements='dict',
options=dict(
sep_id=dict(
type='int',
required=True,
),
pool_names=dict(
type='list',
required=True,
elements='str',
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
),
account_name=dict(
type='str',
default='',
),
access=dict(
type='dict',
),
description=dict(
type='str',
default='',
),
def_netType=dict(
type='str',
choices=[
'PRIVATE',
'PUBLIC',
'NONE',
],
default='PRIVATE',
),
def_netId=dict(
type='int',
),
extNetId=dict(
type='int',
default=0,
),
extNetIp=dict(
type='str',
default='',
),
owner=dict(
type='str',
default='',
),
ipcidr=dict(
type='str',
default='',
),
rename=dict(
type='str',
default='',
),
quotas=dict(
type='dict',
),
resType=dict(
type='list',
),
state=dict(
type='str',
default='present',
choices=[
'absent',
'disabled',
'enabled',
'present',
],
),
permanently=dict(
type='bool',
default='False',
),
rg_name=dict(
type='str',
),
rg_id=dict(
type='int',
),
sep_pools=dict(
type='list',
elements='dict',
options=dict(
sep_id=dict(
type='int',
required=True,
),
pool_names=dict(
type='list',
required=True,
elements='str',
),
),
),
recursive_deletion=dict(
type='bool',
default=False,
)
),
recursive_deletion=dict(
type='bool',
default=False,
)
supports_check_mode=True,
)
# Workflow digest:
# 1) authenticate to DECORT controller & validate authentication by issuing API call - done when creating DECORTController
# 2) check if the RG with the specified id or rg_name:name exists
@@ -320,22 +345,8 @@ class decort_rg(DecortController):
# 5) report result to Ansible
def main():
module_parameters = decort_rg.parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
)
decon = decort_rg(amodule)
decon = decort_rg()
amodule = decon.amodule
#amodule.check_mode=True
if decon.validated_rg_id > 0:
if decon.rg_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING", "DESTROYING", "CONFIRMED"]:

157
library/decort_snapshot.py Normal file
View File

@@ -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()

View File

@@ -14,8 +14,9 @@ from ansible.module_utils.decort_utils import *
class decort_vins(DecortController):
def __init__(self,arg_amodule):
super(decort_vins, self).__init__(arg_amodule)
def __init__(self):
super(decort_vins, self).__init__(AnsibleModule(**self.amodule_init_args))
arg_amodule = self.amodule
self.vins_id = 0
self.vins_level = "" # "ID" if specified by ID, "RG" - at resource group, "ACC" - at account level
@@ -237,61 +238,84 @@ class decort_vins(DecortController):
return ret_dict
@staticmethod
def build_parameters():
"""Build and return a dictionary of parameters expected by decort_vins module in a form accepted
by AnsibleModule utility class."""
return dict(
account_id=dict(type='int', required=False,default=0),
account_name=dict(type='str', required=False, default=''),
description=dict(type='str', required=False, default=''),
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),
# datacenter=dict(type='str', required=False, default=''),
ext_net_id=dict(type='int', required=False, default=-1),
ext_ip_addr=dict(type='str', required=False, default=''),
ipcidr=dict(type='str', required=False, default=''),
mgmtaddr=dict(type='list',required=False, default=[]),
custom_config=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',
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),
state=dict(type='str',
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
default=0,
),
account_name=dict(
type='str',
default='',
),
description=dict(
type='str',
default='',
),
ext_net_id=dict(
type='int',
default=-1,
),
ext_ip_addr=dict(
type='str',
default='',
),
ipcidr=dict(
type='str',
default='',
),
mgmtaddr=dict(
type='list',
default=[],
),
custom_config=dict(
type='bool',
default=False,
),
config_save=dict(
type='bool',
default=False,
),
connect_to=dict(
type='list',
default=[],
),
state=dict(
type='str',
default='present',
choices=['absent', 'disabled', 'enabled', 'present']),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
rg_id=dict(type='int', required=False, default=0),
rg_name=dict(type='str', required=False, default=''),
verify_ssl=dict(type='bool', required=False, default=True),
vins_id=dict(type='int', required=False, default=0),
vins_name=dict(type='str', required=False,default=""),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
choices=[
'absent',
'disabled',
'enabled',
'present',
],
),
rg_id=dict(
type='int',
default=0,
),
rg_name=dict(
type='str',
default='',
),
vins_id=dict(
type='int',
default=0,
),
vins_name=dict(
type='str',
default='',
),
),
supports_check_mode=True,
required_one_of=[
('vins_id', 'vins_name'),
],
)
# Workflow digest:
# 1) authenticate to DECORT controller & validate authentication by issuing API call - done when creating DECORTController
# 2) check if the ViNS with this id or name exists under specified account / resource group
@@ -300,25 +324,8 @@ class decort_vins(DecortController):
# 5) report result to Ansible
def main():
module_parameters = decort_vins.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password'],
],
required_one_of=[
['vins_id', 'vins_name'],
],
)
decon = decort_vins(amodule)
decon = decort_vins()
amodule = decon.amodule
#
# Initial validation of module arguments is complete
#