UNPKG

@intuitionrobotics/google-services

Version:
153 lines 7.34 kB
import { __stringify, BadImplementationException, ImplementationMissingException, Module, ThisShouldNotHappenException, timeout, filterInstances } from "@intuitionrobotics/ts-common"; import { cloudresourcemanager_v1, cloudresourcemanager_v2, serviceusage_v1 } from "googleapis"; import { AuthModule } from "./AuthModule.js"; const Serviceusage = serviceusage_v1.Serviceusage; const Cloudresourcemanager = cloudresourcemanager_v2.Cloudresourcemanager; const CloudresourcemanagerV1 = cloudresourcemanager_v1.Cloudresourcemanager; import { GCPScope, ServiceKey } from "./consts.js"; export class GoogleCloudManager_Class extends Module { cloudServicesManagerAPI; cloudResourcesManagerAPI; cloudResourcesManagerAPIv1; constructor() { super("GoogleCloudManager"); this.setDefaultConfig({ scopes: [GCPScope.CloudPlatform] }); } init() { this.cloudServicesManagerAPI = new Serviceusage(AuthModule.getAuth(this.config.authKey, this.config.scopes, 'v1')); this.cloudResourcesManagerAPI = new Cloudresourcemanager(AuthModule.getAuth(this.config.authKey, this.config.scopes)); this.cloudResourcesManagerAPIv1 = new CloudresourcemanagerV1(AuthModule.getAuth(this.config.authKey, this.config.scopes, 'v1')); } // FOLDERS async getOrCreateFolder(parentFolderId, folderName) { if (parentFolderId === undefined) throw new BadImplementationException("MUST provide a parentFolderId"); if (folderName === undefined) throw new BadImplementationException("MUST provide a folderName"); const folders = await this.queryFolders({ parentId: parentFolderId, folderName }); let parentFolder; if (folders.length > 1) throw new ThisShouldNotHappenException("too many folders for query..."); else if (folders.length === 1) parentFolder = folders[0]; else parentFolder = await this.createFolder({ parentId: parentFolderId, folderName }); if (!parentFolder) throw new BadImplementationException("MUST be parentFolder"); return this.getFolderId(parentFolder); } async createFolder(_request) { const request = { parent: `folders/${_request.parentId}`, requestBody: { displayName: _request.folderName } }; this.logInfo(`Creating GCP folder "${_request.parentId}/${_request.folderName}"`); const res = await this.cloudResourcesManagerAPI.folders.create(request); return await this._waitForFolderOperation(res.data.name); } async queryFolders(_query) { const query = { query: `parent=folders/${_query.parentId} AND displayName=${_query.folderName}` }; const res = await this.cloudResourcesManagerAPI.folders.search({ requestBody: query }); return res.data.folders || []; } getFolderId(folder) { return folder.name.replace("folders/", ""); } async _waitForFolderOperation(name) { let retry = 5; while (retry >= 0) { await timeout(2000); const res = await this.cloudResourcesManagerAPI.operations.get({ name }); if (res.data.done) return res.data.response; retry--; } throw new ImplementationMissingException("need better handling here.."); } // PROJECTS async listProjects(filter = () => true) { const results = await this.cloudResourcesManagerAPIv1.projects.list(); const projects = results.data.projects || []; return projects.filter(filter); } async getOrCreateProjects(parentId, ...projects) { const existingProjects = await this.listProjects(gcproject => !!projects.find(project => project.name === gcproject.name)); const projectsToCreate = projects .filter((project) => !existingProjects.find((gcproject) => gcproject.name === project.name)); const newProjects = await Promise.all(projectsToCreate.map(project => this.createProject(parentId, project.projectId, project.name))); const allProjects = filterInstances([...existingProjects, ...newProjects]); return projects.map(project => allProjects.find(gcpProject => gcpProject.name === project.name)); } async createProject(parentId, projectId, name = projectId) { const options = { projectId, name, parent: { type: "folder", id: parentId } }; this.logInfo(`Creating GCP Project "${parentId}/${projectId}/${name}"`); const response = await this.cloudResourcesManagerAPIv1.projects.create({ requestBody: options }); return this._waitForProjectOperation(response.data.name); } async _waitForProjectOperation(name) { let retry = 5; while (retry >= 0) { await timeout(2000); const res = await this.cloudResourcesManagerAPIv1.operations.get({ name }); if (res.data.done) return res.data.response; retry--; } throw new ImplementationMissingException("need better handling here.."); } // SERVICES async getService(serviceKey, projectId) { const res = await this.cloudServicesManagerAPI.services.get({ name: `projects/${projectId}/services/${serviceKey}` }); return res.data; } async enableService(serviceKey, enable, ...projectIds) { this.logInfo(`Enabling Service "${serviceKey}" for projects: ${__stringify(projectIds)}`); return Promise.all(projectIds.map(projectId => this._enableService(serviceKey, projectId, enable))); } async _enableService(serviceKey, projectId, enable = true) { let service = await this.getService(serviceKey, projectId); if (this._isEnabled(service) === enable) return this.logVerbose(`Service "${serviceKey}" was already enabled for project: ${projectId}`); const name = service.name; let res; if (enable) res = await this.cloudServicesManagerAPI.services.enable({ name }); else res = await this.cloudServicesManagerAPI.services.disable({ name }); service = await this._waitForServiceOperation(res.data.name); if (this._isEnabled(service)) this.logVerbose(`Service "${serviceKey}" is now enabled for project: ${projectId}`); else this.logError(`Service "${serviceKey}" is now disabled for project: ${projectId}`); return service; } async _waitForServiceOperation(name) { let retry = 5; while (retry >= 0) { await timeout(2000); const res = await this.cloudServicesManagerAPI.operations.get({ name }); if (res.data.done) return res.data.response?.service; retry--; } throw new ImplementationMissingException("need better handling here.."); } async isEnabled(serviceKey, projectId) { const service = await this.getService(serviceKey, projectId); return this._isEnabled(service); } _isEnabled(service) { return service.state === "ENABLED"; } } export const GoogleCloudManager = new GoogleCloudManager_Class(); //# sourceMappingURL=GoogleCloudModule.js.map