@adpt/cloud
Version:
AdaptJS cloud component library
152 lines • 6.92 kB
JavaScript
;
/*
* Copyright 2018-2020 Unbounded Systems, LLC
*
* 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 });
const tslib_1 = require("tslib");
const core_1 = tslib_1.__importStar(require("@adpt/core"));
const resource_id_1 = require("../resource_id");
const cf_observer_1 = require("./cf_observer");
const credentials_1 = require("./credentials");
const stack_context_1 = require("./stack_context");
const resourceIds = resource_id_1.resourceIdList("StackName");
/** @beta */
class CFStackPrimitive extends core_1.PrimitiveComponent {
constructor() {
super(...arguments);
this.deployedWhen = async (goalStatus, helpers) => {
const hand = this.props.handle;
if (!hand)
throw new Error("Invalid handle");
const status = await helpers.elementStatus(hand);
if (!status)
return core_1.waiting("No status returned by EC2 API");
if (status.StackStatus) {
switch (status.StackStatus) {
case "CREATE_COMPLETE":
case "UPDATE_COMPLETE":
return goalStatus === core_1.DeployStatus.Deployed ? true :
core_1.waiting(`Unexpected StackStatus ${status.StackStatus}`);
case "DELETE_COMPLETE":
return goalStatus === core_1.DeployStatus.Destroyed ? true :
core_1.waiting(`Unexpected StackStatus ${status.StackStatus}`);
case "CREATE_IN_PROGRESS":
case "UPDATE_IN_PROGRESS":
case "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS":
case "REVIEW_IN_PROGRESS":
case "DELETE_IN_PROGRESS":
return core_1.waiting(status.StackStatus);
case "ROLLBACK_IN_PROGRESS":
case "ROLLBACK_COMPLETE":
case "UPDATE_ROLLBACK_IN_PROGRESS":
case "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS":
case "UPDATE_ROLLBACK_COMPLETE":
case "CREATE_FAILED":
case "ROLLBACK_FAILED":
case "UPDATE_ROLLBACK_FAILED":
case "DELETE_FAILED":
default:
throw new Error(`Operation failed (${status.StackStatus}): ` +
status.StackStatusReason);
}
}
if (status.noStatus === `Stack with id ${this.props.StackName} does not exist`) {
return goalStatus === core_1.DeployStatus.Destroyed ? true :
core_1.waiting(`Stack not found`);
}
if (typeof status.noStatus === "string") {
throw new Error("Unable to get status: " + status.noStatus);
}
throw new Error("Invalid status returned by EC2 API");
};
}
validate() {
try {
this.validateChildren(this.props.children);
}
catch (err) {
if (err instanceof Error && err.message === "Stack within stack") {
return "Nested CFStacks are not currently supported";
}
}
return;
}
// FIXME(mark): This *should* happen during DOM validation, but the
// time complexity of this sucks. A more efficient check would be to
// traverse parents to the root, looking for a CFStackPrimitive, but we
// don't currently have parent info in validate.
validateChildren(children) {
for (const k of core_1.childrenToArray(children)) {
if (isCFStackPrimitiveFinalElement(k))
throw new Error(`Stack within stack`);
if (core_1.isElement(k))
this.validateChildren(k.props.children);
}
}
async status(observe, buildData) {
const { awsCredentials, StackName } = this.props;
if (awsCredentials == null) {
throw new Error(`awsCredentials must be provided to CFStack`);
}
const obsP = observe(cf_observer_1.AwsCfObserver, core_1.gql `
query (
$input: DescribeStacksInput_input!,
$awsAccessKeyId: String!,
$awsSecretAccessKey: String!,
$awsRegion: String!
) {
withCredentials(
awsAccessKeyId: $awsAccessKeyId,
awsSecretAccessKey: $awsSecretAccessKey,
awsRegion: $awsRegion
) {
DescribeStacks(body: $input) @all(depth: 10)
}
}`, Object.assign({ input: { StackName } }, awsCredentials));
return core_1.mergeDefaultChildStatus(this.props, obsP, observe, buildData, (obs) => {
return obs.withCredentials.DescribeStacks.Stacks[0];
});
}
}
exports.CFStackPrimitive = CFStackPrimitive;
/** @beta */
class CFStackBase extends core_1.Component {
constructor(props) {
super(props);
this.setState((prev) => resource_id_1.updateResourceIdState(resourceIds, props, prev, resource_id_1.ResourceIdPolicy.local, { separator: "-" }));
}
initialState() { return {}; }
build() {
const ids = resource_id_1.getResourceIds(resourceIds, this.state);
if (ids == null)
return null; // Haven't completed first state update
// Make sure StackName (and any other ResourceIds are just strings
// in the primitive component)
const _a = Object.assign({}, this.props, ids), { handle: _h } = _a, primProps = tslib_1.__rest(_a, ["handle"]);
const pHandle = core_1.handle();
return (core_1.default.createElement(stack_context_1.CFStackContext.Provider, { key: this.props.key, value: pHandle },
core_1.default.createElement(CFStackPrimitive, Object.assign({}, primProps, { handle: pHandle }))));
}
}
exports.CFStackBase = CFStackBase;
/** @beta */
function isCFStackPrimitiveFinalElement(val) {
return core_1.isFinalDomElement(val) && val.componentType === CFStackPrimitive;
}
exports.isCFStackPrimitiveFinalElement = isCFStackPrimitiveFinalElement;
/** @beta */
// tslint:disable-next-line:variable-name
exports.CFStack = credentials_1.withCredentials(CFStackBase);
//# sourceMappingURL=CFStack.js.map