@adpt/cloud
Version:
AdaptJS cloud component library
140 lines • 5.51 kB
JavaScript
;
/*
* Copyright 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 Container_1 = require("../Container");
const NetworkService_1 = require("../NetworkService");
const DockerContainer_1 = require("./DockerContainer");
const NetworkService_2 = require("./NetworkService");
function mapContainer(absEl, spProps, helpers, portBindings) {
const { containerProps = {} } = spProps;
const _a = absEl.props, { handle: _h } = _a, absProps = tslib_1.__rest(_a, ["handle"]);
const finalProps = Object.assign({}, absProps, containerProps, { key: absEl.props.key });
if (spProps.dockerHost)
finalProps.dockerHost = spProps.dockerHost;
// Add the port bindings from the NetworkServices
if (portBindings) {
finalProps.portBindings = Object.assign({}, (finalProps.portBindings || {}), portBindings);
}
const ctr = core_1.default.createElement(DockerContainer_1.DockerContainer, Object.assign({}, finalProps));
absEl.props.handle.replaceTarget(ctr, helpers);
return ctr;
}
function mapNetworkService(absEl, _props, helpers) {
const _a = absEl.props, { handle: _h } = _a, props = tslib_1.__rest(_a, ["handle"]);
const svc = core_1.default.createElement(NetworkService_2.NetworkService, Object.assign({}, props));
absEl.props.handle.replaceTarget(svc, helpers);
return svc;
}
/**
* Record which NetworkService elements expose a service with external
* scope and record the port binding associated with the endpoint element.
* @internal
*/
function getPortBindings(elems) {
const portMap = new Map();
const getPorts = (el) => {
let ret = portMap.get(el);
if (!ret) {
ret = {};
portMap.set(el, ret);
}
return ret;
};
const toPortNum = (p) => {
const pNum = Number(p);
if (isNaN(pNum) || !Number.isInteger(pNum) || pNum <= 0 || pNum >= 65536) {
throw new Error(`Network service port ${p} is not a valid number`);
}
return pNum;
};
for (const el of elems) {
if (!NetworkService_1.isNetworkServiceElement(el) || el.props.scope !== "external") {
continue;
}
const endpoint = el.props.endpoint && el.props.endpoint.target;
if (!endpoint)
continue;
const ports = getPorts(endpoint);
const proto = el.props.protocol || NetworkService_1.NetworkService.defaultProps.protocol;
const ctrPort = el.props.targetPort || el.props.port;
const hostPort = toPortNum(el.props.port);
ports[`${ctrPort}/${proto.toLowerCase()}`] = hostPort;
}
return portMap;
}
/**
* A component for mapping a group of abstract {@link Container}s and
* {@link NetworkService}s to Docker {@link docker.DockerContainer | DockerContainer}s
* and {@link docker.NetworkService}s.
*
* @remarks
* This component is intended to be used to replace {@link Container} and
* {@link NetworkService} components that are grouped together, as the
* only children of a common parent in a pattern that looks like this:
* ```tsx
* <Service>
* <Container ... />
* <Container ... />
* <NetworkService ... />
* </Service>
* ```
* `ServiceContainerSet` maps those abstract components into Docker components
* like this:
* ```tsx
* <Group>
* <docker.DockerContainer ... >
* <docker.DockerContainer ... >
* <docker.NetworkService ... >
* </Group>
* ```
* An example style rule to do this is:
* ```tsx
* {Service}
* {Adapt.rule((matchedProps) => {
* const { handle, ...remainingProps } = matchedProps;
* return <ServiceContainerSet {...remainingProps} />;
* })}
* ```
*
* Currently, {@link docker.NetworkService} implements the {@link NetworkServiceInstance}
* interface, but does not deploy a network proxy component. So the Docker
* ServiceContainerSet component applies the network port configuration specified by
* the {@link NetworkService}s to their target
* {@link docker.DockerContainer | DockerContainer}s.
*
* @public
*/
class ServiceContainerSet extends core_1.DeferredComponent {
build(helpers) {
const children = core_1.childrenToArray(this.props.children);
const portMap = getPortBindings(children);
const mappedChildren = children.map((c) => {
if (Container_1.isContainerElement(c)) {
return mapContainer(c, this.props, helpers, portMap.get(c));
}
if (NetworkService_1.isNetworkServiceElement(c)) {
return mapNetworkService(c, this.props, helpers);
}
return c;
});
return core_1.default.createElement(core_1.Group, { key: this.props.key }, mappedChildren);
}
}
exports.ServiceContainerSet = ServiceContainerSet;
//# sourceMappingURL=ServiceContainerSet.js.map