"Fossies" - the Fresh Open Source Software Archive

Member "ansible-2.9.27/lib/ansible/modules/network/a10/a10_service_group.py" (11 Oct 2021, 13224 Bytes) of package /linux/misc/ansible-2.9.27.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "a10_service_group.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.9.24_vs_4.3.0.

    1 #!/usr/bin/python
    2 # -*- coding: utf-8 -*-
    3 
    4 # (c) 2014, Mischa Peters <mpeters@a10networks.com>,
    5 #           Eric Chou <ericc@a10networks.com>
    6 #
    7 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
    8 
    9 from __future__ import absolute_import, division, print_function
   10 __metaclass__ = type
   11 
   12 
   13 ANSIBLE_METADATA = {'metadata_version': '1.1',
   14                     'status': ['preview'],
   15                     'supported_by': 'community'}
   16 
   17 
   18 DOCUMENTATION = '''
   19 ---
   20 module: a10_service_group
   21 version_added: 1.8
   22 short_description: Manage A10 Networks AX/SoftAX/Thunder/vThunder devices' service groups.
   23 description:
   24     - Manage SLB (Server Load Balancing) service-group objects on A10 Networks devices via aXAPIv2.
   25 author:
   26   - Eric Chou (@ericchou1)
   27   - Mischa Peters (@mischapeters)
   28 notes:
   29     - Requires A10 Networks aXAPI 2.1.
   30     - When a server doesn't exist and is added to the service-group the server will be created.
   31 extends_documentation_fragment:
   32   - a10
   33   - url
   34 options:
   35   state:
   36     description:
   37       - If the specified service group should exists.
   38     default: present
   39     choices: ['present', 'absent']
   40   partition:
   41     version_added: "2.3"
   42     description:
   43       - set active-partition
   44   service_group:
   45     description:
   46       - The SLB (Server Load Balancing) service-group name
   47     required: true
   48     aliases: ['service', 'pool', 'group']
   49   service_group_protocol:
   50     description:
   51       - The SLB service-group protocol of TCP or UDP.
   52     default: tcp
   53     aliases: ['proto', 'protocol']
   54     choices: ['tcp', 'udp']
   55   service_group_method:
   56     description:
   57       - The SLB service-group load balancing method, such as round-robin or weighted-rr.
   58     default: round-robin
   59     aliases: ['method']
   60     choices:
   61         - 'round-robin'
   62         - 'weighted-rr'
   63         - 'least-connection'
   64         - 'weighted-least-connection'
   65         - 'service-least-connection'
   66         - 'service-weighted-least-connection'
   67         - 'fastest-response'
   68         - 'least-request'
   69         - 'round-robin-strict'
   70         - 'src-ip-only-hash'
   71         - 'src-ip-hash'
   72   servers:
   73     description:
   74       - A list of servers to add to the service group. Each list item should be a
   75         dictionary which specifies the C(server:) and C(port:), but can also optionally
   76         specify the C(status:). See the examples below for details.
   77     aliases: ['server', 'member']
   78   validate_certs:
   79     description:
   80       - If C(no), SSL certificates will not be validated. This should only be used
   81         on personally controlled devices using self-signed certificates.
   82     type: bool
   83     default: 'yes'
   84 
   85 '''
   86 
   87 EXAMPLES = '''
   88 # Create a new service-group
   89 - a10_service_group:
   90     host: a10.mydomain.com
   91     username: myadmin
   92     password: mypassword
   93     partition: mypartition
   94     service_group: sg-80-tcp
   95     servers:
   96       - server: foo1.mydomain.com
   97         port: 8080
   98       - server: foo2.mydomain.com
   99         port: 8080
  100       - server: foo3.mydomain.com
  101         port: 8080
  102       - server: foo4.mydomain.com
  103         port: 8080
  104         status: disabled
  105 
  106 '''
  107 
  108 RETURN = '''
  109 content:
  110   description: the full info regarding the slb_service_group
  111   returned: success
  112   type: str
  113   sample: "mynewservicegroup"
  114 '''
  115 import json
  116 
  117 from ansible.module_utils.network.a10.a10 import (axapi_call, a10_argument_spec, axapi_authenticate, axapi_failure, axapi_enabled_disabled)
  118 from ansible.module_utils.basic import AnsibleModule
  119 from ansible.module_utils.urls import url_argument_spec
  120 
  121 
  122 VALID_SERVICE_GROUP_FIELDS = ['name', 'protocol', 'lb_method']
  123 VALID_SERVER_FIELDS = ['server', 'port', 'status']
  124 
  125 
  126 def validate_servers(module, servers):
  127     for item in servers:
  128         for key in item:
  129             if key not in VALID_SERVER_FIELDS:
  130                 module.fail_json(msg="invalid server field (%s), must be one of: %s" % (key, ','.join(VALID_SERVER_FIELDS)))
  131 
  132         # validate the server name is present
  133         if 'server' not in item:
  134             module.fail_json(msg="server definitions must define the server field")
  135 
  136         # validate the port number is present and an integer
  137         if 'port' in item:
  138             try:
  139                 item['port'] = int(item['port'])
  140             except Exception:
  141                 module.fail_json(msg="server port definitions must be integers")
  142         else:
  143             module.fail_json(msg="server definitions must define the port field")
  144 
  145         # convert the status to the internal API integer value
  146         if 'status' in item:
  147             item['status'] = axapi_enabled_disabled(item['status'])
  148         else:
  149             item['status'] = 1
  150 
  151 
  152 def main():
  153     argument_spec = a10_argument_spec()
  154     argument_spec.update(url_argument_spec())
  155     argument_spec.update(
  156         dict(
  157             state=dict(type='str', default='present', choices=['present', 'absent']),
  158             service_group=dict(type='str', aliases=['service', 'pool', 'group'], required=True),
  159             service_group_protocol=dict(type='str', default='tcp', aliases=['proto', 'protocol'], choices=['tcp', 'udp']),
  160             service_group_method=dict(type='str', default='round-robin',
  161                                       aliases=['method'],
  162                                       choices=['round-robin',
  163                                                'weighted-rr',
  164                                                'least-connection',
  165                                                'weighted-least-connection',
  166                                                'service-least-connection',
  167                                                'service-weighted-least-connection',
  168                                                'fastest-response',
  169                                                'least-request',
  170                                                'round-robin-strict',
  171                                                'src-ip-only-hash',
  172                                                'src-ip-hash']),
  173             servers=dict(type='list', aliases=['server', 'member'], default=[]),
  174             partition=dict(type='str', default=[]),
  175         )
  176     )
  177 
  178     module = AnsibleModule(
  179         argument_spec=argument_spec,
  180         supports_check_mode=False
  181     )
  182 
  183     host = module.params['host']
  184     username = module.params['username']
  185     password = module.params['password']
  186     partition = module.params['partition']
  187     state = module.params['state']
  188     write_config = module.params['write_config']
  189     slb_service_group = module.params['service_group']
  190     slb_service_group_proto = module.params['service_group_protocol']
  191     slb_service_group_method = module.params['service_group_method']
  192     slb_servers = module.params['servers']
  193 
  194     if slb_service_group is None:
  195         module.fail_json(msg='service_group is required')
  196 
  197     axapi_base_url = 'https://' + host + '/services/rest/V2.1/?format=json'
  198     load_balancing_methods = {'round-robin': 0,
  199                               'weighted-rr': 1,
  200                               'least-connection': 2,
  201                               'weighted-least-connection': 3,
  202                               'service-least-connection': 4,
  203                               'service-weighted-least-connection': 5,
  204                               'fastest-response': 6,
  205                               'least-request': 7,
  206                               'round-robin-strict': 8,
  207                               'src-ip-only-hash': 14,
  208                               'src-ip-hash': 15}
  209 
  210     if not slb_service_group_proto or slb_service_group_proto.lower() == 'tcp':
  211         protocol = 2
  212     else:
  213         protocol = 3
  214 
  215     # validate the server data list structure
  216     validate_servers(module, slb_servers)
  217 
  218     json_post = {
  219         'service_group': {
  220             'name': slb_service_group,
  221             'protocol': protocol,
  222             'lb_method': load_balancing_methods[slb_service_group_method],
  223         }
  224     }
  225 
  226     # first we authenticate to get a session id
  227     session_url = axapi_authenticate(module, axapi_base_url, username, password)
  228     # then we select the active-partition
  229     axapi_call(module, session_url + '&method=system.partition.active', json.dumps({'name': partition}))
  230     # then we check to see if the specified group exists
  231     slb_result = axapi_call(module, session_url + '&method=slb.service_group.search', json.dumps({'name': slb_service_group}))
  232     slb_service_group_exist = not axapi_failure(slb_result)
  233 
  234     changed = False
  235     if state == 'present':
  236         # before creating/updating we need to validate that servers
  237         # defined in the servers list exist to prevent errors
  238         checked_servers = []
  239         for server in slb_servers:
  240             result = axapi_call(module, session_url + '&method=slb.server.search', json.dumps({'name': server['server']}))
  241             if axapi_failure(result):
  242                 module.fail_json(msg="the server %s specified in the servers list does not exist" % server['server'])
  243             checked_servers.append(server['server'])
  244 
  245         if not slb_service_group_exist:
  246             result = axapi_call(module, session_url + '&method=slb.service_group.create', json.dumps(json_post))
  247             if axapi_failure(result):
  248                 module.fail_json(msg=result['response']['err']['msg'])
  249             changed = True
  250         else:
  251             # check to see if the service group definition without the
  252             # server members is different, and update that individually
  253             # if it needs it
  254             do_update = False
  255             for field in VALID_SERVICE_GROUP_FIELDS:
  256                 if json_post['service_group'][field] != slb_result['service_group'][field]:
  257                     do_update = True
  258                     break
  259 
  260             if do_update:
  261                 result = axapi_call(module, session_url + '&method=slb.service_group.update', json.dumps(json_post))
  262                 if axapi_failure(result):
  263                     module.fail_json(msg=result['response']['err']['msg'])
  264                 changed = True
  265 
  266         # next we pull the defined list of servers out of the returned
  267         # results to make it a bit easier to iterate over
  268         defined_servers = slb_result.get('service_group', {}).get('member_list', [])
  269 
  270         # next we add/update new member servers from the user-specified
  271         # list if they're different or not on the target device
  272         for server in slb_servers:
  273             found = False
  274             different = False
  275             for def_server in defined_servers:
  276                 if server['server'] == def_server['server']:
  277                     found = True
  278                     for valid_field in VALID_SERVER_FIELDS:
  279                         if server[valid_field] != def_server[valid_field]:
  280                             different = True
  281                             break
  282                     if found or different:
  283                         break
  284             # add or update as required
  285             server_data = {
  286                 "name": slb_service_group,
  287                 "member": server,
  288             }
  289             if not found:
  290                 result = axapi_call(module, session_url + '&method=slb.service_group.member.create', json.dumps(server_data))
  291                 changed = True
  292             elif different:
  293                 result = axapi_call(module, session_url + '&method=slb.service_group.member.update', json.dumps(server_data))
  294                 changed = True
  295 
  296         # finally, remove any servers that are on the target
  297         # device but were not specified in the list given
  298         for server in defined_servers:
  299             found = False
  300             for slb_server in slb_servers:
  301                 if server['server'] == slb_server['server']:
  302                     found = True
  303                     break
  304             # remove if not found
  305             server_data = {
  306                 "name": slb_service_group,
  307                 "member": server,
  308             }
  309             if not found:
  310                 result = axapi_call(module, session_url + '&method=slb.service_group.member.delete', json.dumps(server_data))
  311                 changed = True
  312 
  313         # if we changed things, get the full info regarding
  314         # the service group for the return data below
  315         if changed:
  316             result = axapi_call(module, session_url + '&method=slb.service_group.search', json.dumps({'name': slb_service_group}))
  317         else:
  318             result = slb_result
  319     elif state == 'absent':
  320         if slb_service_group_exist:
  321             result = axapi_call(module, session_url + '&method=slb.service_group.delete', json.dumps({'name': slb_service_group}))
  322             changed = True
  323         else:
  324             result = dict(msg="the service group was not present")
  325 
  326     # if the config has changed, save the config unless otherwise requested
  327     if changed and write_config:
  328         write_result = axapi_call(module, session_url + '&method=system.action.write_memory')
  329         if axapi_failure(write_result):
  330             module.fail_json(msg="failed to save the configuration: %s" % write_result['response']['err']['msg'])
  331 
  332     # log out of the session nicely and exit
  333     axapi_call(module, session_url + '&method=session.close')
  334     module.exit_json(changed=changed, content=result)
  335 
  336 
  337 if __name__ == '__main__':
  338     main()