Skip to content

Commit

Permalink
Add Annotations validation for Template ObjectMeta
Browse files Browse the repository at this point in the history
Check value and key length for Annotations which belongs to Fleet and
GameServerSpec.
  • Loading branch information
aLekSer committed Jan 10, 2020
1 parent 5043e1b commit 6cb1cc8
Show file tree
Hide file tree
Showing 11 changed files with 1,270 additions and 8 deletions.
12 changes: 12 additions & 0 deletions pkg/apis/agones/v1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package v1
import (
"fmt"

apivalidation "k8s.io/apimachinery/pkg/api/validation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -86,5 +87,16 @@ func validateObjectMeta(objMeta metav1.ObjectMeta) []metav1.StatusCause {
})
}
}
errs = apivalidation.ValidateAnnotations(objMeta.Annotations,
field.NewPath("annotations"))
if len(errs) != 0 {
for _, v := range errs {
causes = append(causes, metav1.StatusCause{
Type: metav1.CauseTypeFieldValueInvalid,
Field: "annotations",
Message: v.Error(),
})
}
}
return causes
}
14 changes: 12 additions & 2 deletions pkg/apis/agones/v1/fleet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,28 @@ func TestFleetGameserverSpec(t *testing.T) {
assert.False(t, ok)
assert.Len(t, causes, 2)

longName := strings.Repeat("f", validation.LabelValueMaxLength+1)
f = defaultFleet()
f.ApplyDefaults()
f.Spec.Template.ObjectMeta.Labels = make(map[string]string)
f.Spec.Template.ObjectMeta.Labels["label"] = strings.Repeat("f", validation.LabelValueMaxLength+1)
f.Spec.Template.ObjectMeta.Labels["label"] = longName
causes, ok = f.Validate()
assert.False(t, ok)
assert.Len(t, causes, 1)

f = defaultFleet()
f.ApplyDefaults()
f.Spec.Template.Spec.Template.ObjectMeta.Labels = make(map[string]string)
f.Spec.Template.Spec.Template.ObjectMeta.Labels["label"] = strings.Repeat("f", validation.LabelValueMaxLength+1)
f.Spec.Template.Spec.Template.ObjectMeta.Labels["label"] = longName
causes, ok = f.Validate()
assert.False(t, ok)
assert.Len(t, causes, 1)

// Annotations test
f = defaultFleet()
f.ApplyDefaults()
f.Spec.Template.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
f.Spec.Template.Spec.Template.ObjectMeta.Annotations[longName] = ""
causes, ok = f.Validate()
assert.False(t, ok)
assert.Len(t, causes, 1)
Expand Down
34 changes: 34 additions & 0 deletions pkg/apis/agones/v1/gameserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,40 @@ func TestGameServerValidate(t *testing.T) {
assert.Len(t, causes, 1)
assert.Equal(t, "labels", causes[0].Field)

gs.Spec.Template.ObjectMeta.Labels = make(map[string]string)
gs.Spec.Template.ObjectMeta.Labels["agones.dev/longValueKey"] = longName
causes, ok = gs.Validate()
assert.False(t, ok)
assert.Len(t, causes, 1)
assert.Equal(t, "labels", causes[0].Field)

// Validate Labels and Annotations
gs.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
gs.Spec.Template.ObjectMeta.Annotations[longName] = longName
causes, ok = gs.Validate()
assert.False(t, ok)
assert.Len(t, causes, 2)

// No errors if valid Annotation was used
gs.Spec.Template.ObjectMeta.Labels = make(map[string]string)
gs.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
shortName := "agones.dev/shortName"
gs.Spec.Template.ObjectMeta.Annotations[shortName] = "shortValue"
causes, ok = gs.Validate()
assert.True(t, ok)
assert.Len(t, causes, 0)

gs.Spec.Template.ObjectMeta.Annotations[shortName] = longName
causes, ok = gs.Validate()
assert.True(t, ok)
assert.Len(t, causes, 0)

gs.Spec.Template.ObjectMeta.Annotations["agones.dev/short±Name"] = "shortValue"
causes, ok = gs.Validate()
assert.False(t, ok)
assert.Len(t, causes, 1)
assert.Equal(t, "annotations", causes[0].Field)

gs = GameServer{
Spec: GameServerSpec{
Ports: []GameServerPort{{Name: "one", PortPolicy: Passthrough, ContainerPort: 1294}, {PortPolicy: Passthrough, Name: "two", HostPort: 7890}},
Expand Down
18 changes: 18 additions & 0 deletions pkg/apis/agones/v1/gameserverset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,24 @@ func TestGameServerSetValidateUpdate(t *testing.T) {
assert.Len(t, causes, 1)
assert.Equal(t, "labels", causes[0].Field)

// Similar Annotations validation check
newGSS = gsSet.DeepCopy()
newGSS.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
newGSS.Spec.Template.ObjectMeta.Annotations[longName] = ""
causes, ok = newGSS.Validate()
assert.False(t, ok)
assert.Len(t, causes, 1)
assert.Equal(t, "annotations", causes[0].Field)

// Nested GS Spec Annotations
newGSS = gsSet.DeepCopy()
newGSS.Spec.Template.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
newGSS.Spec.Template.Spec.Template.ObjectMeta.Annotations[longName] = ""
causes, ok = newGSS.Validate()
assert.False(t, ok)
assert.Len(t, causes, 1)
assert.Equal(t, "annotations", causes[0].Field)

gsSet.Spec.Template.Spec.Template =
corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Expand Down
53 changes: 47 additions & 6 deletions test/e2e/fleet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -946,29 +946,70 @@ func TestFleetWithZeroReplicas(t *testing.T) {
assert.Empty(t, list)
}

// TestFleetWithLongLabels ensures that we can not create a fleet
// with label over 64 chars
func TestFleetWithLongLabels(t *testing.T) {
// TestFleetWithLongLabelsAnnotations ensures that we can not create a fleet
// with label over 64 chars and Annotations key over 64
func TestFleetWithLongLabelsAnnotations(t *testing.T) {
t.Parallel()
client := framework.AgonesClient.AgonesV1()
fleetSize := int32(1)
flt := defaultFleet(defaultNs)
flt.Spec.Replicas = fleetSize
normalLengthName := strings.Repeat("f", validation.LabelValueMaxLength)
longName := normalLengthName + "f"
flt.Spec.Template.ObjectMeta.Labels = make(map[string]string)
flt.Spec.Template.ObjectMeta.Labels["label"] = strings.Repeat("f", validation.LabelValueMaxLength+1)
flt.Spec.Template.ObjectMeta.Labels["label"] = longName
_, err := client.Fleets(defaultNs).Create(flt)
assert.NotNil(t, err)
statusErr, ok := err.(*k8serrors.StatusError)
assert.True(t, ok)
assert.True(t, len(statusErr.Status().Details.Causes) > 0)
assert.Len(t, statusErr.Status().Details.Causes, 1)
assert.Equal(t, metav1.CauseTypeFieldValueInvalid, statusErr.Status().Details.Causes[0].Type)
assert.Equal(t, "labels", statusErr.Status().Details.Causes[0].Field)

// Set Label to normal size and add Annotations with an error
flt.Spec.Template.ObjectMeta.Labels["label"] = normalLengthName
flt.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
flt.Spec.Template.ObjectMeta.Annotations[longName] = normalLengthName
_, err = client.Fleets(defaultNs).Create(flt)
assert.NotNil(t, err)
statusErr, ok = err.(*k8serrors.StatusError)
assert.True(t, ok)
assert.Len(t, statusErr.Status().Details.Causes, 1)
assert.Equal(t, "annotations", statusErr.Status().Details.Causes[0].Field)
assert.Equal(t, metav1.CauseTypeFieldValueInvalid, statusErr.Status().Details.Causes[0].Type)

goodFlt := defaultFleet(defaultNs)
goodFlt.Spec.Template.ObjectMeta.Labels = make(map[string]string)
goodFlt.Spec.Template.ObjectMeta.Labels["label"] = strings.Repeat("f", validation.LabelValueMaxLength)
goodFlt.Spec.Template.ObjectMeta.Labels["label"] = normalLengthName
goodFlt, err = client.Fleets(defaultNs).Create(goodFlt)
if assert.Nil(t, err) {
defer client.Fleets(defaultNs).Delete(goodFlt.ObjectMeta.Name, nil) // nolint:errcheck
}
err = framework.WaitForFleetCondition(t, goodFlt, e2e.FleetReadyCount(goodFlt.Spec.Replicas))
assert.Nil(t, err)

// Verify validation on Update()
flt, err = client.Fleets(defaultNs).Get(goodFlt.ObjectMeta.GetName(), metav1.GetOptions{})
assert.Nil(t, err)
goodFlt = flt.DeepCopy()
goodFlt.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
goodFlt.Spec.Template.ObjectMeta.Annotations[longName] = normalLengthName
_, err = client.Fleets(defaultNs).Update(goodFlt)
assert.NotNil(t, err)
statusErr, ok = err.(*k8serrors.StatusError)
assert.True(t, ok)
assert.Len(t, statusErr.Status().Details.Causes, 1)
assert.Equal(t,"annotations", statusErr.Status().Details.Causes[0].Field)
assert.Equal(t, metav1.CauseTypeFieldValueInvalid, statusErr.Status().Details.Causes[0].Type)

// Make sure normal annotations path Validation on Update
flt, err = client.Fleets(defaultNs).Get(goodFlt.ObjectMeta.GetName(), metav1.GetOptions{})
assert.Nil(t, err)
goodFlt = flt.DeepCopy()
goodFlt.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
goodFlt.Spec.Template.ObjectMeta.Annotations[normalLengthName] = longName
_, err = client.Fleets(defaultNs).Update(goodFlt)
assert.Nil(t, err)
}

// TestFleetRecreateGameServers tests various gameserver shutdown scenarios to ensure
Expand Down
18 changes: 18 additions & 0 deletions vendor/k8s.io/apimachinery/pkg/api/validation/doc.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 85 additions & 0 deletions vendor/k8s.io/apimachinery/pkg/api/validation/generic.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 6cb1cc8

Please sign in to comment.