text: #!/usr/bin/python
  # -*- coding: utf-8 -*-
  
  #  Copyright (c) 2017 Citrix Systems
  # 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
  
  
  ANSIBLE_METADATA = {'metadata_version': '1.1',
                      'status': ['preview'],
                      'supported_by': 'community'}
  
  
  DOCUMENTATION = '''
  ---
  module: netscaler_cs_policy
  short_description: Manage content switching policy
  description:
      - Manage content switching policy.
      - "This module is intended to run either on the ansible  control node or a bastion (jumpserver) with access to the actual netscaler instance."
  
  
  author: George Nikolopoulos (@giorgos-nikolopoulos)
  
  options:
  
      policyname:
          description:
              - >-
                  Name for the content switching policy. Must begin with an ASCII alphanumeric or underscore C(_)
                  character, and must contain only ASCII alphanumeric, underscore, hash C(#), period C(.), space C( ), colon
                  C(:), at sign C(@), equal sign C(=), and hyphen C(-) characters. Cannot be changed after a policy is
                  created.
              - "The following requirement applies only to the NetScaler CLI:"
              - >-
                  If the name includes one or more spaces, enclose the name in double or single quotation marks (for
                  example, my policy or my policy).
              - "Minimum length = 1"
  
      url:
          description:
              - >-
                  URL string that is matched with the URL of a request. Can contain a wildcard character. Specify the
                  string value in the following format: C([[prefix] [*]] [.suffix]).
              - "Minimum length = 1"
              - "Maximum length = 208"
  
      rule:
          description:
              - >-
                  Expression, or name of a named expression, against which traffic is evaluated. Written in the classic
                  or default syntax.
              - "Note:"
              - >-
                  Maximum length of a string literal in the expression is 255 characters. A longer string can be split
                  into smaller strings of up to 255 characters each, and the smaller strings concatenated with the +
                  operator. For example, you can create a 500-character string as follows: '"<string of 255
                  characters>" + "<string of 245 characters>"'
  
      domain:
          description:
              - "The domain name. The string value can range to 63 characters."
              - "Minimum length = 1"
  
      action:
          description:
              - >-
                  Content switching action that names the target load balancing virtual server to which the traffic is
                  switched.
  
  extends_documentation_fragment:
  - community.general.netscaler
  
  requirements:
      - nitro python sdk
  '''
  
  EXAMPLES = '''
  - name: Create url cs policy
    delegate_to: localhost
    netscaler_cs_policy:
      nsip: 172.18.0.2
      nitro_user: nsroot
      nitro_pass: nsroot
      validate_certs: no
  
      state: present
  
      policyname: policy_1
      url: /example/
  '''
  
  RETURN = '''
  loglines:
      description: list of logged messages by the module
      returned: always
      type: list
      sample: ['message 1', 'message 2']
  
  msg:
      description: Message detailing the failure reason
      returned: failure
      type: str
      sample: "Could not load nitro python sdk"
  
  diff:
      description: List of differences between the actual configured object and the configuration specified in the module
      returned: failure
      type: dict
      sample: { 'url': 'difference. ours: (str) example1 other: (str) /example1' }
  '''
  
  from ansible.module_utils.basic import AnsibleModule
  from ansible_collections.community.general.plugins.module_utils.network.netscaler.netscaler import ConfigProxy, get_nitro_client, netscaler_common_arguments, log, loglines, ensure_feature_is_enabled
  try:
      from nssrc.com.citrix.netscaler.nitro.resource.config.cs.cspolicy import cspolicy
      from nssrc.com.citrix.netscaler.nitro.exception.nitro_exception import nitro_exception
      PYTHON_SDK_IMPORTED = True
  except ImportError as e:
      PYTHON_SDK_IMPORTED = False
  
  
  def policy_exists(client, module):
      log('Checking if policy exists')
      if cspolicy.count_filtered(client, 'policyname:%s' % module.params['policyname']) > 0:
          return True
      else:
          return False
  
  
  def policy_identical(client, module, cspolicy_proxy):
      log('Checking if defined policy is identical to configured')
      if cspolicy.count_filtered(client, 'policyname:%s' % module.params['policyname']) == 0:
          return False
      policy_list = cspolicy.get_filtered(client, 'policyname:%s' % module.params['policyname'])
      diff_dict = cspolicy_proxy.diff_object(policy_list[0])
      if 'ip' in diff_dict:
          del diff_dict['ip']
      if len(diff_dict) == 0:
          return True
      else:
          return False
  
  
  def diff_list(client, module, cspolicy_proxy):
      policy_list = cspolicy.get_filtered(client, 'policyname:%s' % module.params['policyname'])
      return cspolicy_proxy.diff_object(policy_list[0])
  
  
  def main():
  
      module_specific_arguments = dict(
          policyname=dict(type='str'),
          url=dict(type='str'),
          rule=dict(type='str'),
          domain=dict(type='str'),
          action=dict(type='str'),
      )
  
      hand_inserted_arguments = dict(
      )
  
      argument_spec = dict()
  
      argument_spec.update(netscaler_common_arguments)
      argument_spec.update(module_specific_arguments)
      argument_spec.update(hand_inserted_arguments)
  
      module = AnsibleModule(
          argument_spec=argument_spec,
          supports_check_mode=True,
      )
      module_result = dict(
          changed=False,
          failed=False,
          loglines=loglines,
      )
  
      # Fail the module if imports failed
      if not PYTHON_SDK_IMPORTED:
          module.fail_json(msg='Could not load nitro python sdk')
  
      # Fallthrough to rest of execution
      client = get_nitro_client(module)
  
      try:
          client.login()
      except nitro_exception as e:
          msg = "nitro exception during login. errorcode=%s, message=%s" % (str(e.errorcode), e.message)
          module.fail_json(msg=msg)
      except Exception as e:
          if str(type(e)) == "<class 'requests.exceptions.ConnectionError'>":
              module.fail_json(msg='Connection error %s' % str(e))
          elif str(type(e)) == "<class 'requests.exceptions.SSLError'>":
              module.fail_json(msg='SSL Error %s' % str(e))
          else:
              module.fail_json(msg='Unexpected error during login %s' % str(e))
  
      readwrite_attrs = [
          'policyname',
          'url',
          'rule',
          'domain',
          'action',
      ]
      readonly_attrs = [
          'vstype',
          'hits',
          'bindhits',
          'labelname',
          'labeltype',
          'priority',
          'activepolicy',
          'cspolicytype',
      ]
  
      transforms = {
      }
  
      # Instantiate config proxy
      cspolicy_proxy = ConfigProxy(
          actual=cspolicy(),
          client=client,
          attribute_values_dict=module.params,
          readwrite_attrs=readwrite_attrs,
          readonly_attrs=readonly_attrs,
          transforms=transforms,
      )
  
      try:
          ensure_feature_is_enabled(client, 'CS')
  
          # Apply appropriate state
          if module.params['state'] == 'present':
              log('Sanity checks for state present')
              if not policy_exists(client, module):
                  if not module.check_mode:
                      cspolicy_proxy.add()
                      if module.params['save_config']:
                          client.save_config()
                  module_result['changed'] = True
              elif not policy_identical(client, module, cspolicy_proxy):
                  if not module.check_mode:
                      cspolicy_proxy.update()
                      if module.params['save_config']:
                          client.save_config()
                  module_result['changed'] = True
              else:
                  module_result['changed'] = False
  
              # Sanity check for state
              if not module.check_mode:
                  log('Sanity checks for state present')
                  if not policy_exists(client, module):
                      module.fail_json(msg='Policy does not exist', **module_result)
                  if not policy_identical(client, module, cspolicy_proxy):
                      module.fail_json(msg='Policy differs from configured', diff=diff_list(client, module, cspolicy_proxy), **module_result)
  
          elif module.params['state'] == 'absent':
              log('Applying actions for state absent')
              if policy_exists(client, module):
                  if not module.check_mode:
                      cspolicy_proxy.delete()
                      if module.params['save_config']:
                          client.save_config()
                  module_result['changed'] = True
              else:
                  module_result['changed'] = False
  
              # Sanity check for state
              if not module.check_mode:
                  log('Sanity checks for state absent')
                  if policy_exists(client, module):
                      module.fail_json(msg='Policy still exists', **module_result)
  
      except nitro_exception as e:
          msg = "nitro exception errorcode=%s, message=%s" % (str(e.errorcode), e.message)
          module.fail_json(msg=msg, **module_result)
  
      client.logout()
      module.exit_json(**module_result)
  
  
  if __name__ == "__main__":
      main()
  