terrac
Version:
A minimal private module registry for Terraform and OpenTofu
116 lines (115 loc) • 4.36 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BackendGCP = exports.configSchemaGCP = void 0;
const shared_1 = require("./shared");
const errors_1 = require("../errors");
const storage_1 = require("@google-cloud/storage");
const lodash_1 = require("lodash");
const Joi = require("joi");
exports.configSchemaGCP = Joi.object({
type: Joi.string().allow('gcp').required().description('Backend type'),
bucket: Joi.string().required().description('Bucket name'),
projectId: Joi.string().required().description('Google Cloud project ID for the bucket'),
pathPrefix: Joi.string().optional().allow('').description('Object path prefix'),
});
class BackendGCP {
constructor(config) {
this.config = config;
this.apiEndpoint = process.env.TERRAC_BACKEND_GCP_API_ENDPOINT || 'https://www.googleapis.com';
this.client = new storage_1.Storage({
apiEndpoint: process.env.TERRAC_BACKEND_GCP_API_ENDPOINT,
projectId: this.config.projectId,
});
}
async upload(name, version, packagePath) {
await this.uploadFile(this.getPackagePath(name, version), packagePath);
}
async getSourceUrl(name, version) {
let targetVersion = version;
if (!targetVersion) {
const meta = await this.getMeta(name);
targetVersion = meta.version;
}
const path = this.getPackagePath(name, targetVersion);
if (!this.pathExists(path)) {
throw new errors_1.ModuleNotFoundError();
}
return `gcs::${this.apiEndpoint}/storage/v1/${this.config.bucket}/${path}`;
}
async list(name) {
const moduleList = [];
const prefix = this.config.pathPrefix || '';
if (name) {
if (!(await this.pathExists(this.getMetaPath(name)))) {
throw new errors_1.ModuleNotFoundError();
}
const meta = await this.getMeta(name);
for (const release of meta.releases) {
moduleList.push({
name,
version: release.version,
});
}
}
else {
const keys = await this.listPaths(prefix);
const names = (0, lodash_1.uniq)(keys.map(key => key.replace(prefix, '').split('/').shift()));
for (const name of names) {
moduleList.push({
name,
});
}
}
return moduleList;
}
async exists(name, version) {
const path = version ? this.getPackagePath(name, version) : this.getMetaPath(name);
return this.pathExists(path);
}
async getMeta(name) {
const bucket = this.config.bucket;
const path = this.getMetaPath(name);
if (await this.pathExists(path)) {
const result = await this.client.bucket(bucket).file(path).download();
return JSON.parse(result[0].toString());
}
return (0, shared_1.getNewMeta)(name);
}
async saveMeta(meta) {
const metaKey = this.getMetaPath(meta.name);
await this.uploadObject(metaKey, JSON.stringify(meta));
}
async uploadFile(path, localFilePath) {
await this.client
.bucket(this.config.bucket)
.upload(localFilePath, {
destination: path,
});
}
async uploadObject(path, data) {
await this.client
.bucket(this.config.bucket)
.file(path)
.save(data);
}
async pathExists(path) {
const result = await this.client.bucket(this.config.bucket).file(path).exists();
return result[0];
}
async listPaths(prefix) {
const options = { prefix };
const [files] = await this.client.bucket(this.config.bucket).getFiles(options);
return files.map(file => file.name);
}
getMetaPath(name) {
const basePath = `${name}/meta.json`;
return this.config.pathPrefix ? `${this.config.pathPrefix}${basePath}` : basePath;
}
getPackagePath(name, version) {
var _a;
const basePath = `${name}/${version}/module.zip`;
const pathPrefix = (_a = this.config.pathPrefix) !== null && _a !== void 0 ? _a : '';
return `${pathPrefix}${basePath}`;
}
}
exports.BackendGCP = BackendGCP;