mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-26 04:11:25 -07:00
Refactor common network shared and platform utils code into package (#33452)
* Refactor common network shared and platform specific code into package (part-1) As per proposal #76 refactor common network shared and platform specific code into sub-package. https://github.com/ansible/proposals/issues/76 * ansible.module_utils.network.common - command shared functions * ansible.module_utils.network.{{ platform }} - where platform is platform specific shared functions * Fix review comments * Fix review comments
This commit is contained in:
parent
18aca48075
commit
11c9ad23d5
483 changed files with 871 additions and 887 deletions
|
@ -1,322 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2017 Citrix Systems
|
||||
#
|
||||
# This code is part of Ansible, but is an independent component.
|
||||
# This particular file snippet, and this file snippet only, is BSD licensed.
|
||||
# Modules you write using this snippet, which is embedded dynamically by Ansible
|
||||
# still belong to the author of the module, and may assign their own license
|
||||
# to the complete work.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
from ansible.module_utils.six import binary_type, text_type
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
class ConfigProxy(object):
|
||||
|
||||
def __init__(self, actual, client, attribute_values_dict, readwrite_attrs, transforms=None, readonly_attrs=None, immutable_attrs=None, json_encodes=None):
|
||||
transforms = {} if transforms is None else transforms
|
||||
readonly_attrs = [] if readonly_attrs is None else readonly_attrs
|
||||
immutable_attrs = [] if immutable_attrs is None else immutable_attrs
|
||||
json_encodes = [] if json_encodes is None else json_encodes
|
||||
|
||||
# Actual config object from nitro sdk
|
||||
self.actual = actual
|
||||
|
||||
# nitro client
|
||||
self.client = client
|
||||
|
||||
# ansible attribute_values_dict
|
||||
self.attribute_values_dict = attribute_values_dict
|
||||
|
||||
self.readwrite_attrs = readwrite_attrs
|
||||
self.readonly_attrs = readonly_attrs
|
||||
self.immutable_attrs = immutable_attrs
|
||||
self.json_encodes = json_encodes
|
||||
self.transforms = transforms
|
||||
|
||||
self.attribute_values_processed = {}
|
||||
for attribute, value in self.attribute_values_dict.items():
|
||||
if value is None:
|
||||
continue
|
||||
if attribute in transforms:
|
||||
for transform in self.transforms[attribute]:
|
||||
if transform == 'bool_yes_no':
|
||||
if value is True:
|
||||
value = 'YES'
|
||||
elif value is False:
|
||||
value = 'NO'
|
||||
elif transform == 'bool_on_off':
|
||||
if value is True:
|
||||
value = 'ON'
|
||||
elif value is False:
|
||||
value = 'OFF'
|
||||
elif callable(transform):
|
||||
value = transform(value)
|
||||
else:
|
||||
raise Exception('Invalid transform %s' % transform)
|
||||
self.attribute_values_processed[attribute] = value
|
||||
|
||||
self._copy_attributes_to_actual()
|
||||
|
||||
def _copy_attributes_to_actual(self):
|
||||
for attribute in self.readwrite_attrs:
|
||||
if attribute in self.attribute_values_processed:
|
||||
attribute_value = self.attribute_values_processed[attribute]
|
||||
|
||||
if attribute_value is None:
|
||||
continue
|
||||
|
||||
# Fallthrough
|
||||
if attribute in self.json_encodes:
|
||||
attribute_value = json.JSONEncoder().encode(attribute_value).strip('"')
|
||||
setattr(self.actual, attribute, attribute_value)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name in self.attribute_values_dict:
|
||||
return self.attribute_values_dict[name]
|
||||
else:
|
||||
raise AttributeError('No attribute %s found' % name)
|
||||
|
||||
def add(self):
|
||||
self.actual.__class__.add(self.client, self.actual)
|
||||
|
||||
def update(self):
|
||||
return self.actual.__class__.update(self.client, self.actual)
|
||||
|
||||
def delete(self):
|
||||
self.actual.__class__.delete(self.client, self.actual)
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
result = self.actual.__class__.get(self.client, *args, **kwargs)
|
||||
|
||||
return result
|
||||
|
||||
def has_equal_attributes(self, other):
|
||||
if self.diff_object(other) == {}:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def diff_object(self, other):
|
||||
diff_dict = {}
|
||||
for attribute in self.attribute_values_processed:
|
||||
# Skip readonly attributes
|
||||
if attribute not in self.readwrite_attrs:
|
||||
continue
|
||||
|
||||
# Skip attributes not present in module arguments
|
||||
if self.attribute_values_processed[attribute] is None:
|
||||
continue
|
||||
|
||||
# Check existence
|
||||
if hasattr(other, attribute):
|
||||
attribute_value = getattr(other, attribute)
|
||||
else:
|
||||
diff_dict[attribute] = 'missing from other'
|
||||
continue
|
||||
|
||||
# Compare values
|
||||
param_type = self.attribute_values_processed[attribute].__class__
|
||||
if attribute_value is None or param_type(attribute_value) != self.attribute_values_processed[attribute]:
|
||||
str_tuple = (
|
||||
type(self.attribute_values_processed[attribute]),
|
||||
self.attribute_values_processed[attribute],
|
||||
type(attribute_value),
|
||||
attribute_value,
|
||||
)
|
||||
diff_dict[attribute] = 'difference. ours: (%s) %s other: (%s) %s' % str_tuple
|
||||
return diff_dict
|
||||
|
||||
def get_actual_rw_attributes(self, filter='name'):
|
||||
if self.actual.__class__.count_filtered(self.client, '%s:%s' % (filter, self.attribute_values_dict[filter])) == 0:
|
||||
return {}
|
||||
server_list = self.actual.__class__.get_filtered(self.client, '%s:%s' % (filter, self.attribute_values_dict[filter]))
|
||||
actual_instance = server_list[0]
|
||||
ret_val = {}
|
||||
for attribute in self.readwrite_attrs:
|
||||
if not hasattr(actual_instance, attribute):
|
||||
continue
|
||||
ret_val[attribute] = getattr(actual_instance, attribute)
|
||||
return ret_val
|
||||
|
||||
def get_actual_ro_attributes(self, filter='name'):
|
||||
if self.actual.__class__.count_filtered(self.client, '%s:%s' % (filter, self.attribute_values_dict[filter])) == 0:
|
||||
return {}
|
||||
server_list = self.actual.__class__.get_filtered(self.client, '%s:%s' % (filter, self.attribute_values_dict[filter]))
|
||||
actual_instance = server_list[0]
|
||||
ret_val = {}
|
||||
for attribute in self.readonly_attrs:
|
||||
if not hasattr(actual_instance, attribute):
|
||||
continue
|
||||
ret_val[attribute] = getattr(actual_instance, attribute)
|
||||
return ret_val
|
||||
|
||||
def get_missing_rw_attributes(self):
|
||||
return list(set(self.readwrite_attrs) - set(self.get_actual_rw_attributes().keys()))
|
||||
|
||||
def get_missing_ro_attributes(self):
|
||||
return list(set(self.readonly_attrs) - set(self.get_actual_ro_attributes().keys()))
|
||||
|
||||
|
||||
def get_immutables_intersection(config_proxy, keys):
|
||||
immutables_set = set(config_proxy.immutable_attrs)
|
||||
keys_set = set(keys)
|
||||
# Return list of sets' intersection
|
||||
return list(immutables_set & keys_set)
|
||||
|
||||
|
||||
def ensure_feature_is_enabled(client, feature_str):
|
||||
enabled_features = client.get_enabled_features()
|
||||
|
||||
if enabled_features is None:
|
||||
enabled_features = []
|
||||
|
||||
if feature_str not in enabled_features:
|
||||
client.enable_features(feature_str)
|
||||
client.save_config()
|
||||
|
||||
|
||||
def get_nitro_client(module):
|
||||
from nssrc.com.citrix.netscaler.nitro.service.nitro_service import nitro_service
|
||||
|
||||
client = nitro_service(module.params['nsip'], module.params['nitro_protocol'])
|
||||
client.set_credential(module.params['nitro_user'], module.params['nitro_pass'])
|
||||
client.timeout = float(module.params['nitro_timeout'])
|
||||
client.certvalidation = module.params['validate_certs']
|
||||
return client
|
||||
|
||||
|
||||
netscaler_common_arguments = dict(
|
||||
nsip=dict(
|
||||
required=True,
|
||||
fallback=(env_fallback, ['NETSCALER_NSIP']),
|
||||
),
|
||||
nitro_user=dict(
|
||||
required=True,
|
||||
fallback=(env_fallback, ['NETSCALER_NITRO_USER']),
|
||||
no_log=True
|
||||
),
|
||||
nitro_pass=dict(
|
||||
required=True,
|
||||
fallback=(env_fallback, ['NETSCALER_NITRO_PASS']),
|
||||
no_log=True
|
||||
),
|
||||
nitro_protocol=dict(
|
||||
choices=['http', 'https'],
|
||||
fallback=(env_fallback, ['NETSCALER_NITRO_PROTOCOL']),
|
||||
default='http'
|
||||
),
|
||||
validate_certs=dict(
|
||||
default=True,
|
||||
type='bool'
|
||||
),
|
||||
nitro_timeout=dict(default=310, type='float'),
|
||||
state=dict(
|
||||
choices=[
|
||||
'present',
|
||||
'absent',
|
||||
],
|
||||
default='present',
|
||||
),
|
||||
save_config=dict(
|
||||
type='bool',
|
||||
default=True,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
loglines = []
|
||||
|
||||
|
||||
def complete_missing_attributes(actual, attrs_list, fill_value=None):
|
||||
for attribute in attrs_list:
|
||||
if not hasattr(actual, attribute):
|
||||
setattr(actual, attribute, fill_value)
|
||||
|
||||
|
||||
def log(msg):
|
||||
loglines.append(msg)
|
||||
|
||||
|
||||
def get_ns_version(client):
|
||||
from nssrc.com.citrix.netscaler.nitro.resource.config.ns.nsversion import nsversion
|
||||
result = nsversion.get(client)
|
||||
m = re.match(r'^.*NS(\d+)\.(\d+).*$', result[0].version)
|
||||
if m is None:
|
||||
return None
|
||||
else:
|
||||
return int(m.group(1)), int(m.group(2))
|
||||
|
||||
|
||||
def get_ns_hardware(client):
|
||||
from nssrc.com.citrix.netscaler.nitro.resource.config.ns.nshardware import nshardware
|
||||
result = nshardware.get(client)
|
||||
return result
|
||||
|
||||
|
||||
def monkey_patch_nitro_api():
|
||||
|
||||
from nssrc.com.citrix.netscaler.nitro.resource.base.Json import Json
|
||||
|
||||
def new_resource_to_string_convert(self, resrc):
|
||||
# Line below is the actual patch
|
||||
dict_valid_values = dict((k.replace('_', '', 1), v) for k, v in resrc.__dict__.items() if v)
|
||||
return json.dumps(dict_valid_values)
|
||||
Json.resource_to_string_convert = new_resource_to_string_convert
|
||||
|
||||
from nssrc.com.citrix.netscaler.nitro.util.nitro_util import nitro_util
|
||||
|
||||
@classmethod
|
||||
def object_to_string_new(cls, obj):
|
||||
output = []
|
||||
flds = obj.__dict__
|
||||
for k, v in ((k.replace('_', '', 1), v) for k, v in flds.items() if v):
|
||||
if isinstance(v, bool):
|
||||
output.append('"%s":%s' % (k, v))
|
||||
elif isinstance(v, (binary_type, text_type)):
|
||||
v = to_native(v, errors='surrogate_or_strict')
|
||||
output.append('"%s":"%s"' % (k, v))
|
||||
elif isinstance(v, int):
|
||||
output.append('"%s":"%s"' % (k, v))
|
||||
return ','.join(output)
|
||||
|
||||
@classmethod
|
||||
def object_to_string_withoutquotes_new(cls, obj):
|
||||
output = []
|
||||
flds = obj.__dict__
|
||||
for k, v in ((k.replace('_', '', 1), v) for k, v in flds.items() if v):
|
||||
if isinstance(v, (int, bool)):
|
||||
output.append('%s:%s' % (k, v))
|
||||
elif isinstance(v, (binary_type, text_type)):
|
||||
v = to_native(v, errors='surrogate_or_strict')
|
||||
output.append('%s:%s' % (k, cls.encode(v)))
|
||||
return ','.join(output)
|
||||
|
||||
nitro_util.object_to_string = object_to_string_new
|
||||
nitro_util.object_to_string_withoutquotes = object_to_string_withoutquotes_new
|
Loading…
Add table
Add a link
Reference in a new issue