@pulumi/gcp
Version:
A Pulumi package for creating and managing Google Cloud Platform resources.
174 lines • 8.57 kB
JavaScript
// Copyright 2016-2018, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpCallbackFunction = exports.CallbackFunction = void 0;
const pulumi = require("@pulumi/pulumi");
const cloudfunctions = require(".");
const storage = require("../storage");
const filepath = require("path");
const utils = require("../utils");
/**
* A CallbackFunction is a special type of gcp.cloudfunctions.Function that can be created out of an
* actual JavaScript function instance. The function instance will be analyzed and packaged up
* (including dependencies) into a form that can be used by Cloud Functions. See
* https://github.com/pulumi/docs/blob/master/reference/serializing-functions.md for additional
* details on this process.
*
* Note: CallbackFunctions create Google Cloud Functions that uses the [nodejs8] runtime.
* Importantly, calls follow the `(data, context) => ...` form, not the `(event, callback) => ...`
* form that is used with the [nodejs6] runtime. This also adds support for asynchronous functions
* as well. See
* https://cloud.google.com/functions/docs/writing/background#functions_background_parameters-node8
* for more details.
*/
class CallbackFunction extends pulumi.ComponentResource {
constructor(name, args, opts = {}) {
super("gcp:cloudfunctions:CallbackFunction", name, undefined, opts);
const parentOpts = { parent: this };
const handlerName = "handler";
const serializedFileNameNoExtension = "index";
const func = args.callback || args.callbackFactory;
if (!func) {
throw new Error("One of [callback] or [callbackFactory] must be provided.");
}
const closure = pulumi.runtime.serializeFunction(func, {
serialize: _ => true,
exportName: handlerName,
isFactoryFunction: !!args.callbackFactory,
});
const codePaths = computeCodePaths(closure, serializedFileNameNoExtension, args.codePathOptions);
// https://cloud.google.com/storage/docs/naming
//
// Bucket names must contain only lowercase letters, numbers, dashes (-), underscores (_),
// and dots.
const bucketName = name.toLowerCase().replace(/[^-_a-z0-9]/gi, "-");
this.bucket = args.bucket || new storage.Bucket(bucketName, {
project: args.project,
location: args.location || "US", // The default of "US" here is what it previously defaulted to
}, parentOpts);
this.bucketObject = new storage.BucketObject(`${name}`, {
bucket: this.bucket.name,
source: new pulumi.asset.AssetArchive(codePaths),
}, parentOpts);
const argsCopy = {
...args
};
// remove the values we've added on top of everything.
delete argsCopy.callback;
delete argsCopy.callbackFactory;
delete argsCopy.codePathOptions;
// Function names : can only contain letters, numbers, underscores and hyphens
const functionName = name.replace(/[^-_a-z0-9]/gi, "-");
this.function = new cloudfunctions.Function(functionName, {
...argsCopy,
runtime: utils.ifUndefined(args.runtime, "nodejs18"),
entryPoint: handlerName,
sourceArchiveBucket: this.bucket.name,
sourceArchiveObject: this.bucketObject.name,
}, parentOpts);
const invoker = new cloudfunctions.FunctionIamMember(`${functionName}-invoker`, {
project: this.function.project,
region: this.function.region,
cloudFunction: this.function.name,
role: utils.ifUndefined(args.iamRole, "roles/cloudfunctions.invoker"),
member: utils.ifUndefined(args.iamMember, "allUsers")
}, {
...parentOpts,
/**
* This alias exists to be backwards compatible for previous versions that did
* not set a parent on this resource.
* https://github.com/pulumi/pulumi-gcp/issues/543
*/
aliases: [{ parent: undefined }],
});
this.registerOutputs();
}
}
exports.CallbackFunction = CallbackFunction;
/**
* An http-triggered Cloud-Function that, when invoked, will execute the code supplied by a
* user-provided JavaScript-Function. To handle HTTP, Cloud Functions uses Express 4.16.3.
*
* You invoke HTTP functions from standard HTTP requests. These HTTP requests wait for the response
* and support handling of common HTTP request methods like GET, PUT, POST, DELETE and OPTIONS. When
* you use Cloud Functions, a TLS certificate is automatically provisioned for you, so all HTTP
* functions can be invoked via a secure connection.
*
* See more information at: https://cloud.google.com/functions/docs/writing/http
*/
class HttpCallbackFunction extends CallbackFunction {
constructor(name, callbackOrArgs, opts = {}) {
const argsCopy = callbackOrArgs instanceof Function
? { callback: callbackOrArgs, triggerHttp: true }
: { ...callbackOrArgs, triggerHttp: true };
super(name, argsCopy, opts);
this.httpsTriggerUrl = this.function.httpsTriggerUrl;
}
}
exports.HttpCallbackFunction = HttpCallbackFunction;
// computeCodePaths calculates an AssetMap of files to include in the Function package.
async function computeCodePaths(closure, serializedFileNameNoExtension, codePathOptions = {}) {
codePathOptions.extraIncludePaths = codePathOptions.extraIncludePaths || [];
codePathOptions.extraIncludePackages = codePathOptions.extraIncludePackages || [];
codePathOptions.extraExcludePackages = codePathOptions.extraExcludePackages || [];
if (codePathOptions.extraIncludePackages.length > 0) {
throw new pulumi.ResourceError("codePathOptions.extraIncludePackages not currently supported in GCP.", codePathOptions.logResource);
}
const serializedFunction = await closure;
const excludedPackages = new Set();
for (const p of codePathOptions.extraExcludePackages) {
excludedPackages.add(p);
}
// Include packages to package.json file
const packageJson = await producePackageJson(excludedPackages);
return {
// Always include the serialized function.
[serializedFileNameNoExtension + ".js"]: new pulumi.asset.StringAsset(serializedFunction.text),
// Include package.json and GCP will install packages for us
["package.json"]: new pulumi.asset.StringAsset(packageJson),
// Include files added by user
...processExtraIncludePaths(codePathOptions.extraIncludePaths)
};
}
// Get the list of packages declare in package.json, exclude pulumi and exclusions made by user,
// generate the new package.json to be uploaded to GCP.
// GCP will restore the packages itself.
async function producePackageJson(excludedPackages) {
const PackageJson = require("@npmcli/package-json");
const pkgJson = await PackageJson.load('./');
const packageJson = pkgJson.content;
// Override dependencies by removing @pulumi and excludedPackages
const dependencies = Object.keys(packageJson.dependencies || {})
.filter(pkg => !excludedPackages.has(pkg) && !pkg.startsWith("@pulumi"))
.reduce((obj, key) => {
obj[key] = packageJson.dependencies[key];
return obj;
}, {});
return JSON.stringify({
dependencies: dependencies,
});
}
// Create file assets from specified by user list,
// files will be added to the main directory under the file name thus duplicates will be overridden
// e.g. ['./dir1/file1', './file1'] will add only the last file.
function processExtraIncludePaths(extraIncludePaths) {
const filesToInclude = {};
for (const fullPath of extraIncludePaths) {
const fileName = filepath.basename(fullPath);
filesToInclude[fileName] = new pulumi.asset.FileAsset(fullPath);
}
return filesToInclude;
}
//# sourceMappingURL=zMixins.js.map
;