示例#1
0
    def configure_proxy(self, proxy):
        """Configure GitLab for operation behind a reverse proxy."""
        url = urlparse(self.get_external_uri())

        if url.scheme == "https":
            port = 443
        else:
            port = 80

        if self.charm_config["proxy_via_ip"]:
            networks = hookenv.network_get(proxy.relation_name)
            internal_host = networks["ingress-addresses"][0]
        else:
            internal_host = socket.getfqdn()

        proxy_config = [
            {
                "mode": "http",
                "external_port": port,
                "internal_host": internal_host,
                "internal_port": self.charm_config["http_port"],
                "subdomain": url.hostname,
            },
            {
                "mode": "tcp",
                "external_port": self.charm_config["proxy_ssh_port"],
                "internal_host": internal_host,
                "internal_port": self.charm_config["ssh_port"],
            },
        ]
        proxy.configure(proxy_config)
def configure_systemd_resolved(hosts={}):
    '''
    Render a drop-in config file for systemd-resolved at
    /etc/systemd/resolved.conf.d/ and restart the systemd-resolved service.

    This is done in order to use a local bind9 server as a resolver.
    '''
    charm_config = config()
    realm = charm_config['realm']

    ch_host.mkdir('/etc/systemd/resolved.conf.d/', perms=0o755, owner='root',
                  group='root')

    ctxt = {}
    ctxt['domain'] = realm
    ctxt['dns_ip'] = network_get('dns-server')['ingress-addresses'][0]

    core.templating.render(
        source='local-dns-bind.conf',
        target='/etc/bind/zones/{}'.format(realm),
        context=ctxt,
        owner='root',
        group='root',
        perms=0o644,
    )

    ch_host.service_restart('systemd-resolved')
def websso_trusted_dashboard_changed():
    """
    Provide L7 endpoint details for the dashboard and also
    handle any config changes that may affect those.
    """
    relations = relation_ids('websso-trusted-dashboard')
    if not relations:
        return

    # TODO: check for vault relation in order to determine url scheme
    tls_configured = config('ssl-key') or config('enforce-ssl')
    scheme = 'https://' if tls_configured else 'http://'

    if config('dns-ha') or config('os-public-hostname'):
        hostname = config('os-public-hostname')
    elif config('vip'):
        hostname = config('vip')
    else:
        # use an ingress-address of a given unit as a fallback
        netinfo = network_get('websso-trusted-dashboard')
        hostname = netinfo['ingress-addresses'][0]

    # provide trusted dashboard URL details
    for rid in relations:
        relation_set(relation_id=rid,
                     relation_settings={
                         "scheme": scheme,
                         "hostname": hostname,
                         "path": "/auth/websso/"
                     })
示例#4
0
def provide_database(mysql):
    log('db requested')

    info = network_get('server', relation_id())
    log('network info {0}'.format(info))
    host = info['ingress-addresses'][0]
    if host == "":
        log("no service address yet")
        return

    for request, application in mysql.database_requests().items():
        log('request -> {0} for app -> {1}'.format(request, application))
        database_name = get_state('database')
        user = get_state('user')
        password = get_state('password')

        log('db params: {0}:{1}@{2}'.format(user, password, database_name))

        mysql.provide_database(
            request_id=request,
            host=host,
            port=3306,
            database_name=database_name,
            user=user,
            password=password,
        )
        clear_flag('server.database.requested')
def provide_lb_consumers():
    '''Respond to any LB requests via the lb-consumers relation.

    This is used in favor for the more complex two relation setup using the
    website and loadbalancer relations going forward.
    '''
    lb_consumers = endpoint_from_name('lb-consumers')
    lb_address = _get_lb_address()
    for request in lb_consumers.all_requests:
        response = request.response
        if request.protocol not in (request.protocols.tcp,
                                    request.protocols.http,
                                    request.protocols.https):
            response.error_type = response.error_types.unsupported
            response.error_fields = {
                'protocol': 'Protocol must be one of: tcp, http, https'
            }
            lb_consumers.send_response(request)
            continue
        if lb_address:
            private_address = lb_address
            public_address = lb_address
        else:
            network_info = hookenv.network_get('lb-consumers',
                                               str(request.relation.id))
            private_address = network_info['ingress-addresses'][0]
            public_address = hookenv.unit_get('public-address')
        if request.public:
            response.address = public_address
        else:
            response.address = private_address
        lb_consumers.send_response(request)
def configure_bind_zone(hosts={}):
    '''
    Render bind9 zone configuration.
    '''
    charm_config = config()
    realm = charm_config['realm']

    ch_host.mkdir('/etc/bind/zones', perms=0o755, owner='root',
                  group='bind')

    ctxt = {}
    ctxt['domain'] = realm

    hosts.update({
        socket.gethostname(): network_get('dns-server')['ingress-addresses'][0]
    })

    ctxt['hosts'] = hosts

    core.templating.render(
        source='bind_zone',
        target='/etc/bind/zones/{}'.format(realm),
        context=ctxt,
        owner='root',
        group='bind',
        perms=0o644,
    )

    ch_host.service_restart('bind9')
示例#7
0
def provide_database(mysql):
    log('db requested')

    info = network_get('server', relation_id())
    log('network info {0}'.format(info))
    host = info.get('ingress-addresses', [""])[0]
    if not host:
        log("no service address yet")
        return

    cfg = config()
    user = cfg.get('user')
    password = cfg.get('password')
    database = cfg.get('database')

    for request, application in mysql.database_requests().items():
        log('request -> {0} for app -> {1}'.format(request, application))

        log('db params: {0}:...@{1}'.format(user, database))

        mysql.provide_database(
            request_id=request,
            host=host,
            port=3306,
            database_name=database,
            user=user,
            password=password,
        )
        clear_flag('server.database.requested')
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
示例#9
0
def get_ingress_address(endpoint_name, ignore_addresses=None):
    try:
        network_info = hookenv.network_get(endpoint_name)
    except NotImplementedError:
        network_info = {}

    if not network_info or "ingress-addresses" not in network_info:
        # if they don't have ingress-addresses they are running a juju that
        # doesn't support spaces, so just return the private address
        return hookenv.unit_get("private-address")

    addresses = network_info["ingress-addresses"]

    if ignore_addresses:
        hookenv.log("ingress-addresses before filtering: {}".format(addresses))
        iter_filter = filter(lambda item: item not in ignore_addresses,
                             addresses)
        addresses = list(iter_filter)
        hookenv.log("ingress-addresses after filtering: {}".format(addresses))

    # Need to prefer non-fan IP addresses due to various issues, e.g.
    # https://bugs.launchpad.net/charm-gcp-integrator/+bug/1822997
    # Fan typically likes to use IPs in the 240.0.0.0/4 block, so we'll
    # prioritize those last. Not technically correct, but good enough.
    try:
        sort_key = lambda a: int(a.partition(".")[0]) >= 240  # noqa: E731
        addresses = sorted(addresses, key=sort_key)
    except Exception:
        hookenv.log(traceback.format_exc())

    return addresses[0]
def websso_trusted_dashboard_changed():
    """
    Provide L7 endpoint details for the dashboard and also
    handle any config changes that may affect those.
    """
    relations = relation_ids('websso-trusted-dashboard')
    if not relations:
        return

    # TODO: check for vault relation in order to determine url scheme
    tls_configured = config('ssl-key') or config('enforce-ssl')
    scheme = 'https://' if tls_configured else 'http://'

    if config('dns-ha') or config('os-public-hostname'):
        hostname = config('os-public-hostname')
    elif config('vip'):
        hostname = config('vip')
    else:
        # use an ingress-address of a given unit as a fallback
        netinfo = network_get('websso-trusted-dashboard')
        hostname = netinfo['ingress-addresses'][0]

    # provide trusted dashboard URL details
    for rid in relations:
        relation_set(relation_id=rid, relation_settings={
            "scheme": scheme,
            "hostname": hostname,
            "path": "/auth/websso/"
        })
def configure_staticip():
    network_config = hookenv.network_get(
        hookenv.config('binding')
    )
    nics = {}
    for nic in network_config.get('bind-addresses'):
        nics.update({
            [nic.get('interfacename')]: {
                'addresses': [
                    nic.get('addresses')[0]
                ],
                'gatewayv4': None,  # TODO: Find a reliable way of getting
                                    # the gateway IP.
                'dhcp': 'no',
            }
        })

    netplan_config = {
        'network': {
            'version': 2,
            'renderer': "networkd",
            'ethernets': {

            }
        }
    }

    with open('/etc/netplan/00-set-staticip.yaml', 'w') as npfile:
        npfile.wirte(netplan_config)
示例#12
0
def network_details():
    # even if there are no relations for that endpoint
    # we can still get an address from a space bound to it
    net_details = hookenv.network_get('slurm-dbd-ha')
    return {
        'hostname': socket.gethostname(),
        'ingress_address': net_details['ingress-addresses'][0]
    }
示例#13
0
    def request_certificates():
        cert_provider = endpoint_from_flag('cert-provider.available')

        # get ingress info
        ingress_for_clients = hookenv.network_get(
            'clients')['ingress-addresses']
        ingress_for_db = hookenv.network_get('db')['ingress-addresses']

        # use first ingress address as primary and any additional as SANs
        server_cn, server_sans = ingress_for_clients[
            0], ingress_for_clients[:1]
        client_cn, client_sans = ingress_for_db[0], ingress_for_db[:1]

        # request a single server and single client cert; note that multiple certs
        # of either type can be requested as long as they have unique common names
        cert_provider.request_server_cert(server_cn, server_sans)
        cert_provider.request_client_cert(client_cn, client_sans)
def is_pod_up(endpoint):
    info = network_get(endpoint, relation_id())

    # Check to see if the pod has been assigned it's internal and external ips
    for ingress in info['ingress-addresses']:
        if len(ingress) == 0:
            return False

    return True
示例#15
0
def configure_relation_data():
    endpoint = endpoint_from_flag('endpoint.redis.joined')

    info = network_get('redis', relation_id())
    log('network info {0}'.format(info))
    host = info['ingress-addresses'][0]
    if host == "":
        log("no service address yet")
        return
    else:
        endpoint.configure(host=host, port="6379")
示例#16
0
def get_ingress_address(endpoint_name):
    ''' Returns ingress-address belonging to the named endpoint, if available.
    Falls back to private-address if necessary. '''
    try:
        data = network_get(endpoint_name)
    except NotImplementedError:
        return unit_private_ip()

    if 'ingress-addresses' in data:
        return data['ingress-addresses'][0]
    else:
        return unit_private_ip()
示例#17
0
def get_ingress_addresses(endpoint_name):
    """Returns all ingress-addresses belonging to the named endpoint, if
    available. Falls back to private-address if necessary."""
    try:
        data = network_get(endpoint_name)
    except NotImplementedError:
        return [unit_private_ip()]

    if "ingress-addresses" in data:
        return data["ingress-addresses"]
    else:
        return [unit_private_ip()]
def get_service_ip(endpoint):
    try:
        info = network_get(endpoint, relation_id())
        if 'ingress-addresses' in info:
            addr = info['ingress-addresses'][0]
            if len(addr):
                return addr
        else:
            log("No ingress-addresses: {}".format(info))
    except Exception as e:
        log("Caught exception checking for service IP: {}".format(e))

    return None
示例#19
0
def get_ingress_address(relation):
    try:
        network_info = hookenv.network_get(relation.relation_name)
    except NotImplementedError:
        network_info = []

    if network_info and 'ingress-addresses' in network_info:
        # just grab the first one for now, maybe be more robust here?
        return network_info['ingress-addresses'][0]
    else:
        # if they don't have ingress-addresses they are running a juju that
        # doesn't support spaces, so just return the private address
        return hookenv.unit_get('private-address')
def get_ingress_address(relation):
    try:
        network_info = hookenv.network_get(relation.relation_name)
    except NotImplementedError:
        network_info = []

    if network_info and 'ingress-addresses' in network_info:
        # just grab the first one for now, maybe be more robust here?
        return network_info['ingress-addresses'][0]
    else:
        # if they don't have ingress-addresses they are running a juju that
        # doesn't support spaces, so just return the private address
        return hookenv.unit_get('private-address')
示例#21
0
def listen_ip_address():
    c = config()
    # Pre-juju2, listen_interface was used to control the interface used for
    # communication & replication between Cassandra units.
    if c['listen_interface'] or not hookenv.has_juju_version('2.3'):
        return (interface_to_ip(c['listen_interface']) or
                hookenv.unit_private_ip())

    # Post-juju2, addresses for relation endpoints can be specified at deploy time
    # in a standard way, so listen_interface in config should be unnecessary.
    ip = hookenv.network_get('cluster')['bind-addresses'][0]['addresses'][0]['address']
    hookenv.log('listen_ip_address == {!r}'.format(ip), DEBUG)
    return ip
def configure_relation_data():
    cfg = config()
    endpoint = endpoint_from_flag('endpoint.bitcoind.joined')

    info = network_get('bitcoind', relation_id())
    log('network info {0}'.format(info))
    host = info['ingress-addresses'][0]
    if host == "":
        log("no service address yet")
        return
    else:
        endpoint.configure(host=host, port=cfg.get('btc-rpcport'),
                           user=cfg.get('btc-rpcuser'),
                           password=cfg.get('btc-rpcpassword'))
示例#23
0
 def listen(self, cidr=None, port=None):
     port = port or self.IPERF_BASE_PORT
     if cidr:
         bind_addreess = ch_ip.get_address_in_network(cidr)
     else:
         bind_addreess = (
             hookenv.network_get('magpie')
             ['bind-addresses'][0]['addresses'][0]['address']
         )
     cmd = (
         "iperf -s -m -fm --port " + str(port) +
         " -B " + bind_addreess + " | tee " +
         self.iperf_out + " &"
     )
     os.system(cmd)
示例#24
0
def ingress_address(endpoint, relid):
    # Work around https://github.com/juju/charm-helpers/issues/112
    if not hookenv.has_juju_version("2.3"):
        return hookenv.unit_private_ip()

    try:
        d = hookenv.network_get(endpoint, relid)
        return d["ingress-addresses"][0]
    except NotImplementedError:
        # Warn, although this is normal with older Juju.
        hookenv.log(
            "Unable to determine ingress address, " "falling back to private ip",
            hookenv.WARNING,
        )
        return hookenv.unit_private_ip()
示例#25
0
def rpc_broadcast_ip_address():
    c = config()
    # Pre-juju2, rpc_interface was used to control the interface used for
    # client communication.
    if c['rpc_interface'] or not hookenv.has_juju_version('2.3'):
        return (interface_to_ip(c['rpc_interface']) or
                hookenv.unit_public_ip())

    # Post-juju2, addresses for relation endpoints can be specified at deploy time
    # in a standard way, so listen_interface in config should be unnecessary.
    # Only the database endpoint is used, as Cassandra only supports a single
    # IP address to broadcast as the connection address.
    ip = hookenv.network_get('database')['ingress-addresses'][0]
    hookenv.log('rpc_broadcast_ip_address == {!r}'.format(ip), DEBUG)
    return ip
示例#26
0
def get_ingress_address6(endpoint_name):
    try:
        network_info = hookenv.network_get(endpoint_name)
    except NotImplementedError:
        network_info = {}

    if not network_info or "ingress-addresses" not in network_info:
        return None

    addresses = network_info["ingress-addresses"]

    for addr in addresses:
        ip_addr = ipaddress.ip_interface(addr).ip
        if ip_addr.version == 6:
            return str(ip_addr)
    else:
        return None
示例#27
0
def get_bind_address(endpoint_name):
    ''' Returns the first bind-address found in network info
    belonging to the named endpoint, if available.
    Falls back to private-address if necessary.

        @param endpoint_name the endpoint from where taking the
        bind address
    '''
    try:
        data = network_get(endpoint_name)
    except NotImplementedError:
        return unit_private_ip()

    # Consider that network-get returns something like:
    #
    # bind-addresses:
    # - macaddress: 02:d0:9e:31:d9:e0
    # interfacename: ens5
    # addresses:
    # - hostname: ""
    #     address: 172.31.5.4
    #     cidr: 172.31.0.0/20
    # - hostname: ""
    #     address: 172.31.5.4
    #     cidr: 172.31.0.0/20
    # - macaddress: 8a:32:d7:8d:f6:9a
    # interfacename: fan-252
    # addresses:
    # - hostname: ""
    #     address: 252.5.4.1
    #     cidr: 252.0.0.0/12
    # egress-subnets:
    # - 172.31.5.4/32
    # ingress-addresses:
    # - 172.31.5.4
    # - 172.31.5.4
    # - 252.5.4.1
    if 'bind-addresses' in data:
        bind_addresses = data['bind-addresses']
        if len(bind_addresses) > 0:
            if 'addresses' in bind_addresses[0]:
                if len(bind_addresses[0]['addresses']) > 0:
                    return bind_addresses[0]['addresses'][0]['address']

    return unit_private_ip()
示例#28
0
def get_bind_address():
    ''' Returns a non-fan bind address for the cni endpoint '''
    try:
        data = network_get('cni')
    except NotImplementedError:
        # Juju < 2.1
        return unit_private_ip()

    if 'bind-addresses' not in data:
        # Juju < 2.3
        return unit_private_ip()

    for bind_address in data['bind-addresses']:
        if bind_address['interfacename'].startswith('fan-'):
            continue
        return bind_address['addresses'][0]['address']

    # If we made it here, we didn't find a non-fan CNI bind-address, which is
    # unexpected. Let's log a message and play it safe.
    log('Could not find a non-fan bind-address. Using private-address.')
    return unit_private_ip()
示例#29
0
def is_pod_up(endpoint):
    """Check to see if the pod of a relation is up.

    application-vimdb: 19:29:10 INFO unit.vimdb/0.juju-log network info

    In the example below:
    - 10.1.1.105 is the address of the application pod.
    - 10.152.183.199 is the service cluster ip

    {
        'bind-addresses': [{
            'macaddress': '',
            'interfacename': '',
            'addresses': [{
                'hostname': '',
                'address': '10.1.1.105',
                'cidr': ''
            }]
        }],
        'egress-subnets': [
            '10.152.183.199/32'
        ],
        'ingress-addresses': [
            '10.152.183.199',
            '10.1.1.105'
        ]
    }
    """
    try:
        info = network_get(endpoint, relation_id())

        # Check to see if the pod has been assigned it's internal and
        # external ips
        for ingress in info['ingress-addresses']:
            if len(ingress) == 0:
                return False
    except:
        return False

    return True
示例#30
0
def get_bind_address_interface():
    ''' Returns a non-fan bind-address interface for the cni endpoint.
    Falls back to default_route_interface() if bind-address is not available.
    '''
    try:
        data = network_get('cni')
    except NotImplementedError:
        # Juju < 2.1
        return default_route_interface()

    if 'bind-addresses' not in data:
        # Juju < 2.3
        return default_route_interface()

    for bind_address in data['bind-addresses']:
        if bind_address['interfacename'].startswith('fan-'):
            continue
        return bind_address['interfacename']

    # If we made it here, we didn't find a non-fan CNI bind-address, which is
    # unexpected. Let's log a message and play it safe.
    log('Could not find a non-fan bind-address. Using fallback interface.')
    return default_route_interface()
def get_ingress_address(endpoint_name):
    try:
        network_info = hookenv.network_get(endpoint_name)
    except NotImplementedError:
        network_info = {}

    if not network_info or 'ingress-addresses' not in network_info:
        # if they don't have ingress-addresses they are running a juju that
        # doesn't support spaces, so just return the private address
        return hookenv.unit_get('private-address')

    addresses = network_info['ingress-addresses']

    # Need to prefer non-fan IP addresses due to various issues, e.g.
    # https://bugs.launchpad.net/charm-gcp-integrator/+bug/1822997
    # Fan typically likes to use IPs in the 240.0.0.0/4 block, so we'll
    # prioritize those last. Not technically correct, but good enough.
    try:
        sort_key = lambda a: int(a.partition('.')[0]) >= 240  # noqa: E731
        addresses = sorted(addresses, key=sort_key)
    except Exception:
        hookenv.log(traceback.format_exc())

    return addresses[0]
示例#32
0
    when_not,
)

from charmhelpers.core.hookenv import (application_version_set, network_get,
                                       status_set, config, open_port)

from charmhelpers.core.host import (
    service_restart,
    service_running,
    service_start,
)

from charms.layer.redis import (render_conf, get_redis_version, REDIS_CONF,
                                REDIS_SERVICE)

PRIVATE_IP = network_get('redis')['ingress-addresses'][0]


@when_not('redis.system.configured')
def configure_system_for_redis():
    with open('/etc/sysctl.conf', 'a') as f:
        f.write("\nvm.overcommit_memory = 1")
    call('sysctl vm.overcommit_memory=1'.split())

    with open('/sys/kernel/mm/transparent_hugepage/enabled', 'w') as f:
        f.write('never')

    with open('/proc/sys/net/core/somaxconn', 'w') as f:
        f.write('1024')

    set_flag('redis.system.configured')
示例#33
0
    endpoint_from_flag,
    set_flag,
    when,
    when_not,
)

from charmhelpers.core.hookenv import (network_get, log, status_set, config,
                                       open_port)

from charmhelpers.core import unitdata

from charms.layer.sentry import (render_sentry_config, start_restart,
                                 SENTRY_BIN, SENTRY_WEB_SERVICE,
                                 SENTRY_WORKER_SERVICE, SENTRY_CRON_SERVICE)

PRIVATE_IP = network_get('http')['ingress-addresses'][0]

kv = unitdata.kv()


@when_not('manual.database.check.available')
def check_user_provided_database():
    if not config('db-uri'):
        clear_flag('sentry.manual.database.available')
        log("Manual database not configured")
    else:
        kv.set('db_uri', config('db-uri'))
        set_flag('sentry.manual.database.available')
        clear_flag('sentry.config.available')
        clear_flag('sentry.juju.database.available')
    set_flag('manual.database.check.available')
ES_DEFAULT_FILE_PATH = Path('/etc/default/elasticsearch')

ES_PATH_CONF = Path('/etc/elasticsearch')

ES_YML_PATH = ES_PATH_CONF / 'elasticsearch.yml'

ES_PLUGIN = ES_HOME_DIR / 'bin' / 'elasticsearch-plugin'

ES_SETUP_PASSWORDS = ES_HOME_DIR / 'bin' / 'elasticsearch-setup-passwords'

JVM_OPTIONS = ES_PATH_CONF / 'jvm.options'

JAVA_HOME = Path('/usr/lib/jvm/java-8-openjdk-amd64/jre')

ES_PUBLIC_INGRESS_ADDRESS = network_get('public')['ingress-addresses'][0]

ES_CLUSTER_INGRESS_ADDRESS = network_get('cluster')['ingress-addresses'][0]

ES_NODE_TYPE = config('node-type')

ES_CLUSTER_NAME = config('cluster-name')

ES_HTTP_PORT = 9200

ES_TRANSPORT_PORT = 9300

ES_CERTS_DIR = Path("/etc/elasticsearch/certs")

ES_CA = ES_CERTS_DIR / "ca.p12"