Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added smn module #54793

Merged
merged 1 commit into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
370 changes: 370 additions & 0 deletions lib/ansible/modules/cloud/huawei/hwc_smn_topic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,370 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2019 Huawei
# GNU General Public License v3.0+ (see COPYING or
# https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

###############################################################################
# Documentation
###############################################################################

ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ["preview"],
'supported_by': 'community'}

DOCUMENTATION = '''
---
module: hwc_smn_topic
description:
- Represents a SMN notification topic resource.
short_description: Creates a resource of SMNTopic in Huaweicloud Cloud
version_added: '2.8'
author: Huawei Inc. (@huaweicloud)
requirements:
- requests >= 2.18.4
- keystoneauth1 >= 3.6.0
options:
state:
description:
- Whether the given object should exist in Huaweicloud Cloud.
type: str
choices: ['present', 'absent']
default: 'present'
display_name:
description:
- Topic display name, which is presented as the name of the email
sender in an email message. The topic display name contains a
maximum of 192 bytes.
type: str
required: false
name:
description:
- Name of the topic to be created. The topic name is a string of 1
to 256 characters. It must contain upper- or lower-case letters,
digits, hyphens (-), and underscores C(_), and must start with a
letter or digit.
type: str
required: true
extends_documentation_fragment: hwc
'''

EXAMPLES = '''
- name: create a smn topic
hwc_smn_topic:
identity_endpoint: "{{ identity_endpoint }}"
user_name: "{{ user_name }}"
password: "{{ password }}"
domain_name: "{{ domain_name }}"
project_name: "{{ project_name }}"
region: "{{ region }}"
name: "ansible_smn_topic_test"
state: present
'''

RETURN = '''
create_time:
description:
- Time when the topic was created.
returned: success
type: str
display_name:
description:
- Topic display name, which is presented as the name of the email
sender in an email message. The topic display name contains a
maximum of 192 bytes.
returned: success
type: str
name:
description:
- Name of the topic to be created. The topic name is a string of 1
to 256 characters. It must contain upper- or lower-case letters,
digits, hyphens (-), and underscores C(_), and must start with a
letter or digit.
returned: success
type: str
push_policy:
description:
- Message pushing policy. 0 indicates that the message sending
fails and the message is cached in the queue. 1 indicates that
the failed message is discarded.
returned: success
type: int
topic_urn:
description:
- Resource identifier of a topic, which is unique.
returned: success
type: str
update_time:
description:
- Time when the topic was updated.
returned: success
type: str
'''

###############################################################################
# Imports
###############################################################################

from ansible.module_utils.hwc_utils import (HwcSession, HwcModule,
DictComparison, navigate_hash,
remove_nones_from_dict,
remove_empty_from_dict,
are_dicts_different)
import json
import re

###############################################################################
# Main
###############################################################################


def main():
"""Main function"""

module = HwcModule(
argument_spec=dict(
state=dict(default='present', choices=['present', 'absent'],
type='str'),
display_name=dict(type='str'),
name=dict(required=True, type='str')
),
supports_check_mode=True,
)

session = HwcSession(module, "app")

state = module.params['state']

if not module.params.get("id"):
module.params['id'] = get_resource_id(session)

fetch = None
link = self_link(session)
# the link will include Nones if required format parameters are missed
if not re.search('/None/|/None$', link):
fetch = fetch_resource(session, link)
changed = False

if fetch:
if state == 'present':
expect = _get_resource_editable_properties(module)
current_state = response_to_hash(module, fetch)
if are_dicts_different(expect, current_state):
if not module.check_mode:
fetch = update(session)
fetch = response_to_hash(module, fetch)
changed = True
else:
fetch = current_state
else:
if not module.check_mode:
delete(session)
fetch = {}
changed = True
else:
if state == 'present':
if not module.check_mode:
fetch = create(session)
fetch = response_to_hash(module, fetch)
changed = True
else:
fetch = {}

fetch.update({'changed': changed})

module.exit_json(**fetch)


def create(session):
link = collection(session)
module = session.module
success_codes = [201, 202]
r = return_if_object(module,
session.post(link, create_resource_opts(module)),
success_codes)

return get_resource(session, r)


def update(session):
link = self_link(session)
success_codes = [201, 202]
module = session.module
r = return_if_object(module, session.put(link, update_resource_opts(module)), success_codes)

return get_resource(session, r)


def delete(session):
link = self_link(session)
success_codes = [202, 204]
return_if_object(session.module, session.delete(link), success_codes, False)


def link_wrapper(f):
def _wrapper(module, *args, **kwargs):
try:
return f(module, *args, **kwargs)
except KeyError as ex:
module.fail_json(
msg="Mapping keys(%s) are not found in generating link." % ex)

return _wrapper


def return_if_object(module, response, success_codes, has_content=True):
code = response.status_code

# If not found, return nothing.
if code == 404:
return None

if not success_codes:
success_codes = [200, 201, 202, 203, 204, 205, 206, 207, 208, 226]
# If no content, return nothing.
if code in success_codes and not has_content:
return None

result = None
try:
result = response.json()
except getattr(json.decoder, 'JSONDecodeError', ValueError) as inst:
module.fail_json(msg="Invalid JSON response with error: %s" % inst)

if code not in success_codes:
msg = navigate_hash(result, ['message'])
if msg:
module.fail_json(msg=msg)
else:
module.fail_json(msg="operation failed, return code=%d" % code)

return result


def fetch_resource(session, link, success_codes=None):
if not success_codes:
success_codes = [200]
return return_if_object(session.module, session.get(link), success_codes)


def get_resource(session, result):
combined = session.module.params.copy()
combined['topic_urn'] = navigate_hash(result, ['topic_urn'])
url = 'notifications/topics/{topic_urn}'.format(**combined)

e = session.get_service_endpoint('compute')
url = e.replace("ecs", "smn") + url
return fetch_resource(session, url)


def get_resource_id(session):
module = session.module
link = list_link(session, {'limit': 10, 'offset': '{offset}'})
p = {'offset': 0}
v = module.params.get('name')
ids = set()
while True:
r = fetch_resource(session, link.format(**p))
if r is None:
break
r = r.get('topics', [])
if r == []:
break
for i in r:
if i.get('name') == v:
ids.add(i.get('topic_urn'))
if len(ids) >= 2:
module.fail_json(msg="Multiple resources are found")

p['offset'] += 1

return ids.pop() if ids else None


@link_wrapper
def list_link(session, extra_data=None):
url = "{endpoint}notifications/topics?limit={limit}&offset={offset}"

combined = session.module.params.copy()
if extra_data:
combined.update(extra_data)

e = session.get_service_endpoint('compute')
combined['endpoint'] = e.replace("ecs", "smn")

return url.format(**combined)


@link_wrapper
def self_link(session):
url = "{endpoint}notifications/topics/{id}"

combined = session.module.params.copy()

e = session.get_service_endpoint('compute')
combined['endpoint'] = e.replace("ecs", "smn")

return url.format(**combined)


@link_wrapper
def collection(session):
url = "{endpoint}notifications/topics"

combined = session.module.params.copy()

e = session.get_service_endpoint('compute')
combined['endpoint'] = e.replace("ecs", "smn")

return url.format(**combined)


def create_resource_opts(module):
request = remove_empty_from_dict({
u'display_name': module.params.get('display_name'),
u'name': module.params.get('name')
})
return request


def update_resource_opts(module):
request = remove_nones_from_dict({
u'display_name': module.params.get('display_name')
})
return request


def _get_resource_editable_properties(module):
return remove_nones_from_dict({
"display_name": module.params.get("display_name"),
})


def response_to_hash(module, response):
"""Remove unnecessary properties from the response.
This is for doing comparisons with Ansible's current parameters.
"""
return {
u'create_time': response.get(u'create_time'),
u'display_name': response.get(u'display_name'),
u'name': response.get(u'name'),
u'push_policy': _push_policy_convert_from_response(
response.get('push_policy')),
u'topic_urn': response.get(u'topic_urn'),
u'update_time': response.get(u'update_time')
}


def _push_policy_convert_from_response(value):
return {
0: "the message sending fails and is cached in the queue",
1: "the failed message is discarded",
}.get(int(value))


if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions test/integration/targets/hwc_smn_topic/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
unsupported