UNPKG

@vroomlabs/gsdk-deploy

Version:

Google Cloud deployment script for kubernetes clusters using Global Load Balancer

212 lines (185 loc) 8.14 kB
'use strict'; /****************************************************************************** * MIT License * Copyright (c) 2017 https://github.com/vroomlabs * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Created by rogerk on 7/2/17. ******************************************************************************/Object.defineProperty(exports,'__esModule',{value:true});exports.Configuration=undefined;var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if('value'in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor}}(); var _fs=require('fs');var fs=_interopRequireWildcard(_fs); var _path=require('path');var path=_interopRequireWildcard(_path); var _yamljs=require('yamljs');var YAML=_interopRequireWildcard(_yamljs); var _logger=require('../util/logger'); var _templateArg=require('../util/templateArg'); var _deployConfig=require('./deployConfig');function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key]}}newObj.default=obj;return newObj}}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError('Cannot call a class as a function')}}var Configuration=exports.Configuration=function(){ /** * @param {Arguments} args */ function Configuration(args){_classCallCheck(this,Configuration); if(!fs.existsSync(args.config)){ throw new Error('The configuration file was not found at:\n'+args.config); } if(!args.branch){ throw new Error('Specify a deployment/branch name with -branch=[NAME]'); } /** @type {DeployConfig} */ this.current=this._readConfig(args.config,args.branch); this._stateFile=path.join(args.artifacts,'deployConfig.json'); this.save(); this.current.assertValid(); this.name=this.current.name; this.project=this.current['google-project']; this.current.host=this.current.host.toLowerCase(); this.artifacts=args.artifacts; this.clusters={}; process.env.GCLOUD_PROJECT=this.project; process.env.SERVICE_NAME=this.name; process.env.HOSTNAME=this.current.host; process.env.NODE_PORT=this.getNodePort(); } /** * @private * @param {string} fileName * @param {string} deployName * @returns {DeployConfig} */_createClass(Configuration,[{key:'_readConfig',value:function _readConfig( fileName,deployName){ var cfg=void 0; var rawCfg=fs.readFileSync(fileName).toString(); if(fileName.match(/\.json$/)){ cfg=JSON.parse(rawCfg); }else if(fileName.match(/\.ya?ml$/)){ cfg=YAML.parse(rawCfg); }else { throw new Error('Unknown configuration type, supported types are (json|yaml).'); } if(!cfg.hasOwnProperty(deployName)){ throw new Error('The config file does not have a deployment called "'+deployName+'".'); } var current=Object.assign({},cfg[deployName]); while(current.extend||current.extends){ var baseType=current.extend||current.extends; delete current.extend; delete current.extends; if(!cfg.hasOwnProperty(baseType)){ throw new Error('The deployment extends unknown deployment called "'+baseType+'".'); } current=Object.assign({},cfg[baseType],current); } current=Object.assign(new _deployConfig.DeployConfig,current); current.path=path.resolve(fileName); return current; }},{key:'save',value:function save() { fs.writeFileSync(this._stateFile,JSON.stringify(this,null,2)); } /** * @returns {Array} returns an array of {name:string, value: string} objects */},{key:'getEnvironment',value:function getEnvironment() { var hasport=false; var env=this.current.env. filter(function(i){return typeof item==='string'||i.name}). map(function(item){ if(typeof item==='string'){ var m=item.match(/^([\w_-]+)(=(.*))?$/); item={name:m[1]}; if(typeof m[3]==='string') item.value=m[3]; } item.name=item.name.toUpperCase(); if(!item.hasOwnProperty('value')){ item.value='$'+item.name.toUpperCase(); } hasport=hasport||item.name==='NODE_PORT'; return item; }); if(!hasport){ env.push({name:'NODE_PORT',value:this.current.port.toString()}); } env=(0,_templateArg.replaceInObject)(env); return env; } /** * @returns {number} Returns the specified nodePort or generates one from name */},{key:'getNodePort',value:function getNodePort() { if(!(this.current.nodePort>0)){ // Compute a nodePort base on hash of the service name var crypto=require('crypto'); var md5sum=crypto.createHash('md5'); md5sum.update(this.name); var digits=md5sum.digest('hex'); var digit=parseInt(digits.substr(0,8))^parseInt(digits.substr(8,8))^ parseInt(digits.substr(16,8))^parseInt(digits.substr(24,8)); this.current.nodePort=30000+digit%2768; } if(this.current.nodePort<30000||this.current.nodePort>32767){ throw new Error('The node port '+this.current.nodePort+' is invalid.'); } return this.current.nodePort; } /** * Returns the fully-qualified api source files * @returns {string[]} */},{key:'getApiFiles',value:function getApiFiles() {var _this=this; var apiConfig=[].concat(this.current['api-config']||[]); var basePath=path.dirname(this.current.path); apiConfig=apiConfig.map(function(pth){return path.resolve(basePath,pth)});var _loop=function _loop( ix){ var fname=apiConfig[ix]; var fType=fname.match(/.ya?ml$/i)?YAML:fname.match(/.json$/i)?JSON:null; var cfg=fType?fType.parse(fs.readFileSync(fname).toString()):{}; var prop=null; if(cfg.type==='google.api.Service'&&cfg.name){prop='name'}else if(cfg.swagger&&cfg.swagger.toString().match(/^\d/)){prop='host'}else {return'continue'} // Replace the endpoint proper name with the value from endpointFormat var correctedName=(0,_templateArg.replaceInText)(_this.current.endpointFormat);; var newPath=path.join(_this.artifacts,path.basename(fname)); cfg[prop]=correctedName; _logger.logger.verbose('replaced service endpoint name',{'new':newPath,old:fname,value:cfg[prop]}); // ROK - look for endpoints collection and if it matches the last 2 segments, replace it, i.e. cloud.goog, or vroomapi.com match (cfg.endpoints||[]). forEach(function(ep){ if(ep.name&&ep.name.split('.').slice(-2).join('.')===correctedName.split('.').slice(-2).join('.')){ ep.name=correctedName; } }); fs.writeFileSync(newPath,fType.stringify(cfg,null,2)); apiConfig[ix]=newPath};for(var ix=0;ix<apiConfig.length&&this.current.endpointFormat;ix++){var _ret=_loop(ix);if(_ret==='continue')continue; } return apiConfig; } /** * @returns {string} - The version-specific tag that should be used */},{key:'getDockerTagFormat',value:function getDockerTagFormat() { var tagFormat=this.current.tagFormat; if(!tagFormat&&process.env.CIRCLE_SHA1&&process.env.CIRCLE_BUILD_NUM){ tagFormat='$BRANCH-$CIRCLE_SHA1-$CIRCLE_BUILD_NUM'; }else if(!tagFormat){ tagFormat+='$BRANCH-$BUILD_TIME'; } return tagFormat; }}]);return Configuration}();