mirror of https://github.com/k3s-io/k3s
kubeadm: graduate mark-control-plane phase
Co-authored-by: Lubomir I. Ivanov <lubomirivanov@vmware.com>pull/58/head
parent
a3ccea9d87
commit
daae2a86ea
|
@ -44,7 +44,7 @@ filegroup(
|
|||
"//cmd/kubeadm/app/phases/etcd:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/kubeconfig:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/kubelet:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/markmaster:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/markcontrolplane:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/patchnode:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/selfhosting:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/upgrade:all-srcs",
|
||||
|
|
|
@ -44,7 +44,7 @@ go_library(
|
|||
"//cmd/kubeadm/app/phases/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubelet:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/markmaster:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/markcontrolplane:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/patchnode:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/uploadconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
|
|
|
@ -53,7 +53,6 @@ func newCmdPhase(out io.Writer) *cobra.Command {
|
|||
}
|
||||
|
||||
cmd.AddCommand(phases.NewCmdAddon())
|
||||
cmd.AddCommand(phases.NewCmdMarkMaster())
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ import (
|
|||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
||||
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
|
||||
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
|
||||
uploadconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
|
@ -180,6 +179,7 @@ func NewCmdInit(out io.Writer) *cobra.Command {
|
|||
initRunner.AppendPhase(phases.NewEtcdPhase())
|
||||
initRunner.AppendPhase(phases.NewWaitControlPlanePhase())
|
||||
initRunner.AppendPhase(phases.NewUploadConfigPhase())
|
||||
initRunner.AppendPhase(phases.NewMarkControlPlanePhase())
|
||||
initRunner.AppendPhase(phases.NewBootstrapTokenPhase())
|
||||
// TODO: add other phases to the runner.
|
||||
|
||||
|
@ -491,12 +491,6 @@ func runInit(i *initData, out io.Writer) error {
|
|||
return errors.Wrap(err, "error creating kubelet configuration ConfigMap")
|
||||
}
|
||||
|
||||
// PHASE 4: Mark the master with the right label/taint
|
||||
klog.V(1).Infof("[init] marking the master with right label")
|
||||
if err := markmasterphase.MarkMaster(client, i.cfg.NodeRegistration.Name, i.cfg.NodeRegistration.Taints); err != nil {
|
||||
return errors.Wrap(err, "error marking master")
|
||||
}
|
||||
|
||||
// This feature is disabled by default
|
||||
if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) {
|
||||
kubeletVersion, err := preflight.GetKubeletVersion(utilsexec.New())
|
||||
|
|
|
@ -45,7 +45,7 @@ import (
|
|||
etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
|
||||
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
||||
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
|
||||
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
|
||||
markcontrolplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markcontrolplane"
|
||||
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
|
||||
uploadconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||
|
@ -563,9 +563,9 @@ func (j *Join) PostInstallControlPlane(initConfiguration *kubeadmapi.InitConfigu
|
|||
return errors.Wrap(err, "error uploading configuration")
|
||||
}
|
||||
|
||||
klog.V(1).Info("[join] marking the master with right label")
|
||||
if err = markmasterphase.MarkMaster(client, initConfiguration.NodeRegistration.Name, initConfiguration.NodeRegistration.Taints); err != nil {
|
||||
return errors.Wrap(err, "error applying master label and taints")
|
||||
klog.V(1).Info("[join] marking the control-plane with right label")
|
||||
if err = markcontrolplanephase.MarkControlPlane(client, initConfiguration.NodeRegistration.Name, initConfiguration.NodeRegistration.Taints); err != nil {
|
||||
return errors.Wrap(err, "error applying control-plane label and taints")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -10,7 +10,7 @@ go_library(
|
|||
"etcd.go",
|
||||
"kubeconfig.go",
|
||||
"kubelet.go",
|
||||
"markmaster.go",
|
||||
"markcontrolplane.go",
|
||||
"preflight.go",
|
||||
"uploadconfig.go",
|
||||
"util.go",
|
||||
|
@ -37,7 +37,7 @@ go_library(
|
|||
"//cmd/kubeadm/app/phases/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubelet:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/markmaster:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/markcontrolplane:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/patchnode:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/uploadconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
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 phases
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
||||
markcontrolplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markcontrolplane"
|
||||
"k8s.io/kubernetes/pkg/util/normalizer"
|
||||
)
|
||||
|
||||
var (
|
||||
markControlPlaneExample = normalizer.Examples(`
|
||||
# Applies control-plane label and taint to the current node, functionally equivalent to what executed by kubeadm init.
|
||||
kubeadm init phase mark-control-plane --config config.yml
|
||||
|
||||
# Applies control-plane label and taint to a specific node
|
||||
kubeadm init phase mark-control-plane --node-name myNode
|
||||
`)
|
||||
)
|
||||
|
||||
type markControlPlaneData interface {
|
||||
Cfg() *kubeadmapi.InitConfiguration
|
||||
Client() (clientset.Interface, error)
|
||||
DryRun() bool
|
||||
}
|
||||
|
||||
// NewMarkControlPlanePhase creates a kubeadm workflow phase that implements mark-controlplane checks.
|
||||
func NewMarkControlPlanePhase() workflow.Phase {
|
||||
return workflow.Phase{
|
||||
Name: "mark-control-plane",
|
||||
Short: "Mark a node as a control-plane",
|
||||
Example: markControlPlaneExample,
|
||||
CmdFlags: []string{
|
||||
options.NodeName,
|
||||
},
|
||||
Run: runMarkControlPlane,
|
||||
}
|
||||
}
|
||||
|
||||
// runMarkControlPlane executes markcontrolplane checks logic.
|
||||
func runMarkControlPlane(c workflow.RunData) error {
|
||||
data, ok := c.(markControlPlaneData)
|
||||
if !ok {
|
||||
return errors.New("mark-control-plane phase invoked with an invalid data struct")
|
||||
}
|
||||
|
||||
client, err := data.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeRegistration := data.Cfg().NodeRegistration
|
||||
if err := markcontrolplanephase.MarkControlPlane(client, nodeRegistration.Name, nodeRegistration.Taints); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
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 phases
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||
"k8s.io/kubernetes/pkg/util/normalizer"
|
||||
)
|
||||
|
||||
var (
|
||||
markMasterLongDesc = normalizer.LongDesc(`
|
||||
Applies a label that specifies that a node is a master and a taint that forces workloads to be deployed accordingly.
|
||||
` + cmdutil.AlphaDisclaimer)
|
||||
|
||||
markMasterExample = normalizer.Examples(`
|
||||
# Applies master label and taint to the current node, functionally equivalent to what executed by kubeadm init.
|
||||
kubeadm alpha phase mark-master
|
||||
|
||||
# Applies master label and taint to a specific node
|
||||
kubeadm alpha phase mark-master --node-name myNode
|
||||
`)
|
||||
)
|
||||
|
||||
// NewCmdMarkMaster returns the Cobra command for running the mark-master phase
|
||||
func NewCmdMarkMaster() *cobra.Command {
|
||||
cfg := &kubeadmapiv1beta1.InitConfiguration{}
|
||||
|
||||
// Default values for the cobra help text
|
||||
kubeadmscheme.Scheme.Default(cfg)
|
||||
|
||||
var cfgPath string
|
||||
kubeConfigFile := kubeadmconstants.GetAdminKubeConfigPath()
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "mark-master",
|
||||
Short: "Mark a node as master",
|
||||
Long: markMasterLongDesc,
|
||||
Example: markMasterExample,
|
||||
Aliases: []string{"markmaster"},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
|
||||
kubeadmutil.CheckErr(err)
|
||||
}
|
||||
|
||||
kubeConfigFile = cmdutil.FindExistingKubeConfig(kubeConfigFile)
|
||||
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
// KubernetesVersion is not used, but we set it explicitly to avoid the lookup
|
||||
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
|
||||
SetKubernetesVersion(cfg)
|
||||
|
||||
// This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags
|
||||
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
err = markmasterphase.MarkMaster(client, internalcfg.NodeRegistration.Name, internalcfg.NodeRegistration.Taints)
|
||||
kubeadmutil.CheckErr(err)
|
||||
},
|
||||
}
|
||||
|
||||
options.AddKubeConfigFlag(cmd.Flags(), &kubeConfigFile)
|
||||
cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental")
|
||||
cmd.Flags().StringVar(&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name, `The node name to which label and taints should apply`)
|
||||
|
||||
return cmd
|
||||
}
|
|
@ -8,7 +8,7 @@ load(
|
|||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["markmaster_test.go"],
|
||||
srcs = ["markcontrolplane_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
|
@ -23,8 +23,8 @@ go_test(
|
|||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["markmaster.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster",
|
||||
srcs = ["markcontrolplane.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/markcontrolplane",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package markmaster
|
||||
package markcontrolplane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -25,20 +25,20 @@ import (
|
|||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
)
|
||||
|
||||
// MarkMaster taints the master and sets the master label
|
||||
func MarkMaster(client clientset.Interface, masterName string, taints []v1.Taint) error {
|
||||
// MarkControlPlane taints the control-plane and sets the control-plane label
|
||||
func MarkControlPlane(client clientset.Interface, controlPlaneName string, taints []v1.Taint) error {
|
||||
|
||||
fmt.Printf("[markmaster] Marking the node %s as master by adding the label \"%s=''\"\n", masterName, constants.LabelNodeRoleMaster)
|
||||
fmt.Printf("[mark-control-plane] Marking the node %s as control-plane by adding the label \"%s=''\"\n", controlPlaneName, constants.LabelNodeRoleMaster)
|
||||
|
||||
if taints != nil && len(taints) > 0 {
|
||||
taintStrs := []string{}
|
||||
for _, taint := range taints {
|
||||
taintStrs = append(taintStrs, taint.ToString())
|
||||
}
|
||||
fmt.Printf("[markmaster] Marking the node %s as master by adding the taints %v\n", masterName, taintStrs)
|
||||
fmt.Printf("[mark-control-plane] Marking the node %s as control-plane by adding the taints %v\n", controlPlaneName, taintStrs)
|
||||
}
|
||||
|
||||
return apiclient.PatchNode(client, masterName, func(n *v1.Node) {
|
||||
return apiclient.PatchNode(client, controlPlaneName, func(n *v1.Node) {
|
||||
markMasterNode(n, taints)
|
||||
})
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package markmaster
|
||||
package markcontrolplane
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -33,7 +33,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/util/node"
|
||||
)
|
||||
|
||||
func TestMarkMaster(t *testing.T) {
|
||||
func TestMarkControlPlane(t *testing.T) {
|
||||
// Note: this test takes advantage of the deterministic marshalling of
|
||||
// JSON provided by strategicpatch so that "expectedPatch" can use a
|
||||
// string equality test instead of a logical JSON equality test. That
|
||||
|
@ -47,28 +47,28 @@ func TestMarkMaster(t *testing.T) {
|
|||
expectedPatch string
|
||||
}{
|
||||
{
|
||||
"master label and taint missing",
|
||||
"control-plane label and taint missing",
|
||||
"",
|
||||
nil,
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}},\"spec\":{\"taints\":[{\"effect\":\"NoSchedule\",\"key\":\"node-role.kubernetes.io/master\"}]}}",
|
||||
},
|
||||
{
|
||||
"master label and taint missing but taint not wanted",
|
||||
"control-plane label and taint missing but taint not wanted",
|
||||
"",
|
||||
nil,
|
||||
nil,
|
||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
|
||||
},
|
||||
{
|
||||
"master label missing",
|
||||
"control-plane label missing",
|
||||
"",
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
|
||||
},
|
||||
{
|
||||
"master taint missing",
|
||||
"control-plane taint missing",
|
||||
kubeadmconstants.LabelNodeRoleMaster,
|
||||
nil,
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
|
@ -110,9 +110,9 @@ func TestMarkMaster(t *testing.T) {
|
|||
for _, tc := range tests {
|
||||
hostname, err := node.GetHostname("")
|
||||
if err != nil {
|
||||
t.Fatalf("MarkMaster(%s): unexpected error: %v", tc.name, err)
|
||||
t.Fatalf("MarkControlPlane(%s): unexpected error: %v", tc.name, err)
|
||||
}
|
||||
masterNode := &v1.Node{
|
||||
controlPlaneNode := &v1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: hostname,
|
||||
Labels: map[string]string{
|
||||
|
@ -122,16 +122,16 @@ func TestMarkMaster(t *testing.T) {
|
|||
}
|
||||
|
||||
if tc.existingLabel != "" {
|
||||
masterNode.ObjectMeta.Labels[tc.existingLabel] = ""
|
||||
controlPlaneNode.ObjectMeta.Labels[tc.existingLabel] = ""
|
||||
}
|
||||
|
||||
if tc.existingTaints != nil {
|
||||
masterNode.Spec.Taints = tc.existingTaints
|
||||
controlPlaneNode.Spec.Taints = tc.existingTaints
|
||||
}
|
||||
|
||||
jsonNode, err := json.Marshal(masterNode)
|
||||
jsonNode, err := json.Marshal(controlPlaneNode)
|
||||
if err != nil {
|
||||
t.Fatalf("MarkMaster(%s): unexpected encoding error: %v", tc.name, err)
|
||||
t.Fatalf("MarkControlPlane(%s): unexpected encoding error: %v", tc.name, err)
|
||||
}
|
||||
|
||||
var patchRequest string
|
||||
|
@ -139,7 +139,7 @@ func TestMarkMaster(t *testing.T) {
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if req.URL.Path != "/api/v1/nodes/"+hostname {
|
||||
t.Errorf("MarkMaster(%s): request for unexpected HTTP resource: %v", tc.name, req.URL.Path)
|
||||
t.Errorf("MarkControlPlane(%s): request for unexpected HTTP resource: %v", tc.name, req.URL.Path)
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ func TestMarkMaster(t *testing.T) {
|
|||
case "PATCH":
|
||||
patchRequest = toString(req.Body)
|
||||
default:
|
||||
t.Errorf("MarkMaster(%s): request for unexpected HTTP verb: %v", tc.name, req.Method)
|
||||
t.Errorf("MarkControlPlane(%s): request for unexpected HTTP verb: %v", tc.name, req.Method)
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
@ -161,15 +161,15 @@ func TestMarkMaster(t *testing.T) {
|
|||
|
||||
cs, err := clientset.NewForConfig(&restclient.Config{Host: s.URL})
|
||||
if err != nil {
|
||||
t.Fatalf("MarkMaster(%s): unexpected error building clientset: %v", tc.name, err)
|
||||
t.Fatalf("MarkControlPlane(%s): unexpected error building clientset: %v", tc.name, err)
|
||||
}
|
||||
|
||||
if err := MarkMaster(cs, hostname, tc.newTaints); err != nil {
|
||||
t.Errorf("MarkMaster(%s) returned unexpected error: %v", tc.name, err)
|
||||
if err := MarkControlPlane(cs, hostname, tc.newTaints); err != nil {
|
||||
t.Errorf("MarkControlPlane(%s) returned unexpected error: %v", tc.name, err)
|
||||
}
|
||||
|
||||
if tc.expectedPatch != patchRequest {
|
||||
t.Errorf("MarkMaster(%s) wanted patch %v, got %v", tc.name, tc.expectedPatch, patchRequest)
|
||||
t.Errorf("MarkControlPlane(%s) wanted patch %v, got %v", tc.name, tc.expectedPatch, patchRequest)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue