diff --git a/pkg/cmd/server/start/start_kube_controller_manager.go b/pkg/cmd/server/start/start_kube_controller_manager.go index 173b60ab917b..3443cf83d043 100644 --- a/pkg/cmd/server/start/start_kube_controller_manager.go +++ b/pkg/cmd/server/start/start_kube_controller_manager.go @@ -1,27 +1,17 @@ package start import ( - "io/ioutil" - "os" "strconv" "github.com/golang/glog" "github.com/spf13/pflag" - kapiv1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" kerrors "k8s.io/apimachinery/pkg/util/errors" - kinformers "k8s.io/client-go/informers" controllerapp "k8s.io/kubernetes/cmd/kube-controller-manager/app" controlleroptions "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" - "k8s.io/kubernetes/pkg/api/legacyscheme" - "k8s.io/kubernetes/pkg/volume" _ "k8s.io/kubernetes/plugin/pkg/scheduler/algorithmprovider" - "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" cmdflags "github.com/openshift/origin/pkg/cmd/util/flags" - "k8s.io/kubernetes/pkg/apis/componentconfig" ) func kubeControllerManagerAddFlags(cmserver *controlleroptions.CMServer) func(flags *pflag.FlagSet) { @@ -30,14 +20,8 @@ func kubeControllerManagerAddFlags(cmserver *controlleroptions.CMServer) func(fl } } -func newKubeControllerManager(kubeconfigFile, saPrivateKeyFile, saRootCAFile, podEvictionTimeout, recyclerImage string, dynamicProvisioningEnabled bool, controllerArgs map[string][]string) (*controlleroptions.CMServer, []func(), error) { +func newKubeControllerManager(kubeconfigFile, saPrivateKeyFile, saRootCAFile, podEvictionTimeout, openshiftConfigFile string, dynamicProvisioningEnabled bool) (*controlleroptions.CMServer, error) { cmdLineArgs := map[string][]string{} - // deep-copy the input args to avoid mutation conflict. - for k, v := range controllerArgs { - cmdLineArgs[k] = append([]string{}, v...) - } - cleanupFunctions := []func(){} - if _, ok := cmdLineArgs["controllers"]; !ok { cmdLineArgs["controllers"] = []string{ "*", // start everything but the exceptions} @@ -91,158 +75,24 @@ func newKubeControllerManager(kubeconfigFile, saPrivateKeyFile, saRootCAFile, po if _, ok := cmdLineArgs["leader-elect-resource-lock"]; !ok { cmdLineArgs["leader-elect-resource-lock"] = []string{"configmaps"} } - - _, hostPathTemplateSet := cmdLineArgs["pv-recycler-pod-template-filepath-hostpath"] - _, nfsTemplateSet := cmdLineArgs["pv-recycler-pod-template-filepath-nfs"] - if !hostPathTemplateSet || !nfsTemplateSet { - // OpenShift uses a different default volume recycler template than - // Kubernetes. This default template is hardcoded in Kubernetes and it - // isn't possible to pass it via ControllerContext. Crate a temporary - // file with OpenShift's template and let's pretend it was set by user - // as --recycler-pod-template-filepath-hostpath and - // --pv-recycler-pod-template-filepath-nfs arguments. - // This template then needs to be deleted by caller! - templateFilename, err := createRecylerTemplate(recyclerImage) - if err != nil { - return nil, nil, err - } - - cleanupFunctions = append(cleanupFunctions, func() { - // Remove the template when it's not needed. This is called aftet - // controller is initialized - glog.V(4).Infof("Removing temporary file %s", templateFilename) - err := os.Remove(templateFilename) - if err != nil { - glog.Warningf("Failed to remove %s: %v", templateFilename, err) - } - }) - - if !hostPathTemplateSet { - cmdLineArgs["pv-recycler-pod-template-filepath-hostpath"] = []string{templateFilename} - } - if !nfsTemplateSet { - cmdLineArgs["pv-recycler-pod-template-filepath-nfs"] = []string{templateFilename} - } - } + cmdLineArgs["openshift-config"] = []string{openshiftConfigFile} // resolve arguments controllerManager := controlleroptions.NewCMServer() if err := cmdflags.Resolve(cmdLineArgs, kubeControllerManagerAddFlags(controllerManager)); len(err) > 0 { - return nil, cleanupFunctions, kerrors.NewAggregate(err) + return nil, kerrors.NewAggregate(err) } - // TODO make this configurable or discoverable. This is going to prevent us from running the stock GC controller - // IF YOU ADD ANYTHING TO THIS LIST, MAKE SURE THAT YOU UPDATE THEIR STRATEGIES TO PREVENT GC FINALIZERS - controllerManager.GCIgnoredResources = append(controllerManager.GCIgnoredResources, - // explicitly disabled from GC for now - not enough value to track them - componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "rolebindingrestrictions"}, - componentconfig.GroupResource{Group: "network.openshift.io", Resource: "clusternetworks"}, - componentconfig.GroupResource{Group: "network.openshift.io", Resource: "egressnetworkpolicies"}, - componentconfig.GroupResource{Group: "network.openshift.io", Resource: "hostsubnets"}, - componentconfig.GroupResource{Group: "network.openshift.io", Resource: "netnamespaces"}, - componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthclientauthorizations"}, - componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthclients"}, - componentconfig.GroupResource{Group: "quota.openshift.io", Resource: "clusterresourcequotas"}, - componentconfig.GroupResource{Group: "user.openshift.io", Resource: "groups"}, - componentconfig.GroupResource{Group: "user.openshift.io", Resource: "identities"}, - componentconfig.GroupResource{Group: "user.openshift.io", Resource: "users"}, - componentconfig.GroupResource{Group: "image.openshift.io", Resource: "images"}, - - // virtual resource - componentconfig.GroupResource{Group: "project.openshift.io", Resource: "projects"}, - // virtual and unwatchable resource, surfaced via rbac.authorization.k8s.io objects - componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "clusterroles"}, - componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "clusterrolebindings"}, - componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "roles"}, - componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "rolebindings"}, - // these resources contain security information in their names, and we don't need to track them - componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthaccesstokens"}, - componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthauthorizetokens"}, - // exposed already as extensions v1beta1 by other controllers - componentconfig.GroupResource{Group: "apps", Resource: "deployments"}, - // exposed as autoscaling v1 - componentconfig.GroupResource{Group: "extensions", Resource: "horizontalpodautoscalers"}, - // exposed as security.openshift.io v1 - componentconfig.GroupResource{Group: "", Resource: "securitycontextconstraints"}, - ) - - return controllerManager, cleanupFunctions, nil + return controllerManager, nil } -func createRecylerTemplate(recyclerImage string) (string, error) { - uid := int64(0) - template := volume.NewPersistentVolumeRecyclerPodTemplate() - template.Namespace = "openshift-infra" - template.Spec.ServiceAccountName = bootstrappolicy.InfraPersistentVolumeRecyclerControllerServiceAccountName - template.Spec.Containers[0].Image = recyclerImage - template.Spec.Containers[0].Command = []string{"/usr/bin/openshift-recycle"} - template.Spec.Containers[0].Args = []string{"/scrub"} - template.Spec.Containers[0].SecurityContext = &kapiv1.SecurityContext{RunAsUser: &uid} - template.Spec.Containers[0].ImagePullPolicy = kapiv1.PullIfNotPresent - - templateBytes, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(kapiv1.SchemeGroupVersion), template) - if err != nil { - return "", err - } - - f, err := ioutil.TempFile("", "openshift-recycler-template-") - if err != nil { - return "", err - } - filename := f.Name() - glog.V(4).Infof("Creating file %s with recycler templates", filename) - - _, err = f.Write(templateBytes) - if err != nil { - f.Close() - os.Remove(filename) - return "", err - } - f.Close() - return filename, nil -} - -func runEmbeddedKubeControllerManager(kubeconfigFile, saPrivateKeyFile, saRootCAFile, podEvictionTimeout string, dynamicProvisioningEnabled bool, cmdLineArgs map[string][]string, - recyclerImage string, informers *informers) { - - // Overwrite the informers, because we have our custom generic informers for quota. - // TODO update quota to create its own informer like garbage collection or if we split this out, actually add our external types to the kube generic informer - controllerapp.InformerFactoryOverride = externalKubeInformersWithExtraGenerics{ - SharedInformerFactory: informers.GetExternalKubeInformers(), - genericResourceInformer: informers.ToGenericInformer(), - } - +func runEmbeddedKubeControllerManager(kubeconfigFile, saPrivateKeyFile, saRootCAFile, podEvictionTimeout, openshiftConfigFile string, dynamicProvisioningEnabled bool) { // TODO we need a real identity for this. Right now it's just using the loopback connection like it used to. - controllerManager, cleanupFunctions, err := newKubeControllerManager(kubeconfigFile, saPrivateKeyFile, saRootCAFile, podEvictionTimeout, recyclerImage, dynamicProvisioningEnabled, cmdLineArgs) - defer func() { - // Clean up any temporary files and similar stuff. - // TODO: Make sure this defer is actually called - controllerapp.Run() - // below never returns -> defer is not called. - for _, f := range cleanupFunctions { - f() - } - }() - + controllerManager, err := newKubeControllerManager(kubeconfigFile, saPrivateKeyFile, saRootCAFile, podEvictionTimeout, openshiftConfigFile, dynamicProvisioningEnabled) if err != nil { glog.Fatal(err) } - // this does a second leader election, but doing the second leader election will allow us to move out process in - // 3.8 if we so choose. if err := controllerapp.Run(controllerManager); err != nil { glog.Fatal(err) } } - -type externalKubeInformersWithExtraGenerics struct { - kinformers.SharedInformerFactory - genericResourceInformer GenericResourceInformer -} - -func (i externalKubeInformersWithExtraGenerics) ForResource(resource schema.GroupVersionResource) (kinformers.GenericInformer, error) { - return i.genericResourceInformer.ForResource(resource) -} - -func (i externalKubeInformersWithExtraGenerics) Start(stopCh <-chan struct{}) { - i.SharedInformerFactory.Start(stopCh) - i.genericResourceInformer.Start(stopCh) -} diff --git a/pkg/cmd/server/start/start_master.go b/pkg/cmd/server/start/start_master.go index 3db88a042d9e..ce7e7093c087 100644 --- a/pkg/cmd/server/start/start_master.go +++ b/pkg/cmd/server/start/start_master.go @@ -398,19 +398,12 @@ func (m *Master) Start() error { return err } - imageTemplate := variable.NewDefaultImageTemplate() - imageTemplate.Format = m.config.ImageConfig.Format - imageTemplate.Latest = m.config.ImageConfig.Latest - recyclerImage := imageTemplate.ExpandOrDie("recycler") - // you can't double run healthz, so only do this next bit if we aren't starting the API if !m.api { - glog.Infof("Starting controllers on %s (%s)", m.config.ServingInfo.BindAddress, version.Get().String()) if len(m.config.DisabledFeatures) > 0 { glog.V(4).Infof("Disabled features: %s", strings.Join(m.config.DisabledFeatures, ", ")) } - glog.Infof("Using images from %q", imageTemplate.ExpandOrDie("")) if err := origincontrollers.RunControllerServer(m.config.ServingInfo, clientGoKubeExternal); err != nil { return err @@ -465,19 +458,32 @@ func (m *Master) Start() error { go runEmbeddedScheduler(m.config.MasterClients.OpenShiftLoopbackKubeConfig, m.config.KubernetesMasterConfig.SchedulerConfigFile, m.config.KubernetesMasterConfig.SchedulerArguments) - kubeControllerInformers, err := NewInformers(*m.config) - if err != nil { - return err - } - go runEmbeddedKubeControllerManager( - m.config.MasterClients.OpenShiftLoopbackKubeConfig, - m.config.ServiceAccountConfig.PrivateKeyFile, - m.config.ServiceAccountConfig.MasterCA, - m.config.KubernetesMasterConfig.PodEvictionTimeout, - m.config.VolumeConfig.DynamicProvisioningEnabled, - m.config.KubernetesMasterConfig.ControllerArguments, - recyclerImage, - kubeControllerInformers) + go func() { + kubeControllerConfigBytes, err := configapilatest.WriteYAML(m.config) + if err != nil { + glog.Fatal(err) + } + // this creates using 0600 + kubeControllerConfigFile, err := ioutil.TempFile("", "openshift-kube-controler-manager-config.yaml") + if err != nil { + glog.Fatal(err) + } + defer func() { + os.Remove(kubeControllerConfigFile.Name()) + }() + if err := ioutil.WriteFile(kubeControllerConfigFile.Name(), kubeControllerConfigBytes, 0644); err != nil { + glog.Fatal(err) + } + + runEmbeddedKubeControllerManager( + m.config.MasterClients.OpenShiftLoopbackKubeConfig, + m.config.ServiceAccountConfig.PrivateKeyFile, + m.config.ServiceAccountConfig.MasterCA, + m.config.KubernetesMasterConfig.PodEvictionTimeout, + kubeControllerConfigFile.Name(), + m.config.VolumeConfig.DynamicProvisioningEnabled, + ) + }() go func() { controllerPlug.WaitForStart() diff --git a/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/BUILD b/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/BUILD index f378d945812f..2a047d4db3f4 100644 --- a/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/BUILD @@ -19,6 +19,7 @@ go_library( "//pkg/controller/service:go_default_library", "//pkg/util/configz:go_default_library", "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/pborman/uuid:go_default_library", "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/controllermanager.go b/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/controllermanager.go index c93da56dad55..9a569361e8ac 100644 --- a/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/controllermanager.go +++ b/vendor/k8s.io/kubernetes/cmd/cloud-controller-manager/app/controllermanager.go @@ -49,6 +49,7 @@ import ( "k8s.io/kubernetes/pkg/util/configz" "github.com/golang/glog" + "github.com/pborman/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -158,6 +159,8 @@ func Run(s *options.CloudControllerManagerServer) error { if err != nil { return err } + // add a uniquifier so that two processes on the same host don't accidentally both become active + id = id + " " + string(uuid.NewUUID()) // Lock required for leader election rl, err := resourcelock.New(s.LeaderElection.ResourceLock, diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD index a533b2e29fc1..c42640f8da6b 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD @@ -113,6 +113,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go index 62fd912667bd..c23a78ae020c 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go @@ -64,6 +64,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/spf13/cobra" "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/util/uuid" ) const ( @@ -121,6 +122,12 @@ func Run(s *options.CMServer) error { return err } + cleanupFn, err := ShimForOpenShift(s, kubeconfig) + if err != nil { + return err + } + defer cleanupFn() + if s.Port >= 0 { go startHTTP(s) } @@ -172,6 +179,8 @@ func Run(s *options.CMServer) error { if err != nil { return err } + // add a uniquifier so that two processes on the same host don't accidentally both become active + id = id + " " + string(uuid.NewUUID()) rl, err := resourcelock.New(s.LeaderElection.ResourceLock, "kube-system", @@ -426,10 +435,10 @@ func GetAvailableResources(clientBuilder controller.ControllerClientBuilder) (ma func CreateControllerContext(s *options.CMServer, rootClientBuilder, clientBuilder controller.ControllerClientBuilder, stop <-chan struct{}) (ControllerContext, error) { versionedClient := rootClientBuilder.ClientOrDie("shared-informers") var sharedInformers informers.SharedInformerFactory - if InformerFactoryOverride == nil{ + if InformerFactoryOverride == nil { sharedInformers = informers.NewSharedInformerFactory(versionedClient, ResyncPeriod(s)()) - } else{ - sharedInformers = InformerFactoryOverride + } else { + sharedInformers = InformerFactoryOverride } availableResources, err := GetAvailableResources(rootClientBuilder) diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/options/options.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/options/options.go index d681bfd18957..aeaf00b22acc 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/options/options.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/options/options.go @@ -55,6 +55,8 @@ type CMServer struct { Master string Kubeconfig string + + OpenShiftConfig string } // NewCMServer creates a new CMServer with a default config. @@ -135,6 +137,9 @@ func NewCMServer() *CMServer { // AddFlags adds flags for a specific CMServer to the specified FlagSet func (s *CMServer) AddFlags(fs *pflag.FlagSet, allControllers []string, disabledByDefaultControllers []string) { + fs.StringVar(&s.OpenShiftConfig, "openshift-config", s.OpenShiftConfig, "indicates that this process should be compatible with openshift start master") + fs.MarkHidden("openshift-config") + fs.StringSliceVar(&s.Controllers, "controllers", s.Controllers, fmt.Sprintf(""+ "A list of controllers to enable. '*' enables all on-by-default controllers, 'foo' enables the controller "+ "named 'foo', '-foo' disables the controller named 'foo'.\nAll controllers: %s\nDisabled-by-default controllers: %s", diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch.go index b08bafcb4ff9..494d9ffbbd70 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch.go @@ -1,5 +1,51 @@ package app -import "k8s.io/client-go/informers" +import ( + "k8s.io/client-go/informers" + "k8s.io/client-go/rest" + "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" +) var InformerFactoryOverride informers.SharedInformerFactory + +func ShimForOpenShift(controllerManager *options.CMServer, clientConfig *rest.Config) (func(), error) { + if len(controllerManager.OpenShiftConfig) == 0 { + return func() {}, nil + } + + // TODO this gets removed when no longer take flags and no longer build a recycler template + openshiftConfig, err := getOpenShiftConfig(controllerManager.OpenShiftConfig) + if err != nil { + return func() {}, err + } + // apply the config based controller manager flags. They will override. + // TODO this should be replaced by the installer setting up the flags for us + if err := applyOpenShiftConfigFlags(controllerManager, openshiftConfig); err != nil { + return func() {}, err + } + // set up a non-default template + // TODO this should be replaced by the installer setting up the recycle template file and flags for us + cleanupFn, err := applyOpenShiftDefaultRecycler(controllerManager, openshiftConfig) + if err != nil { + return func() {}, err + } + + // skip GC on some openshift resources + // TODO this should be replaced by discovery information in some way + if err := applyOpenShiftGCConfig(controllerManager); err != nil { + return func() {}, err + } + + // Overwrite the informers, because we have our custom generic informers for quota. + // TODO update quota to create its own informer like garbage collection + combinedInformers, err := NewInformers(clientConfig) + if err != nil { + return cleanupFn, err + } + InformerFactoryOverride = externalKubeInformersWithExtraGenerics{ + SharedInformerFactory: combinedInformers.GetExternalKubeInformers(), + genericResourceInformer: combinedInformers.ToGenericInformer(), + } + + return cleanupFn, nil +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_flags.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_flags.go new file mode 100644 index 000000000000..913146fb7df3 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_flags.go @@ -0,0 +1,88 @@ +package app + +import ( + "fmt" + "io/ioutil" + + "github.com/spf13/pflag" + + kerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/apimachinery/pkg/util/validation/field" + kyaml "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" +) + +func getOpenShiftConfig(configFile string) (map[string]interface{}, error) { + configBytes, err := ioutil.ReadFile(configFile) + if err != nil { + return nil, err + } + jsonBytes, err := kyaml.ToJSON(configBytes) + if err != nil { + return nil, err + } + config := map[string]interface{}{} + if err := json.Unmarshal(jsonBytes, &config); err != nil { + return nil, err + } + + return config, nil +} + +func applyOpenShiftConfigFlags(controllerManager *options.CMServer, openshiftConfig map[string]interface{}) error { + kubeMasterConfig, ok := openshiftConfig["kubernetesMasterConfig"] + if !ok { + return nil + } + + castKubeMasterConfig := kubeMasterConfig.(map[string]interface{}) + controllerArgs, ok := castKubeMasterConfig["controllerArguments"] + if !ok || controllerArgs == nil { + return nil + } + + args := map[string][]string{} + for key, value := range controllerArgs.(map[string]interface{}) { + for _, arrayValue := range value.([]interface{}) { + args[key] = append(args[key], arrayValue.(string)) + } + } + if err := resolveFlags(args, kubeControllerManagerAddFlags(controllerManager)); len(err) > 0 { + return kerrors.NewAggregate(err) + } + + return nil +} + +// applyFlags stores the provided arguments onto a flag set, reporting any errors +// encountered during the process. +func applyFlags(args map[string][]string, flags *pflag.FlagSet) []error { + var errs []error + for key, value := range args { + flag := flags.Lookup(key) + if flag == nil { + errs = append(errs, field.Invalid(field.NewPath("flag"), key, "is not a valid flag")) + continue + } + for _, s := range value { + if err := flag.Value.Set(s); err != nil { + errs = append(errs, field.Invalid(field.NewPath(key), s, fmt.Sprintf("could not be set: %v", err))) + break + } + } + } + return errs +} + +func resolveFlags(args map[string][]string, fn func(*pflag.FlagSet)) []error { + fs := pflag.NewFlagSet("extended", pflag.ContinueOnError) + fn(fs) + return applyFlags(args, fs) +} + +func kubeControllerManagerAddFlags(cmserver *options.CMServer) func(flags *pflag.FlagSet) { + return func(flags *pflag.FlagSet) { + cmserver.AddFlags(flags, KnownControllers(), ControllersDisabledByDefault.List()) + } +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_gc.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_gc.go new file mode 100644 index 000000000000..cf9d6965166b --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_gc.go @@ -0,0 +1,45 @@ +package app + +import ( + "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" + "k8s.io/kubernetes/pkg/apis/componentconfig" +) + +func applyOpenShiftGCConfig(controllerManager *options.CMServer) error { + // TODO make this configurable or discoverable. This is going to prevent us from running the stock GC controller + // IF YOU ADD ANYTHING TO THIS LIST, MAKE SURE THAT YOU UPDATE THEIR STRATEGIES TO PREVENT GC FINALIZERS + controllerManager.GCIgnoredResources = append(controllerManager.GCIgnoredResources, + // explicitly disabled from GC for now - not enough value to track them + componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "rolebindingrestrictions"}, + componentconfig.GroupResource{Group: "network.openshift.io", Resource: "clusternetworks"}, + componentconfig.GroupResource{Group: "network.openshift.io", Resource: "egressnetworkpolicies"}, + componentconfig.GroupResource{Group: "network.openshift.io", Resource: "hostsubnets"}, + componentconfig.GroupResource{Group: "network.openshift.io", Resource: "netnamespaces"}, + componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthclientauthorizations"}, + componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthclients"}, + componentconfig.GroupResource{Group: "quota.openshift.io", Resource: "clusterresourcequotas"}, + componentconfig.GroupResource{Group: "user.openshift.io", Resource: "groups"}, + componentconfig.GroupResource{Group: "user.openshift.io", Resource: "identities"}, + componentconfig.GroupResource{Group: "user.openshift.io", Resource: "users"}, + componentconfig.GroupResource{Group: "image.openshift.io", Resource: "images"}, + + // virtual resource + componentconfig.GroupResource{Group: "project.openshift.io", Resource: "projects"}, + // virtual and unwatchable resource, surfaced via rbac.authorization.k8s.io objects + componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "clusterroles"}, + componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "clusterrolebindings"}, + componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "roles"}, + componentconfig.GroupResource{Group: "authorization.openshift.io", Resource: "rolebindings"}, + // these resources contain security information in their names, and we don't need to track them + componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthaccesstokens"}, + componentconfig.GroupResource{Group: "oauth.openshift.io", Resource: "oauthauthorizetokens"}, + // exposed already as extensions v1beta1 by other controllers + componentconfig.GroupResource{Group: "apps", Resource: "deployments"}, + // exposed as autoscaling v1 + componentconfig.GroupResource{Group: "extensions", Resource: "horizontalpodautoscalers"}, + // exposed as security.openshift.io v1 + componentconfig.GroupResource{Group: "", Resource: "securitycontextconstraints"}, + ) + + return nil +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_imagetemplate.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_imagetemplate.go new file mode 100644 index 000000000000..7034372a1eda --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_imagetemplate.go @@ -0,0 +1,140 @@ +package app + +import ( + "fmt" + "os" + "strings" + + "k8s.io/kubernetes/pkg/version" + + "github.com/golang/glog" +) + +// ImageTemplate is a class to assist in expanding parameterized Docker image references +// from configuration or a file +type ImageTemplate struct { + // Format is required, set to the image template to pull + Format string + Latest bool + // EnvFormat is optional, if set will substitute the value of ${component} with any env + // var that matches this format. Is a printf format string accepting a single + // string parameter. + EnvFormat string +} + +var ( + // defaultImagePrefix is the default prefix for any container image names. + // This value should be set duing build via -ldflags. + DefaultImagePrefix string + + // defaultImageFormat is the default format for container image names used + // to run containerized components of the platform + defaultImageFormat = DefaultImagePrefix + "-${component}:${version}" +) + +const defaultImageEnvFormat = "OPENSHIFT_%s_IMAGE" + +// NewDefaultImageTemplate returns the default image template +func NewDefaultImageTemplate() ImageTemplate { + return ImageTemplate{ + Format: defaultImageFormat, + Latest: false, + EnvFormat: defaultImageEnvFormat, + } +} + +// ExpandOrDie will either expand a string or exit in case of failure +func (t *ImageTemplate) ExpandOrDie(component string) string { + value, err := t.Expand(component) + if err != nil { + glog.Fatalf("Unable to find an image for %q due to an error processing the format: %v", component, err) + } + return value +} + +// Expand expands a string using a series of common format functions +func (t *ImageTemplate) Expand(component string) (string, error) { + template := t.Format + if len(t.EnvFormat) > 0 { + if s, ok := t.imageComponentEnvExpander(component); ok { + template = s + } + } + value, err := ExpandStrict(template, func(key string) (string, bool) { + switch key { + case "component": + return component, true + case "version": + if t.Latest { + return "latest", true + } + } + return "", false + }, Versions) + return value, err +} + +func (t *ImageTemplate) imageComponentEnvExpander(key string) (string, bool) { + s := strings.Replace(strings.ToUpper(key), "-", "_", -1) + val := os.Getenv(fmt.Sprintf(t.EnvFormat, s)) + if len(val) == 0 { + return "", false + } + return val, true +} + +// ExpandStrict expands a string using a series of common format functions +func ExpandStrict(s string, fns ...KeyFunc) (string, error) { + unmatched := []string{} + result := os.Expand(s, func(key string) string { + for _, fn := range fns { + val, ok := fn(key) + if !ok { + continue + } + return val + } + unmatched = append(unmatched, key) + return "" + }) + + switch len(unmatched) { + case 0: + return result, nil + case 1: + return "", fmt.Errorf("the key %q in %q is not recognized", unmatched[0], s) + default: + return "", fmt.Errorf("multiple keys in %q were not recognized: %s", s, strings.Join(unmatched, ", ")) + } +} + +// KeyFunc returns the value associated with the provided key or false if no +// such key exists. +type KeyFunc func(key string) (string, bool) + +// Versions is a KeyFunc for retrieving information about the current version. +func Versions(key string) (string, bool) { + switch key { + case "shortcommit": + s := OverrideVersion.GitCommit + if len(s) > 7 { + s = s[:7] + } + return s, true + case "version": + s := lastSemanticVersion(OverrideVersion.GitVersion) + return s, true + default: + return "", false + } +} + +// OverrideVersion is the latest version, exposed for testing. +var OverrideVersion = version.Get() + +// lastSemanticVersion attempts to return a semantic version from the GitVersion - which +// is either + or on release boundaries. +func lastSemanticVersion(gitVersion string) string { + parts := strings.Split(gitVersion, "+") + return parts[0] +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_informers.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_informers.go new file mode 100644 index 000000000000..c424f5721cec --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_informers.go @@ -0,0 +1,281 @@ +package app + +import ( + "time" + + "github.com/golang/glog" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + + appclient "github.com/openshift/client-go/apps/clientset/versioned" + appinformer "github.com/openshift/client-go/apps/informers/externalversions" + authorizationclient "github.com/openshift/client-go/authorization/clientset/versioned" + authorizationinformer "github.com/openshift/client-go/authorization/informers/externalversions" + buildclient "github.com/openshift/client-go/build/clientset/versioned" + buildinformer "github.com/openshift/client-go/build/informers/externalversions" + imageclient "github.com/openshift/client-go/image/clientset/versioned" + imageinformer "github.com/openshift/client-go/image/informers/externalversions" + networkclient "github.com/openshift/client-go/network/clientset/versioned" + networkinformer "github.com/openshift/client-go/network/informers/externalversions" + oauthclient "github.com/openshift/client-go/oauth/clientset/versioned" + oauthinformer "github.com/openshift/client-go/oauth/informers/externalversions" + quotaclient "github.com/openshift/client-go/quota/clientset/versioned" + quotainformer "github.com/openshift/client-go/quota/informers/externalversions" + routeclient "github.com/openshift/client-go/route/clientset/versioned" + routeinformer "github.com/openshift/client-go/route/informers/externalversions" + securityclient "github.com/openshift/client-go/security/clientset/versioned" + securityinformer "github.com/openshift/client-go/security/informers/externalversions" + templateclient "github.com/openshift/client-go/template/clientset/versioned" + templateinformer "github.com/openshift/client-go/template/informers/externalversions" + userclient "github.com/openshift/client-go/user/clientset/versioned" + userinformer "github.com/openshift/client-go/user/informers/externalversions" +) + +type externalKubeInformersWithExtraGenerics struct { + informers.SharedInformerFactory + genericResourceInformer GenericResourceInformer +} + +func (i externalKubeInformersWithExtraGenerics) ForResource(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.genericResourceInformer.ForResource(resource) +} + +func (i externalKubeInformersWithExtraGenerics) Start(stopCh <-chan struct{}) { + i.SharedInformerFactory.Start(stopCh) + i.genericResourceInformer.Start(stopCh) +} + +type GenericResourceInformer interface { + ForResource(resource schema.GroupVersionResource) (informers.GenericInformer, error) + Start(stopCh <-chan struct{}) +} + +// genericResourceInformerFunc will handle a cast to a matching type +type genericResourceInformerFunc func(resource schema.GroupVersionResource) (informers.GenericInformer, error) + +func (fn genericResourceInformerFunc) ForResource(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return fn(resource) +} + +// this is a temporary condition until we rewrite enough of generation to auto-conform to the required interface and no longer need the internal version shim +func (fn genericResourceInformerFunc) Start(stopCh <-chan struct{}) {} + +type genericInformers struct { + // this is a temporary condition until we rewrite enough of generation to auto-conform to the required interface and no longer need the internal version shim + startFn func(stopCh <-chan struct{}) + generic []GenericResourceInformer +} + +func newGenericInformers(startFn func(stopCh <-chan struct{}), informers ...GenericResourceInformer) genericInformers { + return genericInformers{ + startFn: startFn, + generic: informers, + } +} + +func (i genericInformers) ForResource(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + var firstErr error + for _, generic := range i.generic { + informer, err := generic.ForResource(resource) + if err == nil { + return informer, nil + } + if firstErr == nil { + firstErr = err + } + } + glog.V(4).Infof("Couldn't find informer for %v", resource) + return nil, firstErr +} + +func (i genericInformers) Start(stopCh <-chan struct{}) { + i.startFn(stopCh) + for _, generic := range i.generic { + generic.Start(stopCh) + } +} + +// informers is a convenient way for us to keep track of the informers, but +// is intentionally private. We don't want to leak it out further than this package. +// Everything else should say what it wants. +type combinedInformers struct { + externalKubeInformers informers.SharedInformerFactory + appInformers appinformer.SharedInformerFactory + authorizationInformers authorizationinformer.SharedInformerFactory + buildInformers buildinformer.SharedInformerFactory + imageInformers imageinformer.SharedInformerFactory + networkInformers networkinformer.SharedInformerFactory + oauthInformers oauthinformer.SharedInformerFactory + quotaInformers quotainformer.SharedInformerFactory + routeInformers routeinformer.SharedInformerFactory + securityInformers securityinformer.SharedInformerFactory + templateInformers templateinformer.SharedInformerFactory + userInformers userinformer.SharedInformerFactory +} + +// NewInformers is only exposed for the build's integration testing until it can be fixed more appropriately. +func NewInformers(clientConfig *rest.Config) (*combinedInformers, error) { + kubeClient, err := kubernetes.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + appClient, err := appclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + authorizationClient, err := authorizationclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + buildClient, err := buildclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + imageClient, err := imageclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + networkClient, err := networkclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + oauthClient, err := oauthclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + quotaClient, err := quotaclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + routerClient, err := routeclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + securityClient, err := securityclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + templateClient, err := templateclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + userClient, err := userclient.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + + // TODO find a single place to create and start informers. During the 1.7 rebase this will come more naturally in a config object, + // before then we should try to eliminate our direct to storage access. It's making us do weird things. + const defaultInformerResyncPeriod = 10 * time.Minute + + return &combinedInformers{ + externalKubeInformers: informers.NewSharedInformerFactory(kubeClient, defaultInformerResyncPeriod), + appInformers: appinformer.NewSharedInformerFactory(appClient, defaultInformerResyncPeriod), + authorizationInformers: authorizationinformer.NewSharedInformerFactory(authorizationClient, defaultInformerResyncPeriod), + buildInformers: buildinformer.NewSharedInformerFactory(buildClient, defaultInformerResyncPeriod), + imageInformers: imageinformer.NewSharedInformerFactory(imageClient, defaultInformerResyncPeriod), + networkInformers: networkinformer.NewSharedInformerFactory(networkClient, defaultInformerResyncPeriod), + oauthInformers: oauthinformer.NewSharedInformerFactory(oauthClient, defaultInformerResyncPeriod), + quotaInformers: quotainformer.NewSharedInformerFactory(quotaClient, defaultInformerResyncPeriod), + routeInformers: routeinformer.NewSharedInformerFactory(routerClient, defaultInformerResyncPeriod), + securityInformers: securityinformer.NewSharedInformerFactory(securityClient, defaultInformerResyncPeriod), + templateInformers: templateinformer.NewSharedInformerFactory(templateClient, defaultInformerResyncPeriod), + userInformers: userinformer.NewSharedInformerFactory(userClient, defaultInformerResyncPeriod), + }, nil +} + +func (i *combinedInformers) GetExternalKubeInformers() informers.SharedInformerFactory { + return i.externalKubeInformers +} +func (i *combinedInformers) GetAppInformers() appinformer.SharedInformerFactory { + return i.appInformers +} +func (i *combinedInformers) GetAuthorizationInformers() authorizationinformer.SharedInformerFactory { + return i.authorizationInformers +} +func (i *combinedInformers) GetBuildInformers() buildinformer.SharedInformerFactory { + return i.buildInformers +} +func (i *combinedInformers) GetImageInformers() imageinformer.SharedInformerFactory { + return i.imageInformers +} +func (i *combinedInformers) GetNetworkInformers() networkinformer.SharedInformerFactory { + return i.networkInformers +} +func (i *combinedInformers) GetOauthInformers() oauthinformer.SharedInformerFactory { + return i.oauthInformers +} +func (i *combinedInformers) GetQuotaInformers() quotainformer.SharedInformerFactory { + return i.quotaInformers +} +func (i *combinedInformers) GetRouteInformers() routeinformer.SharedInformerFactory { + return i.routeInformers +} +func (i *combinedInformers) GetSecurityInformers() securityinformer.SharedInformerFactory { + return i.securityInformers +} +func (i *combinedInformers) GetTemplateInformers() templateinformer.SharedInformerFactory { + return i.templateInformers +} +func (i *combinedInformers) GetUserInformers() userinformer.SharedInformerFactory { + return i.userInformers +} + +// Start initializes all requested informers. +func (i *combinedInformers) Start(stopCh <-chan struct{}) { + i.externalKubeInformers.Start(stopCh) + i.appInformers.Start(stopCh) + i.authorizationInformers.Start(stopCh) + i.buildInformers.Start(stopCh) + i.imageInformers.Start(stopCh) + i.networkInformers.Start(stopCh) + i.oauthInformers.Start(stopCh) + i.quotaInformers.Start(stopCh) + i.routeInformers.Start(stopCh) + i.securityInformers.Start(stopCh) + i.templateInformers.Start(stopCh) + i.userInformers.Start(stopCh) +} + +func (i *combinedInformers) ToGenericInformer() GenericResourceInformer { + return newGenericInformers( + i.Start, + i.GetExternalKubeInformers(), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetAppInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetAuthorizationInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetBuildInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetImageInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetNetworkInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetOauthInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetQuotaInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetRouteInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetSecurityInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetTemplateInformers().ForResource(resource) + }), + genericResourceInformerFunc(func(resource schema.GroupVersionResource) (informers.GenericInformer, error) { + return i.GetUserInformers().ForResource(resource) + }), + ) +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_recycler.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_recycler.go new file mode 100644 index 000000000000..d001a53d47eb --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/patch_recycler.go @@ -0,0 +1,108 @@ +package app + +import ( + "io/ioutil" + "os" + + "github.com/golang/glog" + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" + "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/volume" +) + +func applyOpenShiftDefaultRecycler(controllerManager *options.CMServer, openshiftConfig map[string]interface{}) (func(), error) { + hostPathTemplateSet := len(controllerManager.VolumeConfiguration.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathHostPath) != 0 + nfsTemplateSet := len(controllerManager.VolumeConfiguration.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathNFS) != 0 + + // if both are set, nothing to do + if hostPathTemplateSet && nfsTemplateSet { + return func() {}, nil + } + + // OpenShift uses a different default volume recycler template than + // Kubernetes. This default template is hardcoded in Kubernetes and it + // isn't possible to pass it via ControllerContext. Crate a temporary + // file with OpenShift's template and let's pretend it was set by user + // as --recycler-pod-template-filepath-hostpath and + // --pv-recycler-pod-template-filepath-nfs arguments. + // This template then needs to be deleted by caller! + recyclerImage, err := getRecyclerImage(openshiftConfig) + if err != nil { + return func() {}, err + } + + // no image to use + if len(recyclerImage) == 0 { + return func() {}, nil + } + + templateFilename, err := createRecylerTemplate(recyclerImage) + if err != nil { + return func() {}, err + } + cleanupFunction := func() { + // Remove the template when it's not needed. This is called aftet + // controller is initialized + glog.V(4).Infof("Removing temporary file %s", templateFilename) + err := os.Remove(templateFilename) + if err != nil { + glog.Warningf("Failed to remove %s: %v", templateFilename, err) + } + } + + if !hostPathTemplateSet { + controllerManager.VolumeConfiguration.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathHostPath = templateFilename + } + if !nfsTemplateSet { + controllerManager.VolumeConfiguration.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathNFS = templateFilename + } + + return cleanupFunction, nil +} + +func createRecylerTemplate(recyclerImage string) (string, error) { + uid := int64(0) + template := volume.NewPersistentVolumeRecyclerPodTemplate() + template.Namespace = "openshift-infra" + template.Spec.ServiceAccountName = "pv-recycler-controller" + template.Spec.Containers[0].Image = recyclerImage + template.Spec.Containers[0].Command = []string{"/usr/bin/openshift-recycle"} + template.Spec.Containers[0].Args = []string{"/scrub"} + template.Spec.Containers[0].SecurityContext = &v1.SecurityContext{RunAsUser: &uid} + template.Spec.Containers[0].ImagePullPolicy = v1.PullIfNotPresent + + templateBytes, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), template) + if err != nil { + return "", err + } + + f, err := ioutil.TempFile("", "openshift-recycler-template-") + if err != nil { + return "", err + } + filename := f.Name() + glog.V(4).Infof("Creating file %s with recycler templates", filename) + + _, err = f.Write(templateBytes) + if err != nil { + f.Close() + os.Remove(filename) + return "", err + } + f.Close() + return filename, nil +} + +func getRecyclerImage(config map[string]interface{}) (string, error) { + imageConfig, ok := config["imageConfig"] + if !ok { + return "", nil + } + configMap := imageConfig.(map[string]interface{}) + imageTemplate := NewDefaultImageTemplate() + imageTemplate.Format = configMap["format"].(string) + imageTemplate.Latest = configMap["latest"].(bool) + return imageTemplate.Expand("recycler") +} diff --git a/vendor/k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/server.go b/vendor/k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/server.go index 8ef2cc81c170..7b3ae4b14fc0 100644 --- a/vendor/k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/server.go +++ b/vendor/k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/server.go @@ -68,6 +68,7 @@ import ( "k8s.io/kubernetes/plugin/pkg/scheduler/factory" "github.com/golang/glog" + "github.com/pborman/uuid" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -441,13 +442,15 @@ func makeLeaderElectionConfig(config componentconfig.KubeSchedulerLeaderElection if err != nil { return nil, fmt.Errorf("unable to get hostname: %v", err) } + // add a uniquifier so that two processes on the same host don't accidentally both become active + id := hostname + " " + string(uuid.NewUUID()) rl, err := resourcelock.New(config.ResourceLock, config.LockObjectNamespace, config.LockObjectName, client.CoreV1(), resourcelock.ResourceLockConfig{ - Identity: hostname, + Identity: id, EventRecorder: recorder, }) if err != nil {