Clean up brace whitespace in **/validation_test.go
This was making my eyes bleed as I read over code. I used the following in vim. I made them up on the fly, but they seemed to pass manual inspection. :g/},\n\s*{$/s//}, {/ :w :g/{$\n\s*{$/s//{{/ :w :g/^\(\s*\)},\n\1},$/s//}},/ :w :g/^\(\s*\)},$\n\1}$/s//}}/ :w
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -28,96 +28,84 @@ func TestValidateServerStorageVersion(t *testing.T) {
|
||||
cases := []struct {
|
||||
ssv apiserverinternal.ServerStorageVersion
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "-fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1alpha1", "v1"},
|
||||
},
|
||||
expectedErr: "apiServerID: Invalid value",
|
||||
}{{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "-fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1alpha1", "v1"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1beta1", "v1"},
|
||||
},
|
||||
expectedErr: "decodableVersions must include encodingVersion",
|
||||
expectedErr: "apiServerID: Invalid value",
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1beta1", "v1"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1alpha1", "v1", "-fea"},
|
||||
},
|
||||
expectedErr: "decodableVersions[2]: Invalid value",
|
||||
expectedErr: "decodableVersions must include encodingVersion",
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1alpha1", "v1", "-fea"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1alpha1", "v1"},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedErr: "decodableVersions[2]: Invalid value",
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1alpha1",
|
||||
DecodableVersions: []string{"v1alpha1", "v1"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "mygroup.com/v2",
|
||||
DecodableVersions: []string{"v1alpha1", "v1", "mygroup.com/v2"},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedErr: "",
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "mygroup.com/v2",
|
||||
DecodableVersions: []string{"v1alpha1", "v1", "mygroup.com/v2"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "mygroup.com/v2",
|
||||
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
|
||||
},
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "/v3": group part: must be non-empty`,
|
||||
expectedErr: "",
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "mygroup.com/v2",
|
||||
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "mygroup.com/v2",
|
||||
DecodableVersions: []string{"mygroup.com/v2", "mygroup.com/"},
|
||||
},
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/": version part: must be non-empty`,
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "/v3": group part: must be non-empty`,
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "mygroup.com/v2",
|
||||
DecodableVersions: []string{"mygroup.com/v2", "mygroup.com/"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "/v3",
|
||||
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
|
||||
},
|
||||
expectedErr: `[].encodingVersion: Invalid value: "/v3": group part: must be non-empty`,
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/": version part: must be non-empty`,
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "/v3",
|
||||
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1",
|
||||
DecodableVersions: []string{"v1", "mygroup_com/v2"},
|
||||
},
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup_com/v2": group part: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')`,
|
||||
expectedErr: `[].encodingVersion: Invalid value: "/v3": group part: must be non-empty`,
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1",
|
||||
DecodableVersions: []string{"v1", "mygroup_com/v2"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1",
|
||||
DecodableVersions: []string{"v1", "mygroup.com/v2_"},
|
||||
},
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2_": version part: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?')`,
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup_com/v2": group part: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')`,
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1",
|
||||
DecodableVersions: []string{"v1", "mygroup.com/v2_"},
|
||||
},
|
||||
{
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1",
|
||||
DecodableVersions: []string{"v1", "mygroup.com/v2/myresource"},
|
||||
},
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2/myresource": an apiVersion is a DNS-1035 label, which must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?') with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyVersion')`,
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2_": version part: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?')`,
|
||||
}, {
|
||||
ssv: apiserverinternal.ServerStorageVersion{
|
||||
APIServerID: "fea",
|
||||
EncodingVersion: "v1",
|
||||
DecodableVersions: []string{"v1", "mygroup.com/v2/myresource"},
|
||||
},
|
||||
}
|
||||
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2/myresource": an apiVersion is a DNS-1035 label, which must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?') with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyVersion')`,
|
||||
}}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := validateServerStorageVersion(tc.ssv, field.NewPath("")).ToAggregate()
|
||||
@@ -142,91 +130,70 @@ func TestValidateCommonVersion(t *testing.T) {
|
||||
cases := []struct {
|
||||
status apiserverinternal.StorageVersionStatus
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
|
||||
}{{
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
{
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{
|
||||
{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
{
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1",
|
||||
},
|
||||
},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
|
||||
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
|
||||
}, {
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}, {
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1",
|
||||
}},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
{
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{
|
||||
{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
{
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
},
|
||||
CommonEncodingVersion: nil,
|
||||
},
|
||||
expectedErr: "Invalid value: \"null\": the common encoding version is v1alpha1",
|
||||
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
|
||||
}, {
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}, {
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}},
|
||||
CommonEncodingVersion: nil,
|
||||
},
|
||||
{
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{
|
||||
{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
{
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
},
|
||||
CommonEncodingVersion: func() *string { a := "v1"; return &a }(),
|
||||
},
|
||||
expectedErr: "Invalid value: \"v1\": the actual common encoding version is v1alpha1",
|
||||
expectedErr: "Invalid value: \"null\": the common encoding version is v1alpha1",
|
||||
}, {
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}, {
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}},
|
||||
CommonEncodingVersion: func() *string { a := "v1"; return &a }(),
|
||||
},
|
||||
{
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{
|
||||
{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
{
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedErr: "Invalid value: \"v1\": the actual common encoding version is v1alpha1",
|
||||
}, {
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}, {
|
||||
APIServerID: "2",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
{
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{
|
||||
{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
},
|
||||
},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedErr: "",
|
||||
}, {
|
||||
status: apiserverinternal.StorageVersionStatus{
|
||||
StorageVersions: []apiserverinternal.ServerStorageVersion{{
|
||||
APIServerID: "1",
|
||||
EncodingVersion: "v1alpha1",
|
||||
}},
|
||||
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
|
||||
},
|
||||
}
|
||||
expectedErr: "",
|
||||
}}
|
||||
for _, tc := range cases {
|
||||
err := validateCommonVersion(tc.status, field.NewPath(""))
|
||||
if err == nil && len(tc.expectedErr) == 0 {
|
||||
@@ -250,78 +217,58 @@ func TestValidateStorageVersionCondition(t *testing.T) {
|
||||
cases := []struct {
|
||||
conditions []apiserverinternal.StorageVersionCondition
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
conditions: []apiserverinternal.StorageVersionCondition{
|
||||
{
|
||||
Type: "-fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
},
|
||||
},
|
||||
expectedErr: "type: Invalid value",
|
||||
},
|
||||
{
|
||||
conditions: []apiserverinternal.StorageVersionCondition{
|
||||
{
|
||||
Type: "fea",
|
||||
Status: "-True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
},
|
||||
},
|
||||
expectedErr: "status: Invalid value",
|
||||
},
|
||||
{
|
||||
conditions: []apiserverinternal.StorageVersionCondition{
|
||||
{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Message: "unknown",
|
||||
},
|
||||
},
|
||||
expectedErr: "Required value: reason cannot be empty",
|
||||
},
|
||||
{
|
||||
conditions: []apiserverinternal.StorageVersionCondition{
|
||||
{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
},
|
||||
},
|
||||
expectedErr: "Required value: message cannot be empty",
|
||||
},
|
||||
{
|
||||
conditions: []apiserverinternal.StorageVersionCondition{
|
||||
{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
},
|
||||
{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
},
|
||||
},
|
||||
expectedErr: `"fea": the type of the condition is not unique, it also appears in conditions[0]`,
|
||||
},
|
||||
{
|
||||
conditions: []apiserverinternal.StorageVersionCondition{
|
||||
{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
},
|
||||
},
|
||||
expectedErr: "",
|
||||
},
|
||||
}
|
||||
}{{
|
||||
conditions: []apiserverinternal.StorageVersionCondition{{
|
||||
Type: "-fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
}},
|
||||
expectedErr: "type: Invalid value",
|
||||
}, {
|
||||
conditions: []apiserverinternal.StorageVersionCondition{{
|
||||
Type: "fea",
|
||||
Status: "-True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
}},
|
||||
expectedErr: "status: Invalid value",
|
||||
}, {
|
||||
conditions: []apiserverinternal.StorageVersionCondition{{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Message: "unknown",
|
||||
}},
|
||||
expectedErr: "Required value: reason cannot be empty",
|
||||
}, {
|
||||
conditions: []apiserverinternal.StorageVersionCondition{{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
}},
|
||||
expectedErr: "Required value: message cannot be empty",
|
||||
}, {
|
||||
conditions: []apiserverinternal.StorageVersionCondition{{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
}, {
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
}},
|
||||
expectedErr: `"fea": the type of the condition is not unique, it also appears in conditions[0]`,
|
||||
}, {
|
||||
conditions: []apiserverinternal.StorageVersionCondition{{
|
||||
Type: "fea",
|
||||
Status: "True",
|
||||
Reason: "unknown",
|
||||
Message: "unknown",
|
||||
}},
|
||||
expectedErr: "",
|
||||
}}
|
||||
for _, tc := range cases {
|
||||
err := validateStorageVersionCondition(tc.conditions, field.NewPath("")).ToAggregate()
|
||||
if err == nil && len(tc.expectedErr) == 0 {
|
||||
@@ -345,40 +292,31 @@ func TestValidateStorageVersionName(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "",
|
||||
expectedErr: `name must be in the form of <group>.<resource>`,
|
||||
},
|
||||
{
|
||||
name: "pods",
|
||||
expectedErr: `name must be in the form of <group>.<resource>`,
|
||||
},
|
||||
{
|
||||
name: "core.pods",
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
name: "authentication.k8s.io.tokenreviews",
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
name: strings.Repeat("x", 253) + ".tokenreviews",
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
name: strings.Repeat("x", 254) + ".tokenreviews",
|
||||
expectedErr: `the group segment must be no more than 253 characters`,
|
||||
},
|
||||
{
|
||||
name: "authentication.k8s.io." + strings.Repeat("x", 63),
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
name: "authentication.k8s.io." + strings.Repeat("x", 64),
|
||||
expectedErr: `the resource segment must be no more than 63 characters`,
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "",
|
||||
expectedErr: `name must be in the form of <group>.<resource>`,
|
||||
}, {
|
||||
name: "pods",
|
||||
expectedErr: `name must be in the form of <group>.<resource>`,
|
||||
}, {
|
||||
name: "core.pods",
|
||||
expectedErr: "",
|
||||
}, {
|
||||
name: "authentication.k8s.io.tokenreviews",
|
||||
expectedErr: "",
|
||||
}, {
|
||||
name: strings.Repeat("x", 253) + ".tokenreviews",
|
||||
expectedErr: "",
|
||||
}, {
|
||||
name: strings.Repeat("x", 254) + ".tokenreviews",
|
||||
expectedErr: `the group segment must be no more than 253 characters`,
|
||||
}, {
|
||||
name: "authentication.k8s.io." + strings.Repeat("x", 63),
|
||||
expectedErr: "",
|
||||
}, {
|
||||
name: "authentication.k8s.io." + strings.Repeat("x", 64),
|
||||
expectedErr: `the resource segment must be no more than 63 characters`,
|
||||
}}
|
||||
for _, tc := range cases {
|
||||
errs := ValidateStorageVersionName(tc.name, false)
|
||||
if errs == nil && len(tc.expectedErr) == 0 {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -40,29 +40,25 @@ func TestValidateSARSpec(t *testing.T) {
|
||||
name string
|
||||
obj authorizationapi.SubjectAccessReviewSpec
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
name: "neither request",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{User: "me"},
|
||||
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
|
||||
}{{
|
||||
name: "neither request",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{User: "me"},
|
||||
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
|
||||
}, {
|
||||
name: "both requests",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
|
||||
User: "me",
|
||||
},
|
||||
{
|
||||
name: "both requests",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
|
||||
User: "me",
|
||||
},
|
||||
msg: "cannot be specified in combination with resourceAttributes",
|
||||
msg: "cannot be specified in combination with resourceAttributes",
|
||||
}, {
|
||||
name: "no subject",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
},
|
||||
{
|
||||
name: "no subject",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
},
|
||||
msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
|
||||
},
|
||||
}
|
||||
msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
|
||||
}}
|
||||
|
||||
for _, c := range errorCases {
|
||||
errs := ValidateSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
|
||||
@@ -102,21 +98,18 @@ func TestValidateSelfSAR(t *testing.T) {
|
||||
name string
|
||||
obj authorizationapi.SelfSubjectAccessReviewSpec
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
name: "neither request",
|
||||
obj: authorizationapi.SelfSubjectAccessReviewSpec{},
|
||||
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
|
||||
}{{
|
||||
name: "neither request",
|
||||
obj: authorizationapi.SelfSubjectAccessReviewSpec{},
|
||||
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
|
||||
}, {
|
||||
name: "both requests",
|
||||
obj: authorizationapi.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
|
||||
},
|
||||
{
|
||||
name: "both requests",
|
||||
obj: authorizationapi.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
|
||||
},
|
||||
msg: "cannot be specified in combination with resourceAttributes",
|
||||
},
|
||||
}
|
||||
msg: "cannot be specified in combination with resourceAttributes",
|
||||
}}
|
||||
|
||||
for _, c := range errorCases {
|
||||
errs := ValidateSelfSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
|
||||
@@ -136,14 +129,12 @@ func TestValidateSelfSAR(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidateLocalSAR(t *testing.T) {
|
||||
successCases := []authorizationapi.LocalSubjectAccessReview{
|
||||
{
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
successCases := []authorizationapi.LocalSubjectAccessReview{{
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
}
|
||||
}}
|
||||
for _, successCase := range successCases {
|
||||
if errs := ValidateLocalSubjectAccessReview(&successCase); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
@@ -154,41 +145,37 @@ func TestValidateLocalSAR(t *testing.T) {
|
||||
name string
|
||||
obj *authorizationapi.LocalSubjectAccessReview
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
name: "name",
|
||||
obj: &authorizationapi.LocalSubjectAccessReview{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "a"},
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
}{{
|
||||
name: "name",
|
||||
obj: &authorizationapi.LocalSubjectAccessReview{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "a"},
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
msg: "must be empty except for namespace",
|
||||
},
|
||||
{
|
||||
name: "namespace conflict",
|
||||
obj: &authorizationapi.LocalSubjectAccessReview{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
msg: "must be empty except for namespace",
|
||||
}, {
|
||||
name: "namespace conflict",
|
||||
obj: &authorizationapi.LocalSubjectAccessReview{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
msg: "must match metadata.namespace",
|
||||
},
|
||||
{
|
||||
name: "nonresource",
|
||||
obj: &authorizationapi.LocalSubjectAccessReview{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
msg: "must match metadata.namespace",
|
||||
}, {
|
||||
name: "nonresource",
|
||||
obj: &authorizationapi.LocalSubjectAccessReview{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
|
||||
User: "user",
|
||||
},
|
||||
msg: "disallowed on this kind of request",
|
||||
},
|
||||
}
|
||||
msg: "disallowed on this kind of request",
|
||||
}}
|
||||
|
||||
for _, c := range errorCases {
|
||||
errs := ValidateLocalSubjectAccessReview(c.obj)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -112,49 +112,39 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
}, {
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.PodConditionType("CustomConditionType"),
|
||||
Status: api.ConditionFalse,
|
||||
}},
|
||||
}, {
|
||||
Action: batch.PodFailurePolicyActionCount,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.PodConditionType("CustomConditionType"),
|
||||
Status: api.ConditionFalse,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("def"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{4},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionCount,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
}, {
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpNotIn,
|
||||
Values: []int32{5, 6, 7},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("def"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{4},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpNotIn,
|
||||
Values: []int32{5, 6, 7},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -314,11 +304,9 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -331,15 +319,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{11, 11},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{11, 11},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -352,21 +338,19 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: func() (values []int32) {
|
||||
tooManyValues := make([]int32, maxPodFailurePolicyOnExitCodesValues+1)
|
||||
for i := range tooManyValues {
|
||||
tooManyValues[i] = int32(i)
|
||||
}
|
||||
return tooManyValues
|
||||
}(),
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: func() (values []int32) {
|
||||
tooManyValues := make([]int32, maxPodFailurePolicyOnExitCodesValues+1)
|
||||
for i := range tooManyValues {
|
||||
tooManyValues[i] = int32(i)
|
||||
}
|
||||
return tooManyValues
|
||||
}(),
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -404,21 +388,19 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: func() []batch.PodFailurePolicyOnPodConditionsPattern {
|
||||
tooManyPatterns := make([]batch.PodFailurePolicyOnPodConditionsPattern, maxPodFailurePolicyOnPodConditionsPatterns+1)
|
||||
for i := range tooManyPatterns {
|
||||
tooManyPatterns[i] = batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
Type: api.PodConditionType(fmt.Sprintf("CustomType_%d", i)),
|
||||
Status: api.ConditionTrue,
|
||||
}
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: func() []batch.PodFailurePolicyOnPodConditionsPattern {
|
||||
tooManyPatterns := make([]batch.PodFailurePolicyOnPodConditionsPattern, maxPodFailurePolicyOnPodConditionsPatterns+1)
|
||||
for i := range tooManyPatterns {
|
||||
tooManyPatterns[i] = batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
Type: api.PodConditionType(fmt.Sprintf("CustomType_%d", i)),
|
||||
Status: api.ConditionTrue,
|
||||
}
|
||||
return tooManyPatterns
|
||||
}(),
|
||||
},
|
||||
},
|
||||
}
|
||||
return tooManyPatterns
|
||||
}(),
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -431,15 +413,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{12, 13, 13, 13},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{12, 13, 13, 13},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -452,15 +432,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{19, 11},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{19, 11},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -473,15 +451,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -494,15 +470,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: "",
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: "",
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -515,15 +489,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: "",
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: "",
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -536,22 +508,18 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -564,15 +532,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 0, 2},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 0, 2},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -585,24 +551,21 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("xyz"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{5, 6, 7},
|
||||
},
|
||||
}, {
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("xyz"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{5, 6, 7},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -615,16 +578,14 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: "UnknownAction",
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: "UnknownAction",
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -637,15 +598,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: "UnknownOperator",
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: "UnknownOperator",
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -658,16 +617,12 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -680,17 +635,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: "UnknownStatus",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: "UnknownStatus",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -703,16 +654,12 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -725,17 +672,13 @@ func TestValidateJob(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.PodConditionType("Invalid Condition Type"),
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.PodConditionType("Invalid Condition Type"),
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1116,17 +1059,13 @@ func TestValidateJobUpdate(t *testing.T) {
|
||||
validNodeAffinity := &api.Affinity{
|
||||
NodeAffinity: &api.NodeAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||
{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "foo",
|
||||
Operator: api.NodeSelectorOpIn,
|
||||
Values: []string{"bar", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: api.NodeSelectorOpIn,
|
||||
Values: []string{"bar", "value2"},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1134,17 +1073,13 @@ func TestValidateJobUpdate(t *testing.T) {
|
||||
validPodTemplateWithAffinity.Spec.Affinity = &api.Affinity{
|
||||
NodeAffinity: &api.NodeAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||
{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "foo",
|
||||
Operator: api.NodeSelectorOpIn,
|
||||
Values: []string{"bar", "value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: api.NodeSelectorOpIn,
|
||||
Values: []string{"bar", "value"},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1242,17 +1177,13 @@ func TestValidateJobUpdate(t *testing.T) {
|
||||
},
|
||||
update: func(job *batch.Job) {
|
||||
job.Spec.PodFailurePolicy = &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
}},
|
||||
}
|
||||
},
|
||||
err: &field.Error{
|
||||
@@ -1267,29 +1198,23 @@ func TestValidateJobUpdate(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
update: func(job *batch.Job) {
|
||||
job.Spec.PodFailurePolicy.Rules = append(job.Spec.PodFailurePolicy.Rules, batch.PodFailurePolicyRule{
|
||||
Action: batch.PodFailurePolicyActionCount,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
})
|
||||
},
|
||||
err: &field.Error{
|
||||
@@ -1304,17 +1229,13 @@ func TestValidateJobUpdate(t *testing.T) {
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []batch.PodFailurePolicyRule{{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
|
||||
Type: api.DisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -31,56 +31,51 @@ func TestValidateResourceRequirements(t *testing.T) {
|
||||
successCase := []struct {
|
||||
name string
|
||||
requirements v1.ResourceRequirements
|
||||
}{
|
||||
{
|
||||
name: "Resources with Requests equal to Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
},
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
},
|
||||
}{{
|
||||
name: "Resources with Requests equal to Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
},
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Resources with only Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
|
||||
},
|
||||
}, {
|
||||
name: "Resources with only Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Resources with only Requests",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
|
||||
},
|
||||
}, {
|
||||
name: "Resources with only Requests",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Resources with Requests Less Than Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
|
||||
},
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
|
||||
},
|
||||
}, {
|
||||
name: "Resources with Requests Less Than Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
|
||||
},
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}}
|
||||
for _, tc := range successCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources")); len(errs) != 0 {
|
||||
@@ -94,41 +89,37 @@ func TestValidateResourceRequirements(t *testing.T) {
|
||||
requirements v1.ResourceRequirements
|
||||
skipLimitValueCheck bool
|
||||
skipRequestValueCheck bool
|
||||
}{
|
||||
{
|
||||
name: "Resources with Requests Larger Than Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
||||
},
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("9m"),
|
||||
},
|
||||
}{{
|
||||
name: "Resources with Requests Larger Than Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
||||
},
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
|
||||
v1.ResourceName("my.org/resource"): resource.MustParse("9m"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Invalid Resources with Requests",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("my.org"): resource.MustParse("10m"),
|
||||
},
|
||||
}, {
|
||||
name: "Invalid Resources with Requests",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("my.org"): resource.MustParse("10m"),
|
||||
},
|
||||
skipRequestValueCheck: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid Resources with Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName("my.org"): resource.MustParse("9m"),
|
||||
},
|
||||
skipRequestValueCheck: true,
|
||||
}, {
|
||||
name: "Invalid Resources with Limits",
|
||||
requirements: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName("my.org"): resource.MustParse("9m"),
|
||||
},
|
||||
skipLimitValueCheck: true,
|
||||
},
|
||||
}
|
||||
skipLimitValueCheck: true,
|
||||
}}
|
||||
for _, tc := range errorCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources"))
|
||||
@@ -168,28 +159,22 @@ func TestValidateContainerResourceName(t *testing.T) {
|
||||
successCase := []struct {
|
||||
name string
|
||||
ResourceName string
|
||||
}{
|
||||
{
|
||||
name: "CPU resource",
|
||||
ResourceName: "cpu",
|
||||
},
|
||||
{
|
||||
name: "Memory resource",
|
||||
ResourceName: "memory",
|
||||
},
|
||||
{
|
||||
name: "Hugepages resource",
|
||||
ResourceName: "hugepages-2Mi",
|
||||
},
|
||||
{
|
||||
name: "Namespaced resource",
|
||||
ResourceName: "kubernetes.io/resource-foo",
|
||||
},
|
||||
{
|
||||
name: "Extended Resource",
|
||||
ResourceName: "my.org/resource-bar",
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "CPU resource",
|
||||
ResourceName: "cpu",
|
||||
}, {
|
||||
name: "Memory resource",
|
||||
ResourceName: "memory",
|
||||
}, {
|
||||
name: "Hugepages resource",
|
||||
ResourceName: "hugepages-2Mi",
|
||||
}, {
|
||||
name: "Namespaced resource",
|
||||
ResourceName: "kubernetes.io/resource-foo",
|
||||
}, {
|
||||
name: "Extended Resource",
|
||||
ResourceName: "my.org/resource-bar",
|
||||
}}
|
||||
for _, tc := range successCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) != 0 {
|
||||
@@ -201,20 +186,16 @@ func TestValidateContainerResourceName(t *testing.T) {
|
||||
errorCase := []struct {
|
||||
name string
|
||||
ResourceName string
|
||||
}{
|
||||
{
|
||||
name: "Invalid standard resource",
|
||||
ResourceName: "cpu-core",
|
||||
},
|
||||
{
|
||||
name: "Invalid namespaced resource",
|
||||
ResourceName: "kubernetes.io/",
|
||||
},
|
||||
{
|
||||
name: "Invalid extended resource",
|
||||
ResourceName: "my.org-foo-resource",
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "Invalid standard resource",
|
||||
ResourceName: "cpu-core",
|
||||
}, {
|
||||
name: "Invalid namespaced resource",
|
||||
ResourceName: "kubernetes.io/",
|
||||
}, {
|
||||
name: "Invalid extended resource",
|
||||
ResourceName: "my.org-foo-resource",
|
||||
}}
|
||||
for _, tc := range errorCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) == 0 {
|
||||
@@ -239,45 +220,38 @@ func TestValidatePodLogOptions(t *testing.T) {
|
||||
successCase := []struct {
|
||||
name string
|
||||
podLogOptions v1.PodLogOptions
|
||||
}{
|
||||
{
|
||||
name: "Empty PodLogOptions",
|
||||
podLogOptions: v1.PodLogOptions{},
|
||||
}{{
|
||||
name: "Empty PodLogOptions",
|
||||
podLogOptions: v1.PodLogOptions{},
|
||||
}, {
|
||||
name: "PodLogOptions with TailLines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &positiveLine,
|
||||
},
|
||||
{
|
||||
name: "PodLogOptions with TailLines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &positiveLine,
|
||||
},
|
||||
}, {
|
||||
name: "PodLogOptions with LimitBytes",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
},
|
||||
{
|
||||
name: "PodLogOptions with LimitBytes",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
},
|
||||
}, {
|
||||
name: "PodLogOptions with only sinceSeconds",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
{
|
||||
name: "PodLogOptions with only sinceSeconds",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
}, {
|
||||
name: "PodLogOptions with LimitBytes with TailLines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
TailLines: &positiveLine,
|
||||
},
|
||||
{
|
||||
name: "PodLogOptions with LimitBytes with TailLines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
TailLines: &positiveLine,
|
||||
},
|
||||
}, {
|
||||
name: "PodLogOptions with LimitBytes with TailLines with SinceSeconds",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
TailLines: &positiveLine,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
{
|
||||
name: "PodLogOptions with LimitBytes with TailLines with SinceSeconds",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
TailLines: &positiveLine,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}}
|
||||
for _, tc := range successCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) != 0 {
|
||||
@@ -289,40 +263,36 @@ func TestValidatePodLogOptions(t *testing.T) {
|
||||
errorCase := []struct {
|
||||
name string
|
||||
podLogOptions v1.PodLogOptions
|
||||
}{
|
||||
{
|
||||
name: "Invalid podLogOptions with Negative TailLines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &negativeLine,
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
}{{
|
||||
name: "Invalid podLogOptions with Negative TailLines",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &negativeLine,
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
{
|
||||
name: "Invalid podLogOptions with zero or negative LimitBytes",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &positiveLine,
|
||||
LimitBytes: &limitBytesLessThan1,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
}, {
|
||||
name: "Invalid podLogOptions with zero or negative LimitBytes",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &positiveLine,
|
||||
LimitBytes: &limitBytesLessThan1,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
},
|
||||
{
|
||||
name: "Invalid podLogOptions with zero or negative SinceSeconds",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &negativeLine,
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
SinceSeconds: &sinceSecondsLessThan1,
|
||||
},
|
||||
}, {
|
||||
name: "Invalid podLogOptions with both SinceSeconds and SinceTime set",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &negativeLine,
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
SinceTime: ×tamp,
|
||||
},
|
||||
}, {
|
||||
name: "Invalid podLogOptions with zero or negative SinceSeconds",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &negativeLine,
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
SinceSeconds: &sinceSecondsLessThan1,
|
||||
},
|
||||
}
|
||||
}, {
|
||||
name: "Invalid podLogOptions with both SinceSeconds and SinceTime set",
|
||||
podLogOptions: v1.PodLogOptions{
|
||||
TailLines: &negativeLine,
|
||||
LimitBytes: &limitBytesGreaterThan1,
|
||||
SinceSeconds: &sinceSecondsGreaterThan1,
|
||||
SinceTime: ×tamp,
|
||||
},
|
||||
}}
|
||||
for _, tc := range errorCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) == 0 {
|
||||
@@ -338,54 +308,37 @@ func TestAccumulateUniqueHostPorts(t *testing.T) {
|
||||
containers []v1.Container
|
||||
accumulator *sets.String
|
||||
fldPath *field.Path
|
||||
}{
|
||||
{
|
||||
name: "HostPort is not allocated while containers use the same port with different protocol",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
accumulator: &sets.String{},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
},
|
||||
{
|
||||
name: "HostPort is not allocated while containers use different ports",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8081,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
accumulator: &sets.String{},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "HostPort is not allocated while containers use the same port with different protocol",
|
||||
containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}, {
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
}},
|
||||
}},
|
||||
accumulator: &sets.String{},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
}, {
|
||||
name: "HostPort is not allocated while containers use different ports",
|
||||
containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}, {
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8081,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}},
|
||||
accumulator: &sets.String{},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
}}
|
||||
for _, tc := range successCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if errs := AccumulateUniqueHostPorts(tc.containers, tc.accumulator, tc.fldPath); len(errs) != 0 {
|
||||
@@ -398,54 +351,37 @@ func TestAccumulateUniqueHostPorts(t *testing.T) {
|
||||
containers []v1.Container
|
||||
accumulator *sets.String
|
||||
fldPath *field.Path
|
||||
}{
|
||||
{
|
||||
name: "HostPort is already allocated while containers use the same port with UDP",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
accumulator: &sets.String{},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
},
|
||||
{
|
||||
name: "HostPort is already allocated",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
HostPort: 8081,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
accumulator: &sets.String{"8080/UDP": sets.Empty{}},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "HostPort is already allocated while containers use the same port with UDP",
|
||||
containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}, {
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}},
|
||||
accumulator: &sets.String{},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
}, {
|
||||
name: "HostPort is already allocated",
|
||||
containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8080,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}, {
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 8081,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}},
|
||||
accumulator: &sets.String{"8080/UDP": sets.Empty{}},
|
||||
fldPath: field.NewPath("spec", "containers"),
|
||||
}}
|
||||
for _, tc := range errorCase {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if errs := AccumulateUniqueHostPorts(tc.containers, tc.accumulator, tc.fldPath); len(errs) == 0 {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -477,22 +477,18 @@ func TestValidateIngress(t *testing.T) {
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
DefaultBackend: &defaultBackend,
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: networking.IngressLoadBalancerStatus{
|
||||
@@ -595,20 +591,18 @@ func TestValidateIngress(t *testing.T) {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: networking.IngressBackend{
|
||||
Service: serviceBackend,
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.String("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: networking.IngressBackend{
|
||||
Service: serviceBackend,
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.String("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -620,20 +614,18 @@ func TestValidateIngress(t *testing.T) {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: networking.IngressBackend{
|
||||
Service: serviceBackend,
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.String("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: networking.IngressBackend{
|
||||
Service: serviceBackend,
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.String("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -790,15 +782,13 @@ func TestValidateIngressRuleValue(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
irv := &networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: testCase.path,
|
||||
PathType: &testCase.pathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Service: &serviceBackend,
|
||||
},
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: testCase.path,
|
||||
PathType: &testCase.pathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Service: &serviceBackend,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
errs := validateIngressRuleValue(irv, field.NewPath("testing"), IngressValidationOptions{})
|
||||
@@ -1638,22 +1628,18 @@ func TestValidateIngressTLS(t *testing.T) {
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
DefaultBackend: &defaultBackend,
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: networking.IngressLoadBalancerStatus{
|
||||
@@ -1670,11 +1656,9 @@ func TestValidateIngressTLS(t *testing.T) {
|
||||
wildcardHost := "foo.*.bar.com"
|
||||
badWildcardTLS := newValid()
|
||||
badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com"
|
||||
badWildcardTLS.Spec.TLS = []networking.IngressTLS{
|
||||
{
|
||||
Hosts: []string{wildcardHost},
|
||||
},
|
||||
}
|
||||
badWildcardTLS.Spec.TLS = []networking.IngressTLS{{
|
||||
Hosts: []string{wildcardHost},
|
||||
}}
|
||||
badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts[0]: Invalid value: '%v'", wildcardHost)
|
||||
errorCases[badWildcardTLSErr] = badWildcardTLS
|
||||
|
||||
@@ -1696,11 +1680,9 @@ func TestValidateIngressTLS(t *testing.T) {
|
||||
wildHost := "*.bar.com"
|
||||
goodWildcardTLS := newValid()
|
||||
goodWildcardTLS.Spec.Rules[0].Host = "*.bar.com"
|
||||
goodWildcardTLS.Spec.TLS = []networking.IngressTLS{
|
||||
{
|
||||
Hosts: []string{wildHost},
|
||||
},
|
||||
}
|
||||
goodWildcardTLS.Spec.TLS = []networking.IngressTLS{{
|
||||
Hosts: []string{wildHost},
|
||||
}}
|
||||
validCases[fmt.Sprintf("spec.tls[0].hosts: Valid value: '%v'", wildHost)] = goodWildcardTLS
|
||||
for k, v := range validCases {
|
||||
errs := validateIngress(&v, IngressValidationOptions{})
|
||||
@@ -1731,21 +1713,17 @@ func TestValidateEmptyIngressTLS(t *testing.T) {
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1757,11 +1735,9 @@ func TestValidateEmptyIngressTLS(t *testing.T) {
|
||||
}
|
||||
validCases[fmt.Sprintf("spec.tls[0]: Valid value: %v", goodEmptyTLS.Spec.TLS[0])] = goodEmptyTLS
|
||||
goodEmptyHosts := newValid()
|
||||
goodEmptyHosts.Spec.TLS = []networking.IngressTLS{
|
||||
{
|
||||
Hosts: []string{},
|
||||
},
|
||||
}
|
||||
goodEmptyHosts.Spec.TLS = []networking.IngressTLS{{
|
||||
Hosts: []string{},
|
||||
}}
|
||||
validCases[fmt.Sprintf("spec.tls[0]: Valid value: %v", goodEmptyHosts.Spec.TLS[0])] = goodEmptyHosts
|
||||
for k, v := range validCases {
|
||||
errs := validateIngress(&v, IngressValidationOptions{})
|
||||
@@ -1791,21 +1767,17 @@ func TestValidateIngressStatusUpdate(t *testing.T) {
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
DefaultBackend: &defaultBackend,
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
Rules: []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: networking.IngressLoadBalancerStatus{
|
||||
@@ -1867,17 +1839,13 @@ func TestValidateIngressStatusUpdate(t *testing.T) {
|
||||
|
||||
func makeNodeSelector(key string, op api.NodeSelectorOperator, values []string) *api.NodeSelector {
|
||||
return &api.NodeSelector{
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||
{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{
|
||||
{
|
||||
Key: key,
|
||||
Operator: op,
|
||||
Values: values,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelectorTerms: []api.NodeSelectorTerm{{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{{
|
||||
Key: key,
|
||||
Operator: op,
|
||||
Values: values,
|
||||
}},
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1901,59 +1869,49 @@ func TestValidateClusterCIDR(t *testing.T) {
|
||||
name string
|
||||
cc *networking.ClusterCIDR
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid SingleStack IPv4 ClusterCIDR",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits = maxPerNodeHostBits",
|
||||
cc: makeClusterCIDR(16, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits > minPerNodeHostBits",
|
||||
cc: makeClusterCIDR(4, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid SingleStack IPv6 ClusterCIDR",
|
||||
cc: makeClusterCIDR(8, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits = maxPerNodeHostBit",
|
||||
cc: makeClusterCIDR(64, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits > minPerNodeHostBit",
|
||||
cc: makeClusterCIDR(4, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid SingleStack IPv6 ClusterCIDR perNodeHostBits=100",
|
||||
cc: makeClusterCIDR(100, "", "fd00:1:1::/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid DualStack ClusterCIDR",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid DualStack ClusterCIDR, no NodeSelector",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", nil),
|
||||
expectErr: false,
|
||||
},
|
||||
}{{
|
||||
name: "valid SingleStack IPv4 ClusterCIDR",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits = maxPerNodeHostBits",
|
||||
cc: makeClusterCIDR(16, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits > minPerNodeHostBits",
|
||||
cc: makeClusterCIDR(4, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid SingleStack IPv6 ClusterCIDR",
|
||||
cc: makeClusterCIDR(8, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits = maxPerNodeHostBit",
|
||||
cc: makeClusterCIDR(64, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits > minPerNodeHostBit",
|
||||
cc: makeClusterCIDR(4, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid SingleStack IPv6 ClusterCIDR perNodeHostBits=100",
|
||||
cc: makeClusterCIDR(100, "", "fd00:1:1::/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid DualStack ClusterCIDR",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid DualStack ClusterCIDR, no NodeSelector",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", nil),
|
||||
expectErr: false,
|
||||
},
|
||||
// Failure cases.
|
||||
{
|
||||
name: "invalid ClusterCIDR, no IPv4 or IPv6 CIDR",
|
||||
cc: makeClusterCIDR(8, "", "", nil),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid ClusterCIDR, invalid nodeSelector",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("NoUppercaseOrSpecialCharsLike=Equals", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
@@ -1963,13 +1921,11 @@ func TestValidateClusterCIDR(t *testing.T) {
|
||||
name: "invalid SingleStack IPv4 ClusterCIDR, invalid spec.IPv4",
|
||||
cc: makeClusterCIDR(8, "test", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid Singlestack IPv4 ClusterCIDR, perNodeHostBits > maxPerNodeHostBits",
|
||||
cc: makeClusterCIDR(100, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid SingleStack IPv4 ClusterCIDR, perNodeHostBits < minPerNodeHostBits",
|
||||
cc: makeClusterCIDR(2, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
@@ -1979,18 +1935,15 @@ func TestValidateClusterCIDR(t *testing.T) {
|
||||
name: "invalid SingleStack IPv6 ClusterCIDR, invalid spec.IPv6",
|
||||
cc: makeClusterCIDR(8, "", "testv6", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid SingleStack IPv6 ClusterCIDR, valid IPv4 CIDR in spec.IPv6",
|
||||
cc: makeClusterCIDR(8, "", "10.2.0.0/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits > maxPerNodeHostBits",
|
||||
cc: makeClusterCIDR(12, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits < minPerNodeHostBits",
|
||||
cc: makeClusterCIDR(3, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
@@ -2000,18 +1953,15 @@ func TestValidateClusterCIDR(t *testing.T) {
|
||||
name: "invalid DualStack ClusterCIDR, valid spec.IPv4, invalid spec.IPv6",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "testv6", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid DualStack ClusterCIDR, valid spec.IPv6, invalid spec.IPv4",
|
||||
cc: makeClusterCIDR(8, "testv4", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid DualStack ClusterCIDR, invalid perNodeHostBits > maxPerNodeHostBits",
|
||||
cc: makeClusterCIDR(24, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "invalid DualStack ClusterCIDR, valid IPv6 CIDR in spec.IPv4",
|
||||
cc: makeClusterCIDR(8, "fd00::/120", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
@@ -2038,33 +1988,27 @@ func TestValidateClusterConfigUpdate(t *testing.T) {
|
||||
name string
|
||||
cc *networking.ClusterCIDR
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "Successful update, no changes to ClusterCIDR.Spec",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "Failed update, update spec.PerNodeHostBits",
|
||||
cc: makeClusterCIDR(12, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Failed update, update spec.IPv4",
|
||||
cc: makeClusterCIDR(8, "10.2.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Failed update, update spec.IPv6",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:2:/112", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Failed update, update spec.NodeSelector",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar2"})),
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "Successful update, no changes to ClusterCIDR.Spec",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "Failed update, update spec.PerNodeHostBits",
|
||||
cc: makeClusterCIDR(12, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
}, {
|
||||
name: "Failed update, update spec.IPv4",
|
||||
cc: makeClusterCIDR(8, "10.2.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
}, {
|
||||
name: "Failed update, update spec.IPv6",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:2:/112", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
|
||||
expectErr: true,
|
||||
}, {
|
||||
name: "Failed update, update spec.NodeSelector",
|
||||
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar2"})),
|
||||
expectErr: true,
|
||||
}}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
err := ValidateClusterCIDRUpdate(testCase.cc, oldCCC)
|
||||
@@ -2244,15 +2188,14 @@ func TestValidateIPAddressUpdate(t *testing.T) {
|
||||
name string
|
||||
new func(svc *networking.IPAddress) *networking.IPAddress
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "Successful update, no changes",
|
||||
new: func(old *networking.IPAddress) *networking.IPAddress {
|
||||
out := old.DeepCopy()
|
||||
return out
|
||||
},
|
||||
expectErr: false,
|
||||
}{{
|
||||
name: "Successful update, no changes",
|
||||
new: func(old *networking.IPAddress) *networking.IPAddress {
|
||||
out := old.DeepCopy()
|
||||
return out
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Failed update, update spec.ParentRef",
|
||||
@@ -2267,8 +2210,7 @@ func TestValidateIPAddressUpdate(t *testing.T) {
|
||||
|
||||
return out
|
||||
}, expectErr: true,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
name: "Failed update, delete spec.ParentRef",
|
||||
new: func(svc *networking.IPAddress) *networking.IPAddress {
|
||||
out := svc.DeepCopy()
|
||||
|
@@ -134,17 +134,15 @@ func TestValidateOverhead(t *testing.T) {
|
||||
successCase := []struct {
|
||||
Name string
|
||||
overhead *node.Overhead
|
||||
}{
|
||||
{
|
||||
Name: "Overhead with valid cpu and memory resources",
|
||||
overhead: &node.Overhead{
|
||||
PodFixed: core.ResourceList{
|
||||
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
|
||||
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
|
||||
},
|
||||
}{{
|
||||
Name: "Overhead with valid cpu and memory resources",
|
||||
overhead: &node.Overhead{
|
||||
PodFixed: core.ResourceList{
|
||||
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
|
||||
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}}
|
||||
|
||||
for _, tc := range successCase {
|
||||
rc := &node.RuntimeClass{
|
||||
@@ -160,16 +158,14 @@ func TestValidateOverhead(t *testing.T) {
|
||||
errorCase := []struct {
|
||||
Name string
|
||||
overhead *node.Overhead
|
||||
}{
|
||||
{
|
||||
Name: "Invalid Resources",
|
||||
overhead: &node.Overhead{
|
||||
PodFixed: core.ResourceList{
|
||||
core.ResourceName("my.org"): resource.MustParse("10m"),
|
||||
},
|
||||
}{{
|
||||
Name: "Invalid Resources",
|
||||
overhead: &node.Overhead{
|
||||
PodFixed: core.ResourceList{
|
||||
core.ResourceName("my.org"): resource.MustParse("10m"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}}
|
||||
for _, tc := range errorCase {
|
||||
rc := &node.RuntimeClass{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||
|
@@ -107,40 +107,35 @@ func TestValidateUnhealthyPodEvictionPolicyDisruptionBudgetSpec(t *testing.T) {
|
||||
name string
|
||||
pdbSpec policy.PodDisruptionBudgetSpec
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid nil UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: nil,
|
||||
},
|
||||
expectErr: false,
|
||||
}{{
|
||||
name: "valid nil UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: nil,
|
||||
},
|
||||
{
|
||||
name: "valid UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: &alwaysAllowPolicy,
|
||||
},
|
||||
expectErr: false,
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "valid UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: &alwaysAllowPolicy,
|
||||
},
|
||||
{
|
||||
name: "empty UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: new(policy.UnhealthyPodEvictionPolicyType),
|
||||
},
|
||||
expectErr: true,
|
||||
expectErr: false,
|
||||
}, {
|
||||
name: "empty UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: new(policy.UnhealthyPodEvictionPolicyType),
|
||||
},
|
||||
{
|
||||
name: "invalid UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: &invalidPolicy,
|
||||
},
|
||||
expectErr: true,
|
||||
expectErr: true,
|
||||
}, {
|
||||
name: "invalid UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: &invalidPolicy,
|
||||
},
|
||||
}
|
||||
expectErr: true,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -162,128 +157,112 @@ func TestValidatePodDisruptionBudgetStatus(t *testing.T) {
|
||||
name string
|
||||
pdbStatus policy.PodDisruptionBudgetStatus
|
||||
expectErrForVersion map[schema.GroupVersion]bool
|
||||
}{
|
||||
{
|
||||
name: "DisruptionsAllowed: 10",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DisruptionsAllowed: 10,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}{{
|
||||
name: "DisruptionsAllowed: 10",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DisruptionsAllowed: 10,
|
||||
},
|
||||
{
|
||||
name: "CurrentHealthy: 5",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
CurrentHealthy: 5,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
{
|
||||
name: "DesiredHealthy: 3",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DesiredHealthy: 3,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}, {
|
||||
name: "CurrentHealthy: 5",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
CurrentHealthy: 5,
|
||||
},
|
||||
{
|
||||
name: "ExpectedPods: 2",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
ExpectedPods: 2,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
{
|
||||
name: "DisruptionsAllowed: -10",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DisruptionsAllowed: -10,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}, {
|
||||
name: "DesiredHealthy: 3",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DesiredHealthy: 3,
|
||||
},
|
||||
{
|
||||
name: "CurrentHealthy: -5",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
CurrentHealthy: -5,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
{
|
||||
name: "DesiredHealthy: -3",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DesiredHealthy: -3,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}, {
|
||||
name: "ExpectedPods: 2",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
ExpectedPods: 2,
|
||||
},
|
||||
{
|
||||
name: "ExpectedPods: -2",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
ExpectedPods: -2,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
{
|
||||
name: "Conditions valid",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Type: policyv1beta1.DisruptionAllowedCondition,
|
||||
Status: metav1.ConditionTrue,
|
||||
LastTransitionTime: metav1.Time{
|
||||
Time: time.Now().Add(-5 * time.Minute),
|
||||
},
|
||||
Reason: policyv1beta1.SufficientPodsReason,
|
||||
Message: "message",
|
||||
ObservedGeneration: 3,
|
||||
},
|
||||
}, {
|
||||
name: "DisruptionsAllowed: -10",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DisruptionsAllowed: -10,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}, {
|
||||
name: "CurrentHealthy: -5",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
CurrentHealthy: -5,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}, {
|
||||
name: "DesiredHealthy: -3",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
DesiredHealthy: -3,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}, {
|
||||
name: "ExpectedPods: -2",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
ExpectedPods: -2,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}, {
|
||||
name: "Conditions valid",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
Conditions: []metav1.Condition{{
|
||||
Type: policyv1beta1.DisruptionAllowedCondition,
|
||||
Status: metav1.ConditionTrue,
|
||||
LastTransitionTime: metav1.Time{
|
||||
Time: time.Now().Add(-5 * time.Minute),
|
||||
},
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
Reason: policyv1beta1.SufficientPodsReason,
|
||||
Message: "message",
|
||||
ObservedGeneration: 3,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "Conditions not valid",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Type: policyv1beta1.DisruptionAllowedCondition,
|
||||
Status: metav1.ConditionTrue,
|
||||
},
|
||||
{
|
||||
Type: policyv1beta1.DisruptionAllowedCondition,
|
||||
Status: metav1.ConditionFalse,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectErrors,
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectNoErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectNoErrors,
|
||||
},
|
||||
}
|
||||
}, {
|
||||
name: "Conditions not valid",
|
||||
pdbStatus: policy.PodDisruptionBudgetStatus{
|
||||
Conditions: []metav1.Condition{{
|
||||
Type: policyv1beta1.DisruptionAllowedCondition,
|
||||
Status: metav1.ConditionTrue,
|
||||
}, {
|
||||
Type: policyv1beta1.DisruptionAllowedCondition,
|
||||
Status: metav1.ConditionFalse,
|
||||
}},
|
||||
},
|
||||
expectErrForVersion: map[schema.GroupVersion]bool{
|
||||
policy.SchemeGroupVersion: expectErrors,
|
||||
policyv1beta1.SchemeGroupVersion: expectErrors,
|
||||
},
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
for apiVersion, expectErrors := range tc.expectErrForVersion {
|
||||
@@ -1165,23 +1144,19 @@ func TestAllowEphemeralVolumeType(t *testing.T) {
|
||||
description string
|
||||
hasGenericVolume bool
|
||||
psp func() *policy.PodSecurityPolicy
|
||||
}{
|
||||
{
|
||||
description: "PodSecurityPolicySpec Without GenericVolume",
|
||||
hasGenericVolume: false,
|
||||
psp: pspWithoutGenericVolume,
|
||||
},
|
||||
{
|
||||
description: "PodSecurityPolicySpec With GenericVolume",
|
||||
hasGenericVolume: true,
|
||||
psp: pspWithGenericVolume,
|
||||
},
|
||||
{
|
||||
description: "is nil",
|
||||
hasGenericVolume: false,
|
||||
psp: pspNil,
|
||||
},
|
||||
}
|
||||
}{{
|
||||
description: "PodSecurityPolicySpec Without GenericVolume",
|
||||
hasGenericVolume: false,
|
||||
psp: pspWithoutGenericVolume,
|
||||
}, {
|
||||
description: "PodSecurityPolicySpec With GenericVolume",
|
||||
hasGenericVolume: true,
|
||||
psp: pspWithGenericVolume,
|
||||
}, {
|
||||
description: "is nil",
|
||||
hasGenericVolume: false,
|
||||
psp: pspNil,
|
||||
}}
|
||||
|
||||
for _, oldPSPInfo := range pspInfo {
|
||||
for _, newPSPInfo := range pspInfo {
|
||||
|
@@ -402,12 +402,10 @@ func TestValidateRoleNonResourceURL(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
},
|
||||
},
|
||||
Rules: []rbac.PolicyRule{{
|
||||
Verbs: []string{"get"},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
}},
|
||||
},
|
||||
wantErr: false,
|
||||
}.test(t)
|
||||
@@ -420,13 +418,11 @@ func TestValidateRoleNamespacedNonResourceURL(t *testing.T) {
|
||||
Namespace: "default",
|
||||
Name: "default",
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
{
|
||||
// non-resource URLs are invalid for namespaced rules
|
||||
Verbs: []string{"get"},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
},
|
||||
},
|
||||
Rules: []rbac.PolicyRule{{
|
||||
// non-resource URLs are invalid for namespaced rules
|
||||
Verbs: []string{"get"},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
}},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: field.ErrorTypeInvalid,
|
||||
@@ -440,12 +436,10 @@ func TestValidateRoleNonResourceURLNoVerbs(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
},
|
||||
},
|
||||
Rules: []rbac.PolicyRule{{
|
||||
Verbs: []string{},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
}},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: field.ErrorTypeRequired,
|
||||
@@ -460,14 +454,12 @@ func TestValidateRoleMixedNonResourceAndResource(t *testing.T) {
|
||||
Name: "default",
|
||||
Namespace: "default",
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
APIGroups: []string{"v1"},
|
||||
Resources: []string{"pods"},
|
||||
},
|
||||
},
|
||||
Rules: []rbac.PolicyRule{{
|
||||
Verbs: []string{"get"},
|
||||
NonResourceURLs: []string{"/*"},
|
||||
APIGroups: []string{"v1"},
|
||||
Resources: []string{"pods"},
|
||||
}},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: field.ErrorTypeInvalid,
|
||||
@@ -482,13 +474,11 @@ func TestValidateRoleValidResource(t *testing.T) {
|
||||
Name: "default",
|
||||
Namespace: "default",
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"v1"},
|
||||
Resources: []string{"pods"},
|
||||
},
|
||||
},
|
||||
Rules: []rbac.PolicyRule{{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"v1"},
|
||||
Resources: []string{"pods"},
|
||||
}},
|
||||
},
|
||||
wantErr: false,
|
||||
}.test(t)
|
||||
@@ -501,12 +491,10 @@ func TestValidateRoleNoAPIGroup(t *testing.T) {
|
||||
Name: "default",
|
||||
Namespace: "default",
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
Resources: []string{"pods"},
|
||||
},
|
||||
},
|
||||
Rules: []rbac.PolicyRule{{
|
||||
Verbs: []string{"get"},
|
||||
Resources: []string{"pods"},
|
||||
}},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: field.ErrorTypeRequired,
|
||||
@@ -521,12 +509,10 @@ func TestValidateRoleNoResources(t *testing.T) {
|
||||
Name: "default",
|
||||
Namespace: "default",
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"v1"},
|
||||
},
|
||||
},
|
||||
Rules: []rbac.PolicyRule{{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"v1"},
|
||||
}},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: field.ErrorTypeRequired,
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -86,502 +86,442 @@ func TestValidateKubeletConfiguration(t *testing.T) {
|
||||
name string
|
||||
configure func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "Success",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
return conf
|
||||
},
|
||||
}{{
|
||||
name: "Success",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid NodeLeaseDurationSeconds",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.NodeLeaseDurationSeconds = 0
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: nodeLeaseDurationSeconds must be greater than 0",
|
||||
}, {
|
||||
name: "invalid NodeLeaseDurationSeconds",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.NodeLeaseDurationSeconds = 0
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify EnforceNodeAllocatable without enabling CgroupsPerQOS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.CgroupsPerQOS = false
|
||||
conf.EnforceNodeAllocatable = []string{"pods"}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) is not supported unless cgroupsPerQOS (--cgroups-per-qos) is set to true",
|
||||
errMsg: "invalid configuration: nodeLeaseDurationSeconds must be greater than 0",
|
||||
}, {
|
||||
name: "specify EnforceNodeAllocatable without enabling CgroupsPerQOS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.CgroupsPerQOS = false
|
||||
conf.EnforceNodeAllocatable = []string{"pods"}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify SystemCgroups without CgroupRoot",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.SystemCgroups = "/"
|
||||
conf.CgroupRoot = ""
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: systemCgroups (--system-cgroups) was specified and cgroupRoot (--cgroup-root) was not specified",
|
||||
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) is not supported unless cgroupsPerQOS (--cgroups-per-qos) is set to true",
|
||||
}, {
|
||||
name: "specify SystemCgroups without CgroupRoot",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.SystemCgroups = "/"
|
||||
conf.CgroupRoot = ""
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid EventBurst",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EventBurst = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: eventBurst (--event-burst) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: systemCgroups (--system-cgroups) was specified and cgroupRoot (--cgroup-root) was not specified",
|
||||
}, {
|
||||
name: "invalid EventBurst",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EventBurst = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid EventRecordQPS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EventRecordQPS = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: eventRecordQPS (--event-qps) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: eventBurst (--event-burst) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid EventRecordQPS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EventRecordQPS = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid HealthzPort",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.HealthzPort = 65536
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: healthzPort (--healthz-port) 65536 must be between 1 and 65535, inclusive",
|
||||
errMsg: "invalid configuration: eventRecordQPS (--event-qps) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid HealthzPort",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.HealthzPort = 65536
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify CPUCFSQuotaPeriod without enabling CPUCFSQuotaPeriod",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": false}
|
||||
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 200 * time.Millisecond}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {200ms} requires feature gate CustomCPUCFSQuotaPeriod",
|
||||
errMsg: "invalid configuration: healthzPort (--healthz-port) 65536 must be between 1 and 65535, inclusive",
|
||||
}, {
|
||||
name: "specify CPUCFSQuotaPeriod without enabling CPUCFSQuotaPeriod",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": false}
|
||||
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 200 * time.Millisecond}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid CPUCFSQuotaPeriod",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": true}
|
||||
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 2 * time.Second}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {2s} must be between 1ms and 1sec, inclusive",
|
||||
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {200ms} requires feature gate CustomCPUCFSQuotaPeriod",
|
||||
}, {
|
||||
name: "invalid CPUCFSQuotaPeriod",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": true}
|
||||
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 2 * time.Second}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid ImageGCHighThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCHighThresholdPercent = 101
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: imageGCHighThresholdPercent (--image-gc-high-threshold) 101 must be between 0 and 100, inclusive",
|
||||
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {2s} must be between 1ms and 1sec, inclusive",
|
||||
}, {
|
||||
name: "invalid ImageGCHighThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCHighThresholdPercent = 101
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid ImageGCLowThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCLowThresholdPercent = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) -1 must be between 0 and 100, inclusive",
|
||||
errMsg: "invalid configuration: imageGCHighThresholdPercent (--image-gc-high-threshold) 101 must be between 0 and 100, inclusive",
|
||||
}, {
|
||||
name: "invalid ImageGCLowThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCLowThresholdPercent = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "ImageGCLowThresholdPercent is equal to ImageGCHighThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCHighThresholdPercent = 0
|
||||
conf.ImageGCLowThresholdPercent = 0
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 0 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
|
||||
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) -1 must be between 0 and 100, inclusive",
|
||||
}, {
|
||||
name: "ImageGCLowThresholdPercent is equal to ImageGCHighThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCHighThresholdPercent = 0
|
||||
conf.ImageGCLowThresholdPercent = 0
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "ImageGCLowThresholdPercent is greater than ImageGCHighThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCHighThresholdPercent = 0
|
||||
conf.ImageGCLowThresholdPercent = 1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 1 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
|
||||
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 0 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
|
||||
}, {
|
||||
name: "ImageGCLowThresholdPercent is greater than ImageGCHighThresholdPercent",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ImageGCHighThresholdPercent = 0
|
||||
conf.ImageGCLowThresholdPercent = 1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid IPTablesDropBit",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.IPTablesDropBit = 32
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: iptablesDropBit (--iptables-drop-bit) 32 must be between 0 and 31, inclusive",
|
||||
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 1 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
|
||||
}, {
|
||||
name: "invalid IPTablesDropBit",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.IPTablesDropBit = 32
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid IPTablesMasqueradeBit",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.IPTablesMasqueradeBit = 32
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: iptablesMasqueradeBit (--iptables-masquerade-bit) 32 must be between 0 and 31, inclusive",
|
||||
errMsg: "invalid configuration: iptablesDropBit (--iptables-drop-bit) 32 must be between 0 and 31, inclusive",
|
||||
}, {
|
||||
name: "invalid IPTablesMasqueradeBit",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.IPTablesMasqueradeBit = 32
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid KubeAPIBurst",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.KubeAPIBurst = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: kubeAPIBurst (--kube-api-burst) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: iptablesMasqueradeBit (--iptables-masquerade-bit) 32 must be between 0 and 31, inclusive",
|
||||
}, {
|
||||
name: "invalid KubeAPIBurst",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.KubeAPIBurst = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid KubeAPIQPS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.KubeAPIQPS = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: kubeAPIQPS (--kube-api-qps) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: kubeAPIBurst (--kube-api-burst) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid KubeAPIQPS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.KubeAPIQPS = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid NodeStatusMaxImages",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.NodeStatusMaxImages = -2
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: nodeStatusMaxImages (--node-status-max-images) -2 must be -1 or greater",
|
||||
errMsg: "invalid configuration: kubeAPIQPS (--kube-api-qps) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid NodeStatusMaxImages",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.NodeStatusMaxImages = -2
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid MaxOpenFiles",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxOpenFiles = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: maxOpenFiles (--max-open-files) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: nodeStatusMaxImages (--node-status-max-images) -2 must be -1 or greater",
|
||||
}, {
|
||||
name: "invalid MaxOpenFiles",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxOpenFiles = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid MaxPods",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxPods = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: maxPods (--max-pods) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: maxOpenFiles (--max-open-files) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid MaxPods",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxPods = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid OOMScoreAdj",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.OOMScoreAdj = 1001
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: oomScoreAdj (--oom-score-adj) 1001 must be between -1000 and 1000, inclusive",
|
||||
errMsg: "invalid configuration: maxPods (--max-pods) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid OOMScoreAdj",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.OOMScoreAdj = 1001
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid PodsPerCore",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.PodsPerCore = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: podsPerCore (--pods-per-core) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: oomScoreAdj (--oom-score-adj) 1001 must be between -1000 and 1000, inclusive",
|
||||
}, {
|
||||
name: "invalid PodsPerCore",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.PodsPerCore = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid Port",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.Port = 65536
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: port (--port) 65536 must be between 1 and 65535, inclusive",
|
||||
errMsg: "invalid configuration: podsPerCore (--pods-per-core) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid Port",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.Port = 65536
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid ReadOnlyPort",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReadOnlyPort = 65536
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: readOnlyPort (--read-only-port) 65536 must be between 0 and 65535, inclusive",
|
||||
errMsg: "invalid configuration: port (--port) 65536 must be between 1 and 65535, inclusive",
|
||||
}, {
|
||||
name: "invalid ReadOnlyPort",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReadOnlyPort = 65536
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid RegistryBurst",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.RegistryBurst = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: registryBurst (--registry-burst) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: readOnlyPort (--read-only-port) 65536 must be between 0 and 65535, inclusive",
|
||||
}, {
|
||||
name: "invalid RegistryBurst",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.RegistryBurst = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid RegistryPullQPS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.RegistryPullQPS = -1
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: registryPullQPS (--registry-qps) -1 must not be a negative number",
|
||||
errMsg: "invalid configuration: registryBurst (--registry-burst) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid RegistryPullQPS",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.RegistryPullQPS = -1
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid MaxParallelImagePulls",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxParallelImagePulls = utilpointer.Int32(0)
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: maxParallelImagePulls 0 must be a positive number",
|
||||
errMsg: "invalid configuration: registryPullQPS (--registry-qps) -1 must not be a negative number",
|
||||
}, {
|
||||
name: "invalid MaxParallelImagePulls",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxParallelImagePulls = utilpointer.Int32(0)
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid MaxParallelImagePulls and SerializeImagePulls combination",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxParallelImagePulls = utilpointer.Int32(3)
|
||||
conf.SerializeImagePulls = true
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: maxParallelImagePulls cannot be larger than 1 unless SerializeImagePulls (--serialize-image-pulls) is set to false",
|
||||
errMsg: "invalid configuration: maxParallelImagePulls 0 must be a positive number",
|
||||
}, {
|
||||
name: "invalid MaxParallelImagePulls and SerializeImagePulls combination",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxParallelImagePulls = utilpointer.Int32(3)
|
||||
conf.SerializeImagePulls = true
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "valid MaxParallelImagePulls and SerializeImagePulls combination",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxParallelImagePulls = utilpointer.Int32(1)
|
||||
conf.SerializeImagePulls = true
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: maxParallelImagePulls cannot be larger than 1 unless SerializeImagePulls (--serialize-image-pulls) is set to false",
|
||||
}, {
|
||||
name: "valid MaxParallelImagePulls and SerializeImagePulls combination",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MaxParallelImagePulls = utilpointer.Int32(1)
|
||||
conf.SerializeImagePulls = true
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify ServerTLSBootstrap without enabling RotateKubeletServerCertificate",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"RotateKubeletServerCertificate": false}
|
||||
conf.ServerTLSBootstrap = true
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: serverTLSBootstrap true requires feature gate RotateKubeletServerCertificate",
|
||||
}, {
|
||||
name: "specify ServerTLSBootstrap without enabling RotateKubeletServerCertificate",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"RotateKubeletServerCertificate": false}
|
||||
conf.ServerTLSBootstrap = true
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid TopologyManagerPolicy",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.TopologyManagerPolicy = "invalid-policy"
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: topologyManagerPolicy (--topology-manager-policy) \"invalid-policy\" must be one of: [\"none\" \"best-effort\" \"restricted\" \"single-numa-node\"]",
|
||||
errMsg: "invalid configuration: serverTLSBootstrap true requires feature gate RotateKubeletServerCertificate",
|
||||
}, {
|
||||
name: "invalid TopologyManagerPolicy",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.TopologyManagerPolicy = "invalid-policy"
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid TopologyManagerScope",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.TopologyManagerScope = "invalid-scope"
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: topologyManagerScope (--topology-manager-scope) \"invalid-scope\" must be one of: \"container\", or \"pod\"",
|
||||
errMsg: "invalid configuration: topologyManagerPolicy (--topology-manager-policy) \"invalid-policy\" must be one of: [\"none\" \"best-effort\" \"restricted\" \"single-numa-node\"]",
|
||||
}, {
|
||||
name: "invalid TopologyManagerScope",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.TopologyManagerScope = "invalid-scope"
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "ShutdownGracePeriodCriticalPods is greater than ShutdownGracePeriod",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
|
||||
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 2 * time.Second}
|
||||
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {2s} must be <= shutdownGracePeriod {1s}",
|
||||
errMsg: "invalid configuration: topologyManagerScope (--topology-manager-scope) \"invalid-scope\" must be one of: \"container\", or \"pod\"",
|
||||
}, {
|
||||
name: "ShutdownGracePeriodCriticalPods is greater than ShutdownGracePeriod",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
|
||||
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 2 * time.Second}
|
||||
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "ShutdownGracePeriod is less than 1 sec",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
|
||||
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Millisecond}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: shutdownGracePeriod {1ms} must be either zero or otherwise >= 1 sec",
|
||||
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {2s} must be <= shutdownGracePeriod {1s}",
|
||||
}, {
|
||||
name: "ShutdownGracePeriod is less than 1 sec",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
|
||||
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Millisecond}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "ShutdownGracePeriodCriticalPods is less than 1 sec",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
|
||||
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Millisecond}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {1ms} must be either zero or otherwise >= 1 sec",
|
||||
errMsg: "invalid configuration: shutdownGracePeriod {1ms} must be either zero or otherwise >= 1 sec",
|
||||
}, {
|
||||
name: "ShutdownGracePeriodCriticalPods is less than 1 sec",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
|
||||
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Millisecond}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify ShutdownGracePeriod without enabling GracefulNodeShutdown",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
|
||||
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
|
||||
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {1ms} must be either zero or otherwise >= 1 sec",
|
||||
}, {
|
||||
name: "specify ShutdownGracePeriod without enabling GracefulNodeShutdown",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
|
||||
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify ShutdownGracePeriodCriticalPods without enabling GracefulNodeShutdown",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
|
||||
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Second}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
|
||||
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
|
||||
}, {
|
||||
name: "specify ShutdownGracePeriodCriticalPods without enabling GracefulNodeShutdown",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
|
||||
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Second}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid MemorySwap.SwapBehavior",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"NodeSwap": true}
|
||||
conf.MemorySwap.SwapBehavior = "invalid-behavior"
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: memorySwap.swapBehavior \"invalid-behavior\" must be one of: \"\", \"LimitedSwap\", or \"UnlimitedSwap\"",
|
||||
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
|
||||
}, {
|
||||
name: "invalid MemorySwap.SwapBehavior",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"NodeSwap": true}
|
||||
conf.MemorySwap.SwapBehavior = "invalid-behavior"
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify MemorySwap.SwapBehavior without enabling NodeSwap",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"NodeSwap": false}
|
||||
conf.MemorySwap.SwapBehavior = kubetypes.LimitedSwap
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: memorySwap.swapBehavior cannot be set when NodeSwap feature flag is disabled",
|
||||
errMsg: "invalid configuration: memorySwap.swapBehavior \"invalid-behavior\" must be one of: \"\", \"LimitedSwap\", or \"UnlimitedSwap\"",
|
||||
}, {
|
||||
name: "specify MemorySwap.SwapBehavior without enabling NodeSwap",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"NodeSwap": false}
|
||||
conf.MemorySwap.SwapBehavior = kubetypes.LimitedSwap
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify SystemReservedEnforcementKey without specifying SystemReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{kubetypes.SystemReservedEnforcementKey}
|
||||
conf.SystemReservedCgroup = ""
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: systemReservedCgroup (--system-reserved-cgroup) must be specified when \"system-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
|
||||
errMsg: "invalid configuration: memorySwap.swapBehavior cannot be set when NodeSwap feature flag is disabled",
|
||||
}, {
|
||||
name: "specify SystemReservedEnforcementKey without specifying SystemReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{kubetypes.SystemReservedEnforcementKey}
|
||||
conf.SystemReservedCgroup = ""
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify KubeReservedEnforcementKey without specifying KubeReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{kubetypes.KubeReservedEnforcementKey}
|
||||
conf.KubeReservedCgroup = ""
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: kubeReservedCgroup (--kube-reserved-cgroup) must be specified when \"kube-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
|
||||
errMsg: "invalid configuration: systemReservedCgroup (--system-reserved-cgroup) must be specified when \"system-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
|
||||
}, {
|
||||
name: "specify KubeReservedEnforcementKey without specifying KubeReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{kubetypes.KubeReservedEnforcementKey}
|
||||
conf.KubeReservedCgroup = ""
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify NodeAllocatableNoneKey with additional enforcements",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{kubetypes.NodeAllocatableNoneKey, kubetypes.KubeReservedEnforcementKey}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) may not contain additional enforcements when \"none\" is specified",
|
||||
errMsg: "invalid configuration: kubeReservedCgroup (--kube-reserved-cgroup) must be specified when \"kube-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
|
||||
}, {
|
||||
name: "specify NodeAllocatableNoneKey with additional enforcements",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{kubetypes.NodeAllocatableNoneKey, kubetypes.KubeReservedEnforcementKey}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid EnforceNodeAllocatable",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{"invalid-enforce-node-allocatable"}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: option \"invalid-enforce-node-allocatable\" specified for enforceNodeAllocatable (--enforce-node-allocatable). Valid options are \"pods\", \"system-reserved\", \"kube-reserved\", or \"none\"",
|
||||
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) may not contain additional enforcements when \"none\" is specified",
|
||||
}, {
|
||||
name: "invalid EnforceNodeAllocatable",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnforceNodeAllocatable = []string{"invalid-enforce-node-allocatable"}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid HairpinMode",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.HairpinMode = "invalid-hair-pin-mode"
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: option \"invalid-hair-pin-mode\" specified for hairpinMode (--hairpin-mode). Valid options are \"none\", \"hairpin-veth\" or \"promiscuous-bridge\"",
|
||||
errMsg: "invalid configuration: option \"invalid-enforce-node-allocatable\" specified for enforceNodeAllocatable (--enforce-node-allocatable). Valid options are \"pods\", \"system-reserved\", \"kube-reserved\", or \"none\"",
|
||||
}, {
|
||||
name: "invalid HairpinMode",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.HairpinMode = "invalid-hair-pin-mode"
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify ReservedSystemCPUs with SystemReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReservedSystemCPUs = "0-3"
|
||||
conf.SystemReservedCgroup = "/system.slice"
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
|
||||
errMsg: "invalid configuration: option \"invalid-hair-pin-mode\" specified for hairpinMode (--hairpin-mode). Valid options are \"none\", \"hairpin-veth\" or \"promiscuous-bridge\"",
|
||||
}, {
|
||||
name: "specify ReservedSystemCPUs with SystemReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReservedSystemCPUs = "0-3"
|
||||
conf.SystemReservedCgroup = "/system.slice"
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify ReservedSystemCPUs with KubeReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReservedSystemCPUs = "0-3"
|
||||
conf.KubeReservedCgroup = "/system.slice"
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
|
||||
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
|
||||
}, {
|
||||
name: "specify ReservedSystemCPUs with KubeReservedCgroup",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReservedSystemCPUs = "0-3"
|
||||
conf.KubeReservedCgroup = "/system.slice"
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid ReservedSystemCPUs",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReservedSystemCPUs = "invalid-reserved-system-cpus"
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: unable to parse reservedSystemCPUs (--reserved-cpus) invalid-reserved-system-cpus, error:",
|
||||
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
|
||||
}, {
|
||||
name: "invalid ReservedSystemCPUs",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.ReservedSystemCPUs = "invalid-reserved-system-cpus"
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "enable MemoryQoS without specifying MemoryThrottlingFactor",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"MemoryQoS": true}
|
||||
conf.MemoryThrottlingFactor = nil
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: memoryThrottlingFactor is required when MemoryQoS feature flag is enabled",
|
||||
errMsg: "invalid configuration: unable to parse reservedSystemCPUs (--reserved-cpus) invalid-reserved-system-cpus, error:",
|
||||
}, {
|
||||
name: "enable MemoryQoS without specifying MemoryThrottlingFactor",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"MemoryQoS": true}
|
||||
conf.MemoryThrottlingFactor = nil
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid MemoryThrottlingFactor",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MemoryThrottlingFactor = utilpointer.Float64(1.1)
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: memoryThrottlingFactor 1.1 must be greater than 0 and less than or equal to 1.0",
|
||||
errMsg: "invalid configuration: memoryThrottlingFactor is required when MemoryQoS feature flag is enabled",
|
||||
}, {
|
||||
name: "invalid MemoryThrottlingFactor",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.MemoryThrottlingFactor = utilpointer.Float64(1.1)
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid Taint.TimeAdded",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
now := metav1.Now()
|
||||
conf.RegisterWithTaints = []v1.Taint{{TimeAdded: &now}}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: taint.TimeAdded is not nil",
|
||||
errMsg: "invalid configuration: memoryThrottlingFactor 1.1 must be greater than 0 and less than or equal to 1.0",
|
||||
}, {
|
||||
name: "invalid Taint.TimeAdded",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
now := metav1.Now()
|
||||
conf.RegisterWithTaints = []v1.Taint{{TimeAdded: &now}}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify tracing with KubeletTracing disabled",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
samplingRate := int32(99999)
|
||||
conf.FeatureGates = map[string]bool{"KubeletTracing": false}
|
||||
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: tracing should not be configured if KubeletTracing feature flag is disabled.",
|
||||
errMsg: "invalid configuration: taint.TimeAdded is not nil",
|
||||
}, {
|
||||
name: "specify tracing with KubeletTracing disabled",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
samplingRate := int32(99999)
|
||||
conf.FeatureGates = map[string]bool{"KubeletTracing": false}
|
||||
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify tracing invalid sampling rate",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
samplingRate := int32(-1)
|
||||
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
|
||||
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
|
||||
return conf
|
||||
},
|
||||
errMsg: "tracing.samplingRatePerMillion: Invalid value: -1: sampling rate must be positive",
|
||||
errMsg: "invalid configuration: tracing should not be configured if KubeletTracing feature flag is disabled.",
|
||||
}, {
|
||||
name: "specify tracing invalid sampling rate",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
samplingRate := int32(-1)
|
||||
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
|
||||
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "specify tracing invalid endpoint",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
ep := "dn%2s://localhost:4317"
|
||||
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
|
||||
conf.Tracing = &tracingapi.TracingConfiguration{Endpoint: &ep}
|
||||
return conf
|
||||
},
|
||||
errMsg: "tracing.endpoint: Invalid value: \"dn%2s://localhost:4317\": parse \"dn%2s://localhost:4317\": first path segment in URL cannot contain colon",
|
||||
errMsg: "tracing.samplingRatePerMillion: Invalid value: -1: sampling rate must be positive",
|
||||
}, {
|
||||
name: "specify tracing invalid endpoint",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
ep := "dn%2s://localhost:4317"
|
||||
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
|
||||
conf.Tracing = &tracingapi.TracingConfiguration{Endpoint: &ep}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "invalid GracefulNodeShutdownBasedOnPodPriority",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": true}
|
||||
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{
|
||||
{
|
||||
Priority: 0,
|
||||
ShutdownGracePeriodSeconds: 0,
|
||||
}}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: Cannot specify both shutdownGracePeriodByPodPriority and shutdownGracePeriod at the same time",
|
||||
errMsg: "tracing.endpoint: Invalid value: \"dn%2s://localhost:4317\": parse \"dn%2s://localhost:4317\": first path segment in URL cannot contain colon",
|
||||
}, {
|
||||
name: "invalid GracefulNodeShutdownBasedOnPodPriority",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": true}
|
||||
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{{
|
||||
Priority: 0,
|
||||
ShutdownGracePeriodSeconds: 0,
|
||||
}}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "Specifying shutdownGracePeriodByPodPriority without enable GracefulNodeShutdownBasedOnPodPriority",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": false}
|
||||
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{
|
||||
{
|
||||
Priority: 0,
|
||||
ShutdownGracePeriodSeconds: 0,
|
||||
}}
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: Specifying shutdownGracePeriodByPodPriority requires feature gate GracefulNodeShutdownBasedOnPodPriority",
|
||||
errMsg: "invalid configuration: Cannot specify both shutdownGracePeriodByPodPriority and shutdownGracePeriod at the same time",
|
||||
}, {
|
||||
name: "Specifying shutdownGracePeriodByPodPriority without enable GracefulNodeShutdownBasedOnPodPriority",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": false}
|
||||
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{{
|
||||
Priority: 0,
|
||||
ShutdownGracePeriodSeconds: 0,
|
||||
}}
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "enableSystemLogQuery is enabled without NodeLogQuery feature gate",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnableSystemLogQuery = true
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: NodeLogQuery feature gate is required for enableSystemLogHandler",
|
||||
errMsg: "invalid configuration: Specifying shutdownGracePeriodByPodPriority requires feature gate GracefulNodeShutdownBasedOnPodPriority",
|
||||
}, {
|
||||
name: "enableSystemLogQuery is enabled without NodeLogQuery feature gate",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.EnableSystemLogQuery = true
|
||||
return conf
|
||||
},
|
||||
{
|
||||
name: "enableSystemLogQuery is enabled without enableSystemLogHandler",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"NodeLogQuery": true}
|
||||
conf.EnableSystemLogHandler = false
|
||||
conf.EnableSystemLogQuery = true
|
||||
return conf
|
||||
},
|
||||
errMsg: "invalid configuration: enableSystemLogHandler is required for enableSystemLogQuery",
|
||||
errMsg: "invalid configuration: NodeLogQuery feature gate is required for enableSystemLogHandler",
|
||||
}, {
|
||||
name: "enableSystemLogQuery is enabled without enableSystemLogHandler",
|
||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||
conf.FeatureGates = map[string]bool{"NodeLogQuery": true}
|
||||
conf.EnableSystemLogHandler = false
|
||||
conf.EnableSystemLogQuery = true
|
||||
return conf
|
||||
},
|
||||
}
|
||||
errMsg: "invalid configuration: enableSystemLogHandler is required for enableSystemLogQuery",
|
||||
}}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
@@ -36,183 +36,173 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
} else {
|
||||
proxyMode = kubeproxyconfig.ProxyModeIPVS
|
||||
}
|
||||
successCases := []kubeproxyconfig.KubeProxyConfiguration{
|
||||
{
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Mode: proxyMode,
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
successCases := []kubeproxyconfig.KubeProxyConfiguration{{
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Mode: proxyMode,
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "fd00:192:168:59::103",
|
||||
HealthzBindAddress: "",
|
||||
MetricsBindAddress: "[::1]:10249",
|
||||
ClusterCIDR: "fd00:192:168:59::/64",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
}, {
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "fd00:192:168::/64",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
}, {
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24,fd00:192:168::/64",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
DetectLocalMode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
|
||||
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
|
||||
InterfaceNamePrefix: "vethabcde",
|
||||
},
|
||||
}, {
|
||||
BindAddress: "fd00:192:168:59::103",
|
||||
HealthzBindAddress: "",
|
||||
MetricsBindAddress: "[::1]:10249",
|
||||
ClusterCIDR: "fd00:192:168:59::/64",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
{
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
DetectLocalMode: kubeproxyconfig.LocalModeBridgeInterface,
|
||||
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
|
||||
BridgeInterface: "avz",
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
}
|
||||
}, {
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
}, {
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "fd00:192:168::/64",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
}, {
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24,fd00:192:168::/64",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
}, {
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
DetectLocalMode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
|
||||
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
|
||||
InterfaceNamePrefix: "vethabcde",
|
||||
},
|
||||
}, {
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: pointer.Int32(1),
|
||||
Min: pointer.Int32(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
DetectLocalMode: kubeproxyconfig.LocalModeBridgeInterface,
|
||||
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
|
||||
BridgeInterface: "avz",
|
||||
},
|
||||
}}
|
||||
|
||||
for _, successCase := range successCases {
|
||||
if errs := Validate(&successCase); len(errs) != 0 {
|
||||
|
@@ -57,42 +57,35 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) {
|
||||
PodInitialBackoffSeconds: podInitialBackoffSeconds,
|
||||
PodMaxBackoffSeconds: podMaxBackoffSeconds,
|
||||
PercentageOfNodesToScore: pointer.Int32(35),
|
||||
Profiles: []config.KubeSchedulerProfile{
|
||||
{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Score: config.PluginSet{
|
||||
Disabled: []config.Plugin{{Name: "*"}},
|
||||
},
|
||||
Profiles: []config.KubeSchedulerProfile{{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
|
||||
},
|
||||
Score: config.PluginSet{
|
||||
Disabled: []config.Plugin{{Name: "*"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Bind: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomBind"}},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
|
||||
}},
|
||||
}, {
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Bind: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomBind"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Extenders: []config.Extender{
|
||||
{
|
||||
PrioritizeVerb: "prioritize",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
}},
|
||||
Extenders: []config.Extender{{
|
||||
PrioritizeVerb: "prioritize",
|
||||
Weight: 1,
|
||||
}},
|
||||
}
|
||||
|
||||
invalidParallelismValue := validConfig.DeepCopy()
|
||||
@@ -145,60 +138,46 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) {
|
||||
extenderNegativeWeight.Extenders[0].Weight = -1
|
||||
|
||||
invalidNodePercentage := validConfig.DeepCopy()
|
||||
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
|
||||
},
|
||||
}
|
||||
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
|
||||
}}
|
||||
|
||||
invalidPluginArgs := validConfig.DeepCopy()
|
||||
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.InterPodAffinityArgs{},
|
||||
},
|
||||
}
|
||||
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.InterPodAffinityArgs{},
|
||||
}}
|
||||
|
||||
duplicatedPluginConfig := validConfig.DeepCopy()
|
||||
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "config",
|
||||
},
|
||||
{
|
||||
Name: "config",
|
||||
},
|
||||
}
|
||||
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "config",
|
||||
}, {
|
||||
Name: "config",
|
||||
}}
|
||||
|
||||
mismatchQueueSort := validConfig.DeepCopy()
|
||||
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{
|
||||
{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "PrioritySort"}},
|
||||
},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "PrioritySort",
|
||||
},
|
||||
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "PrioritySort"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "CustomSort",
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "PrioritySort",
|
||||
}},
|
||||
}, {
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "CustomSort",
|
||||
}},
|
||||
}}
|
||||
|
||||
extenderDuplicateManagedResource := validConfig.DeepCopy()
|
||||
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
|
||||
@@ -455,42 +434,35 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
|
||||
PodInitialBackoffSeconds: podInitialBackoffSeconds,
|
||||
PodMaxBackoffSeconds: podMaxBackoffSeconds,
|
||||
PercentageOfNodesToScore: pointer.Int32(35),
|
||||
Profiles: []config.KubeSchedulerProfile{
|
||||
{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Score: config.PluginSet{
|
||||
Disabled: []config.Plugin{{Name: "*"}},
|
||||
},
|
||||
Profiles: []config.KubeSchedulerProfile{{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
|
||||
},
|
||||
Score: config.PluginSet{
|
||||
Disabled: []config.Plugin{{Name: "*"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Bind: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomBind"}},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
|
||||
}},
|
||||
}, {
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Bind: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomBind"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Extenders: []config.Extender{
|
||||
{
|
||||
PrioritizeVerb: "prioritize",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
}},
|
||||
Extenders: []config.Extender{{
|
||||
PrioritizeVerb: "prioritize",
|
||||
Weight: 1,
|
||||
}},
|
||||
}
|
||||
|
||||
invalidParallelismValue := validConfig.DeepCopy()
|
||||
@@ -543,20 +515,16 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
|
||||
extenderNegativeWeight.Extenders[0].Weight = -1
|
||||
|
||||
invalidNodePercentage := validConfig.DeepCopy()
|
||||
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
|
||||
},
|
||||
}
|
||||
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
|
||||
}}
|
||||
|
||||
invalidPluginArgs := validConfig.DeepCopy()
|
||||
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.InterPodAffinityArgs{},
|
||||
},
|
||||
}
|
||||
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.InterPodAffinityArgs{},
|
||||
}}
|
||||
|
||||
duplicatedPlugins := validConfig.DeepCopy()
|
||||
duplicatedPlugins.Profiles[0].Plugins.PreEnqueue.Enabled = []config.Plugin{
|
||||
@@ -565,44 +533,34 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
|
||||
}
|
||||
|
||||
duplicatedPluginConfig := validConfig.DeepCopy()
|
||||
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "config",
|
||||
},
|
||||
{
|
||||
Name: "config",
|
||||
},
|
||||
}
|
||||
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "config",
|
||||
}, {
|
||||
Name: "config",
|
||||
}}
|
||||
|
||||
mismatchQueueSort := validConfig.DeepCopy()
|
||||
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{
|
||||
{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "PrioritySort"}},
|
||||
},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "PrioritySort",
|
||||
},
|
||||
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "PrioritySort"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "CustomSort",
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "PrioritySort",
|
||||
}},
|
||||
}, {
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "CustomSort",
|
||||
}},
|
||||
}}
|
||||
|
||||
extenderDuplicateManagedResource := validConfig.DeepCopy()
|
||||
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
|
||||
@@ -858,44 +816,37 @@ func TestValidateKubeSchedulerConfigurationV1(t *testing.T) {
|
||||
},
|
||||
PodInitialBackoffSeconds: podInitialBackoffSeconds,
|
||||
PodMaxBackoffSeconds: podMaxBackoffSeconds,
|
||||
Profiles: []config.KubeSchedulerProfile{
|
||||
{
|
||||
SchedulerName: "me",
|
||||
PercentageOfNodesToScore: pointer.Int32(35),
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Score: config.PluginSet{
|
||||
Disabled: []config.Plugin{{Name: "*"}},
|
||||
},
|
||||
Profiles: []config.KubeSchedulerProfile{{
|
||||
SchedulerName: "me",
|
||||
PercentageOfNodesToScore: pointer.Int32(35),
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
|
||||
},
|
||||
Score: config.PluginSet{
|
||||
Disabled: []config.Plugin{{Name: "*"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
SchedulerName: "other",
|
||||
PercentageOfNodesToScore: pointer.Int32(35),
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Bind: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomBind"}},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
|
||||
}},
|
||||
}, {
|
||||
SchedulerName: "other",
|
||||
PercentageOfNodesToScore: pointer.Int32(35),
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
Bind: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomBind"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Extenders: []config.Extender{
|
||||
{
|
||||
PrioritizeVerb: "prioritize",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
}},
|
||||
Extenders: []config.Extender{{
|
||||
PrioritizeVerb: "prioritize",
|
||||
Weight: 1,
|
||||
}},
|
||||
}
|
||||
|
||||
invalidParallelismValue := validConfig.DeepCopy()
|
||||
@@ -948,60 +899,46 @@ func TestValidateKubeSchedulerConfigurationV1(t *testing.T) {
|
||||
extenderNegativeWeight.Extenders[0].Weight = -1
|
||||
|
||||
invalidNodePercentage := validConfig.DeepCopy()
|
||||
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
|
||||
},
|
||||
}
|
||||
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
|
||||
}}
|
||||
|
||||
invalidPluginArgs := validConfig.DeepCopy()
|
||||
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.InterPodAffinityArgs{},
|
||||
},
|
||||
}
|
||||
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "DefaultPreemption",
|
||||
Args: &config.InterPodAffinityArgs{},
|
||||
}}
|
||||
|
||||
duplicatedPluginConfig := validConfig.DeepCopy()
|
||||
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{
|
||||
{
|
||||
Name: "config",
|
||||
},
|
||||
{
|
||||
Name: "config",
|
||||
},
|
||||
}
|
||||
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{{
|
||||
Name: "config",
|
||||
}, {
|
||||
Name: "config",
|
||||
}}
|
||||
|
||||
mismatchQueueSort := validConfig.DeepCopy()
|
||||
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{
|
||||
{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "PrioritySort"}},
|
||||
},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "PrioritySort",
|
||||
},
|
||||
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{{
|
||||
SchedulerName: "me",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "PrioritySort"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{
|
||||
{
|
||||
Name: "CustomSort",
|
||||
},
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "PrioritySort",
|
||||
}},
|
||||
}, {
|
||||
SchedulerName: "other",
|
||||
Plugins: &config.Plugins{
|
||||
QueueSort: config.PluginSet{
|
||||
Enabled: []config.Plugin{{Name: "CustomSort"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
PluginConfig: []config.PluginConfig{{
|
||||
Name: "CustomSort",
|
||||
}},
|
||||
}}
|
||||
|
||||
extenderDuplicateManagedResource := validConfig.DeepCopy()
|
||||
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
|
||||
|
@@ -27,158 +27,124 @@ func TestValidateConfiguration(t *testing.T) {
|
||||
name string
|
||||
config eventratelimitapi.Configuration
|
||||
expectedResult bool
|
||||
}{
|
||||
{
|
||||
name: "valid server",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "Server",
|
||||
Burst: 5,
|
||||
QPS: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: true,
|
||||
}{{
|
||||
name: "valid server",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "Server",
|
||||
Burst: 5,
|
||||
QPS: 1,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "valid namespace",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "Namespace",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: true,
|
||||
expectedResult: true,
|
||||
}, {
|
||||
name: "valid namespace",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "Namespace",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: 100,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "valid user",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "User",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: true,
|
||||
expectedResult: true,
|
||||
}, {
|
||||
name: "valid user",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "User",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: 100,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "valid source+object",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "SourceAndObject",
|
||||
Burst: 5,
|
||||
QPS: 1,
|
||||
CacheSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: true,
|
||||
expectedResult: true,
|
||||
}, {
|
||||
name: "valid source+object",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "SourceAndObject",
|
||||
Burst: 5,
|
||||
QPS: 1,
|
||||
CacheSize: 1000,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "valid multiple",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "Server",
|
||||
Burst: 5,
|
||||
QPS: 1,
|
||||
},
|
||||
{
|
||||
Type: "Namespace",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: 100,
|
||||
},
|
||||
{
|
||||
Type: "SourceAndObject",
|
||||
Burst: 25,
|
||||
QPS: 10,
|
||||
CacheSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: true,
|
||||
expectedResult: true,
|
||||
}, {
|
||||
name: "valid multiple",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "Server",
|
||||
Burst: 5,
|
||||
QPS: 1,
|
||||
}, {
|
||||
Type: "Namespace",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: 100,
|
||||
}, {
|
||||
Type: "SourceAndObject",
|
||||
Burst: 25,
|
||||
QPS: 10,
|
||||
CacheSize: 1000,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "missing limits",
|
||||
config: eventratelimitapi.Configuration{},
|
||||
expectedResult: false,
|
||||
expectedResult: true,
|
||||
}, {
|
||||
name: "missing limits",
|
||||
config: eventratelimitapi.Configuration{},
|
||||
expectedResult: false,
|
||||
}, {
|
||||
name: "missing type",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Burst: 25,
|
||||
QPS: 10,
|
||||
CacheSize: 1000,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "missing type",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Burst: 25,
|
||||
QPS: 10,
|
||||
CacheSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
expectedResult: false,
|
||||
}, {
|
||||
name: "invalid type",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "unknown-type",
|
||||
Burst: 25,
|
||||
QPS: 10,
|
||||
CacheSize: 1000,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "invalid type",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "unknown-type",
|
||||
Burst: 25,
|
||||
QPS: 10,
|
||||
CacheSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
expectedResult: false,
|
||||
}, {
|
||||
name: "missing burst",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "Server",
|
||||
QPS: 1,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "missing burst",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "Server",
|
||||
QPS: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
expectedResult: false,
|
||||
}, {
|
||||
name: "missing qps",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "Server",
|
||||
Burst: 5,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "missing qps",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "Server",
|
||||
Burst: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
expectedResult: false,
|
||||
}, {
|
||||
name: "negative cache size",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{{
|
||||
Type: "Namespace",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: -1,
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "negative cache size",
|
||||
config: eventratelimitapi.Configuration{
|
||||
Limits: []eventratelimitapi.Limit{
|
||||
{
|
||||
Type: "Namespace",
|
||||
Burst: 10,
|
||||
QPS: 2,
|
||||
CacheSize: -1,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
},
|
||||
}
|
||||
expectedResult: false,
|
||||
}}
|
||||
for _, tc := range cases {
|
||||
errs := ValidateConfiguration(&tc.config)
|
||||
if e, a := tc.expectedResult, len(errs) == 0; e != a {
|
||||
|
@@ -17,9 +17,10 @@ limitations under the License.
|
||||
package validation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
internalapi "k8s.io/kubernetes/plugin/pkg/admission/podtolerationrestriction/apis/podtolerationrestriction"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateConfiguration(t *testing.T) {
|
||||
@@ -28,38 +29,34 @@ func TestValidateConfiguration(t *testing.T) {
|
||||
config internalapi.Configuration
|
||||
testName string
|
||||
testStatus bool
|
||||
}{
|
||||
{
|
||||
config: internalapi.Configuration{
|
||||
Default: []api.Toleration{
|
||||
{Key: "foo", Operator: "Exists", Value: "", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
|
||||
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
|
||||
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoSchedule"},
|
||||
{Operator: "Exists", Effect: "NoSchedule"},
|
||||
},
|
||||
Whitelist: []api.Toleration{
|
||||
{Key: "foo", Value: "bar", Effect: "NoSchedule"},
|
||||
{Key: "foo", Operator: "Equal", Value: "bar"},
|
||||
},
|
||||
}{{
|
||||
config: internalapi.Configuration{
|
||||
Default: []api.Toleration{
|
||||
{Key: "foo", Operator: "Exists", Value: "", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
|
||||
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
|
||||
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoSchedule"},
|
||||
{Operator: "Exists", Effect: "NoSchedule"},
|
||||
},
|
||||
testName: "Valid cases",
|
||||
testStatus: true,
|
||||
},
|
||||
{
|
||||
config: internalapi.Configuration{
|
||||
Whitelist: []api.Toleration{{Key: "foo", Operator: "Exists", Value: "bar", Effect: "NoSchedule"}},
|
||||
Whitelist: []api.Toleration{
|
||||
{Key: "foo", Value: "bar", Effect: "NoSchedule"},
|
||||
{Key: "foo", Operator: "Equal", Value: "bar"},
|
||||
},
|
||||
testName: "Invalid case",
|
||||
testStatus: false,
|
||||
},
|
||||
{
|
||||
config: internalapi.Configuration{
|
||||
Default: []api.Toleration{{Operator: "Equal", Value: "bar", Effect: "NoSchedule"}},
|
||||
},
|
||||
testName: "Invalid case",
|
||||
testStatus: false,
|
||||
testName: "Valid cases",
|
||||
testStatus: true,
|
||||
}, {
|
||||
config: internalapi.Configuration{
|
||||
Whitelist: []api.Toleration{{Key: "foo", Operator: "Exists", Value: "bar", Effect: "NoSchedule"}},
|
||||
},
|
||||
}
|
||||
testName: "Invalid case",
|
||||
testStatus: false,
|
||||
}, {
|
||||
config: internalapi.Configuration{
|
||||
Default: []api.Toleration{{Operator: "Equal", Value: "bar", Effect: "NoSchedule"}},
|
||||
},
|
||||
testName: "Invalid case",
|
||||
testStatus: false,
|
||||
}}
|
||||
|
||||
for i := range tests {
|
||||
errs := ValidateConfiguration(&tests[i].config)
|
||||
|
@@ -17,9 +17,10 @@ limitations under the License.
|
||||
package validation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateListOptions(t *testing.T) {
|
||||
@@ -32,164 +33,145 @@ func TestValidateListOptions(t *testing.T) {
|
||||
opts internalversion.ListOptions
|
||||
watchListFeatureEnabled bool
|
||||
expectErrors []string
|
||||
}{
|
||||
{
|
||||
name: "valid-default",
|
||||
opts: internalversion.ListOptions{},
|
||||
}{{
|
||||
name: "valid-default",
|
||||
opts: internalversion.ListOptions{},
|
||||
}, {
|
||||
name: "valid-resourceversionmatch-exact",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "1",
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
|
||||
},
|
||||
{
|
||||
name: "valid-resourceversionmatch-exact",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "1",
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
|
||||
},
|
||||
}, {
|
||||
name: "invalid-resourceversionmatch-exact",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "0",
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
|
||||
},
|
||||
{
|
||||
name: "invalid-resourceversionmatch-exact",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "0",
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
|
||||
},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch \"exact\" is forbidden for resourceVersion \"0\""},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch \"exact\" is forbidden for resourceVersion \"0\""},
|
||||
}, {
|
||||
name: "valid-resourceversionmatch-notolderthan",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "0",
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
},
|
||||
{
|
||||
name: "valid-resourceversionmatch-notolderthan",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "0",
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
},
|
||||
}, {
|
||||
name: "invalid-resourceversionmatch",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "0",
|
||||
ResourceVersionMatch: "foo",
|
||||
},
|
||||
{
|
||||
name: "invalid-resourceversionmatch",
|
||||
opts: internalversion.ListOptions{
|
||||
ResourceVersion: "0",
|
||||
ResourceVersionMatch: "foo",
|
||||
},
|
||||
expectErrors: []string{"resourceVersionMatch: Unsupported value: \"foo\": supported values: \"Exact\", \"NotOlderThan\", \"\""},
|
||||
expectErrors: []string{"resourceVersionMatch: Unsupported value: \"foo\": supported values: \"Exact\", \"NotOlderThan\", \"\""},
|
||||
}, {
|
||||
name: "list-sendInitialEvents-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
},
|
||||
{
|
||||
name: "list-sendInitialEvents-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
},
|
||||
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list"},
|
||||
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list"},
|
||||
}, {
|
||||
name: "valid-watch-default",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
},
|
||||
{
|
||||
name: "valid-watch-default",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
},
|
||||
}, {
|
||||
name: "valid-watch-sendInitialEvents-on",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
{
|
||||
name: "valid-watch-sendInitialEvents-on",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
watchListFeatureEnabled: true,
|
||||
watchListFeatureEnabled: true,
|
||||
}, {
|
||||
name: "valid-watch-sendInitialEvents-off",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(false),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
{
|
||||
name: "valid-watch-sendInitialEvents-off",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(false),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
watchListFeatureEnabled: true,
|
||||
watchListFeatureEnabled: true,
|
||||
}, {
|
||||
name: "watch-resourceversionmatch-without-sendInitialEvents-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
},
|
||||
{
|
||||
name: "watch-resourceversionmatch-without-sendInitialEvents-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden for watch unless sendInitialEvents is provided"},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden for watch unless sendInitialEvents is provided"},
|
||||
}, {
|
||||
name: "watch-sendInitialEvents-without-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
},
|
||||
{
|
||||
name: "watch-sendInitialEvents-without-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
}, {
|
||||
name: "watch-sendInitialEvents-with-exact-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
{
|
||||
name: "watch-sendInitialEvents-with-exact-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
watchListFeatureEnabled: true,
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"Exact\": supported values: \"NotOlderThan\""},
|
||||
watchListFeatureEnabled: true,
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"Exact\": supported values: \"NotOlderThan\""},
|
||||
}, {
|
||||
name: "watch-sendInitialEvents-on-with-empty-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: "",
|
||||
},
|
||||
{
|
||||
name: "watch-sendInitialEvents-on-with-empty-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: "",
|
||||
},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
}, {
|
||||
name: "watch-sendInitialEvents-off-with-empty-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(false),
|
||||
ResourceVersionMatch: "",
|
||||
},
|
||||
{
|
||||
name: "watch-sendInitialEvents-off-with-empty-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(false),
|
||||
ResourceVersionMatch: "",
|
||||
},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
}, {
|
||||
name: "watch-sendInitialEvents-with-incorrect-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: "incorrect",
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
{
|
||||
name: "watch-sendInitialEvents-with-incorrect-resourceversionmatch-forbidden",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: "incorrect",
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
watchListFeatureEnabled: true,
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"incorrect\": supported values: \"NotOlderThan\""},
|
||||
watchListFeatureEnabled: true,
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"incorrect\": supported values: \"NotOlderThan\""},
|
||||
}, {
|
||||
// note that validating allowWatchBookmarks would break backward compatibility
|
||||
// because it was possible to request initial events via resourceVersion=0 before this change
|
||||
name: "watch-sendInitialEvents-no-allowWatchBookmark",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
},
|
||||
{
|
||||
// note that validating allowWatchBookmarks would break backward compatibility
|
||||
// because it was possible to request initial events via resourceVersion=0 before this change
|
||||
name: "watch-sendInitialEvents-no-allowWatchBookmark",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
},
|
||||
watchListFeatureEnabled: true,
|
||||
watchListFeatureEnabled: true,
|
||||
}, {
|
||||
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
{
|
||||
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
},
|
||||
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
|
||||
}, {
|
||||
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
Continue: "123",
|
||||
},
|
||||
{
|
||||
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
|
||||
opts: internalversion.ListOptions{
|
||||
Watch: true,
|
||||
SendInitialEvents: boolPtrFn(true),
|
||||
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
|
||||
AllowWatchBookmarks: true,
|
||||
Continue: "123",
|
||||
},
|
||||
watchListFeatureEnabled: true,
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden when continue is provided"},
|
||||
},
|
||||
}
|
||||
watchListFeatureEnabled: true,
|
||||
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden when continue is provided"},
|
||||
}}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
@@ -136,31 +136,26 @@ func TestValidPatchOptions(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts metav1.PatchOptions
|
||||
patchType types.PatchType
|
||||
}{
|
||||
{
|
||||
opts: metav1.PatchOptions{
|
||||
Force: boolPtr(true),
|
||||
FieldManager: "kubectl",
|
||||
},
|
||||
patchType: types.ApplyPatchType,
|
||||
}{{
|
||||
opts: metav1.PatchOptions{
|
||||
Force: boolPtr(true),
|
||||
FieldManager: "kubectl",
|
||||
},
|
||||
{
|
||||
opts: metav1.PatchOptions{
|
||||
FieldManager: "kubectl",
|
||||
},
|
||||
patchType: types.ApplyPatchType,
|
||||
patchType: types.ApplyPatchType,
|
||||
}, {
|
||||
opts: metav1.PatchOptions{
|
||||
FieldManager: "kubectl",
|
||||
},
|
||||
{
|
||||
opts: metav1.PatchOptions{},
|
||||
patchType: types.MergePatchType,
|
||||
patchType: types.ApplyPatchType,
|
||||
}, {
|
||||
opts: metav1.PatchOptions{},
|
||||
patchType: types.MergePatchType,
|
||||
}, {
|
||||
opts: metav1.PatchOptions{
|
||||
FieldManager: "patcher",
|
||||
},
|
||||
{
|
||||
opts: metav1.PatchOptions{
|
||||
FieldManager: "patcher",
|
||||
},
|
||||
patchType: types.MergePatchType,
|
||||
},
|
||||
}
|
||||
patchType: types.MergePatchType,
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("%v", test.opts), func(t *testing.T) {
|
||||
@@ -243,36 +238,30 @@ func TestValidateFieldManagerInvalid(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidateManagedFieldsInvalid(t *testing.T) {
|
||||
tests := []metav1.ManagedFieldsEntry{
|
||||
{
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
FieldsType: "RandomVersion",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
{
|
||||
Operation: "RandomOperation",
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
{
|
||||
// Operation is missing
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
{
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
FieldsType: "FieldsV1",
|
||||
// Invalid fieldManager
|
||||
Manager: "field\nmanager",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
{
|
||||
Operation: metav1.ManagedFieldsOperationApply,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
Subresource: "TooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLong",
|
||||
},
|
||||
}
|
||||
tests := []metav1.ManagedFieldsEntry{{
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
FieldsType: "RandomVersion",
|
||||
APIVersion: "v1",
|
||||
}, {
|
||||
Operation: "RandomOperation",
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
}, {
|
||||
// Operation is missing
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
}, {
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
FieldsType: "FieldsV1",
|
||||
// Invalid fieldManager
|
||||
Manager: "field\nmanager",
|
||||
APIVersion: "v1",
|
||||
}, {
|
||||
Operation: metav1.ManagedFieldsOperationApply,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
Subresource: "TooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLong",
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("%#v", test), func(t *testing.T) {
|
||||
@@ -285,30 +274,25 @@ func TestValidateManagedFieldsInvalid(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidateMangedFieldsValid(t *testing.T) {
|
||||
tests := []metav1.ManagedFieldsEntry{
|
||||
{
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
APIVersion: "v1",
|
||||
// FieldsType is missing
|
||||
},
|
||||
{
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
{
|
||||
Operation: metav1.ManagedFieldsOperationApply,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
Subresource: "scale",
|
||||
},
|
||||
{
|
||||
Operation: metav1.ManagedFieldsOperationApply,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
Manager: "🍔",
|
||||
},
|
||||
}
|
||||
tests := []metav1.ManagedFieldsEntry{{
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
APIVersion: "v1",
|
||||
// FieldsType is missing
|
||||
}, {
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
}, {
|
||||
Operation: metav1.ManagedFieldsOperationApply,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
Subresource: "scale",
|
||||
}, {
|
||||
Operation: metav1.ManagedFieldsOperationApply,
|
||||
FieldsType: "FieldsV1",
|
||||
APIVersion: "v1",
|
||||
Manager: "🍔",
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("%#v", test), func(t *testing.T) {
|
||||
@@ -325,99 +309,90 @@ func TestValidateConditions(t *testing.T) {
|
||||
name string
|
||||
conditions []metav1.Condition
|
||||
validateErrs func(t *testing.T, errs field.ErrorList)
|
||||
}{
|
||||
{
|
||||
name: "bunch-of-invalid-fields",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: ":invalid",
|
||||
Status: "unknown",
|
||||
ObservedGeneration: -1,
|
||||
LastTransitionTime: metav1.Time{},
|
||||
Reason: "invalid;val",
|
||||
Message: "",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].type: Invalid value: ":invalid": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].status: Unsupported value: "unknown": supported values: "False", "True", "Unknown"`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].observedGeneration: Invalid value: -1: must be greater than or equal to zero`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].lastTransitionTime: Required value: must be set`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].reason: Invalid value: "invalid;val": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}{{
|
||||
name: "bunch-of-invalid-fields",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: ":invalid",
|
||||
Status: "unknown",
|
||||
ObservedGeneration: -1,
|
||||
LastTransitionTime: metav1.Time{},
|
||||
Reason: "invalid;val",
|
||||
Message: "",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].type: Invalid value: ":invalid": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].status: Unsupported value: "unknown": supported values: "False", "True", "Unknown"`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].observedGeneration: Invalid value: -1: must be greater than or equal to zero`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].lastTransitionTime: Required value: must be set`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
needle = `status.conditions[0].reason: Invalid value: "invalid;val": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "duplicates",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
},
|
||||
{
|
||||
Type: "Second",
|
||||
},
|
||||
{
|
||||
Type: "First",
|
||||
},
|
||||
},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[2].type: Duplicate value: "First"`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "duplicates",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
}, {
|
||||
Type: "Second",
|
||||
}, {
|
||||
Type: "First",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[2].type: Duplicate value: "First"`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "colon-allowed-in-reason",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
Reason: "valid:val",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].reason`
|
||||
if hasPrefixError(errs, needle) {
|
||||
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "colon-allowed-in-reason",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
Reason: "valid:val",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].reason`
|
||||
if hasPrefixError(errs, needle) {
|
||||
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "comma-allowed-in-reason",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
Reason: "valid,val",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].reason`
|
||||
if hasPrefixError(errs, needle) {
|
||||
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "comma-allowed-in-reason",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
Reason: "valid,val",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].reason`
|
||||
if hasPrefixError(errs, needle) {
|
||||
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "reason-does-not-end-in-delimiter",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
Reason: "valid,val:",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].reason: Invalid value: "valid,val:": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "reason-does-not-end-in-delimiter",
|
||||
conditions: []metav1.Condition{{
|
||||
Type: "First",
|
||||
Reason: "valid,val:",
|
||||
}},
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
needle := `status.conditions[0].reason: Invalid value: "valid,val:": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
|
||||
if !hasError(errs, needle) {
|
||||
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -433,79 +408,66 @@ func TestLabelSelectorMatchExpression(t *testing.T) {
|
||||
labelSelector *metav1.LabelSelector
|
||||
wantErrorNumber int
|
||||
validateErrs func(t *testing.T, errs field.ErrorList)
|
||||
}{
|
||||
{
|
||||
name: "Valid LabelSelector",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrorNumber: 0,
|
||||
validateErrs: nil,
|
||||
}{{
|
||||
name: "Valid LabelSelector",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value"},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "MatchExpression's key name isn't valid",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "-key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrorNumber: 1,
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
errMessage := "name part must consist of alphanumeric characters"
|
||||
if !partStringInErrorMessage(errs, errMessage) {
|
||||
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
wantErrorNumber: 0,
|
||||
validateErrs: nil,
|
||||
}, {
|
||||
name: "MatchExpression's key name isn't valid",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{{
|
||||
Key: "-key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value"},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "MatchExpression's operator isn't valid",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: "abc",
|
||||
Values: []string{"value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrorNumber: 1,
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
errMessage := "not a valid selector operator"
|
||||
if !partStringInErrorMessage(errs, errMessage) {
|
||||
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
wantErrorNumber: 1,
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
errMessage := "name part must consist of alphanumeric characters"
|
||||
if !partStringInErrorMessage(errs, errMessage) {
|
||||
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "MatchExpression's value name isn't valid",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"-value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrorNumber: 1,
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
errMessage := "a valid label must be an empty string or consist of"
|
||||
if !partStringInErrorMessage(errs, errMessage) {
|
||||
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "MatchExpression's operator isn't valid",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{{
|
||||
Key: "key",
|
||||
Operator: "abc",
|
||||
Values: []string{"value"},
|
||||
}},
|
||||
},
|
||||
}
|
||||
wantErrorNumber: 1,
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
errMessage := "not a valid selector operator"
|
||||
if !partStringInErrorMessage(errs, errMessage) {
|
||||
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "MatchExpression's value name isn't valid",
|
||||
labelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"-value"},
|
||||
}},
|
||||
},
|
||||
wantErrorNumber: 1,
|
||||
validateErrs: func(t *testing.T, errs field.ErrorList) {
|
||||
errMessage := "a valid label must be an empty string or consist of"
|
||||
if !partStringInErrorMessage(errs, errMessage) {
|
||||
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
|
||||
}
|
||||
},
|
||||
}}
|
||||
for index, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
allErrs := ValidateLabelSelector(testCase.labelSelector, LabelSelectorValidationOptions{false}, field.NewPath("labelSelector"))
|
||||
|
@@ -630,33 +630,27 @@ func TestIsFullyQualifiedName(t *testing.T) {
|
||||
name string
|
||||
targetName string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "name needs to be fully qualified, i.e., contains at least 2 dots",
|
||||
targetName: "k8s.io",
|
||||
err: "should be a domain with at least three segments separated by dots",
|
||||
},
|
||||
{
|
||||
name: "name should not include scheme",
|
||||
targetName: "http://foo.k8s.io",
|
||||
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
|
||||
},
|
||||
{
|
||||
name: "email should be invalid",
|
||||
targetName: "example@foo.k8s.io",
|
||||
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
|
||||
},
|
||||
{
|
||||
name: "name cannot be empty",
|
||||
targetName: "",
|
||||
err: "Required value",
|
||||
},
|
||||
{
|
||||
name: "name must conform to RFC 1123",
|
||||
targetName: "A.B.C",
|
||||
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "name needs to be fully qualified, i.e., contains at least 2 dots",
|
||||
targetName: "k8s.io",
|
||||
err: "should be a domain with at least three segments separated by dots",
|
||||
}, {
|
||||
name: "name should not include scheme",
|
||||
targetName: "http://foo.k8s.io",
|
||||
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
|
||||
}, {
|
||||
name: "email should be invalid",
|
||||
targetName: "example@foo.k8s.io",
|
||||
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
|
||||
}, {
|
||||
name: "name cannot be empty",
|
||||
targetName: "",
|
||||
err: "Required value",
|
||||
}, {
|
||||
name: "name must conform to RFC 1123",
|
||||
targetName: "A.B.C",
|
||||
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
|
||||
}}
|
||||
for _, tc := range messageTests {
|
||||
err := IsFullyQualifiedName(field.NewPath(""), tc.targetName).ToAggregate()
|
||||
switch {
|
||||
|
@@ -23,23 +23,17 @@ import (
|
||||
)
|
||||
|
||||
func TestValidateConfiguration(t *testing.T) {
|
||||
successCases := []resourcequotaapi.Configuration{
|
||||
{
|
||||
LimitedResources: []resourcequotaapi.LimitedResource{
|
||||
{
|
||||
Resource: "pods",
|
||||
MatchContains: []string{"requests.cpu"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LimitedResources: []resourcequotaapi.LimitedResource{
|
||||
{
|
||||
Resource: "persistentvolumeclaims",
|
||||
MatchContains: []string{"requests.storage"},
|
||||
},
|
||||
},
|
||||
},
|
||||
successCases := []resourcequotaapi.Configuration{{
|
||||
LimitedResources: []resourcequotaapi.LimitedResource{{
|
||||
Resource: "pods",
|
||||
MatchContains: []string{"requests.cpu"},
|
||||
}},
|
||||
}, {
|
||||
LimitedResources: []resourcequotaapi.LimitedResource{{
|
||||
Resource: "persistentvolumeclaims",
|
||||
MatchContains: []string{"requests.storage"},
|
||||
}},
|
||||
},
|
||||
}
|
||||
for i := range successCases {
|
||||
configuration := successCases[i]
|
||||
|
@@ -134,11 +134,9 @@ func TestValidatePolicy(t *testing.T) {
|
||||
policy := audit.Policy{OmitStages: []audit.Stage{
|
||||
audit.Stage("foo"),
|
||||
},
|
||||
Rules: []audit.PolicyRule{
|
||||
{
|
||||
Level: audit.LevelMetadata,
|
||||
},
|
||||
},
|
||||
Rules: []audit.PolicyRule{{
|
||||
Level: audit.LevelMetadata,
|
||||
}},
|
||||
}
|
||||
errorCases = append(errorCases, policy)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -748,37 +748,31 @@ func TestErrConfigurationInvalidWithErrorsIs(t *testing.T) {
|
||||
err error
|
||||
matchAgainst error
|
||||
expectMatch bool
|
||||
}{
|
||||
{
|
||||
name: "no match",
|
||||
err: errConfigurationInvalid{errors.New("my-error"), errors.New("my-other-error")},
|
||||
matchAgainst: fmt.Errorf("no entry %s", "here"),
|
||||
},
|
||||
{
|
||||
name: "match via .Is()",
|
||||
err: errConfigurationInvalid{errors.New("forbidden"), alwaysMatchingError{}},
|
||||
matchAgainst: errors.New("unauthorized"),
|
||||
expectMatch: true,
|
||||
},
|
||||
{
|
||||
name: "match via equality",
|
||||
err: errConfigurationInvalid{errors.New("err"), someError{}},
|
||||
matchAgainst: someError{},
|
||||
expectMatch: true,
|
||||
},
|
||||
{
|
||||
name: "match via nested aggregate",
|
||||
err: errConfigurationInvalid{errors.New("closed today"), errConfigurationInvalid{errConfigurationInvalid{someError{}}}},
|
||||
matchAgainst: someError{},
|
||||
expectMatch: true,
|
||||
},
|
||||
{
|
||||
name: "match via wrapped aggregate",
|
||||
err: fmt.Errorf("wrap: %w", errConfigurationInvalid{errors.New("err"), someError{}}),
|
||||
matchAgainst: someError{},
|
||||
expectMatch: true,
|
||||
},
|
||||
}
|
||||
}{{
|
||||
name: "no match",
|
||||
err: errConfigurationInvalid{errors.New("my-error"), errors.New("my-other-error")},
|
||||
matchAgainst: fmt.Errorf("no entry %s", "here"),
|
||||
}, {
|
||||
name: "match via .Is()",
|
||||
err: errConfigurationInvalid{errors.New("forbidden"), alwaysMatchingError{}},
|
||||
matchAgainst: errors.New("unauthorized"),
|
||||
expectMatch: true,
|
||||
}, {
|
||||
name: "match via equality",
|
||||
err: errConfigurationInvalid{errors.New("err"), someError{}},
|
||||
matchAgainst: someError{},
|
||||
expectMatch: true,
|
||||
}, {
|
||||
name: "match via nested aggregate",
|
||||
err: errConfigurationInvalid{errors.New("closed today"), errConfigurationInvalid{errConfigurationInvalid{someError{}}}},
|
||||
matchAgainst: someError{},
|
||||
expectMatch: true,
|
||||
}, {
|
||||
name: "match via wrapped aggregate",
|
||||
err: fmt.Errorf("wrap: %w", errConfigurationInvalid{errors.New("err"), someError{}}),
|
||||
matchAgainst: someError{},
|
||||
expectMatch: true,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
Reference in New Issue
Block a user