// testDeploymentCleanUpPolicy tests that deployment supports cleanup policy func testDeploymentCleanUpPolicy(f *Framework) { ns := f.Namespace.Name unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. deploymentPodLabels := map[string]string{"name": "cleanup-pod"} rsPodLabels := map[string]string{ "name": "cleanup-pod", "pod": "nginx", } rsName := "nginx-controller" replicas := 1 revisionHistoryLimit := util.IntPtr(0) _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, replicas, rsPodLabels, "nginx", "nginx")) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "cleanup-pod", false, 1) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a deployment to delete nginx pods and instead bring up redis pods. deploymentName := "redis-deployment" Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, deploymentPodLabels, "redis", "redis", extensions.RollingUpdateDeploymentStrategyType, revisionHistoryLimit)) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) err = waitForDeploymentOldRSsNum(c, ns, deploymentName, *revisionHistoryLimit) Expect(err).NotTo(HaveOccurred()) }
func testRollingUpdateDeploymentEvents(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. deploymentPodLabels := map[string]string{"name": "sample-pod-2"} rsPodLabels := map[string]string{ "name": "sample-pod-2", "pod": "nginx", } rsName := "nginx-controller" replicas := 1 rsRevision := "3546343826724305832" annotations := make(map[string]string) annotations[deploymentutil.RevisionAnnotation] = rsRevision rs := newRS(rsName, replicas, rsPodLabels, "nginx", "nginx") rs.Annotations = annotations _, err := c.Extensions().ReplicaSets(ns).Create(rs) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "sample-pod-2", false, 1) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a deployment to delete nginx pods and instead bring up redis pods. deploymentName := "redis-deployment-2" Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, deploymentPodLabels, "redis", "redis", extensions.RollingUpdateDeploymentStrategyType, nil)) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) err = waitForDeploymentStatus(c, ns, deploymentName, replicas, replicas-1, replicas+1, 0) Expect(err).NotTo(HaveOccurred()) // Verify that the pods were scaled up and down as expected. We use events to verify that. deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) waitForEvents(unversionedClient, ns, deployment, 2) events, err := c.Core().Events(ns).Search(deployment) if err != nil { Logf("error in listing events: %s", err) Expect(err).NotTo(HaveOccurred()) } // There should be 2 events, one to scale up the new ReplicaSet and then to scale down // the old ReplicaSet. Expect(len(events.Items)).Should(Equal(2)) newRS, err := deploymentutil.GetNewReplicaSet(deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(newRS).NotTo(Equal(nil)) Expect(events.Items[0].Message).Should(Equal(fmt.Sprintf("Scaled up replica set %s to 1", newRS.Name))) Expect(events.Items[1].Message).Should(Equal(fmt.Sprintf("Scaled down replica set %s to 0", rsName))) // Check if it's updated to revision 3546343826724305833 correctly checkDeploymentRevision(c, ns, deploymentName, "3546343826724305833", "redis", "redis") }
func testNewDeployment(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. c := clientset.FromUnversionedClient(f.Client) deploymentName := "test-new-deployment" podLabels := map[string]string{"name": nginxImageName} replicas := 1 Logf("Creating simple deployment %s", deploymentName) d := newDeployment(deploymentName, replicas, podLabels, nginxImageName, nginxImage, extensions.RollingUpdateDeploymentStrategyType, nil) d.Annotations = map[string]string{"test": "should-copy-to-replica-set", kubectl.LastAppliedConfigAnnotation: "should-not-copy-to-replica-set"} _, err := c.Extensions().Deployments(ns).Create(d) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Wait for it to be updated to revision 1 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", nginxImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, replicas, replicas-1, replicas+1, 0) Expect(err).NotTo(HaveOccurred()) deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) newRS, err := deploymentutil.GetNewReplicaSet(deployment, c) Expect(err).NotTo(HaveOccurred()) // Check new RS annotations Expect(newRS.Annotations["test"]).Should(Equal("should-copy-to-replica-set")) Expect(newRS.Annotations[kubectl.LastAppliedConfigAnnotation]).Should(Equal("")) Expect(deployment.Annotations["test"]).Should(Equal("should-copy-to-replica-set")) Expect(deployment.Annotations[kubectl.LastAppliedConfigAnnotation]).Should(Equal("should-not-copy-to-replica-set")) }
// RunServiceAccountTokensController starts the service account token controller func (c *MasterConfig) RunServiceAccountTokensController() { if len(c.Options.ServiceAccountConfig.PrivateKeyFile) == 0 { glog.Infof("Skipped starting Service Account Token Manager, no private key specified") return } privateKey, err := serviceaccount.ReadPrivateKey(c.Options.ServiceAccountConfig.PrivateKeyFile) if err != nil { glog.Fatalf("Error reading signing key for Service Account Token Manager: %v", err) } rootCA := []byte{} if len(c.Options.ServiceAccountConfig.MasterCA) > 0 { rootCA, err = ioutil.ReadFile(c.Options.ServiceAccountConfig.MasterCA) if err != nil { glog.Fatalf("Error reading master ca file for Service Account Token Manager: %s: %v", c.Options.ServiceAccountConfig.MasterCA, err) } if _, err := util.CertsFromPEM(rootCA); err != nil { glog.Fatalf("Error parsing master ca file for Service Account Token Manager: %s: %v", c.Options.ServiceAccountConfig.MasterCA, err) } } options := sacontroller.TokensControllerOptions{ TokenGenerator: serviceaccount.JWTTokenGenerator(privateKey), RootCA: rootCA, } sacontroller.NewTokensController(internalclientset.FromUnversionedClient(c.KubeClient()), options).Run() }
func (c *MasterConfig) RunPersistentVolumeProvisioner(client *client.Client) { provisioner, err := kctrlmgr.NewVolumeProvisioner(c.CloudProvider, c.ControllerManager.VolumeConfiguration) if err != nil { // a provisioner was expected but encountered an error glog.Fatal(err) } // not all cloud providers have a provisioner. if provisioner != nil { allPlugins := []volume.VolumePlugin{} allPlugins = append(allPlugins, aws_ebs.ProbeVolumePlugins()...) allPlugins = append(allPlugins, gce_pd.ProbeVolumePlugins()...) allPlugins = append(allPlugins, cinder.ProbeVolumePlugins()...) controllerClient := volumeclaimbinder.NewControllerClient(internalclientset.FromUnversionedClient(client)) provisionerController, err := volumeclaimbinder.NewPersistentVolumeProvisionerController( controllerClient, c.ControllerManager.PVClaimBinderSyncPeriod.Duration, c.ControllerManager.ClusterName, allPlugins, provisioner, c.CloudProvider, ) if err != nil { glog.Fatalf("Could not start Persistent Volume Provisioner: %+v", err) } provisionerController.Run() } }
func testDeploymentLabelAdopted(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. podName := "nginx" podLabels := map[string]string{"name": podName} rsName := "test-adopted-controller" replicas := 3 _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, replicas, podLabels, podName, podName)) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, podName, false, 3) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a nginx deployment to adopt the old rs. deploymentName := "test-adopted-deployment" Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, podLabels, podName, podName, extensions.RollingUpdateDeploymentStrategyType, nil)) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Wait for it to be updated to revision 1 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", "nginx") Expect(err).NotTo(HaveOccurred()) // The RS and pods should be relabeled before the status is updated by syncRollingUpdateDeployment err = waitForDeploymentStatus(c, ns, deploymentName, replicas, replicas-1, replicas+1, 0) Expect(err).NotTo(HaveOccurred()) // There should be no old RSs (overlapping RS) deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) oldRSs, allOldRSs, err := deploymentutil.GetOldReplicaSets(deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(len(oldRSs)).Should(Equal(0)) Expect(len(allOldRSs)).Should(Equal(0)) // New RS should contain pod-template-hash in its selector, label, and template label newRS, err := deploymentutil.GetNewReplicaSet(deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(len(newRS.Labels[extensions.DefaultDeploymentUniqueLabelKey])).Should(BeNumerically(">", 0)) Expect(len(newRS.Spec.Selector.MatchLabels[extensions.DefaultDeploymentUniqueLabelKey])).Should(BeNumerically(">", 0)) Expect(len(newRS.Spec.Template.Labels[extensions.DefaultDeploymentUniqueLabelKey])).Should(BeNumerically(">", 0)) // All pods targeted by the deployment should contain pod-template-hash in their labels, and there should be only 3 pods selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) Expect(err).NotTo(HaveOccurred()) options := api.ListOptions{LabelSelector: selector} pods, err := c.Core().Pods(ns).List(options) Expect(err).NotTo(HaveOccurred()) for _, pod := range pods.Items { Expect(len(pod.Labels[extensions.DefaultDeploymentUniqueLabelKey])).Should(BeNumerically(">", 0)) } Expect(len(pods.Items)).Should(Equal(replicas)) }
func (c *MasterConfig) RunDaemonSetsController(client *client.Client) { controller := daemon.NewDaemonSetsController( internalclientset.FromUnversionedClient(client), kctrlmgr.ResyncPeriod(c.ControllerManager), c.ControllerManager.LookupCacheSizeForDaemonSet, ) go controller.Run(c.ControllerManager.ConcurrentDaemonSetSyncs, utilwait.NeverStop) }
// RunReplicationController starts the Kubernetes replication controller sync loop func (c *MasterConfig) RunReplicationController(client *client.Client) { controllerManager := replicationcontroller.NewReplicationManager( internalclientset.FromUnversionedClient(client), kctrlmgr.ResyncPeriod(c.ControllerManager), replicationcontroller.BurstReplicas, c.ControllerManager.LookupCacheSizeForRC, ) go controllerManager.Run(c.ControllerManager.ConcurrentRCSyncs, utilwait.NeverStop) }
func (c *MasterConfig) RunPersistentVolumeClaimRecycler(recyclerImageName string, client *client.Client, namespace string) { uid := int64(0) defaultScrubPod := volume.NewPersistentVolumeRecyclerPodTemplate() defaultScrubPod.Namespace = namespace defaultScrubPod.Spec.Containers[0].Image = recyclerImageName defaultScrubPod.Spec.Containers[0].Command = []string{"/usr/bin/recycle"} defaultScrubPod.Spec.Containers[0].Args = []string{"/scrub"} defaultScrubPod.Spec.Containers[0].SecurityContext = &kapi.SecurityContext{RunAsUser: &uid} defaultScrubPod.Spec.Containers[0].ImagePullPolicy = kapi.PullIfNotPresent volumeConfig := c.ControllerManager.VolumeConfiguration hostPathConfig := volume.VolumeConfig{ RecyclerMinimumTimeout: volumeConfig.PersistentVolumeRecyclerConfiguration.MinimumTimeoutHostPath, RecyclerTimeoutIncrement: volumeConfig.PersistentVolumeRecyclerConfiguration.IncrementTimeoutHostPath, RecyclerPodTemplate: defaultScrubPod, } if len(volumeConfig.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathHostPath) != 0 { if err := attemptToLoadRecycler(volumeConfig.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathHostPath, &hostPathConfig); err != nil { glog.Fatalf("Could not create hostpath recycler pod from file %s: %+v", volumeConfig.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathHostPath, err) } } nfsConfig := volume.VolumeConfig{ RecyclerMinimumTimeout: volumeConfig.PersistentVolumeRecyclerConfiguration.MinimumTimeoutNFS, RecyclerTimeoutIncrement: volumeConfig.PersistentVolumeRecyclerConfiguration.IncrementTimeoutNFS, RecyclerPodTemplate: defaultScrubPod, } if len(volumeConfig.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathNFS) != 0 { if err := attemptToLoadRecycler(volumeConfig.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathNFS, &nfsConfig); err != nil { glog.Fatalf("Could not create NFS recycler pod from file %s: %+v", volumeConfig.PersistentVolumeRecyclerConfiguration.PodTemplateFilePathNFS, err) } } allPlugins := []volume.VolumePlugin{} allPlugins = append(allPlugins, host_path.ProbeVolumePlugins(hostPathConfig)...) allPlugins = append(allPlugins, nfs.ProbeVolumePlugins(nfsConfig)...) // dynamic provisioning allows deletion of volumes as a recycling operation after a claim is deleted allPlugins = append(allPlugins, aws_ebs.ProbeVolumePlugins()...) allPlugins = append(allPlugins, gce_pd.ProbeVolumePlugins()...) allPlugins = append(allPlugins, cinder.ProbeVolumePlugins()...) recycler, err := volumeclaimbinder.NewPersistentVolumeRecycler( internalclientset.FromUnversionedClient(client), c.ControllerManager.PVClaimBinderSyncPeriod.Duration, volumeConfig.PersistentVolumeRecyclerConfiguration.MaximumRetry, allPlugins, c.CloudProvider, ) if err != nil { glog.Fatalf("Could not start Persistent Volume Recycler: %+v", err) } recycler.Run() }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) config := HollowNodeConfig{} config.addFlags(pflag.CommandLine) util.InitFlags() if !knownMorphs.Has(config.Morph) { glog.Fatalf("Unknown morph: %v. Allowed values: %v", config.Morph, knownMorphs.List()) } // create a client to communicate with API server. cl, err := createClientFromFile(config.KubeconfigPath) clientset := clientset.FromUnversionedClient(cl) if err != nil { glog.Fatal("Failed to create a Client. Exiting.") } if config.Morph == "kubelet" { cadvisorInterface := new(cadvisortest.Fake) containerManager := cm.NewStubContainerManager() fakeDockerClient := dockertools.NewFakeDockerClient() fakeDockerClient.VersionInfo = docker.Env{"Version=1.1.3", "ApiVersion=1.18"} fakeDockerClient.EnableSleep = true hollowKubelet := kubemark.NewHollowKubelet( config.NodeName, clientset, cadvisorInterface, fakeDockerClient, config.KubeletPort, config.KubeletReadOnlyPort, containerManager, maxPods, ) hollowKubelet.Run() } if config.Morph == "proxy" { eventBroadcaster := record.NewBroadcaster() recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "kube-proxy", Host: config.NodeName}) iptInterface := fakeiptables.NewFake() serviceConfig := proxyconfig.NewServiceConfig() serviceConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) endpointsConfig := proxyconfig.NewEndpointsConfig() endpointsConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) hollowProxy := kubemark.NewHollowProxyOrDie(config.NodeName, cl, endpointsConfig, serviceConfig, iptInterface, eventBroadcaster, recorder) hollowProxy.Run() } }
func testRecreateDeployment(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. deploymentPodLabels := map[string]string{"name": "sample-pod-3"} rsPodLabels := map[string]string{ "name": "sample-pod-3", "pod": nginxImageName, } rsName := "test-recreate-controller" replicas := 3 _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, replicas, rsPodLabels, nginxImageName, nginxImage)) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "sample-pod-3", false, 3) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a deployment to delete nginx pods and instead bring up redis pods. deploymentName := "test-recreate-deployment" Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, deploymentPodLabels, redisImageName, redisImage, extensions.RecreateDeploymentStrategyType, nil)) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Wait for it to be updated to revision 1 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", redisImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, replicas, 0, replicas, 0) Expect(err).NotTo(HaveOccurred()) // Verify that the pods were scaled up and down as expected. We use events to verify that. deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) waitForEvents(unversionedClient, ns, deployment, 2) events, err := c.Core().Events(ns).Search(deployment) if err != nil { Logf("error in listing events: %s", err) Expect(err).NotTo(HaveOccurred()) } // There should be 2 events, one to scale up the new ReplicaSet and then to scale down the old ReplicaSet. Expect(len(events.Items)).Should(Equal(2)) newRS, err := deploymentutil.GetNewReplicaSet(deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(newRS).NotTo(Equal(nil)) Expect(events.Items[0].Message).Should(Equal(fmt.Sprintf("Scaled down replica set %s to 0", rsName))) Expect(events.Items[1].Message).Should(Equal(fmt.Sprintf("Scaled up replica set %s to 3", newRS.Name))) }
// RunHPAController starts the Kubernetes hpa controller sync loop func (c *MasterConfig) RunHPAController(oc *osclient.Client, kc *client.Client, heapsterNamespace string) { clientsetClient := internalclientset.FromUnversionedClient(kc) delegatingScaleNamespacer := osclient.NewDelegatingScaleNamespacer(oc, kc) podautoscaler := podautoscalercontroller.NewHorizontalController( coreunversioned.EventsGetter(clientsetClient), extensionsunversioned.ScalesGetter(delegatingScaleNamespacer), extensionsunversioned.HorizontalPodAutoscalersGetter(clientsetClient), metrics.NewHeapsterMetricsClient(clientsetClient, heapsterNamespace, "https", "heapster", ""), c.ControllerManager.HorizontalPodAutoscalerSyncPeriod.Duration, ) go podautoscaler.Run(utilwait.NeverStop) }
// RunNamespaceController starts the Kubernetes Namespace Manager func (c *MasterConfig) RunNamespaceController() { versions := []string{} for _, version := range configapi.GetEnabledAPIVersionsForGroup(c.Options, configapi.APIGroupKube) { versions = append(versions, unversioned.GroupVersion{Group: configapi.APIGroupKube, Version: version}.String()) } for _, version := range configapi.GetEnabledAPIVersionsForGroup(c.Options, configapi.APIGroupExtensions) { versions = append(versions, unversioned.GroupVersion{Group: configapi.APIGroupExtensions, Version: version}.String()) } apiVersions := &unversioned.APIVersions{Versions: versions} namespaceController := namespacecontroller.NewNamespaceController(internalclientset.FromUnversionedClient(c.KubeClient), apiVersions, c.ControllerManager.NamespaceSyncPeriod) go namespaceController.Run(c.ControllerManager.ConcurrentNamespaceSyncs, utilwait.NeverStop) }
func testRollingUpdateDeployment(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. deploymentPodLabels := map[string]string{"name": "sample-pod"} rcPodLabels := map[string]string{ "name": "sample-pod", "pod": "nginx", } rcName := "nginx-controller" replicas := 3 _, err := c.Core().ReplicationControllers(ns).Create(newRC(rcName, replicas, rcPodLabels, "nginx", "nginx")) Expect(err).NotTo(HaveOccurred()) defer func() { Logf("deleting replication controller %s", rcName) Expect(c.Core().ReplicationControllers(ns).Delete(rcName, nil)).NotTo(HaveOccurred()) }() // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "sample-pod", false, 3) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a deployment to delete nginx pods and instead bring up redis pods. deploymentName := "redis-deployment" Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, deploymentPodLabels, "redis", "redis", extensions.RollingUpdateDeploymentStrategyType, nil)) Expect(err).NotTo(HaveOccurred()) defer func() { deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) Logf("deleting deployment %s", deploymentName) Expect(c.Extensions().Deployments(ns).Delete(deploymentName, nil)).NotTo(HaveOccurred()) // TODO: remove this once we can delete rcs with deployment newRC, err := deploymentutil.GetNewRC(*deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(c.Core().ReplicationControllers(ns).Delete(newRC.Name, nil)).NotTo(HaveOccurred()) }() err = waitForDeploymentStatus(c, ns, deploymentName, replicas, replicas-1, replicas+1, 0) Expect(err).NotTo(HaveOccurred()) // Check if it's updated to revision 1 correctly checkDeploymentRevision(c, ns, deploymentName, "1", "redis", "redis") }
func testNewDeployment(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(f.Client) deploymentName := "nginx-deployment" podLabels := map[string]string{"name": "nginx"} replicas := 1 Logf("Creating simple deployment %s", deploymentName) d := newDeployment(deploymentName, replicas, podLabels, "nginx", "nginx", extensions.RollingUpdateDeploymentStrategyType, nil) d.Annotations = map[string]string{"test": "should-copy-to-RC", kubectl.LastAppliedConfigAnnotation: "should-not-copy-to-RC"} _, err := c.Extensions().Deployments(ns).Create(d) Expect(err).NotTo(HaveOccurred()) defer func() { deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) Logf("deleting deployment %s", deploymentName) Expect(c.Extensions().Deployments(ns).Delete(deploymentName, nil)).NotTo(HaveOccurred()) // TODO: remove this once we can delete rcs with deployment newRC, err := deploymentutil.GetNewRC(*deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(c.Core().ReplicationControllers(ns).Delete(newRC.Name, nil)).NotTo(HaveOccurred()) }() // Check that deployment is created fine. deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "nginx", false, replicas) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // DeploymentStatus should be appropriately updated. deployment, err = c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) Expect(deployment.Status.Replicas).Should(Equal(replicas)) Expect(deployment.Status.UpdatedReplicas).Should(Equal(replicas)) // Check if it's updated to revision 1 correctly _, newRC := checkDeploymentRevision(c, ns, deploymentName, "1", "nginx", "nginx") // Check other annotations Expect(newRC.Annotations["test"]).Should(Equal("should-copy-to-RC")) Expect(newRC.Annotations[kubectl.LastAppliedConfigAnnotation]).Should(Equal("")) Expect(deployment.Annotations["test"]).Should(Equal("should-copy-to-RC")) Expect(deployment.Annotations[kubectl.LastAppliedConfigAnnotation]).Should(Equal("should-not-copy-to-RC")) }
func testRollingUpdateDeployment(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. deploymentPodLabels := map[string]string{"name": "sample-pod"} rsPodLabels := map[string]string{ "name": "sample-pod", "pod": nginxImageName, } rsName := "test-rolling-update-controller" replicas := 3 _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, replicas, rsPodLabels, nginxImageName, nginxImage)) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "sample-pod", false, 3) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a deployment to delete nginx pods and instead bring up redis pods. deploymentName := "test-rolling-update-deployment" Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, deploymentPodLabels, redisImageName, redisImage, extensions.RollingUpdateDeploymentStrategyType, nil)) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Wait for it to be updated to revision 1 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", redisImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, replicas, replicas-1, replicas+1, 0) Expect(err).NotTo(HaveOccurred()) // There should be 1 old RS (nginx-controller, which is adopted) deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) _, allOldRSs, err := deploymentutil.GetOldReplicaSets(deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(len(allOldRSs)).Should(Equal(1)) // The old RS should contain pod-template-hash in its selector, label, and template label Expect(len(allOldRSs[0].Labels[extensions.DefaultDeploymentUniqueLabelKey])).Should(BeNumerically(">", 0)) Expect(len(allOldRSs[0].Spec.Selector.MatchLabels[extensions.DefaultDeploymentUniqueLabelKey])).Should(BeNumerically(">", 0)) Expect(len(allOldRSs[0].Spec.Template.Labels[extensions.DefaultDeploymentUniqueLabelKey])).Should(BeNumerically(">", 0)) }
// RunServiceAccountsController starts the service account controller func (c *MasterConfig) RunServiceAccountsController() { if len(c.Options.ServiceAccountConfig.ManagedNames) == 0 { glog.Infof("Skipped starting Service Account Manager, no managed names specified") return } options := sacontroller.DefaultServiceAccountsControllerOptions() options.ServiceAccounts = []kapi.ServiceAccount{} for _, saName := range c.Options.ServiceAccountConfig.ManagedNames { sa := kapi.ServiceAccount{} sa.Name = saName options.ServiceAccounts = append(options.ServiceAccounts, sa) } sacontroller.NewServiceAccountsController(internalclientset.FromUnversionedClient(c.KubeClient()), options).Run() }
func newServiceAccountTokenGetter(options configapi.MasterConfig, client newetcdclient.Client) (serviceaccount.ServiceAccountTokenGetter, error) { var tokenGetter serviceaccount.ServiceAccountTokenGetter if options.KubernetesMasterConfig == nil { // When we're running against an external Kubernetes, use the external kubernetes client to validate service account tokens // This prevents infinite auth loops if the privilegedLoopbackKubeClient authenticates using a service account token kubeClient, _, err := configapi.GetKubeClient(options.MasterClients.ExternalKubernetesKubeConfig) if err != nil { return nil, err } tokenGetter = sacontroller.NewGetterFromClient(internalclientset.FromUnversionedClient(kubeClient)) } else { // When we're running in-process, go straight to etcd (using the KubernetesStorageVersion/KubernetesStoragePrefix, since service accounts are kubernetes objects) codec := kapi.Codecs.LegacyCodec(unversioned.GroupVersion{Group: kapi.GroupName, Version: options.EtcdStorageConfig.KubernetesStorageVersion}) ketcdHelper := etcdstorage.NewEtcdStorage(client, codec, options.EtcdStorageConfig.KubernetesStoragePrefix, false) tokenGetter = sacontroller.NewGetterFromStorageInterface(ketcdHelper) } return tokenGetter, nil }
// testDeploymentCleanUpPolicy tests that deployment supports cleanup policy func testDeploymentCleanUpPolicy(f *Framework) { ns := f.Namespace.Name unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. deploymentPodLabels := map[string]string{"name": "cleanup-pod"} rcPodLabels := map[string]string{ "name": "cleanup-pod", "pod": "nginx", } rcName := "nginx-controller" replicas := 1 revisionHistoryLimit := new(int) *revisionHistoryLimit = 0 _, err := c.Core().ReplicationControllers(ns).Create(newRC(rcName, replicas, rcPodLabels, "nginx", "nginx")) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "cleanup-pod", false, 1) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a deployment to delete nginx pods and instead bring up redis pods. deploymentName := "redis-deployment" Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, deploymentPodLabels, "redis", "redis", extensions.RollingUpdateDeploymentStrategyType, revisionHistoryLimit)) Expect(err).NotTo(HaveOccurred()) defer func() { deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) Logf("deleting deployment %s", deploymentName) Expect(c.Extensions().Deployments(ns).Delete(deploymentName, nil)).NotTo(HaveOccurred()) // TODO: remove this once we can delete rcs with deployment newRC, err := deploymentutil.GetNewRC(*deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(c.Core().ReplicationControllers(ns).Delete(newRC.Name, nil)).NotTo(HaveOccurred()) }() err = waitForDeploymentOldRCsNum(c, ns, deploymentName, *revisionHistoryLimit) Expect(err).NotTo(HaveOccurred()) }
// RunNodeController starts the node controller func (c *MasterConfig) RunNodeController() { s := c.ControllerManager controller := nodecontroller.NewNodeController( c.CloudProvider, internalclientset.FromUnversionedClient(c.KubeClient), s.PodEvictionTimeout, util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst), util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst), // upstream uses the same ones too s.NodeMonitorGracePeriod, s.NodeStartupGracePeriod, s.NodeMonitorPeriod, (*net.IPNet)(&s.ClusterCIDR), s.AllocateNodeCIDRs, ) controller.Run(s.NodeSyncPeriod) }
// RunResourceQuotaManager starts the resource quota manager func (c *MasterConfig) RunResourceQuotaManager() { client := internalclientset.FromUnversionedClient(c.KubeClient) resourceQuotaRegistry := quotainstall.NewRegistry(client) groupKindsToReplenish := []unversioned.GroupKind{ kapi.Kind("Pod"), kapi.Kind("Service"), kapi.Kind("ReplicationController"), kapi.Kind("PersistentVolumeClaim"), kapi.Kind("Secret"), kapi.Kind("ConfigMap"), } resourceQuotaControllerOptions := &kresourcequota.ResourceQuotaControllerOptions{ KubeClient: client, ResyncPeriod: controller.StaticResyncPeriodFunc(c.ControllerManager.ResourceQuotaSyncPeriod.Duration), Registry: resourceQuotaRegistry, GroupKindsToReplenish: groupKindsToReplenish, ControllerFactory: kresourcequota.NewReplenishmentControllerFactory(client), ReplenishmentResyncPeriod: kctrlmgr.ResyncPeriod(c.ControllerManager), } go kresourcequota.NewResourceQuotaController(resourceQuotaControllerOptions).Run(c.ControllerManager.ConcurrentResourceQuotaSyncs, utilwait.NeverStop) }
// Create creates a NamespaceController. func (factory *NamespaceControllerFactory) Create() controller.RunnableController { namespaceLW := &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return factory.KubeClient.Namespaces().List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return factory.KubeClient.Namespaces().Watch(options) }, } queue := cache.NewFIFO(cache.MetaNamespaceKeyFunc) cache.NewReflector(namespaceLW, &kapi.Namespace{}, queue, 1*time.Minute).Run() namespaceController := &NamespaceController{ Client: factory.Client, KubeClient: internalclientset.FromUnversionedClient(factory.KubeClient), } return &controller.RetryController{ Queue: queue, RetryManager: controller.NewQueueRetryManager( queue, cache.MetaNamespaceKeyFunc, func(obj interface{}, err error, retries controller.Retry) bool { utilruntime.HandleError(err) if _, isFatal := err.(fatalError); isFatal { return false } if retries.Count > 0 { return false } return true }, kutil.NewTokenBucketRateLimiter(1, 10), ), Handle: func(obj interface{}) error { namespace := obj.(*kapi.Namespace) return namespaceController.Handle(namespace) }, } }
// RunBuildController starts the build sync loop for builds and buildConfig processing. func (c *MasterConfig) RunBuildController() { // initialize build controller dockerImage := c.ImageFor("docker-builder") stiImage := c.ImageFor("sti-builder") storageVersion := c.Options.EtcdStorageConfig.OpenShiftStorageVersion groupVersion := unversioned.GroupVersion{Group: "", Version: storageVersion} codec := kapi.Codecs.LegacyCodec(groupVersion) admissionControl := admission.NewFromPlugins(internalclientset.FromUnversionedClient(c.PrivilegedLoopbackKubernetesClient), []string{"SecurityContextConstraint"}, "") osclient, kclient := c.BuildControllerClients() factory := buildcontrollerfactory.BuildControllerFactory{ OSClient: osclient, KubeClient: kclient, BuildUpdater: buildclient.NewOSClientBuildClient(osclient), DockerBuildStrategy: &buildstrategy.DockerBuildStrategy{ Image: dockerImage, // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, }, SourceBuildStrategy: &buildstrategy.SourceBuildStrategy{ Image: stiImage, TempDirectoryCreator: buildstrategy.STITempDirectoryCreator, // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, AdmissionControl: admissionControl, }, CustomBuildStrategy: &buildstrategy.CustomBuildStrategy{ // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, }, } controller := factory.Create() controller.Run() deleteController := factory.CreateDeleteController() deleteController.Run() }
// RunNodeController starts the node controller func (c *MasterConfig) RunNodeController() { s := c.ControllerManager // this cidr has been validated already _, clusterCIDR, _ := net.ParseCIDR(s.ClusterCIDR) controller := nodecontroller.NewNodeController( c.CloudProvider, internalclientset.FromUnversionedClient(c.KubeClient), s.PodEvictionTimeout.Duration, util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst), util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst), // upstream uses the same ones too s.NodeMonitorGracePeriod.Duration, s.NodeStartupGracePeriod.Duration, s.NodeMonitorPeriod.Duration, clusterCIDR, s.AllocateNodeCIDRs, ) controller.Run(s.NodeSyncPeriod.Duration) }
// testRollbackDeploymentRSNoRevision tests that deployment supports rollback even when there's old replica set without revision. // An old replica set without revision is created, and then a deployment is created (v1). The deployment shouldn't add revision // annotation to the old replica set. Then rollback the deployment to last revision, and it should fail. // Then update the deployment to v2 and rollback it to v1 should succeed, now the deployment // becomes v3. Then rollback the deployment to v10 (doesn't exist in history) should fail. // Finally, rollback the deployment (v3) to v3 should be no-op. // TODO: When we finished reporting rollback status in deployment status, check the rollback status here in each case. func testRollbackDeploymentRSNoRevision(f *Framework) { ns := f.Namespace.Name c := clientset.FromUnversionedClient(f.Client) podName := "nginx" deploymentPodLabels := map[string]string{"name": podName} rsPodLabels := map[string]string{ "name": podName, "pod": nginxImageName, } // Create an old RS without revision rsName := "test-rollback-no-revision-controller" rsReplicas := 0 rs := newRS(rsName, rsReplicas, rsPodLabels, nginxImageName, nginxImage) rs.Annotations = make(map[string]string) rs.Annotations["make"] = "difference" _, err := c.Extensions().ReplicaSets(ns).Create(rs) Expect(err).NotTo(HaveOccurred()) // 1. Create a deployment to create nginx pods, which have different template than the replica set created above. deploymentName, deploymentImageName := "test-rollback-no-revision-deployment", nginxImageName deploymentReplicas := 1 deploymentImage := nginxImage deploymentStrategyType := extensions.RollingUpdateDeploymentStrategyType Logf("Creating deployment %s", deploymentName) d := newDeployment(deploymentName, deploymentReplicas, deploymentPodLabels, deploymentImageName, deploymentImage, deploymentStrategyType, nil) _, err = c.Extensions().Deployments(ns).Create(d) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Wait for it to be updated to revision 1 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", deploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, 0) Expect(err).NotTo(HaveOccurred()) // Check that the replica set we created still doesn't contain revision information rs, err = c.Extensions().ReplicaSets(ns).Get(rsName) Expect(err).NotTo(HaveOccurred()) Expect(rs.Annotations[deploymentutil.RevisionAnnotation]).Should(Equal("")) // 2. Update the deploymentRollback to rollback to last revision // Since there's only 1 revision in history, it should stay as revision 1 revision := int64(0) Logf("rolling back deployment %s to last revision", deploymentName) rollback := newDeploymentRollback(deploymentName, nil, revision) err = c.Extensions().Deployments(ns).Rollback(rollback) Expect(err).NotTo(HaveOccurred()) // Wait for the deployment to start rolling back err = waitForDeploymentRollbackCleared(c, ns, deploymentName) Expect(err).NotTo(HaveOccurred()) // TODO: report RollbackRevisionNotFound in deployment status and check it here // The pod template shouldn't change since there's no last revision // Check if the deployment is still revision 1 and still has the old pod template checkDeploymentRevision(c, ns, deploymentName, "1", deploymentImageName, deploymentImage) // 3. Update the deployment to create redis pods. updatedDeploymentImage := redisImage updatedDeploymentImageName := redisImageName deployment, err := updateDeploymentWithRetries(c, ns, d.Name, func(update *extensions.Deployment) { update.Spec.Template.Spec.Containers[0].Name = updatedDeploymentImageName update.Spec.Template.Spec.Containers[0].Image = updatedDeploymentImage }) Expect(err).NotTo(HaveOccurred()) // Use observedGeneration to determine if the controller noticed the pod template update. err = waitForObservedDeployment(c, ns, deploymentName, deployment.Generation) Expect(err).NotTo(HaveOccurred()) // Wait for it to be updated to revision 2 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "2", updatedDeploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, 0) Expect(err).NotTo(HaveOccurred()) // 4. Update the deploymentRollback to rollback to revision 1 revision = 1 Logf("rolling back deployment %s to revision %d", deploymentName, revision) rollback = newDeploymentRollback(deploymentName, nil, revision) err = c.Extensions().Deployments(ns).Rollback(rollback) Expect(err).NotTo(HaveOccurred()) // Wait for the deployment to start rolling back err = waitForDeploymentRollbackCleared(c, ns, deploymentName) Expect(err).NotTo(HaveOccurred()) // TODO: report RollbackDone in deployment status and check it here // The pod template should be updated to the one in revision 1 // Wait for it to be updated to revision 3 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "3", deploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, 0) Expect(err).NotTo(HaveOccurred()) // 5. Update the deploymentRollback to rollback to revision 10 // Since there's no revision 10 in history, it should stay as revision 3 revision = 10 Logf("rolling back deployment %s to revision %d", deploymentName, revision) rollback = newDeploymentRollback(deploymentName, nil, revision) err = c.Extensions().Deployments(ns).Rollback(rollback) Expect(err).NotTo(HaveOccurred()) // Wait for the deployment to start rolling back err = waitForDeploymentRollbackCleared(c, ns, deploymentName) Expect(err).NotTo(HaveOccurred()) // TODO: report RollbackRevisionNotFound in deployment status and check it here // The pod template shouldn't change since there's no revision 10 // Check if it's still revision 3 and still has the old pod template checkDeploymentRevision(c, ns, deploymentName, "3", deploymentImageName, deploymentImage) // 6. Update the deploymentRollback to rollback to revision 3 // Since it's already revision 3, it should be no-op revision = 3 Logf("rolling back deployment %s to revision %d", deploymentName, revision) rollback = newDeploymentRollback(deploymentName, nil, revision) err = c.Extensions().Deployments(ns).Rollback(rollback) Expect(err).NotTo(HaveOccurred()) // Wait for the deployment to start rolling back err = waitForDeploymentRollbackCleared(c, ns, deploymentName) Expect(err).NotTo(HaveOccurred()) // TODO: report RollbackTemplateUnchanged in deployment status and check it here // The pod template shouldn't change since it's already revision 3 // Check if it's still revision 3 and still has the old pod template checkDeploymentRevision(c, ns, deploymentName, "3", deploymentImageName, deploymentImage) }
// testRollbackDeployment tests that a deployment is created (revision 1) and updated (revision 2), and // then rollback to revision 1 (should update template to revision 1, and then update revision 1 to 3), // and then rollback to last revision. func testRollbackDeployment(f *Framework) { ns := f.Namespace.Name unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) podName := "nginx" deploymentPodLabels := map[string]string{"name": podName} // 1. Create a deployment to create nginx pods. deploymentName, deploymentImageName := "test-rollback-deployment", nginxImageName deploymentReplicas := 1 deploymentImage := nginxImage deploymentStrategyType := extensions.RollingUpdateDeploymentStrategyType Logf("Creating deployment %s", deploymentName) d := newDeployment(deploymentName, deploymentReplicas, deploymentPodLabels, deploymentImageName, deploymentImage, deploymentStrategyType, nil) createAnnotation := map[string]string{"action": "create", "author": "minion"} d.Annotations = createAnnotation _, err := c.Extensions().Deployments(ns).Create(d) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Wait for it to be updated to revision 1 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", deploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, 0) Expect(err).NotTo(HaveOccurred()) // Current newRS annotation should be "create" err = checkNewRSAnnotations(c, ns, deploymentName, createAnnotation) Expect(err).NotTo(HaveOccurred()) // 2. Update the deployment to create redis pods. updatedDeploymentImage := redisImage updatedDeploymentImageName := redisImageName updateAnnotation := map[string]string{"action": "update", "log": "I need to update it"} deployment, err := updateDeploymentWithRetries(c, ns, d.Name, func(update *extensions.Deployment) { update.Spec.Template.Spec.Containers[0].Name = updatedDeploymentImageName update.Spec.Template.Spec.Containers[0].Image = updatedDeploymentImage update.Annotations = updateAnnotation }) Expect(err).NotTo(HaveOccurred()) // Use observedGeneration to determine if the controller noticed the pod template update. err = waitForObservedDeployment(c, ns, deploymentName, deployment.Generation) Expect(err).NotTo(HaveOccurred()) // Wait for it to be updated to revision 2 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "2", updatedDeploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, 0) Expect(err).NotTo(HaveOccurred()) // Current newRS annotation should be "update" err = checkNewRSAnnotations(c, ns, deploymentName, updateAnnotation) Expect(err).NotTo(HaveOccurred()) // 3. Update the deploymentRollback to rollback to revision 1 revision := int64(1) Logf("rolling back deployment %s to revision %d", deploymentName, revision) rollback := newDeploymentRollback(deploymentName, nil, revision) err = c.Extensions().Deployments(ns).Rollback(rollback) Expect(err).NotTo(HaveOccurred()) // Wait for the deployment to start rolling back err = waitForDeploymentRollbackCleared(c, ns, deploymentName) Expect(err).NotTo(HaveOccurred()) // TODO: report RollbackDone in deployment status and check it here // Wait for it to be updated to revision 3 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "3", deploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, 0) Expect(err).NotTo(HaveOccurred()) // Current newRS annotation should be "create", after the rollback err = checkNewRSAnnotations(c, ns, deploymentName, createAnnotation) Expect(err).NotTo(HaveOccurred()) // 4. Update the deploymentRollback to rollback to last revision revision = 0 Logf("rolling back deployment %s to last revision", deploymentName) rollback = newDeploymentRollback(deploymentName, nil, revision) err = c.Extensions().Deployments(ns).Rollback(rollback) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentRollbackCleared(c, ns, deploymentName) Expect(err).NotTo(HaveOccurred()) // Wait for it to be updated to revision 4 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "4", updatedDeploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, 0) Expect(err).NotTo(HaveOccurred()) // Current newRS annotation should be "update", after the rollback err = checkNewRSAnnotations(c, ns, deploymentName, updateAnnotation) Expect(err).NotTo(HaveOccurred()) }
func testPausedDeployment(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) deploymentName := "test-paused-deployment" podLabels := map[string]string{"name": nginxImageName} d := newDeployment(deploymentName, 1, podLabels, nginxImageName, nginxImage, extensions.RollingUpdateDeploymentStrategyType, nil) d.Spec.Paused = true Logf("Creating paused deployment %s", deploymentName) _, err := c.Extensions().Deployments(ns).Create(d) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Check that deployment is created fine. deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) // Verify that there is no latest state realized for the new deployment. rs, err := deploymentutil.GetNewReplicaSet(deployment, c) Expect(err).NotTo(HaveOccurred()) if rs != nil { err = fmt.Errorf("unexpected new rs/%s for deployment/%s", rs.Name, deployment.Name) Expect(err).NotTo(HaveOccurred()) } // Update the deployment to run deployment, err = updateDeploymentWithRetries(c, ns, d.Name, func(update *extensions.Deployment) { update.Spec.Paused = false }) Expect(err).NotTo(HaveOccurred()) // Use observedGeneration to determine if the controller noticed the resume. err = waitForObservedDeployment(c, ns, deploymentName, deployment.Generation) Expect(err).NotTo(HaveOccurred()) selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) if err != nil { Expect(err).NotTo(HaveOccurred()) } opts := api.ListOptions{LabelSelector: selector} w, err := c.Extensions().ReplicaSets(ns).Watch(opts) Expect(err).NotTo(HaveOccurred()) select { case <-w.ResultChan(): // this is it case <-time.After(time.Minute): err = fmt.Errorf("expected a new replica set to be created") Expect(err).NotTo(HaveOccurred()) } // Pause the deployment and delete the replica set. // The paused deployment shouldn't recreate a new one. deployment, err = updateDeploymentWithRetries(c, ns, d.Name, func(update *extensions.Deployment) { update.Spec.Paused = true }) Expect(err).NotTo(HaveOccurred()) // Use observedGeneration to determine if the controller noticed the pause. err = waitForObservedDeployment(c, ns, deploymentName, deployment.Generation) Expect(err).NotTo(HaveOccurred()) newRS, err := deploymentutil.GetNewReplicaSet(deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(DeleteReplicaSet(unversionedClient, ns, newRS.Name)).NotTo(HaveOccurred()) deployment, err = c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) if !deployment.Spec.Paused { err = fmt.Errorf("deployment %q should be paused", deployment.Name) Expect(err).NotTo(HaveOccurred()) } shouldBeNil, err := deploymentutil.GetNewReplicaSet(deployment, c) Expect(err).NotTo(HaveOccurred()) if shouldBeNil != nil { err = fmt.Errorf("deployment %q shouldn't have a replica set but there is %q", deployment.Name, shouldBeNil.Name) Expect(err).NotTo(HaveOccurred()) } }
// testRolloverDeployment tests that deployment supports rollover. // i.e. we can change desired state and kick off rolling update, then change desired state again before it finishes. func testRolloverDeployment(f *Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) podName := "rollover-pod" deploymentPodLabels := map[string]string{"name": podName} rsPodLabels := map[string]string{ "name": podName, "pod": nginxImageName, } rsName := "test-rollover-controller" rsReplicas := 4 _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, rsReplicas, rsPodLabels, nginxImageName, nginxImage)) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, podName, false, rsReplicas) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Wait for the required pods to be ready for at least minReadySeconds (be available) deploymentMinReadySeconds := 5 err = waitForPodsReady(c, ns, podName, deploymentMinReadySeconds) Expect(err).NotTo(HaveOccurred()) // Create a deployment to delete nginx pods and instead bring up redis-slave pods. deploymentName, deploymentImageName := "test-rollover-deployment", "redis-slave" deploymentReplicas := 4 deploymentImage := "gcr.io/google_samples/gb-redisslave:v1" deploymentStrategyType := extensions.RollingUpdateDeploymentStrategyType Logf("Creating deployment %s", deploymentName) newDeployment := newDeployment(deploymentName, deploymentReplicas, deploymentPodLabels, deploymentImageName, deploymentImage, deploymentStrategyType, nil) newDeployment.Spec.MinReadySeconds = deploymentMinReadySeconds newDeployment.Spec.Strategy.RollingUpdate = &extensions.RollingUpdateDeployment{ MaxUnavailable: intstr.FromInt(1), MaxSurge: intstr.FromInt(1), } _, err = c.Extensions().Deployments(ns).Create(newDeployment) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Verify that the pods were scaled up and down as expected. We use events to verify that. deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) // Make sure the deployment starts to scale up and down replica sets waitForPartialEvents(unversionedClient, ns, deployment, 2) // Check if it's updated to revision 1 correctly _, newRS := checkDeploymentRevision(c, ns, deploymentName, "1", deploymentImageName, deploymentImage) // Before the deployment finishes, update the deployment to rollover the above 2 ReplicaSets and bring up redis pods. // If the deployment already finished here, the test would fail. When this happens, increase its minReadySeconds or replicas to prevent it. Expect(newRS.Spec.Replicas).Should(BeNumerically("<", deploymentReplicas)) updatedDeploymentImageName, updatedDeploymentImage := redisImageName, redisImage deployment, err = updateDeploymentWithRetries(c, ns, newDeployment.Name, func(update *extensions.Deployment) { update.Spec.Template.Spec.Containers[0].Name = updatedDeploymentImageName update.Spec.Template.Spec.Containers[0].Image = updatedDeploymentImage }) Expect(err).NotTo(HaveOccurred()) // Use observedGeneration to determine if the controller noticed the pod template update. err = waitForObservedDeployment(c, ns, deploymentName, deployment.Generation) Expect(err).NotTo(HaveOccurred()) // Wait for it to be updated to revision 2 err = waitForDeploymentRevisionAndImage(c, ns, deploymentName, "2", updatedDeploymentImage) Expect(err).NotTo(HaveOccurred()) err = waitForDeploymentStatus(c, ns, deploymentName, deploymentReplicas, deploymentReplicas-1, deploymentReplicas+1, deploymentMinReadySeconds) Expect(err).NotTo(HaveOccurred()) }
// testDeploymentCleanUpPolicy tests that deployment supports cleanup policy func testDeploymentCleanUpPolicy(f *Framework) { ns := f.Namespace.Name unversionedClient := f.Client c := clientset.FromUnversionedClient(unversionedClient) // Create nginx pods. deploymentPodLabels := map[string]string{"name": "cleanup-pod"} rsPodLabels := map[string]string{ "name": "cleanup-pod", "pod": nginxImageName, } rsName := "test-cleanup-controller" replicas := 1 revisionHistoryLimit := util.IntPtr(0) _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, replicas, rsPodLabels, nginxImageName, nginxImage)) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = verifyPods(unversionedClient, ns, "cleanup-pod", false, 1) if err != nil { Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a deployment to delete nginx pods and instead bring up redis pods. deploymentName := "test-cleanup-deployment" Logf("Creating deployment %s", deploymentName) pods, err := c.Pods(ns).List(api.ListOptions{LabelSelector: labels.Everything()}) if err != nil { Expect(err).NotTo(HaveOccurred(), "Failed to query for pods: %v", err) } options := api.ListOptions{ ResourceVersion: pods.ListMeta.ResourceVersion, } stopCh := make(chan struct{}) w, err := c.Pods(ns).Watch(options) go func() { // There should be only one pod being created, which is the pod with the redis image. // The old RS shouldn't create new pod when deployment controller adding pod template hash label to its selector. numPodCreation := 1 for { select { case event, _ := <-w.ResultChan(): if event.Type != watch.Added { continue } numPodCreation-- if numPodCreation < 0 { Failf("Expect only one pod creation, the second creation event: %#v\n", event) } pod, ok := event.Object.(*api.Pod) if !ok { Fail("Expect event Object to be a pod") } if pod.Spec.Containers[0].Name != redisImageName { Failf("Expect the created pod to have container name %s, got pod %#v\n", redisImageName, pod) } case <-stopCh: return } } }() _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, deploymentPodLabels, redisImageName, redisImage, extensions.RollingUpdateDeploymentStrategyType, revisionHistoryLimit)) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) err = waitForDeploymentOldRSsNum(c, ns, deploymentName, *revisionHistoryLimit) Expect(err).NotTo(HaveOccurred()) close(stopCh) }
func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client, pluginInitializer oadmission.PluginInitializer) (*MasterConfig, error) { if options.KubernetesMasterConfig == nil { return nil, errors.New("insufficient information to build KubernetesMasterConfig") } // Connect and setup etcd interfaces etcdClient, err := etcd.MakeNewEtcdClient(options.EtcdClientInfo) if err != nil { return nil, err } kubeletClientConfig := configapi.GetKubeletClientConfig(options) kubeletClient, err := kubeletclient.NewStaticKubeletClient(kubeletClientConfig) if err != nil { return nil, fmt.Errorf("unable to configure Kubelet client: %v", err) } // in-order list of plug-ins that should intercept admission decisions // TODO: Push node environment support to upstream in future _, portString, err := net.SplitHostPort(options.ServingInfo.BindAddress) if err != nil { return nil, err } port, err := strconv.Atoi(portString) if err != nil { return nil, err } portRange, err := knet.ParsePortRange(options.KubernetesMasterConfig.ServicesNodePortRange) if err != nil { return nil, err } podEvictionTimeout, err := time.ParseDuration(options.KubernetesMasterConfig.PodEvictionTimeout) if err != nil { return nil, fmt.Errorf("unable to parse PodEvictionTimeout: %v", err) } // Defaults are tested in TestAPIServerDefaults server := apiserveroptions.NewAPIServer() // Adjust defaults server.EventTTL = 2 * time.Hour server.ServiceClusterIPRange = net.IPNet(flagtypes.DefaultIPNet(options.KubernetesMasterConfig.ServicesSubnet)) server.ServiceNodePortRange = *portRange server.AdmissionControl = strings.Join(AdmissionPlugins, ",") server.EnableLogsSupport = false // don't expose server logs // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.APIServerArguments, server.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } if len(options.KubernetesMasterConfig.AdmissionConfig.PluginOrderOverride) > 0 { server.AdmissionControl = strings.Join(options.KubernetesMasterConfig.AdmissionConfig.PluginOrderOverride, ",") } // Defaults are tested in TestCMServerDefaults cmserver := cmapp.NewCMServer() // Adjust defaults cmserver.Address = "" // no healthz endpoint cmserver.Port = 0 // no healthz endpoint cmserver.PodEvictionTimeout = unversioned.Duration{Duration: podEvictionTimeout} // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.ControllerArguments, cmserver.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } cloud, err := cloudprovider.InitCloudProvider(cmserver.CloudProvider, cmserver.CloudConfigFile) if err != nil { return nil, err } if cloud != nil { glog.V(2).Infof("Successfully initialized cloud provider: %q from the config file: %q\n", server.CloudProvider, server.CloudConfigFile) } plugins := []admission.Interface{} for _, pluginName := range strings.Split(server.AdmissionControl, ",") { switch pluginName { case serviceadmit.ExternalIPPluginName: // this needs to be moved upstream to be part of core config reject, admit, err := serviceadmit.ParseCIDRRules(options.NetworkConfig.ExternalIPNetworkCIDRs) if err != nil { // should have been caught with validation return nil, err } plugins = append(plugins, serviceadmit.NewExternalIPRanger(reject, admit)) case saadmit.PluginName: // we need to set some custom parameters on the service account admission controller, so create that one by hand saAdmitter := saadmit.NewServiceAccount(internalclientset.FromUnversionedClient(kubeClient)) saAdmitter.LimitSecretReferences = options.ServiceAccountConfig.LimitSecretReferences saAdmitter.Run() plugins = append(plugins, saAdmitter) default: configFile, err := pluginconfig.GetPluginConfigFile(options.KubernetesMasterConfig.AdmissionConfig.PluginConfig, pluginName, server.AdmissionControlConfigFile) if err != nil { return nil, err } plugin := admission.InitPlugin(pluginName, internalclientset.FromUnversionedClient(kubeClient), configFile) if plugin != nil { plugins = append(plugins, plugin) } } } pluginInitializer.Initialize(plugins) // ensure that plugins have been properly initialized if err := oadmission.Validate(plugins); err != nil { return nil, err } admissionController := admission.NewChainHandler(plugins...) var proxyClientCerts []tls.Certificate if len(options.KubernetesMasterConfig.ProxyClientInfo.CertFile) > 0 { clientCert, err := tls.LoadX509KeyPair( options.KubernetesMasterConfig.ProxyClientInfo.CertFile, options.KubernetesMasterConfig.ProxyClientInfo.KeyFile, ) if err != nil { return nil, err } proxyClientCerts = append(proxyClientCerts, clientCert) } // TODO you have to know every APIGroup you're enabling or upstream will panic. It's alternative to panicing is Fataling // It needs a refactor to return errors storageDestinations := genericapiserver.NewStorageDestinations() // storageVersions is a map from API group to allowed versions that must be a version exposed by the REST API or it breaks. // We need to fix the upstream to stop using the storage version as a preferred api version. storageVersions := map[string]string{} enabledKubeVersions := configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupKube) if len(enabledKubeVersions) > 0 { kubeStorageVersion := unversioned.GroupVersion{Group: configapi.APIGroupKube, Version: options.EtcdStorageConfig.KubernetesStorageVersion} databaseStorage, err := NewEtcdStorage(etcdClient, kubeStorageVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes server storage: %v", err) } storageDestinations.AddAPIGroup(configapi.APIGroupKube, databaseStorage) storageVersions[configapi.APIGroupKube] = options.EtcdStorageConfig.KubernetesStorageVersion } // enable this if extensions API is enabled (or batch or autoscaling, since they persist to extensions/v1beta1 for now) // TODO: replace this with a loop over configured storage versions extensionsEnabled := len(configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupExtensions)) > 0 batchEnabled := len(configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupBatch)) > 0 autoscalingEnabled := len(configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupAutoscaling)) > 0 if extensionsEnabled || autoscalingEnabled || batchEnabled { // TODO: replace this with a configured storage version for extensions once configuration exposes this extensionsStorageVersion := unversioned.GroupVersion{Group: extensions.GroupName, Version: "v1beta1"} databaseStorage, err := NewEtcdStorage(etcdClient, extensionsStorageVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes extensions server storage: %v", err) } storageDestinations.AddAPIGroup(configapi.APIGroupExtensions, databaseStorage) storageVersions[configapi.APIGroupExtensions] = extensionsStorageVersion.String() } // Preserve previous behavior of using the first non-loopback address // TODO: Deprecate this behavior and just require a valid value to be passed in publicAddress := net.ParseIP(options.KubernetesMasterConfig.MasterIP) if publicAddress == nil || publicAddress.IsUnspecified() || publicAddress.IsLoopback() { hostIP, err := knet.ChooseHostInterface() if err != nil { glog.Fatalf("Unable to find suitable network address.error='%v'. Set the masterIP directly to avoid this error.", err) } publicAddress = hostIP glog.Infof("Will report %v as public IP address.", publicAddress) } m := &master.Config{ Config: &genericapiserver.Config{ PublicAddress: publicAddress, ReadWritePort: port, Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admissionController, StorageDestinations: storageDestinations, StorageVersions: storageVersions, ServiceClusterIPRange: (*net.IPNet)(&server.ServiceClusterIPRange), ServiceNodePortRange: server.ServiceNodePortRange, RequestContextMapper: requestContextMapper, APIGroupVersionOverrides: getAPIGroupVersionOverrides(options), APIPrefix: KubeAPIPrefix, APIGroupPrefix: KubeAPIGroupPrefix, MasterCount: options.KubernetesMasterConfig.MasterCount, // Set the TLS options for proxying to pods and services // Proxying to nodes uses the kubeletClient TLS config (so can provide a different cert, and verify the node hostname) ProxyTLSClientConfig: &tls.Config{ // Proxying to pods and services cannot verify hostnames, since they are contacted on randomly allocated IPs InsecureSkipVerify: true, Certificates: proxyClientCerts, }, Serializer: kapi.Codecs, }, EventTTL: server.EventTTL, //MinRequestTimeout: server.MinRequestTimeout, KubeletClient: kubeletClient, EnableCoreControllers: true, } if options.DNSConfig != nil { _, dnsPortStr, err := net.SplitHostPort(options.DNSConfig.BindAddress) if err != nil { return nil, fmt.Errorf("unable to parse DNS bind address %s: %v", options.DNSConfig.BindAddress, err) } dnsPort, err := strconv.Atoi(dnsPortStr) if err != nil { return nil, fmt.Errorf("invalid DNS port: %v", err) } m.ExtraServicePorts = append(m.ExtraServicePorts, kapi.ServicePort{Name: "dns", Port: 53, Protocol: kapi.ProtocolUDP, TargetPort: intstr.FromInt(dnsPort)}, kapi.ServicePort{Name: "dns-tcp", Port: 53, Protocol: kapi.ProtocolTCP, TargetPort: intstr.FromInt(dnsPort)}, ) m.ExtraEndpointPorts = append(m.ExtraEndpointPorts, kapi.EndpointPort{Name: "dns", Port: dnsPort, Protocol: kapi.ProtocolUDP}, kapi.EndpointPort{Name: "dns-tcp", Port: dnsPort, Protocol: kapi.ProtocolTCP}, ) } kmaster := &MasterConfig{ Options: *options.KubernetesMasterConfig, KubeClient: kubeClient, Master: m, ControllerManager: cmserver, CloudProvider: cloud, } return kmaster, nil }