UNPKG

@adpt/cloud

Version:
155 lines 5.81 kB
"use strict"; /* * 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