Files
kustomize/examples/valueAdd.md
2020-05-11 10:56:49 -07:00

8.2 KiB

Simple addition of one string value

Suppose you have several distinct cloud projects (on GCP or AWS or whatever) named:

  • cat-111
  • dog-222
  • fox-333

These might be project names within the company, cloud billing identifiers, or both.

Further suppose

  • You want to deploy these projects to different k8s namespaces, named after the projects.

  • You need to specify the project name in various resource subfields.

  • You want to name the configuration directories using the project name.

Additionally you might want to deploy the projects one at a time, or all at once.

Ideally, you'll want to avoid specifying the project name in more than one place (i.e. you want to stay DRY).

Here's a possible layout:

├── all
│   └── kustomization.yaml
│
├── bases
│   └── iam-iap-tunnel
│       ├── kustomization.yaml
│       └── policymembers.yaml
│
└── projects
    ├── cat-111
    │   └── kustomization.yaml
    ├── dog-222
    │   └── kustomization.yaml
    └── fox-333
        └── kustomization.yaml

This layout allows each project to be individually buildable:

kustomize build projects/cat-111
kustomize build projects/dog-222
kustomize build projects/fox-333

or collectively buildable:

kustomize build all

Make a place to work:

DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/bases/iam-iap-tunnel
mkdir -p $DEMO_HOME/projects/cat-111
mkdir -p $DEMO_HOME/projects/dog-222
mkdir -p $DEMO_HOME/projects/fox-333

To ground this example with a common problem, assume a set of engineers:

who need particular access to one or more projects.

Define an instance of IAMCustomRole:

cat <<'EOF' >$DEMO_HOME/bases/iam-iap-tunnel/customroles.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMCustomRole
metadata:
  name: engineer
spec:
  title: Colorful Engineer
  permissions:
  - iap.tunnelInstances.accessViaIAP
  stage: GA
EOF

Define corresponding instances of IAMPolicyMember.

The resourceRef/external fields in these instances are intentionally incomplete, and will be completed by kustomize below.

The boilerplate in these instances could be removed by making a custom generator, but that's for different tutorial.

cat <<'EOF' >$DEMO_HOME/bases/iam-iap-tunnel/policymembers.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: iap-tunnel-red
spec:
  member: user:red@example.com
  role: roles/engineer
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    kind: Project
    external: projects
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: iap-tunnel-blue
spec:
  member: user:blue@example.com
  role: roles/engineer
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    kind: Project
    external: projects
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: iap-tunnel-yellow
spec:
  member: user:yellow@example.com
  role: roles/engineer
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    kind: Project
    external: projects
EOF

Make a base that combines these:

cat <<'EOF' >$DEMO_HOME/bases/iam-iap-tunnel/kustomization.yaml
resources:
- customroles.yaml
- policymembers.yaml
EOF

Make a transformer, which at the moment has no equivalent directive in the kustomization file.

Its purpose will be more evident momentarily.

mkdir -p $DEMO_HOME/transformers/setProject
cat <<'EOF' >$DEMO_HOME/transformers/setProject/kustomization.yaml
resources:
- setProject.yaml
EOF
cat <<'EOF' >$DEMO_HOME/transformers/setProject/setProject.yaml
apiVersion: builtin
kind: ValueAddTransformer
metadata:
  name: dirNameAdd

#  Omitting the 'value:' field means that the current
#  kustomization root directory name will be used as
#  the value.
# value:  not specified!

targets:
- fieldPath: metadata/namespace
- selector:
    kind: IAMPolicyMember
  fieldPath: spec/resourceRef/external
  filePathPosition: 2
EOF

Now make the cat, dog and fox variants.

These are the targets that one could independently apply to a cluster.

cat <<'EOF' >$DEMO_HOME/projects/cat-111/kustomization.yaml
resources:
- ../../bases/iam-iap-tunnel
transformers:
- ../../transformers/setProject
EOF
cat <<'EOF' >$DEMO_HOME/projects/dog-222/kustomization.yaml
resources:
- ../../bases/iam-iap-tunnel
transformers:
- ../../transformers/setProject
EOF
cat <<'EOF' >$DEMO_HOME/projects/fox-333/kustomization.yaml
resources:
- ../../bases/iam-iap-tunnel
transformers:
- ../../transformers/setProject
EOF

Then, optionally, a target to deploy all the projects at once:

mkdir -p $DEMO_HOME/all
cat <<'EOF' >$DEMO_HOME/all/kustomization.yaml
resources:
- ../projects/cat-111
- ../projects/dog-222
- ../projects/fox-333
EOF

The layout is now:

tree $DEMO_HOME

It should look like:

/tmp/someTmpDir
├── all
│   └── kustomization.yaml
├── bases
│   └── iam-iap-tunnel
│       ├── customroles.yaml
│       ├── kustomization.yaml
│       └── policymembers.yaml
├── projects
│   ├── cat-111
│   │   └── kustomization.yaml
│   ├── dog-222
│   │   └── kustomization.yaml
│   └── fox-333
│       └── kustomization.yaml
└── transformers
    └── setProject
        ├── kustomization.yaml
        └── setProject.yaml

The expected output from building the dog project is as follows:

cat <<EOF >$DEMO_HOME/out_expected.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMCustomRole
metadata:
  name: engineer
  namespace: dog-222
spec:
  permissions:
  - iap.tunnelInstances.accessViaIAP
  stage: GA
  title: Colorful Engineer
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: iap-tunnel-blue
  namespace: dog-222
spec:
  member: user:blue@example.com
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    external: projects/dog-222
    kind: Project
  role: roles/engineer
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: iap-tunnel-red
  namespace: dog-222
spec:
  member: user:red@example.com
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    external: projects/dog-222
    kind: Project
  role: roles/engineer
---
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: iap-tunnel-yellow
  namespace: dog-222
spec:
  member: user:yellow@example.com
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    external: projects/dog-222
    kind: Project
  role: roles/engineer
EOF

In this output, the namespace of all instances is the project name dog-222, and the project name also appears in the resourceRef field of the IAMPolicyMember instances. This project name only appears in the project directory name.

Confirm this is happens:

kustomize build $DEMO_HOME/projects/dog-222 >$DEMO_HOME/out_actual.yaml

Confirm expectations:

diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml

Build all the projects at once like this:

kustomize build $DEMO_HOME/all