mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 08:20:59 +00:00
Merge pull request #52 from Liujingfang1/master
variable reference support
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
150
pkg/commands/testdata/testcase-variable-ref/expected.diff
vendored
Normal file
150
pkg/commands/testdata/testcase-variable-ref/expected.diff
vendored
Normal 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:
|
||||
205
pkg/commands/testdata/testcase-variable-ref/expected.yaml
vendored
Normal file
205
pkg/commands/testdata/testcase-variable-ref/expected.yaml
vendored
Normal 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
|
||||
4
pkg/commands/testdata/testcase-variable-ref/in/overlay/kustomization.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-variable-ref/in/overlay/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
namePrefix: dev-
|
||||
bases:
|
||||
- ../package
|
||||
|
||||
235
pkg/commands/testdata/testcase-variable-ref/in/package/cockroachdb-statefulset-secure.yaml
vendored
Normal file
235
pkg/commands/testdata/testcase-variable-ref/in/package/cockroachdb-statefulset-secure.yaml
vendored
Normal 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
|
||||
26
pkg/commands/testdata/testcase-variable-ref/in/package/kustomization.yaml
vendored
Normal file
26
pkg/commands/testdata/testcase-variable-ref/in/package/kustomization.yaml
vendored
Normal 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
|
||||
|
||||
5
pkg/commands/testdata/testcase-variable-ref/test.yaml
vendored
Normal file
5
pkg/commands/testdata/testcase-variable-ref/test.yaml
vendored
Normal 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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
66
pkg/resource/resource_test.go
Normal file
66
pkg/resource/resource_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
82
pkg/transformers/refvars.go
Normal file
82
pkg/transformers/refvars.go
Normal 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
|
||||
}
|
||||
@@ -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
47
pkg/types/var.go
Normal 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"}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user