1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00
community.general/lib/ansible/module_utils/netscaler.py
2017-09-12 00:11:13 -07:00

322 lines
12 KiB
Python

# -*- 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