def extend_autostop(uuid): """Extend the autostop timer.""" if not re_uuid.match(uuid): abort(400) cursor = get_cursor() cursor.execute('SELECT * FROM trials WHERE id = %s', (uuid,)) row = cursor.fetchone() if not row: abort(404) trial = rowdict(row, cursor.description) trial_cfg = cfgdict(app.config, trial['trial_name']) autostop = trial_cfg.get('autostop') if not autostop: abort(400) client = get_ravello_client(trial['trial_name']) application = client.get_application(trial['application_id']) exp_req = {'expirationFromNowSeconds': autostop*3600} client.set_application_expiration(application, exp_req) state = application_state(application) if state == 'STOPPED': client.start_application(application) elif state not in ('STARTING', 'STARTED'): abort(400) utcnow = datetime.utcnow().replace(tzinfo=pytz.UTC) trial['autostop_at'] = utcnow + timedelta(seconds=autostop*3600) fields = qset('autostop_at') cursor.execute('UPDATE trials set {0} WHERE id = %(id)s'.format(fields), trial) response = make_response() response.status_code = 204 # No content return response
def get_trial_dyn(uuid): """Get trial dynamic metadata.""" if not re_uuid.match(uuid): abort(400) cursor = get_cursor() cursor.execute('SELECT * FROM trials WHERE id = %s', (uuid,)) row = cursor.fetchone() if not row: abort(404) trial = rowdict(row, cursor.description) meta = {'id': trial['id'], 'status': trial['status']} utcnow = datetime.utcnow().replace(tzinfo=pytz.UTC) meta['expires_in'] = format_interval(trial['expires_at'] - utcnow) if trial['autostop_at']: meta['autostop_in'] = format_interval(trial['autostop_at'] - utcnow) if trial['status'] != 'READY': return jsonify(meta) client = get_ravello_client(trial['trial_name']) app = client.get_application(trial['application_id']) deploy = app.get('deployment', {}) meta['cloud'] = deploy.get('cloud') meta['region'] = deploy.get('regionName') state = application_state(app) if isinstance(state, list): if 'STARTING' in state: state = 'STARTING' elif 'STOPPING' in state: state = 'STOPPING' else: state = 'UNKNOWN' meta['status'] = state addr = get_service_addr(app, 'ssh') if addr: meta['ssh_addr'] = addr[0] addr = get_service_addr(app, 'http') if addr: meta['http_url'] = 'http://{2}:{1}/'.format(*addr) return jsonify(meta)
def complete_create_trial(uuid): """Complete the creation of a trial.""" conn = connect_database() cursor = conn.cursor() cursor.execute('SELECT * FROM trials WHERE id = %s', (uuid,)) row = cursor.fetchone() if row is None: raise ValueError('trial {!r} does not exist'.format(uuid)) trial = rowdict(row, cursor.description) trial_cfg = cfgdict(app.config, trial['trial_name']) trial['ssh_private_key'], trial['ssh_public_key'] = generate_keypair() ravello = connect_ravello(trial['trial_name']) blueprint_id = trial_cfg['blueprint'] description = 'Trial ({0}/{1})'.format(trial['trial_name'], filter_ascii(trial['name'])) application = {'name': 'trial-{0}'.format(uuid), 'description': description, 'baseBlueprintId': blueprint_id} application = ravello.create_application(application) trial['application_id'] = application['id'] # If cloudinit is available, we can use that to deploy the ssh key. cloudinit = trial_cfg['cloudinit'] if cloudinit: pubkey = {'name': 'trial-{0}'.format(uuid), 'publicKey': trial['ssh_public_key']} pubkey = ravello.create_keypair(pubkey) for vm in application.get('design', {}).get('vms', []): vm['keypairId'] = pubkey['id'] application = ravello.update_application(application) autostop = trial_cfg.get('autostop') if autostop: exp_req = {'expirationFromNowSeconds': autostop*3600} ravello.set_application_expiration(application, exp_req) nowutc = datetime.utcnow().replace(tzinfo=pytz.UTC) trial['autostop_at'] = nowutc + timedelta(seconds=autostop*3600) else: trial['autostop_at'] = None publish_cfg = cfgdict(app.config, '{0}_publish'.format(trial['trial_name']), 'publish') publish_req = {'preferredCloud': publish_cfg.get('cloud'), 'preferredRegion': publish_cfg.get('region'), 'optimizationLevel': publish_cfg.get('optimization'), 'startAllVms': True} publish_req = dict(((k,v) for k,v in publish_req.items() if v is not None)) ravello.publish_application(application['id'], publish_req) trial['status'] = 'BUILDING' fields = qset('ssh_private_key', 'ssh_public_key', 'application_id', 'status', 'autostop_at') cursor.execute('UPDATE trials set {0} WHERE id = %(id)s'.format(fields), trial) conn.commit() # At this point send the email. send_email(trial['email'], 'registered.txt', trial) # Wait for the application to come up ravello.wait_for(application, lambda app: application_state(app) == 'STARTED', 900) # Wait for ssh to come up. application = ravello.reload(application) ssh_addr = get_service_addr(application, 'ssh') ssh_timeout = trial_cfg.get('ssh_timeout', 300) if not wait_for_service(ssh_addr[:2], ssh_timeout): raise RuntimeError('error waiting for ssh service') privkey = trial_cfg.get('ssh_key') if not cloudinit and privkey: ssh = connect_ssh(ssh_addr[:2], privkey, 'root') pubkey = trial['ssh_public_key'].rstrip() ssh.communicate(textwrap.dedent("""\ cat >> .ssh/authorized_keys << EOM {0} EOM chmod 600 .ssh/authorized_keys """).format(pubkey).encode('ascii')) ssh.wait() if ssh.returncode != 0: raise RuntimeError('error deploying ssh key through ssh') # Optionally wait for another service service = trial_cfg.get('service') if service: svc_addr = get_service_addr(application, service) svc_timeout = trial_cfg.get('service_timeout', 300) if not wait_for_service(svc_addr[:2], svc_timeout): raise RuntimeError('error waiting for {!r} service'.format(service)) # Do we need to reboot? reboot = trial_cfg.get('reboot') if reboot: time.sleep(trial_cfg.get('reboot_delay', 60)) ssh = connect_ssh(ssh_addr[:2], privkey, 'root') ssh.communicate('shutdown -r now'.encode('ascii')) ssh.wait() time.sleep(trial_cfg.get('reboot_timeout', 30)) if not wait_for_service(ssh_addr[:2], ssh_timeout): raise RuntimeError('ssh did not come up after reboot') # Wait again for the service.. if service and not wait_for_service(svc_addr[:2], svc_timeout): raise RuntimeError('error waiting for {!r} service'.format(service)) # Mark as READY! time.sleep(trial_cfg.get('final_delay', 0)) trial['status'] = 'READY' fields = qset('status') cursor.execute('UPDATE trials SET {0} WHERE id = %(id)s'.format(fields), trial) conn.commit() cursor.close() conn.close()