Merge pull request #10126 from medyagh/extension_context

add  annotation to kubeconfig to identify contexts/clusters created by minikube
pull/9985/head^2
Medya Ghazizadeh 2021-01-14 17:23:17 -08:00 committed by GitHub
commit 8b76fa2c46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 7 deletions

View File

@ -35,8 +35,9 @@ var updateContextCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
cname := ClusterFlagValue()
co := mustload.Running(cname)
// cluster extension metada for kubeconfig
updated, err := kubeconfig.UpdateEndpoint(cname, co.CP.Hostname, co.CP.Port, kubeconfig.PathFromEnv())
updated, err := kubeconfig.UpdateEndpoint(cname, co.CP.Hostname, co.CP.Port, kubeconfig.PathFromEnv(), kubeconfig.NewExtension())
if err != nil {
exit.Error(reason.HostKubeconfigUpdate, "update config", err)
}

View File

@ -99,6 +99,8 @@ func SetupCerts(cmd command.Runner, k8s config.KubernetesConfig, n config.Node)
ClientCertificate: path.Join(vmpath.GuestKubernetesCertsDir, "apiserver.crt"),
ClientKey: path.Join(vmpath.GuestKubernetesCertsDir, "apiserver.key"),
CertificateAuthority: path.Join(vmpath.GuestKubernetesCertsDir, "ca.crt"),
ExtensionContext: kubeconfig.NewExtension(),
ExtensionCluster: kubeconfig.NewExtension(),
KeepContext: false,
}

View File

@ -576,14 +576,14 @@ func (k *Bootstrapper) restartControlPlane(cfg config.ClusterConfig) error {
klog.Infof("restartCluster took %s", time.Since(start))
}()
version, err := util.ParseKubernetesVersion(cfg.KubernetesConfig.KubernetesVersion)
k8sVersion, err := util.ParseKubernetesVersion(cfg.KubernetesConfig.KubernetesVersion)
if err != nil {
return errors.Wrap(err, "parsing Kubernetes version")
}
phase := "alpha"
controlPlane := "controlplane"
if version.GTE(semver.MustParse("1.13.0")) {
if k8sVersion.GTE(semver.MustParse("1.13.0")) {
phase = "init"
controlPlane = "control-plane"
}
@ -603,7 +603,7 @@ func (k *Bootstrapper) restartControlPlane(cfg config.ClusterConfig) error {
}
// Save the costly tax of reinstalling Kubernetes if the only issue is a missing kube context
_, err = kubeconfig.UpdateEndpoint(cfg.Name, hostname, port, kubeconfig.PathFromEnv())
_, err = kubeconfig.UpdateEndpoint(cfg.Name, hostname, port, kubeconfig.PathFromEnv(), kubeconfig.NewExtension())
if err != nil {
klog.Warningf("unable to update kubeconfig (cluster will likely require a reset): %v", err)
}

View File

@ -0,0 +1,66 @@
/*
Copyright 2021 The Kubernetes Authors All rights reserved.
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 kubeconfig
import (
"time"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/minikube/pkg/version"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// implementing the runtime.Object internally so we can write extensions to kubeconfig
type Extension struct {
runtime.TypeMeta `json:",inline"`
Version string `json:"version"`
Provider string `json:"provider"`
LastUpdate string `json:"last-update"`
}
// NewExtension returns a minikube formated kubeconfig's extension block to idenity clusters and contexts
func NewExtension() *Extension {
return &Extension{
Provider: "minikube.sigs.k8s.io",
Version: version.GetVersion(),
// time format matching other RFC in notify.go
LastUpdate: time.Now().Format(time.RFC1123)}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extension.
func (in *Extension) DeepCopy() *Extension {
if in == nil {
return nil
}
out := new(Extension)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Extension) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Extension) DeepCopyInto(out *Extension) {
*out = *in
out.TypeMeta = in.TypeMeta
}

View File

@ -105,7 +105,7 @@ func Endpoint(contextName string, configPath ...string) (string, int, error) {
}
// UpdateEndpoint overwrites the IP stored in kubeconfig with the provided IP.
func UpdateEndpoint(contextName string, hostname string, port int, confpath string) (bool, error) {
func UpdateEndpoint(contextName string, hostname string, port int, confpath string, ext *Extension) (bool, error) {
if hostname == "" {
return false, fmt.Errorf("empty ip")
}
@ -136,6 +136,9 @@ func UpdateEndpoint(contextName string, hostname string, port int, confpath stri
CertificateAuthority: path.Join(gp, "ca.crt"),
KeepContext: false,
}
if ext != nil {
kcs.ExtensionCluster = ext
}
err = PopulateFromSettings(kcs, cfg)
if err != nil {
return false, errors.Wrap(err, "populating kubeconfig")

View File

@ -410,7 +410,7 @@ func TestUpdateIP(t *testing.T) {
t.Parallel()
configFilename := tempFile(t, test.existing)
defer os.Remove(configFilename)
statusActual, err := UpdateEndpoint("minikube", test.hostname, test.port, configFilename)
statusActual, err := UpdateEndpoint("minikube", test.hostname, test.port, configFilename, nil)
if err != nil && !test.err {
t.Errorf("Got unexpected error: %v", err)
}
@ -430,7 +430,7 @@ func TestUpdateIP(t *testing.T) {
t.Fatal(err)
}
if !configEquals(actual, expected) {
t.Fatal("configs did not match")
t.Fatalf("configs did not match: Actual:\n%+v\n Expected:\n%+v", actual, expected)
}
})

View File

@ -23,6 +23,7 @@ import (
"github.com/juju/mutex"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/klog/v2"
"k8s.io/minikube/pkg/util/lock"
@ -54,6 +55,12 @@ type Settings struct {
// Should the certificate files be embedded instead of referenced by path
EmbedCerts bool
// Extension meta data for the cluster
ExtensionCluster *Extension
// Extension meta data for the cluster
ExtensionContext *Extension
// kubeConfigFile is the path where the kube config is stored
// Only access this with atomic ops
kubeConfigFile atomic.Value
@ -83,6 +90,10 @@ func PopulateFromSettings(cfg *Settings, apiCfg *api.Config) error {
} else {
cluster.CertificateAuthority = cfg.CertificateAuthority
}
if cfg.ExtensionCluster != nil {
cluster.Extensions = map[string]runtime.Object{"cluster_info": cfg.ExtensionCluster.DeepCopy()}
}
apiCfg.Clusters[clusterName] = cluster
// user
@ -109,6 +120,10 @@ func PopulateFromSettings(cfg *Settings, apiCfg *api.Config) error {
context.Cluster = cfg.ClusterName
context.Namespace = cfg.Namespace
context.AuthInfo = userName
if cfg.ExtensionContext != nil {
context.Extensions = map[string]runtime.Object{"context_info": cfg.ExtensionContext.DeepCopy()}
}
apiCfg.Contexts[contextName] = context
// Only set current context to minikube if the user has not used the keepContext flag
@ -138,6 +153,9 @@ func Update(kcs *Settings) error {
return err
}
ext := NewExtension()
kcs.ExtensionCluster = ext
kcs.ExtensionContext = ext
err = PopulateFromSettings(kcs, kcfg)
if err != nil {
return err