def swift_storage_relation_joined(rid=None): if config('encrypt') and not vaultlocker.vault_relation_complete(): log('Encryption configured and vault not ready, deferring', level=DEBUG) return rel_settings = { 'zone': config('zone'), 'object_port': config('object-server-port'), 'container_port': config('container-server-port'), 'account_port': config('account-server-port'), } if enable_replication(): replication_ip = network_get_primary_address('replication') cluster_ip = network_get_primary_address('cluster') rel_settings.update({ 'ip_rep': replication_ip, 'ip_cls': cluster_ip, 'region': config('storage-region'), 'object_port_rep': config('object-server-port-rep'), 'container_port_rep': config('container-server-port-rep'), 'account_port_rep': config('account-server-port-rep')}) db = kv() devs = db.get('prepared-devices', []) devs = [os.path.basename(d) for d in devs] rel_settings['device'] = ':'.join(devs) # Keep a reference of devices we are adding to the ring remember_devices(devs) rel_settings['private-address'] = get_relation_ip('swift-storage') relation_set(relation_id=rid, relation_settings=rel_settings)
def _network_get_primary_address(binding): """Wrapper for hookenv.network_get_primary_address hookenv.network_get_primary_address may return a string or bytes depending on the version of python (Bug #1595418). When fix has landed in pypi wrapper may be discarded""" try: address = hookenv.network_get_primary_address(binding).decode('utf-8') except AttributeError: address = hookenv.network_get_primary_address(binding) return address
def get_relation_ip(interface, cidr_network=None): """Return this unit's IP for the given interface. Allow for an arbitrary interface to use with network-get to select an IP. Handle all address selection options including passed cidr network and IPv6. Usage: get_relation_ip('amqp', cidr_network='10.0.0.0/8') @param interface: string name of the relation. @param cidr_network: string CIDR Network to select an address from. @raises Exception if prefer-ipv6 is configured but IPv6 unsupported. @returns IPv6 or IPv4 address """ # Select the interface address first # For possible use as a fallback bellow with get_address_in_network try: # Get the interface specific IP address = network_get_primary_address(interface) except NotImplementedError: # If network-get is not available address = get_host_ip(unit_get('private-address')) if config('prefer-ipv6'): # Currently IPv6 has priority, eventually we want IPv6 to just be # another network space. assert_charm_supports_ipv6() return get_ipv6_addr()[0] elif cidr_network: # If a specific CIDR network is passed get the address from that # network. return get_address_in_network(cidr_network, address) # Return the interface address return address
def get_relation_ip(interface, config_override=None): """Return this unit's IP for the given relation. Allow for an arbitrary interface to use with network-get to select an IP. Handle all address selection options including configuration parameter override and IPv6. Usage: get_relation_ip('amqp', config_override='access-network') @param interface: string name of the relation. @param config_override: string name of the config option for network override. Supports legacy network override configuration parameters. @raises Exception if prefer-ipv6 is configured but IPv6 unsupported. @returns IPv6 or IPv4 address """ fallback = get_host_ip(unit_get('private-address')) if config('prefer-ipv6'): assert_charm_supports_ipv6() return get_ipv6_addr()[0] elif config_override and config(config_override): return get_address_in_network(config(config_override), fallback) else: try: return network_get_primary_address(interface) except NotImplementedError: return fallback
def get_unit_ip(config_override=AMQP_OVERRIDE_CONFIG, interface=AMQP_INTERFACE): """Return this unit's IP. Future proof to allow for network spaces or other more complex addresss selection. @param config_override: string name of the config option for network override. Default to amqp-network @param interface: string name of the relation. Default to amqp. @raises Exception if prefer-ipv6 is configured but IPv6 unsupported. @returns IPv6 or IPv4 address """ fallback = get_host_ip(unit_get('private-address')) if config('prefer-ipv6'): assert_charm_supports_ipv6() return get_ipv6_addr()[0] elif config(config_override): # NOTE(jamespage) # override private-address settings if access-network is # configured and an appropriate network interface is # configured. return get_address_in_network(config(config_override), fallback) else: # NOTE(jamespage) # Try using network spaces if access-network is not # configured, fallback to private address if not # supported try: return network_get_primary_address(interface) except NotImplementedError: return fallback
def cluster_joined(): relation_settings = {} if config('prefer-ipv6'): addr = get_ipv6_addr(exc_list=[config('vip')])[0] relation_settings = { 'private-address': addr, 'hostname': socket.gethostname() } cluster_network = config('cluster-network') if cluster_network: cluster_addr = get_address_in_network(cluster_network, fatal=True) relation_settings['cluster-address'] = cluster_addr else: try: cluster_addr = network_get_primary_address('cluster') relation_settings['cluster-address'] = cluster_addr except NotImplementedError: # NOTE(jamespage): skip - fallback to previous behaviour pass log("Setting cluster relation: '%s'" % (relation_settings), level=INFO) relation_set(relation_settings=relation_settings) # Ensure all new peers are aware cluster_state_uuid = relation_get('bootstrap-uuid', unit=local_unit()) if cluster_state_uuid: notify_bootstrapped(cluster_rid=relation_id(), cluster_uuid=cluster_state_uuid)
def configure(self, database, username, hostname=None, prefix=None): """ Called by charm layer that uses this interface to configure a database. """ if not hostname: conversation = self.conversation() try: hostname = hookenv.network_get_primary_address( conversation.relation_name ) except NotImplementedError: hostname = hookenv.unit_private_ip() if prefix: relation_info = { prefix + '_database': database, prefix + '_username': username, prefix + '_hostname': hostname, } self.set_prefix(prefix) else: relation_info = { 'database': database, 'username': username, 'hostname': hostname, } self.set_remote(**relation_info) self.set_local(**relation_info)
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 cluster_connected(hacluster): """Configure HA resources in corosync""" dns_record = config('dns-ha-access-record') vips = config('vip') or None if vips and dns_record: set_flag('config.dns_vip.invalid') log("Unsupported configuration. vip and dns-ha cannot both be set", level=ERROR) return else: clear_flag('config.dns_vip.invalid') if vips: vips = vips.split() for vip in vips: if vip == vault.get_vip(binding='external'): hacluster.add_vip('vault-ext', vip) else: hacluster.add_vip('vault', vip) elif dns_record: try: ip = network_get_primary_address('access') except NotImplementedError: ip = unit_private_ip() hacluster.add_dnsha('vault', ip, dns_record, 'access') hacluster.bind_resources()
def endpoint_address(self): """ Determine the local endpoint network address """ try: return hookenv.network_get_primary_address( self.expand_name('{endpoint_name}')) except NotImplementedError: return hookenv.unit_private_ip()
def get_database_setup(self): """Provide the default database credentials as a list of 3-tuples returns a structure of: [ {'database': <database>, 'username': <username>, 'hostname': <hostname of this unit> 'prefix': <the optional prefix for the database>, }, ] :returns [{'database': ...}, ...]: credentials for multiple databases """ host = None try: host = hookenv.network_get_primary_address('shared-db') except NotImplementedError: host = hookenv.unit_get('private-address') return [ dict( database=self.config['database'], username=self.config['database-user'], hostname=host, ) ]
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_local_ingress_address(binding): """Get ingress IP address for a binding. binding - e.g. 'monitors' """ # using network-get to retrieve the address details if available. hookenv.log("Getting ingress IP address for binding %s" % binding) try: network_info = hookenv.network_get(binding) if network_info is not None and "ingress-addresses" in network_info: hookenv.log("Using ingress-addresses") ip_address = network_info["ingress-addresses"][0] hookenv.log(ip_address) return ip_address except (NotImplementedError, FileNotFoundError): # We'll fallthrough to the Pre 2.3 code below. pass # Pre 2.3 output try: ip_address = hookenv.network_get_primary_address(binding) hookenv.log("Using primary-addresses") except NotImplementedError: # pre Juju 2.0 ip_address = hookenv.unit_private_ip() hookenv.log("Using unit_private_ip") hookenv.log(ip_address) return ip_address
def __call__(self): api_settings = super(NeutronGatewayContext, self).__call__() ctxt = { 'shared_secret': get_shared_secret(), 'core_plugin': core_plugin(), 'plugin': config('plugin'), 'debug': config('debug'), 'verbose': config('verbose'), 'instance_mtu': config('instance-mtu'), 'l2_population': api_settings['l2_population'], 'enable_dvr': api_settings['enable_dvr'], 'enable_l3ha': api_settings['enable_l3ha'], 'overlay_network_type': api_settings['overlay_network_type'], 'enable_metadata_network': config('enable-metadata-network'), 'enable_isolated_metadata': config('enable-isolated-metadata'), } fallback = get_host_ip(unit_get('private-address')) if config('os-data-network'): # NOTE: prefer any existing use of config based networking ctxt['local_ip'] = \ get_address_in_network(config('os-data-network'), fallback) else: # NOTE: test out network-spaces support, then fallback try: ctxt['local_ip'] = get_host_ip( network_get_primary_address('data')) except NotImplementedError: ctxt['local_ip'] = fallback mappings = config('bridge-mappings') if mappings: ctxt['bridge_mappings'] = ','.join(mappings.split()) flat_providers = config('flat-network-providers') if flat_providers: ctxt['network_providers'] = ','.join(flat_providers.split()) vlan_ranges = config('vlan-ranges') if vlan_ranges: ctxt['vlan_ranges'] = ','.join(vlan_ranges.split()) dnsmasq_flags = config('dnsmasq-flags') if dnsmasq_flags: ctxt['dnsmasq_flags'] = config_flags_parser(dnsmasq_flags) net_dev_mtu = api_settings['network_device_mtu'] if net_dev_mtu: ctxt['network_device_mtu'] = net_dev_mtu ctxt['veth_mtu'] = net_dev_mtu # Override user supplied config for these plugins as these settings are # mandatory if ctxt['plugin'] in ['nvp', 'nsx', 'n1kv']: ctxt['enable_metadata_network'] = True ctxt['enable_isolated_metadata'] = True return ctxt
def ovs_ctxt(self): # In addition to generating config context, ensure the OVS service # is running and the OVS bridge exists. Also need to ensure # local_ip points to actual IP, not hostname. ovs_ctxt = super(OVSPluginContext, self).ovs_ctxt() if not ovs_ctxt: return {} conf = config() fallback = get_host_ip(unit_get('private-address')) if config('os-data-network'): # NOTE: prefer any existing use of config based networking ovs_ctxt['local_ip'] = \ get_address_in_network(config('os-data-network'), fallback) else: # NOTE: test out network-spaces support, then fallback try: ovs_ctxt['local_ip'] = get_host_ip( network_get_primary_address('data') ) except NotImplementedError: ovs_ctxt['local_ip'] = fallback neutron_api_settings = NeutronAPIContext()() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] ovs_ctxt['distributed_routing'] = neutron_api_settings['enable_dvr'] ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] # TODO: We need to sort out the syslog and debug/verbose options as a # general context helper ovs_ctxt['use_syslog'] = conf['use-syslog'] ovs_ctxt['verbose'] = conf['verbose'] ovs_ctxt['debug'] = conf['debug'] ovs_ctxt['prevent_arp_spoofing'] = conf['prevent-arp-spoofing'] ovs_ctxt['enable_dpdk'] = conf['enable-dpdk'] net_dev_mtu = neutron_api_settings.get('network_device_mtu') if net_dev_mtu: # neutron.conf ovs_ctxt['network_device_mtu'] = net_dev_mtu # ml2 conf ovs_ctxt['veth_mtu'] = net_dev_mtu mappings = config('bridge-mappings') if mappings: ovs_ctxt['bridge_mappings'] = ','.join(mappings.split()) flat_providers = config('flat-network-providers') if flat_providers: ovs_ctxt['network_providers'] = ','.join(flat_providers.split()) vlan_ranges = config('vlan-ranges') if vlan_ranges: ovs_ctxt['vlan_ranges'] = ','.join(vlan_ranges.split()) return ovs_ctxt
def ovs_ctxt(self): # In addition to generating config context, ensure the OVS service # is running and the OVS bridge exists. Also need to ensure # local_ip points to actual IP, not hostname. ovs_ctxt = super(OVSPluginContext, self).ovs_ctxt() if not ovs_ctxt: return {} conf = config() fallback = get_host_ip(unit_get('private-address')) if config('os-data-network'): # NOTE: prefer any existing use of config based networking ovs_ctxt['local_ip'] = \ get_address_in_network(config('os-data-network'), fallback) else: # NOTE: test out network-spaces support, then fallback try: ovs_ctxt['local_ip'] = get_host_ip( network_get_primary_address('data')) except NotImplementedError: ovs_ctxt['local_ip'] = fallback neutron_api_settings = NeutronAPIContext()() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] ovs_ctxt['distributed_routing'] = neutron_api_settings['enable_dvr'] ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] # TODO: We need to sort out the syslog and debug/verbose options as a # general context helper ovs_ctxt['use_syslog'] = conf['use-syslog'] ovs_ctxt['verbose'] = conf['verbose'] ovs_ctxt['debug'] = conf['debug'] ovs_ctxt['prevent_arp_spoofing'] = conf['prevent-arp-spoofing'] ovs_ctxt['enable_dpdk'] = conf['enable-dpdk'] net_dev_mtu = neutron_api_settings.get('network_device_mtu') if net_dev_mtu: # neutron.conf ovs_ctxt['network_device_mtu'] = net_dev_mtu # ml2 conf ovs_ctxt['veth_mtu'] = net_dev_mtu mappings = config('bridge-mappings') if mappings: ovs_ctxt['bridge_mappings'] = ','.join(mappings.split()) flat_providers = config('flat-network-providers') if flat_providers: ovs_ctxt['network_providers'] = ','.join(flat_providers.split()) vlan_ranges = config('vlan-ranges') if vlan_ranges: ovs_ctxt['vlan_ranges'] = ','.join(vlan_ranges.split()) return ovs_ctxt
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 get_public_addr(self): if config('ceph-public-network'): return self.get_network_addrs('ceph-public-network')[0] try: return network_get_primary_address('public') except NotImplementedError: log("network-get not supported", DEBUG) return self.get_host_ip()
def get_cluster_addr(): if config('ceph-cluster-network'): return get_network_addrs('ceph-cluster-network')[0] try: return network_get_primary_address('cluster') except NotImplementedError: log("network-get not supported", DEBUG) return get_host_ip()
def configure_ceph_exporter_relation(target): config = hookenv.config() if data_changed('target.config', config): try: hostname = hookenv.network_get_primary_address('target').decode( "utf-8") except NotImplementedError: hostname = resolve_address(endpoint_type=INTERNAL) target.configure(hostname=hostname, port=config.get('port')) hookenv.status_set('active', 'Ready')
def __call__(self): api_settings = super(NeutronGatewayContext, self).__call__() ctxt = { 'shared_secret': get_shared_secret(), 'core_plugin': core_plugin(), 'plugin': config('plugin'), 'debug': config('debug'), 'verbose': config('verbose'), 'instance_mtu': config('instance-mtu'), 'l2_population': api_settings['l2_population'], 'enable_dvr': api_settings['enable_dvr'], 'enable_l3ha': api_settings['enable_l3ha'], 'overlay_network_type': api_settings['overlay_network_type'], } fallback = get_host_ip(unit_get('private-address')) if config('os-data-network'): # NOTE: prefer any existing use of config based networking ctxt['local_ip'] = \ get_address_in_network(config('os-data-network'), fallback) else: # NOTE: test out network-spaces support, then fallback try: ctxt['local_ip'] = get_host_ip( network_get_primary_address('data') ) except NotImplementedError: ctxt['local_ip'] = fallback mappings = config('bridge-mappings') if mappings: ctxt['bridge_mappings'] = ','.join(mappings.split()) flat_providers = config('flat-network-providers') if flat_providers: ctxt['network_providers'] = ','.join(flat_providers.split()) vlan_ranges = config('vlan-ranges') if vlan_ranges: ctxt['vlan_ranges'] = ','.join(vlan_ranges.split()) dnsmasq_flags = config('dnsmasq-flags') if dnsmasq_flags: ctxt['dnsmasq_flags'] = config_flags_parser(dnsmasq_flags) net_dev_mtu = api_settings['network_device_mtu'] if net_dev_mtu: ctxt['network_device_mtu'] = net_dev_mtu ctxt['veth_mtu'] = net_dev_mtu return ctxt
def get_local_ip(): fallback = get_host_ip(unit_get('private-address')) if config('os-data-network'): # NOTE: prefer any existing use of config based networking local_ip = get_address_in_network(config('os-data-network'), fallback) else: # NOTE: test out network-spaces support, then fallback try: local_ip = get_host_ip(network_get_primary_address('data')) except NotImplementedError: local_ip = fallback return local_ip
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 provide_data(self): try: address = hookenv.network_get_primary_address('monitors') except NotImplementedError: address = hookenv.unit_get('private-address') relation_info = { 'target-id': self.principal_relation.nagios_hostname(), 'monitors': self.get_monitors(), 'private-address': address, 'machine_id': os.environ['JUJU_MACHINE_ID'], } return relation_info
def publish_stonith_info(): """Provide remote hacluster with info for including remote in cluster""" remote_ip = hookenv.network_get_primary_address('pacemaker-remote') remote_hostname = socket.getfqdn() if hookenv.config('enable-stonith'): stonith_hostname = remote_hostname else: stonith_hostname = None remote = reactive.endpoint_from_flag('endpoint.pacemaker-remote.joined') remote.publish_info(remote_hostname=remote_hostname, remote_ip=remote_ip, enable_resources=hookenv.config('enable-resources'), stonith_hostname=stonith_hostname)
def db_joined(relation_id=None): juju_log('**********shared-db-relation-joined') try: # NOTE: try to use network spaces host = network_get_primary_address('shared-db') except NotImplementedError: # NOTE: fallback to private-address host = unit_get('private-address') conf = config() relation_set(database=conf['database'], username=conf['database-user'], hostname=host, relation_id=relation_id)
def slave_joined(interface='slave'): relation_settings = {} cluster_id = get_cluster_id() if not is_clustered(): log("Not clustered yet", level=DEBUG) return if is_leader(): configure_slave() relation_settings = {'slave_address': network_get_primary_address(interface)} relation_settings['cluster_id'] = cluster_id log("Setting slave relation: '{}'".format(relation_settings), level=INFO) for rid in relation_ids(interface): relation_set(relation_id=rid, relation_settings=relation_settings)
def get_local_ip(): fallback = get_host_ip(unit_get('private-address')) if config('os-data-network'): # NOTE: prefer any existing use of config based networking local_ip = get_address_in_network( config('os-data-network'), fallback) else: # NOTE: test out network-spaces support, then fallback try: local_ip = get_host_ip(network_get_primary_address('data')) except NotImplementedError: local_ip = fallback return local_ip
def get_cluster_hosts(): hosts_map = {} if config('cluster-network'): hostname = get_address_in_network(config('cluster-network'), fatal=True) else: try: hostname = network_get_primary_address('cluster') except NotImplementedError: # NOTE(jamespage): skip - fallback to previous behaviour hostname = get_host_ip() # We need to add this localhost dns name to /etc/hosts along with peer # hosts to ensure percona gets consistently resolved addresses. if config('prefer-ipv6'): addr = get_ipv6_addr(exc_list=[config('vip')], fatal=True)[0] hosts_map = {addr: hostname} hosts = [hostname] for relid in relation_ids('cluster'): for unit in related_units(relid): rdata = relation_get(unit=unit, rid=relid) # NOTE(dosaboy): see LP: #1599447 cluster_address = rdata.get('cluster-address', rdata.get('private-address')) if config('prefer-ipv6'): hostname = rdata.get('hostname') if not hostname or hostname in hosts: log("(unit=%s) Ignoring hostname '%s' provided by cluster " "relation for addr %s" % (unit, hostname, cluster_address), level=DEBUG) continue else: log("(unit=%s) hostname '%s' provided by cluster relation " "for addr %s" % (unit, hostname, cluster_address), level=DEBUG) hosts_map[cluster_address] = hostname hosts.append(hostname) else: hosts.append(get_host_ip(cluster_address)) if hosts_map: update_hosts_file(hosts_map) return hosts
def db_joined(): if config('prefer-ipv6'): sync_db_with_multi_ipv6_addresses(config('database'), config('database-user')) else: host = None try: # NOTE: try to use network spaces host = network_get_primary_address('shared-db') except NotImplementedError: # NOTE: fallback to private-address host = unit_get('private-address') relation_set(database=config('database'), username=config('database-user'), hostname=host)
def get_cluster_host_ip(): """Get the this host's IP address for use with percona cluster peers @returns IP to pass to cluster peers """ cluster_network = config('cluster-network') if cluster_network: cluster_addr = get_address_in_network(cluster_network, fatal=True) else: try: cluster_addr = network_get_primary_address('cluster') except NotImplementedError: # NOTE(jamespage): fallback to previous behaviour cluster_addr = resolve_hostname_to_ip(unit_get('private-address')) return cluster_addr
def local_address(unit_get_fallback='public-address'): """Return a network address for this unit. Attempt to retrieve a 'default' IP address for this unit from network-get. If this is running with an old version of Juju then fallback to unit_get. :param unit_get_fallback: Either 'public-address' or 'private-address'. Only used with old versions of Juju. :type unit_get_fallback: str :returns: IP Address :rtype: str """ try: return network_get_primary_address('juju-info') except NotImplementedError: return unit_get(unit_get_fallback)
def request_access(self, username, vhost, hostname=None): """ Request access to vhost for the supplied username. """ if not hostname: try: hostname = hookenv.network_get_primary_address( self.conversation().relation_name) except NotImplementedError: hostname = hookenv.unit_private_ip() relation_info = { 'username': username, 'vhost': vhost, 'private-address': hostname, } self.set_local(**relation_info) self.set_remote(**relation_info)
def db_joined(): if is_relation_made("pgsql-db"): # error, postgresql is used e = "Attempting to associate a mysql database when there is already " "associated a postgresql one" log(e, level=ERROR) raise Exception(e) if config("prefer-ipv6"): sync_db_with_multi_ipv6_addresses(config("database"), config("database-user")) else: host = None try: # NOTE: try to use network spaces host = network_get_primary_address("shared-db") except NotImplementedError: # NOTE: fallback to private-address host = unit_get("private-address") relation_set(database=config("database"), username=config("database-user"), hostname=host)
def request_access(self, username, vhost, hostname=None): """ Request access to vhost for the supplied username. """ if not hostname: try: hostname = hookenv.network_get_primary_address( self.conversation().relation_name ) except NotImplementedError: hostname = hookenv.unit_private_ip() relation_info = { 'username': username, 'vhost': vhost, 'private-address': hostname, } self.set_local(**relation_info) self.set_remote(**relation_info)
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_cluster_host_ip(): """Get the this host's IP address for use with percona cluster peers @returns IP to pass to cluster peers """ cluster_network = config('cluster-network') if cluster_network: cluster_addr = get_address_in_network(cluster_network, fatal=True) else: try: cluster_addr = network_get_primary_address('cluster') except NotImplementedError: # NOTE(jamespage): fallback to previous behaviour cluster_addr = resolve_hostname_to_ip( unit_get('private-address') ) return cluster_addr
def get_master_status(interface): """ Get master status (lp1776171) Returns MySQL asynchronous replication master status. :param interface: relation name :type interface: str :returns: tuple of (IP address in space associated with 'master' binding, replication file, replication file position) :rtype: (str, str, str) :raises: OperationalError """ m_helper = get_db_helper() try: m_helper.connect(password=m_helper.get_mysql_root_password()) except OperationalError: log("Could not connect to db", level=DEBUG) raise results = m_helper.select("SHOW MASTER STATUS;") return network_get_primary_address(interface), results[0][0], results[0][1]
def db_joined(relation_id=None): if is_relation_made('pgsql-nova-db') or \ is_relation_made('pgsql-neutron-db'): # error, postgresql is used e = ('Attempting to associate a mysql database when there is already ' 'associated a postgresql one') log(e, level=ERROR) raise Exception(e) if config('prefer-ipv6'): sync_db_with_multi_ipv6_addresses(config('database'), config('database-user'), relation_prefix='nova') if os_release('nova-common') >= 'mitaka': # NOTE: mitaka uses a second nova-api database as well sync_db_with_multi_ipv6_addresses('nova_api', config('database-user'), relation_prefix='novaapi') else: host = None try: # NOTE: try to use network spaces host = network_get_primary_address('shared-db') except NotImplementedError: # NOTE: fallback to private-address host = unit_get('private-address') relation_set(nova_database=config('database'), nova_username=config('database-user'), nova_hostname=host, relation_id=relation_id) if os_release('nova-common') >= 'mitaka': # NOTE: mitaka uses a second nova-api database as well relation_set(novaapi_database='nova_api', novaapi_username=config('database-user'), novaapi_hostname=host, relation_id=relation_id)
def get_unit_ip(config_override='multicast-intf', address_family=ni.AF_INET): """Get the IP of this unit for cplane-controller relationship If the config override interface is configured use that address otherwise consult network-get for the correct address. As a last resort use the fallback interface. @param config_overide: The string name of the configuration value that can override the use of network spaces @param address_family: The netifaces address familiy i.e. for IPv4 AF_INET Only used when config(config_override) is configured @returns: IP address for this unit for the cplane-controller relationship """ # If the config override is not set to an interface use network-get # to leverage network spaces in MAAS 2.x if not config(config_override): try: return network_get_primary_address('cplane-controller') except NotImplementedError: # Juju 1.x enviornment return unit_get('private-address') interface = config(config_override) try: interface_config = ni.ifaddresses(interface).get(address_family) if interface_config: for link in interface_config: addr = link['addr'] if addr: return addr except ValueError as e: raise UnconfiguredInterface("Interface {} is invalid: {}" "".format(interface, e.message)) raise UnconfiguredInterface("{} interface has no address in the " "address family {}".format(interface, address_family))
def get_relation_ip(interface, cidr_network=None): """Return this unit's IP for the given interface. Allow for an arbitrary interface to use with network-get to select an IP. Handle all address selection options including passed cidr network and IPv6. Usage: get_relation_ip('amqp', cidr_network='10.0.0.0/8') @param interface: string name of the relation. @param cidr_network: string CIDR Network to select an address from. @raises Exception if prefer-ipv6 is configured but IPv6 unsupported. @returns IPv6 or IPv4 address """ # Select the interface address first # For possible use as a fallback bellow with get_address_in_network try: # Get the interface specific IP address = network_get_primary_address(interface) except NotImplementedError: # If network-get is not available address = get_host_ip(unit_get('private-address')) except NoNetworkBinding: log("No network binding for {}".format(interface), WARNING) address = get_host_ip(unit_get('private-address')) if config('prefer-ipv6'): # Currently IPv6 has priority, eventually we want IPv6 to just be # another network space. assert_charm_supports_ipv6() return get_ipv6_addr()[0] elif cidr_network: # If a specific CIDR network is passed get the address from that # network. return get_address_in_network(cidr_network, address) # Return the interface address return address
def db_joined(): if is_relation_made('pgsql-db'): # error, postgresql is used e = ('Attempting to associate a mysql database when there is already ' 'associated a postgresql one') log(e, level=ERROR) raise Exception(e) if config('prefer-ipv6'): sync_db_with_multi_ipv6_addresses(config('database'), config('database-user')) else: host = None try: # NOTE: try to use network spaces host = network_get_primary_address('shared-db') except NotImplementedError: # NOTE: fallback to private-address host = unit_get('private-address') conf = config() relation_set(database=conf['database'], username=conf['database-user'], hostname=host)
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')
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 ovs_ctxt(self): # In addition to generating config context, ensure the OVS service # is running and the OVS bridge exists. Also need to ensure # local_ip points to actual IP, not hostname. ovs_ctxt = super(OVSPluginContext, self).ovs_ctxt() if not ovs_ctxt: return {} conf = config() fallback = get_host_ip(unit_get('private-address')) if config('os-data-network'): # NOTE: prefer any existing use of config based networking ovs_ctxt['local_ip'] = \ get_address_in_network(config('os-data-network'), fallback) else: # NOTE: test out network-spaces support, then fallback try: ovs_ctxt['local_ip'] = get_host_ip( network_get_primary_address('data') ) except NotImplementedError: ovs_ctxt['local_ip'] = fallback neutron_api_settings = NeutronAPIContext()() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] ovs_ctxt['distributed_routing'] = neutron_api_settings['enable_dvr'] ovs_ctxt['extension_drivers'] = neutron_api_settings[ 'extension_drivers'] ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] ovs_ctxt['polling_interval'] = neutron_api_settings['polling_interval'] ovs_ctxt['rpc_response_timeout'] = \ neutron_api_settings['rpc_response_timeout'] ovs_ctxt['report_interval'] = neutron_api_settings['report_interval'] # TODO: We need to sort out the syslog and debug/verbose options as a # general context helper ovs_ctxt['use_syslog'] = conf['use-syslog'] ovs_ctxt['verbose'] = conf['verbose'] ovs_ctxt['debug'] = conf['debug'] cmp_release = CompareOpenStackReleases( os_release('neutron-common', base='icehouse')) if conf['prevent-arp-spoofing'] and cmp_release >= 'ocata': log("prevent-arp-spoofing is True yet this feature is deprecated " "and no longer has any effect in your version of Openstack", WARNING) ovs_ctxt['prevent_arp_spoofing'] = conf['prevent-arp-spoofing'] ovs_ctxt['enable_dpdk'] = conf['enable-dpdk'] net_dev_mtu = neutron_api_settings.get('network_device_mtu') if net_dev_mtu: # neutron.conf ovs_ctxt['network_device_mtu'] = net_dev_mtu # ml2 conf ovs_ctxt['veth_mtu'] = net_dev_mtu mappings = config('bridge-mappings') if mappings: ovs_ctxt['bridge_mappings'] = ','.join(mappings.split()) sriov_mappings = config('sriov-device-mappings') if sriov_mappings: ovs_ctxt['sriov_device_mappings'] = ( ','.join(sriov_mappings.split()) ) enable_sriov = config('enable-sriov') if enable_sriov: ovs_ctxt['enable_sriov'] = True sriov_numvfs = config('sriov-numvfs') if sriov_numvfs: try: if sriov_numvfs != 'auto': int(sriov_numvfs) except ValueError: ovs_ctxt['sriov_vfs_list'] = sriov_numvfs else: ovs_ctxt['sriov_vfs_blanket'] = sriov_numvfs flat_providers = config('flat-network-providers') if flat_providers: ovs_ctxt['network_providers'] = ','.join(flat_providers.split()) vlan_ranges = config('vlan-ranges') if vlan_ranges: ovs_ctxt['vlan_ranges'] = ','.join(vlan_ranges.split()) ovs_ctxt['enable_nsg_logging'] = \ neutron_api_settings['enable_nsg_logging'] ovs_ctxt['nsg_log_output_base'] = get_nsg_log_path( config('security-group-log-output-base') ) ovs_ctxt['nsg_log_rate_limit'] = \ config('security-group-log-rate-limit') ovs_ctxt['nsg_log_burst_limit'] = \ config('security-group-log-burst-limit') ovs_ctxt['firewall_driver'] = _get_firewall_driver(ovs_ctxt) if ovs_ctxt['firewall_driver'] != OPENVSWITCH: ovs_ctxt['enable_nsg_logging'] = False return ovs_ctxt