@adpt/cloud
Version:
AdaptJS cloud component library
155 lines • 5.81 kB
JavaScript
;
/*
* Copyright 2018-2019 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 utils_1 = require("@adpt/utils");
const Container_1 = require("../Container");
const env_1 = require("../env");
const toK8sEnv = env_1.mergeEnvPairs;
const defaultProtocol = "tcp";
class PortInfo {
constructor() {
this.portMap = new Map();
}
get containerPorts() {
if (this.portMap.size === 0)
return undefined;
return utils_1.mapMap(this.portMap, (_, p) => p);
}
addPortMapping(ctrPort, hostPort) {
ctrPort = Number(ctrPort);
if (isNaN(ctrPort)) {
throw new Error(`Non-numeric port description not implemented`);
}
const e = this.entry(ctrPort);
if (hostPort !== undefined)
e.hostPort = hostPort;
}
entry(containerPort) {
const key = this.makeKey(containerPort);
let e = this.portMap.get(key);
if (e === undefined) {
e = { containerPort };
this.portMap.set(key, e);
}
return e;
}
makeKey(ctrPort, protocol = defaultProtocol) {
return `${protocol}/${ctrPort}`;
}
}
function toK8sPorts(abstractProps) {
const { ports, portBindings } = abstractProps;
const pInfo = new PortInfo();
if (ports != null)
ports.forEach((p) => pInfo.addPortMapping(p));
if (portBindings != null) {
Object.keys(portBindings).forEach((ctrPort) => pInfo.addPortMapping(ctrPort, portBindings[ctrPort]));
}
return pInfo.containerPorts;
}
/**
* Low level utility function to translate from the abstract {@link Container}
* component props ({@link ContainerProps}) to {@link k8s.K8sContainerProps}
* to be used in a {@link k8s.K8sContainer}.
* @remarks
* Note: The `image` property in the passed in {@link ContainerProps} must
* be a `string`, not a `Handle`.
* In most cases, it is preferable to use the {@link k8s.Container} component
* instead, which is designed specifically to deal with this issue.
*
* @param abstractProps - The abstract {@link ContainerProps} to translate from.
* @param k8sProps - Props that are specific to the {@link k8s.K8sContainer}
* component that should be merged into the resulting returned
* {@link k8s.K8sContainerProps} object.
* @public
*/
function k8sContainerProps(abstractProps, k8sProps) {
const { command, entrypoint, environment, tty, workingDir } = abstractProps;
const ret = Object.assign({ key: abstractProps.key, name: abstractProps.name, image: abstractProps.image }, (k8sProps || {}));
if (entrypoint != null) {
ret.args = Array.isArray(entrypoint) ? entrypoint : [entrypoint];
}
if (command != null) {
ret.command = Array.isArray(command) ? command : [command];
}
ret.env = toK8sEnv(environment);
ret.ports = toK8sPorts(abstractProps);
if (tty != null)
ret.tty = tty;
if (workingDir != null)
ret.workingDir = workingDir;
return ret;
}
exports.k8sContainerProps = k8sContainerProps;
/**
* Tests whether an element is a {@link k8s.K8sContainer} element
* @param x - element to test
* @returns `true` if element is a {@link k8s.K8sContainer}, `false` otherwise
*
* @remarks
* Acts as a TypeScript type assertion that will assert that `x` is `AdaptElement<K8sContainerProps>`
*
* @public
*/
function isK8sContainerElement(x) {
return x.componentType === K8sContainer;
}
exports.isK8sContainerElement = isK8sContainerElement;
/**
* Kubernetes-specific container.
* @public
*/
class K8sContainer extends core_1.PrimitiveComponent {
validate() {
if (this.props.image == null || this.props.image === "") {
throw new Error("K8sContainer: image is a required value");
}
return undefined;
//FIXME(manishv) check if name is legal in k8s
//FIXME(manishv) check if image string is valid URL
//FIXME(manishv) check if workDir is valid path
}
}
K8sContainer.defaultProps = {
imagePullPolicy: "IfNotPresent"
};
exports.K8sContainer = K8sContainer;
/**
* Component that implements the abstract {@link Container} interface and
* translates to a Kubernetes-specific {@link k8s.K8sContainer}.
* @public
*/
function Container(props) {
const _a = props, { image: imgOrHandle, k8sContainerProps: addlProps } = _a, rest = tslib_1.__rest(_a, ["image", "k8sContainerProps"]);
const image = Container_1.useLatestImageFrom(imgOrHandle);
core_1.useDeployedWhen((gs) => {
if (gs === core_1.GoalStatus.Destroyed || image)
return true;
return core_1.waiting("Waiting for Docker image");
});
if (!image)
return null;
const kProps = k8sContainerProps(Object.assign({}, rest, { image }), addlProps);
return core_1.default.createElement(K8sContainer, Object.assign({}, kProps));
}
exports.Container = Container;
// TODO: The "as any" is a workaround for an api-extractor bug. See issue #185.
Container.displayName = "k8s.Container";
Container.defaultProps = Container_1.Container.defaultProps;
//# sourceMappingURL=Container.js.map