// GetOldReplicaSetsFromLists returns two sets of old replica sets targeted by the given Deployment; get PodList and ReplicaSetList with input functions. // Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets. func GetOldReplicaSetsFromLists(deployment extensions.Deployment, c clientset.Interface, getPodList func(string, api.ListOptions) (*api.PodList, error), getRSList func(string, api.ListOptions) ([]extensions.ReplicaSet, error)) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, error) { namespace := deployment.ObjectMeta.Namespace selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) if err != nil { return nil, nil, fmt.Errorf("invalid label selector: %v", err) } // 1. Find all pods whose labels match deployment.Spec.Selector options := api.ListOptions{LabelSelector: selector} podList, err := getPodList(namespace, options) if err != nil { return nil, nil, fmt.Errorf("error listing pods: %v", err) } // 2. Find the corresponding replica sets for pods in podList. // TODO: Right now we list all replica sets and then filter. We should add an API for this. oldRSs := map[string]extensions.ReplicaSet{} allOldRSs := map[string]extensions.ReplicaSet{} rsList, err := getRSList(namespace, options) if err != nil { return nil, nil, fmt.Errorf("error listing replica sets: %v", err) } newRSTemplate := GetNewReplicaSetTemplate(deployment) for _, pod := range podList.Items { podLabelsSelector := labels.Set(pod.ObjectMeta.Labels) for _, rs := range rsList { rsLabelsSelector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector) if err != nil { return nil, nil, fmt.Errorf("invalid label selector: %v", err) } // Filter out replica set that has the same pod template spec as the deployment - that is the new replica set. if api.Semantic.DeepEqual(rs.Spec.Template, &newRSTemplate) { continue } allOldRSs[rs.ObjectMeta.Name] = rs if rsLabelsSelector.Matches(podLabelsSelector) { oldRSs[rs.ObjectMeta.Name] = rs } } } requiredRSs := []*extensions.ReplicaSet{} for key := range oldRSs { value := oldRSs[key] requiredRSs = append(requiredRSs, &value) } allRSs := []*extensions.ReplicaSet{} for key := range allOldRSs { value := allOldRSs[key] allRSs = append(allRSs, &value) } return requiredRSs, allRSs, nil }
// FindOldReplicaSets returns the old replica sets targeted by the given Deployment, with the given PodList and slice of RSes. // Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets. func FindOldReplicaSets(deployment *extensions.Deployment, rsList []extensions.ReplicaSet, podList *api.PodList) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, error) { // Find all pods whose labels match deployment.Spec.Selector, and corresponding replica sets for pods in podList. // All pods and replica sets are labeled with pod-template-hash to prevent overlapping oldRSs := map[string]extensions.ReplicaSet{} allOldRSs := map[string]extensions.ReplicaSet{} newRSTemplate := GetNewReplicaSetTemplate(deployment) for _, pod := range podList.Items { podLabelsSelector := labels.Set(pod.ObjectMeta.Labels) for _, rs := range rsList { rsLabelsSelector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector) if err != nil { return nil, nil, fmt.Errorf("invalid label selector: %v", err) } // Filter out replica set that has the same pod template spec as the deployment - that is the new replica set. if api.Semantic.DeepEqual(rs.Spec.Template, newRSTemplate) { continue } allOldRSs[rs.ObjectMeta.Name] = rs if rsLabelsSelector.Matches(podLabelsSelector) { oldRSs[rs.ObjectMeta.Name] = rs } } } requiredRSs := []*extensions.ReplicaSet{} for key := range oldRSs { value := oldRSs[key] requiredRSs = append(requiredRSs, &value) } allRSs := []*extensions.ReplicaSet{} for key := range allOldRSs { value := allOldRSs[key] allRSs = append(allRSs, &value) } return requiredRSs, allRSs, nil }
func TestNumberReadyStatus(t *testing.T) { manager, podControl := newTestController() addNodes(manager.nodeStore.Store, 0, 2, simpleNodeLabel) addPods(manager.podStore.Indexer, "node-0", simpleDaemonSetLabel, 1) addPods(manager.podStore.Indexer, "node-1", simpleDaemonSetLabel, 1) daemon := newDaemonSet("foo") manager.dsStore.Add(daemon) syncAndValidateDaemonSets(t, manager, daemon, podControl, 0, 0) if daemon.Status.NumberReady != 0 { t.Errorf("Wrong daemon %s status: %v", daemon.Name, daemon.Status) } selector, _ := unversioned.LabelSelectorAsSelector(daemon.Spec.Selector) daemonPods, _ := manager.podStore.Pods(daemon.Namespace).List(selector) for _, pod := range daemonPods { condition := api.PodCondition{Type: api.PodReady, Status: api.ConditionTrue} pod.Status.Conditions = append(pod.Status.Conditions, condition) } syncAndValidateDaemonSets(t, manager, daemon, podControl, 0, 0) if daemon.Status.NumberReady != 2 { t.Errorf("Wrong daemon %s status: %v", daemon.Name, daemon.Status) } }
// Returns structure containing DaemonSet and Pods for the given daemon set. func getRawDaemonSetWithPods(client client.Interface, namespace, name string) ( *DaemonSetWithPods, error) { daemonSet, err := client.Extensions().DaemonSets(namespace).Get(name) if err != nil { return nil, err } labelSelector, err := unversioned.LabelSelectorAsSelector(daemonSet.Spec.Selector) if err != nil { return nil, err } pods, err := client.Pods(namespace).List( api.ListOptions{ LabelSelector: labelSelector, FieldSelector: fields.Everything(), }) if err != nil { return nil, err } daemonSetAndPods := &DaemonSetWithPods{ DaemonSet: daemonSet, Pods: pods, } return daemonSetAndPods, nil }
// DeleteDaemonSetServices deletes services related to daemon set with given name in given namespace. func DeleteDaemonSetServices(client k8sClient.Interface, namespace, name string) error { log.Printf("Deleting services related to %s daemon set from %s namespace", name, namespace) daemonSet, err := client.Extensions().DaemonSets(namespace).Get(name) if err != nil { return err } labelSelector, err := unversioned.LabelSelectorAsSelector(daemonSet.Spec.Selector) if err != nil { return err } services, err := getServicesForDSDeletion(client, labelSelector, namespace) if err != nil { return err } for _, service := range services { if err := client.Services(namespace).Delete(service.Name); err != nil { return err } } log.Printf("Successfully deleted services related to %s daemon set from %s namespace", name, namespace) return nil }
// GetPodPetSets returns a list of PetSets managing a pod. Returns an error only if no matching PetSets are found. func (s *StoreToPetSetLister) GetPodPetSets(pod *api.Pod) (psList []apps.PetSet, err error) { var selector labels.Selector var ps apps.PetSet if len(pod.Labels) == 0 { err = fmt.Errorf("no PetSets found for pod %v because it has no labels", pod.Name) return } for _, m := range s.Store.List() { ps = *m.(*apps.PetSet) if ps.Namespace != pod.Namespace { continue } selector, err = unversioned.LabelSelectorAsSelector(ps.Spec.Selector) if err != nil { err = fmt.Errorf("invalid selector: %v", err) return } // If a PetSet with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { continue } psList = append(psList, ps) } if len(psList) == 0 { err = fmt.Errorf("could not find PetSet for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) } return }
// GetPodJobs returns a list of jobs managing a pod. Returns an error only if no matching jobs are found. func (s *StoreToJobLister) GetPodJobs(pod *api.Pod) (jobs []extensions.Job, err error) { var selector labels.Selector var job extensions.Job if len(pod.Labels) == 0 { err = fmt.Errorf("no jobs found for pod %v because it has no labels", pod.Name) return } for _, m := range s.Store.List() { job = *m.(*extensions.Job) if job.Namespace != pod.Namespace { continue } selector, _ = unversioned.LabelSelectorAsSelector(job.Spec.Selector) if !selector.Matches(labels.Set(pod.Labels)) { continue } jobs = append(jobs, job) } if len(jobs) == 0 { err = fmt.Errorf("could not find jobs for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) } return }
// GetPodReplicaSets returns a list of ReplicaSets managing a pod. Returns an error only if no matching ReplicaSets are found. func (s *StoreToReplicaSetLister) GetPodReplicaSets(pod *v1.Pod) (rss []*extensions.ReplicaSet, err error) { if len(pod.Labels) == 0 { err = fmt.Errorf("no ReplicaSets found for pod %v because it has no labels", pod.Name) return } list, err := s.ReplicaSets(pod.Namespace).List(labels.Everything()) if err != nil { return } for _, rs := range list { if rs.Namespace != pod.Namespace { continue } selector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid selector: %v", err) } // If a ReplicaSet with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { continue } rss = append(rss, rs) } if len(rss) == 0 { err = fmt.Errorf("could not find ReplicaSet for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) } return }
// GetDeploymentEvents returns model events for a deployment with the given name in the given // namespace func GetDeploymentEvents(client client.Interface, dsQuery *dataselect.DataSelectQuery, namespace string, deploymentName string) ( *common.EventList, error) { deployment, err := client.Extensions().Deployments(namespace).Get(deploymentName) if err != nil { return nil, err } selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) if err != nil { return nil, err } options := api.ListOptions{LabelSelector: selector} channels := &common.ResourceChannels{ EventList: common.GetEventListChannelWithOptions(client, common.NewSameNamespaceQuery(namespace), options, 1), } eventRaw := <-channels.EventList.List if err := <-channels.EventList.Error; err != nil { return nil, err } dpEvents := eventRaw.Items if !event.IsTypeFilled(dpEvents) { dpEvents = event.FillEventsType(dpEvents) } eventList := event.CreateEventList(dpEvents, dsQuery) return &eventList, nil }
// Validates given deployment spec. func ValidateDeploymentSpec(spec *extensions.DeploymentSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...) if spec.Selector == nil { allErrs = append(allErrs, field.Required(fldPath.Child("selector"), "")) } else { allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) if len(spec.Selector.MatchLabels)+len(spec.Selector.MatchExpressions) == 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "empty selector is not valid for deployment.")) } } selector, err := unversioned.LabelSelectorAsSelector(spec.Selector) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "failed to convert LabelSelector to Selector.")) } else { allErrs = append(allErrs, ValidatePodTemplateSpecForReplicaSet(&spec.Template, selector, spec.Replicas, fldPath.Child("template"))...) } allErrs = append(allErrs, ValidateDeploymentStrategy(&spec.Strategy, fldPath.Child("strategy"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...) if spec.RevisionHistoryLimit != nil { // zero is a valid RevisionHistoryLimit allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.RevisionHistoryLimit), fldPath.Child("revisionHistoryLimit"))...) } if spec.RollbackTo != nil { allErrs = append(allErrs, ValidateRollback(spec.RollbackTo, fldPath.Child("rollback"))...) } return allErrs }
func ValidateJobSpec(spec *extensions.JobSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if spec.Parallelism != nil { allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.Parallelism), fldPath.Child("parallelism"))...) } if spec.Completions != nil { allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.Completions), fldPath.Child("completions"))...) } if spec.ActiveDeadlineSeconds != nil { allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.ActiveDeadlineSeconds), fldPath.Child("activeDeadlineSeconds"))...) } if spec.Selector == nil { allErrs = append(allErrs, field.Required(fldPath.Child("selector"), "")) } else { allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) } if selector, err := unversioned.LabelSelectorAsSelector(spec.Selector); err == nil { labels := labels.Set(spec.Template.Labels) if !selector.Matches(labels) { allErrs = append(allErrs, field.Invalid(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "`selector` does not match template `labels`")) } } allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(&spec.Template, fldPath.Child("template"))...) if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure && spec.Template.Spec.RestartPolicy != api.RestartPolicyNever { allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)})) } return allErrs }
// rsAndPodsWithHashKeySynced returns the RSs and pods the given deployment targets, with pod-template-hash information synced. func rsAndPodsWithHashKeySynced(deployment extensions.Deployment, c clientset.Interface, getRSList rsListFunc, getPodList podListFunc) ([]extensions.ReplicaSet, *api.PodList, error) { namespace := deployment.Namespace selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) if err != nil { return nil, nil, err } options := api.ListOptions{LabelSelector: selector} rsList, err := getRSList(namespace, options) if err != nil { return nil, nil, err } syncedRSList := []extensions.ReplicaSet{} for _, rs := range rsList { // Add pod-template-hash information if it's not in the RS. // Otherwise, new RS produced by Deployment will overlap with pre-existing ones // that aren't constrained by the pod-template-hash. syncedRS, err := addHashKeyToRSAndPods(deployment, c, rs, getPodList) if err != nil { return nil, nil, err } syncedRSList = append(syncedRSList, *syncedRS) } syncedPodList, err := getPodList(namespace, options) if err != nil { return nil, nil, err } return syncedRSList, syncedPodList, nil }
func (p *statefulSetTester) getPodList(ps *apps.StatefulSet) *api.PodList { selector, err := unversioned.LabelSelectorAsSelector(ps.Spec.Selector) ExpectNoError(err) podList, err := p.c.Core().Pods(ps.Namespace).List(api.ListOptions{LabelSelector: selector}) ExpectNoError(err) return podList }
// GetPodDaemonSets returns a list of daemon sets managing a pod. // Returns an error if and only if no matching daemon sets are found. func (s *StoreToDaemonSetLister) GetPodDaemonSets(pod *api.Pod) (daemonSets []extensions.DaemonSet, err error) { var selector labels.Selector var daemonSet extensions.DaemonSet if len(pod.Labels) == 0 { err = fmt.Errorf("no daemon sets found for pod %v because it has no labels", pod.Name) return } for _, m := range s.Store.List() { daemonSet = *m.(*extensions.DaemonSet) if daemonSet.Namespace != pod.Namespace { continue } selector, err = unversioned.LabelSelectorAsSelector(daemonSet.Spec.Selector) if err != nil { // this should not happen if the DaemonSet passed validation return nil, err } // If a daemonSet with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { continue } daemonSets = append(daemonSets, daemonSet) } if len(daemonSets) == 0 { err = fmt.Errorf("could not find daemon set for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) } return }
// getJobPods returns list of pods targeting deployment. func GetDeploymentPods(client client.Interface, heapsterClient heapster.HeapsterClient, dsQuery *dataselect.DataSelectQuery, namespace string, deploymentName string) (*pod.PodList, error) { deployment, err := client.Extensions().Deployments(namespace).Get(deploymentName) if err != nil { return nil, err } selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) if err != nil { return nil, err } options := api.ListOptions{LabelSelector: selector} channels := &common.ResourceChannels{ PodList: common.GetPodListChannelWithOptions(client, common.NewSameNamespaceQuery(namespace), options, 1), } rawPods := <-channels.PodList.List if err := <-channels.PodList.Error; err != nil { return nil, err } pods := common.FilterNamespacedPodsBySelector(rawPods.Items, deployment.ObjectMeta.Namespace, deployment.Spec.Selector.MatchLabels) podList := pod.CreatePodList(pods, []api.Event{}, dsQuery, heapsterClient) return &podList, nil }
// GetPodPodDisruptionBudgets returns a list of PodDisruptionBudgets matching a pod. Returns an error only if no matching PodDisruptionBudgets are found. func (s *StoreToPodDisruptionBudgetLister) GetPodPodDisruptionBudgets(pod *api.Pod) (pdbList []policy.PodDisruptionBudget, err error) { var selector labels.Selector if len(pod.Labels) == 0 { err = fmt.Errorf("no PodDisruptionBudgets found for pod %v because it has no labels", pod.Name) return } for _, m := range s.Store.List() { pdb, ok := m.(*policy.PodDisruptionBudget) if !ok { glog.Errorf("Unexpected: %v is not a PodDisruptionBudget", m) continue } if pdb.Namespace != pod.Namespace { continue } selector, err = unversioned.LabelSelectorAsSelector(pdb.Spec.Selector) if err != nil { glog.Warningf("invalid selector: %v", err) // TODO(mml): add an event to the PDB continue } // If a PDB with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { continue } pdbList = append(pdbList, *pdb) } if len(pdbList) == 0 { err = fmt.Errorf("could not find PodDisruptionBudget for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) } return }
func TestToLabelSelector(t *testing.T) { selector, _ := unversioned.LabelSelectorAsSelector( &unversioned.LabelSelector{MatchLabels: map[string]string{"app": "test"}}) cases := []struct { selector map[string]string expected labels.Selector }{ { map[string]string{}, labels.SelectorFromSet(nil), }, { map[string]string{"app": "test"}, selector, }, } for _, c := range cases { actual, _ := toLabelSelector(c.selector) if !reflect.DeepEqual(actual, c.expected) { t.Errorf("toLabelSelector(%#v) == \n%#v\nexpected \n%#v\n", c.selector, actual, c.expected) } } }
func labelSelectorAsSelector(ps *v1beta1.LabelSelector) (labels.Selector, error) { unversionedSelector := unversioned.LabelSelector{} if err := api.Scheme.Convert(ps, &unversionedSelector, nil); err != nil { return nil, err } return unversioned.LabelSelectorAsSelector(&unversionedSelector) }
// A function that calculates how many pods from the list are in one of // the meaningful (from the replica set perspective) states. This function is // a temporary workaround against the current lack of ownerRef in pods. func AnalysePods(selectorv1 *unversioned.LabelSelector, allPods []util.FederatedObject, currentTime time.Time) (map[string]PodAnalysisResult, error) { selector, err := unversioned.LabelSelectorAsSelector(selectorv1) if err != nil { return nil, fmt.Errorf("invalid selector: %v", err) } result := make(map[string]PodAnalysisResult) for _, fedObject := range allPods { pod, isPod := fedObject.Object.(*api_v1.Pod) if !isPod { return nil, fmt.Errorf("invalid arg content - not a *pod") } if !selector.Empty() && selector.Matches(labels.Set(pod.Labels)) { status := result[fedObject.ClusterName] status.Total++ for _, condition := range pod.Status.Conditions { if pod.Status.Phase == api_v1.PodRunning { if condition.Type == api_v1.PodReady { status.RunningAndReady++ } } else { if condition.Type == api_v1.PodScheduled && condition.Status == api_v1.ConditionFalse && condition.Reason == "Unschedulable" && condition.LastTransitionTime.Add(UnschedulableThreshold).Before(currentTime) { status.Unschedulable++ } } } result[fedObject.ClusterName] = status } } return result, nil }
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)) }
// ValidateStatefulSetSpec tests if required fields in the StatefulSet spec are set. func ValidateStatefulSetSpec(spec *apps.StatefulSetSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...) if spec.Selector == nil { allErrs = append(allErrs, field.Required(fldPath.Child("selector"), "")) } else { allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) if len(spec.Selector.MatchLabels)+len(spec.Selector.MatchExpressions) == 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "empty selector is not valid for statefulset.")) } } selector, err := unversioned.LabelSelectorAsSelector(spec.Selector) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "")) } else { allErrs = append(allErrs, ValidatePodTemplateSpecForStatefulSet(&spec.Template, selector, fldPath.Child("template"))...) } if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) } return allErrs }
// handleOverlap relists all deployment in the same namespace for overlaps, and avoid syncing // the newer overlapping ones (only sync the oldest one). New/old is determined by when the // deployment's selector is last updated. func (dc *DeploymentController) handleOverlap(d *extensions.Deployment) error { selector, err := unversioned.LabelSelectorAsSelector(d.Spec.Selector) if err != nil { return fmt.Errorf("deployment %s/%s has invalid label selector: %v", d.Namespace, d.Name, err) } deployments, err := dc.dStore.Deployments(d.Namespace).List(labels.Everything()) if err != nil { return fmt.Errorf("error listing deployments in namespace %s: %v", d.Namespace, err) } overlapping := false for i := range deployments { other := &deployments[i] if !selector.Empty() && selector.Matches(labels.Set(other.Spec.Template.Labels)) && d.UID != other.UID { overlapping = true // We don't care if the overlapping annotation update failed or not (we don't make decision on it) d, _ = dc.markDeploymentOverlap(d, other.Name) other, _ = dc.markDeploymentOverlap(other, d.Name) // Skip syncing this one if older overlapping one is found // TODO: figure out a better way to determine which deployment to skip, // either with controller reference, or with validation. // Using oldest active replica set to determine which deployment to skip wouldn't make much difference, // since new replica set hasn't been created after selector update if util.SelectorUpdatedBefore(other, d) { return fmt.Errorf("found deployment %s/%s has overlapping selector with an older deployment %s/%s, skip syncing it", d.Namespace, d.Name, other.Namespace, other.Name) } } } if !overlapping { // We don't care if the overlapping annotation update failed or not (we don't make decision on it) d, _ = dc.clearDeploymentOverlap(d) } return nil }
// Returns any PDBs that match the pod. // err is set if there's an error. func (r *EvictionREST) getPodDisruptionBudgets(ctx api.Context, pod *api.Pod) (pdbs []policy.PodDisruptionBudget, err error) { if len(pod.Labels) == 0 { return } pdbList, err := r.podDisruptionBudgetClient.PodDisruptionBudgets(pod.Namespace).List(api.ListOptions{}) if err != nil { return } for _, pdb := range pdbList.Items { if pdb.Namespace != pod.Namespace { continue } selector, err := unversioned.LabelSelectorAsSelector(pdb.Spec.Selector) if err != nil { continue } // If a PDB with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { continue } pdbs = append(pdbs, pdb) } return pdbs, nil }
// GetDeploymentsForDeployments returns a list of deployments managing a pod. Returns an error only if no matching deployments are found. // TODO eliminate shallow copies func (s *StoreToDeploymentLister) GetDeploymentsForPod(pod *v1.Pod) (deployments []*extensions.Deployment, err error) { if len(pod.Labels) == 0 { err = fmt.Errorf("no deployments found for Pod %v because it has no labels", pod.Name) return } if len(pod.Labels[extensions.DefaultDeploymentUniqueLabelKey]) == 0 { return } dList, err := s.Deployments(pod.Namespace).List(labels.Everything()) if err != nil { return } for _, d := range dList { selector, err := unversioned.LabelSelectorAsSelector(d.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } // If a deployment with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { continue } deployments = append(deployments, d) } if len(deployments) == 0 { err = fmt.Errorf("could not find deployments set for Pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) } return }
func (a *HorizontalController) computeReplicasForCPUUtilization(hpa *extensions.HorizontalPodAutoscaler, scale *extensions.Scale) (int, *int, time.Time, error) { targetUtilization := defaultTargetCPUUtilizationPercentage if hpa.Spec.CPUUtilization != nil { targetUtilization = hpa.Spec.CPUUtilization.TargetPercentage } currentReplicas := scale.Status.Replicas if scale.Status.Selector == nil { errMsg := "selector is required" a.eventRecorder.Event(hpa, api.EventTypeWarning, "SelectorRequired", errMsg) return 0, nil, time.Time{}, fmt.Errorf(errMsg) } selector, err := unversioned.LabelSelectorAsSelector(scale.Status.Selector) if err != nil { errMsg := fmt.Sprintf("couldn't convert selector string to a corresponding selector object: %v", err) a.eventRecorder.Event(hpa, api.EventTypeWarning, "InvalidSelector", errMsg) return 0, nil, time.Time{}, fmt.Errorf(errMsg) } currentUtilization, timestamp, err := a.metricsClient.GetCPUUtilization(hpa.Namespace, selector) // TODO: what to do on partial errors (like metrics obtained for 75% of pods). if err != nil { a.eventRecorder.Event(hpa, api.EventTypeWarning, "FailedGetMetrics", err.Error()) return 0, nil, time.Time{}, fmt.Errorf("failed to get CPU utilization: %v", err) } usageRatio := float64(*currentUtilization) / float64(targetUtilization) if math.Abs(1.0-usageRatio) > tolerance { return int(math.Ceil(usageRatio * float64(currentReplicas))), currentUtilization, timestamp, nil } else { return currentReplicas, currentUtilization, timestamp, nil } }
// handleOverlap relists all deployment in the same namespace for overlaps, and avoid syncing // the newer overlapping ones (only sync the oldest one). New/old is determined by when the // deployment's selector is last updated. func (dc *DeploymentController) handleOverlap(d *extensions.Deployment) error { selector, err := unversioned.LabelSelectorAsSelector(d.Spec.Selector) if err != nil { return fmt.Errorf("deployment %s/%s has invalid label selector: %v", d.Namespace, d.Name, err) } deployments, err := dc.dLister.Deployments(d.Namespace).List(labels.Everything()) if err != nil { return fmt.Errorf("error listing deployments in namespace %s: %v", d.Namespace, err) } overlapping := false for _, other := range deployments { if !selector.Empty() && selector.Matches(labels.Set(other.Spec.Template.Labels)) && d.UID != other.UID { deploymentCopy, err := util.DeploymentDeepCopy(other) if err != nil { return err } overlapping = true // Skip syncing this one if older overlapping one is found. if util.SelectorUpdatedBefore(deploymentCopy, d) { // We don't care if the overlapping annotation update failed or not (we don't make decision on it) dc.markDeploymentOverlap(d, deploymentCopy.Name) dc.clearDeploymentOverlap(deploymentCopy) return fmt.Errorf("found deployment %s/%s has overlapping selector with an older deployment %s/%s, skip syncing it", d.Namespace, d.Name, deploymentCopy.Namespace, deploymentCopy.Name) } dc.markDeploymentOverlap(deploymentCopy, d.Name) d, _ = dc.clearDeploymentOverlap(d) } } if !overlapping { // We don't care if the overlapping annotation update failed or not (we don't make decision on it) d, _ = dc.clearDeploymentOverlap(d) } return nil }
// GetPodReplicaSets returns a list of ReplicaSets managing a pod. Returns an error only if no matching ReplicaSets are found. func (s *StoreToReplicaSetLister) GetPodReplicaSets(pod *api.Pod) (rss []extensions.ReplicaSet, err error) { var selector labels.Selector var rs extensions.ReplicaSet if len(pod.Labels) == 0 { err = fmt.Errorf("no ReplicaSets found for pod %v because it has no labels", pod.Name) return } for _, m := range s.Store.List() { rs = *m.(*extensions.ReplicaSet) if rs.Namespace != pod.Namespace { continue } selector, err = unversioned.LabelSelectorAsSelector(rs.Spec.Selector) if err != nil { err = fmt.Errorf("failed to convert pod selector to selector: %v", err) return } // If a ReplicaSet with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { continue } rss = append(rss, rs) } if len(rss) == 0 { err = fmt.Errorf("could not find ReplicaSet for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) } return }
// GetDeploymentsForReplicaSet returns a list of deployments managing a replica set. Returns an error only if no matching deployments are found. func (s *StoreToDeploymentLister) GetDeploymentsForReplicaSet(rs *extensions.ReplicaSet) (deployments []*extensions.Deployment, err error) { if len(rs.Labels) == 0 { err = fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name) return } // TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label dList, err := s.Deployments(rs.Namespace).List(labels.Everything()) if err != nil { return } for _, d := range dList { selector, err := unversioned.LabelSelectorAsSelector(d.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } // If a deployment with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) { continue } deployments = append(deployments, d) } if len(deployments) == 0 { err = fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels) } return }
func (f *factory) LogsForObject(object, options runtime.Object) (*restclient.Request, error) { clientset, err := f.clients.ClientSetForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.Pod: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil case *api.ReplicationController: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector := labels.SelectorFromSet(t.Spec.Selector) sortBy := func(pods []*api.Pod) sort.Interface { return controller.ByLogging(pods) } pod, numPods, err := GetFirstPod(clientset.Core(), t.Namespace, selector, 20*time.Second, sortBy) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return clientset.Core().Pods(pod.Namespace).GetLogs(pod.Name, opts), nil case *extensions.ReplicaSet: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } sortBy := func(pods []*api.Pod) sort.Interface { return controller.ByLogging(pods) } pod, numPods, err := GetFirstPod(clientset.Core(), t.Namespace, selector, 20*time.Second, sortBy) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return clientset.Core().Pods(pod.Namespace).GetLogs(pod.Name, opts), nil default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot get the logs from %v", gvks[0]) } }
// addHashKeyToRSAndPods adds pod-template-hash information to the given rs, if it's not already there, with the following steps: // 1. Add hash label to the rs's pod template, and make sure the controller sees this update so that no orphaned pods will be created // 2. Add hash label to all pods this rs owns // 3. Add hash label to the rs's label and selector func addHashKeyToRSAndPods(deployment extensions.Deployment, c clientset.Interface, rs extensions.ReplicaSet, getPodList podListFunc) (updatedRS *extensions.ReplicaSet, err error) { updatedRS = &rs // If the rs already has the new hash label in its selector, it's done syncing if labelsutil.SelectorHasLabel(rs.Spec.Selector, extensions.DefaultDeploymentUniqueLabelKey) { return } namespace := deployment.Namespace meta := rs.Spec.Template.ObjectMeta meta.Labels = labelsutil.CloneAndRemoveLabel(meta.Labels, extensions.DefaultDeploymentUniqueLabelKey) hash := fmt.Sprintf("%d", podutil.GetPodTemplateSpecHash(api.PodTemplateSpec{ ObjectMeta: meta, Spec: rs.Spec.Template.Spec, })) // 1. Add hash template label to the rs. This ensures that any newly created pods will have the new label. if len(updatedRS.Spec.Template.Labels[extensions.DefaultDeploymentUniqueLabelKey]) == 0 { updatedRS, err = updateRSWithRetries(c.Extensions().ReplicaSets(namespace), updatedRS, func(updated *extensions.ReplicaSet) { updated.Spec.Template.Labels = labelsutil.AddLabel(updated.Spec.Template.Labels, extensions.DefaultDeploymentUniqueLabelKey, hash) }) if err != nil { return nil, fmt.Errorf("error updating rs %s pod template label with template hash: %v", updatedRS.Name, err) } // Make sure rs pod template is updated so that it won't create pods without the new label (orphaned pods). if updatedRS.Generation > updatedRS.Status.ObservedGeneration { if err = waitForReplicaSetUpdated(c, updatedRS.Generation, namespace, updatedRS.Name); err != nil { return nil, fmt.Errorf("error waiting for rs %s generation %d observed by controller: %v", updatedRS.Name, updatedRS.Generation, err) } } glog.V(4).Infof("Observed the update of rs %s's pod template with hash %s.", rs.Name, hash) } // 2. Update all pods managed by the rs to have the new hash label, so they will be correctly adopted. selector, err := unversioned.LabelSelectorAsSelector(updatedRS.Spec.Selector) if err != nil { return nil, err } options := api.ListOptions{LabelSelector: selector} podList, err := getPodList(namespace, options) if err != nil { return nil, err } if err = labelPodsWithHash(podList, c, namespace, hash); err != nil { return nil, err } glog.V(4).Infof("Labeled rs %s's pods with hash %s.", rs.Name, hash) // 3. Update rs label and selector to include the new hash label // Copy the old selector, so that we can scrub out any orphaned pods if updatedRS, err = updateRSWithRetries(c.Extensions().ReplicaSets(namespace), updatedRS, func(updated *extensions.ReplicaSet) { updated.Labels = labelsutil.AddLabel(updated.Labels, extensions.DefaultDeploymentUniqueLabelKey, hash) updated.Spec.Selector = labelsutil.AddLabelToSelector(updated.Spec.Selector, extensions.DefaultDeploymentUniqueLabelKey, hash) }); err != nil { return nil, fmt.Errorf("error updating rs %s label and selector with template hash: %v", updatedRS.Name, err) } glog.V(4).Infof("Updated rs %s's selector and label with hash %s.", rs.Name, hash) // TODO: look for orphaned pods and label them in the background somewhere else periodically return updatedRS, nil }