@adityasinghal26/plugin-oracle-cloud-backend
Version:
A backend plugin implementation to connect to the Oracle Cloud API.
518 lines (507 loc) • 22 kB
JavaScript
;
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