diff --git a/lib/ansible/modules/network/f5/bigip_user.py b/lib/ansible/modules/network/f5/bigip_user.py index 78bb6a6456e..37f2e9098fb 100644 --- a/lib/ansible/modules/network/f5/bigip_user.py +++ b/lib/ansible/modules/network/f5/bigip_user.py @@ -638,7 +638,7 @@ class UnpartitionedManager(BaseManager): uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format( self.client.provider['server'], self.client.provider['server_port'], - self.want.name + self.want.username_credential ) resp = self.client.api.get(uri) try: @@ -651,7 +651,7 @@ class UnpartitionedManager(BaseManager): def create_on_device(self): params = self.changes.api_params() - params['name'] = self.want.name + params['name'] = self.want.username_credential uri = "https://{0}:{1}/mgmt/tm/auth/user/".format( self.client.provider['server'], self.client.provider['server_port'] @@ -674,7 +674,7 @@ class UnpartitionedManager(BaseManager): uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format( self.client.provider['server'], self.client.provider['server_port'], - self.want.name + self.want.username_credential ) resp = self.client.api.patch(uri, json=params) try: @@ -692,7 +692,7 @@ class UnpartitionedManager(BaseManager): uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format( self.client.provider['server'], self.client.provider['server_port'], - self.want.name + self.want.username_credential ) response = self.client.api.delete(uri) if response.status == 200: @@ -703,7 +703,7 @@ class UnpartitionedManager(BaseManager): uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format( self.client.provider['server'], self.client.provider['server_port'], - self.want.name + self.want.username_credential ) resp = self.client.api.get(uri) try: @@ -723,7 +723,7 @@ class PartitionedManager(BaseManager): def exists(self): response = self.list_users_on_device() if 'items' in response: - collection = [x for x in response['items'] if x['name'] == self.want.name] + collection = [x for x in response['items'] if x['name'] == self.want.username_credential] if len(collection) == 1: return True elif len(collection) == 0: @@ -736,7 +736,7 @@ class PartitionedManager(BaseManager): def create_on_device(self): params = self.changes.api_params() - params['name'] = self.want.name + params['name'] = self.want.username_credential params['partition'] = self.want.partition uri = "https://{0}:{1}/mgmt/tm/auth/user/".format( self.client.provider['server'], @@ -747,17 +747,16 @@ class PartitionedManager(BaseManager): response = resp.json() except ValueError as ex: raise F5ModuleError(str(ex)) - - if 'code' in response and response['code'] in [400, 404, 409]: + if 'code' in response and response['code'] in [400, 404, 409, 403]: if 'message' in response: raise F5ModuleError(response['message']) else: raise F5ModuleError(resp.content) - return response['selfLink'] + return True def read_current_from_device(self): response = self.list_users_on_device() - collection = [x for x in response['items'] if x['name'] == self.want.name] + collection = [x for x in response['items'] if x['name'] == self.want.username_credential] if len(collection) == 1: user = collection.pop() return ApiParameters(params=user) @@ -775,7 +774,7 @@ class PartitionedManager(BaseManager): uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format( self.client.provider['server'], self.client.provider['server_port'], - self.want.name + self.want.username_credential ) resp = self.client.api.patch(uri, json=params) try: @@ -783,7 +782,7 @@ class PartitionedManager(BaseManager): except ValueError as ex: raise F5ModuleError(str(ex)) - if 'code' in response and response['code'] in [400, 404, 409]: + if 'code' in response and response['code'] in [400, 404, 409, 403]: if 'message' in response: if 'updated successfully' not in response['message']: raise F5ModuleError(response['message']) @@ -794,7 +793,7 @@ class PartitionedManager(BaseManager): uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format( self.client.provider['server'], self.client.provider['server_port'], - self.want.name + self.want.username_credential ) response = self.client.api.delete(uri) if response.status == 200: diff --git a/lib/ansible/modules/network/f5/bigip_virtual_server.py b/lib/ansible/modules/network/f5/bigip_virtual_server.py index 59711ecf82f..2876bf4c795 100644 --- a/lib/ansible/modules/network/f5/bigip_virtual_server.py +++ b/lib/ansible/modules/network/f5/bigip_virtual_server.py @@ -892,6 +892,7 @@ try: from library.module_utils.network.f5.common import flatten_boolean from library.module_utils.network.f5.compare import cmp_simple_list from library.module_utils.network.f5.ipaddress import is_valid_ip + from library.module_utils.network.f5.ipaddress import is_valid_ip_interface from library.module_utils.network.f5.ipaddress import ip_interface from library.module_utils.network.f5.ipaddress import validate_ip_v6_address from library.module_utils.network.f5.ipaddress import get_netmask @@ -911,6 +912,7 @@ except ImportError: from ansible.module_utils.network.f5.common import flatten_boolean from ansible.module_utils.network.f5.compare import cmp_simple_list from ansible.module_utils.network.f5.ipaddress import is_valid_ip + from ansible.module_utils.network.f5.ipaddress import is_valid_ip_interface from ansible.module_utils.network.f5.ipaddress import ip_interface from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address from ansible.module_utils.network.f5.ipaddress import get_netmask @@ -1108,10 +1110,7 @@ class Parameters(AnsibleF5Parameters): def _format_port_for_destination(self, ip, port): if validate_ip_v6_address(ip): - if port == 0: - result = '.any' - else: - result = '.{0}'.format(port) + result = '.{0}'.format(port) else: result = ':{0}'.format(port) return result @@ -1158,19 +1157,6 @@ class Parameters(AnsibleF5Parameters): "Specified ip_protocol was neither a number nor in the list of common protocols." ) - @property - def source(self): - if self._values['source'] is None: - return None - try: - addr = ip_interface(u'{0}'.format(self._values['source'])) - result = '{0}/{1}'.format(str(addr.ip), addr.network.prefixlen) - return result - except ValueError: - raise F5ModuleError( - "The source IP address must be specified in CIDR format: address/prefix" - ) - @property def has_message_routing_profiles(self): if self.profiles is None: @@ -1528,6 +1514,18 @@ class ApiParameters(Parameters): ) return result + # match IPv6 wildcard with port without RD + pattern = r'(?P[^.]+).(?P[0-9]+|any)' + matches = re.search(pattern, destination) + if matches: + result = Destination( + ip=matches.group('ip'), + port=matches.group('port'), + route_domain=None, + mask=self.mask + ) + return result + result = Destination(ip=None, port=None, route_domain=None, mask=None) return result @@ -1779,15 +1777,65 @@ class ModuleParameters(Parameters): 'You must specify only one clone pool for each context.' ) + @property + def source(self): + if self._values['source'] is None: + return None + source = self.source_tuple + if is_valid_ip_interface(u'{0}/{1}'.format(source.ip, source.cidr)): + if source.route_domain: + result = '{0}%{1}/{2}'.format(source.ip, source.route_domain, source.cidr) + else: + result = '{0}/{1}'.format(source.ip, source.cidr) + return result + raise F5ModuleError( + "The source IP address must be a valid CIDR format: address/prefix." + ) + + @property + def source_tuple(self): + Source = namedtuple('Source', ['ip', 'route_domain', 'cidr']) + if self._values['source'] is None: + result = Source(ip=None, route_domain=None, cidr=None) + return result + # match source with RD + pattern = r'(?P[^%]+)%(?P[0-9]+)/(?P[0-9]+)' + matches = re.search(pattern, self._values['source']) + if matches: + result = Source( + ip=matches.group('ip'), + route_domain=matches.group('route_domain'), + cidr=matches.group('cidr') + ) + return result + # match source without RD + pattern = r'(?P[^%]+)/(?P[0-9]+)' + matches = re.search(pattern, self._values['source']) + if matches: + result = Source( + ip=matches.group('ip'), + route_domain=None, + cidr=matches.group('cidr') + ) + return result + + result = Source(ip=None, route_domain=None, cidr=None) + return result + @property def destination(self): pattern = r'^[a-zA-Z0-9_.-]+' - addr = self._values['destination'].split("%")[0].split('/')[0] + if len(self._values['destination'].split('/')) > 1: + addr, dud = self._values['destination'].split('/') + if '%' in addr: + addr = addr.split('%')[0] + else: + addr = self._values['destination'].split('%')[0] if not is_valid_ip(addr): matches = re.search(pattern, addr) if not matches: raise F5ModuleError( - "The provided destination is not a valid IP address or a Virtual Address name" + "The provided destination is not a valid IP address or a Virtual Address name." ) result = self._format_destination(addr, self.port, self.route_domain) return result @@ -1796,8 +1844,14 @@ class ModuleParameters(Parameters): def route_domain(self): if self._values['destination'] is None: return None - result = self._values['destination'].split("%") - if len(result) > 1: + result = None + if len(self._values['destination'].split('/')) > 1: + addr, dud = self._values['destination'].split('/') + if '%' in addr: + result = addr.split('%') + else: + result = self._values['destination'].split('%') + if result and len(result) > 1: pattern = r'^[a-zA-Z0-9_.-]+' matches = re.search(pattern, result[0]) if matches and not is_valid_ip(result[0]): @@ -1822,13 +1876,20 @@ class ModuleParameters(Parameters): def mask(self): if self._values['destination'] is None: return None - addr = self._values['destination'].split("%")[0] + if len(self._values['destination'].split('/')) > 1: + addr, cidr = self._values['destination'].split('/') + if '%' in addr: + addr = addr.split('%')[0] + '/' + cidr + else: + addr = self._values['destination'] + else: + addr = self._values['destination'].split('%')[0] if addr in ['0.0.0.0', '0.0.0.0/any', '0.0.0.0/0']: return 'any' if addr in ['::', '::/0', '::/any6']: return 'any6' if self._values['mask'] is None: - if is_valid_ip(addr): + if is_valid_ip_interface(addr): return get_netmask(addr) else: return None @@ -1838,7 +1899,7 @@ class ModuleParameters(Parameters): def port(self): if self._values['port'] is None: return None - if self._values['port'] in ['*', 'any']: + if self._values['port'] in ['*', 'any', '0']: return 0 if self._values['port'] in self.services_map: port = self._values['port'] @@ -1948,15 +2009,6 @@ class ModuleParameters(Parameters): return None elif any(x.lower() for x in self._values['enabled_vlans'] if x.lower() in ['all', '*']): result = [fq_name(self.partition, 'all')] - if result[0].endswith('/all'): - if self._values['__warnings'] is None: - self._values['__warnings'] = [] - self._values['__warnings'].append( - dict( - msg="Usage of the 'ALL' value for 'enabled_vlans' parameter is deprecated. Use '*' instead", - version='2.9' - ) - ) return result results = list(set([fq_name(self.partition, x) for x in self._values['enabled_vlans']])) results.sort() @@ -2436,9 +2488,6 @@ class VirtualServerValidator(object): self.module = module def check_update(self): - # TODO(Remove in Ansible 2.9) - self._override_standard_type_from_profiles() - # Regular checks self._override_port_by_type() self._override_protocol_by_type() @@ -2455,9 +2504,6 @@ class VirtualServerValidator(object): self._verify_stateless_profile() def check_create(self): - # TODO(Remove in Ansible 2.9) - self._override_standard_type_from_profiles() - # Regular checks self._set_default_ip_protocol() self._set_default_profiles() @@ -2528,44 +2574,6 @@ class VirtualServerValidator(object): if self.want.type in ['stateless']: self.want.update({'ip_protocol': 17}) - def _override_standard_type_from_profiles(self): - """Overrides a standard virtual server type given the specified profiles - - For legacy purposes, this module will do some basic overriding of the default - ``type`` parameter to support cases where changing the ``type`` only requires - specifying a different set of profiles. - - Ideally, ``type`` would always be specified, but in the past, this module only - supported an implicit "standard" type. Module users would specify some different - types of profiles and this would change the type...in some circumstances. - - Now that this module supports a ``type`` param, the implicit ``type`` changing - that used to happen is technically deprecated (and will be warned on). Users - should always specify a ``type`` now, or, accept the default standard type. - - Returns: - void - """ - if self.want.type == 'standard': - if self.want.has_fastl4_profiles: - self.want.update({'type': 'performance-l4'}) - self.module.deprecate( - msg="Specifying 'performance-l4' profiles on a 'standard' type is deprecated and will be removed.", - version='2.10' - ) - if self.want.has_fasthttp_profiles: - self.want.update({'type': 'performance-http'}) - self.module.deprecate( - msg="Specifying 'performance-http' profiles on a 'standard' type is deprecated and will be removed.", - version='2.10' - ) - if self.want.has_message_routing_profiles: - self.want.update({'type': 'message-routing'}) - self.module.deprecate( - msg="Specifying 'message-routing' profiles on a 'standard' type is deprecated and will be removed.", - version='2.10' - ) - def _check_source_and_destination_match(self): """Verify that destination and source are of the same IP version @@ -2580,7 +2588,7 @@ class VirtualServerValidator(object): F5ModuleError: Raised when the IP versions of source and destination differ. """ if self.want.source and self.want.destination: - want = ip_interface(u'{0}'.format(self.want.source)) + want = ip_interface(u'{0}/{1}'.format(self.want.source_tuple.ip, self.want.source_tuple.cidr)) have = ip_interface(u'{0}'.format(self.want.destination_tuple.ip)) if want.version != have.version: raise F5ModuleError( @@ -3025,7 +3033,7 @@ class Difference(object): return addr_tuple = [self.want.destination, self.want.port, self.want.route_domain] - if all(x for x in addr_tuple if x is None): + if all(x is None for x in addr_tuple): return None have = self.have.destination_tuple