mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Add DaemonSet templateGeneration validation and tests, and fix a bunch of validation test errors
1. Validate that templateGeneration is increased when and only when template is changed 2. Validate that templateGeneration is never decreased 3. Added validation tests for templateGeneration 4. Fix a bunch of errors in validate tests, for example, all validation test error cases failed on lack of resource version, or on name changes, not on the real validation we wanted to test
This commit is contained in:
		@@ -98,10 +98,30 @@ func ValidateDaemonSet(ds *extensions.DaemonSet) field.ErrorList {
 | 
				
			|||||||
// ValidateDaemonSetUpdate tests if required fields in the DaemonSet are set.
 | 
					// ValidateDaemonSetUpdate tests if required fields in the DaemonSet are set.
 | 
				
			||||||
func ValidateDaemonSetUpdate(ds, oldDS *extensions.DaemonSet) field.ErrorList {
 | 
					func ValidateDaemonSetUpdate(ds, oldDS *extensions.DaemonSet) field.ErrorList {
 | 
				
			||||||
	allErrs := apivalidation.ValidateObjectMetaUpdate(&ds.ObjectMeta, &oldDS.ObjectMeta, field.NewPath("metadata"))
 | 
						allErrs := apivalidation.ValidateObjectMetaUpdate(&ds.ObjectMeta, &oldDS.ObjectMeta, field.NewPath("metadata"))
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateDaemonSetSpecUpdate(&ds.Spec, &oldDS.Spec, field.NewPath("spec"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateDaemonSetSpec(&ds.Spec, field.NewPath("spec"))...)
 | 
						allErrs = append(allErrs, ValidateDaemonSetSpec(&ds.Spec, field.NewPath("spec"))...)
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ValidateDaemonSetSpecUpdate(newSpec, oldSpec *extensions.DaemonSetSpec, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TemplateGeneration shouldn't be decremented
 | 
				
			||||||
 | 
						if newSpec.TemplateGeneration < oldSpec.TemplateGeneration {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath.Child("templateGeneration"), newSpec.TemplateGeneration, "must not be decremented"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TemplateGeneration should be increased when and only when template is changed
 | 
				
			||||||
 | 
						templateUpdated := !reflect.DeepEqual(newSpec.Template, oldSpec.Template)
 | 
				
			||||||
 | 
						if newSpec.TemplateGeneration == oldSpec.TemplateGeneration && templateUpdated {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath.Child("templateGeneration"), newSpec.TemplateGeneration, "must be incremented upon template update"))
 | 
				
			||||||
 | 
						} else if newSpec.TemplateGeneration > oldSpec.TemplateGeneration && !templateUpdated {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath.Child("templateGeneration"), newSpec.TemplateGeneration, "must not be incremented without template update"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// validateDaemonSetStatus validates a DaemonSetStatus
 | 
					// validateDaemonSetStatus validates a DaemonSetStatus
 | 
				
			||||||
func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.Path) field.ErrorList {
 | 
					func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -471,11 +471,12 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
 | 
				
			|||||||
	invalidPodTemplate := api.PodTemplate{
 | 
						invalidPodTemplate := api.PodTemplate{
 | 
				
			||||||
		Template: api.PodTemplateSpec{
 | 
							Template: api.PodTemplateSpec{
 | 
				
			||||||
			Spec: api.PodSpec{
 | 
								Spec: api.PodSpec{
 | 
				
			||||||
 | 
									// no containers specified
 | 
				
			||||||
				RestartPolicy: api.RestartPolicyAlways,
 | 
									RestartPolicy: api.RestartPolicyAlways,
 | 
				
			||||||
				DNSPolicy:     api.DNSClusterFirst,
 | 
									DNSPolicy:     api.DNSClusterFirst,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
				Labels: invalidSelector,
 | 
									Labels: validSelector,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -489,16 +490,18 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	type dsUpdateTest struct {
 | 
						type dsUpdateTest struct {
 | 
				
			||||||
		old    extensions.DaemonSet
 | 
							old            extensions.DaemonSet
 | 
				
			||||||
		update extensions.DaemonSet
 | 
							update         extensions.DaemonSet
 | 
				
			||||||
 | 
							expectedErrNum int
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	successCases := []dsUpdateTest{
 | 
						successCases := map[string]dsUpdateTest{
 | 
				
			||||||
		{
 | 
							"no change": {
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
					UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
						Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
@@ -507,20 +510,22 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
 | 
				
			|||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
					UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
						Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							"change template and selector": {
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 2,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
					UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
						Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
@@ -529,20 +534,22 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
 | 
				
			|||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector2},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector2},
 | 
				
			||||||
					Template: validPodTemplateAbc2.Template,
 | 
										TemplateGeneration: 3,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc2.Template,
 | 
				
			||||||
					UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
						Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							"change template": {
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 3,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
					UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
						Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
@@ -551,20 +558,80 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
 | 
				
			|||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateNodeSelector.Template,
 | 
										TemplateGeneration: 4,
 | 
				
			||||||
 | 
										Template:           validPodTemplateNodeSelector.Template,
 | 
				
			||||||
					UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
						Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							"change container image name": {
 | 
				
			||||||
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector2},
 | 
				
			||||||
 | 
										TemplateGeneration: 2,
 | 
				
			||||||
 | 
										Template:           validPodTemplateDef.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"change update strategy": {
 | 
				
			||||||
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										TemplateGeneration: 4,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										TemplateGeneration: 4,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.RollingUpdateDaemonSetStrategyType,
 | 
				
			||||||
 | 
											RollingUpdate: &extensions.RollingUpdateDaemonSet{
 | 
				
			||||||
 | 
												MaxUnavailable: intstr.FromInt(1),
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, successCase := range successCases {
 | 
						for testName, successCase := range successCases {
 | 
				
			||||||
 | 
							// ResourceVersion is required for updates.
 | 
				
			||||||
		successCase.old.ObjectMeta.ResourceVersion = "1"
 | 
							successCase.old.ObjectMeta.ResourceVersion = "1"
 | 
				
			||||||
		successCase.update.ObjectMeta.ResourceVersion = "1"
 | 
							successCase.update.ObjectMeta.ResourceVersion = "2"
 | 
				
			||||||
 | 
							// Check test setup
 | 
				
			||||||
 | 
							if successCase.expectedErrNum > 0 {
 | 
				
			||||||
 | 
								t.Errorf("%q has incorrect test setup with expectedErrNum %d, expected no error", testName, successCase.expectedErrNum)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(successCase.old.ObjectMeta.ResourceVersion) == 0 || len(successCase.update.ObjectMeta.ResourceVersion) == 0 {
 | 
				
			||||||
 | 
								t.Errorf("%q has incorrect test setup with no resource version set", testName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if errs := ValidateDaemonSetUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
 | 
							if errs := ValidateDaemonSetUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
 | 
				
			||||||
			t.Errorf("expected success: %v", errs)
 | 
								t.Errorf("%q expected no error, but got: %v", testName, errs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	errorCases := map[string]dsUpdateTest{
 | 
						errorCases := map[string]dsUpdateTest{
 | 
				
			||||||
@@ -572,102 +639,219 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
 | 
				
			|||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"invalid selector": {
 | 
							"invalid selector": {
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: invalidSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: invalidSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"invalid pod": {
 | 
							"invalid pod": {
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: invalidPodTemplate.Template,
 | 
										TemplateGeneration: 2,
 | 
				
			||||||
 | 
										Template:           invalidPodTemplate.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"change container image": {
 | 
							"invalid read-write volume": {
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateDef.Template,
 | 
										TemplateGeneration: 2,
 | 
				
			||||||
				},
 | 
										Template:           readWriteVolumePodTemplate.Template,
 | 
				
			||||||
			},
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
		},
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
		"read-write volume": {
 | 
										},
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
					 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
 | 
					 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
					 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
					 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			update: extensions.DaemonSet{
 | 
					 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
					 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
					 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
					 | 
				
			||||||
					Template: readWriteVolumePodTemplate.Template,
 | 
					 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"invalid update strategy": {
 | 
							"invalid update strategy": {
 | 
				
			||||||
			old: extensions.DaemonSet{
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: validSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			update: extensions.DaemonSet{
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
				Spec: extensions.DaemonSetSpec{
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
					Selector: &metav1.LabelSelector{MatchLabels: invalidSelector},
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
					Template: validPodTemplateAbc.Template,
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: "Random",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"negative templateGeneration": {
 | 
				
			||||||
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										TemplateGeneration: -1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										TemplateGeneration: -1,
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"decreased templateGeneration": {
 | 
				
			||||||
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										TemplateGeneration: 2,
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										TemplateGeneration: 1,
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"unchanged templateGeneration upon template update": {
 | 
				
			||||||
 | 
								old: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										TemplateGeneration: 2,
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector},
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								update: extensions.DaemonSet{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
 | 
				
			||||||
 | 
									Spec: extensions.DaemonSetSpec{
 | 
				
			||||||
 | 
										TemplateGeneration: 2,
 | 
				
			||||||
 | 
										Selector:           &metav1.LabelSelector{MatchLabels: validSelector2},
 | 
				
			||||||
 | 
										Template:           validPodTemplateAbc2.Template,
 | 
				
			||||||
 | 
										UpdateStrategy: extensions.DaemonSetUpdateStrategy{
 | 
				
			||||||
 | 
											Type: extensions.OnDeleteDaemonSetStrategyType,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedErrNum: 1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for testName, errorCase := range errorCases {
 | 
						for testName, errorCase := range errorCases {
 | 
				
			||||||
		if errs := ValidateDaemonSetUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
 | 
							// ResourceVersion is required for updates.
 | 
				
			||||||
			t.Errorf("expected failure: %s", testName)
 | 
							errorCase.old.ObjectMeta.ResourceVersion = "1"
 | 
				
			||||||
 | 
							errorCase.update.ObjectMeta.ResourceVersion = "2"
 | 
				
			||||||
 | 
							// Check test setup
 | 
				
			||||||
 | 
							if errorCase.expectedErrNum <= 0 {
 | 
				
			||||||
 | 
								t.Errorf("%q has incorrect test setup with expectedErrNum %d, expected at least one error", testName, errorCase.expectedErrNum)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(errorCase.old.ObjectMeta.ResourceVersion) == 0 || len(errorCase.update.ObjectMeta.ResourceVersion) == 0 {
 | 
				
			||||||
 | 
								t.Errorf("%q has incorrect test setup with no resource version set", testName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Run the tests
 | 
				
			||||||
 | 
							if errs := ValidateDaemonSetUpdate(&errorCase.update, &errorCase.old); len(errs) != errorCase.expectedErrNum {
 | 
				
			||||||
 | 
								t.Errorf("%q expected %d errors, but got %d error: %v", testName, errorCase.expectedErrNum, len(errs), errs)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								t.Logf("(PASS) %q got errors %v", testName, errs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user