UNPKG

@pulumi/kubernetesx

Version:

Pulumi Kubernetes Extensions

331 lines (330 loc) 12.2 kB
"use strict"; // Copyright 2016-2019, 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.Secret = exports.ConfigMap = exports.PersistentVolumeClaim = exports.Job = exports.StatefulSet = exports.Service = exports.Deployment = exports.Pod = exports.PodBuilder = exports.types = void 0; const k8s = require("@pulumi/kubernetes"); const pulumi = require("@pulumi/pulumi"); var types; (function (types) { let ServiceType; (function (ServiceType) { ServiceType["ClusterIP"] = "ClusterIP"; ServiceType["LoadBalancer"] = "LoadBalancer"; })(ServiceType = types.ServiceType || (types.ServiceType = {})); })(types = exports.types || (exports.types = {})); function buildPodSpec(args) { return pulumi.output(args).apply(podSpec => { const volumes = []; let initContainers = []; if (podSpec.initContainers) { initContainers = podSpec.initContainers.map(container => buildContainer(container, volumes)); } const containers = podSpec.containers.map(container => buildContainer(container, volumes)); return pulumi.output(Object.assign(Object.assign({}, podSpec), { initContainers: initContainers, containers: containers, volumes: [ ...podSpec.volumes || [], ...volumes, ] })); }); } function buildContainer(container, volumes) { const isEnvMap = (env) => env.length === undefined; const isPortMap = (ports) => ports.length === undefined; const isMountObject = (object) => object.hasOwnProperty("volume"); const c = Object.assign(Object.assign({}, container), { env: [], name: "", ports: [], volumeMounts: [] }); if (container.name) { c.name = container.name; } else { const re = /(.*\/|^)(?<image>\w+)(:(?<tag>.*))?/; const imageArg = container.image || ""; const result = re.exec(imageArg); if (!result) { throw new Error("Failed to parse image name from " + imageArg); } c.name = result[2]; } const env = container.env; if (env) { if (isEnvMap(env)) { Object.keys(env).forEach(key => { const value = env[key]; if (typeof value === "string") { c.env.push({ name: key, value: value }); } else { c.env.push({ name: key, valueFrom: value }); } }); } else { c.env = env; } } const ports = container.ports; if (ports) { if (isPortMap(ports)) { Object.keys(ports).forEach(key => { const value = ports[key]; c.ports.push({ name: key, containerPort: value }); }); } else { c.ports = ports; } } const volumeMounts = container.volumeMounts; if (volumeMounts) { volumeMounts.forEach(mount => { if (isMountObject(mount)) { c.volumeMounts.push({ name: mount.volume.name, mountPath: mount.destPath, subPath: mount.srcPath, }); volumes.push(Object.assign({}, mount.volume)); } else { c.volumeMounts.push(mount); } }); } return c; } class PodBuilder { constructor(args) { this.podSpec = buildPodSpec(args); this.podName = this.podSpec.containers.apply((containers) => { return pulumi.output(containers[0].name); }); } asDeploymentSpec(args) { var _a; const appLabels = { app: this.podName }; const _args = args || {}; const deploymentSpec = Object.assign(Object.assign({}, _args), { selector: { matchLabels: appLabels }, replicas: (_a = _args.replicas) !== null && _a !== void 0 ? _a : 1, template: { metadata: { labels: appLabels }, spec: this.podSpec, } }); return pulumi.output(deploymentSpec); } asStatefulSetSpec(args) { var _a; const appLabels = { app: this.podName }; const statefulSetSpec = { selector: { matchLabels: appLabels }, replicas: (_a = args === null || args === void 0 ? void 0 : args.replicas) !== null && _a !== void 0 ? _a : 1, serviceName: "", template: { metadata: { labels: appLabels }, spec: this.podSpec, }, }; return pulumi.output(statefulSetSpec); } asJobSpec(args) { const appLabels = { app: this.podName }; const jobSpec = Object.assign(Object.assign({}, args), { template: { metadata: { labels: appLabels }, spec: this.podSpec, } }); return pulumi.output(jobSpec); } } exports.PodBuilder = PodBuilder; class Pod extends k8s.core.v1.Pod { constructor(name, args, opts) { const isPodBuilder = (object) => object.hasOwnProperty("podSpec"); const spec = pulumi.output(args.spec).apply(specArg => { if (isPodBuilder(specArg)) { return pulumi.output(specArg.podSpec); } else { return buildPodSpec(specArg); } }); super(name, Object.assign(Object.assign({}, args), { spec: spec }), opts); } } exports.Pod = Pod; class Deployment extends k8s.apps.v1.Deployment { constructor(name, args, opts) { const spec = pulumi.output(args) .apply(args => { const podSpec = buildPodSpec(args.spec.template.spec); return pulumi.output(Object.assign(Object.assign({}, args.spec), { template: Object.assign(Object.assign({}, args.spec.template), { spec: podSpec }) })); }); super(name, Object.assign(Object.assign({}, args), { spec: spec }), opts); this.name = name; this.opts = opts; } createService(args = {}) { const serviceSpec = pulumi .all([this.spec.template.spec.containers, args]) .apply(([containers, args]) => { // TODO: handle merging ports from args const ports = {}; containers.forEach(container => { if (container.ports) { container.ports.forEach(port => { ports[port.name] = port.containerPort; }); } }); return Object.assign(Object.assign({}, args), { ports: args.ports || ports, selector: this.spec.selector.matchLabels, // TODO: probably need to unwrap args.type in case it's a computed value type: args && args.type }); }); return new Service(this.name, { metadata: { namespace: this.metadata.namespace }, spec: serviceSpec, }, Object.assign(Object.assign({}, this.opts), { parent: this })); } } exports.Deployment = Deployment; class Service extends k8s.core.v1.Service { constructor(name, args, opts) { const spec = pulumi.output(args) .apply((args) => { const isPortMap = (ports) => ports.length === undefined; let ports = []; const portsArg = args.spec.ports; if (portsArg) { if (isPortMap(portsArg)) { Object.keys(portsArg).forEach(key => { const value = portsArg[key]; ports.push({ name: key, port: value }); }); } else { ports = portsArg; } } return Object.assign(Object.assign({}, args.spec), { ports: ports, type: args.spec.type }); }); super(name, Object.assign(Object.assign({}, args), { spec: spec }), opts); } /** * Endpoint of the Service. This can be either an IP address or a hostname, * depending on the k8s cluster provider. */ get endpoint() { return this.status.loadBalancer.ingress .apply((ingress) => { if (ingress.length > 0) { return ingress[0].ip || ingress[0].hostname; } return ""; }); } } exports.Service = Service; class StatefulSet extends pulumi.ComponentResource { constructor(name, args, opts) { const spec = pulumi.output(args) .apply(args => { const podSpec = buildPodSpec(args.spec.template.spec); return pulumi.output(Object.assign(Object.assign({}, args.spec), { serviceName: `${name}-service`, template: Object.assign(Object.assign({}, args.spec.template), { spec: podSpec }) })); }); super("kubernetesx:StatefulSet", name, Object.assign(Object.assign({}, args), { spec: spec }), opts); const statefulSet = new k8s.apps.v1.StatefulSet(name, Object.assign(Object.assign({}, args), { spec: spec }), Object.assign(Object.assign({}, opts), { parent: this })); this.name = name; this.opts = opts; } } exports.StatefulSet = StatefulSet; class Job extends k8s.batch.v1.Job { constructor(name, args, opts) { const spec = pulumi.output(args) .apply(args => { const podSpec = buildPodSpec(args.spec.template.spec); return pulumi.output(Object.assign(Object.assign({}, args.spec), { template: Object.assign(Object.assign({}, args.spec.template), { spec: podSpec }) })); }); super(name, Object.assign(Object.assign({}, args), { spec: spec }), opts); this.name = name; this.opts = opts; } } exports.Job = Job; class PersistentVolumeClaim extends k8s.core.v1.PersistentVolumeClaim { constructor(name, args, opts) { super(name, args, opts); } // TODO: define input type? mount(destPath, srcPath) { return pulumi.output({ volume: { name: this.metadata.name, persistentVolumeClaim: { claimName: this.metadata.name, }, }, destPath: destPath, srcPath: srcPath, }); } } exports.PersistentVolumeClaim = PersistentVolumeClaim; class ConfigMap extends k8s.core.v1.ConfigMap { constructor(name, args, opts) { super(name, args, opts); } mount(destPath, srcPath) { return pulumi.output({ volume: { name: this.metadata.name, configMap: { name: this.metadata.name, }, }, destPath: destPath, srcPath: srcPath, }); } asEnvValue(key) { return pulumi.output({ configMapKeyRef: { name: this.metadata.name, key: key, }, }); } } exports.ConfigMap = ConfigMap; class Secret extends k8s.core.v1.Secret { constructor(name, args, opts) { super(name, args, opts); } mount(destPath, srcPath) { return pulumi.output({ volume: { name: this.metadata.name, secret: { secretName: this.metadata.name, }, }, destPath: destPath, srcPath: srcPath, }); } asEnvValue(key) { return pulumi.output({ secretKeyRef: { name: this.metadata.name, key: key, }, }); } } exports.Secret = Secret;