Proxy config for control plane

Along with the change to support proxy configuration for control plane
there is a change for replacement transformer to support arrays of strings.

The current implementation of cloud-init configuration for the control plane
based on KubeadmControlPlane object and uses an array of strings for commands.

Change-Id: Id0a49cc1a0fdbc392c7c7a56859b21737065b0d6
This commit is contained in:
Stanislav Egorov 2020-09-29 09:42:00 -07:00
parent d812b6c165
commit 71f04ed976
5 changed files with 191 additions and 87 deletions

View File

@ -13,6 +13,13 @@ spec:
clusterConfiguration: clusterConfiguration:
apiServer: apiServer:
timeoutForControlPlane: 1000s timeoutForControlPlane: 1000s
files:
- path: "/etc/systemd/system/docker.service.d/http-proxy.conf"
content: |
[Service]
Environment="HTTP_PROXY=REPLACEMENT_HTTP_PROXY"
Environment="HTTPS_PROXY=REPLACEMENT_HTTPS_PROXY"
Environment="NO_PROXY=REPLACEMENT_NO_PROXY"
preKubeadmCommands: preKubeadmCommands:
- echo 'root:r00tme' | chpasswd - echo 'root:r00tme' | chpasswd
- echo 'ubuntu:r00tme' | chpasswd - echo 'ubuntu:r00tme' | chpasswd
@ -23,6 +30,12 @@ spec:
EOF EOF
- sysctl --system - sysctl --system
- swapoff -a - swapoff -a
- export HTTP_PROXY=REPLACEMENT_HTTP_PROXY
- export HTTPS_PROXY=REPLACEMENT_HTTPS_PROXY
- export http_proxy=${HTTP_PROXY}
- export https_proxy=${HTTPS_PROXY}
- export NO_PROXY=REPLACEMENT_NO_PROXY
- export no_proxy=${NO_PROXY}
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
- curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - - curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
- echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee -a /etc/apt/sources.list - echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee -a /etc/apt/sources.list
@ -35,6 +48,7 @@ spec:
containerd.io containerd.io
- apt install -y kubelet=1.18.6-00 kubeadm=1.18.6-00 kubectl=1.18.6-00 - apt install -y kubelet=1.18.6-00 kubeadm=1.18.6-00 kubectl=1.18.6-00
- apt-mark hold docker-ce docker-ce-cli containerd.io kubelet kubeadm kubectl - apt-mark hold docker-ce docker-ce-cli containerd.io kubelet kubeadm kubectl
- unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY no_proxy NO_PROXY
initConfiguration: initConfiguration:
nodeRegistration: nodeRegistration:
name: '{{ ds.meta_data.local_hostname }}' name: '{{ ds.meta_data.local_hostname }}'

View File

@ -0,0 +1,40 @@
# These rules inject env vars into the k8scontrol function.
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: k8scontrol-env-vars-replacements
replacements:
# Replace the proxy vars
- source:
objref:
name: env-vars-catalogue
fieldref: env.HTTP_PROXY
target:
objref:
kind: KubeadmControlPlane
name: cluster-controlplane
fieldrefs:
- "spec.kubeadmConfigSpec.preKubeadmCommands%REPLACEMENT_HTTP_PROXY%"
- "spec.kubeadmConfigSpec.files[path=/etc/systemd/system/docker.service.d/http-proxy.conf].content%REPLACEMENT_HTTP_PROXY%"
- source:
objref:
name: env-vars-catalogue
fieldref: env.HTTPS_PROXY
target:
objref:
kind: KubeadmControlPlane
name: cluster-controlplane
fieldrefs:
- "spec.kubeadmConfigSpec.preKubeadmCommands%REPLACEMENT_HTTPS_PROXY%"
- "spec.kubeadmConfigSpec.files[path=/etc/systemd/system/docker.service.d/http-proxy.conf].content%REPLACEMENT_HTTPS_PROXY%"
- source:
objref:
name: env-vars-catalogue
fieldref: env.NO_PROXY
target:
objref:
kind: KubeadmControlPlane
name: cluster-controlplane
fieldrefs:
- "spec.kubeadmConfigSpec.preKubeadmCommands%REPLACEMENT_NO_PROXY%"
- "spec.kubeadmConfigSpec.files[path=/etc/systemd/system/docker.service.d/http-proxy.conf].content%REPLACEMENT_NO_PROXY%"

View File

@ -2,3 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
resources: resources:
- versions.yaml - versions.yaml
- k8scontrol-env-vars.yaml

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"reflect"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -209,12 +210,6 @@ func substituteSubstring(tgt *yaml.RNode, fieldRef, substringPattern string, val
switch curVal.YNode().Kind { switch curVal.YNode().Kind {
case yaml.ScalarNode: case yaml.ScalarNode:
p := regexp.MustCompile(substringPattern) p := regexp.MustCompile(substringPattern)
if !p.MatchString(yaml.GetValue(curVal)) {
return ErrPatternSubstring{
Msg: fmt.Sprintf("pattern '%s' is defined in configuration but was not found in target value %s",
substringPattern, yaml.GetValue(curVal)),
}
}
curVal.YNode().Value = p.ReplaceAllString(yaml.GetValue(curVal), yaml.GetValue(value)) curVal.YNode().Value = p.ReplaceAllString(yaml.GetValue(curVal), yaml.GetValue(value))
case yaml.SequenceNode: case yaml.SequenceNode:
@ -227,12 +222,6 @@ func substituteSubstring(tgt *yaml.RNode, fieldRef, substringPattern string, val
return err return err
} }
p := regexp.MustCompile(substringPattern) p := regexp.MustCompile(substringPattern)
if !p.MatchString(yaml.GetValue(item)) {
return ErrPatternSubstring{
Msg: fmt.Sprintf("pattern '%s' is defined in configuration but was not found in target value %s",
substringPattern, yaml.GetValue(item)),
}
}
item.YNode().Value = p.ReplaceAllString(yaml.GetValue(item), yaml.GetValue(value)) item.YNode().Value = p.ReplaceAllString(yaml.GetValue(item), yaml.GetValue(value))
} }
default: default:
@ -343,6 +332,32 @@ func extractSubstringPattern(path string) (extractedPath string, substringPatter
return groups[1], groups[2] return groups[1], groups[2]
} }
// replaces substring in a string if pattern applies
func processString(field string, substringPattern string, replacement string) string {
pattern := regexp.MustCompile(substringPattern)
return pattern.ReplaceAllString(field, replacement)
}
// replaces substring in any string in the array if pattern applies
func processArray(tgt []string, pattern string, replacement string) []string {
result := make([]string, 0, len(tgt))
for _, field := range tgt {
result = append(result, processString(field, pattern, replacement))
}
return result
}
// converts array of interfaces to array of strings
func convertToStrings(iFaces []interface{}) ([]string, bool) {
result := []string{}
for _, val := range iFaces {
if str, ok := val.(string); ok {
result = append(result, str)
}
}
return result, (len(result) != 0)
}
// apply a substring substitution based on a pattern // apply a substring substitution based on a pattern
func applySubstringPattern(target interface{}, replacement interface{}, func applySubstringPattern(target interface{}, replacement interface{},
substringPattern string) (regexedReplacement interface{}, err error) { substringPattern string) (regexedReplacement interface{}, err error) {
@ -364,19 +379,23 @@ func applySubstringPattern(target interface{}, replacement interface{},
"with string or numeric replacement values"} "with string or numeric replacement values"}
} }
tgt, ok := target.(string) switch reflect.TypeOf(target).Kind() {
if !ok { case reflect.String:
return nil, ErrPatternSubstring{Msg: "pattern-based substitution can only be applied to string target fields"} return processString(target.(string), substringPattern, replacementString), nil
} case reflect.Slice:
if ifaceArray, ok := target.([]interface{}); ok {
p := regexp.MustCompile(substringPattern) if strArray, ok := convertToStrings(ifaceArray); ok {
if !p.MatchString(tgt) { return processArray(strArray, substringPattern, replacementString), nil
return nil, ErrPatternSubstring{ }
Msg: fmt.Sprintf("pattern '%s' is defined in configuration but was not found in target value %s", }
substringPattern, tgt), if strArray, ok := target.([]string); ok {
return processArray(strArray, substringPattern, replacementString), nil
} }
} }
return p.ReplaceAllString(tgt, replacementString), nil return nil, ErrPatternSubstring{
Msg: "pattern-based substitution can only be applied to string " +
"or array of strings target fields",
}
} }
func updateMapField(m map[string]interface{}, pathToField []string, replacement interface{}) error { func updateMapField(m map[string]interface{}, pathToField []string, replacement interface{}) error {

View File

@ -83,7 +83,7 @@ var testCases = []struct {
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_0
replacements: replacements:
- source: - source:
value: nginx:newtag value: nginx:newtag
@ -158,7 +158,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_1
replacements: replacements:
- source: - source:
value: 1.17.0 value: 1.17.0
@ -195,13 +195,82 @@ spec:
name: nginx-tagged name: nginx-tagged
`, `,
}, },
{ {
cfg: ` cfg: `
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_2
replacements:
- source:
value: test.proxy.com
target:
objref:
kind: Secret
name: deploy1_secret
fieldrefs:
- stringData%REPLACEME%
`,
in: `
apiVersion: v1
kind: Secret
metadata:
name: deploy1_secret
stringData: PROXY=REPLACEME
type: Opaque
`,
expectedOut: `apiVersion: v1
kind: Secret
metadata:
name: deploy1_secret
stringData: PROXY=test.proxy.com
type: Opaque
`,
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_3
replacements:
- source:
value: testString
target:
objref:
kind: KubeadmControlPlane
name: cluster-controlplane
fieldrefs:
- spec.kubeadmConfigSpec.preKubeadmCommands%REPLACEME%
`,
in: `
apiVersion: controlplane.cluster.x-k8s.io/v1alpha3
kind: KubeadmControlPlane
metadata:
name: cluster-controlplane
spec:
kubeadmConfigSpec:
preKubeadmCommands:
- echo REPLACEME
`,
expectedOut: `apiVersion: controlplane.cluster.x-k8s.io/v1alpha3
kind: KubeadmControlPlane
metadata:
name: cluster-controlplane
spec:
kubeadmConfigSpec:
preKubeadmCommands:
- echo testString
`,
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_4
replacements: replacements:
- source: - source:
objref: objref:
@ -270,7 +339,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_5
replacements: replacements:
- source: - source:
objref: objref:
@ -370,7 +439,7 @@ metadata:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_6
replacements: replacements:
- source: - source:
value: regexedtag value: regexedtag
@ -442,7 +511,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_7
replacements: replacements:
- source: - source:
objref: objref:
@ -499,7 +568,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_8
replacements: replacements:
- source: - source:
objref: objref:
@ -558,7 +627,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: test-for-numeric-conversion name: Test_Case_9
replacements: replacements:
- source: - source:
objref: objref:
@ -617,7 +686,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_10
replacements: replacements:
- source: - source:
objref: objref:
@ -652,7 +721,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_11
replacements: replacements:
- source: - source:
objref: objref:
@ -676,7 +745,7 @@ metadata:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_12
replacements: replacements:
- source: - source:
objref: objref:
@ -703,7 +772,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_13
replacements: replacements:
- source: - source:
objref: objref:
@ -742,7 +811,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_14
replacements: replacements:
- source: - source:
objref: objref:
@ -781,7 +850,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_15
replacements: replacements:
- source: - source:
objref: objref:
@ -822,7 +891,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_16
replacements: replacements:
- source: - source:
objref: objref:
@ -861,7 +930,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_17
replacements: replacements:
- source: - source:
objref: objref:
@ -900,7 +969,7 @@ spec:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_18
replacements: replacements:
- source: - source:
objref: objref:
@ -932,53 +1001,14 @@ spec:
containers: containers:
- image: nginx:TAG - image: nginx:TAG
name: nginx-latest`, name: nginx-latest`,
expectedErr: "pattern-based substitution can only be applied to string target fields", expectedErr: "pattern-based substitution can only be applied to string or array of strings target fields",
}, },
{ {
cfg: ` cfg: `
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer kind: ReplacementTransformer
metadata: metadata:
name: notImportantHere name: Test_Case_19
replacements:
- source:
objref:
kind: Pod
name: pod1
target:
objref:
kind: Deployment
fieldrefs:
- spec.template.spec.containers[name=nginx-latest].image%TAG%`,
in: `
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: myapp-container
image: busybox
---
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:latest
name: nginx-latest`,
expectedErr: "pattern 'TAG' is defined in configuration but was not found in target value nginx:latest",
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: notImportantHere
replacements: replacements:
- source: - source:
value: "12345678" value: "12345678"
@ -1050,15 +1080,15 @@ func TestReplacementTransformer(t *testing.T) {
func TestExec(t *testing.T) { func TestExec(t *testing.T) {
// TODO (dukov) Remove this once we migrate to new kustomize plugin approach // TODO (dukov) Remove this once we migrate to new kustomize plugin approach
// NOTE (dukov) we need this since error format is different for new kustomize plugins // NOTE (dukov) we need this since error format is different for new kustomize plugins
testCases[11].expectedErr = "wrong Node Kind for labels.somelabel expected: " + testCases[13].expectedErr = "wrong Node Kind for labels.somelabel expected: " +
"MappingNode was ScalarNode: value: {'some string value'}" "MappingNode was ScalarNode: value: {'some string value'}"
testCases[12].expectedErr = "wrong Node Kind for labels.somelabel expected: " + testCases[14].expectedErr = "wrong Node Kind for labels.somelabel expected: " +
"SequenceNode was ScalarNode: value: {'some string value'}" "SequenceNode was ScalarNode: value: {'some string value'}"
testCases[13].expectedErr = "wrong Node Kind for spec expected: " + testCases[15].expectedErr = "wrong Node Kind for spec expected: " +
"SequenceNode was MappingNode: value: {containers:\n- name: myapp-container\n image: busybox}" "SequenceNode was MappingNode: value: {containers:\n- name: myapp-container\n image: busybox}"
testCases[15].expectedErr = "wrong Node Kind for spec.containers expected: " + testCases[17].expectedErr = "wrong Node Kind for spec.containers expected: " +
"MappingNode was SequenceNode: value: {- name: myapp-container\n image: busybox}" "MappingNode was SequenceNode: value: {- name: myapp-container\n image: busybox}"
testCases[16].expectedErr = "wrong Node Kind for expected: " + testCases[18].expectedErr = "wrong Node Kind for expected: " +
"ScalarNode was MappingNode: value: {image: nginx:TAG\nname: nginx-latest}" "ScalarNode was MappingNode: value: {image: nginx:TAG\nname: nginx-latest}"
for i, tc := range testCases { for i, tc := range testCases {