mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
kubeadm: apply patches to static Pods
Add PatchStaticPod() in staticpod/utils.go Apply patches to static Pods in: - phases/controlplane/CreateStaticPodFiles() - phases/etcd/CreateLocalEtcdStaticPodManifestFile() and CreateStackedEtcdStaticPodManifestFile() Add unit tests and update Bazel.
This commit is contained in:
parent
144778db83
commit
ceb768ccbd
@ -19,6 +19,7 @@ package controlplane
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -117,6 +118,15 @@ func CreateStaticPodFiles(manifestDir, kustomizeDir, patchesDir string, cfg *kub
|
||||
spec = *kustomizedSpec
|
||||
}
|
||||
|
||||
// if patchesDir is defined, patch the static Pod manifest
|
||||
if patchesDir != "" {
|
||||
patchedSpec, err := staticpodutil.PatchStaticPod(&spec, patchesDir, os.Stdout)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to patch static Pod manifest file for %q", componentName)
|
||||
}
|
||||
spec = *patchedSpec
|
||||
}
|
||||
|
||||
// writes the StaticPodSpec to disk
|
||||
if err := staticpodutil.WriteStaticPodToDisk(componentName, manifestDir, spec); err != nil {
|
||||
return errors.Wrapf(err, "failed to create static pod manifest file for %q", componentName)
|
||||
|
@ -191,6 +191,52 @@ func TestCreateStaticPodFilesKustomize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateStaticPodFilesWithPatches(t *testing.T) {
|
||||
// Create temp folder for the test case
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Creates a Cluster Configuration
|
||||
cfg := &kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.9.0",
|
||||
}
|
||||
|
||||
patchesPath := filepath.Join(tmpdir, "patch-files")
|
||||
err := os.MkdirAll(patchesPath, 0777)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create %s", patchesPath)
|
||||
}
|
||||
|
||||
patchString := dedent.Dedent(`
|
||||
metadata:
|
||||
annotations:
|
||||
patched: "true"
|
||||
`)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(patchesPath, kubeadmconstants.KubeAPIServer+".yaml"), []byte(patchString), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("WriteFile returned unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Execute createStaticPodFunction with patches
|
||||
manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName)
|
||||
err = CreateStaticPodFiles(manifestPath, "", patchesPath, cfg, &kubeadmapi.APIEndpoint{}, kubeadmconstants.KubeAPIServer)
|
||||
if err != nil {
|
||||
t.Errorf("Error executing createStaticPodFunction: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
pod, err := staticpodutil.ReadStaticPodFromDisk(filepath.Join(manifestPath, fmt.Sprintf("%s.yaml", kubeadmconstants.KubeAPIServer)))
|
||||
if err != nil {
|
||||
t.Errorf("Error executing ReadStaticPodFromDisk: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := pod.ObjectMeta.Annotations["patched"]; !ok {
|
||||
t.Errorf("Patches were not applied to %s", kubeadmconstants.KubeAPIServer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAPIServerCommand(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
|
@ -19,6 +19,7 @@ package etcd
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -64,6 +65,15 @@ func CreateLocalEtcdStaticPodManifestFile(manifestDir, kustomizeDir, patchesDir
|
||||
spec = *kustomizedSpec
|
||||
}
|
||||
|
||||
// if patchesDir is defined, patch the static Pod manifest
|
||||
if patchesDir != "" {
|
||||
patchedSpec, err := staticpodutil.PatchStaticPod(&spec, patchesDir, os.Stdout)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to patch static Pod manifest file for %q", kubeadmconstants.Etcd)
|
||||
}
|
||||
spec = *patchedSpec
|
||||
}
|
||||
|
||||
// writes etcd StaticPod to disk
|
||||
if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil {
|
||||
return err
|
||||
@ -174,6 +184,15 @@ func CreateStackedEtcdStaticPodManifestFile(client clientset.Interface, manifest
|
||||
spec = *kustomizedSpec
|
||||
}
|
||||
|
||||
// if patchesDir is defined, patch the static Pod manifest
|
||||
if patchesDir != "" {
|
||||
patchedSpec, err := staticpodutil.PatchStaticPod(&spec, patchesDir, os.Stdout)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to patch static Pod manifest file for %q", kubeadmconstants.Etcd)
|
||||
}
|
||||
spec = *patchedSpec
|
||||
}
|
||||
|
||||
// writes etcd StaticPod to disk
|
||||
if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil {
|
||||
return err
|
||||
|
@ -166,6 +166,56 @@ func TestCreateLocalEtcdStaticPodManifestFileKustomize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateLocalEtcdStaticPodManifestFileWithPatches(t *testing.T) {
|
||||
// Create temp folder for the test case
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Creates a Cluster Configuration
|
||||
cfg := &kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: tmpdir + "/etcd",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
patchesPath := filepath.Join(tmpdir, "patch-files")
|
||||
err := os.MkdirAll(patchesPath, 0777)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create %s", patchesPath)
|
||||
}
|
||||
|
||||
patchString := dedent.Dedent(`
|
||||
metadata:
|
||||
annotations:
|
||||
patched: "true"
|
||||
`)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(patchesPath, kubeadmconstants.Etcd+".yaml"), []byte(patchString), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("WriteFile returned unexpected error: %v", err)
|
||||
}
|
||||
|
||||
manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName)
|
||||
err = CreateLocalEtcdStaticPodManifestFile(manifestPath, "", patchesPath, "", cfg, &kubeadmapi.APIEndpoint{})
|
||||
if err != nil {
|
||||
t.Errorf("Error executing createStaticPodFunction: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
pod, err := staticpodutil.ReadStaticPodFromDisk(filepath.Join(manifestPath, kubeadmconstants.Etcd+".yaml"))
|
||||
if err != nil {
|
||||
t.Errorf("Error executing ReadStaticPodFromDisk: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := pod.ObjectMeta.Annotations["patched"]; !ok {
|
||||
t.Errorf("Patches were not applied to %s", kubeadmconstants.Etcd)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEtcdCommand(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
|
@ -29,6 +29,7 @@ go_library(
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/kustomize:go_default_library",
|
||||
"//cmd/kubeadm/app/util/patches:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
|
@ -19,6 +19,7 @@ package staticpod
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"net/url"
|
||||
@ -37,6 +38,7 @@ import (
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/kustomize"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/patches"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -180,6 +182,48 @@ func KustomizeStaticPod(pod *v1.Pod, kustomizeDir string) (*v1.Pod, error) {
|
||||
return pod2, nil
|
||||
}
|
||||
|
||||
// PatchStaticPod applies patches stored in patchesDir to a static Pod.
|
||||
func PatchStaticPod(pod *v1.Pod, patchesDir string, output io.Writer) (*v1.Pod, error) {
|
||||
// Marshal the Pod manifest into YAML.
|
||||
podYAML, err := kubeadmutil.MarshalToYaml(pod, v1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return pod, errors.Wrapf(err, "failed to marshal Pod manifest to YAML")
|
||||
}
|
||||
|
||||
var knownTargets = []string{
|
||||
kubeadmconstants.Etcd,
|
||||
kubeadmconstants.KubeAPIServer,
|
||||
kubeadmconstants.KubeControllerManager,
|
||||
kubeadmconstants.KubeScheduler,
|
||||
}
|
||||
|
||||
patchManager, err := patches.GetPatchManagerForPath(patchesDir, knownTargets, output)
|
||||
if err != nil {
|
||||
return pod, err
|
||||
}
|
||||
|
||||
patchTarget := &patches.PatchTarget{
|
||||
Name: pod.Name,
|
||||
StrategicMergePatchObject: v1.Pod{},
|
||||
Data: podYAML,
|
||||
}
|
||||
if err := patchManager.ApplyPatchesToTarget(patchTarget); err != nil {
|
||||
return pod, err
|
||||
}
|
||||
|
||||
obj, err := kubeadmutil.UnmarshalFromYaml(patchTarget.Data, v1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return pod, errors.Wrap(err, "failed to unmarshal patched manifest from YAML")
|
||||
}
|
||||
|
||||
pod2, ok := obj.(*v1.Pod)
|
||||
if !ok {
|
||||
return pod, errors.Wrap(err, "patched manifest is not a valid Pod object")
|
||||
}
|
||||
|
||||
return pod2, nil
|
||||
}
|
||||
|
||||
// WriteStaticPodToDisk writes a static pod file to disk
|
||||
func WriteStaticPodToDisk(componentName, manifestDir string, pod v1.Pod) error {
|
||||
|
||||
|
@ -796,3 +796,84 @@ func TestKustomizeStaticPod(t *testing.T) {
|
||||
t.Error("Kustomize did not apply patches corresponding to the resource")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatchStaticPod(t *testing.T) {
|
||||
type file struct {
|
||||
name string
|
||||
data string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
files []*file
|
||||
pod *v1.Pod
|
||||
expectedPod *v1.Pod
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid: patch a kube-apiserver target using a couple of ordered patches",
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "kube-apiserver",
|
||||
Namespace: "foo",
|
||||
},
|
||||
},
|
||||
expectedPod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "kube-apiserver",
|
||||
Namespace: "bar2",
|
||||
},
|
||||
},
|
||||
files: []*file{
|
||||
{
|
||||
name: "kube-apiserver1+merge.json",
|
||||
data: `{"metadata":{"namespace":"bar2"}}`,
|
||||
},
|
||||
{
|
||||
name: "kube-apiserver0+json.json",
|
||||
data: `[{"op": "replace", "path": "/metadata/namespace", "value": "bar1"}]`,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid: unknown patch target name",
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: "bar",
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "patch-files")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
for _, file := range tc.files {
|
||||
filePath := filepath.Join(tempDir, file.name)
|
||||
err := ioutil.WriteFile(filePath, []byte(file.data), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("could not write temporary file %q", filePath)
|
||||
}
|
||||
}
|
||||
|
||||
pod, err := PatchStaticPod(tc.pod, tempDir, ioutil.Discard)
|
||||
if (err != nil) != tc.expectedError {
|
||||
t.Fatalf("expected error: %v, got: %v, error: %v", tc.expectedError, (err != nil), err)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if tc.expectedPod.String() != pod.String() {
|
||||
t.Fatalf("expected object:\n%s\ngot:\n%s", tc.expectedPod.String(), pod.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user