def api_model_update(modelname): """ Deploys new bundle """ bundle = request.data # Write bundle bundle_path = tempfile.mkdtemp() + '/bundle.yaml' with open(bundle_path, 'w+') as bundle_file: bundle_file.write(bundle) # Create environment from bundle if not exist, else deploy bundle if JujuEnvironment.env_exists(modelname): env = JujuEnvironment(modelname) output = env.deploy_bundle(bundle_path, '--skip-unit-wait') else: try: output = subprocess.check_output( ['tengu', 'create-model', '--bundle', bundle_path, modelname], stderr=subprocess.STDOUT) except CalledProcessError as process_error: return create_response( 500, { "msg": "Failed to deploy bundle to environment {}. Output: {}". format(modelname, process_error.output) }) return create_response( 200, { "msg": "Sucessfully deployed bundle to environment {}. Output: {}".format( modelname, output) })
def c_export_juju_env(name, filename): """export juju environment to given yaml file """ jujuenv = JujuEnvironment(name) environment = {} environment['environment'] = jujuenv.return_environment() with open(filename, 'w+') as o_file: o_file.write(yaml.dump(environment, default_flow_style=False))
def c_add_machines(name): """Add machines of jfed experiment to Juju environment NAME: name of Tengu """ env_conf = init_environment_config(name) env = PROVIDER.get(env_conf) machines = env.machines machines.pop(0) jujuenv = JujuEnvironment(name) jujuenv.add_machines(machines)
def c_add_machines(model): """Add machines of jfed experiment to Juju environment NAME: name of model """ env_conf = init_environment_config(model) env = get_provider(env_conf).get(env_conf) machines = env.machines machines.pop(0) jujuenv = JujuEnvironment(model) jujuenv.add_machines(machines)
def c_destroy_model(name): """Destroys model with given name NAME: name of model """ if click.confirm( 'Warning! This will destroy both the Juju environment and the jFed experiment of the model "{}". Are you sure you want to continue?' .format(name)): jujuenv = JujuEnvironment(name) env_conf = init_environment_config(name) jujuenv.destroy(env_conf['locked']) provider_env = get_provider(env_conf).get(env_conf) provider_env.destroy()
def create_juju(env_conf, provider_env): if JujuEnvironment.env_exists(env_conf['env-name']): fail( "Juju environment already exists. Remove it first with 'tengu destroy {}'" .format(env_conf['env-name'])) try: machines = provider_env.machines except Exception as ex: # pylint: disable=W0703 fail("Could not get machines from manifest", ex) # Create Juju environment env_conf['juju-env-conf']['bootstrap-host'] = machines.pop(0) env_conf.save() wait_for_init(env_conf) return JujuEnvironment.create(env_conf['env-name'], env_conf['juju-env-conf']['bootstrap-host'], env_conf['juju-env-conf'], machines)
def api_hauchiwa_info(instance_id): """ Shows the info of the specified Hauchiwa instance """ if len(instance_id) > 10: return Response("instance_id cannot be longer than 10 characters", status=400, mimetype='text/plain') # get values from request #TODO: Authenticate this action #s4_cert = str(request.headers.get('emulab-s4-cert')) juju = JujuEnvironment(None) info = juju.status['services'].get('h-{}'.format(instance_id)) if info: info = { 'status': info['service-status'], 'public-address': info['units'].values()[0].get('public-address') } resp = Response( json.dumps(info), status=200, mimetype='application/json', ) else: resp = Response( 'Cannot find instance {}'.format(instance_id), status=404, mimetype='text/plain', ) resp.headers['location'] = '/hauchiwa/{}'.format(instance_id) resp.headers['Access-Control-Allow-Origin'] = 'tengu.intec.ugent.be' return resp
def upgrade(modelname, name): """ Shows the status of this hauchiwa instance """ env = JujuEnvironment(modelname) service = Service(name, env) service.upgrade() return create_response( 200, {"msg": 'Started upgrade of service {}'.format(name)})
def c_status(name): """Show status of Tengu with given name NAME: name of Tengu """ env_conf = init_environment_config(name) env = PROVIDER.get(env_conf) responsedict = env.status if responsedict['short_status'] == 'READY': statusdict = responsedict['json_output'] try: okblue("Status of experiment is {}".format( statusdict['AMs'].values()[0]['amGlobalSliverStatus'])) okblue("Experiment will expire at {}".format( statusdict['earliestSliverExpireDate'])) except (yaml.parser.ParserError, ValueError, KeyError) as exc: print("could not parse status from ouptut. statusdict: ") PPRINTER.pprint(statusdict) raise exc else: okwhite("Status of jfed slice is {}. responsedict: ".format( responsedict['short_status'])) PPRINTER.pprint(responsedict) if JujuEnvironment.env_exists(name): okblue('Juju environment exists') else: okwhite("Juju environment doesn't exist")
def create_juju(env_conf, provider_env): if JujuEnvironment.env_exists(env_conf['env-name']): fail("Juju environment already exists. Remove it first with 'tengu destroy {}'".format(env_conf['env-name'])) try: machines = provider_env.machines except Exception as ex: # pylint: disable=W0703 fail("Could not get machines from manifest", ex) # Create Juju environment env_conf['juju-env-conf']['bootstrap-host'] = machines.pop(0) env_conf.save() wait_for_init(env_conf) return JujuEnvironment.create( env_conf['env-name'], env_conf['juju-env-conf']['bootstrap-host'], env_conf['juju-env-conf'], machines )
def c_destroy_service(modelname, services): """Destroys given services MODELNAME: name of the model SERVICES: services to destroy""" jujuenv = JujuEnvironment(modelname) for servicename in jujuenv.status['services'].keys(): if servicename in services: Service(servicename, jujuenv).destroy(force=True)
def api_root(): """ Welcome message """ info = { "name":socket.gethostname(), "models": JujuEnvironment.list_environments(), "version": "1.0.0", # see http://semver.org/ } return create_response(200, info)
def c_export(name, path): """Export Tengu with given NAME""" jujuenv = JujuEnvironment(name) config = jujuenv.return_environment() files = { "tengu-env-conf": env_conf_path(name), } env_conf = init_environment_config(name) env = PROVIDER.get(env_conf) files.update(env.files) for f_name, f_path in files.iteritems(): with open(f_path, 'r') as f_file: config[f_name] = base64.b64encode(f_file.read()) config['emulab-project-name'] = global_conf['project-name'] export = {str(name): config} with open(path, 'w+') as outfile: outfile.write(yaml.dump(export))
def c_export_model(model, path): """Export the config of the model with given NAME""" jujuenv = JujuEnvironment(model) config = jujuenv.return_environment() files = { "tengu-env-conf": env_conf_path(model), } env_conf = init_environment_config(model) env = get_provider(env_conf).get(env_conf) files.update(env.files) for f_name, f_path in files.iteritems(): with open(f_path, 'r') as f_file: config[f_name] = base64.b64encode(f_file.read()) config['emulab-project-name'] = GLOBAL_CONF['project-name'] export = {str(model): config} with open(path, 'w+') as outfile: outfile.write(yaml.dump(export))
def api_model_update(modelname): """ Deploys new bundle """ bundle = request.data # Write bundle bundle_path = tempfile.mkdtemp() + '/bundle.yaml' with open(bundle_path, 'w+') as bundle_file: bundle_file.write(bundle) # Create environment from bundle if not exist, else deploy bundle if JujuEnvironment.env_exists(modelname): env = JujuEnvironment(modelname) output = env.deploy_bundle(bundle_path, '--skip-unit-wait') else: try: output = subprocess.check_output(['/opt/tengu/scripts/tengu.py', 'create', '--bundle', bundle_path, modelname]) except CalledProcessError as process_error: return create_response(500, {"msg": "Failed to deploy bundle to environment {}. Output: {}".format(modelname, process_error.output)}) return create_response(200, {"msg": "Sucessfully deployed bundle to environment {}. Output: {}".format(modelname, output)})
def api_hauchiwa_create(instance_id): """ Creates new tengu hauchiwa """ if len(instance_id) > 10: return Response("instance_id cannot be longer than 10 characters", status=400, mimetype="text/plain") # get values from request s4_cert = str(request.headers.get("emulab-s4-cert")) body = request.get_json() ssh_keys = body.get("ssh-keys", "") bundle = body.get("bundle", "") # Create config file hauchiwa_name = "h-{}".format(instance_id) hauchiwa_cfg = { str(hauchiwa_name): { "emulab-s4-cert": s4_cert, "emulab-project-name": "tengu", "charm-repo-source": "https://github.com/galgalesh/tengu-charms.git", "ssh-keys": str(",".join([DEFAULT_PUBKEYS, ssh_keys])), "bundle": bundle, } } hauchiwa_cfg_path = tempfile.mkdtemp() + "hauchiwa-cfg.yaml" with open(hauchiwa_cfg_path, "w+") as hauchiwa_cfg_file: hauchiwa_cfg_file.write(yaml.dump(hauchiwa_cfg, default_flow_style=False)) # Deploy Hauchiwa juju = JujuEnvironment(None) juju.deploy("local:hauchiwa", hauchiwa_name, config_path=hauchiwa_cfg_path, to="lxc:1") juju.add_relation(hauchiwa_name, "rest2jfed") juju.add_relation(hauchiwa_name, "dhcp-server") resp = Response("Created hauchiwa instance {}".format(instance_id), status=201, mimetype="text/plain") resp.headers["location"] = "/hauchiwa/{}".format(instance_id) return resp
def c_show_config(model, servicename): """Get the config of a service in a format that can be used to set the config of a service. NAME: name of model SERVICENAME: name of the service""" env = JujuEnvironment(model) service = Service(servicename, env) print( yaml.dump({str(servicename): service.get_config()}, default_flow_style=False))
def c_export(name, path): """Export Tengu with given NAME""" jujuenv = JujuEnvironment(name) config = jujuenv.return_environment() files = { "tengu-env-conf" : env_conf_path(name), } env_conf = init_environment_config(name) env = PROVIDER.get(env_conf) files.update(env.files) for f_name, f_path in files.iteritems(): with open(f_path, 'r') as f_file: config[f_name] = base64.b64encode(f_file.read()) config['emulab-project-name'] = global_conf['project-name'] export = { str(name) : config } with open(path, 'w+') as outfile: outfile.write(yaml.dump(export))
def c_expose_service(model, servicename): """ Expose the service so it is publicly available from the internet. NAME: name of model SERVICENAME: name of the service to expose""" env_conf = init_environment_config(model) provider_env = get_provider(env_conf).get(env_conf) env_conf = init_environment_config(model) env = JujuEnvironment(model) service = Service(servicename, env) provider_env.expose(service)
def api_hauchiwa(): """ Shows the status of the users Hauchiwa instances """ # get values from request s4_cert = str(request.headers.get('emulab-s4-cert')) juju = JujuEnvironment(None) services = juju.get_services('h-', 'emulab-s4-cert', s4_cert) lst = {} for service in services.keys(): lst[service] = { 'status' : services[service]['service-status'], 'public-address' : services[service]['units'].values()[0].get('public-address') } resp = Response( json.dumps(lst), status=200, mimetype='application/json', ) resp.headers['Access-Control-Allow-Origin'] = 'tengu.intec.ugent.be' return resp
def api_hauchiwa_create(instance_id): """ Creates new tengu hauchiwa """ if len(instance_id) > 10: return Response("instance_id cannot be longer than 10 characters", status=400, mimetype='text/plain') # get values from request s4_cert = str(request.headers.get('emulab-s4-cert')) body = request.get_json() ssh_keys = body.get('ssh-keys', "") bundle = body.get('bundle', "") # Create config file hauchiwa_name = 'h-{}'.format(instance_id) hauchiwa_cfg = { str(hauchiwa_name):{ 'emulab-s4-cert' : s4_cert, 'emulab-project-name' : "tengu", 'charm-repo-source' : "https://github.com/galgalesh/tengu-charms.git", 'ssh-keys' : str(','.join([DEFAULT_PUBKEYS, ssh_keys])), 'bundle' : bundle, } } hauchiwa_cfg_path = tempfile.mkdtemp() + 'hauchiwa-cfg.yaml' with open(hauchiwa_cfg_path, 'w+') as hauchiwa_cfg_file: hauchiwa_cfg_file.write(yaml.dump(hauchiwa_cfg, default_flow_style=False)) # Deploy Hauchiwa juju = JujuEnvironment(None) juju.deploy('local:hauchiwa', hauchiwa_name, config_path=hauchiwa_cfg_path, to='lxc:1') juju.add_relation(hauchiwa_name, 'rest2jfed') resp = Response( "Created hauchiwa instance {}".format(instance_id), status=201, mimetype='text/plain', ) resp.headers['location'] = '/hauchiwa/{}'.format(instance_id) resp.headers['Access-Control-Allow-Origin'] = 'tengu.intec.ugent.be' return resp
def api_hauchiwa(): """ Shows the status of the users Hauchiwa instances """ # get values from request s4_cert = str(request.headers.get('emulab-s4-cert')) juju = JujuEnvironment(None) services = juju.get_services('h-', 'emulab-s4-cert', s4_cert) lst = {} for service in services.keys(): lst[service] = { 'status': services[service]['service-status'], 'public-address': services[service]['units'].values()[0].get('public-address') } resp = Response( json.dumps(lst), status=200, mimetype='application/json', ) resp.headers['Access-Control-Allow-Origin'] = 'tengu.intec.ugent.be' return resp
def c_import(path): """Import Tengu from config file""" with open(path, 'r') as stream: export = yaml.load(stream) name = export.keys()[0] config = export.values()[0] if not os.path.isdir(os.path.dirname(env_conf_path(name))): os.makedirs(os.path.dirname(env_conf_path(name))) elif not click.confirm('Warning! Tengu with name {} already configured, are you sure you want to overwrite the config files?'.format(name)): exit() files = { "tengu-env-conf" : env_conf_path(name), } env_conf = init_environment_config(name) env = PROVIDER.get(env_conf) files.update(env.files) for f_key, f_path in files.iteritems(): with open(f_path, 'w+') as f_file: f_file.write(base64.b64decode(config[f_key])) global_conf['project_name'] = config['emulab-project-name'] global_conf.save() JujuEnvironment.import_environment(config)
def api_service_config_change(modelname, servicename): """ Change config of specified hauchiwa """ config = request.json juju = JujuEnvironment(modelname) service = Service(servicename, juju) try: service.set_config(config) except JujuException as exception: print(exception.message) return create_response(500, { "msg": 'config change failed', "output": exception.message }) return create_response(200, {"msg": 'Config change requested'})
def c_import(path): """Import Tengu from config file""" with open(path, 'r') as stream: export = yaml.load(stream) name = export.keys()[0] config = export.values()[0] if not os.path.isdir(os.path.dirname(env_conf_path(name))): os.makedirs(os.path.dirname(env_conf_path(name))) elif not click.confirm( 'Warning! Tengu with name {} already configured, are you sure you want to overwrite the config files?' .format(name)): exit() files = { "tengu-env-conf": env_conf_path(name), } env_conf = init_environment_config(name) env = PROVIDER.get(env_conf) files.update(env.files) for f_key, f_path in files.iteritems(): with open(f_path, 'w+') as f_file: f_file.write(base64.b64decode(config[f_key])) global_conf['project_name'] = config['emulab-project-name'] global_conf.save() JujuEnvironment.import_environment(config)
def c_reset_model(modelname): """ Destroys the model's services and containers except for lxc-networking, network-agent and openvpn. if whitelist is provided, only services in whitelist will be destroyed. NAME: name of model WHITELIST: names of charms to destroy """ if click.confirm( 'Warning! This will remove all services and containers of the model "{}". Are you sure you want to continue?' .format(modelname)): env_conf = init_environment_config(modelname) if env_conf['locked']: fail('Cannot reset locked environment') else: jujuenv = JujuEnvironment(modelname) for servicename in jujuenv.status['services'].keys(): if servicename not in [ 'lxc-networking', 'network-agent', 'openvpn' ]: # We should get these services from the init bundle... Service(servicename, jujuenv).destroy(force=True)
def api_info(): """ Shows the status of this hauchiwa instance """ # get values from request #TODO: Authenticate this action #s4_cert = str(request.headers.get('emulab-s4-cert')) env = JujuEnvironment(None) info = env.status if info: resp = Response( json.dumps(info), status=200, mimetype='application/json', ) else: resp = Response( "Environment {} doesn't exist or isn't bootstrapped".format( env.name), status=404, mimetype='text/plain', ) return resp
def api_root(): """ Welcome message """ id_status = {} # Check that the ID Token is valid. if FEATURE_FLAG_AUTH: if g.gplus_id: # Client library can verify the ID token. id_status['valid'] = True id_status['gplus_id'] = g.gplus_id id_status['message'] = 'ID Token is valid.' else: id_status['valid'] = False id_status['gplus_id'] = None id_status['message'] = 'Invalid ID Token.' info = { "name": socket.gethostname(), "models": JujuEnvironment.list_environments(), "version": "1.1.0", # see http://semver.org/ "request-id-token-status": id_status, } return create_response(200, info)
def c_status(name): """Show status of Tengu with given name NAME: name of Tengu """ env_conf = init_environment_config(name) env = PROVIDER.get(env_conf) responsedict = env.status if responsedict['short_status'] == 'READY': statusdict = responsedict['json_output'] try: okblue("Status of experiment is {}".format(statusdict['AMs'].values()[0]['amGlobalSliverStatus'])) okblue("Experiment will expire at {}".format(statusdict['earliestSliverExpireDate'])) except (yaml.parser.ParserError, ValueError, KeyError) as exc: print("could not parse status from ouptut. statusdict: ") PPRINTER.pprint(statusdict) raise exc else: okwhite("Status of jfed slice is {}. responsedict: ".format(responsedict['short_status'])) PPRINTER.pprint(responsedict) if JujuEnvironment.env_exists(name): okblue('Juju environment exists') else: okwhite("Juju environment doesn't exist")
def c_create_model(bundle, name, create_machines): """Create a model with given name. Skips slice creation if it already exists. NAME: name of model """ env_conf = init_environment_config(name) try: with open(bundle, 'r') as bundle_file: bundledict = yaml.load(bundle_file) except yaml.YAMLError as yamlerror: raise click.ClickException( 'Parsing bundle \033[91mfailed\033[0m: {}'.format(str(yamlerror))) downloadbigfiles(os.environ.get('JUJU_REPOSITORY', '')) if create_machines: provider_env = get_provider(env_conf).create_from_bundle( env_conf, bundledict) else: provider_env = get_provider(env_conf).get(env_conf) juju_env = JujuEnvironment.create( env_conf['env-name'], env_conf['juju-env-conf'], provider_env.machines, env_conf['init-bundle'], ) juju_env.deploy_bundle(bundle)
def api_hauchiwa_create(instance_id): """ Creates new tengu hauchiwa """ if len(instance_id) > 10: return Response("instance_id cannot be longer than 10 characters", status=400, mimetype='text/plain') # get values from request s4_cert = str(request.headers.get('emulab-s4-cert')) body = request.get_json() ssh_keys = body.get('ssh-keys', "") bundle = body.get('bundle', "") # Create config file hauchiwa_name = 'h-{}'.format(instance_id) hauchiwa_cfg = { str(hauchiwa_name): { 'emulab-s4-cert': s4_cert, 'emulab-project-name': "tengu", 'charm-repo-source': "https://github.com/galgalesh/tengu-charms.git", 'ssh-keys': str(','.join([DEFAULT_PUBKEYS, ssh_keys])), 'bundle': bundle, } } hauchiwa_cfg_path = tempfile.mkdtemp() + 'hauchiwa-cfg.yaml' with open(hauchiwa_cfg_path, 'w+') as hauchiwa_cfg_file: hauchiwa_cfg_file.write( yaml.dump(hauchiwa_cfg, default_flow_style=False)) # Deploy Hauchiwa juju = JujuEnvironment(None) juju.deploy('local:hauchiwa', hauchiwa_name, config_path=hauchiwa_cfg_path, to='lxc:1') juju.add_relation(hauchiwa_name, 'rest2jfed') resp = Response( "Created hauchiwa instance {}".format(instance_id), status=201, mimetype='text/plain', ) resp.headers['location'] = '/hauchiwa/{}'.format(instance_id) resp.headers['Access-Control-Allow-Origin'] = 'tengu.intec.ugent.be' return resp
def c_deploy(bundle, name): """Create a Tengu with given name. Skips slice creation if it already exists. NAME: name of Tengu """ downloadbigfiles(os.environ['JUJU_REPOSITORY']) juju_env = JujuEnvironment(name) juju_env.deploy_bundle(bundle)
# Own modules from output import okblue, fail, okwhite from config import Config, script_dir, tengu_dir from jujuhelpers import JujuEnvironment import jfed_provider import ssh_provider global_conf = Config(realpath(script_dir() + "/../etc/global-conf.yaml")) # pylint: disable=c0103 DEFAULT_ENV_CONF = realpath(script_dir() + "/../templates/env-conf.yaml.template") ENV_CONF_NAME = "env-conf.yaml" PPRINTER = pprint.PrettyPrinter() #PROVIDER = jfed_provider.JfedProvider(global_conf) PROVIDER = ssh_provider.SSHProvider(global_conf) DEFAULT_ENV = JujuEnvironment.current_env() def init_environment_config(env_name): """ Inits environment config. Does not override environment config if it exists """ config = Config(env_conf_path(env_name), default_path=DEFAULT_ENV_CONF) config['env-name'] = env_name config.save() return config def wait_for_init(env_conf): """Waits until VW prepare script has happened""" bootstrap_host = env_conf['juju-env-conf']['bootstrap-host'] bootstrap_user = env_conf['juju-env-conf']['bootstrap-user']
def api_service_config(modelname, servicename): """ Shows the info of the specified Hauchiwa instance """ juju = JujuEnvironment(modelname) service = Service(servicename, juju) info = service.config return create_response(200, info)
def api_model_info(modelname): """ Shows the status of this hauchiwa instance """ env = JujuEnvironment(modelname) info = env.status if info: return create_response(200, info)