def configure_link(bgp_info, remote_addr): CONF_ROUTER_BGP = ['conf t', 'router bgp {}'.format(quagga.get_asn())] EXIT_ROUTER_BGP_WRITE = ['exit', 'exit', 'write'] vtysh_cmd = copy.deepcopy(CONF_ROUTER_BGP) ch_core.hookenv.log('DEBUG: configure neighbour {} ' 'remote-as {}' ''.format(remote_addr, bgp_info['asn'])) vtysh_cmd += [ 'neighbor {} remote-as {}' ''.format(remote_addr, bgp_info['asn']) ] if bgp_info['passive']: vtysh_cmd += ['neighbor {} passive' ''.format(remote_addr)] if ch_net_ip.is_ipv6(remote_addr): vtysh_cmd += [ 'no neighbor {} activate'.format(remote_addr), 'address-family ipv6', # workaround for quagga redistribute connected # not working as expected for IPv6 'network {}'.format(ch_net_ip.resolve_network_cidr(remote_addr)), 'neighbor {} activate'.format(remote_addr), 'exit', ] # Exit and write vtysh_cmd += EXIT_ROUTER_BGP_WRITE # Execute the command quagga.vtysh(vtysh_cmd)
def get_certificate_sans(bindings=None): """Get all possible IP addresses for certificate SANs. """ _sans = [unit_get('private-address')] if bindings: # Add default API bindings to bindings list bindings = set(bindings + get_default_api_bindings()) else: # Use default API bindings bindings = get_default_api_bindings() for binding in bindings: # Check for config override try: net_config = config(ADDRESS_MAP[binding]['config']) except KeyError: # There is no configuration network for this binding name net_config = None # Using resolve_address is likely redundant. Keeping it here in # case there is an edge case it handles. net_addr = resolve_address(endpoint_type=binding) ip = get_relation_ip(binding, cidr_network=net_config) _sans = _sans + [net_addr, ip] vip = get_vip_in_network(resolve_network_cidr(ip)) if vip: _sans.append(vip) return set(_sans)
def get_certificate_request(json_encode=True): """Generate a certificatee requests based on the network confioguration """ req = CertRequest(json_encode=json_encode) req.add_hostname_cn() # Add os-hostname entries for net_type in [INTERNAL, ADMIN, PUBLIC]: net_config = config(ADDRESS_MAP[net_type]['override']) try: net_addr = resolve_address(endpoint_type=net_type) ip = network_get_primary_address(ADDRESS_MAP[net_type]['binding']) addresses = [net_addr, ip] vip = get_vip_in_network(resolve_network_cidr(ip)) if vip: addresses.append(vip) if net_config: req.add_entry(net_type, net_config, addresses) else: # There is network address with no corresponding hostname. # Add the ip to the hostname cert to allow for this. req.add_hostname_cn_ip(addresses) except NoNetworkBinding: log( "Skipping request for certificate for ip in {} space, no " "local address found".format(net_type), WARNING) return req.get_request()
def get_certificate_request(json_encode=True): """Generate a certificatee requests based on the network confioguration """ req = CertRequest(json_encode=json_encode) req.add_hostname_cn() # Add os-hostname entries for net_type in [INTERNAL, ADMIN, PUBLIC]: net_config = config(ADDRESS_MAP[net_type]['override']) try: net_addr = resolve_address(endpoint_type=net_type) ip = network_get_primary_address( ADDRESS_MAP[net_type]['binding']) addresses = [net_addr, ip] vip = get_vip_in_network(resolve_network_cidr(ip)) if vip: addresses.append(vip) if net_config: req.add_entry( net_type, net_config, addresses) else: # There is network address with no corresponding hostname. # Add the ip to the hostname cert to allow for this. req.add_hostname_cn_ip(addresses) except NoNetworkBinding: log("Skipping request for certificate for ip in {} space, no " "local address found".format(net_type), WARNING) return req.get_request()
def get_db_host(client_hostname, interface='shared-db'): """Get address of local database host. If an access-network has been configured, expect selected address to be on that network. If none can be found, revert to primary address. If network spaces are supported (Juju >= 2.0), use network-get to retrieve the network binding for the interface. If vip(s) are configured, chooses first available. """ vips = config('vip').split() if config('vip') else [] dns_ha = config('dns-ha') access_network = config('access-network') client_ip = get_host_ip(client_hostname) if is_clustered() and dns_ha: log("Using DNS HA hostname: {}".format(config('os-access-hostname'))) return config('os-access-hostname') elif access_network: if is_address_in_network(access_network, client_ip): if is_clustered(): for vip in vips: if is_address_in_network(access_network, vip): return vip log("Unable to identify a VIP in the access-network '%s'" % (access_network), level=WARNING) else: return get_address_in_network(access_network) else: log("Client address '%s' not in access-network '%s'" % (client_ip, access_network), level=WARNING) else: try: # NOTE(jamespage) # Try to use network spaces to resolve binding for # interface, and to resolve the VIP associated with # the binding if provided. interface_binding = network_get_primary_address(interface) if is_clustered() and vips: interface_cidr = resolve_network_cidr(interface_binding) for vip in vips: if is_address_in_network(interface_cidr, vip): return vip return interface_binding except NotImplementedError: # NOTE(jamespage): skip - fallback to previous behaviour pass if is_clustered() and vips: return vips[0] # NOTE on private network if config('prefer-ipv6'): return get_ipv6_addr(exc_list=vips)[0] return unit_get('private-address')
def add_hostname_cn(self): """Add a request for the hostname of the machine""" ip = unit_get('private-address') addresses = [ip] # If a vip is being used without os-hostname config or # network spaces then we need to ensure the local units # cert has the approriate vip in the SAN list vip = get_vip_in_network(resolve_network_cidr(ip)) if vip: addresses.append(vip) self.hostname_entry = {'cn': get_hostname(ip), 'addresses': addresses}
def get_certificate_request(json_encode=True, bindings=None): """Generate a certificate requests based on the network configuration :param json_encode: Encode request in JSON or not. Used for setting directly on a relation. :type json_encode: boolean :param bindings: List of bindings to check in addition to default api bindings. :type bindings: list of strings :returns: CertRequest request as dictionary or JSON string. :rtype: Union[dict, json] """ if bindings: # Add default API bindings to bindings list bindings = set(bindings + get_default_api_bindings()) else: # Use default API bindings bindings = get_default_api_bindings() req = CertRequest(json_encode=json_encode) req.add_hostname_cn() # Add os-hostname entries _sans = get_certificate_sans() # Handle specific hostnames per binding for binding in bindings: hostname_override = config(ADDRESS_MAP[binding]['override']) try: net_addr = resolve_address(endpoint_type=binding) ip = network_get_primary_address(ADDRESS_MAP[binding]['binding']) addresses = [net_addr, ip] vip = get_vip_in_network(resolve_network_cidr(ip)) if vip: addresses.append(vip) # Add hostname certificate request if hostname_override: req.add_entry(binding, hostname_override, addresses) # Remove hostname specific addresses from _sans for addr in addresses: try: _sans.remove(addr) except (ValueError, KeyError): pass except NoNetworkBinding: log( "Skipping request for certificate for ip in {} space, no " "local address found".format(binding), WARNING) # Gurantee all SANs are covered # These are network addresses with no corresponding hostname. # Add the ips to the hostname cert to allow for this. req.add_hostname_cn_ip(_sans) return req.get_request()
def get_db_host(client_hostname, interface='shared-db'): """Get address of local database host. If an access-network has been configured, expect selected address to be on that network. If none can be found, revert to primary address. If network spaces are supported (Juju >= 2.0), use network-get to retrieve the network binding for the interface. If vip(s) are configured, chooses first available. """ vips = config('vip').split() if config('vip') else [] access_network = config('access-network') client_ip = get_host_ip(client_hostname) if access_network: if is_address_in_network(access_network, client_ip): if is_clustered(): for vip in vips: if is_address_in_network(access_network, vip): return vip log("Unable to identify a VIP in the access-network '%s'" % (access_network), level=WARNING) else: return get_address_in_network(access_network) else: log("Client address '%s' not in access-network '%s'" % (client_ip, access_network), level=WARNING) else: try: # NOTE(jamespage) # Try to use network spaces to resolve binding for # interface, and to resolve the VIP associated with # the binding if provided. interface_binding = network_get_primary_address(interface) if is_clustered() and vips: interface_cidr = resolve_network_cidr(interface_binding) for vip in vips: if is_address_in_network(interface_cidr, vip): return vip return interface_binding except NotImplementedError: # NOTE(jamespage): skip - fallback to previous behaviour pass if is_clustered() and vips: return vips[0] # NOTE on private network if config('prefer-ipv6'): return get_ipv6_addr(exc_list=vips)[0] return unit_get('private-address')
def cluster_network(self): """Get CIDR for the Ceph cluster network. The cluster network address advertiesed on the relation is mapped to the corrensponding local interface from which we get the netmask/cidr of the network. :returns: CIDR or None :rtype: Option[str, None] """ cluster_addr = self.all_joined_units.received['ceph-cluster-address'] if cluster_addr: return ch_ip.resolve_network_cidr(cluster_addr)
def add_hostname_cn(self): """Add a request for the hostname of the machine""" ip = unit_get('private-address') addresses = [ip] # If a vip is being used without os-hostname config or # network spaces then we need to ensure the local units # cert has the approriate vip in the SAN list vip = get_vip_in_network(resolve_network_cidr(ip)) if vip: addresses.append(vip) self.hostname_entry = { 'cn': get_hostname(ip), 'addresses': addresses}
def access_ip(self): vips = config().get('vip') if vips: vips = vips.split() clustered = is_clustered() net_addr = ch_net_ip.get_relation_ip('tenant-storage') bound_cidr = ch_net_ip.resolve_network_cidr( ch_net_ip.network_get_primary_address('tenant-storage')) if clustered and vips: for vip in vips: if ch_net_ip.is_address_in_network(bound_cidr, vip): return vip return net_addr
def get_vip(binding=None): vip = hookenv.config('vip') if not vip: return None vips = vip.split() if len(vips) == 1: return vips[0] if not binding: binding = 'access' bound_cidr = resolve_network_cidr(binding_address(binding)) for vip in vips: if is_address_in_network(bound_cidr, vip): return vip return None
def cluster_network(self): """Get CIDR for the Ceph cluster network. The cluster network address advertiesed on the relation is mapped to the corrensponding local interface from which we get the netmask/cidr of the network. :returns: CIDR or None :rtype: Option[str, None] """ cluster_addr = self.all_joined_units.received['ceph-cluster-address'] if cluster_addr: try: return ch_ip.resolve_network_cidr(cluster_addr) except AddrFormatError: # LP#1898299 in some cases the netmask will be None, which # leads to an AddrFormatError. In this case, we should return # None return None
def publish_url(self, vault_url, remote_binding=None): """ Publish URL for Vault to all Relations :param vault_url: api url used by remote client to speak to vault. :param remote_binding: if provided, remote units not using this binding will be ignored. """ for relation in self.relations: if remote_binding: units = relation.units if units: addr = units[0].received['ingress-address'] or \ units[0].received['access_address'] bound_cidr = resolve_network_cidr( network_get_primary_address(remote_binding)) if not (addr and is_address_in_network(bound_cidr, addr)): continue relation.to_publish['vault_url'] = vault_url
def get_certificate_sans(bindings=None): """Get all possible IP addresses for certificate SANs. :param bindings: List of bindings to check in addition to default api bindings. :type bindings: list of strings :returns: List of binding string names :rtype: List[str] """ _sans = [local_address(unit_get_fallback='private-address')] if bindings: # Add default API bindings to bindings list bindings = list(bindings + get_default_api_bindings()) else: # Use default API bindings bindings = get_default_api_bindings() for binding in bindings: # Check for config override try: net_config = config(ADDRESS_MAP[binding]['config']) except KeyError: # There is no configuration network for this binding name net_config = None # Using resolve_address is likely redundant. Keeping it here in # case there is an edge case it handles. try: net_addr = resolve_address(endpoint_type=binding) except KeyError: net_addr = None ip = get_relation_ip(binding, cidr_network=net_config) _sans = _sans + [net_addr, ip] vip = get_vip_in_network(resolve_network_cidr(ip)) if vip: _sans.append(vip) # Clear any Nones and duplicates return list(set([i for i in _sans if i]))
def resolve_address(endpoint_type=PUBLIC, override=True): """Return unit address depending on net config. If unit is clustered with vip(s) and has net splits defined, return vip on correct network. If clustered with no nets defined, return primary vip. If not clustered, return unit address ensuring address is on configured net split if one is configured, or a Juju 2.0 extra-binding has been used. :param endpoint_type: Network endpoing type :param override: Accept hostname overrides or not """ resolved_address = None if override: resolved_address = _get_address_override(endpoint_type) if resolved_address: return resolved_address vips = config('vip') if vips: vips = vips.split() net_type = ADDRESS_MAP[endpoint_type]['config'] net_addr = config(net_type) net_fallback = ADDRESS_MAP[endpoint_type]['fallback'] binding = ADDRESS_MAP[endpoint_type]['binding'] clustered = is_clustered() if clustered and vips: if net_addr: for vip in vips: if is_address_in_network(net_addr, vip): resolved_address = vip break else: # NOTE: endeavour to check vips against network space # bindings try: bound_cidr = resolve_network_cidr( network_get_primary_address(binding) ) for vip in vips: if is_address_in_network(bound_cidr, vip): resolved_address = vip break except NotImplementedError: # If no net-splits configured and no support for extra # bindings/network spaces so we expect a single vip resolved_address = vips[0] else: if config('prefer-ipv6'): fallback_addr = get_ipv6_addr(exc_list=vips)[0] else: fallback_addr = unit_get(net_fallback) if net_addr: resolved_address = get_address_in_network(net_addr, fallback_addr) else: # NOTE: only try to use extra bindings if legacy network # configuration is not in use try: resolved_address = network_get_primary_address(binding) except NotImplementedError: resolved_address = fallback_addr if resolved_address is None: raise ValueError("Unable to resolve a suitable IP address based on " "charm state and configuration. (net_type=%s, " "clustered=%s)" % (net_type, clustered)) return resolved_address
def get_db_host(client_hostname, interface='shared-db'): """Get address of local database host for use by db clients If an access-network has been configured, expect selected address to be on that network. If none can be found, revert to primary address. If network spaces are supported (Juju >= 2.0), use network-get to retrieve the network binding for the interface. If DNSHA is set pass os-access-hostname If vip(s) are configured, chooses first available. @param client_hostname: hostname of client side relation setting hostname. Only used if access-network is configured @param interface: Network space binding to check. Usually the relationship name. @returns IP for use with db clients """ vips = config('vip').split() if config('vip') else [] dns_ha = config('dns-ha') access_network = config('access-network') if is_clustered() and dns_ha: log("Using DNS HA hostname: {}".format(config('os-access-hostname'))) return config('os-access-hostname') elif access_network: client_ip = resolve_hostname_to_ip(client_hostname) if is_address_in_network(access_network, client_ip): if is_clustered(): for vip in vips: if is_address_in_network(access_network, vip): return vip log("Unable to identify a VIP in the access-network '%s'" % (access_network), level=WARNING) else: return get_address_in_network(access_network) else: log("Client address '%s' not in access-network '%s'" % (client_ip, access_network), level=WARNING) else: try: # NOTE(jamespage) # Try to use network spaces to resolve binding for # interface, and to resolve the VIP associated with # the binding if provided. interface_binding = network_get_primary_address(interface) if is_clustered() and vips: interface_cidr = resolve_network_cidr(interface_binding) for vip in vips: if is_address_in_network(interface_cidr, vip): return vip return interface_binding except NotImplementedError: # NOTE(jamespage): skip - fallback to previous behaviour pass if is_clustered() and vips: return vips[0] # NOTE on private network if config('prefer-ipv6'): return get_ipv6_addr(exc_list=vips)[0] # Last resort return unit_get('private-address')