UNPKG

11.2 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22exports.loadRealms = exports.assertRealm = exports.getRemoteImageName = exports.getConfigurationNames = exports.templatize = exports.formatAsTable = exports.renderRealmFile = exports.getCurrentRealm = exports.setRealm = void 0;
23const backlib_1 = require("backlib");
24const fs = __importStar(require("fs-extra"));
25const Path = __importStar(require("path"));
26const utils_min_1 = require("utils-min");
27const docker_1 = require("./docker");
28const hook_1 = require("./hook");
29const k8s_1 = require("./k8s");
30const renderer_1 = require("./renderer");
31const utils_1 = require("./utils");
32const vdev_config_1 = require("./vdev-config");
33// --------- /Public Types --------- //
34// --------- Public Realms APIs --------- //
35/**
36 * Set/Change the current (k8s context and eventual google project). Only change what is needed.
37 * @param {*} realm the realm object.
38 * @return {profileChanged?: true, contextChanged?: true} return a change object with what has changed.
39 */
40async function setRealm(realm) {
41 const currentRealm = await getCurrentRealm(false);
42 const change = {};
43 // NOTE: When realm.project is undefined, it will set the gclougProject to undefined,
44 // which is fine since we want to avoid accidental operation to the project.
45 // FIXME: Needs to handle the case where realm.project is not defined (probably remove the current google project to make sure no side effect)
46 const hookReturn = await hook_1.callHook(realm, 'realm_set_begin', currentRealm);
47 if (hookReturn != null) {
48 change.profileChanged = true;
49 }
50 if (realm.context === null) {
51 console.log(`INFO: realm ${realm.name} does not have a kubernetes context, skipping 'kubectl config use-context ...' (current kubectl context still active)`);
52 }
53 else if (!currentRealm || currentRealm.context !== realm.context) {
54 change.contextChanged = true;
55 await k8s_1.setCurrentContext(realm.context);
56 }
57 return change;
58}
59exports.setRealm = setRealm;
60/**
61 * Get the current Realm. Return undefined if not found
62 */
63async function getCurrentRealm(check = true) {
64 const realms = await loadRealms();
65 const context = await k8s_1.getCurrentContext();
66 let realm;
67 for (let realmName in realms) {
68 let realmItem = realms[realmName];
69 if (realmItem.context === context) {
70 realm = realmItem;
71 break;
72 }
73 }
74 if (check && realm) {
75 await hook_1.callHook(realm, 'realm_check');
76 }
77 // if no context matching, try get the first realm that has no context
78 if (!realm) {
79 realm = Object.values(realms).find(r => r.context === null);
80 }
81 return realm;
82}
83exports.getCurrentRealm = getCurrentRealm;
84/**
85 * Render realm yaml file.
86 * @param realm
87 * @param name name of the yaml file (without extension)
88 * @return The yaml file path
89 */
90async function renderRealmFile(realm, name) {
91 const realmOutDir = getRealmOutDir(realm);
92 const srcYamlFile = await findKFile(realm, name);
93 const srcYamlFileName = Path.parse(srcYamlFile).base;
94 const srcYamlContent = await fs.readFile(srcYamlFile, 'utf8');
95 const outYamlFile = Path.join(realmOutDir, srcYamlFileName);
96 // render the content
97 var data = realm;
98 const outYamlContent = await renderer_1.render(srcYamlContent, data);
99 // for now, we do not generate do any template
100 await fs.ensureDir(realmOutDir);
101 await fs.writeFile(outYamlFile, outYamlContent);
102 return outYamlFile;
103}
104exports.renderRealmFile = renderRealmFile;
105function formatAsTable(realms, currentRealm) {
106 const txts = [];
107 const header = ' ' + 'REALM'.padEnd(20) + 'TYPE'.padEnd(12) + 'PROJECT/PROFILE'.padEnd(20) + 'CONTEXT';
108 txts.push(header);
109 const currentRealmName = (currentRealm) ? currentRealm.name : null;
110 const currentProject = (currentRealm) ? currentRealm.project : null;
111 for (let realm of Object.values(realms)) {
112 let row = (realm.name === currentRealmName) ? "* " : " ";
113 row += realm.name.padEnd(20);
114 row += realm.type.padEnd(12);
115 let profile = (realm.type === 'gcp') ? realm.project : realm.profile;
116 profile = (profile == null) ? '' : profile;
117 row += profile.padEnd(20);
118 row += (realm.context ? realm.context : 'NO CONTEXT FOUND');
119 txts.push(row);
120 }
121 return txts.join('\n');
122}
123exports.formatAsTable = formatAsTable;
124/**
125 * Templatize a set of yaml files
126 * @param resourceNames either a single name, comma deliminated set of names, or an array.
127 */
128async function templatize(realm, resourceNames) {
129 const names = await getConfigurationNames(realm, resourceNames);
130 const result = [];
131 for (let name of names) {
132 const path = await renderRealmFile(realm, name);
133 result.push({ name, path });
134 }
135 return result;
136}
137exports.templatize = templatize;
138// --------- /Resource Management --------- //
139/**
140 * Returns a list of k8s configuration file names for a given realm and optional configurations names delimited string or array.
141 * - If configurationNames is an array, then, just return as is.
142 * - If configurationNames is string (e.g., 'web-server, queue') then it will split on ',' and trim each item as returns.
143 * - If no resourceNames then returns all of the resourceNames for the realm.
144 */
145async function getConfigurationNames(realm, configurationNames) {
146 // Note: for now, we do the check if the realm has a context here, because this is called for each k*** commands
147 // TODO: Might want to make it more explicit, as validateRealmForKubectlCommand(realm)
148 if (realm.context === null) {
149 throw Error(`Realm '${realm.name}' does not have a Kubernetes context, cannot perform kubectly commands.`);
150 }
151 if (configurationNames) {
152 return utils_1.asNames(configurationNames);
153 }
154 else if (realm.defaultConfigurations) {
155 return realm.defaultConfigurations;
156 }
157 else {
158 return getAllConfigurationNames(realm);
159 }
160}
161exports.getConfigurationNames = getConfigurationNames;
162/**
163 * Note: right now assume remote is on gke cloud (gcr.io/)
164 * @param realm
165 * @param serviceName
166 */
167function getRemoteImageName(block, realm) {
168 return docker_1._getImageName(block, realm.registry);
169}
170exports.getRemoteImageName = getRemoteImageName;
171function assertRealm(realm) {
172 if (!realm) {
173 throw new Error(`No realm found, do a 'npm run realm' to see the list of realm, and 'npm run realm realm_name' to set a realm`);
174 }
175 return realm;
176}
177exports.assertRealm = assertRealm;
178// --------- Loader --------- //
179async function loadRealms(rootDir) {
180 var _a;
181 const rawConfig = await vdev_config_1.loadVdevConfig(rootDir);
182 const rawRealms = rawConfig.realms;
183 const realms = {};
184 const base = {
185 system: rawConfig.system,
186 };
187 // get the _common variables and delete it from the realm list
188 let _common = {};
189 if (rawRealms._common) {
190 _common = rawRealms._common;
191 delete rawRealms._common;
192 }
193 // Create the realm object
194 for (let name in rawRealms) {
195 const rawRealm = rawRealms[name];
196 // TODO: must do a deep merge
197 const realm = { ...base, ..._common, ...rawRealm };
198 // NOTE: this is needed in realm, because ktemplate does not know if the k8s yaml is related to which block
199 // TODO: need to throw error if realm have a imageTag override
200 realm.imageTag = rawConfig.imageTag;
201 //// determine the type
202 let type = 'local';
203 const context = realm.context;
204 if (context) {
205 if (context.startsWith('arn:aws')) {
206 type = 'aws';
207 realm.profile = (realm.profile != null) ? realm.profile : 'default';
208 }
209 else if (context.startsWith('gke')) {
210 type = 'gcp';
211 }
212 else if (realm.registry && realm.registry.includes('azurecr')) {
213 type = 'azure';
214 }
215 }
216 else {
217 realm.context = null;
218 }
219 realm.type = type;
220 //// determine registry
221 if (!realm.registry) {
222 if (type === 'local' && realm.context) { // do not create localhost registry for local realm without context
223 realm.registry = 'localhost:5000/';
224 }
225 else if (type === 'gcp') {
226 realm.registry = `gcr.io/${realm.project}/`;
227 }
228 else if (type === 'aws') {
229 console.log(`WARNING - realm ${realm.name} of type 'aws' must have a registry property in the vdev.yaml`);
230 }
231 }
232 // set the name
233 realm.name = name;
234 // set the yamlDirs from yamlDir
235 realm.yamlDirs = (_a = realm.yamlDirs) !== null && _a !== void 0 ? _a : utils_min_1.asArray(realm.yamlDir);
236 // Call hook to finish initializing the realm (i.e., realm type specific initialization)
237 // TODO: not sure this is the right place to init the current realm. This is loading the realm.
238 await hook_1.callHook(realm, 'realm_init');
239 realms[name] = realm;
240 }
241 return realms;
242}
243exports.loadRealms = loadRealms;
244// --------- /Loader --------- //
245// --------- Private Helpers --------- //
246/** Get all of the resourceNames for a given realm */
247async function getAllConfigurationNames(realm) {
248 const nameSet = new Set();
249 for (const yamlDir of realm.yamlDirs) {
250 const yamlFiles = await backlib_1.glob('*.yaml', yamlDir);
251 yamlFiles.forEach(file => { nameSet.add(Path.basename(file, '.yaml')); });
252 }
253 return Array.from(nameSet);
254}
255function getRealmOutDir(realm) {
256 return Path.join(realm.yamlDirs[0], '.out/', realm.name + '/');
257}
258// get the Original Kubernets Yaml file (which could be a template)
259async function findKFile(realm, kName) {
260 const fileName = `${kName.trim()}.yaml`;
261 for (const yamlDir of realm.yamlDirs) {
262 const file = Path.join(yamlDir, fileName);
263 if (await fs.pathExists(file)) {
264 return file;
265 }
266 }
267 throw new Error(`Kubernetes resource file ${fileName} not found in directories ${realm.yamlDirs.join(', ')}`);
268}
269async function cleanRealmOutDir(realm) {
270 await backlib_1.saferRemove(getRealmOutDir(realm));
271}
272// --------- /Private Helpers --------- //