def add_hostname_cn(self): """Add a request for the hostname of the machine""" ip = local_address(unit_get_fallback='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 create_ip_cert_links(ssl_dir, custom_hostname_link=None, bindings=None): """Create symlinks for SAN records :param ssl_dir: str Directory to create symlinks in :param custom_hostname_link: str Additional link to be created :param bindings: List of bindings to check in addition to default api bindings. :type bindings: list of strings """ 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() # This includes the hostname cert and any specific bindng certs: # admin, internal, public req = get_certificate_request(json_encode=False, bindings=bindings)["cert_requests"] # Specific certs for cert_req in req.keys(): requested_cert = os.path.join( ssl_dir, 'cert_{}'.format(cert_req)) requested_key = os.path.join( ssl_dir, 'key_{}'.format(cert_req)) for addr in req[cert_req]['sans']: cert = os.path.join(ssl_dir, 'cert_{}'.format(addr)) key = os.path.join(ssl_dir, 'key_{}'.format(addr)) if os.path.isfile(requested_cert) and not os.path.isfile(cert): os.symlink(requested_cert, cert) os.symlink(requested_key, key) # Handle custom hostnames hostname = get_hostname(local_address(unit_get_fallback='private-address')) hostname_cert = os.path.join( ssl_dir, 'cert_{}'.format(hostname)) hostname_key = os.path.join( ssl_dir, 'key_{}'.format(hostname)) if custom_hostname_link: custom_cert = os.path.join( ssl_dir, 'cert_{}'.format(custom_hostname_link)) custom_key = os.path.join( ssl_dir, 'key_{}'.format(custom_hostname_link)) if os.path.isfile(hostname_cert) and not os.path.isfile(custom_cert): os.symlink(hostname_cert, custom_cert) os.symlink(hostname_key, custom_key)
def get_local_addresses(self): """Return list of local addresses on each configured network For each network return an address the local unit has on that network if one exists. :returns: [private_addr, admin_addr, public_addr, ...] :rtype: List[str] """ addresses = [ os_utils.get_host_ip(ch_os_ip.local_address( unit_get_fallback='private-address'))] for addr_type in os_ip.ADDRESS_MAP.keys(): laddr = os_ip.resolve_address(endpoint_type=addr_type) if laddr: addresses.append(laddr) return sorted(list(set(addresses)))
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 has vip(s) configured and has net splits defined, return vip on correct network. If vip configured with no nets defined, return primary vip. If no vip is configured, 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 = hookenv.config('vip') if vips: vips = vips.split() net_type = ADDRESS_MAP[endpoint_type]['config'] net_addr = hookenv.config(net_type) net_fallback = ADDRESS_MAP[endpoint_type]['fallback'] binding = ADDRESS_MAP[endpoint_type]['binding'] if vips: if net_addr: for vip in vips: if net_ip.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 net_ip.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 hookenv.config('prefer-ipv6'): fallback_addr = net_ip.get_ipv6_addr(exc_list=vips)[0] else: fallback_addr = ch_os_ip.local_address( unit_get_fallback=net_fallback) if net_addr: resolved_address = net_ip.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={})".format(net_type)) return resolved_address