Merge pull request #52 from Liujingfang1/master

variable reference support
This commit is contained in:
Jeff Regan
2018-06-06 16:43:48 -07:00
committed by GitHub
12 changed files with 957 additions and 8 deletions

View File

@@ -21,8 +21,11 @@ package app
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"github.com/ghodss/yaml"
"github.com/golang/glog"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
interror "github.com/kubernetes-sigs/kustomize/pkg/internal/error"
@@ -43,6 +46,8 @@ type Application interface {
// 1) untransformed resources from current kustomization file
// 2) transformed resources from sub packages
RawResources() (resmap.ResMap, error)
// Vars returns all the variables defined by the app
Vars() ([]types.Var, error)
}
var _ Application = &applicationImpl{}
@@ -76,7 +81,7 @@ func (a *applicationImpl) Resources() (resmap.ResMap, error) {
if err != nil {
return nil, err
}
t, err := a.getHashAndReferenceTransformer()
t, err := a.newHashAndReferenceTransformer(res)
if err != nil {
return nil, err
}
@@ -122,7 +127,7 @@ func (a *applicationImpl) SemiResources() (resmap.ResMap, error) {
return nil, errs
}
t, err := a.getTransformer(patches)
t, err := a.newTransformer(patches)
if err != nil {
return nil, err
}
@@ -130,7 +135,6 @@ func (a *applicationImpl) SemiResources() (resmap.ResMap, error) {
if err != nil {
return nil, err
}
return allRes, nil
}
@@ -142,7 +146,7 @@ func (a *applicationImpl) RawResources() (resmap.ResMap, error) {
if err != nil {
return nil, err
}
t, err := a.getHashAndReferenceTransformer()
t, err := a.newHashAndReferenceTransformer(res)
if err != nil {
return nil, err
}
@@ -196,12 +200,34 @@ func (a *applicationImpl) subAppResources() (resmap.ResMap, *interror.Kustomizat
return allResources, errs
}
// getTransformer generates the following transformers:
func (a *applicationImpl) subApp() ([]Application, error) {
var apps []Application
errs := &interror.KustomizationErrors{}
for _, basePath := range a.kustomization.Bases {
subloader, err := a.loader.New(basePath)
if err != nil {
errs.Append(err)
continue
}
subapp, err := New(subloader)
if err != nil {
errs.Append(err)
continue
}
apps = append(apps, subapp)
}
if len(errs.Get()) > 0 {
return nil, errs
}
return apps, nil
}
// newTransformer generates the following transformers:
// 1) apply overlay
// 2) name prefix
// 3) apply labels
// 4) apply annotations
func (a *applicationImpl) getTransformer(patches []*resource.Resource) (transformers.Transformer, error) {
func (a *applicationImpl) newTransformer(patches []*resource.Resource) (transformers.Transformer, error) {
ts := []transformers.Transformer{}
ot, err := transformers.NewOverlayTransformer(patches)
@@ -233,10 +259,11 @@ func (a *applicationImpl) getTransformer(patches []*resource.Resource) (transfor
return transformers.NewMultiTransformer(ts), nil
}
// getHashAndReferenceTransformer generates the following transformers:
// newHashAndReferenceTransformer generates the following transformers:
// 1) name hash for configmap and secrests
// 2) apply name reference
func (a *applicationImpl) getHashAndReferenceTransformer() (transformers.Transformer, error) {
// 3) apply reference variables
func (a *applicationImpl) newHashAndReferenceTransformer(allRes resmap.ResMap) (transformers.Transformer, error) {
ts := []transformers.Transformer{}
nht := transformers.NewNameHashTransformer()
ts = append(ts, nht)
@@ -246,9 +273,30 @@ func (a *applicationImpl) getHashAndReferenceTransformer() (transformers.Transfo
return nil, err
}
ts = append(ts, nrt)
t, err := a.newVariableReferenceTransformer(allRes)
if err != nil {
return nil, err
}
ts = append(ts, t)
return transformers.NewMultiTransformer(ts), nil
}
func (a *applicationImpl) newVariableReferenceTransformer(allRes resmap.ResMap) (transformers.Transformer, error) {
refvars, err := a.resolveRefVars(allRes)
if err != nil {
return nil, err
}
glog.Infof("found all the refvars: %+v", refvars)
varExpander, err := transformers.NewRefVarTransformer(refvars)
if err != nil {
return nil, err
}
return varExpander, nil
}
func unmarshal(y []byte, o interface{}) error {
j, err := yaml.YAMLToJSON(y)
if err != nil {
@@ -259,3 +307,54 @@ func unmarshal(y []byte, o interface{}) error {
dec.DisallowUnknownFields()
return dec.Decode(o)
}
func (a *applicationImpl) resolveRefVars(resources resmap.ResMap) (map[string]string, error) {
refvars := map[string]string{}
vars, err := a.Vars()
if err != nil {
return refvars, err
}
for _, refvar := range vars {
refGVKN := resource.NewResId(refvar.ObjRef.GroupVersionKind(), refvar.ObjRef.Name)
if r, found := resources[refGVKN]; found {
s, err := resource.GetFieldValue(r.Unstruct().UnstructuredContent(), strings.Split(refvar.FieldRef.FieldPath, "."))
if err != nil {
return nil, fmt.Errorf("failed to resolve referred var: %+v", refvar)
}
refvars[refvar.Name] = s
} else {
glog.Infof("couldn't resolve refvar: %v", refvar)
}
}
return refvars, nil
}
// Vars returns all the variables defined at the app and subapps of the app
func (a *applicationImpl) Vars() ([]types.Var, error) {
vars := []types.Var{}
errs := &interror.KustomizationErrors{}
apps, err := a.subApp()
if err != nil {
return nil, err
}
// TODO: computing vars and resources for subApps can be combined
for _, subApp := range apps {
subAppVars, err := subApp.Vars()
if err != nil {
errs.Append(err)
continue
}
vars = append(vars, subAppVars...)
}
for _, v := range a.kustomization.Vars {
v.Defaulting()
vars = append(vars, v)
}
if len(errs.Get()) > 0 {
return nil, errs
}
return vars, nil
}

View File

@@ -0,0 +1,150 @@
diff -u -N /tmp/noop/apps_v1beta1_StatefulSet_cockroachdb.yaml /tmp/transformed/apps_v1beta1_StatefulSet_cockroachdb.yaml
--- /tmp/noop/apps_v1beta1_StatefulSet_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/apps_v1beta1_StatefulSet_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
@@ -1,10 +1,10 @@
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
- name: base-cockroachdb
+ name: dev-base-cockroachdb
spec:
replicas: 3
- serviceName: base-cockroachdb
+ serviceName: dev-base-cockroachdb
template:
metadata:
labels:
@@ -27,7 +27,7 @@
- /bin/bash
- -ecx
- exec /cockroach/cockroach start --logtostderr --certs-dir /cockroach/cockroach-certs
- --host $(hostname -f) --http-host 0.0.0.0 --join base-cockroachdb-0.base-cockroachdb,base-cockroachdb-1.base-cockroachdb,base-cockroachdb-2.base-cockroachdb
+ --host $(hostname -f) --http-host 0.0.0.0 --join dev-base-cockroachdb-0.dev-base-cockroachdb,dev-base-cockroachdb-1.dev-base-cockroachdb,dev-base-cockroachdb-2.dev-base-cockroachdb
--cache 25% --max-sql-memory 25%
image: cockroachdb/cockroach:v1.1.5
imagePullPolicy: IfNotPresent
@@ -48,7 +48,7 @@
- -ecx
- /request-cert -namespace=${POD_NAMESPACE} -certs-dir=/cockroach-certs -type=node
-addresses=localhost,127.0.0.1,${POD_IP},$(hostname -f),$(hostname -f|cut
- -f 1-2 -d '.'),base-cockroachdb-public -symlink-ca-from=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ -f 1-2 -d '.'),dev-base-cockroachdb-public -symlink-ca-from=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
env:
- name: POD_IP
valueFrom:
@@ -64,7 +64,7 @@
volumeMounts:
- mountPath: /cockroach-certs
name: certs
- serviceAccountName: base-cockroachdb
+ serviceAccountName: dev-base-cockroachdb
terminationGracePeriodSeconds: 60
volumes:
- name: datadir
diff -u -N /tmp/noop/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml /tmp/transformed/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml
--- /tmp/noop/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml YYYY-MM-DD HH:MM:SS
@@ -3,7 +3,7 @@
metadata:
labels:
app: cockroachdb
- name: base-cockroachdb-budget
+ name: dev-base-cockroachdb-budget
spec:
maxUnavailable: 1
selector:
diff -u -N /tmp/noop/rbac.authorization.k8s.io_v1beta1_ClusterRoleBinding_cockroachdb.yaml /tmp/transformed/rbac.authorization.k8s.io_v1beta1_ClusterRoleBinding_cockroachdb.yaml
--- /tmp/noop/rbac.authorization.k8s.io_v1beta1_ClusterRoleBinding_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/rbac.authorization.k8s.io_v1beta1_ClusterRoleBinding_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
@@ -3,12 +3,12 @@
metadata:
labels:
app: cockroachdb
- name: base-cockroachdb
+ name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
- name: base-cockroachdb
+ name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
- name: base-cockroachdb
+ name: dev-base-cockroachdb
namespace: default
diff -u -N /tmp/noop/rbac.authorization.k8s.io_v1beta1_ClusterRole_cockroachdb.yaml /tmp/transformed/rbac.authorization.k8s.io_v1beta1_ClusterRole_cockroachdb.yaml
--- /tmp/noop/rbac.authorization.k8s.io_v1beta1_ClusterRole_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/rbac.authorization.k8s.io_v1beta1_ClusterRole_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
@@ -3,7 +3,7 @@
metadata:
labels:
app: cockroachdb
- name: base-cockroachdb
+ name: dev-base-cockroachdb
rules:
- apiGroups:
- certificates.k8s.io
diff -u -N /tmp/noop/rbac.authorization.k8s.io_v1beta1_RoleBinding_cockroachdb.yaml /tmp/transformed/rbac.authorization.k8s.io_v1beta1_RoleBinding_cockroachdb.yaml
--- /tmp/noop/rbac.authorization.k8s.io_v1beta1_RoleBinding_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/rbac.authorization.k8s.io_v1beta1_RoleBinding_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
@@ -3,12 +3,12 @@
metadata:
labels:
app: cockroachdb
- name: base-cockroachdb
+ name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
- name: base-cockroachdb
+ name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
- name: base-cockroachdb
+ name: dev-base-cockroachdb
namespace: default
diff -u -N /tmp/noop/rbac.authorization.k8s.io_v1beta1_Role_cockroachdb.yaml /tmp/transformed/rbac.authorization.k8s.io_v1beta1_Role_cockroachdb.yaml
--- /tmp/noop/rbac.authorization.k8s.io_v1beta1_Role_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/rbac.authorization.k8s.io_v1beta1_Role_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
@@ -3,7 +3,7 @@
metadata:
labels:
app: cockroachdb
- name: base-cockroachdb
+ name: dev-base-cockroachdb
rules:
- apiGroups:
- ""
diff -u -N /tmp/noop/v1_ServiceAccount_cockroachdb.yaml /tmp/transformed/v1_ServiceAccount_cockroachdb.yaml
--- /tmp/noop/v1_ServiceAccount_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/v1_ServiceAccount_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
@@ -3,4 +3,4 @@
metadata:
labels:
app: cockroachdb
- name: base-cockroachdb
+ name: dev-base-cockroachdb
diff -u -N /tmp/noop/v1_Service_cockroachdb-public.yaml /tmp/transformed/v1_Service_cockroachdb-public.yaml
--- /tmp/noop/v1_Service_cockroachdb-public.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/v1_Service_cockroachdb-public.yaml YYYY-MM-DD HH:MM:SS
@@ -3,7 +3,7 @@
metadata:
labels:
app: cockroachdb
- name: base-cockroachdb-public
+ name: dev-base-cockroachdb-public
spec:
ports:
- name: grpc
diff -u -N /tmp/noop/v1_Service_cockroachdb.yaml /tmp/transformed/v1_Service_cockroachdb.yaml
--- /tmp/noop/v1_Service_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/v1_Service_cockroachdb.yaml YYYY-MM-DD HH:MM:SS
@@ -8,7 +8,7 @@
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
labels:
app: cockroachdb
- name: base-cockroachdb
+ name: dev-base-cockroachdb
spec:
clusterIP: None
ports:

View File

@@ -0,0 +1,205 @@
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/path: _status/vars
prometheus.io/port: "8080"
prometheus.io/scrape: "true"
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
labels:
app: cockroachdb
name: dev-base-cockroachdb
spec:
clusterIP: None
ports:
- name: grpc
port: 26257
targetPort: 26257
- name: http
port: 8080
targetPort: 8080
selector:
app: cockroachdb
---
apiVersion: v1
kind: Service
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb-public
spec:
ports:
- name: grpc
port: 26257
targetPort: 26257
- name: http
port: 8080
targetPort: 8080
selector:
app: cockroachdb
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: dev-base-cockroachdb
spec:
replicas: 3
serviceName: dev-base-cockroachdb
template:
metadata:
labels:
app: cockroachdb
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cockroachdb
topologyKey: kubernetes.io/hostname
weight: 100
containers:
- command:
- /bin/bash
- -ecx
- exec /cockroach/cockroach start --logtostderr --certs-dir /cockroach/cockroach-certs
--host $(hostname -f) --http-host 0.0.0.0 --join dev-base-cockroachdb-0.dev-base-cockroachdb,dev-base-cockroachdb-1.dev-base-cockroachdb,dev-base-cockroachdb-2.dev-base-cockroachdb
--cache 25% --max-sql-memory 25%
image: cockroachdb/cockroach:v1.1.5
imagePullPolicy: IfNotPresent
name: cockroachdb
ports:
- containerPort: 26257
name: grpc
- containerPort: 8080
name: http
volumeMounts:
- mountPath: /cockroach/cockroach-data
name: datadir
- mountPath: /cockroach/cockroach-certs
name: certs
initContainers:
- command:
- /bin/ash
- -ecx
- /request-cert -namespace=${POD_NAMESPACE} -certs-dir=/cockroach-certs -type=node
-addresses=localhost,127.0.0.1,${POD_IP},$(hostname -f),$(hostname -f|cut
-f 1-2 -d '.'),dev-base-cockroachdb-public -symlink-ca-from=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: cockroachdb/cockroach-k8s-request-cert:0.2
imagePullPolicy: IfNotPresent
name: init-certs
volumeMounts:
- mountPath: /cockroach-certs
name: certs
serviceAccountName: dev-base-cockroachdb
terminationGracePeriodSeconds: 60
volumes:
- name: datadir
persistentVolumeClaim:
claimName: datadir
- emptyDir: {}
name: certs
updateStrategy:
type: RollingUpdate
volumeClaimTemplates:
- metadata:
name: datadir
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb-budget
spec:
maxUnavailable: 1
selector:
matchLabels:
app: cockroachdb
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- get
- watch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
name: dev-base-cockroachdb
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
name: dev-base-cockroachdb
namespace: default

View File

@@ -0,0 +1,4 @@
namePrefix: dev-
bases:
- ../package

View File

@@ -0,0 +1,235 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: cockroachdb
labels:
app: cockroachdb
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: cockroachdb
labels:
app: cockroachdb
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: cockroachdb
labels:
app: cockroachdb
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- get
- watch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: cockroachdb
labels:
app: cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cockroachdb
subjects:
- kind: ServiceAccount
name: cockroachdb
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: cockroachdb
labels:
app: cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cockroachdb
subjects:
- kind: ServiceAccount
name: cockroachdb
namespace: default
---
apiVersion: v1
kind: Service
metadata:
# This service is meant to be used by clients of the database. It exposes a ClusterIP that will
# automatically load balance connections to the different database pods.
name: cockroachdb-public
labels:
app: cockroachdb
spec:
ports:
# The main port, served by gRPC, serves Postgres-flavor SQL, internode
# traffic and the cli.
- port: 26257
targetPort: 26257
name: grpc
# The secondary port serves the UI as well as health and debug endpoints.
- port: 8080
targetPort: 8080
name: http
selector:
app: cockroachdb
---
apiVersion: v1
kind: Service
metadata:
# This service only exists to create DNS entries for each pod in the stateful
# set such that they can resolve each other's IP addresses. It does not
# create a load-balanced ClusterIP and should not be used directly by clients
# in most circumstances.
name: cockroachdb
labels:
app: cockroachdb
annotations:
# This is needed to make the peer-finder work properly and to help avoid
# edge cases where instance 0 comes up after losing its data and needs to
# decide whether it should create a new cluster or try to join an existing
# one. If it creates a new cluster when it should have joined an existing
# one, we'd end up with two separate clusters listening at the same service
# endpoint, which would be very bad.
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
# Enable automatic monitoring of all instances when Prometheus is running in the cluster.
prometheus.io/scrape: "true"
prometheus.io/path: "_status/vars"
prometheus.io/port: "8080"
spec:
ports:
- port: 26257
targetPort: 26257
name: grpc
- port: 8080
targetPort: 8080
name: http
clusterIP: None
selector:
app: cockroachdb
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: cockroachdb-budget
labels:
app: cockroachdb
spec:
selector:
matchLabels:
app: cockroachdb
maxUnavailable: 1
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: cockroachdb
spec:
serviceName: "cockroachdb"
replicas: 3
template:
metadata:
labels:
app: cockroachdb
spec:
serviceAccountName: cockroachdb
# Init containers are run only once in the lifetime of a pod, before
# it's started up for the first time. It has to exit successfully
# before the pod's main containers are allowed to start.
initContainers:
# The init-certs container sends a certificate signing request to the
# kubernetes cluster.
# You can see pending requests using: kubectl get csr
# CSRs can be approved using: kubectl certificate approve <csr name>
#
# All addresses used to contact a node must be specified in the --addresses arg.
#
# In addition to the node certificate and key, the init-certs entrypoint will symlink
# the cluster CA to the certs directory.
- name: init-certs
image: cockroachdb/cockroach-k8s-request-cert:0.2
imagePullPolicy: IfNotPresent
command:
- "/bin/ash"
- "-ecx"
- "/request-cert -namespace=${POD_NAMESPACE} -certs-dir=/cockroach-certs -type=node -addresses=localhost,127.0.0.1,${POD_IP},$(hostname -f),$(hostname -f|cut -f 1-2 -d '.'),$(CDB_PUBLIC_SVC) -symlink-ca-from=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: certs
mountPath: /cockroach-certs
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cockroachdb
topologyKey: kubernetes.io/hostname
containers:
- name: cockroachdb
image: cockroachdb/cockroach:v1.1.5
imagePullPolicy: IfNotPresent
ports:
- containerPort: 26257
name: grpc
- containerPort: 8080
name: http
volumeMounts:
- name: datadir
mountPath: /cockroach/cockroach-data
- name: certs
mountPath: /cockroach/cockroach-certs
command:
- "/bin/bash"
- "-ecx"
# The use of qualified `hostname -f` is crucial:
# Other nodes aren't able to look up the unqualified hostname.
# Once 2.0 is out, we should be able to switch from --host to --advertise-host to make port-forwarding work to the main port.
- "exec /cockroach/cockroach start --logtostderr --certs-dir /cockroach/cockroach-certs --host $(hostname -f) --http-host 0.0.0.0 --join $(CDB_STATEFULSET_NAME)-0.$(CDB_STATEFULSET_SVC),$(CDB_STATEFULSET_NAME)-1.$(CDB_STATEFULSET_SVC),$(CDB_STATEFULSET_NAME)-2.$(CDB_STATEFULSET_SVC) --cache 25% --max-sql-memory 25%"
# No pre-stop hook is required, a SIGTERM plus some time is all that's
# needed for graceful shutdown of a node.
terminationGracePeriodSeconds: 60
volumes:
- name: datadir
persistentVolumeClaim:
claimName: datadir
- name: certs
emptyDir: {}
updateStrategy:
type: RollingUpdate
volumeClaimTemplates:
- metadata:
name: datadir
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: 1Gi

View File

@@ -0,0 +1,26 @@
namePrefix: base-
resources:
- cockroachdb-statefulset-secure.yaml
vars:
- name: CDB_PUBLIC_SVC
objref:
kind: Service
name: cockroachdb-public
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: CDB_STATEFULSET_NAME
objref:
kind: StatefulSet
name: cockroachdb
apiVersion: apps/v1beta1
fieldref:
fieldpath: metadata.name
- name: CDB_STATEFULSET_SVC
objref:
kind: Service
name: cockroachdb
apiVersion: v1
fieldref:
fieldpath: metadata.name

View File

@@ -0,0 +1,5 @@
description: variable reference and substitution
args: []
filename: testdata/testcase-variable-ref/in/overlay/
expectedStdout: testdata/testcase-variable-ref/expected.yaml
expectedDiff: testdata/testcase-variable-ref/expected.diff

View File

@@ -19,6 +19,7 @@ package resource
import (
"encoding/json"
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -109,3 +110,29 @@ func newUnstructuredFromObject(in runtime.Object) (*unstructured.Unstructured, e
err = out.UnmarshalJSON(marshaled)
return &out, err
}
func GetFieldValue(m map[string]interface{}, pathToField []string) (string, error) {
if len(pathToField) == 0 {
return "", fmt.Errorf("Field not found")
}
if len(pathToField) == 1 {
if v, found := m[pathToField[0]]; found {
if s, ok := v.(string); ok {
return s, nil
}
return "", fmt.Errorf("value at fieldpath is not of string type")
}
return "", fmt.Errorf("field at given fieldpath does not exist")
}
curr, rest := pathToField[0], pathToField[1]
v := m[curr]
switch typedV := v.(type) {
case map[string]interface{}:
return GetFieldValue(typedV, []string{rest})
default:
return "", fmt.Errorf("%#v is not expected to be a primitive type", typedV)
}
}

View File

@@ -0,0 +1,66 @@
/*
Copyright 2018 The Kubernetes Authors.
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.
*/
package resource
import (
"testing"
)
func TestGetFieldAsString(t *testing.T) {
m := map[string]interface{}{
"Kind": "Service",
"metadata": map[string]interface{}{
"labels": map[string]string{
"app": "application-name",
},
"name": "service-name",
},
}
tests := []struct {
pathToField []string
expectedName string
expectedError bool
}{
{
pathToField: []string{"Kind"},
expectedName: "Service",
expectedError: false,
},
{
pathToField: []string{"metadata", "name"},
expectedName: "service-name",
expectedError: false,
},
{
pathToField: []string{"metadata", "non-existing-field"},
expectedName: "",
expectedError: true,
},
}
for _, test := range tests {
s, err := GetFieldValue(m, test.pathToField)
if test.expectedError && err == nil {
t.Fatalf("should return error, but no error returned")
} else {
if test.expectedName != s {
t.Fatalf("Got:%s expected:%s", s, test.expectedName)
}
}
}
}

View File

@@ -0,0 +1,82 @@
package transformers
import (
"fmt"
"github.com/kubernetes-sigs/kustomize/pkg/expansion"
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type refvarTransformer struct {
pathConfigs []PathConfig
vars map[string]string
}
// NewRefVarTransformer returns a Trasformer that replaces $(VAR) style variables with values.
func NewRefVarTransformer(vars map[string]string) (Transformer, error) {
return &refvarTransformer{
vars: vars,
pathConfigs: []PathConfig{
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "StatefulSet"},
Path: []string{"spec", "template", "spec", "initContainers", "command"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "StatefulSet"},
Path: []string{"spec", "template", "spec", "containers", "command"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Job"},
Path: []string{"spec", "template", "spec", "containers", "command"},
},
},
}, nil
}
// Transform determines the final values of variables:
//
// 1. Determine the final value of each variable:
// a. If the variable's Value is set, expand the `$(var)` references to other
// variables in the .Value field; the sources of variables are the declared
// variables of the container and the service environment variables
// b. If a source is defined for an environment variable, resolve the source
// 2. Create the container's environment in the order variables are declared
// 3. Add remaining service environment vars
func (rv *refvarTransformer) Transform(resources resmap.ResMap) error {
for GVKn := range resources {
obj := resources[GVKn].Unstruct()
objMap := obj.UnstructuredContent()
for _, pc := range rv.pathConfigs {
if !selectByGVK(GVKn.Gvk(), pc.GroupVersionKind) {
continue
}
err := mutateField(objMap, pc.Path, false, func(in interface{}) (interface{}, error) {
var (
mappingFunc = expansion.MappingFuncFor(rv.vars)
)
switch vt := in.(type) {
case []interface{}:
var xs []string
for _, a := range in.([]interface{}) {
xs = append(xs, expansion.Expand(a.(string), mappingFunc))
}
return xs, nil
case interface{}:
s, ok := in.(string)
if !ok {
return nil, fmt.Errorf("%#v is expectd to be %T", in, s)
}
runtimeVal := expansion.Expand(s, mappingFunc)
return runtimeVal, nil
default:
return "", fmt.Errorf("invalid type encountered %T", vt)
}
})
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -62,6 +62,9 @@ type Kustomization struct {
// If a secret want to have a base and an overlay, it should go to Bases and
// Overlays fields.
SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"`
// Variables which will be substituted at runtime
Vars []Var `json:"vars,omitempty" yaml:"vars,omitempty"`
}
// ConfigMapArg contains the metadata of how to generate a configmap.

47
pkg/types/var.go Normal file
View File

@@ -0,0 +1,47 @@
/*
Copyright 2017 The Kubernetes Authors.
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.
*/
package types
import (
corev1 "k8s.io/api/core/v1"
)
// Var represents a variable whose value will be sourced
// from a field in a Kubernetes object.
type Var struct {
// Value of identifier name e.g. FOO used in container args, annotations
// Appears in pod template as $(FOO)
Name string `json:"name" yaml:"name"`
// ObjRef must refer to a Kubernetes resource under the
// purview of this kustomization. ObjRef should use the
// raw name of the object (the name specified in its YAML,
// before addition of a namePrefix).
ObjRef corev1.ObjectReference `json:"objref" yaml:"objref"`
// FieldRef refers to the field of the object referred to by
// ObjRef whose value will be extracted for use in
// replacing $(FOO).
// If unspecified, this defaults to fieldpath: metadata.name
FieldRef corev1.ObjectFieldSelector `json:"fieldref,omitempty" yaml:"objref,omitempty"`
}
func (v *Var) Defaulting() {
if (corev1.ObjectFieldSelector{}) == v.FieldRef {
v.FieldRef = corev1.ObjectFieldSelector{FieldPath: "metadata.name"}
}
}