def run_relation_hook(self, relation_name, action): # TODO: It would be nice to use our own relation here, rather than reusing the 'website' relation if relation_name == 'website': return self._run_loadbalancer_hook(action) # TODO: Only on certain actions? logger.info("Running relation hook %s %s", relation_name, action) relation = Relation.default() properties = {} if not action == "broken": properties = relation.get_properties() logger.info("Got relation properties %s", properties) xaas = self._privateclient() config = Juju.config() service_name = Juju.service_name() unit_id = Juju.unit_name() remote_name = os.environ["JUJU_REMOTE_UNIT"] relation_id = relation.relation_id new_properties = xaas.update_relation_properties(service_name=service_name, relation=relation_name, relation_id=relation_id, unit_id=unit_id, remote_name=remote_name, action=action, properties=properties) if new_properties: logger.info("Setting relation properties to: %s", new_properties) relation.set_properties(new_properties)
def on_config_changed(self): config = Juju.config() open_ports = config.get('open-ports', '') for open_port in open_ports.split(','): open_port = open_port.strip() if open_port == "": continue Juju.open_port(open_port) return None
def _run_loadbalancer_hook(self, action): logger.info("Running load-balancer hook %s", action) host = Juju.private_address() config = Juju.config() private_port = config['private-port'] if private_port == 0: logger.info("Private port is 0; won't configure load balancer") public_port = config['public-port'] if public_port == 0: logger.info("Public port is 0; won't configure load balancer") protocol = config.get('protocol', '').strip().lower() service_name = Juju.unit_name() service_name = service_name.split('/')[0] relation = Relation.default() relation_id = relation.relation_id servers = [] servers.append(['s_1', host, private_port, '']) service_options = [ 'mode tcp', 'balance leastconn' ] if protocol == 'tls': service_options.append('ssl') service = {} service['service_name'] = service_name service['service_options'] = service_options service['servers'] = servers # Must set both service_host and service_port, or else haproxy ignores the other service['service_host'] = '0.0.0.0' service['service_port'] = public_port services = [] services.append(service) new_properties = {} new_properties['services'] = yaml.dump(services) # relation-set "services= # - { service_name: my_web_app, # service_options: [mode http, balance leastconn], # servers: [[my_web_app_1, $host, $port, option httpchk GET / HTTP/1.0], # [... optionally more servers here ...]]} # - { ... optionally more services here ... } # " if new_properties: logger.info("Setting relation properties to: %s", new_properties) relation.set_properties(new_properties)
def run_relation_hook(self, relation_name, action, interface_id=None): logger.info("Running relation hook %s %s", relation_name, action) # TODO: Only on certain actions? if action == "broken": return xaas = self._client() bundle_type = self.config["charm"] instance_id = Juju.service_name() if interface_id is None: interface_id = instance_id logger.info("Fetching service properties for %s/%s/%s", bundle_type, instance_id, interface_id) response = xaas.get_relation_properties(bundle_type=bundle_type, instance_id=instance_id, relation=interface_id) relation_properties = response.get("Properties", {}) protocol = relation_properties.get("protocol") if protocol == "tls": relation_properties = self._ensure_tls(bundle_type, relation_properties) relation = Relation.default() logger.info("Setting relation properties to: %s", relation_properties) relation.set_properties(relation_properties)
def on_config_changed(self): xaas = self._client() options = Juju.config() bundle_type = self.config["charm"] instance_id = Juju.service_name() logger.info("Ensuring that service is configured: %s %s", bundle_type, instance_id) service = xaas.ensure_instance(bundle_type=bundle_type, instance_id=instance_id, options=options) # TODO: Timeout & throw error after a while while service.get("Status") != "started": logger.info("Waiting for service to reach active state. Current state %s", service.get("Status")) time.sleep(5) service = xaas.get_instance_state(bundle_type=bundle_type, instance_id=instance_id) return service
def _ensure_tls(self, bundle_type, properties): # TODO: We could create some system properties here, that work everywhere host = properties.get("host") or properties.get("private-address") port = properties.get("port") logger.info("Properties before rewrite: %s" % properties) default_port = self._get_default_port(bundle_type) # By using the default_port again, we can make things easier for clients # that don't support the port accept = "0.0.0.0:" + str(default_port) connect = host + ":" + str(port) stunnel_config = """ client=yes [tlswrap] accept=%s connect=%s """ % ( accept, connect, ) changed = False if utils.write_file("/etc/stunnel/tlswrap.conf", stunnel_config): changed = True if utils.update_keyvalue("/etc/default/stunnel4", {"ENABLED": "1"}): changed = True if changed: utils.run_command(["/etc/init.d/stunnel4", "start"]) utils.run_command(["/etc/init.d/stunnel4", "reload"]) if "hopst" in properties: properties["host"] = Juju.private_address() if "private-address" in properties: properties["private-address"] = Juju.private_address() properties["port"] = str(default_port) logger.info("Properties after rewrite: %s" % properties) return properties
def _privateclient(self): config = Juju.config() url = config.get('jxaas-privateurl', '') if not url: raise Exception("jxaas-privateurl is required") tenant = config.get('jxaas-tenant', '') if not tenant: raise Exception("jxaas-tenant is required") username = config.get('jxaas-user', '') secret = config.get('jxaas-secret', '') client = jujuxaas.privateclient.PrivateClient(url=url, tenant=tenant, username=username, password=secret) return client
def _client(self): config = Juju.config() url = config.get("jxaas-url", "") if not url: raise Exception("jxaas-url is required") authmode = config.get("jxaas-authmode", "") tenant = config.get("jxaas-tenant", "") if not tenant: raise Exception("jxaas-tenant is required") username = config.get("jxaas-user", "") secret = config.get("jxaas-secret", "") authmode = authmode.strip().lower() if authmode == "openstack": auth = jujuxaas.auth.openstack.AuthOpenstack(url=url, tenant=tenant, username=username, password=secret) else: auth = jujuxaas.auth.direct.AuthDirect(url=url, tenant=tenant, username=username, password=secret) xaas = jujuxaas.client.Client(auth) return xaas
def run_relation_hook(): relation_name = os.environ["JUJU_RELATION"] juju_action = Juju.action() stub = Stub() return stub.run_relation_hook(relation_name, juju_action)
def run_relation_hook(interface_id=None): relation_name = os.environ["JUJU_RELATION"] juju_action = Juju.action() proxy = Proxy() return proxy.run_relation_hook(relation_name, juju_action, interface_id=interface_id)