mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-07 22:02:50 +00:00
Reformat everything.
This commit is contained in:
@@ -153,45 +153,66 @@ import xml.etree.ElementTree as ET
|
||||
class spectrum_model_attrs:
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.url = module.params['url']
|
||||
self.url = module.params["url"]
|
||||
# If the user did not define a full path to the restul space in url:
|
||||
# params, add what we believe it to be.
|
||||
if not re.search('\\/.+', self.url.split('://')[1]):
|
||||
if not re.search("\\/.+", self.url.split("://")[1]):
|
||||
self.url = f"{self.url.rstrip('/')}/spectrum/restful"
|
||||
# Align these with what is defined in OneClick's UI under:
|
||||
# Locator -> Devices -> By Model Name -> <enter any model> ->
|
||||
# Attributes tab.
|
||||
self.attr_map = dict(App_Manufacturer=hex(0x230683),
|
||||
CollectionsModelNameString=hex(0x12adb),
|
||||
Condition=hex(0x1000a),
|
||||
Criticality=hex(0x1290c),
|
||||
DeviceType=hex(0x23000e),
|
||||
isManaged=hex(0x1295d),
|
||||
Model_Class=hex(0x11ee8),
|
||||
Model_Handle=hex(0x129fa),
|
||||
Model_Name=hex(0x1006e),
|
||||
Modeltype_Handle=hex(0x10001),
|
||||
Modeltype_Name=hex(0x10000),
|
||||
Network_Address=hex(0x12d7f),
|
||||
Notes=hex(0x11564),
|
||||
ServiceDesk_Asset_ID=hex(0x12db9),
|
||||
TopologyModelNameString=hex(0x129e7),
|
||||
sysDescr=hex(0x10052),
|
||||
sysName=hex(0x10b5b),
|
||||
Vendor_Name=hex(0x11570),
|
||||
Description=hex(0x230017))
|
||||
self.attr_map = dict(
|
||||
App_Manufacturer=hex(0x230683),
|
||||
CollectionsModelNameString=hex(0x12ADB),
|
||||
Condition=hex(0x1000A),
|
||||
Criticality=hex(0x1290C),
|
||||
DeviceType=hex(0x23000E),
|
||||
isManaged=hex(0x1295D),
|
||||
Model_Class=hex(0x11EE8),
|
||||
Model_Handle=hex(0x129FA),
|
||||
Model_Name=hex(0x1006E),
|
||||
Modeltype_Handle=hex(0x10001),
|
||||
Modeltype_Name=hex(0x10000),
|
||||
Network_Address=hex(0x12D7F),
|
||||
Notes=hex(0x11564),
|
||||
ServiceDesk_Asset_ID=hex(0x12DB9),
|
||||
TopologyModelNameString=hex(0x129E7),
|
||||
sysDescr=hex(0x10052),
|
||||
sysName=hex(0x10B5B),
|
||||
Vendor_Name=hex(0x11570),
|
||||
Description=hex(0x230017),
|
||||
)
|
||||
self.search_qualifiers = [
|
||||
"and", "or", "not", "greater-than", "greater-than-or-equals",
|
||||
"less-than", "less-than-or-equals", "equals", "equals-ignore-case",
|
||||
"does-not-equal", "does-not-equal-ignore-case", "has-prefix",
|
||||
"does-not-have-prefix", "has-prefix-ignore-case",
|
||||
"does-not-have-prefix-ignore-case", "has-substring",
|
||||
"does-not-have-substring", "has-substring-ignore-case",
|
||||
"does-not-have-substring-ignore-case", "has-suffix",
|
||||
"does-not-have-suffix", "has-suffix-ignore-case",
|
||||
"does-not-have-suffix-ignore-case", "has-pcre",
|
||||
"has-pcre-ignore-case", "has-wildcard", "has-wildcard-ignore-case",
|
||||
"is-derived-from", "not-is-derived-from"]
|
||||
"and",
|
||||
"or",
|
||||
"not",
|
||||
"greater-than",
|
||||
"greater-than-or-equals",
|
||||
"less-than",
|
||||
"less-than-or-equals",
|
||||
"equals",
|
||||
"equals-ignore-case",
|
||||
"does-not-equal",
|
||||
"does-not-equal-ignore-case",
|
||||
"has-prefix",
|
||||
"does-not-have-prefix",
|
||||
"has-prefix-ignore-case",
|
||||
"does-not-have-prefix-ignore-case",
|
||||
"has-substring",
|
||||
"does-not-have-substring",
|
||||
"has-substring-ignore-case",
|
||||
"does-not-have-substring-ignore-case",
|
||||
"has-suffix",
|
||||
"does-not-have-suffix",
|
||||
"has-suffix-ignore-case",
|
||||
"does-not-have-suffix-ignore-case",
|
||||
"has-pcre",
|
||||
"has-pcre-ignore-case",
|
||||
"has-wildcard",
|
||||
"has-wildcard-ignore-case",
|
||||
"is-derived-from",
|
||||
"not-is-derived-from",
|
||||
]
|
||||
|
||||
self.resp_namespace = dict(ca="http://www.ca.com/spectrum/restful/schema/response")
|
||||
|
||||
@@ -266,23 +287,26 @@ class spectrum_model_attrs:
|
||||
# None values should be converted to empty strings
|
||||
val = ""
|
||||
val = self.urlencode(str(val))
|
||||
if not update_url.endswith('?'):
|
||||
if not update_url.endswith("?"):
|
||||
update_url += "&"
|
||||
|
||||
update_url += f"attr={self.attr_id(name) or name}&val={val}"
|
||||
|
||||
# POST to /model to update the attributes, or fail.
|
||||
resp, info = fetch_url(self.module, update_url, method="PUT",
|
||||
headers={"Content-Type": "application/json",
|
||||
"Accept": "application/json"},
|
||||
use_proxy=self.module.params['use_proxy'])
|
||||
resp, info = fetch_url(
|
||||
self.module,
|
||||
update_url,
|
||||
method="PUT",
|
||||
headers={"Content-Type": "application/json", "Accept": "application/json"},
|
||||
use_proxy=self.module.params["use_proxy"],
|
||||
)
|
||||
status_code = info["status"]
|
||||
if status_code >= 400:
|
||||
body = info['body']
|
||||
body = info["body"]
|
||||
else:
|
||||
body = "" if resp is None else resp.read()
|
||||
if status_code != 200:
|
||||
self.result['msg'] = f"HTTP PUT error {status_code}: {update_url}: {body}"
|
||||
self.result["msg"] = f"HTTP PUT error {status_code}: {update_url}: {body}"
|
||||
self.module.fail_json(**self.result)
|
||||
|
||||
# Load and parse the JSON response and either fail or set results.
|
||||
@@ -293,17 +317,17 @@ class spectrum_model_attrs:
|
||||
Example failure response:
|
||||
{'model-update-response-list': {'model-responses': {'model': {'@error': 'PartialFailure', '@mh': '0x1010e76', 'attribute': {'@error-message': 'brn0vlappua001: You do not have permission to set attribute Network_Address for this model.', '@error': 'Error', '@id': '0x12d7f'}}}}}
|
||||
""" # noqa
|
||||
model_resp = json_resp['model-update-response-list']['model-responses']['model']
|
||||
if model_resp['@error'] != "Success":
|
||||
model_resp = json_resp["model-update-response-list"]["model-responses"]["model"]
|
||||
if model_resp["@error"] != "Success":
|
||||
# I'm not 100% confident on the expected failure structure so just
|
||||
# dump all of ['attribute'].
|
||||
self.result['msg'] = str(model_resp['attribute'])
|
||||
self.result["msg"] = str(model_resp["attribute"])
|
||||
self.module.fail_json(**self.result)
|
||||
|
||||
# Should be OK if we get to here, set results.
|
||||
self.result['msg'] = self.success_msg
|
||||
self.result['changed_attrs'].update(attrs)
|
||||
self.result['changed'] = True
|
||||
self.result["msg"] = self.success_msg
|
||||
self.result["changed_attrs"].update(attrs)
|
||||
self.result["changed"] = True
|
||||
|
||||
def find_model(self, search_criteria, ret_attrs=None):
|
||||
"""
|
||||
@@ -319,7 +343,7 @@ class spectrum_model_attrs:
|
||||
|
||||
# If no return attributes were asked for, return Model_Handle.
|
||||
if ret_attrs is None:
|
||||
ret_attrs = ['Model_Handle']
|
||||
ret_attrs = ["Model_Handle"]
|
||||
|
||||
# Set the XML <rs:requested-attribute id=<id>> tags. If no hex ID
|
||||
# is found for the name, assume it is already in hex. {name: hex ID}
|
||||
@@ -347,44 +371,52 @@ xsi:schemaLocation="http://www.ca.com/spectrum/restful/schema/request ../../../x
|
||||
|
||||
# POST to /models and fail on errors.
|
||||
url = self.build_url("/models")
|
||||
resp, info = fetch_url(self.module, url, data=xml, method="POST",
|
||||
use_proxy=self.module.params['use_proxy'],
|
||||
headers={"Content-Type": "application/xml",
|
||||
"Accept": "application/xml"})
|
||||
resp, info = fetch_url(
|
||||
self.module,
|
||||
url,
|
||||
data=xml,
|
||||
method="POST",
|
||||
use_proxy=self.module.params["use_proxy"],
|
||||
headers={"Content-Type": "application/xml", "Accept": "application/xml"},
|
||||
)
|
||||
status_code = info["status"]
|
||||
if status_code >= 400:
|
||||
body = info['body']
|
||||
body = info["body"]
|
||||
else:
|
||||
body = "" if resp is None else resp.read()
|
||||
if status_code != 200:
|
||||
self.result['msg'] = f"HTTP POST error {status_code}: {url}: {body}"
|
||||
self.result["msg"] = f"HTTP POST error {status_code}: {url}: {body}"
|
||||
self.module.fail_json(**self.result)
|
||||
|
||||
# Parse through the XML response and fail on any detected errors.
|
||||
root = ET.fromstring(body)
|
||||
total_models = int(root.attrib['total-models'])
|
||||
error = root.attrib['error']
|
||||
model_responses = root.find('ca:model-responses', self.resp_namespace)
|
||||
total_models = int(root.attrib["total-models"])
|
||||
error = root.attrib["error"]
|
||||
model_responses = root.find("ca:model-responses", self.resp_namespace)
|
||||
if total_models < 1:
|
||||
self.result['msg'] = f"No models found matching search criteria `{search_criteria}'"
|
||||
self.result["msg"] = f"No models found matching search criteria `{search_criteria}'"
|
||||
self.module.fail_json(**self.result)
|
||||
elif total_models > 1:
|
||||
self.result['msg'] = f"More than one model found ({total_models}): `{ET.tostring(model_responses, encoding='unicode')}'"
|
||||
self.result["msg"] = (
|
||||
f"More than one model found ({total_models}): `{ET.tostring(model_responses, encoding='unicode')}'"
|
||||
)
|
||||
self.module.fail_json(**self.result)
|
||||
if error != "EndOfResults":
|
||||
self.result['msg'] = f"Unexpected search response `{error}': {ET.tostring(model_responses, encoding='unicode')}"
|
||||
self.result["msg"] = (
|
||||
f"Unexpected search response `{error}': {ET.tostring(model_responses, encoding='unicode')}"
|
||||
)
|
||||
self.module.fail_json(**self.result)
|
||||
model = model_responses.find('ca:model', self.resp_namespace)
|
||||
attrs = model.findall('ca:attribute', self.resp_namespace)
|
||||
model = model_responses.find("ca:model", self.resp_namespace)
|
||||
attrs = model.findall("ca:attribute", self.resp_namespace)
|
||||
if not attrs:
|
||||
self.result['msg'] = "No attributes returned."
|
||||
self.result["msg"] = "No attributes returned."
|
||||
self.module.fail_json(**self.result)
|
||||
|
||||
# XML response should be successful. Iterate and set each returned
|
||||
# attribute ID/name and value for return.
|
||||
ret = dict()
|
||||
for attr in attrs:
|
||||
attr_id = attr.get('id')
|
||||
attr_id = attr.get("id")
|
||||
attr_name = self.attr_name(attr_id)
|
||||
# Note: all values except empty strings (None) are strings only!
|
||||
attr_val = attr.text
|
||||
@@ -410,7 +442,7 @@ xsi:schemaLocation="http://www.ca.com/spectrum/restful/schema/request ../../../x
|
||||
|
||||
# If no return attributes were asked for, return Model_Handle.
|
||||
if ret_attrs is None:
|
||||
ret_attrs = ['Model_Handle']
|
||||
ret_attrs = ["Model_Handle"]
|
||||
|
||||
"""This is basically as follows:
|
||||
<filtered-models>
|
||||
@@ -428,58 +460,51 @@ xsi:schemaLocation="http://www.ca.com/spectrum/restful/schema/request ../../../x
|
||||
"""
|
||||
|
||||
# Parent filter tag
|
||||
filtered_models = ET.Element('filtered-models')
|
||||
filtered_models = ET.Element("filtered-models")
|
||||
# Logically and
|
||||
_and = ET.SubElement(filtered_models, 'and')
|
||||
_and = ET.SubElement(filtered_models, "and")
|
||||
|
||||
# Model Name
|
||||
MN_equals = ET.SubElement(_and, 'equals')
|
||||
Model_Name = ET.SubElement(MN_equals, 'attribute',
|
||||
{'id': self.attr_map['Model_Name']})
|
||||
MN_value = ET.SubElement(Model_Name, 'value')
|
||||
MN_equals = ET.SubElement(_and, "equals")
|
||||
Model_Name = ET.SubElement(MN_equals, "attribute", {"id": self.attr_map["Model_Name"]})
|
||||
MN_value = ET.SubElement(Model_Name, "value")
|
||||
MN_value.text = mname
|
||||
|
||||
# Model Type Name
|
||||
MTN_equals = ET.SubElement(_and, 'equals')
|
||||
Modeltype_Name = ET.SubElement(MTN_equals, 'attribute',
|
||||
{'id': self.attr_map['Modeltype_Name']})
|
||||
MTN_value = ET.SubElement(Modeltype_Name, 'value')
|
||||
MTN_equals = ET.SubElement(_and, "equals")
|
||||
Modeltype_Name = ET.SubElement(MTN_equals, "attribute", {"id": self.attr_map["Modeltype_Name"]})
|
||||
MTN_value = ET.SubElement(Modeltype_Name, "value")
|
||||
MTN_value.text = mtype
|
||||
|
||||
return self.find_model(ET.tostring(filtered_models,
|
||||
encoding='unicode'),
|
||||
ret_attrs)
|
||||
return self.find_model(ET.tostring(filtered_models, encoding="unicode"), ret_attrs)
|
||||
|
||||
def ensure_model_attrs(self):
|
||||
|
||||
# Get a list of all requested attribute names/IDs plus Model_Handle and
|
||||
# use them to query the values currently set. Store finding in a
|
||||
# dictionary.
|
||||
req_attrs = []
|
||||
for attr in self.module.params['attributes']:
|
||||
req_attrs.append(attr['name'])
|
||||
if 'Model_Handle' not in req_attrs:
|
||||
req_attrs.append('Model_Handle')
|
||||
for attr in self.module.params["attributes"]:
|
||||
req_attrs.append(attr["name"])
|
||||
if "Model_Handle" not in req_attrs:
|
||||
req_attrs.append("Model_Handle")
|
||||
|
||||
# Survey attributes currently set and store in a dict.
|
||||
cur_attrs = self.find_model_by_name_type(self.module.params['name'],
|
||||
self.module.params['type'],
|
||||
req_attrs)
|
||||
cur_attrs = self.find_model_by_name_type(self.module.params["name"], self.module.params["type"], req_attrs)
|
||||
|
||||
# Iterate through the requested attributes names/IDs values pair and
|
||||
# compare with those currently set. If different, attempt to change.
|
||||
Model_Handle = cur_attrs.pop("Model_Handle")
|
||||
for attr in self.module.params['attributes']:
|
||||
req_name = attr['name']
|
||||
req_val = attr['value']
|
||||
for attr in self.module.params["attributes"]:
|
||||
req_name = attr["name"]
|
||||
req_val = attr["value"]
|
||||
if req_val == "":
|
||||
# The API will return None on empty string
|
||||
req_val = None
|
||||
if cur_attrs[req_name] != req_val:
|
||||
if self.module.check_mode:
|
||||
self.result['changed_attrs'][req_name] = req_val
|
||||
self.result['msg'] = self.success_msg
|
||||
self.result['changed'] = True
|
||||
self.result["changed_attrs"][req_name] = req_val
|
||||
self.result["msg"] = self.success_msg
|
||||
self.result["changed"] = True
|
||||
continue
|
||||
resp = self.update_model(Model_Handle, {req_name: req_val})
|
||||
|
||||
@@ -488,21 +513,19 @@ xsi:schemaLocation="http://www.ca.com/spectrum/restful/schema/request ../../../x
|
||||
|
||||
def run_module():
|
||||
argument_spec = dict(
|
||||
url=dict(type='str', required=True),
|
||||
url_username=dict(type='str', required=True, aliases=['username']),
|
||||
url_password=dict(type='str', required=True, aliases=['password'],
|
||||
no_log=True),
|
||||
validate_certs=dict(type='bool', default=True),
|
||||
use_proxy=dict(type='bool', default=True),
|
||||
name=dict(type='str', required=True),
|
||||
type=dict(type='str', required=True),
|
||||
attributes=dict(type='list',
|
||||
required=True,
|
||||
elements='dict',
|
||||
options=dict(
|
||||
name=dict(type='str', required=True),
|
||||
value=dict(type='str', required=True)
|
||||
)),
|
||||
url=dict(type="str", required=True),
|
||||
url_username=dict(type="str", required=True, aliases=["username"]),
|
||||
url_password=dict(type="str", required=True, aliases=["password"], no_log=True),
|
||||
validate_certs=dict(type="bool", default=True),
|
||||
use_proxy=dict(type="bool", default=True),
|
||||
name=dict(type="str", required=True),
|
||||
type=dict(type="str", required=True),
|
||||
attributes=dict(
|
||||
type="list",
|
||||
required=True,
|
||||
elements="dict",
|
||||
options=dict(name=dict(type="str", required=True), value=dict(type="str", required=True)),
|
||||
),
|
||||
)
|
||||
module = AnsibleModule(
|
||||
supports_check_mode=True,
|
||||
|
||||
Reference in New Issue
Block a user