Skip to content
This repository was archived by the owner on Oct 11, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/replication/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ go_library(
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/go.uber.org/zap:go_default_library",
"//vendor/k8s.io/api/admission/v1beta1:go_default_library",
"//vendor/k8s.io/api/authentication/v1:go_default_library",
"//vendor/k8s.io/api/authorization/v1:go_default_library",
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
Expand Down
33 changes: 20 additions & 13 deletions pkg/replication/admission.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/pkg/errors"
"go.uber.org/zap"
admissionv1beta1 "k8s.io/api/admission/v1beta1"
authenticationv1 "k8s.io/api/authentication/v1"
authz_v1 "k8s.io/api/authorization/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiext_v1b1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
Expand All @@ -37,6 +38,9 @@ import (
)

const (
// User account the replication controller uses
replicationUser = "system:serviceaccount:voyager:replication"

// key is the name of the annotation applied to the ServiceDescriptor
updatedKey = "mutationTimestamp"
hashKey = "mutationHash"
Expand Down Expand Up @@ -184,7 +188,7 @@ func (ac *AdmissionContext) servicedescriptorMutationAdmitFunc(ctx context.Conte
return admissionResponse, nil
}

patch, err := createAnnotationPatch(admissionRequest.Operation, newSD)
patch, err := createAnnotationPatch(admissionRequest.Operation, newSD, admissionRequest.UserInfo)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -332,8 +336,12 @@ func (ac *AdmissionContext) validateLocationsAndTransforms(sd *comp_v1.ServiceDe
return RejectionMessage(strings.Join(rejectionMessages, ", "))
}

func createAnnotationPatch(operation admissionv1beta1.Operation, newSD *comp_v1.ServiceDescriptor) ([]byte, error) {
ts, err := generateUpdated(operation, newSD)
func isReplicationController(userInfo authenticationv1.UserInfo) bool {
return userInfo.Username == replicationUser
}

func createAnnotationPatch(operation admissionv1beta1.Operation, newSD *comp_v1.ServiceDescriptor, userInfo authenticationv1.UserInfo) ([]byte, error) {
ts, err := generateUpdated(isReplicationController(userInfo), operation, newSD)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -451,7 +459,7 @@ func validateTimes(new time.Time, old time.Time) RejectionMessage {
// The "new" object is from the past - abort!
if new.Before(old) {
return RejectionMessage(fmt.Sprintf("You are attempting to override a Service Descriptor from %s with an older version from %s",
new.Format(time.RFC3339), old.Format(time.RFC3339)))
old.Format(time.RFC3339), new.Format(time.RFC3339)))
}

return ""
Expand Down Expand Up @@ -489,16 +497,15 @@ func addAnnotation(key, value string) util.Patch {
}
}

func generateUpdated(operation admissionv1beta1.Operation, newSD *comp_v1.ServiceDescriptor) (time.Time, error) {
if operation != admissionv1beta1.Update {
return time.Now(), nil
}
ts, exists := newSD.Annotations[updatedKey]
if !exists || ts == "" {
return time.Now(), nil
func generateUpdated(isReplication bool, operation admissionv1beta1.Operation, newSD *comp_v1.ServiceDescriptor) (time.Time, error) {
if isReplication {
ts, exists := newSD.Annotations[updatedKey]
if !exists {
return time.Now(), errors.New("replication controller must set the mutation timestamp")
}
return parseTimestamp(ts)
}

return parseTimestamp(ts)
return time.Now(), nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think we may need to keep the timestamp if hash hasn't changed, e.g. when someone adds/deletes annotation or finalizer.
So you need to pass a flag if hash has changed?

}

func generateSpecHash(sd *comp_v1.ServiceDescriptor) (string, error) {
Expand Down
12 changes: 9 additions & 3 deletions pkg/replication/admission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
admissionv1beta1 "k8s.io/api/admission/v1beta1"
authenticationv1 "k8s.io/api/authentication/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
Expand Down Expand Up @@ -546,7 +547,7 @@ func TestBackwardsTimestamp(t *testing.T) {
}),
})
require.NoError(t, err)
require.Equal(t, rejected("", "You are attempting to override a Service Descriptor from 2009-11-10T22:00:00Z with an older version from 2009-11-10T22:00:01Z"), resp)
require.Equal(t, rejected("", "You are attempting to override a Service Descriptor from 2009-11-10T22:00:01Z with an older version from 2009-11-10T22:00:00Z"), resp)
}

func TestEqualTimestamp(t *testing.T) {
Expand Down Expand Up @@ -652,7 +653,7 @@ func TestAddAnnotationsCreate(t *testing.T) {
assert.Equal(t, "3a619f41b19fe334cc7330a143138b4a8b5e0bf3", value[hashKey])
}

func TestAddAnnotationsUpdateKeepsSubmittedTS(t *testing.T) {
func TestAddAnnotationsUpdateKeepsSubmittedTSAsReplication(t *testing.T) {
t.Parallel()
resp, err := admitWithContextAndLogger(t, &admissionv1beta1.AdmissionRequest{
Operation: admissionv1beta1.Update,
Expand All @@ -673,6 +674,9 @@ func TestAddAnnotationsUpdateKeepsSubmittedTS(t *testing.T) {
},
Spec: getValidSdSpec(),
}),
UserInfo: authenticationv1.UserInfo{
Username: replicationUser,
},
})
require.NoError(t, err)
assert.True(t, resp.Allowed)
Expand All @@ -699,7 +703,7 @@ func TestEditExistingSD(t *testing.T) {
Object: objectToRawExtension(t, &comp_v1.ServiceDescriptor{
ObjectMeta: meta_v1.ObjectMeta{
Annotations: map[string]string{
updatedKey: "2009-11-10T22:00:01Z",
updatedKey: "2009-11-10T22:00:00Z",
},
},
Spec: comp_v1.ServiceDescriptorSpec{
Expand Down Expand Up @@ -779,6 +783,8 @@ func TestEditExistingSD(t *testing.T) {
})
require.NoError(t, err)
assert.True(t, resp.Allowed)
patches := getPatches(t, resp)
assert.NotEqual(t, "2009-11-10T22:00:00Z", patches[0].Value)
}

func assertSaneTime(t *testing.T, startTime time.Time, timeString string) {
Expand Down