mirror of
https://github.com/carlosedp/cluster-monitoring.git
synced 2024-11-20 19:07:17 +01:00
Improve Makefile. Reformat code.
This commit is contained in:
parent
d4be411a81
commit
8c418b73bb
58
Makefile
58
Makefile
@ -1,55 +1,65 @@
|
||||
JSONNET_FMT := jsonnet fmt -n 2 --max-blank-lines 2 --string-style s --comment-style s
|
||||
|
||||
GOPATH ?= `$(pwd)`
|
||||
|
||||
JSONNET_BIN := $(GOPATH)/bin/jsonnet
|
||||
JB_BINARY := $(GOPATH)/bin/jb
|
||||
|
||||
.PHONY: generate vendor fmt manifests
|
||||
JSONNET_FMT := $(GOPATH)/bin/jsonnetfmt -n 2 --max-blank-lines 2 --string-style s --comment-style s
|
||||
|
||||
all: manifests
|
||||
.PHONY: generate vendor fmt manifests help
|
||||
|
||||
manifests: jsonnet
|
||||
all: manifests ## Builds the manifests
|
||||
|
||||
help: # Show help
|
||||
@echo "Makefile targets:"
|
||||
@echo ""
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
manifests: $(JSONNET_BIN) ## Builds the manifests
|
||||
rm -rf manifests
|
||||
./scripts/build.sh main.jsonnet $(JSONNET_BIN)
|
||||
|
||||
update: jsonnet_bundler
|
||||
jb update
|
||||
update_libs: $(JB_BINARY) ## Updates vendor libs. Require a regeneration of the manifests
|
||||
$(JB_BINARY) update
|
||||
|
||||
vendor: jsonnet_bundler jsonnetfile.json jsonnetfile.lock.json
|
||||
vendor: $(JB_BINARY) jsonnetfile.json jsonnetfile.lock.json ## Download vendor libs
|
||||
rm -rf vendor
|
||||
$(JB_BINARY) install
|
||||
|
||||
fmt:
|
||||
find . -name 'vendor' -prune -o -name '*.libsonnet' -o -name '*.jsonnet' -print | xargs -n 1 -- $(JSONNET_FMT) -i
|
||||
fmt: ## Formats all jsonnet and libsonnet files (except on vendor dir)
|
||||
@echo "Formatting jsonnet files"
|
||||
@find . -name 'vendor' -prune -o -name '*.libsonnet' -o -name '*.jsonnet' -print | xargs -n 1 -- $(JSONNET_FMT) -i
|
||||
|
||||
deploy: manifests
|
||||
deploy: manifests ## Rebuilds manifests and deploy to configured cluster
|
||||
kubectl apply -f ./manifests/
|
||||
echo "Will wait 40 seconds to reapply manifests"
|
||||
sleep 40
|
||||
kubectl apply -f ./manifests/
|
||||
|
||||
teardown:
|
||||
teardown: ## Delete all monitoring stack resources from configured cluster
|
||||
kubectl delete -f ./manifests/
|
||||
|
||||
tar: manifests
|
||||
rm -rf manifests.tar
|
||||
tar -cf manifests.tar manifests
|
||||
tar: manifests ## Generates a .tar.gz from manifests dir
|
||||
rm -rf manifests.tar.gz
|
||||
tar -cfz manifests.tar.gz manifests
|
||||
|
||||
jsonnet_bundler:
|
||||
ifeq (, $(shell which jb))
|
||||
$(JB_BINARY): ## Installs jsonnet-bundler utility
|
||||
@echo "Installing jsonnet-bundler"
|
||||
@go get -u github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb
|
||||
endif
|
||||
|
||||
jsonnet:
|
||||
ifeq (, $(shell which jsonnet))
|
||||
$(JSONNET_BIN): ## Installs jsonnet and jsonnetfmt utility
|
||||
@echo "Installing jsonnet"
|
||||
@go get github.com/google/go-jsonnet/cmd/jsonnet
|
||||
@go get github.com/brancz/gojsontoyaml
|
||||
endif
|
||||
@go get -u github.com/google/go-jsonnet/cmd/jsonnet
|
||||
@go get -u github.com/google/go-jsonnet/cmd/jsonnetfmt
|
||||
@go get -u github.com/brancz/gojsontoyaml
|
||||
|
||||
change_suffix:
|
||||
update_tools: ## Updates jsonnet, jsonnetfmt and jb utilities
|
||||
@echo "Updating jsonnet"
|
||||
@go get -u github.com/google/go-jsonnet/cmd/jsonnet
|
||||
@go get -u github.com/google/go-jsonnet/cmd/jsonnetfmt
|
||||
@go get -u github.com/brancz/gojsontoyaml
|
||||
@go get -u github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb
|
||||
|
||||
change_suffix: ## Changes suffix for the ingress
|
||||
@perl -p -i -e 's/^(\s*)\-\ host:.*/\1- host: alertmanager.${IP}.nip.io/g' manifests/ingress-alertmanager.yaml manifests/ingress-prometheus.yaml manifests/ingress-grafana.yaml
|
||||
@echo "Ingress IPs changed to [service].${IP}.nip.io"
|
||||
${K3S} kubectl apply -f manifests/ingress-alertmanager.yaml
|
||||
|
@ -20,14 +20,16 @@ local utils = import 'utils.libsonnet';
|
||||
|
||||
clusterRole:
|
||||
utils.newClusterRole('arm-exporter', [
|
||||
{apis: ['authentication.k8s.io'],
|
||||
res: ['tokenreviews'],
|
||||
verbs: ['create']
|
||||
{
|
||||
apis: ['authentication.k8s.io'],
|
||||
res: ['tokenreviews'],
|
||||
verbs: ['create'],
|
||||
},
|
||||
{
|
||||
apis: ['authorization.k8s.io'],
|
||||
res: ['subjectaccessreviews'],
|
||||
verbs: ['create'],
|
||||
},
|
||||
{apis: ['authorization.k8s.io'],
|
||||
res: ['subjectaccessreviews'],
|
||||
verbs: ['create']
|
||||
}
|
||||
], null),
|
||||
|
||||
clusterRoleBinding:
|
||||
@ -86,9 +88,10 @@ local utils = import 'utils.libsonnet';
|
||||
service.mixin.spec.withClusterIp('None'),
|
||||
|
||||
serviceMonitor:
|
||||
utils.newServiceMonitorHTTPS('arm-exporter',
|
||||
utils.newServiceMonitorHTTPS(
|
||||
'arm-exporter',
|
||||
$._config.namespace,
|
||||
{'k8s-app': 'arm-exporter'},
|
||||
{ 'k8s-app': 'arm-exporter' },
|
||||
$._config.namespace,
|
||||
'https',
|
||||
'https',
|
||||
|
@ -82,19 +82,21 @@ local utils = import 'utils.libsonnet';
|
||||
utils.newServiceMonitor(
|
||||
'elasticsearch',
|
||||
$._config.namespace,
|
||||
{'k8s-app': 'elasticsearch-exporter'},
|
||||
{ 'k8s-app': 'elasticsearch-exporter' },
|
||||
'monitoring',
|
||||
'es-metrics',
|
||||
'http'),
|
||||
'http'
|
||||
),
|
||||
|
||||
serviceMonitorFluentd:
|
||||
utils.newServiceMonitor(
|
||||
'fluentd-es',
|
||||
$._config.namespace,
|
||||
{'k8s-app': 'fluentd-es'},
|
||||
{ 'k8s-app': 'fluentd-es' },
|
||||
'logging',
|
||||
'metrics',
|
||||
'http'),
|
||||
'http'
|
||||
),
|
||||
},
|
||||
// Add Prometheus monitoring rules for ElasticSearch
|
||||
prometheusRules+:: {
|
||||
|
@ -13,7 +13,7 @@ local utils = import 'utils.libsonnet';
|
||||
|
||||
metallbExporter+:: {
|
||||
serviceMonitor:
|
||||
utils.newServiceMonitor('metallb', $._config.namespace, {'k8s-app': 'metallb-controller'}, 'metallb-system', 'http', 'http'),
|
||||
utils.newServiceMonitor('metallb', $._config.namespace, { 'k8s-app': 'metallb-controller' }, 'metallb-system', 'http', 'http'),
|
||||
|
||||
service:
|
||||
local service = k.core.v1.service;
|
||||
|
@ -12,6 +12,6 @@ local utils = import 'utils.libsonnet';
|
||||
|
||||
traefikExporter+:: {
|
||||
serviceMonitor:
|
||||
utils.newServiceMonitor('traefik', $._config.namespace, {'app': 'traefik'}, 'kube-system', 'metrics', 'http'),
|
||||
utils.newServiceMonitor('traefik', $._config.namespace, { app: 'traefik' }, 'kube-system', 'metrics', 'http'),
|
||||
},
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ local utils = import 'utils.libsonnet';
|
||||
|
||||
upsExporter+:: {
|
||||
serviceMonitor:
|
||||
utils.newServiceMonitor('ups-exporter', $._config.namespace, {'k8s-app': 'ups-exporter'}, $._config.namespace, 'metrics', 'http'),
|
||||
utils.newServiceMonitor('ups-exporter', $._config.namespace, { 'k8s-app': 'ups-exporter' }, $._config.namespace, 'metrics', 'http'),
|
||||
|
||||
service:
|
||||
local service = k.core.v1.service;
|
||||
|
258
utils.libsonnet
258
utils.libsonnet
@ -5,7 +5,8 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
generate(kp):: (
|
||||
{
|
||||
[std.asciiLower(module) + '-' + name]: kp[module][name]
|
||||
for module in std.objectFieldsAll(kp) if !std.startsWith(module, '_')
|
||||
for module in std.objectFieldsAll(kp)
|
||||
if !std.startsWith(module, '_')
|
||||
for name in std.objectFields(kp[module])
|
||||
}
|
||||
),
|
||||
@ -21,11 +22,11 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
|
||||
// Creates serviceaccount
|
||||
newServiceAccount(name, namespace, labels):: (
|
||||
local serviceAccount = k.core.v1.serviceAccount;
|
||||
local serviceAccount = k.core.v1.serviceAccount;
|
||||
|
||||
serviceAccount.new(name)
|
||||
+ (if labels != null then serviceAccount.mixin.metadata.withLabels(labels) else {})
|
||||
+ serviceAccount.mixin.metadata.withNamespace(namespace)
|
||||
serviceAccount.new(name)
|
||||
+ (if labels != null then serviceAccount.mixin.metadata.withLabels(labels) else {})
|
||||
+ serviceAccount.mixin.metadata.withNamespace(namespace)
|
||||
),
|
||||
|
||||
// Creates ClusterRoles
|
||||
@ -33,38 +34,38 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
// res: ['tokenreviews'],
|
||||
// verbs: ['create']
|
||||
// },[{...}]]
|
||||
newClusterRole(name, roles, labels):: (
|
||||
local clusterRole = k.rbac.v1.clusterRole;
|
||||
local policyRule = clusterRole.rulesType;
|
||||
newClusterRole(name, roles, labels):: (
|
||||
local clusterRole = k.rbac.v1.clusterRole;
|
||||
local policyRule = clusterRole.rulesType;
|
||||
|
||||
local p(apigroups, resources, verbs) = policyRule.new()
|
||||
+ policyRule.withApiGroups([a for a in apigroups])
|
||||
+ policyRule.withResources([r for r in resources])
|
||||
+ policyRule.withVerbs([v for v in verbs]);
|
||||
local p(apigroups, resources, verbs) = policyRule.new()
|
||||
+ policyRule.withApiGroups([a for a in apigroups])
|
||||
+ policyRule.withResources([r for r in resources])
|
||||
+ policyRule.withVerbs([v for v in verbs]);
|
||||
|
||||
local r = [ p(pol.apis, pol.res, pol.verbs) for pol in roles ];
|
||||
local r = [p(pol.apis, pol.res, pol.verbs) for pol in roles];
|
||||
|
||||
local rules = r;
|
||||
local rules = r;
|
||||
|
||||
local c = clusterRole.new()
|
||||
+ (if labels != null then clusterRole.mixin.metadata.withLabels(labels) else {})
|
||||
+ clusterRole.mixin.metadata.withName(name)
|
||||
+ clusterRole.withRules(rules);
|
||||
c
|
||||
),
|
||||
local c = clusterRole.new()
|
||||
+ (if labels != null then clusterRole.mixin.metadata.withLabels(labels) else {})
|
||||
+ clusterRole.mixin.metadata.withName(name)
|
||||
+ clusterRole.withRules(rules);
|
||||
c
|
||||
),
|
||||
|
||||
// Creates a ClusterRoleBinding between a `clusterRole` and a `serviceAccount` on `serviceAccountNamespace`
|
||||
newClusterRoleBinding(name, serviceAccount, serviceAccountNamespace, clusterRole, labels):: (
|
||||
local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
|
||||
// Creates a ClusterRoleBinding between a `clusterRole` and a `serviceAccount` on `serviceAccountNamespace`
|
||||
newClusterRoleBinding(name, serviceAccount, serviceAccountNamespace, clusterRole, labels):: (
|
||||
local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
|
||||
|
||||
clusterRoleBinding.new()
|
||||
+ clusterRoleBinding.mixin.metadata.withName(name)
|
||||
+ (if labels != null then clusterRoleBinding.mixin.metadata.withLabels(labels) else {})
|
||||
+ clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io')
|
||||
+ clusterRoleBinding.mixin.roleRef.withName(clusterRole)
|
||||
+ clusterRoleBinding.mixin.roleRef.mixinInstance({ kind: 'ClusterRole' })
|
||||
+ clusterRoleBinding.withSubjects([{ kind: 'ServiceAccount', 'name': serviceAccount, 'namespace': serviceAccountNamespace }])
|
||||
),
|
||||
clusterRoleBinding.new()
|
||||
+ clusterRoleBinding.mixin.metadata.withName(name)
|
||||
+ (if labels != null then clusterRoleBinding.mixin.metadata.withLabels(labels) else {})
|
||||
+ clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io')
|
||||
+ clusterRoleBinding.mixin.roleRef.withName(clusterRole)
|
||||
+ clusterRoleBinding.mixin.roleRef.mixinInstance({ kind: 'ClusterRole' })
|
||||
+ clusterRoleBinding.withSubjects([{ kind: 'ServiceAccount', name: serviceAccount, namespace: serviceAccountNamespace }])
|
||||
),
|
||||
|
||||
// Creates endpoint objects
|
||||
newEndpoint(name, namespace, ips, portName, portNumber):: (
|
||||
@ -72,22 +73,22 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
local endpointSubset = endpoints.subsetsType;
|
||||
local endpointPort = endpointSubset.portsType;
|
||||
local Port = endpointPort.new()
|
||||
+ endpointPort.withName(portName)
|
||||
+ endpointPort.withPort(portNumber)
|
||||
+ endpointPort.withProtocol('TCP');
|
||||
+ endpointPort.withName(portName)
|
||||
+ endpointPort.withPort(portNumber)
|
||||
+ endpointPort.withProtocol('TCP');
|
||||
|
||||
local subset = endpointSubset.new()
|
||||
+ endpointSubset.withAddresses([
|
||||
{ ip: IP }
|
||||
for IP in ips
|
||||
])
|
||||
+ endpointSubset.withPorts(Port);
|
||||
+ endpointSubset.withAddresses([
|
||||
{ ip: IP }
|
||||
for IP in ips
|
||||
])
|
||||
+ endpointSubset.withPorts(Port);
|
||||
endpoints.new()
|
||||
+ endpoints.mixin.metadata.withName(name)
|
||||
+ endpoints.mixin.metadata.withNamespace(namespace)
|
||||
+ endpoints.mixin.metadata.withLabels({ 'k8s-app': name })
|
||||
+ endpoints.withSubsets(subset)
|
||||
),
|
||||
+ endpoints.mixin.metadata.withName(name)
|
||||
+ endpoints.mixin.metadata.withNamespace(namespace)
|
||||
+ endpoints.mixin.metadata.withLabels({ 'k8s-app': name })
|
||||
+ endpoints.withSubsets(subset)
|
||||
),
|
||||
|
||||
// Creates ingress objects
|
||||
newIngress(name, namespace, host, path, serviceName, servicePort):: (
|
||||
@ -120,8 +121,8 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
|
||||
I + ingress.mixin.spec.withTls(
|
||||
ingressTls.new() +
|
||||
ingressTls.withHosts(host) +
|
||||
(if S != '' then {'secretName': S} else {})
|
||||
ingressTls.withHosts(host) +
|
||||
(if S != '' then { secretName: S } else {})
|
||||
)
|
||||
),
|
||||
|
||||
@ -130,13 +131,14 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
local secret = k.core.v1.secret;
|
||||
|
||||
secret.new('ingress-secret') +
|
||||
secret.mixin.metadata.withNamespace(namespace) +
|
||||
secret.withType('kubernetes.io/tls') +
|
||||
secret.withData(
|
||||
{
|
||||
secret.mixin.metadata.withNamespace(namespace) +
|
||||
secret.withType('kubernetes.io/tls') +
|
||||
secret.withData(
|
||||
{
|
||||
'tls.crt': std.base64(crt),
|
||||
'tls.key': std.base64(key),
|
||||
})
|
||||
}
|
||||
)
|
||||
),
|
||||
|
||||
// Creates new basic deployments
|
||||
@ -152,12 +154,12 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
|
||||
local c = [con];
|
||||
|
||||
local d = deployment.new(name, 1, c, {'app': name})
|
||||
+ deployment.mixin.metadata.withNamespace(namespace)
|
||||
+ deployment.mixin.metadata.withLabels({'app': name})
|
||||
+ deployment.mixin.spec.selector.withMatchLabels({'app': name})
|
||||
+ deployment.mixin.spec.strategy.withType('RollingUpdate')
|
||||
+ deployment.mixin.spec.template.spec.withRestartPolicy('Always');
|
||||
local d = deployment.new(name, 1, c, { app: name })
|
||||
+ deployment.mixin.metadata.withNamespace(namespace)
|
||||
+ deployment.mixin.metadata.withLabels({ app: name })
|
||||
+ deployment.mixin.spec.selector.withMatchLabels({ app: name })
|
||||
+ deployment.mixin.spec.strategy.withType('RollingUpdate')
|
||||
+ deployment.mixin.spec.template.spec.withRestartPolicy('Always');
|
||||
d
|
||||
),
|
||||
|
||||
@ -166,40 +168,40 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
local servicePort = k.core.v1.service.mixin.spec.portsType;
|
||||
local p = servicePort.newNamed(name, port, port);
|
||||
|
||||
local s = service.new(name, {'app': name}, p)
|
||||
+ service.mixin.metadata.withNamespace(namespace)
|
||||
+ service.mixin.metadata.withLabels({'app': name});
|
||||
local s = service.new(name, { app: name }, p)
|
||||
+ service.mixin.metadata.withNamespace(namespace)
|
||||
+ service.mixin.metadata.withLabels({ app: name });
|
||||
s
|
||||
),
|
||||
|
||||
// Creates http ServiceMonitor objects
|
||||
newServiceMonitor(name, namespace, matchLabel, matchNamespace, portName, portScheme, path='metrics'):: (
|
||||
{
|
||||
apiVersion: 'monitoring.coreos.com/v1',
|
||||
kind: 'ServiceMonitor',
|
||||
metadata: {
|
||||
name: name,
|
||||
namespace: namespace,
|
||||
labels: {
|
||||
'app': name,
|
||||
},
|
||||
apiVersion: 'monitoring.coreos.com/v1',
|
||||
kind: 'ServiceMonitor',
|
||||
metadata: {
|
||||
name: name,
|
||||
namespace: namespace,
|
||||
labels: {
|
||||
app: name,
|
||||
},
|
||||
spec: {
|
||||
jobLabel: name+'-exporter',
|
||||
selector: {
|
||||
matchLabels: matchLabel,
|
||||
},
|
||||
endpoints: [
|
||||
{
|
||||
port: portName,
|
||||
scheme: portScheme,
|
||||
interval: '30s',
|
||||
},
|
||||
],
|
||||
namespaceSelector: {
|
||||
matchNames: [matchNamespace],
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
jobLabel: name + '-exporter',
|
||||
selector: {
|
||||
matchLabels: matchLabel,
|
||||
},
|
||||
endpoints: [
|
||||
{
|
||||
port: portName,
|
||||
scheme: portScheme,
|
||||
interval: '30s',
|
||||
},
|
||||
],
|
||||
namespaceSelector: {
|
||||
matchNames: [matchNamespace],
|
||||
},
|
||||
},
|
||||
}
|
||||
),
|
||||
|
||||
@ -210,58 +212,58 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
|
||||
local t = {
|
||||
spec: {
|
||||
endpoints: [{
|
||||
port: portName,
|
||||
scheme: portScheme,
|
||||
interval: '30s',
|
||||
bearerTokenFile: token,
|
||||
tlsConfig: {
|
||||
insecureSkipVerify: true,
|
||||
}
|
||||
}],
|
||||
}
|
||||
port: portName,
|
||||
scheme: portScheme,
|
||||
interval: '30s',
|
||||
bearerTokenFile: token,
|
||||
tlsConfig: {
|
||||
insecureSkipVerify: true,
|
||||
},
|
||||
}],
|
||||
},
|
||||
};
|
||||
std.mergePatch(s, t)
|
||||
// s + t
|
||||
),
|
||||
|
||||
|
||||
# Adds arguments to a container in a deployment
|
||||
# args is an array of arguments in the format
|
||||
# ["arg1","arg2",]
|
||||
addArguments(deployment, container, args):: (
|
||||
{spec+: {
|
||||
template+: {
|
||||
spec+: {
|
||||
containers:
|
||||
std.map(
|
||||
function(c)
|
||||
if c.name == container then
|
||||
c { args+: args }
|
||||
else c,
|
||||
super.containers
|
||||
),
|
||||
},
|
||||
// Adds arguments to a container in a deployment
|
||||
// args is an array of arguments in the format
|
||||
// ["arg1","arg2",]
|
||||
addArguments(deployment, container, args):: (
|
||||
{ spec+: {
|
||||
template+: {
|
||||
spec+: {
|
||||
containers:
|
||||
std.map(
|
||||
function(c)
|
||||
if c.name == container then
|
||||
c { args+: args }
|
||||
else c,
|
||||
super.containers
|
||||
),
|
||||
},
|
||||
}}
|
||||
),
|
||||
},
|
||||
} }
|
||||
),
|
||||
|
||||
# Adds environment variables to a container in a deployment
|
||||
# envs is an array of environment variables in the format
|
||||
# [{name: 'VARNAME', value: 'var_value'},{...},]
|
||||
addEnviromnentVars(deployment, container, envs):: (
|
||||
{spec+: {
|
||||
template+: {
|
||||
spec+: {
|
||||
containers:
|
||||
std.map(
|
||||
function(c)
|
||||
if c.name == container then
|
||||
c { env+: envs }
|
||||
else c,
|
||||
super.containers
|
||||
),
|
||||
},
|
||||
// Adds environment variables to a container in a deployment
|
||||
// envs is an array of environment variables in the format
|
||||
// [{name: 'VARNAME', value: 'var_value'},{...},]
|
||||
addEnviromnentVars(deployment, container, envs):: (
|
||||
{ spec+: {
|
||||
template+: {
|
||||
spec+: {
|
||||
containers:
|
||||
std.map(
|
||||
function(c)
|
||||
if c.name == container then
|
||||
c { env+: envs }
|
||||
else c,
|
||||
super.containers
|
||||
),
|
||||
},
|
||||
}}
|
||||
),
|
||||
},
|
||||
} }
|
||||
),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user