def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), group_name=dict(type='str', required=True), group_enabled=dict(type='bool', default=True), group_description=dict(type='str', default=''), group_members=dict(type='list', default=[]), group_state=dict(type='str', choices=['present', 'absent'], default='present'), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of group group_name = module.params['group_name'] group_enabled = str(int(module.params['group_enabled'])) group_members = module.params['group_members'] group_state = module.params['group_state'] group_description = module.params['group_description'] # Instantiate API connection api_url = module.params['api_url'] api_auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, api_auth, api_ssl_verify) # Fetch list of groups groups = apiconnection.listObjects('group') # Get an empty group object to lookup UUIDs for group members empty_group = apiconnection.getObjectByUuid('group', '') group_members_uuids = [] for group_member in group_members: for key,value in empty_group['members']: if value['value'] == group_member: group_members_uuids.append(key) # Build dict with desired state desired_properties = { 'enabled': group_enabled, 'description': group_description, 'members': ','.join(group_members_uuids) } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if group object with specified name exists for group in groups: if group['name'] == group_name: uuid = group['uuid'] break group_exists = (uuid != '') if group_state == 'present': if group_exists: group = apiconnection.getObjectByName('group', group_name) for prop in desired_properties.keys(): # Special case for members where two lists have to be compared if prop == 'members': current_members_keys = apiconnection.getSelectedList(group[prop]) if not apiconnection.compareLists(current_members_keys, group_members): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing members: %s => %s' %(current_members_keys, desired_properties[prop])) else: if group[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, group[prop], desired_properties[prop])) if not needs_change: result = {'changed': False, 'msg': ['Group already present: %s' %group_name]} else: if not module.check_mode: additional_msg.append(apiconnection.updateObject('group', group_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Group %s must be changed.' %group_name, additional_msg]} else: if not module.check_mode: additional_msg.append(apiconnection.createObject('group', group_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Group %s must be created.' %group_name, additional_msg]} else: if group_exists: if not module.check_mode: additional_msg.append(apiconnection.deleteObject('group', group_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Group %s must be deleted.' %group_name, additional_msg]} else: result = {'changed': False, 'msg': ['Group %s is not present.' %group_name]} module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), user_name=dict(type='str', required=True), user_password=dict(type='str', default='', no_log=True), user_enabled=dict(type='bool', default=True), user_description=dict(type='str', default=''), user_state=dict(type='str', choices=['present', 'absent'], default='present'), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of user user_name = module.params['user_name'] user_password = module.params['user_password'] user_enabled = str(int(module.params['user_enabled'])) user_state = module.params['user_state'] user_description = module.params['user_description'] # Instantiate API connection api_url = module.params['api_url'] auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, auth, api_ssl_verify) # Fetch list of users users = apiconnection.listObjects('user') # Build dict with desired state desired_properties = {'password': user_password, 'enabled': user_enabled, 'description': user_description} # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if user object with specified name exists for user in users: if user['name'] == user_name: user_exists = True uuid = user['uuid'] additional_msg.append(uuid) break user_exists = (uuid != '') if user_state == 'present': if user_exists: user = apiconnection.getObjectByName('user', user_name) for prop in desired_properties.keys(): if user[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, user[prop], desired_properties[prop])) if not needs_change: result = {'changed': False, 'msg': ['User already present: %s' %user_name]} else: if not module.check_mode: additional_msg.append(apiconnection.updateObject('user', user_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['User %s must be changed.' %user_name, additional_msg]} else: if not module.check_mode: additional_msg.append(apiconnection.createObject('user', user_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['User %s must be created.' %user_name, additional_msg]} else: if user_exists: if not module.check_mode: additional_msg.append(apiconnection.deleteObject('user', user_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['User %s must be deleted.' %user_name, additional_msg]} else: result = {'changed': False, 'msg': ['User %s is not present.' %user_name]} module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), action_name=dict(type='str', required=True), action_description=dict(type='str', default=''), action_test_type=dict(type='str', choices=['if', 'unless'], default='if'), action_linked_acls=dict(type='list', default=[]), action_operator=dict(type='str', choices=['and', 'or'], default='and'), action_type=dict( type='str', choices=[ 'use_backend', 'use_server', 'map_use_backend', 'http-request_allow', 'http-request_deny', 'http-request_tarpit', 'http-request_auth', 'http-request_redirect', 'http-request_lua', 'http-request_use-service', 'http-request_add-header', 'http-request_set-header', 'http-request_del-header', 'http-request_replace-header', 'http-request_replace-value', 'http-request_set-path', 'http-response_allow', 'http-response_deny', 'http-response_lua', 'http-response_add-header', 'http-response_set-header', 'http-response_del-header', 'http-response_replace-header', 'http-response_replace-value', 'http-response_set-status', 'tcp-request_connection_accept', 'tcp-request_connection_reject', 'tcp-request_content_accept', 'tcp-request_content_reject', 'tcp-request_content_lua', 'tcp-request_content_use-service', 'tcp-request_inspect-delay', 'tcp-response_content_accept', 'tcp-response_content_reject', 'tcp-response_content_lua', 'tcp-response_inspect-delay', 'custom' ], required=True), action_value=dict(type='str', required=True), action_state=dict(type='str', choices=['present', 'absent'], default='present'), haproxy_reload=dict(type='bool', default=False)), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of action action_name = module.params['action_name'] action_test_type = module.params['action_test_type'] action_type = module.params['action_type'] action_value = module.params['action_value'] action_linked_acls = module.params['action_linked_acls'] action_operator = module.params['action_operator'] action_description = module.params['action_description'] action_state = module.params['action_state'] # Instantiate API connection api_url = module.params['api_url'] auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, auth, api_ssl_verify) # Fetch list of acls actions = apiconnection.listObjects('action') # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Replace all dashes in action_type since their keys only use underscores: action_type_key = action_type.replace('-', '_') # Retrieve an empty action object to lookup UUIDs of linked ACLs empty_action = apiconnection.getObjectByUuid('action', '') action_linked_acls_uuids = [] for action_linked_acl in action_linked_acls: for key, value in empty_action['linkedAcls'].iteritems(): if value['value'] == action_linked_acl: action_linked_acls_uuids.append(key) # Build dict with desired state desired_properties = { 'description': action_description, 'testType': action_test_type, 'operator': action_operator, 'type': action_type, action_type_key: action_value, 'linkedAcls': ','.join(action_linked_acls_uuids) #'linkedAcls': ','.join(apiconnection.getUuidsFromNames('acl', action_linked_acls)) } # Special case for several http actions which use 2 fields: if 'http' in action_type and 'header' in action_type: # del only needs the name of HTTP header to delete if 'del' in action_type: desired_properties[action_type_key + '_name'] = action_value else: value_name = action_value.split('::')[0] desired_properties[action_type_key + '_name'] = value_name # regex actions have _name and _regex if 'regex' in action_type: value_regex = action_value.split('::')[1] desired_properties[action_type_key + '_regex'] = value_regex else: value_content = action_value.split('::')[1] desired_properties[action_type_key + '_content'] = value_content # Special case for http_*_replace_value which also needs http_*_replace_regex elif 'http' in action_type and 'value' in action_type: value_name = action_value.split('::')[0] desired_properties[action_type_key + '_name'] = value_name value_regex = action_value.split('::')[1] desired_properties[action_type_key + '_regex'] = value_regex elif 'http' in action_type and 'status' in action_type: value_code = action_value.split('::')[0] desired_properties[action_type_key + '_code'] = value_code value_reason = action_value.split('::')[1] desired_properties[action_type_key + '_reason'] = value_reason # Special case for use_backend since it needs a uuid elif action_type == 'use_backend': #desired_properties[action_type_key] = apiconnection.getUuidByName('backend', action_value) backend_uuid = '' for key, value in empty_action['use_backend'].iteritems(): if value['value'] == action_value: backend_uuid = key desired_properties[action_type_key] = backend_uuid else: desired_properties[action_type_key] = action_value # Initialize some control vars needs_change = False uuid = '' # Check if action object with specified name exists for action in actions: if action['name'] == action_name: uuid = action['uuid'] additional_msg.append('Found action with uuid %s' % uuid) break action_exists = (uuid != '') if action_state == 'present': if action_exists: action = apiconnection.getObjectByName('action', action_name) # Check if simple properties differ for prop in ['description']: if action[prop] != desired_properties[prop]: needs_change = True additional_msg.append('simple prop') changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, action[prop], desired_properties[prop])) # Check if action_type_key is already present, if not, replace the whole dict if action_type_key not in action: # Special cases will be handled a bit further below if 'http' in action_type and ('header' in action_type or 'value' in action_type or 'status' in action_type): pass else: needs_change = True changed_properties = desired_properties additional_msg.append('action_type_key %s not in action' % action_type_key) # Entries in testType, operator and type dicts must be checked separately if property selected == 1: complex_types_list = ['testType', 'operator', 'type'] for complex_type in complex_types_list: for key, value in action[complex_type].iteritems(): if value['selected'] == '1' and key != desired_properties[ complex_type]: # Currently selected type value does not match desired type value, replace the whole dict: additional_msg.append('%s not selected' % (complex_type)) needs_change = True changed_properties = desired_properties # Special case where use_backend contains a dict with one selected element if not needs_change and action_type == 'use_backend': current_use_backend = apiconnection.getSelected( action[action_type_key]) if current_use_backend != desired_properties[action_type_key]: needs_change = True changed_properties[action_type_key] = desired_properties[ action_type_key] additional_msg.append( 'Changing %s: %s => %s' % (action_type_key, current_use_backend, desired_properties[action_type_key])) # Check special cases where differently named properties exist (HTTP header): elif not needs_change and 'http' in action_type and ( 'header' in action_type or 'value' in action_type or 'status' in action_type): if action[action_type_key + '_name'] != desired_properties[action_type_key + '_name']: needs_change = True changed_properties[action_type_key + '_name'] = desired_properties[ action_type_key + '_name'] for special_property in [ action_type_key + '_name', action_type_key + '_regex', action_type_key + '_content' ]: if special_property in desired_properties: if special_property not in action: # Current property is missing completely additional_msg.append('property %s missing' % special_property) needs_change = True changed_properties = desired_properties else: if action[special_property] != desired_properties[ special_property]: # Current property exists, but value is different, change it additional_msg.append('action value differs') needs_change = True changed_properties[ special_property] = desired_properties[ special_property] # Check if value of action needs to be changed: elif not needs_change and action_type_key in action: if action[action_type_key] != desired_properties[ action_type_key]: needs_change = True changed_properties[action_type_key] = desired_properties[ action_type_key] additional_msg.append( 'Changing %s: %s => %s' % (action_type_key, action[action_type_key], desired_properties[action_type_key])) # Check if currently an acl is linked which should not be linked: for key, value in action['linkedAcls'].iteritems(): if value['selected'] == 1: # Get name of linkedAcl and compare with action_linked_acls list #acl = apiconnection.getObjectByUuid('acl', key) acl = empty_action['linkedAcls'][key]['value'] additional_msg.append('Found a linked acl with name: %s' % acl) if acl not in action_linked_acls: # Current element is not in action_linked_acls, rebuild linkedAcls completely needs_change = True additional_msg.append( 'linkedAcls containing unwanted element') changed_properties['linkedAcls'] = desired_properties[ 'linkedAcls'] # Reverse acl check, make sure every entry in linked_acl is selected in current action object for acl in action_linked_acls: #acl_uuid = apiconnection.getUuidByName('acl', acl) acl_uuid = '' for key, value in empty_action['linkedAcls'].iteritems(): if value['value'] == acl: acl_uuid = key if action['linkedAcls'][acl_uuid]['selected'] == 0: needs_change = True changed_properties['linkedAcls'] = desired_properties[ 'linkedAcls'] if not needs_change: result = { 'changed': False, 'msg': [ 'Action already present: %s' % action_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.updateObject('action', action_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Action %s must be changed.' % action_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.createObject('action', action_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Action %s must be created.' % action_name, additional_msg] } else: if action_exists: if not module.check_mode: additional_msg.append( apiconnection.deleteObject('action', action_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Action %s must be deleted.' % action_name, additional_msg] } else: result = { 'changed': False, 'msg': ['Action %s is not present.' % action_name] } module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), cpu_state=dict(type='str', choices=['present', 'absent'], default='present'), cpu_enabled=dict(type='bool', default=True), cpu_name=dict(type='str', required=True), cpu_process_id=dict(type='str', choices=[ 'all', 'odd', 'even', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'x31', 'x32', 'x33', 'x34', 'x35', 'x36', 'x37', 'x38', 'x39', 'x40', 'x41', 'x42', 'x43', 'x44', 'x45', 'x46', 'x47', 'x48', 'x49', 'x50', 'x51', 'x52', 'x53', 'x54', 'x55', 'x56', 'x57', 'x58', 'x59', 'x60', 'x61', 'x62', 'x63', ], default='all'), cpu_thread_id=dict(type='str', choices=[ 'all', 'odd', 'even', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'x31', 'x32', 'x33', 'x34', 'x35', 'x36', 'x37', 'x38', 'x39', 'x40', 'x41', 'x42', 'x43', 'x44', 'x45', 'x46', 'x47', 'x48', 'x49', 'x50', 'x51', 'x52', 'x53', 'x54', 'x55', 'x56', 'x57', 'x58', 'x59', 'x60', 'x61', 'x62', 'x63', ], default='all'), cpu_cpu_id=dict(type='list', elements='str', options=dict( choices=[ 'all', 'odd', 'even', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'x31', 'x32', 'x33', 'x34', 'x35', 'x36', 'x37', 'x38', 'x39', 'x40', 'x41', 'x42', 'x43', 'x44', 'x45', 'x46', 'x47', 'x48', 'x49', 'x50', 'x51', 'x52', 'x53', 'x54', 'x55', 'x56', 'x57', 'x58', 'x59', 'x60', 'x61', 'x62', 'x63', ] ), default=['all']), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of cpu cpu_state = module.params['cpu_state'] cpu_enabled = str(int(module.params['cpu_enabled'])) cpu_name = module.params['cpu_name'] cpu_process_id = module.params['cpu_process_id'] cpu_thread_id = module.params['cpu_thread_id'] cpu_cpu_id = module.params['cpu_cpu_id'] # Instantiate API connection api_url = module.params['api_url'] api_auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, api_auth, api_ssl_verify) # Fetch list of cpus cpus = apiconnection.listObjects('cpu') # Build dict with desired state desired_properties = { 'enabled': cpu_enabled, 'process_id': cpu_process_id, 'thread_id': cpu_thread_id, 'cpu_id': ','.join(cpu_cpu_id) } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if cpu object with specified name exists for cpu in cpus: if cpu['name'] == cpu_name: uuid = cpu['uuid'] break cpu_exists = (uuid != '') if cpu_state == 'present': if cpu_exists: cpu = apiconnection.getObjectByName('cpu', cpu_name) for prop in desired_properties.keys(): # Special cases for complex propertierts: if prop == 'process_id': current_process_id = apiconnection.getSelected(cpu[prop]) if current_process_id != cpu_process_id: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_process_id, desired_properties[prop])) elif prop == 'thread_id': current_thread_id = apiconnection.getSelected(cpu[prop]) if current_thread_id != cpu_thread_id: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_thread_id, desired_properties[prop])) elif prop == 'cpu_id': current_cpu_id = apiconnection.getSelectedList(cpu[prop], retval='key') if not apiconnection.compareLists(current_cpu_id, cpu_cpu_id): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_cpu_id, desired_properties[prop])) else: # catch all other properties if cpu[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, cpu[prop], desired_properties[prop])) if not needs_change: result = {'changed': False, 'msg': ['Cpu already present: %s' %cpu_name, additional_msg]} else: if not module.check_mode: additional_msg.append(apiconnection.updateObject('cpu', cpu_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Cpu %s must be changed.' %cpu_name, additional_msg]} else: if not module.check_mode: additional_msg.append(apiconnection.createObject('cpu', cpu_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Cpu %s must be created.' %cpu_name, additional_msg]} else: if cpu_exists: if not module.check_mode: additional_msg.append(apiconnection.deleteObject('cpu', cpu_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Cpu %s must be deleted.' %cpu_name, additional_msg]} else: result = {'changed': False, 'msg': ['Cpu %s is not present.' %cpu_name]} module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), healthcheck_state=dict(type='str', choices=['present', 'absent'], default='present'), healthcheck_name=dict(type='str', required=True), healthcheck_type=dict(type='str', choices=[ 'tcp', 'http', 'agent', 'ldap', 'mysql', 'pgsql', 'redis', 'smtp', 'esmtp', 'ssl' ], default='http'), healthcheck_description=dict(type='str', default=''), healthcheck_interval=dict(type='str', default='2s'), healthcheck_force_ssl=dict(type='bool', default=False), healthcheck_checkport=dict(type='str', default=''), healthcheck_http_method=dict(type='str', default='options'), healthcheck_http_uri=dict(type='str', default='/'), healthcheck_http_version=dict(type=str, choices=['http10', 'http11'], default='http10'), healthcheck_http_host=dict(type='str', default='localhost'), healthcheck_http_expression_enabled=dict(type='bool', default=False), healthcheck_http_expression=dict( type='str', choices=['', 'status', 'rstatus', 'string', 'rstring'], default=''), healthcheck_http_negate=dict(type='bool', default=False), healthcheck_http_value=dict(type='str', default=''), healthcheck_tcp_enabled=dict(type='bool', default=False), healthcheck_tcp_send_value=dict(type='str', default=''), healthcheck_tcp_match_type=dict( type='str', choices=['', 'string', 'rstring', 'binary'], default=''), healthcheck_tcp_negate=dict(type='bool', default=False), healthcheck_tcp_match_value=dict(type='str', default=''), healthcheck_agent_port=dict(type='str', default=''), healthcheck_mysql_user=dict(type='str', default=''), healthcheck_mysql_post41=dict(type='bool', default=False), healthcheck_pgsql_user=dict(type='str', default=''), healthcheck_smtp_domain=dict(type='str', default=''), healthcheck_esmtp_domain=dict(type='str', default=''), healthcheck_db_user=dict(type='str', default=''), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of healthcheck healthcheck_state = module.params['healthcheck_state'] healthcheck_name = module.params['healthcheck_name'] healthcheck_description = module.params['healthcheck_description'] healthcheck_type = module.params['healthcheck_type'] healthcheck_interval = module.params['healthcheck_interval'] healthcheck_force_ssl = module.params['healthcheck_force_ssl'] healthcheck_checkport = module.params['healthcheck_checkport'] healthcheck_http_method = module.params['healthcheck_http_method'] healthcheck_http_uri = module.params['healthcheck_http_uri'] healthcheck_http_version = module.params['healthcheck_http_version'] healthcheck_http_host = module.params['healthcheck_http_host'] healthcheck_http_expression = module.params['healthcheck_http_expression'] healthcheck_http_expression_enabled = module.params[ 'healthcheck_http_expression_enabled'] healthcheck_http_negate = module.params['healthcheck_http_negate'] healthcheck_http_value = module.params['healthcheck_http_value'] healthcheck_tcp_enabled = module.params['healthcheck_tcp_enabled'] healthcheck_tcp_send_value = module.params['healthcheck_tcp_send_value'] healthcheck_tcp_match_type = module.params['healthcheck_tcp_match_type'] healthcheck_tcp_negate = module.params['healthcheck_tcp_negate'] healthcheck_tcp_match_value = module.params['healthcheck_tcp_match_value'] healthcheck_agent_port = module.params['healthcheck_agent_port'] healthcheck_mysql_user = module.params['healthcheck_mysql_user'] healthcheck_mysql_post41 = module.params['healthcheck_mysql_post41'] healthcheck_pgsql_user = module.params['healthcheck_pgsql_user'] healthcheck_smtp_domain = module.params['healthcheck_smtp_domain'] healthcheck_esmtp_domain = module.params['healthcheck_esmtp_domain'] healthcheck_db_user = module.params['healthcheck_db_user'] # Instantiate API connection api_url = module.params['api_url'] api_auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, api_auth, api_ssl_verify) # Fetch list of healthchecks healthchecks = apiconnection.listObjects('healthcheck') # Build dict with desired state desired_properties = { 'description': healthcheck_description, 'type': healthcheck_type, 'interval': healthcheck_interval, 'force_ssl': str(int(healthcheck_force_ssl)), 'checkport': healthcheck_checkport, 'http_method': healthcheck_http_method, 'http_uri': healthcheck_http_uri, 'http_version': healthcheck_http_version, 'http_host': healthcheck_http_host, 'http_expressionEnabled': str(int(healthcheck_http_expression_enabled)), 'http_expression': healthcheck_http_expression, 'http_negate': str(int(healthcheck_http_negate)), 'http_value': healthcheck_http_value, 'tcp_enabled': str(int(healthcheck_tcp_enabled)), 'tcp_sendValue': healthcheck_tcp_send_value, 'tcp_matchType': healthcheck_tcp_match_type, 'tcp_negate': str(int(healthcheck_tcp_negate)), 'tcp_matchValue': healthcheck_tcp_match_value, 'agent_port': healthcheck_agent_port, 'mysql_user': healthcheck_mysql_user, 'mysql_post41': str(int(healthcheck_mysql_post41)), 'pgsql_user': healthcheck_pgsql_user, 'smtp_domain': healthcheck_smtp_domain, 'esmtp_domain': healthcheck_esmtp_domain, 'agentPort': healthcheck_agent_port, 'smtpDomain': healthcheck_smtp_domain } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if healthcheck object with specified name exists for healthcheck in healthchecks: if healthcheck['name'] == healthcheck_name: uuid = healthcheck['uuid'] break healthcheck_exists = (uuid != '') if healthcheck_state == 'present': if healthcheck_exists: healthcheck = apiconnection.getObjectByName( 'healthcheck', healthcheck_name) for prop in desired_properties.keys(): # Special cases for complex propertierts: if prop == 'type': current_type = apiconnection.getSelected(healthcheck[prop]) if current_type != healthcheck_type: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_type, desired_properties[prop])) elif prop == 'http_method': current_http_method = apiconnection.getSelected( healthcheck[prop]) if current_http_method != healthcheck_http_method: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_http_method, desired_properties[prop])) elif prop == 'http_version': current_http_version = apiconnection.getSelected( healthcheck[prop]) if current_http_version != healthcheck_http_version: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_http_version, desired_properties[prop])) elif prop == 'http_expression': current_http_expression = apiconnection.getSelected( healthcheck[prop]) if current_http_expression != healthcheck_http_expression: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_http_expression, desired_properties[prop])) elif prop == 'tcp_matchType': current_tcp_match_type = apiconnection.getSelected( healthcheck[prop]) if current_tcp_match_type != healthcheck_tcp_match_type: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_tcp_match_type, desired_properties[prop])) else: # catch all other properties if healthcheck[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, healthcheck[prop], desired_properties[prop])) if not needs_change: result = { 'changed': False, 'msg': [ 'Healthcheck already present: %s' % healthcheck_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.updateObject('healthcheck', healthcheck_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Healthcheck %s must be changed.' % healthcheck_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.createObject('healthcheck', healthcheck_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Healthcheck %s must be created.' % healthcheck_name, additional_msg ] } else: if healthcheck_exists: if not module.check_mode: additional_msg.append( apiconnection.deleteObject('healthcheck', healthcheck_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Healthcheck %s must be deleted.' % healthcheck_name, additional_msg ] } else: result = { 'changed': False, 'msg': ['Healthcheck %s is not present.' % healthcheck_name] } module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), server_enabled=dict(type='bool', default=True), server_name=dict(type='str', required=True), server_address=dict(type='str', required=True), server_description=dict(type='str', default=''), server_port=dict(type='str', required=True), server_checkport=dict(type='str', default=''), server_mode=dict(type='str', default='active'), server_ssl=dict(type='bool', default=False), server_ssl_verify=dict(type='bool', default=True), server_ssl_ca=dict(type='list', default=[]), server_ssl_crl=dict(type='str', default=''), server_ssl_client_certificate=dict(type='str', default=''), server_weight=dict(type='str', default=''), server_check_interval=dict(type='str', default=''), server_check_down_interval=dict(type='str', default=''), server_source=dict(type='str', default=''), server_advanced=dict(type='str', default=''), server_state=dict(type='str', choices=['present', 'absent'], default='present'), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of server server_state = module.params['server_state'] server_enabled = module.params['server_enabled'] server_name = module.params['server_name'] server_description = module.params['server_description'] server_address = module.params['server_address'] server_port = module.params['server_port'] server_checkport = module.params['server_port'] server_mode = module.params['server_mode'] server_ssl = module.params['server_ssl'] server_ssl_verify = module.params['server_ssl_verify'] server_ssl_ca = module.params['server_ssl_ca'] server_ssl_crl = module.params['server_ssl_crl'] server_ssl_client_certificate = module.params[ 'server_ssl_client_certificate'] server_weight = module.params['server_weight'] server_check_interval = module.params['server_check_interval'] server_check_down_interval = module.params['server_check_down_interval'] server_source = module.params['server_source'] server_advanced = module.params['server_advanced'] # Instantiate API connection api_url = module.params['api_url'] auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, auth, api_ssl_verify) # Fetch list of servers servers = apiconnection.listObjects('server') # Build dict with desired state desired_properties = { 'name': server_name, 'address': server_address, 'description': server_description, 'port': server_port, 'checkport': server_checkport, 'mode': server_mode, 'ssl': str(int(server_ssl)), 'sslVerify': str(int(server_ssl_verify)), 'sslCA': server_ssl_ca, 'sslCRL': server_ssl_crl, 'sslClientCertificate': server_ssl_client_certificate, 'weight': server_weight, 'checkInterval': server_check_interval, 'checkDownInterval': server_check_down_interval, 'source': server_source, 'advanced': server_advanced, } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if server object with specified name exists for server in servers: if server['name'] == server_name: server_exists = True uuid = server['uuid'] break server_exists = (uuid != '') if server_state == 'present': if server_exists: server = apiconnection.getObjectByName('server', server_name) #for prop in ['code', 'content', 'description']: for prop in desired_properties.keys(): # Special case for mode where selected element must be determined if prop == 'mode': current_mode = apiconnection.getSelected(server[prop]) if current_mode != server_mode: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing mode: %s => %s' % (current_mode, server_mode)) # Special case for sslCA where a list must be compared to a dict elif prop == 'sslCA': # Get current list of selected CAs by their name current_ssl_ca = apiconnection.getSelectedList( server[prop]) # Build list with keys of desired CAs desired_ssl_ca = [] # Search the ids of desired ssl_ca names for ca in server_ssl_ca: ca_key = apiconnection.findValueInDict(server[prop], searchvalue=ca) if ca_key != '': desired_ssl_ca.append(ca_key) # Compare current and desired list of CA names if not apiconnection.compareLists(current_ssl_ca, server_ssl_ca): needs_change = True changed_properties['sslCA'] = ','.join(desired_ssl_ca) additional_msg.append('Changing sslCA: %s => %s' % (current_ssl_ca, desired_ssl_ca)) # Special case for sslCRL where a list must be compared to a dict elif prop == 'sslCRL': current_ssl_crl = apiconnection.getSelected(server[prop]) # Find id of sslCRL with desired name desired_ssl_crl = apiconnection.findValueInDict( server[prop], searchvalue=server_ssl_crl) if not current_ssl_crl == desired_ssl_crl: needs_change = True changed_properties['sslCRL'] = desired_ssl_crl additional_msg.append( 'Changing sslCRL: %s => %s' % (current_ssl_crl, server_ssl_crl)) # Special case for sslClientCertificate where a single object must be determined from a list elif prop == 'sslClientCertificate': current_ssl_client_certificate = apiconnection.getSelected( server[prop], retval='value') if current_ssl_client_certificate != server_ssl_client_certificate: needs_change = True desired_ssl_client_certificate = apiconnection.findValueInDict( server[prop], searchvalue=server_ssl_client_certificate) changed_properties[ 'sslClientCertificate'] = desired_ssl_client_certificate additional_msg.append( 'Changing sslClientCertificate: %s => %s' % (current_ssl_client_certificate, server_ssl_client_certificate)) # Standard case for regular simple values else: if server[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, server[prop], desired_properties[prop])) if not needs_change: result = { 'changed': False, 'msg': [ 'Server already present: %s' % server_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.updateObject('server', server_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Server %s must be changed.' % server_name, additional_msg ] } else: if not module.check_mode: # clear parameters sslCA, sslCRL and sslClientCertificate, because we can't get their available ids at this time desired_properties['sslCA'] = '' desired_properties['sslCRL'] = '' desired_properties['sslClientCertificate'] = '' additional_msg.append( apiconnection.createObject('server', server_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Server %s must be created.' % server_name, additional_msg] } else: if server_exists: if not module.check_mode: additional_msg.append( apiconnection.deleteObject('server', server_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Server %s must be deleted.' % server_name, additional_msg] } else: result = { 'changed': False, 'msg': ['Server %s is not present.' % server_name] } module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), mapfile_name=dict(type='str', required=True), mapfile_description=dict(type='str', default=''), mapfile_content=dict(type='str', default=''), mapfile_state=dict(type='str', choices=['present', 'absent'], default='present'), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of mapfile mapfile_name = module.params['mapfile_name'] mapfile_content = module.params['mapfile_content'] mapfile_state = module.params['mapfile_state'] mapfile_description = module.params['mapfile_description'] # Instantiate API connection api_url = module.params['api_url'] api_auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, api_auth, api_ssl_verify) # Fetch list of mapfiles mapfiles = apiconnection.listObjects('mapfile') # Build dict with desired state desired_properties = { 'description': mapfile_description, 'content': mapfile_content } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if mapfile object with specified name exists for mapfile in mapfiles: if mapfile['name'] == mapfile_name: uuid = mapfile['uuid'] break mapfile_exists = (uuid != '') if mapfile_state == 'present': if mapfile_exists: mapfile = apiconnection.getObjectByName('mapfile', mapfile_name) for prop in desired_properties.keys(): if mapfile[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] if not needs_change: result = { 'changed': False, 'msg': ['Mapfile already present: %s' % mapfile_name] } else: if not module.check_mode: additional_msg.append( apiconnection.updateObject('mapfile', mapfile_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Mapfile %s must be changed.' % mapfile_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.createObject('mapfile', mapfile_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Mapfile %s must be created.' % mapfile_name, additional_msg] } else: if mapfile_exists: if not module.check_mode: additional_msg.append( apiconnection.deleteObject('mapfile', mapfile_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Mapfile %s must be deleted.' % mapfile_name, additional_msg] } else: result = { 'changed': False, 'msg': ['Mapfile %s is not present.' % mapfile_name] } module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), backend_state=dict(type='str', choices=['present', 'absent'], default='present'), backend_enabled=dict(type='bool', default=True), backend_name=dict(type='str', required=True), backend_description=dict(type='str', default=''), backend_mode=dict(type='str', choices=['http', 'tcp'], default='http'), backend_algorithm=dict(type='str', choices=[ 'source', 'roundrobin', 'static-rr', 'leastconn', 'uri' ], default='source'), backend_proxy_protocol=dict(type='str', choices=['', 'v1', 'v2'], default=''), backend_linked_servers=dict(type='list', default=[]), backend_source=dict(type='str', default=''), backend_health_check_enabled=dict(type='bool', default=True), backend_health_check=dict(type='str', default=''), backend_health_check_log_status=dict(type='bool', default=False), backend_check_interval=dict(type='str', default=''), backend_check_down_interval=dict(type='str', default=''), backend_health_check_fall=dict(type='str', default=''), backend_health_check_rise=dict(type='str', default=''), backend_persistence=dict(type='str', choices=['', 'sticktable', 'cookie'], default='sticktable'), backend_persistence_cookie_mode=dict(type='str', choices=['piggyback', 'new'], default='piggyback'), backend_persistence_cookie_name=dict(type='str', default='SRVCOOKIE'), backend_persistence_strip_quotes=dict(type='bool', default=True), backend_stickiness_pattern=dict(type='str', choices=[ '', 'sourceipv4', 'sourceipv6', 'cookievalue', 'rdpcookie' ], default='sourceipv4'), backend_stickiness_data_types=dict( type='list', elements='str', options=dict(choices=[ 'conn_cnt', 'conn_cur', 'conn_rate', 'sess_cnt', 'sess_rate', 'http_req_cnt', 'http_req_rate', 'http_err_cnt', 'http_err_rate', 'bytes_in_cnt', 'bytes_in_rate', 'bytes_out_cnt', 'bytes_out_rate' ], ), default=[]), backend_stickiness_expire=dict(type='str', default='30m'), backend_stickiness_size=dict(type='str', default='50k'), backend_stickiness_cookie_name=dict(type='str', default=''), backend_stickiness_cookie_length=dict(type='str', default=''), backend_stickiness_conn_rate_period=dict(type='str', default='10s'), backend_stickiness_sess_rate_period=dict(type='str', default='10s'), backend_stickiness_http_req_rate_period=dict(type='str', default='10s'), backend_stickiness_http_err_rate_period=dict(type='str', default='10s'), backend_stickiness_bytes_in_rate_period=dict(type='str', default='1m'), backend_stickiness_bytes_out_rate_period=dict(type='str', default='1m'), backend_basic_auth_enabled=dict(type='bool', default=False), backend_basic_auth_users=dict(type='list', default=[]), backend_basic_auth_groups=dict(type='list', default=[]), backend_tuning_timeout_connect=dict(type='str', default=''), backend_tuning_timeout_check=dict(type='str', default=''), backend_tuning_timeout_server=dict(type='str', default=''), backend_tuning_retries=dict(type='str', default=''), backend_custom_options=dict(type='str', default=''), backend_tuning_default_server=dict(type='str', default=''), backend_tuning_no_port=dict(type='bool', default=False), backend_tuning_http_reuse=dict( type='str', choices=['', 'never', 'safe', 'aggressive', 'always'], default='never'), backend_linked_actions=dict(type='list', default=[]), backend_linked_errorfiles=dict(type='list', default=[]), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of backend backend_state = module.params['backend_state'] backend_enabled = str(int(module.params['backend_enabled'])) backend_name = module.params['backend_name'] backend_description = module.params['backend_description'] backend_mode = module.params['backend_mode'] backend_algorithm = module.params['backend_algorithm'] backend_proxy_protocol = module.params['backend_proxy_protocol'] backend_linked_servers = module.params['backend_linked_servers'] backend_source = module.params['backend_source'] backend_health_check_enabled = module.params[ 'backend_health_check_enabled'] backend_health_check = module.params['backend_health_check'] backend_health_check_log_status = module.params[ 'backend_health_check_log_status'] backend_check_interval = module.params['backend_check_interval'] backend_check_down_interval = module.params['backend_check_down_interval'] backend_health_check_fall = module.params['backend_health_check_fall'] backend_health_check_rise = module.params['backend_health_check_rise'] backend_persistence = module.params['backend_persistence'] backend_persistence_cookie_mode = module.params[ 'backend_persistence_cookie_mode'] backend_persistence_cookie_name = module.params[ 'backend_persistence_cookie_name'] backend_persistence_strip_quotes = module.params[ 'backend_persistence_strip_quotes'] backend_stickiness_pattern = module.params['backend_stickiness_pattern'] backend_stickiness_data_types = module.params[ 'backend_stickiness_data_types'] backend_stickiness_expire = module.params['backend_stickiness_expire'] backend_stickiness_size = module.params['backend_stickiness_size'] backend_stickiness_cookie_name = module.params[ 'backend_stickiness_cookie_name'] backend_stickiness_cookie_length = module.params[ 'backend_stickiness_cookie_length'] backend_stickiness_conn_rate_period = module.params[ 'backend_stickiness_conn_rate_period'] backend_stickiness_sess_rate_period = module.params[ 'backend_stickiness_sess_rate_period'] backend_stickiness_http_req_rate_period = module.params[ 'backend_stickiness_http_req_rate_period'] backend_stickiness_http_err_rate_period = module.params[ 'backend_stickiness_http_err_rate_period'] backend_stickiness_bytes_in_rate_period = module.params[ 'backend_stickiness_bytes_in_rate_period'] backend_stickiness_bytes_out_rate_period = module.params[ 'backend_stickiness_bytes_out_rate_period'] backend_basic_auth_enabled = module.params['backend_basic_auth_enabled'] backend_basic_auth_users = module.params['backend_basic_auth_users'] backend_basic_auth_groups = module.params['backend_basic_auth_groups'] backend_tuning_timeout_connect = module.params[ 'backend_tuning_timeout_connect'] backend_tuning_timeout_check = module.params[ 'backend_tuning_timeout_check'] backend_tuning_timeout_server = module.params[ 'backend_tuning_timeout_server'] backend_tuning_retries = module.params['backend_tuning_retries'] backend_custom_options = module.params['backend_custom_options'] backend_tuning_default_server = module.params[ 'backend_tuning_default_server'] backend_tuning_no_port = module.params['backend_tuning_no_port'] backend_tuning_http_reuse = module.params['backend_tuning_http_reuse'] backend_linked_actions = module.params['backend_linked_actions'] backend_linked_errorfiles = module.params['backend_linked_errorfiles'] # Instantiate API connection api_url = module.params['api_url'] api_auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, api_auth, api_ssl_verify) # Fetch list of backends backends = apiconnection.listObjects('backend') # Get an empty backend object to lookup UUIDs for: # - linkedServers # - healthCheck # - basicAuthUsers # - basicAuthGroups # - linkedActions # - linkedErrorfiles empty_backend = apiconnection.getObjectByUuid('backend', '') # Need to get UUIDs for: # linkedServers, healthCheck, basicAuthUsers, basicAuthGroups, linkedActions, linkedErrorfiles backend_linked_servers_uuids = [] #backend_linked_servers_uuids = apiconnection.getUuidsFromNames('server', backend_linked_servers) for backend_linked_server in backend_linked_servers: for key, value in empty_backend['linkedServers'].iteritems(): if value['value'] == backend_linked_server: backend_linked_servers_uuids.append(key) backend_health_check_uuid = '' if backend_health_check != '': #backend_health_check_uuid = apiconnection.getUuidByName('healthcheck', backend_health_check) for key, value in empty_backend['healthCheck'].iteritems(): if value['value'] == backend_health_check: backend_health_check_uuid = key #backend_basic_auth_users_uuids = apiconnection.getUuidsFromNames('user', backend_basic_auth_users) backend_basic_auth_users_uuids = [] for backend_basic_auth_user in backend_basic_auth_users: for key, value in empty_backend['basicAuthUsers'].iteritems(): if value['value'] == backend_basic_auth_user: backend_basic_auth_users_uuids.append(key) #backend_basic_auth_groups_uuids = apiconnection.getUuidsFromNames('group', backend_basic_auth_groups) backend_basic_auth_groups_uuids = [] for backend_basic_auth_group in backend_basic_auth_groups: for key, value in empty_backend['basicAuthGroups'].iteritems(): if value['value'] == backend_basic_auth_group: backend_basic_auth_groups_uuids.append(key) #backend_linked_actions_uuids = apiconnection.getUuidsFromNames('action', backend_linked_actions) backend_linked_actions_uuids = [] for backend_linked_action in backend_linked_actions: for key, value in empty_backend['linkedActions'].iteritems(): if value['value'] == backend_linked_action: backend_linked_actions_uuids.append(key) #backend_linked_errorfiles_uuids = apiconnection.getUuidsFromNames('errorfile', backend_linked_errorfiles) backend_linked_errorfiles_uuids = [] for backend_linked_errorfile in backend_linked_errorfiles: for key, value in empty_backend['linkedErrorfiles'].iteritems(): if value['value'] == backend_linked_errorfile: backend_linked_errorfiles_uuids.append(key) # Build dict with desired state desired_properties = { 'enabled': backend_enabled, 'description': backend_description, 'mode': backend_mode, 'algorithm': backend_algorithm, 'proxyProtocol': backend_proxy_protocol, 'linkedServers': ','.join(backend_linked_servers_uuids), 'source': backend_source, 'healthCheckEnabled': str(int(backend_health_check_enabled)), 'healthCheck': backend_health_check_uuid, 'healthCheckLogStatus': str(int(backend_health_check_log_status)), 'checkInterval': backend_check_interval, 'checkDownInterval': backend_check_down_interval, 'healthCheckFall': backend_health_check_fall, 'healthCheckRise': backend_health_check_rise, 'persistence': backend_persistence, 'persistence_cookiemode': backend_persistence_cookie_mode, 'persistence_cookiename': backend_persistence_cookie_name, 'persistence_stripquotes': str(int(backend_persistence_strip_quotes)), 'stickiness_pattern': backend_stickiness_pattern, 'stickiness_dataTypes': ','.join(backend_stickiness_data_types), 'stickiness_expire': backend_stickiness_expire, 'stickiness_size': backend_stickiness_size, 'stickiness_cookiename': backend_stickiness_cookie_name, 'stickiness_cookielength': backend_stickiness_cookie_length, 'stickiness_connRatePeriod': backend_stickiness_conn_rate_period, 'stickiness_sessRatePeriod': backend_stickiness_sess_rate_period, 'stickiness_httpReqRatePeriod': backend_stickiness_http_req_rate_period, 'stickiness_httpErrRatePeriod': backend_stickiness_http_err_rate_period, 'stickiness_bytesInRatePeriod': backend_stickiness_bytes_in_rate_period, 'stickiness_bytesOutRatePeriod': backend_stickiness_bytes_out_rate_period, 'basicAuthEnabled': str(int(backend_basic_auth_enabled)), 'basicAuthUsers': ','.join(backend_basic_auth_users_uuids), 'basicAuthGroups': ','.join(backend_basic_auth_groups_uuids), 'tuning_timeoutConnect': backend_tuning_timeout_connect, 'tuning_timeoutCheck': backend_tuning_timeout_check, 'tuning_timeoutServer': backend_tuning_timeout_server, 'tuning_retries': backend_tuning_retries, 'customOptions': backend_custom_options, 'tuning_defaultserver': backend_tuning_default_server, 'tuning_noport': str(int(backend_tuning_no_port)), 'tuning_httpreuse': backend_tuning_http_reuse, 'linkedActions': ','.join(backend_linked_actions_uuids), 'linkedErrorfiles': ','.join(backend_linked_errorfiles_uuids) } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if backend object with specified name exists for backend in backends: if backend['name'] == backend_name: uuid = backend['uuid'] break backend_exists = (uuid != '') if backend_state == 'present': if backend_exists: backend = apiconnection.getObjectByName('backend', backend_name) for prop in desired_properties.keys(): # Special cases for complex propertierts: if prop == 'mode': current_mode = apiconnection.getSelected(backend[prop]) if current_mode != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_mode, desired_properties[prop])) elif prop == 'algorithm': current_algorithm = apiconnection.getSelected( backend[prop]) if current_algorithm != backend_algorithm: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_algorithm, desired_properties[prop])) elif prop == 'proxyProtocol': current_proxy_protocol = apiconnection.getSelected( backend[prop]) if current_proxy_protocol != backend_proxy_protocol: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_proxy_protocol, desired_properties[prop])) elif prop == 'linkedServers': current_linked_servers = apiconnection.getSelectedList( backend[prop], retval='key') if not apiconnection.compareLists( current_linked_servers, backend_linked_servers_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_linked_servers, desired_properties[prop])) elif prop == 'healthCheck': current_health_check = apiconnection.getSelected( backend[prop], retval='value') if current_health_check != backend_health_check: if current_health_check == 'none' and backend_health_check == '': pass else: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_health_check, desired_properties[prop])) elif prop == 'persistence': current_persistence = apiconnection.getSelected( backend[prop], retval='key') if current_persistence != backend_persistence: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_persistence, desired_properties[prop])) elif prop == 'persistence_cookiemode': current_persistence_cookie_mode = apiconnection.getSelected( backend[prop], retval='key') if current_persistence_cookie_mode != backend_persistence_cookie_mode: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_persistence_cookie_mode, desired_properties[prop])) elif prop == 'stickiness_pattern': current_stickiness_pattern = apiconnection.getSelected( backend[prop]) if current_stickiness_pattern != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_stickiness_pattern, desired_properties[prop])) elif prop == 'stickiness_dataTypes': current_stickiness_data_types = apiconnection.getSelected( backend[prop]) if not apiconnection.compareLists( current_stickiness_data_types, backend_stickiness_data_types): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_stickiness_data_types, desired_properties[prop])) elif prop == 'basicAuthUsers': # only care about basicAuthUsers when basic auth is enabled if backend_basic_auth_enabled: current_basic_auth_users = apiconnection.getSelectedList( backend[prop]) if not apiconnection.compareLists( current_basic_auth_users, backend_basic_auth_users): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_basic_auth_users, desired_properties[prop])) elif prop == 'basicAuthGroups': # only care about basicAuthGroups when basic auth is enabled if backend_basic_auth_enabled: current_basic_auth_groups = apiconnection.getSelectedList( backend[prop]) if not apiconnection.compareLists( current_basic_auth_groups, backend_basic_auth_groups): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_basic_auth_groups, desired_properties[prop])) elif prop == 'tuning_httpreuse': current_tuning_httpreuse = apiconnection.getSelected( backend[prop]) if current_tuning_httpreuse != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_tuning_httpreuse, desired_properties[prop])) elif prop == 'linkedActions': current_linked_actions = apiconnection.getSelectedList( backend[prop], retval='key') if not apiconnection.compareLists( current_linked_actions, backend_linked_actions_uuids, order_sensitive=True): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_linked_actions, desired_properties[prop])) elif prop == 'linkedErrorfiles': current_linked_errorfiles = apiconnection.getSelectedList( backend[prop], retval='key') if not apiconnection.compareLists( current_linked_errorfiles, backend_linked_errorfiles_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_linked_errorfiles, desired_properties[prop])) else: # catch all other properties if backend[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, backend[prop], desired_properties[prop])) if not needs_change: result = { 'changed': False, 'msg': [ 'Backend already present: %s' % backend_name, additional_msg ] } else: if not module.check_mode: # workaround for https://github.com/opnsense/plugins/issues/1494 # any change must include the linkedActions to maintain the correct order changed_properties['linkedActions'] = desired_properties[ 'linkedActions'] additional_msg.append( apiconnection.updateObject('backend', backend_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Backend %s must be changed.' % backend_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.createObject('backend', backend_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Backend %s must be created.' % backend_name, additional_msg] } else: if backend_exists: if not module.check_mode: additional_msg.append( apiconnection.deleteObject('backend', backend_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': ['Backend %s must be deleted.' % backend_name, additional_msg] } else: result = { 'changed': False, 'msg': ['Backend %s is not present.' % backend_name] } module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), acl_state=dict(type='str', choices=['present', 'absent'], default='present'), acl_name=dict(type='str', required=True), acl_description=dict(type='str', default=''), acl_expression=dict(type='str', choices=[ 'http_auth', 'hdr_beg', 'hdr_end', 'hdr', 'hdr_reg', 'hdr_sub', 'path_beg', 'path_end', 'path', 'path_reg', 'path_dir', 'path_sub', 'url_param', 'ssl_c_verify', 'ssl_c_verify_code', 'ssl_c_ca_commonname', 'src', 'src_is_local', 'src_port', 'src_bytes_in_rate', 'src_bytes_out_rate', 'src_kbytes_in', 'src_kbytes_out', 'src_conn_cnt', 'src_conn_cur', 'src_conn_rate', 'src_http_err_cnt', 'src_http_err_rate', 'src_http_req_cnt', 'src_http_req_rate', 'src_sess_rate', 'nbsrv', 'traffic_is_http', 'traffic_is_ssl', 'ssl_fc', 'ssl_fc_sni', 'ssl_sni', 'ssl_sni_sub', 'ssl_sni_beg', 'ssl_sni_end', 'ssl_sni_reg', 'custom_acl' ], required=True), acl_negate=dict(type='bool', default=False), acl_hdr_beg=dict(type='str', default=''), acl_hdr_end=dict(type='str', default=''), acl_hdr=dict(type='str', default=''), acl_hdr_reg=dict(type='str', default=''), acl_hdr_sub=dict(type='str', default=''), acl_path_beg=dict(type='str', default=''), acl_path_end=dict(type='str', default=''), acl_path=dict(type='str', default=''), acl_path_reg=dict(type='str', default=''), acl_path_dir=dict(type='str', default=''), acl_path_sub=dict(type='str', default=''), acl_url_param=dict(type='str', default=''), acl_url_param_value=dict(type='str', default=''), acl_ssl_c_verify_code=dict(type='str', default=''), acl_ssl_c_ca_commonname=dict(type='str', default=''), acl_src=dict(type='str', default=''), acl_src_bytes_in_rate_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_bytes_in_rate=dict(type='str', default=''), acl_src_bytes_out_rate_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_bytes_out_rate=dict(type='str', default=''), acl_src_conn_cnt_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_conn_cnt=dict(type='str', default=''), acl_src_conn_rate_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_conn_rate=dict(type='str', default=''), acl_src_http_err_cnt_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_http_err_cnt=dict(type='str', default=''), acl_src_http_err_rate_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_http_err_rate=dict(type='str', default=''), acl_src_http_req_rate_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_http_req_rate=dict(type='str', default=''), acl_src_kbytes_in_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_kbytes_in=dict(type='str', default=''), acl_src_kbytes_out_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_kbytes_out=dict(type='str', default=''), acl_src_port_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_port=dict(type='str', default=''), acl_src_sess_cnt_comparison=dict(type='str', choices=['', 'gt', 'ge', 'eq', 'lt', 'le'], default='gt'), acl_src_sess_cnt=dict(type='str', default=''), acl_nbsrv=dict(type='str', default=''), acl_nbsrv_backend=dict(type='str', default=''), acl_ssl_fc_sni=dict(type='str', default=''), acl_ssl_sni=dict(type='str', default=''), acl_ssl_sni_sub=dict(type='str', default=''), acl_ssl_sni_beg=dict(type='str', default=''), acl_ssl_sni_end=dict(type='str', default=''), acl_ssl_sni_reg=dict(type='str', default=''), acl_custom_acl=dict(type='str', default=''), acl_value=dict(type='str', default=''), acl_query_backend=dict(type='str', default=''), acl_allowed_users=dict(type='list', default=[]), acl_allowed_groups=dict(type='list', default=[]), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) # Instantiate API connection api_url = module.params['api_url'] api_auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, api_auth, api_ssl_verify) # Prepare properties of acl haproxy_reload = module.params['haproxy_reload'] acl_state = module.params['acl_state'] acl_name = module.params['acl_name'] acl_description = module.params['acl_description'] acl_expression = module.params['acl_expression'] acl_negate = module.params['acl_negate'] acl_hdr_beg = module.params['acl_hdr_beg'] acl_hdr_end = module.params['acl_hdr_end'] acl_hdr = module.params['acl_hdr'] acl_hdr_reg = module.params['acl_hdr_reg'] acl_hdr_sub = module.params['acl_hdr_sub'] acl_path_beg = module.params['acl_path_beg'] acl_path_end = module.params['acl_path_end'] acl_path = module.params['acl_path'] acl_path_reg = module.params['acl_path_reg'] acl_path_dir = module.params['acl_path_dir'] acl_path_sub = module.params['acl_path_sub'] acl_url_param = module.params['acl_url_param'] acl_url_param_value = module.params['acl_url_param_value'] acl_ssl_c_verify_code = module.params['acl_ssl_c_verify_code'] acl_ssl_c_ca_commonname = module.params['acl_ssl_c_ca_commonname'] acl_src = module.params['acl_src'] acl_src_bytes_in_rate_comparison = module.params['acl_src_bytes_in_rate_comparison'] acl_src_bytes_in_rate = module.params['acl_src_bytes_in_rate'] acl_src_bytes_out_rate_comparison = module.params['acl_src_bytes_out_rate_comparison'] acl_src_bytes_out_rate = module.params['acl_src_bytes_out_rate'] acl_src_conn_cnt_comparison = module.params['acl_src_conn_cnt_comparison'] acl_src_conn_cnt = module.params['acl_src_conn_cnt'] acl_src_conn_rate_comparison = module.params['acl_src_conn_rate_comparison'] acl_src_conn_rate = module.params['acl_src_conn_rate'] acl_src_http_err_cnt_comparison = module.params['acl_src_http_err_cnt_comparison'] acl_src_http_err_cnt = module.params['acl_src_http_err_cnt'] acl_src_http_err_rate_comparison = module.params['acl_src_http_err_rate_comparison'] acl_src_http_err_rate = module.params['acl_src_http_err_rate'] acl_src_http_req_rate_comparison = module.params['acl_src_http_req_rate_comparison'] acl_src_http_req_rate = module.params['acl_src_http_req_rate'] acl_src_kbytes_in_comparison = module.params['acl_src_kbytes_in_comparison'] acl_src_kbytes_in = module.params['acl_src_kbytes_in'] acl_src_kbytes_out_comparison = module.params['acl_src_kbytes_out_comparison'] acl_src_kbytes_out = module.params['acl_src_kbytes_out'] acl_src_port_comparison = module.params['acl_src_port_comparison'] acl_src_port = module.params['acl_src_port'] acl_src_sess_cnt_comparison = module.params['acl_src_sess_cnt_comparison'] acl_src_sess_cnt = module.params['acl_src_sess_cnt'] acl_nbsrv = module.params['acl_nbsrv'] acl_nbsrv_backend = module.params['acl_nbsrv_backend'] acl_ssl_fc_sni = module.params['acl_ssl_fc_sni'] acl_ssl_sni = module.params['acl_ssl_sni'] acl_ssl_sni_sub = module.params['acl_ssl_sni_sub'] acl_ssl_sni_beg = module.params['acl_ssl_sni_beg'] acl_ssl_sni_end = module.params['acl_ssl_sni_end'] acl_ssl_sni_reg = module.params['acl_ssl_sni_reg'] acl_custom_acl = module.params['acl_custom_acl'] acl_value = module.params['acl_value'] acl_query_backend = module.params['acl_query_backend'] acl_allowed_users = module.params['acl_allowed_users'] acl_allowed_groups = module.params['acl_allowed_groups'] # Get empty ACL object to lookup UUIDs for allowedUsers, allowedGroups, nbsrv_backend, queryBackend empty_acl = apiconnection.getObjectByUuid('acl', '') #acl_nbsrv_backend = apiconnection.getUuidByName('backend', module.params['acl_nbsrv_backend']) acl_nbsrv_backend_uuid = '' if acl_nbsrv_backend != '': for key,value in empty_acl['nbsrv_backend'].iteritems(): if value['value'] == acl_nbsrv_backend: acl_nbsrv_backend_uuid = key #acl_query_backend = apiconnection.getUuidByName('backend', module.params['acl_query_backend']) acl_query_backend_uuid = '' if acl_query_backend != '': for key,value in empty_acl['queryBackend'].iteritems(): if value['value'] == acl_query_backend: acl_query_backend_uuid = key # Resolve UUIDs for users acl_allowed_users_uuids = [] for acl_allowed_user in acl_allowed_users: #acl_allowed_users_uuids.append(apiconnection.getUuidByName('user', acl_allowed_user)) for key,value in empty_acl['allowedUsers'].iteritems(): if value['value'] == acl_allowed_user: acl_allowed_users_uuids.append(key) # Resolve UUIDs for allowedGroups acl_allowed_groups_uuids = [] for acl_allowed_group in acl_allowed_groups: #acl_allowed_groups_uuids.append(apiconnection.getUuidByName('group', acl_allowed_group)) for key,value in empty_acl['allowedGroups'].iteritems(): if value['value'] == acl_allowed_group: acl_allowed_groups_uuids.append(key) # Fetch list of acls acls = apiconnection.listObjects('acl') # Build dict with desired state desired_properties = { 'description': acl_description, 'expression': acl_expression, 'negate': str(int(acl_negate)), 'hdr_beg': acl_hdr_beg, 'hdr_end': acl_hdr_end, 'hdr': acl_hdr, 'hdr_reg': acl_hdr_beg, 'hdr_sub': acl_hdr_sub, 'path_beg': acl_path_beg, 'path_end': acl_path_end, 'path': acl_path, 'path_reg': acl_path_reg, 'path_dir': acl_path_dir, 'path_sub': acl_path_sub, 'url_param': acl_url_param, 'url_param_value': acl_url_param_value, 'ssl_c_verify_code': acl_ssl_c_verify_code, 'ssl_c_ca_commonname': acl_ssl_c_ca_commonname, 'src': acl_src, 'src_bytes_in_rate_comparison': acl_src_bytes_in_rate_comparison, 'src_bytes_in_rate': acl_src_bytes_in_rate, 'src_bytes_out_rate_comparison': acl_src_bytes_out_rate_comparison, 'src_bytes_out_rate': acl_src_bytes_out_rate, 'src_conn_cnt_comparison': acl_src_conn_cnt_comparison, 'src_conn_cnt': acl_src_conn_cnt, 'src_conn_rate_comparison': acl_src_conn_rate_comparison, 'src_conn_rate': acl_src_conn_rate, 'src_http_err_cnt_comparison': acl_src_http_err_cnt_comparison, 'src_http_err_cnt': acl_src_http_err_cnt, 'src_http_err_rate_comparison': acl_src_http_err_rate_comparison, 'src_http_err_rate': acl_src_http_err_rate, 'src_http_req_rate_comparison': acl_src_http_req_rate_comparison, 'src_http_req_rate': acl_src_http_req_rate, 'src_kbytes_in_comparison': acl_src_kbytes_in_comparison, 'src_kbytes_in': acl_src_kbytes_in, 'src_kbytes_out_comparison': acl_src_kbytes_out_comparison, 'src_kbytes_out': acl_src_kbytes_out, 'src_port_comparison': acl_src_port_comparison, 'src_port': acl_src_port, 'src_sess_cnt_comparison': acl_src_sess_cnt_comparison, 'src_sess_cnt': acl_src_sess_cnt, 'nbsrv': acl_nbsrv, 'nbsrv_backend': acl_nbsrv_backend_uuid, 'ssl_fc_sni': acl_ssl_fc_sni, 'ssl_sni': acl_ssl_sni, 'ssl_sni_sub': acl_ssl_sni_sub, 'ssl_sni_beg': acl_ssl_sni_beg, 'ssl_sni_end': acl_ssl_sni_end, 'ssl_sni_reg': acl_ssl_sni_reg, 'custom_acl': acl_custom_acl, 'value': acl_value, 'queryBackend': acl_query_backend, 'allowedUsers': ','.join(acl_allowed_users_uuids), 'allowedGroups': ','.join(acl_allowed_groups_uuids) } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if acl object with specified name exists for acl in acls: if acl['name'] == acl_name: uuid = acl['uuid'] break acl_exists = (uuid != '') if acl_state == 'present': if acl_exists: acl = apiconnection.getObjectByName('acl', acl_name) for prop in desired_properties.keys(): # Special cases for complex propertierts: if prop == 'expression': current_expression = apiconnection.getSelected(acl[prop]) if current_expression != acl_expression: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_expression, desired_properties[prop])) # Catch all _comparison properties elif '_comparison' in prop: current_comparison = apiconnection.getSelected(acl[prop]) if current_comparison != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_comparison, desired_properties[prop])) elif prop == 'nbsrv_backend': current_nbsrv_backend = apiconnection.getSelected(acl[prop]) if current_nbsrv_backend != acl_nbsrv_backend: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_nbsrv_backend, desired_properties[prop])) elif prop == 'queryBackend': current_query_backend = apiconnection.getSelected(acl[prop]) if current_query_backend != acl_query_backend: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_query_backend, desired_properties[prop])) elif prop == 'allowedUsers': current_allowed_users = apiconnection.getSelectedList(acl[prop]) if not apiconnection.compareLists(current_allowed_users, acl_allowed_users_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_allowed_users, desired_properties[prop])) elif prop == 'allowedGroups': current_allowed_groups = apiconnection.getSelectedList(acl[prop]) if not apiconnection.compareLists(current_allowed_groups, acl_allowed_groups_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, current_allowed_groups, desired_properties[prop])) else: # catch all other properties if acl[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' %(prop, acl[prop], desired_properties[prop])) if not needs_change: result = {'changed': False, 'msg': ['Acl already present: %s' %acl_name, additional_msg]} else: if not module.check_mode: additional_msg.append(apiconnection.updateObject('acl', acl_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Acl %s must be changed.' %acl_name, additional_msg]} else: if not module.check_mode: additional_msg.append(apiconnection.createObject('acl', acl_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Acl %s must be created.' %acl_name, additional_msg]} else: if acl_exists: if not module.check_mode: additional_msg.append(apiconnection.deleteObject('acl', acl_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = {'changed': True, 'msg': ['Acl %s must be deleted.' %acl_name, additional_msg]} else: result = {'changed': False, 'msg': ['Acl %s is not present.' %acl_name]} module.exit_json(**result)
def main(): global module # Instantiate module module = AnsibleModule( argument_spec=dict( api_url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), api_secret=dict(type='str', required=True, no_log=True), api_ssl_verify=dict(type='bool', default=False), frontend_state=dict(type='str', choices=['present', 'absent'], default='present'), frontend_enabled=dict(type='bool', default=True), frontend_name=dict(type='str', required=True), frontend_description=dict(type='str', default=''), frontend_bind=dict(type='list', required=True), frontend_bind_options=dict(type='str', default=''), frontend_mode=dict(type='str', choices=['http', 'ssl', 'tcp'], default='http'), frontend_default_backend=dict(type='str', default='none'), frontend_ssl_enabled=dict(type='bool', default=False), frontend_ssl_certificates=dict(type='list', default=[]), frontend_ssl_default_certificate=dict(type='str', default=''), frontend_ssl_custom_options=dict(type='str', default=''), frontend_ssl_advanced_enabled=dict(type='bool', default=False), frontend_ssl_bind_options=dict(type='list', elements='str', options=dict(choices=[ 'no-sslv3', 'no-tlsv10', 'no-tlsv11', 'no-tlsv12', 'no-tls-tickets', 'force-sslv3', 'force-tlsv10', 'force-tlsv11', 'force-tlsv12', 'strict-sni' ], ), default=[]), frontend_ssl_cipher_list=dict( type='str', default= 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256' ), frontend_ssl_http2_enabled=dict(type='bool', default=False), frontend_ssl_hsts_enabled=dict(type='bool', default=True), frontend_ssl_hsts_include_sub_domains=dict(type='bool', default=False), frontend_ssl_hsts_preload=dict(type='bool', default=False), frontend_ssl_hsts_max_age=dict(type='str', default='15768000'), frontend_ssl_client_auth_enabled=dict(type='bool', default=False), frontend_ssl_client_auth_verify=dict( type='str', choices=['none', 'optional', 'required'], default='none'), frontend_ssl_client_auth_cas=dict(type='list', default=[]), frontend_ssl_client_auth_crls=dict(type='list', default=[]), frontend_basic_auth_enabled=dict(type='bool', default=False), frontend_basic_auth_users=dict(type='list', default=[]), frontend_basic_auth_groups=dict(type='list', default=[]), frontend_tuning_max_connections=dict(type='str', default=''), frontend_tuning_timeout_client=dict(type='str', default=''), frontend_tuning_timeout_http_req=dict(type='str', default=''), frontend_tuning_timeout_http_keep_alive=dict(type='str', default=''), frontend_linked_cpu_affinity_rules=dict(type='list', default=[]), frontend_logging_dont_log_null=dict(type='bool', default=False), frontend_logging_dont_log_normal=dict(type='bool', default=False), frontend_logging_log_separate_errors=dict(type='bool', default=False), frontend_logging_detailed_log=dict(type='bool', default=False), frontend_logging_socket_stats=dict(type='bool', default=False), frontend_stickiness_pattern=dict( type='str', choices=['ipv4', 'ipv6', 'integer', 'string', 'binary'], default='ipv4'), frontend_stickiness_data_types=dict( type='list', elements='str', options=dict(choices=[ 'conn_cnt', 'conn_cur', 'conn_rate', 'sess_cnt', 'sess_rate', 'http_req_cnt', 'http_req_rate', 'http_err_cnt', 'http_err_rate', 'bytes_in_cnt', 'bytes_in_rate', 'bytes_out_cnt', 'bytes_out_rate' ], ), default=[]), frontend_stickiness_expire=dict(type='str', default='30m'), frontend_stickiness_size=dict(type='str', default='50k'), frontend_stickiness_counter=dict(type='bool', default=True), frontend_stickiness_counter_key=dict(type='str', default='src'), frontend_stickiness_length=dict(type='str', default=''), frontend_stickiness_conn_rate_period=dict(type='str', default='10s'), frontend_stickiness_sess_rate_period=dict(type='str', default='10s'), frontend_stickiness_http_req_rate_period=dict(type='str', default='10s'), frontend_stickiness_http_err_rate_period=dict(type='str', default='10s'), frontend_stickiness_bytes_in_rate_period=dict(type='str', default='1m'), frontend_stickiness_bytes_out_rate_period=dict(type='str', default='1m'), frontend_forward_for=dict(type='bool', default=False), frontend_connection_behaviour=dict(type='str', choices=[ 'http-keep-alive', 'http-tunnel', 'httpclose', 'http-server-close', 'forceclose' ], default='http-keep-alive'), frontend_custom_options=dict(type='str', default=''), frontend_linked_actions=dict(type='list', default=[]), frontend_linked_errorfiles=dict(type='list', default=[]), haproxy_reload=dict(type='bool', default=False), ), supports_check_mode=True, ) haproxy_reload = module.params['haproxy_reload'] # Prepare properties of frontend frontend_state = module.params['frontend_state'] frontend_enabled = str(int(module.params['frontend_enabled'])) frontend_name = module.params['frontend_name'] frontend_description = module.params['frontend_description'] frontend_bind = module.params['frontend_bind'] frontend_bind_options = module.params['frontend_bind_options'] frontend_mode = module.params['frontend_mode'] frontend_default_backend = module.params['frontend_default_backend'] frontend_ssl_enabled = module.params['frontend_ssl_enabled'] frontend_ssl_certificates = module.params['frontend_ssl_certificates'] frontend_ssl_default_certificate = module.params[ 'frontend_ssl_default_certificate'] frontend_ssl_custom_options = module.params['frontend_ssl_custom_options'] frontend_ssl_advanced_enabled = module.params[ 'frontend_ssl_advanced_enabled'] frontend_ssl_bind_options = module.params['frontend_ssl_bind_options'] frontend_ssl_cipher_list = module.params['frontend_ssl_cipher_list'] frontend_ssl_http2_enabled = module.params['frontend_ssl_http2_enabled'] frontend_ssl_hsts_enabled = module.params['frontend_ssl_hsts_enabled'] frontend_ssl_hsts_include_sub_domains = module.params[ 'frontend_ssl_hsts_include_sub_domains'] frontend_ssl_hsts_preload = module.params['frontend_ssl_hsts_preload'] frontend_ssl_hsts_max_age = module.params['frontend_ssl_hsts_max_age'] frontend_ssl_client_auth_enabled = module.params[ 'frontend_ssl_client_auth_enabled'] frontend_ssl_client_auth_verify = module.params[ 'frontend_ssl_client_auth_verify'] frontend_ssl_client_auth_cas = module.params[ 'frontend_ssl_client_auth_cas'] frontend_ssl_client_auth_crls = module.params[ 'frontend_ssl_client_auth_crls'] frontend_basic_auth_enabled = module.params['frontend_basic_auth_enabled'] frontend_basic_auth_users = module.params['frontend_basic_auth_users'] frontend_basic_auth_groups = module.params['frontend_basic_auth_groups'] frontend_tuning_max_connections = module.params[ 'frontend_tuning_max_connections'] frontend_tuning_timeout_client = module.params[ 'frontend_tuning_timeout_client'] frontend_tuning_timeout_http_req = module.params[ 'frontend_tuning_timeout_http_req'] frontend_tuning_timeout_http_keep_alive = module.params[ 'frontend_tuning_timeout_http_keep_alive'] frontend_linked_cpu_affinity_rules = module.params[ 'frontend_linked_cpu_affinity_rules'] frontend_logging_dont_log_null = module.params[ 'frontend_logging_dont_log_null'] frontend_logging_dont_log_normal = module.params[ 'frontend_logging_dont_log_normal'] frontend_logging_log_separate_errors = module.params[ 'frontend_logging_log_separate_errors'] frontend_logging_detailed_log = module.params[ 'frontend_logging_detailed_log'] frontend_logging_socket_stats = module.params[ 'frontend_logging_socket_stats'] frontend_stickiness_pattern = module.params['frontend_stickiness_pattern'] frontend_stickiness_data_types = module.params[ 'frontend_stickiness_data_types'] frontend_stickiness_expire = module.params['frontend_stickiness_expire'] frontend_stickiness_size = module.params['frontend_stickiness_size'] frontend_stickiness_counter = module.params['frontend_stickiness_counter'] frontend_stickiness_counter_key = module.params[ 'frontend_stickiness_counter_key'] frontend_stickiness_length = module.params['frontend_stickiness_length'] frontend_stickiness_conn_rate_period = module.params[ 'frontend_stickiness_conn_rate_period'] frontend_stickiness_sess_rate_period = module.params[ 'frontend_stickiness_sess_rate_period'] frontend_stickiness_http_req_rate_period = module.params[ 'frontend_stickiness_http_req_rate_period'] frontend_stickiness_http_err_rate_period = module.params[ 'frontend_stickiness_http_err_rate_period'] frontend_stickiness_bytes_in_rate_period = module.params[ 'frontend_stickiness_bytes_in_rate_period'] frontend_stickiness_bytes_out_rate_period = module.params[ 'frontend_stickiness_bytes_out_rate_period'] frontend_forward_for = module.params['frontend_forward_for'] frontend_connection_behaviour = module.params[ 'frontend_connection_behaviour'] frontend_custom_options = module.params['frontend_custom_options'] frontend_linked_actions = module.params['frontend_linked_actions'] frontend_linked_errorfiles = module.params['frontend_linked_errorfiles'] # Instantiate API connection api_url = module.params['api_url'] api_auth = (module.params['api_key'], module.params['api_secret']) api_ssl_verify = module.params['api_ssl_verify'] apiconnection = OpnsenseApi.Haproxy(api_url, api_auth, api_ssl_verify) # Fetch list of frontends frontends = apiconnection.listObjects('frontend') # Get an empty default object: # - to determine API version (not yet implemented) # - to retrieve UUIDs for: # - SSL objects (ssl_certificates, ssl_default_certificate, ssl_clientAuthCAs, ssl_clientAuthCRLs) # - defaultBackend # - basicAuthUsers # - basicAuthGroups # - linkedCpuAffinityRules # - linkedActions # - linkedErrorfiles empty_frontend = apiconnection.getObjectByUuid('frontend', '') # Need to get UUIDs for: # defaultBackend, basicAuthUsers, basicAuthGroups, linkedCpuAffinityRules, linkedActions, linkedErrorfiles frontend_default_backend_uuid = '' if frontend_default_backend != 'none': #frontend_default_backend_uuid = apiconnection.getUuidByName('backend', frontend_default_backend) for key, value in empty_frontend['defaultBackend'].iteritems(): if value['value'] == frontend_default_backend: frontend_default_backend_uuid = key #frontend_basic_auth_users_uuids = apiconnection.getUuidsFromNames('user', frontend_basic_auth_users) frontend_basic_auth_users_uuids = [] for frontend_basic_auth_user in frontend_basic_auth_users: for key, value in empty_frontend['basicAuthUsers'].iteritems(): if value['value'] == frontend_basic_auth_user: frontend_basic_auth_users_uuids.append(key) #frontend_basic_auth_groups_uuids = apiconnection.getUuidsFromNames('group', frontend_basic_auth_groups) frontend_basic_auth_groups_uuids = [] for frontend_basic_auth_group in frontend_basic_auth_groups: for key, value in empty_frontend['basicAuthGroups'].iteritems(): if value['value'] == frontend_basic_auth_group: frontend_basic_auth_groups_uuids.append(key) #frontend_linked_cpu_affinity_rules_uuids = apiconnection.getUuidsFromNames('cpu', frontend_linked_cpu_affinity_rules) frontend_linked_cpu_affinity_rules_uuids = [] for frontend_linked_cpu_affinity_rule in frontend_linked_cpu_affinity_rules: for key, value in empty_frontend['linkedCpuAffinityRules'].iteritems(): if value['value'] == frontend_linked_cpu_affinity_rule: frontend_linked_cpu_affinity_rules_uuids.append(key) #frontend_linked_actions_uuids = apiconnection.getUuidsFromNames('action', frontend_linked_actions) frontend_linked_actions_uuids = [] for frontend_linked_action in frontend_linked_actions: for key, value in empty_frontend['linkedActions'].iteritems(): if value['value'] == frontend_linked_action: frontend_linked_actions_uuids.append(key) #frontend_linked_errorfiles_uuids = apiconnection.getUuidsFromNames('errorfile', frontend_linked_errorfiles) frontend_linked_errorfiles_uuids = [] for frontend_linked_errorfile in frontend_linked_errorfiles: for key, value in empty_frontend['linkedErrorfiles'].iteritems(): if value['value'] == frontend_linked_errorfile: frontend_linked_errorfiles_uuids.append(key) frontend_ssl_certificates_uuids = apiconnection.getSslObjectKeys( empty_frontend['ssl_certificates'], frontend_ssl_certificates) # Only fetch default SSL cert uuid when one is set, otherwise supply an empty string frontend_ssl_default_certificate_uuid = '' if frontend_ssl_default_certificate != '': frontend_ssl_default_certificate_uuid = apiconnection.getSslObjectKeys( empty_frontend['ssl_default_certificate'], [frontend_ssl_default_certificate])[0] frontend_ssl_client_auth_cas_uuids = apiconnection.getSslObjectKeys( empty_frontend['ssl_clientAuthCAs'], frontend_ssl_client_auth_cas) frontend_ssl_client_auth_crls_uuids = apiconnection.getSslObjectKeys( empty_frontend['ssl_clientAuthCRLs'], frontend_ssl_client_auth_crls) # Build dict with desired state desired_properties = { 'enabled': frontend_enabled, 'description': frontend_description, 'bind': ','.join(frontend_bind), 'bindOptions': frontend_bind_options, 'mode': frontend_mode, 'defaultBackend': frontend_default_backend_uuid, 'ssl_enabled': str(int(frontend_ssl_enabled)), 'ssl_certificates': ','.join(frontend_ssl_certificates_uuids), 'ssl_default_certificate': frontend_ssl_default_certificate_uuid, 'ssl_customOptions': frontend_ssl_custom_options, 'ssl_advancedEnabled': str(int(frontend_ssl_advanced_enabled)), 'ssl_bindOptions': ','.join(frontend_ssl_bind_options), 'ssl_cipherList': frontend_ssl_cipher_list, 'ssl_http2Enabled': str(int(frontend_ssl_http2_enabled)), 'ssl_hstsEnabled': str(int(frontend_ssl_hsts_enabled)), 'ssl_hstsIncludeSubDomains': str(int(frontend_ssl_hsts_include_sub_domains)), 'ssl_hstsPreload': str(int(frontend_ssl_hsts_preload)), 'ssl_hstsMaxAge': frontend_ssl_hsts_max_age, 'ssl_clientAuthEnabled': str(int(frontend_ssl_client_auth_enabled)), 'ssl_clientAuthVerify': frontend_ssl_client_auth_verify, 'ssl_clientAuthCAs': ','.join(frontend_ssl_client_auth_cas_uuids), 'ssl_clientAuthCRLs': ','.join(frontend_ssl_client_auth_crls_uuids), 'basicAuthEnabled': str(int(frontend_basic_auth_enabled)), 'basicAuthUsers': ','.join(frontend_basic_auth_users_uuids), 'basicAuthGroups': ','.join(frontend_basic_auth_groups_uuids), 'tuning_maxConnections': frontend_tuning_max_connections, 'tuning_timeoutClient': frontend_tuning_timeout_client, 'tuning_timeoutHttpReq': frontend_tuning_timeout_http_req, 'tuning_timeoutHttpKeepAlive': frontend_tuning_timeout_http_keep_alive, 'linkedCpuAffinityRules': ','.join(frontend_linked_cpu_affinity_rules_uuids), 'logging_dontLogNull': str(int(frontend_logging_dont_log_null)), 'logging_dontLogNormal': str(int(frontend_logging_dont_log_normal)), 'logging_logSeparateErrors': str(int(frontend_logging_log_separate_errors)), 'logging_detailedLog': str(int(frontend_logging_detailed_log)), 'logging_socketStats': str(int(frontend_logging_socket_stats)), 'stickiness_pattern': frontend_stickiness_pattern, 'stickiness_dataTypes': ','.join(frontend_stickiness_data_types), 'stickiness_expire': frontend_stickiness_expire, 'stickiness_size': frontend_stickiness_size, 'stickiness_counter': str(int(frontend_stickiness_counter)), 'stickiness_counter_key': frontend_stickiness_counter_key, 'stickiness_length': frontend_stickiness_length, 'stickiness_connRatePeriod': frontend_stickiness_conn_rate_period, 'stickiness_sessRatePeriod': frontend_stickiness_sess_rate_period, 'stickiness_httpReqRatePeriod': frontend_stickiness_http_req_rate_period, 'stickiness_httpErrRatePeriod': frontend_stickiness_http_err_rate_period, 'stickiness_bytesInRatePeriod': frontend_stickiness_bytes_in_rate_period, 'stickiness_bytesOutRatePeriod': frontend_stickiness_bytes_out_rate_period, 'forwardFor': str(int(frontend_forward_for)), 'connectionBehaviour': frontend_connection_behaviour, 'customOptions': frontend_custom_options, 'linkedActions': ','.join(frontend_linked_actions_uuids), 'linkedErrorfiles': ','.join(frontend_linked_errorfiles_uuids) } # Prepare dict with properties needing change changed_properties = {} # Prepare result dict result = {} additional_msg = [] # Initialize some control vars needs_change = False uuid = '' # Check if frontend object with specified name exists for frontend in frontends: if frontend['name'] == frontend_name: uuid = frontend['uuid'] break frontend_exists = (uuid != '') if frontend_state == 'present': if frontend_exists: frontend = apiconnection.getObjectByName('frontend', frontend_name) for prop in desired_properties.keys(): # Special cases for complex propertierts: if prop == 'bind': current_binds = apiconnection.getSelectedList( frontend[prop]) if not apiconnection.compareLists(frontend_bind, frontend[prop]): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Property %s must be changed' % prop) elif prop == 'mode': current_mode = apiconnection.getSelected(frontend[prop]) if current_mode != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Property %s must be changed' % prop) elif prop == 'defaultBackend': current_default_backend = apiconnection.getSelected( frontend[prop], retval='value') if current_default_backend != frontend_default_backend: # Check if current default backend is an empty string and we don't want to have one: if current_default_backend == '' and frontend_default_backend == 'none': pass else: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_default_backend, desired_properties[prop])) elif prop == 'ssl_certificates' and frontend_ssl_enabled: current_ssl_certificates = apiconnection.getSelectedList( frontend[prop], retval='key') if not apiconnection.compareLists( current_ssl_certificates, frontend_ssl_certificates_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Property %s must be changed' % prop) elif prop == 'ssl_default_certificate' and frontend_ssl_enabled: current_ssl_default_certificate = apiconnection.getSelected( frontend[prop]) if current_ssl_default_certificate != desired_properties[ prop]: # Check if current default certificate is an empty string and we don't want to have one: #if current_ssl_default_certificate == '' and frontend_ssl_default_certificate == 'none': # pass #else: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_ssl_default_certificate, desired_properties[prop])) elif prop == 'ssl_bindOptions' and frontend_ssl_enabled: current_ssl_bind_options = apiconnection.getSelectedList( frontend[prop]) if not apiconnection.compareLists( current_ssl_bind_options, frontend_ssl_bind_options): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_ssl_bind_options, desired_properties[prop])) # only care about ssl_clientAuthVerify when SSL client auth is enabled elif prop == 'ssl_clientAuthVerify' and frontend_ssl_enabled: if not frontend_ssl_client_auth_enabled: pass else: current_ssl_client_auth_verify = apiconnection.getSelected( frontend[prop]) if current_ssl_client_auth_verify != desired_properties[ prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_ssl_client_auth_verify, desired_properties[prop])) # only care about ssl_clientAuthVerify when SSL client auth is enabled elif prop == 'ssl_clientAuthCAs' and frontend_ssl_enabled: if not frontend_ssl_client_auth_enabled: pass else: current_ssl_client_auth_cas = apiconnection.getSelectedList( frontend[prop]) if not apiconnection.compareLists( current_ssl_client_auth_cas, frontend_ssl_client_auth_cas_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_ssl_client_auth_cas, desired_properties[prop])) # only care about ssl_clientAuthVerify when SSL client auth is enabled elif prop == 'ssl_clientAuthCRLs' and frontend_ssl_enabled: if not frontend_ssl_client_auth_enabled: pass else: current_ssl_client_auth_crls = apiconnection.getSelectedList( frontend[prop]) if not apiconnection.compareLists( current_ssl_client_auth_crls, frontend_ssl_client_auth_crls_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_ssl_client_auth_crls, desired_properties[prop])) elif prop == 'basicAuthUsers': # only care about basicAuthUsers when basic auth is enabled if frontend_basic_auth_enabled: current_basic_auth_users = apiconnection.getSelectedList( frontend[prop]) if not apiconnection.compareLists( current_basic_auth_users, frontend_basic_auth_users): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_basic_auth_users, desired_properties[prop])) elif prop == 'basicAuthGroups': # only care about basicAuthGroups when basic auth is enabled if frontend_basic_auth_enabled: current_basic_auth_groups = apiconnection.getSelectedList( frontend[prop]) if not apiconnection.compareLists( current_basic_auth_groups, frontend_basic_auth_groups): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_basic_auth_groups, desired_properties[prop])) elif prop == 'stickiness_pattern': current_stickiness_pattern = apiconnection.getSelected( frontend[prop]) if current_stickiness_pattern != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_stickiness_pattern, desired_properties[prop])) elif prop == 'stickiness_dataTypes': current_stickiness_data_types = apiconnection.getSelected( frontend[prop]) if not apiconnection.compareLists( current_stickiness_data_types, frontend_stickiness_data_types): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_stickiness_data_types, desired_properties[prop])) pass elif prop == 'connectionBehaviour': current_connection_behaviour = apiconnection.getSelected( frontend[prop]) if current_connection_behaviour != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_connection_behaviour, desired_properties[prop])) elif prop == 'linkedCpuAffinityRules': current_linked_cpu_affinity_rules = apiconnection.getSelectedList( frontend[prop], retval='key') if not apiconnection.compareLists( current_linked_cpu_affinity_rules, frontend_linked_cpu_affinity_rules): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, current_linked_cpu_affinity_rules, desired_properties[prop])) elif prop == 'linkedActions': current_linked_actions = apiconnection.getSelectedList( frontend[prop], retval='key') if not apiconnection.compareLists( current_linked_actions, frontend_linked_actions_uuids, order_sensitive=True): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_linked_actions, desired_properties[prop])) elif prop == 'linkedErrorfiles': current_linked_errorfiles = apiconnection.getSelectedList( frontend[prop], retval='key') if not apiconnection.compareLists( current_linked_errorfiles, frontend_linked_errorfiles_uuids): needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, current_linked_errorfiles, desired_properties[prop])) else: # only care about SSL properties when it should be enabled if 'ssl' in prop and not frontend_ssl_enabled: # SSL enabled must still be evaluated if prop == 'ssl_enabled' and frontend[ prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, frontend[prop], desired_properties[prop])) else: pass elif 'ssl' in prop and frontend_ssl_enabled: # Some properties are only stored when enabling advanced SSL options if not frontend_ssl_advanced_enabled and prop == 'ssl_bindOptions': pass elif not frontend_ssl_advanced_enabled and prop == 'ssl_cipherList': pass elif not frontend_ssl_advanced_enabled and prop == 'ssl_http2Enabled': pass elif not frontend_ssl_advanced_enabled and prop == 'ssl_hstsEnabled': pass elif not frontend_ssl_advanced_enabled and prop == 'ssl_hstsIncludeSubdomains': pass elif not frontend_ssl_advanced_enabled and prop == 'ssl_hstsPreload': pass elif not frontend_ssl_advanced_enabled and prop == 'ssl_hstsMaxAge': pass else: if prop not in frontend: # prop might not be present in current state needs_change = True changed_properties[prop] = desired_properties[ prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, '', desired_properties[prop])) else: if frontend[prop] != desired_properties[prop]: needs_change = True changed_properties[ prop] = desired_properties[prop] additional_msg.append( 'Changing %s: %s => %s' % (prop, frontend[prop], desired_properties[prop])) # catch all other properties else: if frontend[prop] != desired_properties[prop]: needs_change = True changed_properties[prop] = desired_properties[prop] additional_msg.append('Changing %s: %s => %s' % (prop, frontend[prop], desired_properties[prop])) if not needs_change: result = { 'changed': False, 'msg': [ 'Frontend already present: %s' % frontend_name, additional_msg ] } else: if not module.check_mode: # workaround for https://github.com/opnsense/plugins/issues/1494 # any change must include the linkedActions to maintain the correct order changed_properties['linkedActions'] = desired_properties[ 'linkedActions'] additional_msg.append( apiconnection.updateObject('frontend', frontend_name, changed_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Frontend %s must be changed.' % frontend_name, additional_msg ] } else: if not module.check_mode: additional_msg.append( apiconnection.createObject('frontend', frontend_name, desired_properties)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Frontend %s must be created.' % frontend_name, additional_msg ] } else: if frontend_exists: if not module.check_mode: additional_msg.append( apiconnection.deleteObject('frontend', frontend_name)) if haproxy_reload: additional_msg.append(apiconnection.applyConfig()) result = { 'changed': True, 'msg': [ 'Frontend %s must be deleted.' % frontend_name, additional_msg ] } else: result = { 'changed': False, 'msg': ['Frontend %s is not present.' % frontend_name] } module.exit_json(**result)