diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f6f766..b8c72f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,137 +1,16 @@
-# Список изменений в версии 5.3.0
+# Список изменений в версии 5.4.0
## Обновления
-### Глобальные
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-62 | Добавлен вывод текста ответа в сообщение об ошибке запроса к API. |
-
-
-### Модуль decort_bservice
+### Модуль decort_account_info
| Идентификатор
задачи | Описание |
| --- | --- |
-| BANS-434 | В модуле **decort_bservice** в возвращаемом словаре `facts` ключи `groupsIds` и `groupsName` заменены на ключ `groups`, который содержит словари с информацией о группах базовой службы. |
+| BANS-471 | Добавлен новый модуль **decort_account_info**, который позволяет получить основную информацию об аккаунте. |
## Исправления
-### Модуль decort_bservice
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-366 | Работа модуля **decort_bservice** завершалась ошибкой Python при удалении базовой службы. |
-| BANS-367 | Работа модуля **decort_bservice** завершалась ошибкой модуля при использовании параметров `rg_name` и `account_name` вместо параметра `rg_id`. |
-| BANS-368 | Работа модуля **decort_bservice** завершалась ошибкой Python при повторном запуске создания базовой службы. |
-| BANS-369 | Модуль **decort_bservice** не реагировал на режим **check mode** при создании базовой службы. |
-
-### Модуль decort_disk
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-246 | Работа модуля **decort_disk** завершалась ошибкой Python при обработке ошибочных сценариев работы. |
-| BANS-248 | Работа модуля **decort_disk** завершалась ошибкой Python при попытке валидировать заданный параметр `limitIO`. |
-| BANS-249 | Работа модуля **decort_disk** завершалась ошибкой Python при попытке при попытке выполнить изменения в соответствии с заданным параметром `limitIO`. |
-| BANS-250 | Работа модуля **decort_disk** завершалась ошибкой Python при заданном параметре `shareable`. |
-| BANS-255 | Модуль **decort_disk** не выполнял безвозвратное удаление кластера из корзины. |
-| BANS-260 | Работа модуля **decort_disk** завершалась ошибкой Python при попытке переименовать диск. |
-| BANS-264 | Работа модуля **decort_disk** завершалась ошибкой Python при попытке изменить объём диска в режиме **check mode**. |
-
-### Модуль decort_group
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-390 | Работа модуля **decort_group** завершалась ошибкой запроса к API при создании группы БС. |
-| BANS-391 | Модуль **decort_group** не использовал заданные в параметре `networks` внешние сети при создании группы БС. |
-| BANS-395 | Работа модуля **decort_group** завершалась ошибкой запроса к API при повторном запуске создания группы БС. |
-| BANS-396 | Модуль **decort_group** при повторном запуске создания сообщал о том, что были выполнены изменения. |
-| BANS-399 | Работа модуля **decort_group** завершалась ошибкой запроса к API при удалении группы БС. |
-| BANS-419 | Модуль **decort_group** при повторном запуске изменения параметра networks сообщал о том, что были выполнены изменения. |
-
-### Модуль decort_k8s
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-197 | Работа модуля **decort_k8s** завершалась ошибкой Python если не задан параметр `oidc_cert`. |
-| BANS-202 | Работа модуля **decort_k8s** завершалась ошибкой модуля при попытке использовать `rg_name` и `account_name` вместо `rg_id` при создании кластера. |
-| BANS-203 | В модуле **decort_k8s** был задан неверный тип данных для параметров `cluster_conf`, `kublet_conf`, `kubeproxy_conf`, `join_conf` |
-| BANS-216 | Работа модуля **decort_k8s** завершалась ошибкой модуля при попытке создать кластер в режиме **check mode**. |
-| BANS-218 | Модуль **decort_k8s** не выполнял безвозвратное удаление кластера из корзины. |
-| BANS-221 | Модуль **decort_k8s** некорректно обрабатывал параметр `vins_id`, что вызывало создание новой внутренней сети при заданном параметре `vins_id`. |
-| BANS-225 | Модуль **decort_k8s** не сообщал о выполненных изменениях при выполнении восстановления кластера из корзины. |
-| BANS-226 | Модуль **decort_k8s** не выполнял запуск кластера после его восстановления из корзины. |
-| BANS-236 | Модуль **decort_k8s** игнорировал заданный параметр `getConfig` при запуске в режиме **check mode**. |
-| BANS-243 | Модуль **decort_k8s** выполнял изменения в соответствии с заданным параметром `workers` при запуске в режиме **check mode**. |
-
-### Модуль decort_kvmvm
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-38 | Работа модуля **decort_kvmvm** завершалась ошибкой Python при попытке удалить все существующие правила affinity у ВМ. |
-| BANS-39 | Работа модуля **decort_kvmvm** завершалась ошибкой Python при попытке удалить все существующие правила anti affinity у ВМ. |
-| BANS-60 | Работа модуля **decort_kvmvm** завершалась ошибкой Python при незаданном параметре `boot_disk` для существующей ВМ. |
-| BANS-61 | В модуле **decort_kvmvm** происходила автоматическая конвертация из ГБ в МБ при изменении параметра `ram` на значение менее 512 для существующей ВМ. |
-| BANS-445 | В модуле **decort_kvmvm** был задан неверный тип данных для параметра `ci_user_data`. |
-
-### Модуль decort_lb
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-321 | Работа модуля **decort_lb** завершалась ошибкой модуля при использовании параметра `rg_name`. |
-| BANS-322 | Работа модуля **decort_lb** завершалась ошибкой Python при использовании параметра `account_id`. |
-| BANS-323 | Модуль **decort_lb** игнорировал параметр `vins_name` и создавал балансировщик без подключения к внутренней сети. |
-| BANS-324 | Модуль **decort_lb** при повторном запуске создания сообщал о том, что были выполнены изменения. |
-| BANS-325 | Модуль **decort_lb** не реагировал на параметр `annotation`. |
-| BANS-326 | Модуль **decort_lb** при указании нескольких конфигураций frontend в параметре `frontends` добавлял в балансировщик только первую конфигурацию frontend. |
-| BANS-331 | Работа модуля **decort_lb** завершалась ошибкой Python при выполнении создания балансировщика в режиме **check mode**. |
-| BANS-334 | Модуль **decort_lb** не выполнял безвозвратное удаление балансировщика из корзины. |
-| BANS-338 | Работа модуля **decort_lb** завершалась ошибкой Python при запуске восстановления балансировщика из корзины. |
-| BANS-339 | Работа модуля **decort_lb** завершалась ошибкой Python при запуске восстановления балансировщика из корзины. |
-| BANS-340 | Модуль **decort_lb** оставлял балансировщик выключенным после его восстановления из корзины. |
-| BANS-341 | Модуль **decort_lb** оставлял балансировщик остановленным после его восстановления из корзины. |
-| BANS-346 | Модуль **decort_lb** не производил запуск балансировщика при запуске с заданным параметром `state: enabled` или `state: present`. |
-| BANS-352 | Работа модуля **decort_lb** завершалась ошибкой Python при удалении конфигурации frontend у балансировщика. |
-| BANS-353 | Работа модуля **decort_lb** завершалась ошибкой запроса к API при удалении конфигурации frontend и связанной с ней конфигурации backend у балансировщика |
-| BANS-354 | Модуль **decort_lb** не применял значения из подпараметров `check` и `server_settings` при добавлении нового сервера в существующую конфигурацию backend балансировщика. |
-| BANS-357 | Модуль **decort_lb** игнорировал режим **check mode** для параметров `backends`, `frontends`, `servers`. |
-| BANS-457 | Модуль **decort_lb** возвращал некорректный статус для удалённого балансировщика и указывал некорректный статус балансировщика в сообщении при повторном запуске модуля.
-
-### Модуль decort_osimage
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-295 | Работа модуля **decort_osimage** завершалась ошибкой запроса к API при повторном запуске удаления шаблонного образа. |
-| BANS-296 | Работа модуля **decort_osimage** завершалась ошибкой модуля при повторном запуске удаления шаблонного образа. |
-| BANS-297 | Работа модуля **decort_osimage** завершалась ошибкой запроса к API при указании параметра `account_name` вместо параметра `account_Id` |
-| BANS-299 | Модуль **decort_osimage** при повторном запуске переименования образа сообщал о том, что были выполнены изменения. |
-| BANS-300 | Работа модуля **decort_osimage** завершалась ошибкой Python при создании виртуального образа. |
-| BANS-301 | Работа модуля **decort_osimage** завершалась ошибкой модуля при повторном запуске удаления виртуального образа. |
-| BANS-302 | Работа модуля **decort_osimage** завершалась ошибкой Python с удалением шаблонного образа при попытке удалить виртуальный образ. |
-| BANS-303 | Модуль **decort_osimage** не выполнял переименование виртуального образа. |
-| BANS-304 | Работа модуля **decort_osimage** завершалась ошибкой Python при повторном запуске удаления виртуального образа. |
-
-### Модуль decort_pfw
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-283 | Работа модуля **decort_pfw** завершалась ошибкой Python при повторном запуске удаления правил. |
-| BANS-451 | Модуль **decort_pfw** при запуске удаления удалял все правила переадресации портов на виртуальном маршрутизаторе заданной внутренней сети, вместо удаления правил только для заданной ВМ. |
-
-### Модуль decort_rg
-
-| Идентификатор
задачи | Описание |
-| --- | --- |
-| BANS-58 | Работа модуля **decort_rg** завершалась ошибкой Python при передаче некорректных данных об аккаунте и/или пользователе. |
-| BANS-63 | Модуль **decort_rg** выполнял некорректное получение/изменение квоты на объём дисков. |
-| BANS-64 | Работа модуля **decort_rg** завершалась ошибкой Python при повторном запуске на создание. |
-| BANS-65 | Модуль **decort_rg** не выполнял восстановление РГ из корзины при заданном параметре `state: disabled` или `state: enabled`. |
-| BANS-66 | В модуле **decort_rg** не выполнялась проверка наличия параметра `rg_name` при создании РГ. |
-| BANS-67 | Работа модуля **decort_rg** завершалась ошибкой запроса к API при создании РГ когда РГ с таким именем есть в корзине. |
-| BANS-68 | Модуль **decort_rg** не выполнял восстановление РГ из корзины при указании `rg_name` вместо `rg_id`. |
-| BANS-425 | Работа модуля **decort_rg** завершалась ошибкой модуля при создании РГ в режиме **check mode**. |
-
-### Модуль decort_vins
-
+### Глобальные
| Идентификатор
задачи | Описание |
| --- | --- |
-| BANS-59 | Работа модуля **decort_vins** завершалась ошибкой Python при создании внутренней сети на уровне аккаунта. |
\ No newline at end of file
+| BANS-467 | При указании идентификатора аккаунта, который не существует или к которому у пользователя нет доступа, модули завершались с ошибкой запроса к API. |
\ No newline at end of file
diff --git a/README.md b/README.md
index 76f9186..c373a31 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
| Версия платформы | Версия модулей Ansible |
| :---: | :---: |
-| 4.0.0 | 5.3.0 |
+| 4.0.0 | 5.4.0 |
| 3.8.9 | 5.2.6 |
| 3.8.8 | 5.2.6 |
| 3.8.7 | 5.2.5 |
diff --git a/library/decort_account_info.py b/library/decort_account_info.py
new file mode 100644
index 0000000..e98924a
--- /dev/null
+++ b/library/decort_account_info.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+
+# Copyright: ...
+# ...
+
+DOCUMENTATION = r'''
+---
+module: decort_account_info
+
+version_added: "2.16"
+
+description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home).
+'''
+
+# EXAMPLES = r'''
+# '''
+
+# RETURN = r'''
+# '''
+
+from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.decort_utils import DecortController
+
+
+class DecortAccountInfo(DecortController):
+ MODULE_ARGS = dict(
+ argument_spec=dict(
+ app_id=dict(
+ type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_APP_ID'])
+ ),
+ app_secret=dict(
+ type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_APP_SECRET']),
+ no_log=True
+ ),
+ authenticator=dict(
+ type='str',
+ required=True,
+ choices=['oauth2', 'jwt']
+ ),
+ controller_url=dict(
+ type='str',
+ required=True
+ ),
+ id=dict(
+ type='int',
+ required=False
+ ),
+ jwt=dict(
+ type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_JWT']),
+ no_log=True
+ ),
+ name=dict(
+ type='str',
+ required=False
+ ),
+ oauth2_url=dict(
+ type='str',
+ required=False,
+ fallback=(env_fallback, ['DECORT_OAUTH2_URL'])
+ ),
+ verify_ssl=dict(
+ type='bool',
+ required=False,
+ default=True
+ ),
+ ),
+ mutually_exclusive=[
+ ('id', 'name')
+ ],
+ required_one_of=[
+ ('id', 'name')
+ ],
+ required_if=[
+ ('authenticator', 'oauth2',
+ ('oauth2_url', 'app_id', 'app_secret')),
+ ('authenticator', 'jwt', ('jwt',))
+ ]
+ )
+
+ def __init__(self):
+ amodule = AnsibleModule(**self.MODULE_ARGS, supports_check_mode=True)
+
+ super().__init__(amodule)
+
+ self.id, self.facts = self.account_find(
+ account_name=amodule.params['name'],
+ account_id=amodule.params['id'],
+ fail_if_not_found=True
+ )
+
+ def exit(self):
+ self.result['facts'] = self.facts
+ self.amodule.exit_json(**self.result)
+
+
+def main():
+ decort_account_info = DecortAccountInfo()
+ decort_account_info.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/module_utils/decort_utils.py b/module_utils/decort_utils.py
index b3cd0be..ae03ea0 100644
--- a/module_utils/decort_utils.py
+++ b/module_utils/decort_utils.py
@@ -74,16 +74,16 @@ class DecortController(object):
self.app_id = arg_amodule.params['app_id']
self.app_secret = arg_amodule.params['app_secret']
self.oauth2_url = arg_amodule.params['oauth2_url']
- self.password = arg_amodule.params['password']
- self.user = arg_amodule.params['user']
+ # self.password = arg_amodule.params['password']
+ # self.user = arg_amodule.params['user']
self.session_key = ''
# self.iconf = arg_iconf
self.verify_ssl = arg_amodule.params['verify_ssl']
self.workflow_callback_present = False
- self.workflow_callback = arg_amodule.params['workflow_callback']
- self.workflow_context = arg_amodule.params['workflow_context']
- if self.workflow_callback != "":
- self.workflow_callback_present = True
+ # self.workflow_callback = arg_amodule.params['workflow_callback']
+ # self.workflow_context = arg_amodule.params['workflow_context']
+ # if self.workflow_callback != "":
+ # self.workflow_callback_present = True
# The following will be initialized to the name of the user in DECORT controller, who corresponds to
# the credentials supplied as authentication information parameters.
@@ -153,6 +153,12 @@ class DecortController(object):
# self.run_phase = "Initializing DecortController instance complete."
return
+ @staticmethod
+ def sec_to_dt_str(sec: int, str_format: str = '%Y-%m-%d_%H-%M-%S') -> str:
+ if sec:
+ return time.strftime(str_format, time.gmtime(sec))
+ return ''
+
def check_amodule_argument(self, arg_name, abort=True):
"""Checks if the argument identified by the arg_name is defined in the module parameters.
@@ -335,7 +341,8 @@ class DecortController(object):
return True
- def decort_api_call(self, arg_req_function, arg_api_name, arg_params, arg_files=None):
+ def decort_api_call(self, arg_req_function, arg_api_name, arg_params,
+ arg_files=None, not_fail_codes: None | list = None):
"""Wrapper around DECORT API calls. It uses authorization mode and credentials validated at the class
instance creation to properly format API call and send it to the DECORT controller URL.
If connection errors are detected, it aborts execution of the script and relay error messages to upstream
@@ -386,6 +393,8 @@ class DecortController(object):
if api_resp.status_code == 200:
return api_resp
+ elif not_fail_codes and api_resp.status_code in not_fail_codes:
+ return api_resp
elif api_resp.status_code == 503:
retry_timeout = 5 + 10 * (max_retries - retry_counter)
time.sleep(retry_timeout)
@@ -1920,7 +1929,8 @@ class DecortController(object):
self.result['changed'] = True
return
- def account_find(self, account_name, account_id=0):
+ def account_find(self, account_name, account_id=0,
+ fail_if_not_found=False):
"""Find cloud account specified by the name and return facts about the account. Knowing account is
required for certain cloud resource management tasks (e.g. creating new RG).
@@ -1935,36 +1945,65 @@ class DecortController(object):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "account_find")
- if account_name == "" and account_id == 0:
- self.result['failed'] = True
- self.result['msg'] = "Cannot find account if account name is empty and account ID is zero."
+ if not account_id and not account_name:
+ self.result['msg'] = ('Cannot find account if account name and'
+ ' id are not specified.')
self.amodule.fail_json(**self.result)
- api_params = dict()
+ account_details = None
+ _account_id = account_id
+
+ if account_name and not account_id:
+ api_params = {
+ 'name': account_name
+ }
+ api_resp = self.decort_api_call(
+ arg_req_function=requests.post,
+ arg_api_name='/restmachine/cloudapi/account/list',
+ arg_params=api_params
+ )
+ accounts_list = api_resp.json()['data']
+ for account in accounts_list:
+ if account['name'] == account_name:
+ _account_id = account['id']
+ break
- if account_name == "":
- api_params['accountId'] = account_id
- api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/get", api_params)
- if api_resp.status_code == 200:
- account_details = json.loads(api_resp.content.decode('utf8'))
- return account_details['id'], account_details
- else:
- api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/list", api_params)
+ if _account_id:
+ api_params = {
+ 'accountId': _account_id
+ }
+ api_resp = self.decort_api_call(
+ arg_req_function=requests.post,
+ arg_api_name='/restmachine/cloudapi/account/get',
+ arg_params=api_params,
+ not_fail_codes=[404]
+ )
if api_resp.status_code == 200:
- # Parse response to see if a account matching arg_account_name is found in the output
- # If it is found, assign its ID to the return variable and copy dictionary with the facts
- accounts_list = json.loads(api_resp.content.decode('utf8'))
- for runner in accounts_list['data']:
- if runner['name'] == account_name:
- # get detailed information about the account from "accounts/get" call as
- # "accounts/list" does not return all necessary fields
- api_params['accountId'] = runner['id']
- api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/get", api_params)
- if api_resp.status_code == 200:
- account_details = json.loads(api_resp.content.decode('utf8'))
- return account_details['id'], account_details
+ account_details = api_resp.json()
- return 0, None
+ if account_details:
+ account_details['createdTime_readable'] = self.sec_to_dt_str(
+ account_details['createdTime']
+ )
+ account_details['deactivationTime_readable'] = self.sec_to_dt_str(
+ account_details['deactivationTime']
+ )
+ account_details['deletedTime_readable'] = self.sec_to_dt_str(
+ account_details['deletedTime']
+ )
+ account_details['updatedTime_readable'] = self.sec_to_dt_str(
+ account_details['updatedTime']
+ )
+
+ return account_details['id'], account_details
+ else:
+ if fail_if_not_found:
+ self.result['msg'] = ("Current user does not have access to"
+ " the requested account or non-existent"
+ " account specified.")
+ self.amodule.fail_json(**self.result)
+ else:
+ return 0, None
###################################
# GPU resource manipulation methods