UNPKG

@adityasinghal26/plugin-oracle-cloud-backend

Version:

A backend plugin implementation to connect to the Oracle Cloud API.

518 lines (507 loc) 22 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var backendCommon = require('@backstage/backend-common'); var express = require('express'); var Router = require('express-promise-router'); var common = require('oci-common'); var identity = require('oci-identity'); var artifacts = require('oci-artifacts'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var express__default = /*#__PURE__*/_interopDefaultLegacy(express); var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router); var common__namespace = /*#__PURE__*/_interopNamespace(common); var identity__namespace = /*#__PURE__*/_interopNamespace(identity); var artifacts__namespace = /*#__PURE__*/_interopNamespace(artifacts); var __defProp$1 = Object.defineProperty; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$1 = (obj, key, value) => { __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; class OracleCloudApi { constructor(logger, config, tenancyList) { /** * * @param logger - Object to add different logs to the server * @param config - Backend configuration loaded from app-config.*.yaml * @param tenancyList - List of Oracle Cloud tenancies configuration from config file * */ __publicField$1(this, "logger"); __publicField$1(this, "config"); __publicField$1(this, "tenancyList"); this.logger = logger; this.config = config; this.tenancyList = tenancyList; } /** * Read all tenancy configurations from config file * @param config - Root configuration from app-config.*.yaml file * @param options - Various options required to complement config * @returns A OracleCloudApi object that contains list of tenancies */ static fromConfiguration(config, options) { var _a; const { logger } = options; const DEFAULT_ORACLE_TENANCY_NAME = "default"; const DEFAULT_ORACLE_TENANCY_PROFILE = "DEFAULT"; const oracleCloudConfig = config.getConfig("oracleCloud"); const tenancyConfigList = ((_a = oracleCloudConfig.getOptionalConfigArray("tenancies")) == null ? void 0 : _a.map((c) => ({ tenancyName: c.getString("tenancyName"), configFilePath: c.getString("configFilePath"), defaultProfile: c.getOptionalString("defaultProfile") ? c.getOptionalString("defaultProfile") : DEFAULT_ORACLE_TENANCY_PROFILE }))) || []; const defaultTenancyName = DEFAULT_ORACLE_TENANCY_NAME; const defaultTenancyConfigFilePath = oracleCloudConfig.getOptionalString("configFilePath"); const defaultTenancyProfile = oracleCloudConfig.getOptionalString("defaultProfile") ? oracleCloudConfig.getOptionalString("defaultProfile") : DEFAULT_ORACLE_TENANCY_PROFILE; const checkNamedDefault = tenancyConfigList.some( (x) => x.tenancyName === defaultTenancyName ); if (checkNamedDefault && (defaultTenancyConfigFilePath || defaultTenancyProfile)) { throw new Error( `Found Oracle Cloud tenancy with name ${defaultTenancyName} at both array level and top level configFilePath or defaultProfile config. Use only one style of config.` ); } const defaultNonePresent = !defaultTenancyConfigFilePath && !defaultTenancyProfile; const defaultAllPresent = defaultTenancyConfigFilePath && defaultTenancyProfile; if (!(defaultNonePresent || defaultAllPresent)) { throw new Error( `Found partial default Oracle Cloud config. All (or none) of configFilePath and defaultProfile must be provided.` ); } if (defaultAllPresent) { const defaultTenancyConfig = [ { tenancyName: defaultTenancyName, configFilePath: defaultTenancyConfigFilePath, defaultProfile: defaultTenancyProfile } ]; const tenancyList = [ ...tenancyConfigList, ...defaultTenancyConfig ]; return new OracleCloudApi(logger, config, tenancyList); } return new OracleCloudApi(logger, config, tenancyConfigList); } /** * Reads configuration for a particular tenancy * @param name - Name of the tenancy for which config is required * @returns configurationFilePath and defaultProfile from the config * @public */ async getTenancyConfiguration(name) { var _a, _b, _c; (_a = this.logger) == null ? void 0 : _a.debug( `Getting Oracle Cloud tenancy config, for API client services` ); const options = { logger: this.logger }; const DEFAULT_ORACLE_TENANCY_NAME = "default"; const tenancyName = name ? name : DEFAULT_ORACLE_TENANCY_NAME; const tenancyList = OracleCloudApi.fromConfiguration(this.config, options).tenancyList; const checkTenancyInConfig = tenancyList.some( (x) => x.tenancyName === tenancyName ); if (!checkTenancyInConfig) { throw new Error( `Could not find config with name ${tenancyName} . Make sure that the tenancy is properly configured.` ); } const configurationFilePath = (_b = tenancyList.find( (x) => x.tenancyName === tenancyName )) == null ? void 0 : _b.configFilePath; const defaultProfile = (_c = tenancyList.find( (x) => x.tenancyName === tenancyName )) == null ? void 0 : _c.defaultProfile; return { configurationFilePath, defaultProfile }; } /** * Reads profile details map from config file * @param configurationFilePath - Path of the Oracle configuration file * @param profile - Profile to be used * @returns a Map of the configured Profile * @public */ async getProfileConfig(configurationFilePath, profile) { const configuration = common__namespace.ConfigFileReader.parseFileFromPath(configurationFilePath, profile); const configProfile = configuration.accumulator.configurationsByProfile.get(profile); return configProfile; } /** * Read profile details based on tenancy name * Gets the config file path and default profile for tenancy * and passes that to {@link getProfileConfig} for Profile details map * @param tenancyName - Name of the tenancy * @param profile - Profile to be used * @returns Profile details Map to read the configurations */ async getProfileConfigFromTenancy(tenancyName, profile) { const tenancyConfiguration = await this.getTenancyConfiguration(tenancyName); const requiredProfileName = profile ? profile : tenancyConfiguration.defaultProfile; const tenancyProfileConfig = await this.getProfileConfig(tenancyConfiguration.configurationFilePath, requiredProfileName); return tenancyProfileConfig; } /** * Creates provider for Oracle Downstream API modules * @param configurationFilePath - Path of the Oracle configuration file * @param profile - Profile to be used * @returns an instance of Oracle Authentication Details Provider * @public */ async getAuthenticationDetailsProvider(configurationFilePath, profile) { const provider = new common__namespace.ConfigFileAuthenticationDetailsProvider( configurationFilePath, profile ); return provider; } // private async getIaasApi<T>( // apiType: string, // ): Promise<T | undefined> { // const configurationFilePath = "~/your_config_location"; // const profile = "your_profile_name"; // const provider = await this.getAuthenticationDetailsProvider(configurationFilePath, profile); // switch(apiType) { // case 'artifacts': // return (await this.getArtifactsClient(provider)) as T; // case 'identity': // return (await this.getIdentityClient(provider)) as T; // default: // return undefined; // } // } } class IdentityApi extends OracleCloudApi { /** * Read all tenancy configurations from config file * @param config - Root configuration from app-config.*.yaml file * @param options - Various options required to complement config * @returns A IdentityApi object that contains list of tenancies */ static fromConfig(config, options) { const { logger } = options; const tenancyList = IdentityApi.fromConfiguration(config, options).tenancyList; return new IdentityApi(logger, config, tenancyList); } /** * Read config file and profile for an Identity API client * @param tenancyName - Name of the tenancy * @param profile - Name of the profile for getting the client * @returns an instance of {@link IdentityClient} to trigger Identity REST APIs * @public */ async getIdentityClient(tenancyName, profile) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Creating Oracle Cloud REST API client, for Identity services` ); const { configurationFilePath, defaultProfile } = await this.getTenancyConfiguration(tenancyName); const requiredProfile = profile ? profile : defaultProfile; const provider = await super.getAuthenticationDetailsProvider(configurationFilePath, requiredProfile); const client = new identity__namespace.IdentityClient({ authenticationDetailsProvider: provider }); return client; } /** * Fetch the details of the tenancy configured * based on the tenancyId for a certain config file and profile * @param tenancyName - Name of the tenancy * @param profile - Profile to be used from the config file * @returns an instance of {@link GetTenancyResponse} from Identity Responses * @public */ async getTenancy(tenancyName, profile) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Calling Oracle Cloud REST API, for getting ${tenancyName} tenancy details` ); const apiClient = this.getIdentityClient(tenancyName, profile); const tenancyProfileConfig = await super.getProfileConfigFromTenancy(tenancyName, profile); const response = await (await apiClient).getTenancy({ tenancyId: tenancyProfileConfig.get("tenancy") }); return response; } /** * Get the list of compartments in Tenancy * @param tenancyName - Name of the tenancy * @param profile - Profile to be used * @param compartmentName - Name of the compartment to filter with (if any) * @returns an instance of {@link ListCompartmentsResponse} with compartment items * @public */ async getCompartmentsInTenancy(tenancyName, profile, compartmentName) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Calling Oracle Cloud REST API, for getting ${tenancyName} compartment details` ); const tenancyProfileConfig = await super.getProfileConfigFromTenancy(tenancyName, profile); const apiClient = await this.getIdentityClient(tenancyName, profile); const response = await apiClient.listCompartments({ compartmentId: tenancyProfileConfig.get("tenancy"), name: compartmentName }); return response; } /** * Get the details of the compartment in a tenancy * @param compartmentName - Name of the compartment to get details for * @param tenancyName - Name of the tenancy * @param profile - Profile to be used * @returns an instance of {@link GetCompartmentResponse} with compartment model * @public */ async getCompartmentDetailsInTenancy(compartmentName, tenancyName, profile) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Calling Oracle Cloud REST API, for getting ${compartmentName} compartment details` ); if (!compartmentName) { throw new Error( `No compartment name was provided in the query parameters.` ); } const tenancyProfileConfig = await super.getProfileConfigFromTenancy(tenancyName, profile); const compartmentList = (await this.getCompartmentsInTenancy(tenancyName, profile, compartmentName)).items; const requiredCompartment = compartmentList.filter( (compartment) => compartment.compartmentId === tenancyProfileConfig.get("tenancy") ); const apiClient = await this.getIdentityClient(tenancyName, profile); if (requiredCompartment.length < 1) { throw new Error( `No compartment found with name '${compartmentName}' in tenancy '${tenancyName}'` ); } if (requiredCompartment.length > 1) { throw new Error( `Multiple compartments found with name '${compartmentName}' in tenancy '${tenancyName}'` ); } const response = await apiClient.getCompartment({ compartmentId: requiredCompartment[0].id }); return response; } } var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; class ArtifactsApi extends OracleCloudApi { constructor(logger, config, tenancyList, identityApi) { super(logger, config, tenancyList); __publicField(this, "identityApi"); this.identityApi = identityApi; } /** * Read all tenancy configurations from config file * @param config - Root configuration from app-config.*.yaml file * @param options - Various options required to complement config * @returns A ArtifactsApi object that contains list of tenancies */ static fromConfig(config, options) { const { logger } = options; const tenancyList = ArtifactsApi.fromConfiguration(config, options).tenancyList; const identityApi = IdentityApi.fromConfig(config, options); return new ArtifactsApi(logger, config, tenancyList, identityApi); } /** * Read config file and profile for an Artifacts API client * @param tenancyName - Name of the tenancy * @param profile - Name of the profile for getting the client * @returns an instance of ArtifactsClient to trigger Artifacts REST APIs * @public */ async getArtifactsClient(tenancyName, profile) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Creating Oracle Cloud REST API client, for Artifacts services` ); const { configurationFilePath, defaultProfile } = await this.getTenancyConfiguration(tenancyName); const requiredProfile = profile ? profile : defaultProfile; const provider = await super.getAuthenticationDetailsProvider(configurationFilePath, requiredProfile); const client = new artifacts__namespace.ArtifactsClient({ authenticationDetailsProvider: provider }); return client; } /** * Fetch the list and the details of the container repositories present * based on the compartment name for a certain config file and profile * @param compartmentName - Name of the compartment * @param tenancyName - Name of the tenancy * @param profile - Profile to be used from the config file * @returns an instance of GetTenancyResponse from Identity Responses * @public */ async getContainerRepositories(compartmentName, tenancyName, profile) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Calling Oracle Cloud REST API, for getting ${compartmentName} container repositories` ); if (!compartmentName) { throw new Error( `No compartment name was provided in the query parameters.` ); } const apiClient = await this.getArtifactsClient(tenancyName, profile); const compartmentDetails = await this.identityApi.getCompartmentDetailsInTenancy(compartmentName, tenancyName, profile); const response = await apiClient.listContainerRepositories({ compartmentId: compartmentDetails.compartment.id }); return response; } /** * Fetch the list and the details of the container images present based on * the compartment and repository name for a certain config file and profile * @param compartmentName - Name of the compartment * @param repositoryName - Name of the container repository * @param tenancyName - Name of the tenancy * @param profile - Profile to be used from the config file * @returns an instance of {@link ListContainerImagesResponse} from Identity Responses */ async getContainerImagesInRepository(compartmentName, repositoryName, tenancyName, profile) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Calling Oracle Cloud REST API, for getting images in ${compartmentName} container repository` ); if (!compartmentName || !repositoryName) { throw new Error( `No compartment or repository name was provided in the query parameters.` ); } const apiClient = await this.getArtifactsClient(tenancyName, profile); const compartmentDetails = await this.identityApi.getCompartmentDetailsInTenancy(compartmentName, tenancyName, profile); const response = await apiClient.listContainerImages({ compartmentId: compartmentDetails.compartment.id, repositoryName }); return response; } /** * Create a new container repository in a child compartment of Tenancy Root * @param compartmentName - Name of the compartment * @param repositoryName - Name of the container repository * @param tenancyName - Name of the tenancy * @param profile - Profile to be used from the config file * @returns */ async createContainerRepository(compartmentName, repositoryName, tenancyName, profile) { var _a; (_a = this.logger) == null ? void 0 : _a.debug( `Calling Oracle Cloud REST API, for creating repository in ${compartmentName}` ); if (!compartmentName || !repositoryName) { throw new Error( `No compartment or repository name was provided in the query parameters.` ); } const apiClient = await this.getArtifactsClient(tenancyName, profile); const compartmentDetails = await this.identityApi.getCompartmentDetailsInTenancy(compartmentName, tenancyName, profile); const response = await apiClient.createContainerRepository({ createContainerRepositoryDetails: { compartmentId: compartmentDetails.compartment.id, displayName: repositoryName, isImmutable: false, // Requirement is to set isImmutable as true, but that gives error as below: // Setting isImmutable is not currently supported isPublic: false } }); return response; } } async function createRouter(options) { const { logger, config } = options; const identityApi = options.identityApi || IdentityApi.fromConfig(config, { logger }); const artifactsApi = options.artifactsApi || ArtifactsApi.fromConfig(config, { logger }); const router = Router__default["default"](); router.use(express__default["default"].json()); router.get("/health", (_, response) => { logger.info("PONG!"); response.json({ status: "ok" }); }); router.get("/identity/tenancy", async (request, response) => { logger.info("Getting tenancy details!"); const tenancyName = request.query.tenancyName; const profile = request.query.profile; response.status(200).json( await identityApi.getTenancy(tenancyName, profile) ); }); router.get("/identity/tenancy/compartments", async (request, response) => { logger.info(`Getting compartment list`); const tenancyName = request.query.tenancyName; const profile = request.query.profile; const compartmentName = request.query.compartmentName; response.status(200).json( await identityApi.getCompartmentsInTenancy(tenancyName, profile, compartmentName) ); }); router.get("/identity/tenancy/compartment", async (request, response) => { logger.info(`Getting compartment details`); const tenancyName = request.query.tenancyName; const profile = request.query.profile; const compartmentName = request.query.compartmentName; response.status(200).json( await identityApi.getCompartmentDetailsInTenancy(compartmentName, tenancyName, profile) ); }); router.get("/artifacts/container/repositories", async (request, response) => { logger.info(`Getting container repositories list`); const tenancyName = request.query.tenancyName; const profile = request.query.profile; const compartmentName = request.query.compartmentName; response.status(200).json( await artifactsApi.getContainerRepositories(compartmentName, tenancyName, profile) ); }); router.post("/artifacts/container/repository", async (request, response) => { logger.info(`Create container repository in a compartment`); const tenancyName = request.query.tenancyName; const profile = request.query.profile; const compartmentName = request.query.compartmentName; const repositoryName = request.query.repositoryName; response.status(200).json( await artifactsApi.createContainerRepository(compartmentName, repositoryName, tenancyName, profile) ); }); router.get("/artifacts/container/repository/images", async (request, response) => { logger.info(`Getting container images list in a repository`); const tenancyName = request.query.tenancyName; const profile = request.query.profile; const compartmentName = request.query.compartmentName; const repositoryName = request.query.repositoryName; response.status(200).json( await artifactsApi.getContainerImagesInRepository(compartmentName, repositoryName, tenancyName, profile) ); }); router.use(backendCommon.errorHandler()); return router; } exports.createRouter = createRouter; //# sourceMappingURL=index.cjs.js.map