UNPKG

@pradyumn-el/pollycli

Version:

pollycli lets users access the functionalities of Polly over a command line interface

217 lines (192 loc) 7.93 kB
const fs = require('fs'); const pollymsg = require('./message'); const { pollyApi } = require('./api-client'); import { organizationDetails } from './organization'; const envTemplate = '{"data":{"type":"environments","attributes":{"org_id":"",\ "resource_info":{"docker_repo":"","is_base_environment":true,"description":"",\ "base_docker_config":{"docker_repo":"","hash":"","tag":""},"base_kernel":"",\ "commit_hash":""},"resource_name":"","resource_access":"","is_hidden":false}}}'; function isFileValid(envFile) { try { if (fs.existsSync(envFile)) { // extracting file let envInfo = null; try { envInfo = fs.readFileSync(envFile) envInfo = JSON.parse(envInfo); } catch (error) { pollymsg.pollyError(`File ${envFile} not valid.`) } } else { pollymsg.pollyError(`File ${envFile} does not exist.`) } } catch (error) { pollymsg.pollyError(`File path ${envFile} is not valid.`) } return true; } function isEnvInfoValid(envInfo) { // checking if necessary fiels are present const minRequiredKeys = ['name', 'description', 'docker_image', 'kernel']; const missingFields = minRequiredKeys.filter(x => !Object.keys(envInfo).includes(x) || !envInfo[x]); if (missingFields.length > 0) { pollymsg.pollyError("missing required fields: " + missingFields.join(", ")); } if (Object.keys(envInfo).includes('resource_access') && envInfo.resource_access != "public" && envInfo.resource_access != "private" ) { pollymsg.pollyError(`resource_access field should be either "public" or "private"`); } return true; } function getEnvReqBody(envInfo, org_id) { const envBody = JSON.parse(envTemplate); envBody.data.attributes.org_id = org_id; envBody.data.attributes.resource_name = envInfo.name; envBody.data.attributes.resource_info.description = envInfo.description; envBody.data.attributes.resource_info.docker_repo = envInfo.docker_image.split("/")[1].split(":")[0]; envBody.data.attributes.resource_info.base_kernel = envInfo.kernel; envBody.data.attributes.resource_info.commit_hash = envInfo.commit_hash; envBody.data.attributes.resource_access = !!envInfo.resource_access ? envInfo.resource_access : "private"; if(!!envInfo.base_env) { envBody.data.attributes.resource_info.base_docker_config = envInfo.base_env; envBody.data.attributes.resource_info.is_base_is_base_environment = false; } return envBody; } async function getDockerRepoInfo(org_id, docker_repo) { try { const dockerUrl = `/organizations/${org_id}/resources/dockers`+ `?filter[scope]=global&filter[resource_access]=public`+ `&filter[app_name]=${docker_repo}`; const dockerRes = await pollyApi.get(dockerUrl); return dockerRes.data.data[0]; } catch(e) { pollymsg.pollyError(`docker image ${docker_repo} not found`) } } async function getNotebookEnvInfo(org_id, env_name) { try { const envUrl = `/organizations/${org_id}/resources/environments`+ `?filter[app_name]=${env_name}`; const envRes = await pollyApi.get(envUrl); return envRes.data.data[0]; } catch(e) { pollymsg.pollyError(`notebook environment ${env_name} not found`); } } async function getDockerCommitHash(org_id, docker_image) { const docker_repo = docker_image.split(":")[0]; const docker_tag = docker_image.split(":")[1]; const docker_info = await getDockerRepoInfo(org_id, docker_repo); const commitUrl = `/organizations/${org_id}/resources/dockers`+ `/${docker_info.id}/commits`; const commit_res = await pollyApi.get(commitUrl); // loop through docker all the commits and match the tag for(let commit of commit_res.data.data) { if(commit.id == docker_tag) { // return the latest hash incase multiple hashes exist for same tag return Object.keys(commit.attributes.commit_info).pop().split("sha256:")[1]; } } pollymsg.pollyError(`tag ${docker_tag} for image ${docker_repo} not present`); } export async function createEnvironment(envFile, envInfo) { try { if(envFile && isFileValid(envFile)) { envInfo = fs.readFileSync(envFile) envInfo = JSON.parse(envInfo); } isEnvInfoValid(envInfo); const { org_id } = await organizationDetails(); envInfo.commit_hash = await getDockerCommitHash(org_id, envInfo.docker_image); if(!!envInfo.base_env) { const base_env_info = await getNotebookEnvInfo(org_id, envInfo.base_env); envInfo.base_env = { "docker_repo": base_env_info.attributes.resource_info.docker_repo, "hash": base_env_info.attributes.resource_info.latest_commits.pop(), }; } const envBody = getEnvReqBody(envInfo, org_id); const envUrl = `/organizations/${org_id}/resources/environments` await pollyApi.post(envUrl, envBody); pollymsg.pollySuccess(`${envInfo.name} notebook environment created`); } catch(e) { if(e.response.status == 409) { return pollymsg.pollyError(`Name ${envInfo.name} already in use`); } pollymsg.pollyError("Unable to create notebook environment"); } } export async function updateEnvironment(env_name, envInfo) { try { if(!env_name) { pollymsg.pollyError(`missing required argument --env-name`); } const { org_id, slug } = await organizationDetails(); const nb_env = await getNotebookEnvInfo(org_id, slug+"/"+env_name); const envUrl = `/organizations/${org_id}/resources/environments/${nb_env.id}`; const reqBody = { "data": { "type": "environments", "id": nb_env.id, "attributes": { "resource_info": {} } } } if(!!envInfo.tag) { let docker_repo = nb_env.attributes.resource_info.docker_repo; docker_repo = docker_repo.split(":")[0] + ":" + envInfo.tag; const commit_hash = await getDockerCommitHash(org_id, docker_repo); reqBody.data.attributes.resource_info.commit_hash = commit_hash; } if(!!envInfo.description) { reqBody.data.attributes.resource_info.description = envInfo.description; } if(!!envInfo.resource_access && (envInfo.resource_access == "public" || envInfo.resource_access == "private")) { reqBody.data.attributes.resource_access = envInfo.resource_access; } if(Object.keys(reqBody.data.attributes.resource_info).length === 0 && !reqBody.data.attributes.resource_access) { return pollymsg.pollySuccess(`${env_name} notebook environment unchanged`); } await pollyApi.patch(envUrl, reqBody); pollymsg.pollySuccess(`${env_name} notebook environment updated`); } catch(e) { pollymsg.pollyError("unable to update notebook environment"); } } export async function removeEnvironment(env_name) { try { const { org_id, slug } = await organizationDetails(); const nb_env = await getNotebookEnvInfo(org_id, slug+"/"+env_name); const envUrl = `/organizations/${org_id}/resources/environments/${nb_env.id}` const reqBody = { "data": { "type": "environments", "id": nb_env.id, "attributes": { "is_hidden": true } } } await pollyApi.patch(envUrl, reqBody); pollymsg.pollySuccess(`${env_name} notebook environment removed`); } catch(e) { pollymsg.pollyError("unable to remove notebook environment"); } } export function sampleEnvFormat() { const envFormat = { "name": "Display name of you environment", "description": "small description of you environment", "docker_image": "docker image with org slug and tag", "kernel": "base kernel of your image (py2, py3, r, sos)", "resource_access": "(optional) public/private", "base_env": "(optional) name of base docker env for building this image" } console.log(envFormat); }