Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c554c8edd | |||
| becbe65993 |
@@ -1,30 +0,0 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: no-commit-to-branch
|
||||
name: no-commit-to-branch (main, master, dev_*)
|
||||
args:
|
||||
- --pattern
|
||||
- dev_.*
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 7.2.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
exclude: |
|
||||
(?x)^(
|
||||
module_utils/decort_utils.py |
|
||||
library/decort_bservice.py |
|
||||
library/decort_disk.py |
|
||||
library/decort_group.py |
|
||||
library/decort_k8s.py |
|
||||
library/decort_kvmvm.py |
|
||||
library/decort_lb.py |
|
||||
library/decort_osimage.py |
|
||||
library/decort_pfw.py |
|
||||
library/decort_rg.py |
|
||||
library/decort_vins.py
|
||||
)$
|
||||
args:
|
||||
- --extend-ignore=E402
|
||||
117
CHANGELOG.md
117
CHANGELOG.md
@@ -1,122 +1,11 @@
|
||||
# Список изменений в версии 9.0.0
|
||||
# Список изменений в версии 10.0.1
|
||||
|
||||
## Добавлено
|
||||
### Глобально
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-798 | Обновлены системные требования: версия интерпретатора Python обновлена до 3.12, версия Python-библиотеки ansible обновлена до 11.6.0 |
|
||||
|
||||
### Модуль decort_kvmvm
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-790 | Добавлен параметр `zone_id` и возвращаемое значение `zone_id`. |
|
||||
| BANS-810 | Добавлен параметр `guest_agent` и возвращаемое значение `guest_agent`. |
|
||||
| BANS-806 | Добавлен параметр `get_snapshot_merge_status` и возвращаемое значение `snapshot_merge_status`. |
|
||||
| BANS-823 | Добавлено значение `TRUNK` для параметра `networks.type`. |
|
||||
| BANS-813 | Добавлено значение `SDN` для параметра `networks.type`. |
|
||||
| BANS-835 | Добавлена возможность использования параметра `networks.mtu` для внешней сети. |
|
||||
|
||||
### Модуль decort_lb
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-793 | Добавлен параметр `zone_id` и возвращаемое значение `zone_id`. |
|
||||
| BANS-819 | Добавлено возвращаемое значение `account_id`. |
|
||||
| BANS-800 | Добавлены значения `stopped` и `started` для параметра `state` и возвращаемое значение `tech_status`. |
|
||||
|
||||
### Модуль decort_k8s
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-794 | Добавлен параметр `zone_id` и возвращаемое значение `zone_id`. |
|
||||
| BANS-804 | Добавлены значения `stopped` и `started` для параметра `state`. |
|
||||
|
||||
### Модуль decort_vins
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-791 | Добавлен параметр `zone_id` и возвращаемое значение `zone_id`. |
|
||||
|
||||
### Модуль decort_bservice
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-792 | Добавлен параметр `zone_id` и возвращаемое значение `zone_id`. |
|
||||
| BANS-805 | Добавлены значения `stopped` и `started` для параметра `state`. |
|
||||
|
||||
### Модуль decort_user_info
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-796 | Добавлен параметр `zones` и возвращаемое значение `zones`. |
|
||||
| BANS-826 | Добавлен параметр `trunks` и возвращаемое значение `trunks`. |
|
||||
|
||||
### Модуль decort_account
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-789 | Добавлен параметр `default_zone_id` и возвращаемые значение `zoneIds`, `defaultZoneId`. |
|
||||
|
||||
### Модуль decort_account_info
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-809 | Добавлено значение `MERGE` для параметра `computes.filter.tech_status`. |
|
||||
| BANS-855 | Добавлены значения `SNAPCREATE`, `CLONING`, `ROLLBACK` для параметра `computes.filter.tech_status`. |
|
||||
|
||||
### Модуль decort_rg
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-812 | Добавлен параметр `sdn_access_group_id` и возвращаемое значение `sdn_access_group_id`. |
|
||||
|
||||
### Модуль decort_zone
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-795 | Добавлен модуль `decort_zone` для получения информации о зонах. |
|
||||
|
||||
### Модуль decort_trunk
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-825 | Добавлен модуль `decort_trunk` для получения информации о транковых портах. |
|
||||
|
||||
### Модуль decort_snapshot
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-808 | Добавлено значение `merge_aborted` для параметра `state`. |
|
||||
|
||||
### Модуль decort_osimage
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-849 | Добавлен параметр `account_id`, используемый при создании шаблонных и виртуальных образов. |
|
||||
|
||||
## Удалено
|
||||
### Модуль decort_disk
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-815 | Удалено значение по умолчанию для параметра `description`. |
|
||||
|
||||
### Модуль decort_lb
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-815 | Удалено значение по умолчанию для параметра `description`. |
|
||||
|
||||
### Модуль decort_k8s
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-804 | Удален параметр `started` в связи с переносом логики в параметр `state` (значение `started`). |
|
||||
|
||||
### Модуль decort_bservice
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-805 | Удален параметр `started` в связи с переносом логики в параметр `state` (значение `started`). |
|
||||
|
||||
### Модуль decort_osimage
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-849 | Удален параметр `account_Id` в связи с переименованием в `account_id`. |
|
||||
|
||||
## Исправлено
|
||||
### Модуль decort_lb
|
||||
### Модуль decort_group
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-803 | Модуль завершал работу ошибкой Python при создании балансировщика с указанием параметра `backends` или `frontends`. |
|
||||
| BANS-820 | Выполнение модуля с указанием параметра `vins_id` и без указания параметра `ext_net_id` вызывало создание балансировщика с некорректной сетевой конфигурацией, дальнейшее добавление конфигурации backend к которому завершалось ошибкой платформы. |
|
||||
| BANS-799 | Скорректирована логика параметра целевого состояния `present`. Теперь состояние `present` соответствует тому, что балансировщик нагрузки существует, и не приводит к изменению состояния существующего балансировщика нагрузки. Также для параметра `state` значение по умолчанию `present` теперь только при создании балансировщика нагрузки. |
|
||||
|
||||
### Модуль decort_account
|
||||
| Идентификатор<br>задачи | Описание |
|
||||
| --- | --- |
|
||||
| BANS-817 | Модуль некорректно отслеживал завершение удаления и восстановления аккаунта. |
|
||||
| BANS-941 | Исправлена ошибка, из-за которой не происходил запуск группы после создании с указанием параметра `timeoutStart`. |
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
| Версия платформы | Версия модулей Ansible |
|
||||
|:----------------:|:--------------------------:|
|
||||
| 4.4.0 | 10.0.x |
|
||||
| 4.4.0 build 963 | 9.0.x |
|
||||
| 4.3.0 | 8.0.x |
|
||||
| 4.2.0 | 7.0.x, 7.1.x, 7.2.x |
|
||||
|
||||
@@ -28,7 +28,7 @@ class decort_bservice(DecortController):
|
||||
self.fail_json(**self.result)
|
||||
if not arg_amodule.params['id']:
|
||||
if not arg_amodule.params['rg_id']: # RG ID is not set -> locate RG by name -> need account ID
|
||||
validated_acc_id, self.acc_info = self.account_find(arg_amodule.params['account_name'],
|
||||
validated_acc_id, self._acc_info = self.account_find(arg_amodule.params['account_name'],
|
||||
arg_amodule.params['account_id'])
|
||||
if not validated_acc_id:
|
||||
self.result['failed'] = True
|
||||
@@ -113,7 +113,7 @@ class decort_bservice(DecortController):
|
||||
)
|
||||
if self.bservice_id:
|
||||
_, self.bservice_info = self.bservice_get_by_id(self.bservice_id)
|
||||
self.bservice_state(self.bservice_info,'enabled')
|
||||
self.bservice_state(self.bservice_info, self.aparams['state'])
|
||||
return
|
||||
|
||||
def action(self,d_state):
|
||||
@@ -176,7 +176,6 @@ class decort_bservice(DecortController):
|
||||
),
|
||||
state=dict(
|
||||
type='str',
|
||||
default='present',
|
||||
choices=[
|
||||
'absent',
|
||||
'disabled',
|
||||
@@ -298,25 +297,30 @@ def main():
|
||||
subj.action(amodule.params['state'])
|
||||
if amodule.params['state'] == 'absent':
|
||||
subj.nop()
|
||||
elif subj.bservice_info['status'] in ('ENABLED', 'DISABLED'):
|
||||
elif subj.bservice_info['status'] in (
|
||||
'ENABLED', 'DISABLED', 'CREATED',
|
||||
):
|
||||
if amodule.params['state'] == 'absent':
|
||||
subj.destroy()
|
||||
else:
|
||||
subj.action(amodule.params['state'])
|
||||
elif subj.bservice_info['status'] == "DESTROED":
|
||||
elif subj.bservice_info['status'] == "DESTROYED":
|
||||
if amodule.params['state'] in ('present','enabled'):
|
||||
subj.create()
|
||||
subj.action(amodule.params['state'])
|
||||
if amodule.params['state'] == 'absent':
|
||||
subj.nop()
|
||||
else:
|
||||
if amodule.params['state'] == 'absent':
|
||||
state = amodule.params['state']
|
||||
if state is None:
|
||||
state = 'present'
|
||||
if state == 'absent':
|
||||
subj.nop()
|
||||
if amodule.params['state'] in ('present','started'):
|
||||
if state in ('present','started'):
|
||||
subj.create()
|
||||
elif amodule.params['state'] in ('stopped', 'disabled','enabled'):
|
||||
elif state in ('stopped', 'disabled','enabled'):
|
||||
subj.error()
|
||||
|
||||
|
||||
if subj.result['failed']:
|
||||
amodule.fail_json(**subj.result)
|
||||
else:
|
||||
|
||||
@@ -23,7 +23,7 @@ class decort_disk(DecortController):
|
||||
self.disk_id = 0
|
||||
self.account_id = 0
|
||||
# limitIO check for exclusive parameters
|
||||
|
||||
|
||||
if arg_amodule.params['limitIO']:
|
||||
self.disk_check_iotune_arg(arg_amodule.params['limitIO'])
|
||||
|
||||
@@ -41,6 +41,8 @@ class decort_disk(DecortController):
|
||||
validated_acc_id, validated_acc_info = self.account_find(
|
||||
arg_amodule.params['account_name'],
|
||||
arg_amodule.params['account_id'])
|
||||
self.acc_id = validated_acc_id
|
||||
self._acc_info = validated_acc_info
|
||||
if not validated_acc_id:
|
||||
self.result['changed'] = False
|
||||
self.result['msg'] = (
|
||||
@@ -51,8 +53,6 @@ class decort_disk(DecortController):
|
||||
)
|
||||
self.amodule.fail_json(**self.result)
|
||||
|
||||
self.acc_id = validated_acc_id
|
||||
self._acc_info = validated_acc_info
|
||||
validated_disk_id, validated_disk_facts = self.disk_find(
|
||||
disk_id=arg_amodule.params['id'],
|
||||
name=arg_amodule.params['name'] if "name" in arg_amodule.params else "",
|
||||
@@ -67,15 +67,21 @@ class decort_disk(DecortController):
|
||||
self.disk_id = validated_disk_id
|
||||
self.disk_info = validated_disk_facts
|
||||
|
||||
if self.disk_id:
|
||||
self.acc_id = validated_disk_facts['accountId']
|
||||
self.check_amodule_args_for_change()
|
||||
else:
|
||||
self.check_amodule_args_for_create()
|
||||
|
||||
def create(self):
|
||||
|
||||
self.disk_id = self.disk_create(accountId=self.acc_id,
|
||||
name = self.amodule.params['name'],
|
||||
description=self.amodule.params['description'],
|
||||
size=self.amodule.params['size'],
|
||||
iops=self.amodule.params['iops'],
|
||||
sep_id=self.amodule.params['sep_id'],
|
||||
pool=self.amodule.params['pool'],
|
||||
self.disk_id = self.disk_create(
|
||||
accountId=self.acc_id,
|
||||
name = self.amodule.params['name'],
|
||||
description=self.amodule.params['description'],
|
||||
size=self.amodule.params['size'],
|
||||
sep_id=self.amodule.params['sep_id'],
|
||||
pool=self.amodule.params['pool'],
|
||||
storage_policy_id=self.aparams['storage_policy_id'],
|
||||
)
|
||||
#IO tune
|
||||
if self.amodule.params['limitIO']:
|
||||
@@ -115,16 +121,27 @@ class decort_disk(DecortController):
|
||||
#raise Exception(self.amodule.params['shareable'])
|
||||
if self.amodule.params['shareable'] != self.disk_info['shareable']:
|
||||
self.disk_share(self.disk_id,self.amodule.params['shareable'])
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if (
|
||||
aparam_storage_policy_id is not None
|
||||
and aparam_storage_policy_id != self.disk_info['storage_policy_id']
|
||||
):
|
||||
self.disk_change_storage_policy(
|
||||
disk_id=self.disk_id,
|
||||
storage_policy_id=aparam_storage_policy_id,
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
self.disk_id = self.disk_delete(disk_id=self.disk_id,
|
||||
self.disk_delete(disk_id=self.disk_id,
|
||||
detach=self.amodule.params['force_detach'],
|
||||
permanently=self.amodule.params['permanently'],
|
||||
reason=self.amodule.params['reason'])
|
||||
self.disk_info['status'] = "DELETED"
|
||||
self.disk_id, self.disk_info = self._disk_get_by_id(self.disk_id)
|
||||
return
|
||||
|
||||
|
||||
def rename(self):
|
||||
|
||||
|
||||
@@ -175,6 +192,8 @@ class decort_disk(DecortController):
|
||||
ret_dict['iotune'] = self.disk_info['iotune']
|
||||
ret_dict['size_available'] = self.disk_info['sizeAvailable']
|
||||
ret_dict['size_used'] = self.disk_info['sizeUsed']
|
||||
ret_dict['storage_policy_id'] = self.disk_info['storage_policy_id']
|
||||
ret_dict['to_clean'] = self.disk_info['to_clean']
|
||||
|
||||
return ret_dict
|
||||
|
||||
@@ -219,10 +238,6 @@ class decort_disk(DecortController):
|
||||
size=dict(
|
||||
type='int',
|
||||
),
|
||||
iops=dict(
|
||||
type='int',
|
||||
default=2000,
|
||||
),
|
||||
limitIO=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
@@ -287,6 +302,9 @@ class decort_disk(DecortController):
|
||||
'present',
|
||||
],
|
||||
),
|
||||
storage_policy_id=dict(
|
||||
type='int',
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
required_one_of=[
|
||||
@@ -294,6 +312,73 @@ class decort_disk(DecortController):
|
||||
],
|
||||
)
|
||||
|
||||
def check_amodule_args_for_change(self):
|
||||
check_errors = False
|
||||
|
||||
if self.check_aparam_storage_policy_id() is False:
|
||||
check_errors = True
|
||||
if self.check_aparam_size() is False:
|
||||
check_errors = True
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_amodule_args_for_create(self):
|
||||
check_errors = False
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id must be specified when creating '
|
||||
'a new disk'
|
||||
)
|
||||
|
||||
if self.check_aparam_storage_policy_id() is False:
|
||||
check_errors = True
|
||||
if self.check_aparam_size() is False:
|
||||
check_errors = True
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_aparam_storage_policy_id(self) -> bool:
|
||||
check_errors = False
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if (
|
||||
aparam_storage_policy_id is not None
|
||||
and aparam_storage_policy_id
|
||||
not in self.acc_info['storage_policy_ids']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
f'Account ID {self.acc_id} does not have access to '
|
||||
f'storage_policy_id {aparam_storage_policy_id}'
|
||||
)
|
||||
|
||||
return not check_errors
|
||||
|
||||
def check_aparam_size(self) -> bool:
|
||||
check_errors = False
|
||||
|
||||
aparam_size = self.aparams['size']
|
||||
if (
|
||||
aparam_size is not None
|
||||
and aparam_size <= 0
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg=(
|
||||
'Check for parameter "size" failed: '
|
||||
f'Disk cannot be size {aparam_size}'
|
||||
),
|
||||
)
|
||||
|
||||
return not check_errors
|
||||
|
||||
def main():
|
||||
decon = decort_disk()
|
||||
amodule = decon.amodule
|
||||
@@ -334,12 +419,12 @@ def main():
|
||||
if amodule.params['state'] == 'absent':
|
||||
decon.nop()
|
||||
else:
|
||||
decon.create()
|
||||
|
||||
decon.create()
|
||||
|
||||
if decon.result['failed']:
|
||||
amodule.fail_json(**decon.result)
|
||||
else:
|
||||
if decon.result['changed'] and amodule.params['state'] in ('present'):
|
||||
if decon.result['changed']:
|
||||
_, decon.disk_info = decon.disk_find(decon.disk_id)
|
||||
decon.result['facts'] = decon.package_facts(amodule.check_mode)
|
||||
amodule.exit_json(**decon.result)
|
||||
|
||||
@@ -36,11 +36,15 @@ class decort_group(DecortController):
|
||||
group_id=arg_amodule.params['id'],
|
||||
group_name=arg_amodule.params['name'],
|
||||
)
|
||||
self.acc_id = self.bservice_info['accountId']
|
||||
self.rg_id = self.bservice_info['rgId']
|
||||
|
||||
if self.group_id:
|
||||
self.group_should_exist = True
|
||||
self.check_amodule_args_for_change()
|
||||
|
||||
else:
|
||||
self.check_amodule_args_for_create()
|
||||
|
||||
return
|
||||
def nop(self):
|
||||
"""No operation (NOP) handler for B-service.
|
||||
@@ -84,6 +88,17 @@ class decort_group(DecortController):
|
||||
warning=True,
|
||||
)
|
||||
|
||||
driver = self.aparams['driver']
|
||||
if driver is None:
|
||||
driver = 'KVM_X86'
|
||||
self.message(
|
||||
msg=self.MESSAGES.default_value_used(
|
||||
param_name='driver',
|
||||
default_value=driver,
|
||||
),
|
||||
warning=True,
|
||||
)
|
||||
|
||||
self.group_id=self.group_provision(
|
||||
bs_id=self.bservice_id,
|
||||
arg_name=self.amodule.params['name'],
|
||||
@@ -92,13 +107,14 @@ class decort_group(DecortController):
|
||||
arg_ram=self.amodule.params['ram'],
|
||||
arg_boot_disk=self.amodule.params['boot_disk'],
|
||||
arg_image_id=self.amodule.params['image_id'],
|
||||
arg_driver=self.amodule.params['driver'],
|
||||
arg_role=self.amodule.params['role'],
|
||||
arg_network=self.amodule.params['networks'],
|
||||
arg_timeout=self.amodule.params['timeoutStart'],
|
||||
arg_timeout=self.amodule.params['timeoutStart'],
|
||||
chipset=chipset,
|
||||
storage_policy_id=self.aparams['storage_policy_id'],
|
||||
driver=driver,
|
||||
)
|
||||
|
||||
|
||||
if self.amodule.params['state'] in ('started','present'):
|
||||
self.group_state(self.bservice_id,self.group_id,self.amodule.params['state'])
|
||||
|
||||
@@ -196,6 +212,7 @@ class decort_group(DecortController):
|
||||
ret_dict['techStatus'] = self.group_info['techStatus']
|
||||
ret_dict['state'] = self.group_info['status']
|
||||
ret_dict['Computes'] = self.group_info['computes']
|
||||
ret_dict['driver'] = self.group_info['driver']
|
||||
return ret_dict
|
||||
|
||||
@property
|
||||
@@ -229,17 +246,6 @@ class decort_group(DecortController):
|
||||
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',
|
||||
),
|
||||
@@ -287,17 +293,16 @@ class decort_group(DecortController):
|
||||
'i440fx',
|
||||
]
|
||||
),
|
||||
storage_policy_id=dict(
|
||||
type='int',
|
||||
),
|
||||
driver=dict(
|
||||
type='str',
|
||||
),
|
||||
),
|
||||
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'),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -306,7 +311,7 @@ class decort_group(DecortController):
|
||||
|
||||
if (
|
||||
self.aparams['chipset'] is None
|
||||
and self.aparams['count'] > len(self.group_info['computes'])
|
||||
and (self.aparams['count'] if self.aparams['count'] is not None else 0) > len(self.group_info['computes'])
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
@@ -335,9 +340,71 @@ class decort_group(DecortController):
|
||||
)
|
||||
break
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is not None:
|
||||
for compute in self.group_info['computes']:
|
||||
_, compute_info, _ = self._compute_get_by_id(compute['id'])
|
||||
for disk in compute_info['disks']:
|
||||
if aparam_storage_policy_id != disk['storage_policy_id']:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" '
|
||||
'failed: storage_policy_id can not be changed '
|
||||
f'for compute ID {compute['id']} '
|
||||
f'disk ID {disk['id']}'
|
||||
)
|
||||
|
||||
aparam_driver = self.aparams['driver']
|
||||
if (
|
||||
aparam_driver is not None
|
||||
and aparam_driver != self.group_info['driver']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "driver" failed: '
|
||||
'driver can not be changed'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_amodule_args_for_create(self):
|
||||
check_errors = False
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id must be specified when creating '
|
||||
'a new group'
|
||||
)
|
||||
else:
|
||||
if (
|
||||
aparam_storage_policy_id
|
||||
not in self.rg_info['storage_policy_ids']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
f'RG ID {self.rg_id} does not have access to '
|
||||
f'storage_policy_id {aparam_storage_policy_id}'
|
||||
)
|
||||
if (
|
||||
aparam_storage_policy_id
|
||||
not in self.acc_info['storage_policy_ids']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
f'Account ID {self.acc_id} does not have access to '
|
||||
f'storage_policy_id {aparam_storage_policy_id}'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
|
||||
def main():
|
||||
subj = decort_group()
|
||||
amodule = subj.amodule
|
||||
@@ -359,8 +426,7 @@ def main():
|
||||
|
||||
if subj.group_id:
|
||||
if subj.group_info['status'] in ("DELETING","DESTROYNG","CREATING","DESTROYING",
|
||||
"ENABLING","DISABLING","RESTORING","MODELED",
|
||||
"DISABLED","DESTROYED"):
|
||||
"ENABLING","DISABLING","RESTORING","MODELED","DESTROYED"):
|
||||
subj.error()
|
||||
elif subj.group_info['status'] in ("DELETED","DESTROYED"):
|
||||
if amodule.params['state'] == 'absent':
|
||||
|
||||
@@ -166,34 +166,36 @@ class decort_k8s(DecortController):
|
||||
if wg[param] is None:
|
||||
wg[param] = default_value
|
||||
|
||||
k8s_id = self.k8s_provision(self.amodule.params['name'],
|
||||
self.amodule.params['k8ci_id'],
|
||||
self.amodule.params['rg_id'],
|
||||
self.amodule.params['vins_id'],
|
||||
self.amodule.params['network_plugin'],
|
||||
self.amodule.params['master_count'],
|
||||
self.amodule.params['master_cpu'],
|
||||
self.amodule.params['master_ram'],
|
||||
self.amodule.params['master_disk'],
|
||||
self.amodule.params['master_sepid'],
|
||||
self.amodule.params['master_pool'],
|
||||
target_wgs[0],
|
||||
self.amodule.params['extnet_id'],
|
||||
self.amodule.params['with_lb'],
|
||||
self.amodule.params['ha_lb'],
|
||||
self.amodule.params['additionalSANs'],
|
||||
self.amodule.params['init_conf'],
|
||||
self.amodule.params['cluster_conf'],
|
||||
self.amodule.params['kublet_conf'],
|
||||
self.amodule.params['kubeproxy_conf'],
|
||||
self.amodule.params['join_conf'],
|
||||
self.amodule.params['oidc_cert'],
|
||||
self.amodule.params['description'],
|
||||
self.amodule.params['extnet_only'],
|
||||
master_chipset,
|
||||
lb_sysctl=self.amodule.params['lb_sysctl'],
|
||||
zone_id=self.aparams['zone_id'],
|
||||
)
|
||||
k8s_id = self.k8s_provision(
|
||||
self.amodule.params['name'],
|
||||
self.amodule.params['k8ci_id'],
|
||||
self.amodule.params['rg_id'],
|
||||
self.amodule.params['vins_id'],
|
||||
self.amodule.params['network_plugin'],
|
||||
self.amodule.params['master_count'],
|
||||
self.amodule.params['master_cpu'],
|
||||
self.amodule.params['master_ram'],
|
||||
self.amodule.params['master_disk'],
|
||||
self.amodule.params['master_sepid'],
|
||||
self.amodule.params['master_pool'],
|
||||
target_wgs[0],
|
||||
self.amodule.params['extnet_id'],
|
||||
self.amodule.params['with_lb'],
|
||||
self.amodule.params['ha_lb'],
|
||||
self.amodule.params['additionalSANs'],
|
||||
self.amodule.params['init_conf'],
|
||||
self.amodule.params['cluster_conf'],
|
||||
self.amodule.params['kublet_conf'],
|
||||
self.amodule.params['kubeproxy_conf'],
|
||||
self.amodule.params['join_conf'],
|
||||
self.amodule.params['oidc_cert'],
|
||||
self.amodule.params['description'],
|
||||
self.amodule.params['extnet_only'],
|
||||
master_chipset=master_chipset,
|
||||
lb_sysctl=self.amodule.params['lb_sysctl'],
|
||||
zone_id=self.aparams['zone_id'],
|
||||
storage_policy_id=self.aparams['storage_policy_id'],
|
||||
)
|
||||
|
||||
if not k8s_id:
|
||||
if k8s_id == 0:
|
||||
@@ -241,6 +243,12 @@ class decort_k8s(DecortController):
|
||||
)
|
||||
self.exit(fail=True)
|
||||
|
||||
if (
|
||||
self.aparams['name'] is not None
|
||||
and self.aparams['name'] != self.k8s_info['name']
|
||||
):
|
||||
self.k8s_update(id=self.k8s_id, name=self.aparams['name'])
|
||||
|
||||
if preupdate:
|
||||
# K8s info updating
|
||||
self.k8s_info = self.k8s_get_by_id(k8s_id=self.k8s_id)
|
||||
@@ -275,9 +283,6 @@ class decort_k8s(DecortController):
|
||||
type='str',
|
||||
default='',
|
||||
),
|
||||
quotas=dict(
|
||||
type='dict',
|
||||
),
|
||||
state=dict(
|
||||
type='str',
|
||||
default='present',
|
||||
@@ -448,6 +453,9 @@ class decort_k8s(DecortController):
|
||||
zone_id=dict(
|
||||
type='int',
|
||||
),
|
||||
storage_policy_id=dict(
|
||||
type='int',
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
required_one_of=[
|
||||
@@ -499,6 +507,32 @@ class decort_k8s(DecortController):
|
||||
'K8s cluster must be stopped to migrate to a zone.'
|
||||
)
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is not None:
|
||||
computes_ids = []
|
||||
for master_node in self.k8s_info['k8sGroups']['masters'][
|
||||
'detailedInfo'
|
||||
]:
|
||||
computes_ids.append(master_node['id'])
|
||||
for wg in self.k8s_info['k8sGroups']['workers']:
|
||||
workers_ids = [
|
||||
worker['id'] for worker in wg['detailedInfo']
|
||||
]
|
||||
computes_ids.extend(workers_ids)
|
||||
for compute_id in computes_ids:
|
||||
_, compute_info, _ = self._compute_get_by_id(
|
||||
comp_id=compute_id
|
||||
)
|
||||
for disk in compute_info['disks']:
|
||||
if aparam_storage_policy_id != disk['storage_policy_id']:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" '
|
||||
'failed: storage_policy_id can not be changed '
|
||||
f'for k8s cluster ID {self.k8s_id} compute ID '
|
||||
f'{compute_id} disk ID {disk['id']}'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
@@ -540,6 +574,26 @@ class decort_k8s(DecortController):
|
||||
if self.check_aparam_zone_id() is False:
|
||||
check_errors = True
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id must be specified when creating '
|
||||
'a new cluster'
|
||||
)
|
||||
elif (
|
||||
aparam_storage_policy_id
|
||||
not in self.rg_info['storage_policy_ids']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
f'RG ID {self.rg_id} does not have access to '
|
||||
f'storage_policy_id {aparam_storage_policy_id}'
|
||||
)
|
||||
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ class decort_kvmvm(DecortController):
|
||||
comp_id=self.aparams['clone_from']['id'],
|
||||
)
|
||||
)
|
||||
self.rg_id = self.vm_to_clone_info['rgId']
|
||||
if not self.vm_to_clone_id:
|
||||
self.message(
|
||||
f'Check for parameter "clone_from.id" failed: '
|
||||
@@ -73,7 +74,7 @@ class decort_kvmvm(DecortController):
|
||||
|
||||
clone_id, clone_dict, _ = self.compute_find(
|
||||
comp_name=self.aparams['name'],
|
||||
rg_id=self.vm_to_clone_info['rgId'],
|
||||
rg_id=self.rg_id,
|
||||
)
|
||||
self.check_amodule_args_for_clone(
|
||||
clone_id=clone_id,
|
||||
@@ -389,7 +390,7 @@ class decort_kvmvm(DecortController):
|
||||
Compute instance with the specified characteristics into the target Resource Group.
|
||||
The target RG must exist.
|
||||
"""
|
||||
# the following parameters must be present: cpu, ram, image_id or image_name
|
||||
# the following parameters must be present: cpu, ram, image_id
|
||||
# each of the following calls will abort if argument is missing
|
||||
self.check_amodule_argument('cpu')
|
||||
self.check_amodule_argument('ram')
|
||||
@@ -429,27 +430,15 @@ class decort_kvmvm(DecortController):
|
||||
|
||||
image_id, image_facts = None, None
|
||||
if self.aparam_image:
|
||||
# either image_name or image_id must be present
|
||||
if (
|
||||
self.check_amodule_argument('image_id', abort=False)
|
||||
and self.amodule.params['image_id'] > 0
|
||||
):
|
||||
# find image by image ID and account ID
|
||||
# image_find(self, image_id, image_name, account_id, rg_id=0, sepid=0, pool=""):
|
||||
# image_find(self, image_id, account_id, rg_id=0, sepid=0, pool=""):
|
||||
image_id, image_facts = self.image_find(
|
||||
image_id=self.amodule.params['image_id'],
|
||||
image_name="",
|
||||
account_id=self.acc_id)
|
||||
elif (
|
||||
self.check_amodule_argument('image_name', abort=False)
|
||||
and self.amodule.params['image_name'] != ""
|
||||
):
|
||||
# find image by image name and account ID
|
||||
image_id, image_facts = self.image_find(
|
||||
image_id=0,
|
||||
image_name=self.amodule.params['image_name'],
|
||||
account_id=self.acc_id,
|
||||
)
|
||||
|
||||
if validated_bdisk_size <= image_facts['size']:
|
||||
# adjust disk size to the minimum allowed by OS image, which will be used to spin off this Compute
|
||||
@@ -523,26 +512,31 @@ class decort_kvmvm(DecortController):
|
||||
# if we get through here, all parameters required to create new Compute instance should be at hand
|
||||
|
||||
# NOTE: KVM VM is created in HALTED state and must be explicitly started
|
||||
self.comp_id = self.kvmvm_provision(rg_id=self.rg_id,
|
||||
comp_name=self.amodule.params['name'],
|
||||
cpu=self.amodule.params['cpu'], ram=self.amodule.params['ram'],
|
||||
boot_disk_size=validated_bdisk_size,
|
||||
image_id=image_id,
|
||||
description=self.amodule.params['description'],
|
||||
userdata=cloud_init_params,
|
||||
sep_id=self.amodule.params['sep_id' ] if "sep_id" in self.amodule.params else None,
|
||||
pool_name=self.amodule.params['pool'] if "pool" in self.amodule.params else None,
|
||||
start_on_create=start_compute,
|
||||
chipset=chipset,
|
||||
cpu_pin=cpu_pin,
|
||||
hp_backed=hp_backed,
|
||||
numa_affinity=numa_affinity,
|
||||
preferred_cpu_cores=self.amodule.params['preferred_cpu_cores'],
|
||||
boot_mode=boot_mode,
|
||||
boot_loader_type=loader_type,
|
||||
network_interface_naming=network_interface_naming,
|
||||
hot_resize=hot_resize,
|
||||
zone_id=self.aparams['zone_id'],)
|
||||
self.comp_id = self.kvmvm_provision(
|
||||
rg_id=self.rg_id,
|
||||
comp_name=self.amodule.params['name'],
|
||||
cpu=self.amodule.params['cpu'],
|
||||
ram=self.amodule.params['ram'],
|
||||
boot_disk_size=validated_bdisk_size,
|
||||
image_id=image_id,
|
||||
description=self.amodule.params['description'],
|
||||
userdata=cloud_init_params,
|
||||
sep_id=self.amodule.params['sep_id' ] if "sep_id" in self.amodule.params else None,
|
||||
pool_name=self.amodule.params['pool'] if "pool" in self.amodule.params else None,
|
||||
start_on_create=start_compute,
|
||||
chipset=chipset,
|
||||
cpu_pin=cpu_pin,
|
||||
hp_backed=hp_backed,
|
||||
numa_affinity=numa_affinity,
|
||||
preferred_cpu_cores=self.amodule.params['preferred_cpu_cores'],
|
||||
boot_mode=boot_mode,
|
||||
boot_loader_type=loader_type,
|
||||
network_interface_naming=network_interface_naming,
|
||||
hot_resize=hot_resize,
|
||||
zone_id=self.aparams['zone_id'],
|
||||
storage_policy_id=self.aparams['storage_policy_id'],
|
||||
os_version=self.aparams['os_version'],
|
||||
)
|
||||
self.comp_should_exist = True
|
||||
|
||||
# Originally we would have had to re-read comp_info after VM was provisioned
|
||||
@@ -579,7 +573,7 @@ class decort_kvmvm(DecortController):
|
||||
if self.amodule.params['disks'] is not None:
|
||||
self.compute_disks(
|
||||
comp_dict=self.comp_info,
|
||||
aparam_disks=self.amodule.params['disks'],
|
||||
aparam_disks_dict=self.amodule.params['disks'],
|
||||
)
|
||||
|
||||
self.compute_affinity(self.comp_info,
|
||||
@@ -626,8 +620,7 @@ class decort_kvmvm(DecortController):
|
||||
Note that this handler deletes the VM permanently together with all assigned disk resources.
|
||||
"""
|
||||
self.compute_delete(comp_id=self.comp_id, permanently=True)
|
||||
self.comp_info['status'] = 'DESTROYED'
|
||||
self.comp_should_exist = False
|
||||
self.comp_id, self.comp_info, _ = self._compute_get_by_id(self.comp_id)
|
||||
return
|
||||
|
||||
def restore(self):
|
||||
@@ -676,7 +669,7 @@ class decort_kvmvm(DecortController):
|
||||
if self.amodule.params['disks'] is not None:
|
||||
self.compute_disks(
|
||||
comp_dict=self.comp_info,
|
||||
aparam_disks=self.amodule.params['disks'],
|
||||
aparam_disks_dict=self.amodule.params['disks'],
|
||||
)
|
||||
|
||||
aparam_boot = self.amodule.params['boot']
|
||||
@@ -695,6 +688,59 @@ class decort_kvmvm(DecortController):
|
||||
if boot_disk_new_size:
|
||||
self.compute_bootdisk_size(self.comp_info, boot_disk_new_size)
|
||||
|
||||
boot_order = aparam_boot['order']
|
||||
if (
|
||||
boot_order is not None
|
||||
and self.comp_info['bootOrder'] != boot_order
|
||||
):
|
||||
self.compute_set_boot_order(
|
||||
vm_id=self.comp_id,
|
||||
order=boot_order,
|
||||
)
|
||||
|
||||
disk_redeploy = aparam_boot['disk_redeploy']
|
||||
if disk_redeploy:
|
||||
auto_start = False
|
||||
if self.aparams['state'] is None:
|
||||
if self.comp_info['techStatus'] == 'STARTED':
|
||||
auto_start = True
|
||||
else:
|
||||
if self.aparams['state'] == 'started':
|
||||
auto_start = True
|
||||
|
||||
disk_size = None
|
||||
if (
|
||||
aparam_boot is not None
|
||||
and aparam_boot['disk_size'] is not None
|
||||
):
|
||||
disk_size = aparam_boot['disk_size']
|
||||
elif self.aparams['image_id'] is not None:
|
||||
_, image_facts = self.image_find(
|
||||
image_id=self.aparams['image_id'],
|
||||
)
|
||||
disk_size = image_facts['size']
|
||||
|
||||
os_version = None
|
||||
if (
|
||||
self.aparams['image_id'] is None
|
||||
or self.aparams['image_id'] == self.comp_info['imageId']
|
||||
):
|
||||
if self.aparams['os_version'] is None:
|
||||
os_version = self.comp_info['os_version']
|
||||
else:
|
||||
os_version = self.aparams['os_version']
|
||||
elif self.aparams['image_id'] != self.comp_info['imageId']:
|
||||
os_version = self.aparams['os_version']
|
||||
|
||||
self.compute_disk_redeploy(
|
||||
vm_id=self.comp_id,
|
||||
storage_policy_id=self.aparams['storage_policy_id'],
|
||||
image_id=self.aparams['image_id'],
|
||||
disk_size=disk_size,
|
||||
auto_start=auto_start,
|
||||
os_version=os_version,
|
||||
)
|
||||
|
||||
self.compute_resize(self.comp_info,
|
||||
self.amodule.params['cpu'], self.amodule.params['ram'],
|
||||
wait_for_state_change=arg_wait_cycles)
|
||||
@@ -754,6 +800,28 @@ class decort_kvmvm(DecortController):
|
||||
)
|
||||
)
|
||||
|
||||
aparam_cdrom = self.aparams['cdrom']
|
||||
if aparam_cdrom is not None:
|
||||
mode = aparam_cdrom['mode']
|
||||
image_id = aparam_cdrom['image_id']
|
||||
if (
|
||||
mode == 'insert'
|
||||
and self.comp_info['cdImageId'] != image_id
|
||||
):
|
||||
self.compute_cd_insert(
|
||||
vm_id=self.comp_id,
|
||||
image_id=image_id,
|
||||
)
|
||||
elif mode == 'eject':
|
||||
self.compute_cd_eject(
|
||||
vm_id=self.comp_id,
|
||||
)
|
||||
|
||||
if self.aparams['abort_cloning']:
|
||||
self.compute_clone_abort(
|
||||
vm_id=self.comp_id,
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
@property
|
||||
@@ -773,6 +841,7 @@ class decort_kvmvm(DecortController):
|
||||
'boot.loader_type': 'loaderType',
|
||||
'network_interface_naming': 'networkInterfaceNaming',
|
||||
'hot_resize': 'hotResize',
|
||||
'os_version': 'os_version',
|
||||
}
|
||||
|
||||
def get_nested_value(
|
||||
@@ -814,6 +883,14 @@ class decort_kvmvm(DecortController):
|
||||
)
|
||||
|
||||
if aparam_value is not None and aparam_value != comp_value:
|
||||
# If disk_redeploy = True no need to update os_version.
|
||||
# Updating os_version through compute_disk_redeploy
|
||||
if (
|
||||
aparam_name == 'os_version'
|
||||
and self.aparams['boot'] is not None
|
||||
and self.aparams['boot']['disk_redeploy']
|
||||
):
|
||||
continue
|
||||
result_args[aparam_name.replace('.', '_')] = (
|
||||
aparam_value
|
||||
)
|
||||
@@ -837,7 +914,6 @@ class decort_kvmvm(DecortController):
|
||||
cpu="",
|
||||
ram="",
|
||||
disk_size=0,
|
||||
data_disks=[], # IDs of attached data disks; this list can be emty
|
||||
state="CHECK_MODE",
|
||||
tech_status="",
|
||||
account_id=0,
|
||||
@@ -898,18 +974,19 @@ class decort_kvmvm(DecortController):
|
||||
elif iface['connType'] == "VLAN": # This is direct external network connection
|
||||
ret_dict['public_ips'].append(iface['ipAddress'])
|
||||
|
||||
iface['security_group_mode'] = iface.pop('enable_secgroups')
|
||||
iface['security_group_ids'] = iface.pop('security_groups')
|
||||
|
||||
ret_dict['cpu'] = self.comp_info['cpus']
|
||||
ret_dict['ram'] = self.comp_info['ram']
|
||||
|
||||
ret_dict['image_id'] = self.comp_info['imageId']
|
||||
|
||||
for ddisk in self.comp_info['disks']:
|
||||
if ddisk['type'] == 'B':
|
||||
ret_dict['disks'] = self.comp_info['disks']
|
||||
for disk in ret_dict['disks']:
|
||||
if disk['type'] == 'B':
|
||||
# if it is a boot disk - store its size
|
||||
ret_dict['disk_size'] = ddisk['sizeMax']
|
||||
elif ddisk['type'] == 'D':
|
||||
# if it is a data disk - append its ID to the list of data disks IDs
|
||||
ret_dict['data_disks'].append(ddisk['id'])
|
||||
ret_dict['disk_size'] = disk['sizeMax']
|
||||
|
||||
ret_dict['chipset'] = self.comp_info['chipset']
|
||||
|
||||
@@ -960,15 +1037,30 @@ class decort_kvmvm(DecortController):
|
||||
self.comp_info['snapshot_merge_status']
|
||||
)
|
||||
|
||||
ret_dict['cd_image_id'] = self.comp_info['cdImageId']
|
||||
|
||||
ret_dict['boot_order'] = self.comp_info['bootOrder']
|
||||
|
||||
ret_dict['os_version'] = self.comp_info['os_version']
|
||||
|
||||
ret_dict['boot_loader_metaiso'] = self.comp_info['loaderMetaIso']
|
||||
if self.comp_info['loaderMetaIso'] is not None:
|
||||
ret_dict['boot_loader_metaiso'] = {
|
||||
'device_name': self.comp_info['loaderMetaIso']['devicename'],
|
||||
'path': self.comp_info['loaderMetaIso']['path'],
|
||||
}
|
||||
|
||||
if self.amodule.params['get_cloning_status']:
|
||||
ret_dict['cloning_status'] = self.compute_get_clone_status(
|
||||
vm_id=self.comp_id,
|
||||
)
|
||||
|
||||
return ret_dict
|
||||
|
||||
def check_amodule_args_for_create(self):
|
||||
check_errors = False
|
||||
# Check for unacceptable parameters for a blank Compute
|
||||
if (
|
||||
self.aparams['image_id'] is not None
|
||||
or self.aparams['image_name'] is not None
|
||||
):
|
||||
if self.aparams['image_id'] is not None:
|
||||
self.aparam_image = True
|
||||
for param in (
|
||||
'network_interface_naming',
|
||||
@@ -1017,7 +1109,7 @@ class decort_kvmvm(DecortController):
|
||||
check_errors = True
|
||||
self.message(
|
||||
f'Check for parameter "{parameter}" failed: '
|
||||
f'"image_id" or "image_name" must be specified '
|
||||
f'"image_id" must be specified '
|
||||
f'to set {parameter}.'
|
||||
)
|
||||
|
||||
@@ -1029,7 +1121,7 @@ class decort_kvmvm(DecortController):
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "sep_id" failed: '
|
||||
'"image_id" or "image_name" or "boot.disk_size" '
|
||||
'"image_id" or "boot.disk_size" '
|
||||
'must be specified to set sep_id.'
|
||||
)
|
||||
|
||||
@@ -1072,6 +1164,39 @@ class decort_kvmvm(DecortController):
|
||||
if self.check_aparam_networks_trunk() is False:
|
||||
check_errors = True
|
||||
|
||||
if self.aparams['cdrom'] is not None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "cdrom" failed: '
|
||||
'cdrom can be specified only for existing compute.'
|
||||
)
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id must be specified when creating '
|
||||
'a new compute'
|
||||
)
|
||||
elif (
|
||||
aparam_storage_policy_id
|
||||
not in self.rg_info['storage_policy_ids']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
f'RG ID {self.rg_id} does not have access to '
|
||||
f'storage_policy_id {aparam_storage_policy_id}'
|
||||
)
|
||||
|
||||
if self.aparams['abort_cloning'] is not None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "abort_cloning" failed: '
|
||||
'abort_cloning can be specified only for existing compute.'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
@@ -1114,6 +1239,19 @@ class decort_kvmvm(DecortController):
|
||||
'unknown',
|
||||
],
|
||||
),
|
||||
from_cdrom=dict(
|
||||
type='int',
|
||||
),
|
||||
order=dict(
|
||||
type='list',
|
||||
elements='str',
|
||||
choices=[
|
||||
e.value for e in self.VMBootDevice
|
||||
],
|
||||
),
|
||||
disk_redeploy=dict(
|
||||
type='bool',
|
||||
),
|
||||
),
|
||||
),
|
||||
sep_id=dict(
|
||||
@@ -1142,9 +1280,24 @@ class decort_kvmvm(DecortController):
|
||||
],
|
||||
default='update',
|
||||
),
|
||||
ids=dict(
|
||||
objects=dict(
|
||||
type='list',
|
||||
elements='int',
|
||||
elements='dict',
|
||||
options=dict(
|
||||
id=dict(
|
||||
type='int',
|
||||
required=True,
|
||||
),
|
||||
pci_slot_num_hex=dict(
|
||||
type='str',
|
||||
),
|
||||
bus_num_hex=dict(
|
||||
type='str',
|
||||
),
|
||||
),
|
||||
required_together=[
|
||||
('pci_slot_num_hex', 'bus_num_hex'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1155,9 +1308,6 @@ class decort_kvmvm(DecortController):
|
||||
image_id=dict(
|
||||
type='int',
|
||||
),
|
||||
image_name=dict(
|
||||
type='str',
|
||||
),
|
||||
name=dict(
|
||||
type='str',
|
||||
),
|
||||
@@ -1190,6 +1340,16 @@ class decort_kvmvm(DecortController):
|
||||
mac=dict(
|
||||
type='str',
|
||||
),
|
||||
security_group_ids=dict(
|
||||
type='list',
|
||||
elements='int',
|
||||
),
|
||||
security_group_mode=dict(
|
||||
type='bool',
|
||||
),
|
||||
enabled=dict(
|
||||
type='bool',
|
||||
),
|
||||
),
|
||||
required_if=[
|
||||
('type', 'VINS', ('id',)),
|
||||
@@ -1197,7 +1357,7 @@ class decort_kvmvm(DecortController):
|
||||
('type', 'VFNIC', ('id',)),
|
||||
('type', 'DPDK', ('id',)),
|
||||
('type', 'TRUNK', ('id',)),
|
||||
('type', 'SDN', ('id', 'mac')),
|
||||
('type', 'SDN', ('id',)),
|
||||
],
|
||||
),
|
||||
network_order_changing=dict(
|
||||
@@ -1326,6 +1486,16 @@ class decort_kvmvm(DecortController):
|
||||
('name', 'timestamp', 'datetime'),
|
||||
],
|
||||
),
|
||||
sep_pool_name=dict(
|
||||
type='str',
|
||||
),
|
||||
sep_id=dict(
|
||||
type='int',
|
||||
),
|
||||
storage_policy_id=dict(
|
||||
type='int',
|
||||
requiered=True,
|
||||
),
|
||||
),
|
||||
),
|
||||
network_interface_naming=dict(
|
||||
@@ -1368,6 +1538,34 @@ class decort_kvmvm(DecortController):
|
||||
get_snapshot_merge_status=dict(
|
||||
type='bool',
|
||||
),
|
||||
cdrom=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
mode=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'insert',
|
||||
'eject',
|
||||
],
|
||||
default='insert',
|
||||
),
|
||||
image_id=dict(
|
||||
type='int',
|
||||
),
|
||||
),
|
||||
),
|
||||
storage_policy_id=dict(
|
||||
type='int',
|
||||
),
|
||||
os_version=dict(
|
||||
type='str',
|
||||
),
|
||||
get_cloning_status=dict(
|
||||
type='bool',
|
||||
),
|
||||
abort_cloning=dict(
|
||||
type='bool',
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
required_one_of=[
|
||||
@@ -1377,7 +1575,7 @@ class decort_kvmvm(DecortController):
|
||||
'clone_from': 'name',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def check_amodule_args_for_change(self):
|
||||
check_errors = False
|
||||
|
||||
@@ -1404,30 +1602,6 @@ class decort_kvmvm(DecortController):
|
||||
|
||||
aparam_boot = self.amodule.params['boot']
|
||||
if aparam_boot is not None:
|
||||
new_boot_disk_size = aparam_boot['disk_size']
|
||||
if new_boot_disk_size is not None:
|
||||
boot_disk_size = 0
|
||||
for disk in self.comp_info['disks']:
|
||||
if disk['type'] == 'B':
|
||||
boot_disk_size = disk['sizeMax']
|
||||
break
|
||||
else:
|
||||
if aparam_boot is None or aparam_boot['disk_id'] is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
f'Can\'t set boot disk size for Compute '
|
||||
f'{comp_id}, because it doesn\'t '
|
||||
f'have a boot disk.'
|
||||
)
|
||||
|
||||
if new_boot_disk_size < boot_disk_size:
|
||||
check_errors = True
|
||||
self.message(
|
||||
f'New boot disk size {new_boot_disk_size} is less'
|
||||
f' than current {boot_disk_size} for Compute ID '
|
||||
f'{comp_id}'
|
||||
)
|
||||
|
||||
aparam_disks = self.amodule.params['disks']
|
||||
aparam_boot_disk_id = aparam_boot['disk_id']
|
||||
comp_disk_ids = [disk['id'] for disk in self.comp_info['disks']]
|
||||
@@ -1479,6 +1653,75 @@ class decort_kvmvm(DecortController):
|
||||
f'to Compute ID {self.comp_id}.'
|
||||
)
|
||||
|
||||
if self.check_aparam_boot_disk_redeploy() is False:
|
||||
check_errors = True
|
||||
|
||||
new_boot_disk_size = aparam_boot['disk_size']
|
||||
if new_boot_disk_size is not None:
|
||||
boot_disk_size = 0
|
||||
for disk in self.comp_info['disks']:
|
||||
if disk['type'] == 'B':
|
||||
boot_disk_size = disk['sizeMax']
|
||||
break
|
||||
else:
|
||||
if aparam_boot is None or aparam_boot['disk_id'] is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
f'Can\'t set boot disk size for Compute '
|
||||
f'{comp_id}, because it doesn\'t '
|
||||
f'have a boot disk.'
|
||||
)
|
||||
|
||||
if new_boot_disk_size < boot_disk_size:
|
||||
check_errors = True
|
||||
self.message(
|
||||
f'New boot disk size {new_boot_disk_size} is less'
|
||||
f' than current {boot_disk_size} for Compute ID '
|
||||
f'{comp_id}'
|
||||
)
|
||||
|
||||
cd_rom_image_id = aparam_boot['from_cdrom']
|
||||
if cd_rom_image_id is not None:
|
||||
if not (
|
||||
self.comp_info['techStatus'] == 'STOPPED'
|
||||
and self.aparams['state'] == 'started'
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
f'Check for parameter "boot.from_cdrom" failed: '
|
||||
f'VM ID {self.comp_id} must be stopped and "state" '
|
||||
'must be "started" to boot from CD-ROM.'
|
||||
)
|
||||
_, image_info = self._image_get_by_id(
|
||||
image_id=cd_rom_image_id,
|
||||
)
|
||||
if image_info is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "boot.from_cdrom" failed: '
|
||||
f'Image ID {cd_rom_image_id} not found.'
|
||||
)
|
||||
elif image_info['type'] != 'cdrom':
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "boot.from_cdrom" failed: '
|
||||
f'Image ID {cd_rom_image_id} is not a cd-rom type.'
|
||||
)
|
||||
|
||||
boot_order_list = aparam_boot['order']
|
||||
if boot_order_list is not None:
|
||||
boot_order_duplicates = set([
|
||||
boot_dev for boot_dev in boot_order_list
|
||||
if boot_order_list.count(boot_dev) > 1
|
||||
])
|
||||
if boot_order_duplicates:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "boot.order" failed: '
|
||||
'List of boot devices has duplicates: '
|
||||
f'{boot_order_duplicates}.'
|
||||
)
|
||||
|
||||
if (
|
||||
not comp_info['imageId']
|
||||
and self.amodule.params['state'] in (
|
||||
@@ -1574,24 +1817,24 @@ class decort_kvmvm(DecortController):
|
||||
'VM must be started to get console url.'
|
||||
)
|
||||
|
||||
aparam_disks = self.aparams['disks']
|
||||
if aparam_disks is not None:
|
||||
aparam_disks_ids = aparam_disks['ids']
|
||||
aparam_disks_dict = self.aparams['disks']
|
||||
if aparam_disks_dict is not None:
|
||||
aparam_disks = aparam_disks_dict.get('objects', [])
|
||||
aparam_disks_ids = [disk['id'] for disk in aparam_disks]
|
||||
comp_boot_disk_id = None
|
||||
for comp_disk in self.comp_info['disks']:
|
||||
if comp_disk['type'] == 'B':
|
||||
comp_boot_disk_id = comp_disk['id']
|
||||
break
|
||||
disks_to_detach = []
|
||||
match aparam_disks['mode']:
|
||||
match aparam_disks_dict['mode']:
|
||||
case 'detach' | 'delete':
|
||||
disks_to_detach = aparam_disks_ids
|
||||
case 'match':
|
||||
comp_disk_ids = {
|
||||
disk['id'] for disk in self.comp_info['disks']
|
||||
}
|
||||
disks = set(aparam_disks_ids)
|
||||
disks_to_detach = comp_disk_ids - disks
|
||||
disks_to_detach = comp_disk_ids - set(aparam_disks_ids)
|
||||
if (
|
||||
comp_boot_disk_id is not None
|
||||
and comp_boot_disk_id in disks_to_detach
|
||||
@@ -1611,6 +1854,18 @@ class decort_kvmvm(DecortController):
|
||||
f'Compute ID {self.comp_id} while snapshots exist.'
|
||||
)
|
||||
|
||||
if aparam_disks_dict['mode'] in ('delete', 'detach'):
|
||||
for disk in aparam_disks:
|
||||
for param, value in disk.items():
|
||||
if param != 'id' and value is not None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "disks.objects" '
|
||||
'failed: only disk id can be specified if '
|
||||
'disks.mode is "delete" or "detach"'
|
||||
)
|
||||
break
|
||||
|
||||
if (
|
||||
(
|
||||
self.aparams['cpu'] is not None
|
||||
@@ -1637,11 +1892,72 @@ class decort_kvmvm(DecortController):
|
||||
|
||||
aparam_networks = self.aparams['networks']
|
||||
if aparam_networks is not None:
|
||||
vm_networks = self.comp_info['interfaces']
|
||||
if (
|
||||
not vm_networks
|
||||
and not self.is_vm_stopped_or_will_be_stopped
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "networks" failed: '
|
||||
'VM must be stopped before attach it\'s first network.'
|
||||
)
|
||||
vm_networks_ids = [
|
||||
network['netId'] for network in vm_networks
|
||||
if network['type'] != self.VMNetType.EMPTY.value
|
||||
]
|
||||
aparam_networks_ids = [
|
||||
network['id'] for network in aparam_networks
|
||||
if network['type'] != self.VMNetType.EMPTY.value
|
||||
]
|
||||
new_networks = list(
|
||||
set(aparam_networks_ids) - set(vm_networks_ids)
|
||||
)
|
||||
net_types = {net['type'] for net in aparam_networks}
|
||||
if new_networks:
|
||||
if not (
|
||||
len(new_networks) == 1
|
||||
and self.VMNetType.DPDK.value in net_types
|
||||
) and not self.is_vm_stopped_or_will_be_stopped:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "networks" failed: '
|
||||
'VM must be stopped to attach non-DPDK network.'
|
||||
)
|
||||
|
||||
if self.VMNetType.TRUNK.value in net_types:
|
||||
if self.check_aparam_networks_trunk() is False:
|
||||
check_errors = True
|
||||
|
||||
for network in aparam_networks:
|
||||
if (
|
||||
network['enabled'] is not None
|
||||
and network['type'] not in [
|
||||
self.VMNetType.VINS.value,
|
||||
self.VMNetType.EXTNET.value,
|
||||
self.VMNetType.DPDK.value,
|
||||
self.VMNetType.SDN.value,
|
||||
self.VMNetType.TRUNK.value,
|
||||
]
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "networks.enabled" failed: '
|
||||
'Can not enable or disable network '
|
||||
f'ID {network['id']} and type {network['type']}.'
|
||||
'Only networks of type VINS, EXTNET, DPDK, SDN, TRUNK '
|
||||
'can be enabled or disabled.'
|
||||
)
|
||||
|
||||
if self.check_aparam_cdrom() is False:
|
||||
check_errors = True
|
||||
|
||||
if self.check_aparam_storage_policy_id() is False:
|
||||
check_errors = True
|
||||
|
||||
if self.check_aparam_image_id() is False:
|
||||
check_errors = True
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
@@ -1731,6 +2047,9 @@ class decort_kvmvm(DecortController):
|
||||
snapshot_timestamp=snapshot_timestamp,
|
||||
snapshot_name=snapshot_name,
|
||||
snapshot_datetime=snapshot_datetime,
|
||||
sep_pool_name=self.aparams['clone_from']['sep_pool_name'],
|
||||
sep_id=self.aparams['clone_from']['sep_id'],
|
||||
storage_policy_id=self.aparams['clone_from']['storage_policy_id'],
|
||||
)
|
||||
return clone_id
|
||||
|
||||
@@ -1812,6 +2131,130 @@ class decort_kvmvm(DecortController):
|
||||
|
||||
return not check_errors
|
||||
|
||||
def check_aparam_cdrom(self) -> bool | None:
|
||||
check_errors = False
|
||||
aparam_cdrom = self.aparams['cdrom']
|
||||
if aparam_cdrom is not None:
|
||||
mode = aparam_cdrom['mode']
|
||||
if self.is_vm_stopped_or_will_be_stopped:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "cdrom" failed: '
|
||||
f'VM ID {self.comp_id} must be started to {mode} '
|
||||
f'CD-ROM.'
|
||||
)
|
||||
image_id = aparam_cdrom['image_id']
|
||||
match mode:
|
||||
case 'insert':
|
||||
if image_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "cdrom.image_id" failed: '
|
||||
f'cdrom.image_id must be specified '
|
||||
f'if cdrom.mode is "insert".'
|
||||
)
|
||||
_, image_info = self._image_get_by_id(
|
||||
image_id=image_id,
|
||||
)
|
||||
if image_info is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "cdrom.image_id" failed: '
|
||||
f'Image ID {image_id} not found.'
|
||||
)
|
||||
elif image_info['type'] != 'cdrom':
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "cdrom.image_id" failed: '
|
||||
f'Image ID {image_id} is not a CD-ROM type.'
|
||||
)
|
||||
case 'eject':
|
||||
if image_id is not None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "cdrom.image_id" failed: '
|
||||
f'cdrom.image_id must not be specified '
|
||||
f'if cdrom.mode is "eject".'
|
||||
)
|
||||
if not self.comp_info['cdImageId']:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "cdrom.mode" failed: '
|
||||
f'VM ID {self.comp_id} does not have CD-ROM '
|
||||
'to eject.'
|
||||
)
|
||||
|
||||
return not check_errors
|
||||
|
||||
def check_aparam_storage_policy_id(self) -> bool:
|
||||
check_errors = False
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is not None:
|
||||
for disk in self.comp_info['disks']:
|
||||
if aparam_storage_policy_id != disk['storage_policy_id']:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id can not be changed for compute '
|
||||
f'ID {self.comp_id} disk ID {disk['id']}'
|
||||
)
|
||||
|
||||
return not check_errors
|
||||
|
||||
def check_aparam_boot_disk_redeploy(self) -> bool:
|
||||
check_errors = False
|
||||
|
||||
disk_redeploy = self.aparams['boot']['disk_redeploy']
|
||||
if disk_redeploy:
|
||||
if self.aparams['storage_policy_id'] is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "storage_policy_id" failed:'
|
||||
'"storage_policy_id" must be specified to redeploy.'
|
||||
)
|
||||
|
||||
vm_has_boot_disk = False
|
||||
for disk in self.comp_info['disks']:
|
||||
if disk['type'] == 'B':
|
||||
vm_has_boot_disk = True
|
||||
break
|
||||
if not vm_has_boot_disk:
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "boot.redeploy" failed: '
|
||||
'VM does not have boot disk to redeploy.'
|
||||
)
|
||||
|
||||
aparam_disks = self.amodule.params['disks']
|
||||
if aparam_disks is not None and aparam_disks['mode'] == 'match':
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "disks.mode" failed: '
|
||||
'"disks.mode" must not be "match" to redeploy.'
|
||||
)
|
||||
|
||||
return not check_errors
|
||||
|
||||
def check_aparam_image_id(self) -> bool:
|
||||
check_errors = False
|
||||
|
||||
aparam_image_id = self.aparams['image_id']
|
||||
if aparam_image_id is not None:
|
||||
if aparam_image_id != self.comp_info['imageId']:
|
||||
if (
|
||||
self.aparams['boot'] is None
|
||||
or self.aparams['boot']['disk_redeploy'] is None
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
'Check for parameter "image_id" failed: '
|
||||
'"boot.disk_redeploy" must be set to True to change '
|
||||
'VM image.'
|
||||
)
|
||||
|
||||
return not check_errors
|
||||
|
||||
def find_networks_tags_intersections(
|
||||
self,
|
||||
trunk_networks: list,
|
||||
@@ -1958,7 +2401,7 @@ def main():
|
||||
amodule = subj.amodule
|
||||
|
||||
if subj.comp_id:
|
||||
if subj.comp_info['status'] in ("DISABLED", "MIGRATING", "DELETING", "DESTROYING", "ERROR", "REDEPLOYING"):
|
||||
if subj.comp_info['status'] in ("MIGRATING", "DELETING", "DESTROYING", "ERROR", "REDEPLOYING"):
|
||||
# cannot do anything on the existing Compute in the listed states
|
||||
subj.error() # was subj.nop()
|
||||
elif subj.comp_info['status'] in ("ENABLED", "DISABLED"):
|
||||
|
||||
@@ -42,8 +42,8 @@ class decort_lb(DecortController):
|
||||
if not self.lb_id:
|
||||
self.result['failed'] = True
|
||||
self.result['msg'] = "Specified LB ID {} not found."\
|
||||
.format(arg_amodule.params['lb _id'])
|
||||
self.fail_json(**self.result)
|
||||
.format(arg_amodule.params['lb_id'])
|
||||
self.amodule.fail_json(**self.result)
|
||||
self.rg_id = self.lb_facts['rgId']
|
||||
self.vins_id = self.lb_facts['vinsId']
|
||||
|
||||
@@ -51,12 +51,11 @@ class decort_lb(DecortController):
|
||||
self.rg_id, self.rg_facts = self.rg_find(0,arg_amodule.params['rg_id'], arg_rg_name="")
|
||||
if not self.rg_id:
|
||||
self.result['failed'] = True
|
||||
self.result['msg'] = "Specified RG ID {} not found.".format(arg_amodule.params['vins_id'])
|
||||
self.result['msg'] = "Specified RG ID {} not found.".format(arg_amodule.params['rg_id'])
|
||||
self.amodule.fail_json(**self.result)
|
||||
self.acc_id = self.rg_facts['accountId']
|
||||
|
||||
elif arg_amodule.params['account_id'] or arg_amodule.params['account_name'] != "":
|
||||
|
||||
if not arg_amodule.params['rg_name']:
|
||||
self.result['failed'] = True
|
||||
self.result['msg'] = ("RG name must be specified with account present")
|
||||
@@ -163,8 +162,9 @@ class decort_lb(DecortController):
|
||||
|
||||
def delete(self):
|
||||
self.lb_delete(self.lb_id, self.amodule.params['permanently'])
|
||||
self.lb_facts['status'] = 'DESTROYED'
|
||||
self.lb_id, self.lb_facts = self._lb_get_by_id(self.lb_id)
|
||||
return
|
||||
|
||||
def nop(self):
|
||||
"""No operation (NOP) handler for LB management by decort_lb module.
|
||||
This function is intended to be called from the main switch construct of the module
|
||||
@@ -252,10 +252,6 @@ class decort_lb(DecortController):
|
||||
type='int',
|
||||
default=0,
|
||||
),
|
||||
ext_ip_addr=dict(
|
||||
type='str',
|
||||
default='',
|
||||
),
|
||||
state=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
@@ -411,10 +407,10 @@ def main():
|
||||
if decon.result['failed']:
|
||||
amodule.fail_json(**decon.result)
|
||||
else:
|
||||
if decon.result['changed'] and amodule.params['state'] != 'absent':
|
||||
_, decon.lb_facts = decon.lb_find(decon.lb_id)
|
||||
if decon.lb_id:
|
||||
decon.result['facts'] = decon.package_facts(amodule.check_mode)
|
||||
if decon.result['changed']:
|
||||
_, decon.lb_facts = decon.lb_find(lb_id=decon.lb_id)
|
||||
decon.result['facts'] = decon.package_facts(amodule.check_mode)
|
||||
amodule.exit_json(**decon.result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -22,7 +22,8 @@ class decort_osimage(DecortController):
|
||||
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']
|
||||
self.image_info: dict
|
||||
self.virt_image_info: dict
|
||||
if amodule.params['account_name']:
|
||||
self.validated_account_id, _ = self.account_find(amodule.params['account_name'])
|
||||
else:
|
||||
@@ -34,23 +35,51 @@ class decort_osimage(DecortController):
|
||||
self.result['changed'] = False
|
||||
self.result['msg'] = ("Cannot find account '{}'").format(amodule.params['account_name'])
|
||||
amodule.fail_json(**self.result)
|
||||
self.acc_id = self.validated_account_id
|
||||
|
||||
|
||||
if amodule.params['virt_id'] != 0 and amodule.params['virt_name']:
|
||||
self.validated_virt_image_id, image_facts =\
|
||||
if (
|
||||
self.aparams['virt_id'] != 0
|
||||
or self.aparams['virt_name'] is not None
|
||||
):
|
||||
self.validated_virt_image_id, self.virt_image_info = (
|
||||
self.decort_virt_image_find(amodule)
|
||||
if (self.validated_virt_image_id and
|
||||
amodule.params['virt_name'] != image_facts['name']):
|
||||
self.decort_virt_image_rename(amodule)
|
||||
self.result['msg'] = 'Virtual image renamed successfully'
|
||||
elif amodule.params['image_id'] != 0 and amodule.params['image_name']:
|
||||
self.validated_image_id, image_facts = self.decort_image_find(amodule)
|
||||
if (self.validated_image_id and
|
||||
amodule.params['image_name'] != image_facts['name']):
|
||||
decort_osimage.decort_image_rename(self,amodule)
|
||||
self.result['msg'] = ("Image renamed successfully")
|
||||
|
||||
)
|
||||
if self.virt_image_info:
|
||||
_, linked_image_info = self._image_get_by_id(
|
||||
image_id=self.virt_image_info['linkTo']
|
||||
)
|
||||
self.acc_id = linked_image_info['accountId']
|
||||
if (
|
||||
self.aparams['virt_name'] is not None
|
||||
and self.aparams['virt_name']
|
||||
!= self.virt_image_info['name']
|
||||
):
|
||||
self.decort_virt_image_rename(amodule)
|
||||
self.result['msg'] = 'Virtual image renamed successfully'
|
||||
elif (
|
||||
self.aparams['image_id'] != 0
|
||||
or self.aparams['image_name'] is not None
|
||||
):
|
||||
self.validated_image_id, self.image_info = (
|
||||
self.decort_image_find(amodule)
|
||||
)
|
||||
if self.image_info:
|
||||
self.acc_id = self.image_info['accountId']
|
||||
if (
|
||||
amodule.params['image_name']
|
||||
and amodule.params['image_name'] != self.image_info['name']
|
||||
):
|
||||
decort_osimage.decort_image_rename(self,amodule)
|
||||
self.result['msg'] = ("Image renamed successfully")
|
||||
|
||||
if self.validated_image_id:
|
||||
self.check_amodule_args_for_change()
|
||||
elif self.validated_virt_image_id:
|
||||
self.check_amodule_args_for_change_virt_image()
|
||||
elif self.aparams['virt_name']:
|
||||
self.check_amodule_args_for_create_virt_image()
|
||||
else:
|
||||
self.check_amodule_args_for_create_image()
|
||||
|
||||
def decort_image_find(self, amodule):
|
||||
# function that finds the OS image
|
||||
@@ -121,21 +150,22 @@ class decort_osimage(DecortController):
|
||||
)
|
||||
|
||||
# function that creates OS image
|
||||
image_facts = self.image_create(img_name=self.validated_image_name,
|
||||
url=amodule.params['url'],
|
||||
gid=amodule.params['gid'],
|
||||
boot_mode=boot_mode,
|
||||
boot_loader_type=loader_type,
|
||||
hot_resize=hot_resize,
|
||||
username=amodule.params['image_username'],
|
||||
password=amodule.params['image_password'],
|
||||
account_id=self.validated_account_id,
|
||||
usernameDL=amodule.params['usernameDL'],
|
||||
passwordDL=amodule.params['passwordDL'],
|
||||
sepId=amodule.params['sepId'],
|
||||
poolName=amodule.params['poolName'],
|
||||
drivers=amodule.params['drivers'],
|
||||
network_interface_naming=network_interface_naming)
|
||||
image_facts = self.image_create(
|
||||
img_name=self.validated_image_name,
|
||||
url=amodule.params['url'],
|
||||
boot_mode=boot_mode,
|
||||
boot_loader_type=loader_type,
|
||||
hot_resize=hot_resize,
|
||||
username=amodule.params['image_username'],
|
||||
password=amodule.params['image_password'],
|
||||
account_id=self.validated_account_id,
|
||||
usernameDL=amodule.params['usernameDL'],
|
||||
passwordDL=amodule.params['passwordDL'],
|
||||
sepId=amodule.params['sepId'],
|
||||
poolName=amodule.params['poolName'],
|
||||
network_interface_naming=network_interface_naming,
|
||||
storage_policy_id=amodule.params['storage_policy_id'],
|
||||
)
|
||||
self.result['changed'] = True
|
||||
return image_facts
|
||||
|
||||
@@ -151,8 +181,9 @@ class decort_osimage(DecortController):
|
||||
def decort_image_delete(self,amodule):
|
||||
# function that removes an image
|
||||
self.image_delete(imageId=amodule.image_id_delete)
|
||||
self.result['changed'] = True
|
||||
self.result['msg'] = ("Image '{}' deleted").format(amodule.image_id_delete)
|
||||
_, image_facts = decort_osimage._image_get_by_id(self, amodule.image_id_delete)
|
||||
self.result['facts'] = decort_osimage.decort_osimage_package_facts(image_facts, amodule.check_mode)
|
||||
return
|
||||
|
||||
def decort_virt_image_create(self,amodule):
|
||||
# function that creates a virtual image
|
||||
@@ -231,6 +262,8 @@ class decort_osimage(DecortController):
|
||||
'networkInterfaceNaming'
|
||||
]
|
||||
ret_dict['hot_resize'] = arg_osimage_facts['hotResize']
|
||||
ret_dict['storage_policy_id'] = arg_osimage_facts['storage_policy_id']
|
||||
ret_dict['to_clean'] = arg_osimage_facts['to_clean']
|
||||
return ret_dict
|
||||
|
||||
@property
|
||||
@@ -273,17 +306,9 @@ class decort_osimage(DecortController):
|
||||
'present',
|
||||
],
|
||||
),
|
||||
drivers=dict(
|
||||
type='str',
|
||||
default='KVM_X86',
|
||||
),
|
||||
url=dict(
|
||||
type='str',
|
||||
),
|
||||
gid=dict(
|
||||
type='int',
|
||||
default=0,
|
||||
),
|
||||
sepId=dict(
|
||||
type='int',
|
||||
default=0,
|
||||
@@ -333,10 +358,102 @@ class decort_osimage(DecortController):
|
||||
'eth',
|
||||
],
|
||||
),
|
||||
storage_policy_id=dict(
|
||||
type='int',
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
def check_amodule_args_for_change(self):
|
||||
check_errors = False
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if (
|
||||
aparam_storage_policy_id is not None
|
||||
and aparam_storage_policy_id
|
||||
not in self.acc_info['storage_policy_ids']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
f'Account ID {self.acc_id} does not have access to '
|
||||
f'storage_policy_id {aparam_storage_policy_id}'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_amodule_args_for_change_virt_image(self):
|
||||
check_errors = False
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if (
|
||||
aparam_storage_policy_id is not None
|
||||
and (
|
||||
aparam_storage_policy_id
|
||||
!= self.virt_image_info['storage_policy_id']
|
||||
)
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id can not be changed in virtual image'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_amodule_args_for_create_image(self):
|
||||
check_errors = False
|
||||
|
||||
aparam_account_id = self.aparams['account_id']
|
||||
if aparam_account_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "account_id" failed: '
|
||||
'account_id must be specified when creating '
|
||||
'a new image'
|
||||
)
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id must be specified when creating '
|
||||
'a new image'
|
||||
)
|
||||
elif (
|
||||
aparam_storage_policy_id
|
||||
not in self.acc_info['storage_policy_ids']
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
f'Account ID {self.acc_id} does not have access to '
|
||||
f'storage_policy_id {aparam_storage_policy_id}'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_amodule_args_for_create_virt_image(self):
|
||||
check_errors = False
|
||||
|
||||
aparam_storage_policy_id = self.aparams['storage_policy_id']
|
||||
if aparam_storage_policy_id is not None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "storage_policy_id" failed: '
|
||||
'storage_policy_id can not be specified when creating '
|
||||
'virtual image'
|
||||
)
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
|
||||
def main():
|
||||
decon = decort_osimage()
|
||||
amodule = decon.amodule
|
||||
@@ -360,15 +477,31 @@ def main():
|
||||
decon.result['msg'] = ("Cannot find OS image")
|
||||
amodule.fail_json(**decon.result)
|
||||
|
||||
if decon.validated_virt_image_id and decon.target_image_id:
|
||||
if decort_osimage.decort_osimage_package_facts(image_facts)['linkto'] != decon.target_image_id:
|
||||
if decon.validated_virt_image_id:
|
||||
if (
|
||||
decon.target_image_id
|
||||
and decort_osimage.decort_osimage_package_facts(image_facts)[
|
||||
'linkto'
|
||||
] != decon.target_image_id
|
||||
):
|
||||
decort_osimage.decort_virt_image_link(decon,amodule)
|
||||
decon.result['changed'] = True
|
||||
amodule.exit_json(**decon.result)
|
||||
if (
|
||||
amodule.params['storage_policy_id'] is not None
|
||||
and amodule.params['storage_policy_id']
|
||||
!= image_facts['storage_policy_id']
|
||||
):
|
||||
decon.image_change_storage_policy(
|
||||
image_id=decon.validated_virt_image_id,
|
||||
storage_policy_id=amodule.params['storage_policy_id'],
|
||||
)
|
||||
|
||||
if decon.validated_virt_image_id > 0 and amodule.params['state'] == "absent":
|
||||
if amodule.params['state'] == "absent" and decon.validated_virt_image_id:
|
||||
amodule.image_id_delete = decon.validated_virt_image_id
|
||||
decort_osimage.decort_image_delete(decon, amodule)
|
||||
image_id, image_facts = decort_osimage.decort_virt_image_find(decon, amodule)
|
||||
if image_facts['status'] != 'PURGED':
|
||||
decort_osimage.decort_image_delete(decon,amodule)
|
||||
|
||||
elif amodule.params['image_name'] or amodule.params['image_id']:
|
||||
image_id, image_facts = decort_osimage.decort_image_find(decon, amodule)
|
||||
@@ -385,16 +518,38 @@ def main():
|
||||
decon.validated_image_id = decort_osimage.decort_osimage_package_facts(image_facts)['id']
|
||||
|
||||
elif amodule.params['state'] == "absent" and decon.validated_image_id:
|
||||
amodule.image_id_delete = decon.validated_image_id
|
||||
amodule.image_id_delete = decon.validated_image_id
|
||||
image_id, image_facts = decort_osimage.decort_image_find(decon, amodule)
|
||||
if image_facts['status'] != 'DESTROYED':
|
||||
decort_osimage.decort_image_delete(decon,amodule)
|
||||
|
||||
if decon.validated_image_id:
|
||||
if (
|
||||
amodule.params['storage_policy_id'] is not None
|
||||
and amodule.params['storage_policy_id']
|
||||
!= image_facts['storage_policy_id']
|
||||
):
|
||||
decon.image_change_storage_policy(
|
||||
image_id=decon.validated_image_id,
|
||||
storage_policy_id=amodule.params['storage_policy_id'],
|
||||
)
|
||||
|
||||
if decon.result['failed'] == True:
|
||||
# we failed to find the specified image - fail the module
|
||||
decon.result['changed'] = False
|
||||
amodule.fail_json(**decon.result)
|
||||
else:
|
||||
if decon.validated_image_id:
|
||||
_, image_facts = decon.decort_image_find(amodule=amodule)
|
||||
elif decon.validated_virt_image_id:
|
||||
_, image_facts = decon.decort_virt_image_find(amodule=amodule)
|
||||
decon.result['facts'] = decort_osimage.decort_osimage_package_facts(
|
||||
arg_osimage_facts=image_facts,
|
||||
arg_check_mode=amodule.check_mode,
|
||||
)
|
||||
|
||||
amodule.exit_json(**decon.result)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -97,26 +97,57 @@ class decort_rg(DecortController):
|
||||
self.amodule.params['rg_name'],
|
||||
self.validated_acc_id)
|
||||
return
|
||||
|
||||
|
||||
def update(self):
|
||||
resources = self.rg_facts['Resources']['Reserved']
|
||||
incorrect_quota = dict(Requested=dict(),
|
||||
Reserved=dict(),)
|
||||
query_key_map = dict(cpu='cpu',
|
||||
ram='ram',
|
||||
disk='disksize',
|
||||
ext_ips='extips',
|
||||
net_transfer='exttraffic',)
|
||||
query_key_map = dict(
|
||||
cpu='cpu',
|
||||
ram='ram',
|
||||
disk='disksize',
|
||||
ext_ips='extips',
|
||||
net_transfer='exttraffic',
|
||||
storage_policies='policies',
|
||||
)
|
||||
if self.amodule.params['quotas']:
|
||||
for quota_item in self.amodule.params['quotas']:
|
||||
if self.amodule.params['quotas'][quota_item] < resources[query_key_map[quota_item]]:
|
||||
incorrect_quota['Requested'][quota_item]=self.amodule.params['quotas'][quota_item]
|
||||
incorrect_quota['Reserved'][quota_item]=resources[query_key_map[quota_item]]
|
||||
if quota_item == 'storage_policies':
|
||||
rg_storage_policies = resources[query_key_map[quota_item]]
|
||||
aparam_storage_policies = self.amodule.params['quotas'][
|
||||
quota_item
|
||||
]
|
||||
for aparam_storage_policy in aparam_storage_policies:
|
||||
aparam_storage_policy_id = aparam_storage_policy['id']
|
||||
rg_storage_policy = rg_storage_policies.get(
|
||||
str(aparam_storage_policy_id)
|
||||
)
|
||||
if (
|
||||
rg_storage_policy
|
||||
and aparam_storage_policy['storage_size_gb']
|
||||
< rg_storage_policy['disksize']
|
||||
):
|
||||
incorrect_quota['Requested'][quota_item] = (
|
||||
self.amodule.params['quotas'][quota_item]
|
||||
)
|
||||
incorrect_quota['Reserved'][quota_item] = (
|
||||
resources[query_key_map[quota_item]]
|
||||
)
|
||||
elif (
|
||||
self.amodule.params['quotas'][quota_item]
|
||||
< resources[query_key_map[quota_item]]
|
||||
):
|
||||
incorrect_quota['Requested'][quota_item] = (
|
||||
self.amodule.params['quotas'][quota_item]
|
||||
)
|
||||
incorrect_quota['Reserved'][quota_item] = (
|
||||
resources[query_key_map[quota_item]]
|
||||
)
|
||||
|
||||
if incorrect_quota['Requested']:
|
||||
self.result['msg'] = ("Cannot limit less than already reserved'{}'").format(incorrect_quota)
|
||||
self.result['failed'] = True
|
||||
|
||||
|
||||
if not self.result['failed']:
|
||||
self.rg_update(
|
||||
arg_rg_dict=self.rg_facts,
|
||||
@@ -243,6 +274,7 @@ class decort_rg(DecortController):
|
||||
ret_dict['uniqPools'] = self.rg_facts['uniqPools']
|
||||
ret_dict['description'] = self.rg_facts['desc']
|
||||
ret_dict['sdn_access_group_id'] = self.rg_facts['sdn_access_group_id']
|
||||
ret_dict['storage_policy_ids'] = self.rg_facts['storage_policy_ids']
|
||||
|
||||
return ret_dict
|
||||
|
||||
|
||||
351
library/decort_security_group.py
Normal file
351
library/decort_security_group.py
Normal file
@@ -0,0 +1,351 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: decort_security_group
|
||||
|
||||
description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home). # noqa: E501
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.decort_utils import DecortController
|
||||
|
||||
|
||||
class DecortSecurityGroup(DecortController):
|
||||
id: int = 0
|
||||
facts: dict = dict()
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(AnsibleModule(**self.amodule_init_args))
|
||||
|
||||
@property
|
||||
def amodule_init_args(self) -> dict:
|
||||
return self.pack_amodule_init_args(
|
||||
argument_spec=dict(
|
||||
account_id=dict(
|
||||
type='int',
|
||||
),
|
||||
description=dict(
|
||||
type='str',
|
||||
),
|
||||
id=dict(
|
||||
type='int',
|
||||
),
|
||||
name=dict(
|
||||
type='str',
|
||||
),
|
||||
rules=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
mode=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
e.value
|
||||
for e in self.SecurityGroupRuleMode
|
||||
],
|
||||
default=self.SecurityGroupRuleMode.update.value,
|
||||
),
|
||||
objects=dict(
|
||||
type='list',
|
||||
elements='dict',
|
||||
required=True,
|
||||
options=dict(
|
||||
direction=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
e.name for e in
|
||||
self.SecurityGroupRuleDirection
|
||||
],
|
||||
required=True,
|
||||
),
|
||||
ethertype=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
e.name for e in
|
||||
self.SecurityGroupRuleEtherType
|
||||
],
|
||||
),
|
||||
id=dict(
|
||||
type='int',
|
||||
),
|
||||
port_range=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
min=dict(
|
||||
type='int',
|
||||
),
|
||||
max=dict(
|
||||
type='int',
|
||||
),
|
||||
),
|
||||
),
|
||||
protocol=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
e.name for e in
|
||||
self.SecurityGroupRuleProtocol
|
||||
],
|
||||
),
|
||||
remote_ip_prefix=dict(
|
||||
type='str',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
state=dict(
|
||||
type='str',
|
||||
choices=[e.value for e in self.SecurityGroupState],
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
def run(self):
|
||||
if self.aparams['id'] is not None:
|
||||
self.id = self.aparams['id']
|
||||
elif self.aparams['name'] is not None:
|
||||
security_group = self.security_group_find(
|
||||
account_id=self.aparams['account_id'],
|
||||
name=self.aparams['name'],
|
||||
)
|
||||
if security_group:
|
||||
self.id = security_group['id']
|
||||
|
||||
if self.id:
|
||||
self.get_info()
|
||||
self.check_amodule_args_for_change()
|
||||
self.change()
|
||||
else:
|
||||
self.check_amodule_args_for_create()
|
||||
self.create()
|
||||
if not self.amodule.check_mode:
|
||||
self.change_rules()
|
||||
|
||||
if self.result['changed']:
|
||||
self.get_info()
|
||||
self.exit()
|
||||
|
||||
def get_info(self):
|
||||
self.facts: dict = self.security_group_get(id=self.id)
|
||||
self.facts['created_timestamp'] = self.facts.pop('created_at')
|
||||
self.facts['updated_timestamp'] = self.facts.pop('updated_at')
|
||||
for rule in self.facts['rules']:
|
||||
rule['port_range'] = {
|
||||
'min': rule.pop('port_range_min'),
|
||||
'max': rule.pop('port_range_max'),
|
||||
}
|
||||
|
||||
def check_amodule_args_for_create(self):
|
||||
check_errors = False
|
||||
|
||||
aparam_account_id = self.aparams['account_id']
|
||||
if aparam_account_id is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "account_id" failed: '
|
||||
'account_id must be specified when creating '
|
||||
'a new security group'
|
||||
)
|
||||
|
||||
aparam_name = self.aparams['name']
|
||||
if aparam_name is None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "name" failed: '
|
||||
'name must be specified when creating '
|
||||
'a new security group'
|
||||
)
|
||||
|
||||
aparam_state = self.aparams['state']
|
||||
if (
|
||||
aparam_state is not None
|
||||
and aparam_state == self.SecurityGroupState.absent.value
|
||||
):
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "state" failed: '
|
||||
'state can not be "absent" when creating '
|
||||
'a new security group'
|
||||
)
|
||||
|
||||
if self.check_aparam_rules(for_create=True) is False:
|
||||
check_errors = True
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_amodule_args_for_change(self):
|
||||
check_errors = False
|
||||
|
||||
if self.check_aparam_rules() is False:
|
||||
check_errors = True
|
||||
|
||||
if check_errors:
|
||||
self.exit(fail=True)
|
||||
|
||||
def check_aparam_rules(self, for_create: bool = False):
|
||||
check_errors = False
|
||||
|
||||
aparam_rules = self.aparams['rules']
|
||||
if aparam_rules is None:
|
||||
return True
|
||||
|
||||
mode = aparam_rules['mode']
|
||||
rules = aparam_rules['objects']
|
||||
|
||||
if for_create and mode == self.SecurityGroupRuleMode.delete.value:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "rules.mode" failed: '
|
||||
'mode can not be "delete" when creating '
|
||||
'new security group'
|
||||
)
|
||||
|
||||
sg_rules_ids = []
|
||||
if self.facts.get('rules'):
|
||||
sg_rules_ids = [rule['id'] for rule in self.facts['rules']]
|
||||
for rule in rules:
|
||||
rule_id = rule.get('id')
|
||||
if rule_id is not None:
|
||||
if for_create:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "rules.objects.id" failed: '
|
||||
'can not set rule id when creating new '
|
||||
'security group'
|
||||
)
|
||||
elif rule_id not in sg_rules_ids:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "rules.objects.id" failed: '
|
||||
f'rule ID {rule_id} not found for '
|
||||
f'security group ID {self.id}'
|
||||
)
|
||||
if mode == self.SecurityGroupRuleMode.delete.value:
|
||||
for param, value in rule.items():
|
||||
if param != 'id' and value is not None:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "rules.objects" '
|
||||
'failed: only rule id can be specified if'
|
||||
'rules.mode is "delete"'
|
||||
)
|
||||
break
|
||||
elif mode == self.SecurityGroupRuleMode.delete.value:
|
||||
check_errors = True
|
||||
self.message(
|
||||
msg='Check for parameter "rules.objects" '
|
||||
'failed: rule id must be specified if mode is delete'
|
||||
)
|
||||
|
||||
return not check_errors
|
||||
|
||||
def create(self):
|
||||
security_groups_by_account_id = self.user_security_groups(
|
||||
account_id=self.aparams['account_id']
|
||||
)
|
||||
sg_names = [sg['name'] for sg in security_groups_by_account_id]
|
||||
if self.aparams['name'] not in sg_names:
|
||||
self.id = self.security_group_create(
|
||||
account_id=self.aparams['account_id'],
|
||||
name=self.aparams['name'],
|
||||
description=self.aparams['description'],
|
||||
)
|
||||
|
||||
def change(self):
|
||||
self.change_state()
|
||||
self.change_params()
|
||||
self.change_rules()
|
||||
|
||||
def change_state(self):
|
||||
if self.aparams['state'] == self.SecurityGroupState.absent.value:
|
||||
self.delete()
|
||||
|
||||
def change_params(self):
|
||||
aparam_name = self.aparams['name']
|
||||
aparam_description = self.aparams['description']
|
||||
new_name, new_description = None, None
|
||||
if (
|
||||
aparam_name is not None
|
||||
and aparam_name != self.facts['name']
|
||||
):
|
||||
new_name = aparam_name
|
||||
if (
|
||||
aparam_description is not None
|
||||
and aparam_description != self.facts['description']
|
||||
):
|
||||
new_description = aparam_description
|
||||
if new_name or new_description:
|
||||
self.security_group_update(
|
||||
security_group_id=self.id,
|
||||
name=new_name,
|
||||
description=new_description,
|
||||
)
|
||||
|
||||
def change_rules(self):
|
||||
aparam_rules = self.aparams['rules']
|
||||
if aparam_rules is not None:
|
||||
rules = aparam_rules['objects']
|
||||
match aparam_rules['mode']:
|
||||
case self.SecurityGroupRuleMode.delete.value:
|
||||
for rule in rules:
|
||||
self.security_group_detele_rule(
|
||||
security_group_id=self.id,
|
||||
rule_id=rule['id'],
|
||||
)
|
||||
case self.SecurityGroupRuleMode.match.value:
|
||||
for rule in rules:
|
||||
if rule.get('id') is None:
|
||||
self.create_rule(rule=rule)
|
||||
|
||||
sg_rules_ids = set(
|
||||
[rule['id'] for rule in self.facts['rules']]
|
||||
)
|
||||
aparam_rules_ids = set(
|
||||
[rule['id'] for rule in rules if rule.get('id')]
|
||||
)
|
||||
rules_ids_to_delete = sg_rules_ids - aparam_rules_ids
|
||||
for rule_id in rules_ids_to_delete:
|
||||
self.security_group_detele_rule(
|
||||
security_group_id=self.id,
|
||||
rule_id=rule_id,
|
||||
)
|
||||
case self.SecurityGroupRuleMode.update.value:
|
||||
for rule in rules:
|
||||
if rule.get('id') is None:
|
||||
self.create_rule(rule=rule)
|
||||
|
||||
def delete(self):
|
||||
self.security_group_detele(security_group_id=self.id)
|
||||
self.facts = {}
|
||||
self.exit()
|
||||
|
||||
def create_rule(self, rule: dict):
|
||||
port_range_min, port_range_max = None, None
|
||||
if rule.get('port_range'):
|
||||
port_range_min = rule['port_range'].get('min')
|
||||
port_range_max = rule['port_range'].get('max')
|
||||
self.security_group_create_rule(
|
||||
security_group_id=self.id,
|
||||
direction=self.SecurityGroupRuleDirection[rule['direction']],
|
||||
ethertype=(
|
||||
self.SecurityGroupRuleEtherType[rule['ethertype']]
|
||||
if rule.get('ethertype') else None
|
||||
),
|
||||
protocol=(
|
||||
self.SecurityGroupRuleProtocol[rule['protocol']]
|
||||
if rule.get('protocol') else None
|
||||
),
|
||||
port_range_min=port_range_min,
|
||||
port_range_max=port_range_max,
|
||||
remote_ip_prefix=rule.get('remote_ip_prefix'),
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
DecortSecurityGroup().run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
50
library/decort_storage_policy.py
Normal file
50
library/decort_storage_policy.py
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: decort_storage_policy
|
||||
|
||||
description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home). # noqa: E501
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.decort_utils import DecortController
|
||||
|
||||
|
||||
class DecortStoragePolicy(DecortController):
|
||||
def __init__(self):
|
||||
super().__init__(AnsibleModule(**self.amodule_init_args))
|
||||
self.id: int = self.aparams['id']
|
||||
|
||||
@property
|
||||
def amodule_init_args(self) -> dict:
|
||||
return self.pack_amodule_init_args(
|
||||
argument_spec=dict(
|
||||
id=dict(
|
||||
type='int',
|
||||
required=True,
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
def run(self):
|
||||
self.get_info()
|
||||
self.exit()
|
||||
|
||||
def get_info(self):
|
||||
self.facts = self.storage_policy_get(id=self.id)
|
||||
self.facts['sep_pools'] = self.facts.pop('access_seps_pools')
|
||||
self.facts['iops_limit'] = self.facts.pop('limit_iops')
|
||||
self.facts['usage']['account_ids'] = self.facts['usage'].pop(
|
||||
'accounts'
|
||||
)
|
||||
self.facts['usage']['rg_ids'] = self.facts['usage'].pop('resgroups')
|
||||
|
||||
|
||||
def main():
|
||||
DecortStoragePolicy().run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -48,6 +48,9 @@ class DecortUserInfo(DecortController):
|
||||
e.value for e in self.AccountStatus
|
||||
],
|
||||
),
|
||||
zone_id=dict(
|
||||
type='int',
|
||||
),
|
||||
),
|
||||
),
|
||||
pagination=dict(
|
||||
@@ -303,6 +306,143 @@ class DecortUserInfo(DecortController):
|
||||
),
|
||||
),
|
||||
),
|
||||
storage_policies=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
filter=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
account_id=dict(
|
||||
type='int',
|
||||
),
|
||||
description=dict(
|
||||
type='str',
|
||||
),
|
||||
id=dict(
|
||||
type='int',
|
||||
),
|
||||
iops_limit=dict(
|
||||
type='int',
|
||||
),
|
||||
name=dict(
|
||||
type='str',
|
||||
),
|
||||
pool_name=dict(
|
||||
type='str',
|
||||
),
|
||||
rg_id=dict(
|
||||
type='int',
|
||||
),
|
||||
sep_id=dict(
|
||||
type='int',
|
||||
),
|
||||
status=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
e.value for e
|
||||
in self.StoragePolicyStatus
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
pagination=dict(
|
||||
type='dict',
|
||||
apply_defaults=True,
|
||||
options=dict(
|
||||
number=dict(
|
||||
type='int',
|
||||
default=1,
|
||||
),
|
||||
size=dict(
|
||||
type='int',
|
||||
default=50,
|
||||
),
|
||||
),
|
||||
),
|
||||
sorting=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
asc=dict(
|
||||
type='bool',
|
||||
default=True,
|
||||
),
|
||||
field=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
e.value for e
|
||||
in self.StoragePoliciesSortableField
|
||||
],
|
||||
required=True,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
security_groups=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
filter=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
account_id=dict(
|
||||
type='int',
|
||||
),
|
||||
created_timestamp_max=dict(
|
||||
type='int',
|
||||
),
|
||||
created_timestamp_min=dict(
|
||||
type='int',
|
||||
),
|
||||
description=dict(
|
||||
type='str',
|
||||
),
|
||||
id=dict(
|
||||
type='int',
|
||||
),
|
||||
name=dict(
|
||||
type='str',
|
||||
),
|
||||
updated_timestamp_max=dict(
|
||||
type='int',
|
||||
),
|
||||
updated_timestamp_min=dict(
|
||||
type='int',
|
||||
),
|
||||
),
|
||||
),
|
||||
pagination=dict(
|
||||
type='dict',
|
||||
apply_defaults=True,
|
||||
options=dict(
|
||||
number=dict(
|
||||
type='int',
|
||||
default=1,
|
||||
),
|
||||
size=dict(
|
||||
type='int',
|
||||
default=50,
|
||||
),
|
||||
),
|
||||
),
|
||||
sorting=dict(
|
||||
type='dict',
|
||||
options=dict(
|
||||
asc=dict(
|
||||
type='bool',
|
||||
default=True,
|
||||
),
|
||||
field=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
e.name for e
|
||||
in self.SecurityGroupSortableField
|
||||
],
|
||||
required=True,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
@@ -390,6 +530,8 @@ class DecortUserInfo(DecortController):
|
||||
self.AccountStatus(input_args_filter_status)
|
||||
)
|
||||
|
||||
mapped_args['zone_id'] = input_args_filter['zone_id']
|
||||
|
||||
input_args_pagination = input_args['pagination']
|
||||
if input_args_pagination:
|
||||
mapped_args['page_number'] = input_args_pagination['number']
|
||||
@@ -552,6 +694,82 @@ class DecortUserInfo(DecortController):
|
||||
|
||||
return mapped_args
|
||||
|
||||
@property
|
||||
def mapped_storage_policies_args(self):
|
||||
"""
|
||||
Map the module argument `storage_policies` to
|
||||
arguments dictionary for the method
|
||||
`DecortController.user_storage_policies`.
|
||||
"""
|
||||
|
||||
input_args = self.aparams['storage_policies']
|
||||
if not input_args:
|
||||
return input_args
|
||||
|
||||
mapped_args = {}
|
||||
|
||||
input_args_filter = input_args['filter']
|
||||
if input_args_filter:
|
||||
mapped_args.update(input_args_filter)
|
||||
|
||||
input_args_filter_status = input_args_filter['status']
|
||||
if input_args_filter_status:
|
||||
mapped_args['status'] = (
|
||||
self.StoragePolicyStatus(input_args_filter_status)
|
||||
)
|
||||
|
||||
input_args_pagination = input_args['pagination']
|
||||
if input_args_pagination:
|
||||
mapped_args['page_number'] = input_args_pagination['number']
|
||||
mapped_args['page_size'] = input_args_pagination['size']
|
||||
|
||||
input_args_sorting = input_args['sorting']
|
||||
if input_args_sorting:
|
||||
mapped_args['sort_by_asc'] = input_args_sorting['asc']
|
||||
|
||||
input_args_sorting_field = input_args_sorting['field']
|
||||
if input_args_sorting_field:
|
||||
mapped_args['sort_by_field'] = (
|
||||
self.StoragePoliciesSortableField(input_args_sorting_field)
|
||||
)
|
||||
|
||||
return mapped_args
|
||||
|
||||
@property
|
||||
def mapped_security_groups_args(self):
|
||||
"""
|
||||
Map the module argument `security_groups` to
|
||||
arguments dictionary for the method
|
||||
`DecortController.user_security_groups`.
|
||||
"""
|
||||
|
||||
input_args = self.aparams['security_groups']
|
||||
if not input_args:
|
||||
return input_args
|
||||
|
||||
mapped_args = {}
|
||||
|
||||
input_args_filter = input_args['filter']
|
||||
if input_args_filter:
|
||||
mapped_args.update(input_args_filter)
|
||||
|
||||
input_args_pagination = input_args['pagination']
|
||||
if input_args_pagination:
|
||||
mapped_args['page_number'] = input_args_pagination['number']
|
||||
mapped_args['page_size'] = input_args_pagination['size']
|
||||
|
||||
input_args_sorting = input_args['sorting']
|
||||
if input_args_sorting:
|
||||
mapped_args['sort_by_asc'] = input_args_sorting['asc']
|
||||
|
||||
input_args_sorting_field = input_args_sorting['field']
|
||||
if input_args_sorting_field:
|
||||
mapped_args['sort_by_field'] = (
|
||||
self.SecurityGroupSortableField[input_args_sorting_field]
|
||||
)
|
||||
|
||||
return mapped_args
|
||||
|
||||
def run(self):
|
||||
self.get_info()
|
||||
self.exit()
|
||||
@@ -606,6 +824,52 @@ class DecortUserInfo(DecortController):
|
||||
trunk_facts['ovs_bridge'] = trunk_facts.pop('ovsBridge')
|
||||
trunk_facts['vlan_ids'] = trunk_facts.pop('trunkTags')
|
||||
|
||||
if self.aparams['storage_policies']:
|
||||
self.facts['storage_policies'] = self.user_storage_policies(
|
||||
**self.mapped_storage_policies_args
|
||||
)
|
||||
for storage_policy_facts in self.facts['storage_policies']:
|
||||
storage_policy_facts['sep_pools'] = storage_policy_facts.pop(
|
||||
'access_seps_pools'
|
||||
)
|
||||
storage_policy_facts['iops_limit'] = storage_policy_facts.pop(
|
||||
'limit_iops'
|
||||
)
|
||||
storage_policy_facts['usage']['account_ids'] = (
|
||||
storage_policy_facts['usage'].pop('accounts')
|
||||
)
|
||||
storage_policy_facts['usage']['rg_ids'] = (
|
||||
storage_policy_facts['usage'].pop('resgroups')
|
||||
)
|
||||
|
||||
if self.aparams['security_groups']:
|
||||
self.facts['security_groups'] = self.user_security_groups(
|
||||
**self.mapped_security_groups_args
|
||||
)
|
||||
for security_groups_facts in self.facts['security_groups']:
|
||||
for rule in security_groups_facts.get('rules', []):
|
||||
rule['port_range'] = {
|
||||
'min': rule.pop('port_range_min'),
|
||||
'max': rule.pop('port_range_max'),
|
||||
}
|
||||
|
||||
security_groups_facts['created_timestamp'] = (
|
||||
security_groups_facts.pop('created_at')
|
||||
)
|
||||
security_groups_facts['created_timestamp_readable'] = (
|
||||
self.sec_to_dt_str(security_groups_facts[
|
||||
'created_timestamp'
|
||||
])
|
||||
)
|
||||
security_groups_facts['updated_timestamp'] = (
|
||||
security_groups_facts.pop('updated_at')
|
||||
)
|
||||
security_groups_facts['updated_timestamp_readable'] = (
|
||||
self.sec_to_dt_str(security_groups_facts[
|
||||
'updated_timestamp'
|
||||
])
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
DecortUserInfo().run()
|
||||
|
||||
@@ -170,7 +170,7 @@ class decort_vins(DecortController):
|
||||
|
||||
return
|
||||
def delete(self):
|
||||
self.vins_delete(self.vins_id, permanently=True)
|
||||
self.vins_delete(self.vins_id, self.amodule.params['permanently'])
|
||||
self.vins_facts['status'] = 'DESTROYED'
|
||||
return
|
||||
def nop(self):
|
||||
@@ -320,6 +320,10 @@ class decort_vins(DecortController):
|
||||
type='str',
|
||||
default='',
|
||||
),
|
||||
permanently=dict(
|
||||
type='bool',
|
||||
default=False,
|
||||
),
|
||||
vins_id=dict(
|
||||
type='int',
|
||||
default=0,
|
||||
@@ -416,8 +420,9 @@ def main():
|
||||
vins_should_exist = True
|
||||
elif amodule.params['state'] == 'absent':
|
||||
# destroy permanently
|
||||
decon.delete()
|
||||
vins_should_exist = False
|
||||
if decon.amodule.params['permanently']:
|
||||
decon.delete()
|
||||
vins_should_exist = False
|
||||
elif amodule.params['state'] == 'disabled':
|
||||
decon.error()
|
||||
vins_should_exist = False
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: decort_snapshot
|
||||
module: decort_vm_snapshot
|
||||
|
||||
description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home). # noqa: E501
|
||||
'''
|
||||
@@ -12,7 +12,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.decort_utils import DecortController
|
||||
|
||||
|
||||
class DecortSnapshot(DecortController):
|
||||
class DecortVMSnapshot(DecortController):
|
||||
def __init__(self):
|
||||
super().__init__(AnsibleModule(**self.amodule_init_args))
|
||||
self.check_amodule_args()
|
||||
@@ -181,7 +181,7 @@ class DecortSnapshot(DecortController):
|
||||
|
||||
|
||||
def main():
|
||||
DecortSnapshot().run()
|
||||
DecortVMSnapshot().run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user