def housekeeping(): """ calls housekeep for each manager. is run periodically. """ token = get_token() logger.info('provisioning plugins queried from worker') mgr = get_provisioning_manager() mgr.map_method(mgr.names(), 'housekeep', token)
def proxy_add_route(route_key, target, options): """ adds a route to nginx configs for access to e.g. a container """ logger.info('proxy_add_route(%s, %s)' % (route_key, target)) # generate a location snippet for nginx proxy config # see https://support.rstudio.com/hc/en-us/articles/200552326-Running-with-a-Proxy config = [ 'location /notebooks/%s/ {' % (route_key), 'proxy_pass %s;' % (target), 'proxy_http_version 1.1;', 'proxy_set_header Upgrade $http_upgrade;', 'proxy_set_header Connection "upgrade";', 'proxy_read_timeout 86400;' ] dynamic_config = get_dynamic_config() external_https_port = dynamic_config['EXTERNAL_HTTPS_PORT'] if 'proxy_rewrite' in options: config.append('rewrite ^/notebooks/%s/(.*)$ /$1 break;' % (route_key)) if 'proxy_redirect' in options: config.append('proxy_redirect %s $scheme://$host:%d/notebooks/%s;' % (target, external_https_port, route_key)) if 'set_host_header' in options: config.append('proxy_set_header Host $host;') if 'bypass_token_authentication' in options: instance_id = options['bypass_token_authentication'] config.append('proxy_set_header Authorization "token %s";' % (instance_id)) config.append('}') path = '%s/route_key-%s' % (RUNTIME_PATH, route_key) with open(path, 'w') as f: f.write('\n'.join(config)) refresh_nginx_config()
def send_mails(users, text=None): """ ToDo: document. apparently sends activation emails. """ dynamic_config = get_dynamic_config() j2_env = jinja2.Environment( loader=jinja2.PackageLoader('pebbles', 'templates')) base_url = dynamic_config['BASE_URL'].strip('/') for email, token, user_active in users: if text is None: activation_url = '%s/#/activate/%s' % (base_url, token) msg = MIMEText( j2_env.get_template('invitation.txt').render( activation_link=activation_url, instance_name=dynamic_config['INSTALLATION_NAME'], instance_description=dynamic_config[ 'INSTALLATION_DESCRIPTION'], user_active=user_active)) subject = '%s account activation' if not user_active else '%s password reset' msg['Subject'] = subject % dynamic_config['INSTALLATION_NAME'] else: msg = MIMEText(text['message']) subject = text['subject'] + " - %s" msg['Subject'] = subject % dynamic_config['INSTALLATION_NAME'] msg['To'] = email msg['From'] = dynamic_config['SENDER_EMAIL'] logger.info(msg) if not dynamic_config['MAIL_SUPPRESS_SEND']: s = smtplib.SMTP(dynamic_config['MAIL_SERVER']) if dynamic_config['MAIL_USE_TLS']: s.starttls() s.sendmail(msg['From'], [msg['To']], msg.as_string()) s.quit() else: logger.info('Mail sending suppressed in config')
def send_mails(users): """ ToDo: document. apparently sends activation emails. """ config = get_config() j2_env = jinja2.Environment( loader=jinja2.PackageLoader('pebbles', 'templates')) base_url = config['BASE_URL'].strip('/') for email, token in users: activation_url = '%s/#/activate/%s' % (base_url, token) msg = MIMEText( j2_env.get_template('invitation.txt').render( activation_link=activation_url)) msg['Subject'] = 'Pebbles account activation' msg['To'] = email msg['From'] = config['SENDER_EMAIL'] logger.info(msg) if not config['MAIL_SUPPRESS_SEND']: s = smtplib.SMTP(config['MAIL_SERVER']) if config['MAIL_USE_TLS']: s.starttls() s.sendmail(msg['From'], [msg['To']], msg.as_string()) s.quit() else: logger.info('Mail sending suppressed in config')
def update_user_connectivity(instance_id): """ updates the connectivity for a single instance. """ logger.info('updating connectivity for instance %s' % instance_id) token = get_token() mgr = get_provisioning_manager() plugin = get_provisioning_type(token, instance_id) mgr.map_method([plugin], 'update_connectivity', token, instance_id) logger.info('update connectivity for instance %s ready' % instance_id)
def run_update(instance_id): """ calls the update method for the manager of a single instance. """ logger.info('update triggered for %s' % instance_id) token = get_token() mgr = get_provisioning_manager() plugin = get_provisioning_type(token, instance_id) mgr.map_method([plugin], 'update', token, instance_id) logger.info('update done, notifying server')
def proxy_remove_route(route_key): """ removes a route from nginx config e.g. when removing a resource. """ logger.info('proxy_remove_route(%s)' % route_key) path = '%s/route_key-%s' % (RUNTIME_PATH, route_key) if os.path.exists(path): os.remove(path) else: logger.info('proxy_remove_route(): no such file') refresh_nginx_config()
def periodic_update(): """ Runs periodic updates. In particular sets old instances up for deprovisioning after they are past their maximum_lifetime and sets instances up for up updates. Both deletion and update events are not guaranteed to take place immediately. If there are more than 10 instances a random sample of 10 updates and deletions will take place to ensure task is safe to run and won't slow down other tasks. """ token = get_token() pbclient = PBClient(token, local_config['INTERNAL_API_BASE_URL'], ssl_verify=False) instances = pbclient.get_instances() deprovision_list = [] update_list = [] for instance in instances: logger.debug('checking instance for actions %s' % instance['name']) deprovision_required = False if instance.get('state') in [Instance.STATE_RUNNING]: if not instance.get('lifetime_left') and instance.get( 'maximum_lifetime'): deprovision_required = True if deprovision_required: deprovision_list.append(instance) elif instance.get('state') not in [Instance.STATE_FAILED]: update_list.append(instance) # ToDo: refactor magic number to variable if len(deprovision_list) > 10: deprovision_list = random.sample(deprovision_list, 10) for instance in deprovision_list: logger.info( 'deprovisioning triggered for %s (reason: maximum lifetime exceeded)' % instance.get('id')) pbclient.do_instance_patch(instance['id'], {'to_be_deleted': True}) run_update.delay(instance.get('id')) if len(update_list) > 10: update_list = random.sample(update_list, 10) for instance in update_list: run_update.delay(instance.get('id'))
def publish_plugins(): """ ToDo: document. """ logger.info('provisioning plugins queried from worker') token = get_token() mgr = get_provisioning_manager() for plugin in mgr.names(): payload = {'plugin': plugin} res = mgr.map_method([plugin], 'get_configuration') if not len(res): logger.warn('plugin returned empty configuration: %s' % plugin) continue config = res[0] if not config: logger.warn('No config for %s obtained' % plugin) continue for key in ('schema', 'form', 'model'): payload[key] = json.dumps(config.get(key, {})) do_post(token, 'plugins', payload)