@pulumi/kubernetesx
Version:
Pulumi Kubernetes Extensions
331 lines (330 loc) • 12.2 kB
JavaScript
;
// 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;