feat(workers): implement worker service add/set/remove api tags
This commit is contained in:
1 parent
d5633952db
commit
28f53a64b4
15 files changed
+2354
-192
No files matched your search
@@ -44,6 +44,9 @@ var (
|
||||
action.Read,
|
||||
action.Update,
|
||||
action.Delete,
|
||||
action.AddWorkerTags,
|
||||
action.SetWorkerTags,
|
||||
action.RemoveWorkerTags,
|
||||
}
|
||||
|
||||
// CollectionActions contains the set of actions that can be performed on
|
||||
@@ -297,6 +300,114 @@ func (s Service) UpdateWorker(ctx context.Context, req *pbs.UpdateWorkerRequest)
|
||||
return &pbs.UpdateWorkerResponse{Item: item}, nil
|
||||
}
|
||||
|
||||
// AddWorkerTags implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) AddWorkerTags(ctx context.Context, req *pbs.AddWorkerTagsRequest) (*pbs.AddWorkerTagsResponse, error) {
|
||||
const op = "workers.(Service).AddWorkerTags"
|
||||
|
||||
if err := validateAddTagsRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetId(), action.AddWorkerTags)
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
w, err := s.addTagsInRepo(ctx, req.GetId(), req.GetVersion(), req.GetApiTags())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputFields, ok := requests.OutputFields(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, w.GetPublicId(), IdActions).Strings()))
|
||||
}
|
||||
item, err := toProto(ctx, w, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pbs.AddWorkerTagsResponse{Item: item}, nil
|
||||
}
|
||||
|
||||
// SetWorkerTags implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) SetWorkerTags(ctx context.Context, req *pbs.SetWorkerTagsRequest) (*pbs.SetWorkerTagsResponse, error) {
|
||||
const op = "workers.(Service).SetWorkerTags"
|
||||
|
||||
if err := validateSetTagsRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetId(), action.SetWorkerTags)
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
w, err := s.setTagsInRepo(ctx, req.GetId(), req.GetVersion(), req.GetApiTags())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputFields, ok := requests.OutputFields(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, w.GetPublicId(), IdActions).Strings()))
|
||||
}
|
||||
item, err := toProto(ctx, w, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pbs.SetWorkerTagsResponse{Item: item}, nil
|
||||
}
|
||||
|
||||
// RemoveWorkerTags implements the interface pbs.WorkerServiceServer.
|
||||
func (s Service) RemoveWorkerTags(ctx context.Context, req *pbs.RemoveWorkerTagsRequest) (*pbs.RemoveWorkerTagsResponse, error) {
|
||||
const op = "workers.(Service).RemoveWorkerTags"
|
||||
|
||||
if err := validateRemoveTagsRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetId(), action.RemoveWorkerTags)
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
w, err := s.removeTagsInRepo(ctx, req.GetId(), req.GetVersion(), req.GetApiTags())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputFields, ok := requests.OutputFields(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, w.GetPublicId(), IdActions).Strings()))
|
||||
}
|
||||
item, err := toProto(ctx, w, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pbs.RemoveWorkerTagsResponse{Item: item}, nil
|
||||
}
|
||||
|
||||
func (s Service) listFromRepo(ctx context.Context, scopeIds []string) ([]*server.Worker, error) {
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
@@ -390,6 +501,87 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s Service) addTagsInRepo(ctx context.Context, workerId string, workerVersion uint32, addTags map[string]*structpb.ListValue) (*server.Worker, error) {
|
||||
const op = "workers.(Service).addTagsInRepo"
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tags := make([]*server.Tag, 0, len(addTags))
|
||||
for k, lv := range addTags {
|
||||
for _, v := range lv.GetValues() {
|
||||
tags = append(tags, &server.Tag{Key: k, Value: v.GetStringValue()})
|
||||
}
|
||||
}
|
||||
_, err = repo.AddWorkerTags(ctx, workerId, workerVersion, tags)
|
||||
if err != nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add worker tags in repo: %v.", err)
|
||||
}
|
||||
w, err := repo.LookupWorker(ctx, workerId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up worker after adding tags"))
|
||||
}
|
||||
if w == nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to look up worker after adding tags.")
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (s Service) setTagsInRepo(ctx context.Context, workerId string, workerVersion uint32, setTags map[string]*structpb.ListValue) (*server.Worker, error) {
|
||||
const op = "workers.(Service).setTagsInRepo"
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tags := make([]*server.Tag, 0, len(setTags))
|
||||
for k, lv := range setTags {
|
||||
for _, v := range lv.GetValues() {
|
||||
tags = append(tags, &server.Tag{Key: k, Value: v.GetStringValue()})
|
||||
}
|
||||
}
|
||||
_, err = repo.SetWorkerTags(ctx, workerId, workerVersion, tags)
|
||||
if err != nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set worker tags in repo: %v.", err)
|
||||
}
|
||||
w, err := repo.LookupWorker(ctx, workerId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up worker after setting tags"))
|
||||
}
|
||||
if w == nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to look up worker after setting tags.")
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (s Service) removeTagsInRepo(ctx context.Context, workerId string, workerVersion uint32, removeTags map[string]*structpb.ListValue) (*server.Worker, error) {
|
||||
const op = "workers.(Service).removeTagsInRepo"
|
||||
repo, err := s.repoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tags := make([]*server.Tag, 0, len(removeTags))
|
||||
for k, lv := range removeTags {
|
||||
for _, v := range lv.GetValues() {
|
||||
tags = append(tags, &server.Tag{Key: k, Value: v.GetStringValue()})
|
||||
}
|
||||
}
|
||||
_, err = repo.DeleteWorkerTags(ctx, workerId, workerVersion, tags)
|
||||
if err != nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove worker tags in repo: %v.", err)
|
||||
}
|
||||
w, err := repo.LookupWorker(ctx, workerId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up worker after removing tags"))
|
||||
}
|
||||
if w == nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to look up worker after removing tags.")
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.VerifyResults {
|
||||
res := auth.VerifyResults{}
|
||||
repo, err := s.repoFn()
|
||||
@@ -485,6 +677,13 @@ func toProto(ctx context.Context, in *server.Worker, opt ...handlers.Option) (*p
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error preparing config tags proto"))
|
||||
}
|
||||
}
|
||||
if outputFields.Has(globals.ApiTagsField) && len(in.GetApiTags()) > 0 {
|
||||
var err error
|
||||
out.ApiTags, err = tagsToMapProto(in.GetApiTags())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error preparing api tags proto"))
|
||||
}
|
||||
}
|
||||
if outputFields.Has(globals.CanonicalTagsField) && len(in.CanonicalTags()) > 0 {
|
||||
var err error
|
||||
out.CanonicalTags, err = tagsToMapProto(in.CanonicalTags())
|
||||
@@ -615,3 +814,124 @@ func validateCreateRequest(req *pbs.CreateWorkerLedRequest) error {
|
||||
return badFields
|
||||
})
|
||||
}
|
||||
|
||||
// validateStringForDb checks a string is valid for db storage and returns a string for an error message if needed.
|
||||
// returns an empty string otherwise.
|
||||
func validateStringForDb(str string) string {
|
||||
switch {
|
||||
case len(str) <= 0:
|
||||
return "must be non-empty."
|
||||
case len(str) > 512:
|
||||
return "must be within 512 characters."
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func validateAddTagsRequest(req *pbs.AddWorkerTagsRequest) error {
|
||||
badFields := map[string]string{}
|
||||
if !handlers.ValidId(handlers.Id(req.GetId()), server.WorkerPrefix) {
|
||||
badFields[globals.IdField] = "Incorrectly formatted identifier."
|
||||
}
|
||||
if req.GetVersion() == 0 {
|
||||
badFields[globals.VersionField] = "Required field."
|
||||
}
|
||||
if req.GetApiTags() == nil {
|
||||
badFields[globals.ApiTagsField] = "Must be non-empty."
|
||||
}
|
||||
for k, lv := range req.GetApiTags() {
|
||||
if err := validateStringForDb(k); err != "" {
|
||||
badFields[globals.ApiTagsField] = "Tag keys " + err
|
||||
break
|
||||
}
|
||||
if lv.GetValues() == nil {
|
||||
badFields[globals.ApiTagsField] = "Tag values must be non-empty."
|
||||
break
|
||||
}
|
||||
for _, v := range lv.GetValues() {
|
||||
if _, ok := v.GetKind().(*structpb.Value_StringValue); !ok {
|
||||
badFields[globals.ApiTagsField] = "Tag values must be strings."
|
||||
break
|
||||
}
|
||||
if err := validateStringForDb(v.GetStringValue()); err != "" {
|
||||
badFields[globals.ApiTagsField] = "Tag values " + err
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(badFields) > 0 {
|
||||
return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSetTagsRequest(req *pbs.SetWorkerTagsRequest) error {
|
||||
badFields := map[string]string{}
|
||||
if !handlers.ValidId(handlers.Id(req.GetId()), server.WorkerPrefix) {
|
||||
badFields[globals.IdField] = "Incorrectly formatted identifier."
|
||||
}
|
||||
if req.GetVersion() == 0 {
|
||||
badFields[globals.VersionField] = "Required field."
|
||||
}
|
||||
for k, lv := range req.GetApiTags() {
|
||||
if err := validateStringForDb(k); err != "" {
|
||||
badFields[globals.ApiTagsField] = "Tag keys " + err
|
||||
break
|
||||
}
|
||||
if lv.GetValues() == nil {
|
||||
badFields[globals.ApiTagsField] = "Tag values must be non-empty."
|
||||
break
|
||||
}
|
||||
for _, v := range lv.GetValues() {
|
||||
if _, ok := v.GetKind().(*structpb.Value_StringValue); !ok {
|
||||
badFields[globals.ApiTagsField] = "Tag values must be strings."
|
||||
break
|
||||
}
|
||||
if err := validateStringForDb(v.GetStringValue()); err != "" {
|
||||
badFields[globals.ApiTagsField] = "Tag values " + err
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(badFields) > 0 {
|
||||
return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateRemoveTagsRequest(req *pbs.RemoveWorkerTagsRequest) error {
|
||||
badFields := map[string]string{}
|
||||
if !handlers.ValidId(handlers.Id(req.GetId()), server.WorkerPrefix) {
|
||||
badFields[globals.IdField] = "Incorrectly formatted identifier."
|
||||
}
|
||||
if req.GetVersion() == 0 {
|
||||
badFields[globals.VersionField] = "Required field."
|
||||
}
|
||||
if req.GetApiTags() == nil {
|
||||
badFields[globals.ApiTagsField] = "Must be non-empty."
|
||||
}
|
||||
for k, lv := range req.GetApiTags() {
|
||||
if err := validateStringForDb(k); err != "" {
|
||||
badFields[globals.ApiTagsField] = "Tag keys " + err
|
||||
break
|
||||
}
|
||||
if lv.GetValues() == nil {
|
||||
badFields[globals.ApiTagsField] = "Tag values must be non-empty."
|
||||
break
|
||||
}
|
||||
for _, v := range lv.GetValues() {
|
||||
if _, ok := v.GetKind().(*structpb.Value_StringValue); !ok {
|
||||
badFields[globals.ApiTagsField] = "Tag values must be strings."
|
||||
break
|
||||
}
|
||||
if err := validateStringForDb(v.GetStringValue()); err != "" {
|
||||
badFields[globals.ApiTagsField] = "Tag values " + err
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(badFields) > 0 {
|
||||
return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -37,7 +37,7 @@ import (
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
var testAuthorizedActions = []string{"no-op", "read", "update", "delete"}
|
||||
var testAuthorizedActions = []string{"no-op", "read", "update", "delete", "add-worker-tags", "set-worker-tags", "remove-worker-tags"}
|
||||
|
||||
func structListValue(t *testing.T, ss ...string) *structpb.ListValue {
|
||||
t.Helper()
|
||||
@@ -50,6 +50,26 @@ func structListValue(t *testing.T, ss ...string) *structpb.ListValue {
|
||||
return lv
|
||||
}
|
||||
|
||||
func equalTags(t *testing.T, expected map[string]*structpb.ListValue, actual map[string]*structpb.ListValue) bool {
|
||||
t.Helper()
|
||||
if len(expected) != len(actual) {
|
||||
return false
|
||||
}
|
||||
for eK, eValList := range expected {
|
||||
found := false
|
||||
for k, valList := range actual {
|
||||
if eK == k && eValList.String() == valList.String() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrap := db.TestWrapper(t)
|
||||
@@ -1295,3 +1315,479 @@ func TestCreateWorkerLed(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_AddWorkerTags(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
_, proj := iam.TestScopes(t, iamRepo)
|
||||
rw := db.New(conn)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
repoFn := func() (*server.Repository, error) {
|
||||
return server.NewRepository(rw, rw, testKms)
|
||||
}
|
||||
s, err := NewService(context.Background(), repoFn, iamRepoFn)
|
||||
require.NoError(err)
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
req *pbs.AddWorkerTagsRequest
|
||||
wantTags map[string]*structpb.ListValue
|
||||
wantErrContains string
|
||||
}{
|
||||
{
|
||||
name: "bad-id",
|
||||
req: &pbs.AddWorkerTagsRequest{
|
||||
Id: "bad_id",
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
wantErrContains: "Incorrectly formatted identifier.",
|
||||
},
|
||||
{
|
||||
name: "nil-version",
|
||||
req: &pbs.AddWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
wantErrContains: "Required field.",
|
||||
},
|
||||
{
|
||||
name: "nil-tags",
|
||||
req: &pbs.AddWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
},
|
||||
wantErrContains: "Must be non-empty.",
|
||||
},
|
||||
{
|
||||
name: "valid-tags",
|
||||
req: &pbs.AddWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
wantTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
{
|
||||
name: "many-valid-tags",
|
||||
req: func() *pbs.AddWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.AddWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value"), structpb.NewStringValue("value2")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value"), structpb.NewStringValue("value2")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid-tag-value",
|
||||
req: func() *pbs.AddWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.AddWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewBoolValue(false)}}},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Tag values must be strings.",
|
||||
},
|
||||
{
|
||||
name: "mixed-invalid-tags",
|
||||
req: func() *pbs.AddWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.AddWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"": {Values: nil},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{nil}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Tag keys must be non-empty.",
|
||||
},
|
||||
{
|
||||
name: "duplicate-tags",
|
||||
req: func() *pbs.AddWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.AddWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2"), structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Unable to add worker tags in repo",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := s.AddWorkerTags(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), tc.req)
|
||||
if len(tc.wantErrContains) > 0 {
|
||||
assert.Nil(got)
|
||||
assert.Contains(err.Error(), tc.wantErrContains)
|
||||
}
|
||||
if tc.wantTags != nil {
|
||||
assert.Nil(err)
|
||||
assert.True(equalTags(t, tc.wantTags, got.GetItem().GetApiTags()), "want tags: %q got: %q", tc.wantTags, got.GetItem().GetApiTags())
|
||||
assert.Equal(tc.req.Version+1, got.GetItem().GetVersion())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_SetWorkerTags(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
_, proj := iam.TestScopes(t, iamRepo)
|
||||
rw := db.New(conn)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
repoFn := func() (*server.Repository, error) {
|
||||
return server.NewRepository(rw, rw, testKms)
|
||||
}
|
||||
s, err := NewService(context.Background(), repoFn, iamRepoFn)
|
||||
require.NoError(err)
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
req *pbs.SetWorkerTagsRequest
|
||||
wantTags map[string]*structpb.ListValue
|
||||
wantErrContains string
|
||||
}{
|
||||
{
|
||||
name: "bad-id",
|
||||
req: &pbs.SetWorkerTagsRequest{
|
||||
Id: "bad_id",
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
wantErrContains: "Incorrectly formatted identifier.",
|
||||
},
|
||||
{
|
||||
name: "nil-version",
|
||||
req: &pbs.SetWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
wantErrContains: "Required field.",
|
||||
},
|
||||
{
|
||||
name: "nil-tags",
|
||||
req: &pbs.SetWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
},
|
||||
wantTags: map[string]*structpb.ListValue{},
|
||||
},
|
||||
{
|
||||
name: "valid-tags",
|
||||
req: func() *pbs.SetWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.SetWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
}
|
||||
}(),
|
||||
wantTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
{
|
||||
name: "many-valid-tags",
|
||||
req: func() *pbs.SetWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.SetWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value"), structpb.NewStringValue("value2")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value"), structpb.NewStringValue("value2")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid-tag-value",
|
||||
req: func() *pbs.SetWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.SetWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewBoolValue(false)}}},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Tag values must be strings.",
|
||||
},
|
||||
{
|
||||
name: "mixed-invalid-tags",
|
||||
req: func() *pbs.SetWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.SetWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: nil},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Tag values must be non-empty.",
|
||||
},
|
||||
{
|
||||
name: "duplicate-tags",
|
||||
req: func() *pbs.SetWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.SetWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2"), structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Unable to set worker tags in repo",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := s.SetWorkerTags(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), tc.req)
|
||||
if len(tc.wantErrContains) > 0 {
|
||||
assert.Nil(got)
|
||||
assert.Contains(err.Error(), tc.wantErrContains)
|
||||
}
|
||||
if tc.wantTags != nil {
|
||||
assert.Nil(err)
|
||||
assert.True(equalTags(t, tc.wantTags, got.GetItem().GetApiTags()))
|
||||
assert.Equal(tc.req.Version+1, got.GetItem().GetVersion())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_RemoveWorkerTags(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
_, proj := iam.TestScopes(t, iamRepo)
|
||||
rw := db.New(conn)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
repoFn := func() (*server.Repository, error) {
|
||||
return server.NewRepository(rw, rw, testKms)
|
||||
}
|
||||
s, err := NewService(context.Background(), repoFn, iamRepoFn)
|
||||
require.NoError(err)
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
req *pbs.RemoveWorkerTagsRequest
|
||||
wantDeletedTags map[string]*structpb.ListValue
|
||||
wantErrContains string
|
||||
}{
|
||||
{
|
||||
name: "bad-id",
|
||||
req: &pbs.RemoveWorkerTagsRequest{
|
||||
Id: "bad_id",
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
wantErrContains: "Incorrectly formatted identifier.",
|
||||
},
|
||||
{
|
||||
name: "nil-version",
|
||||
req: &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
wantErrContains: "Required field.",
|
||||
},
|
||||
{
|
||||
name: "nil-tags",
|
||||
req: &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
},
|
||||
wantErrContains: "Must be non-empty.",
|
||||
},
|
||||
{
|
||||
name: "remove-valid-tag",
|
||||
req: func() *pbs.RemoveWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
|
||||
worker.Version, map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}})
|
||||
return &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version + 1,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
}
|
||||
}(),
|
||||
wantDeletedTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}}},
|
||||
},
|
||||
{
|
||||
name: "remove-many-valid-tags",
|
||||
req: func() *pbs.RemoveWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
|
||||
worker.Version, map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value"), structpb.NewStringValue("value1")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
"key5": {Values: []*structpb.Value{structpb.NewStringValue("value5")}},
|
||||
"key6": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
})
|
||||
return &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version + 1,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value"), structpb.NewStringValue("value1")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
"key5": {Values: []*structpb.Value{structpb.NewStringValue("value5")}},
|
||||
"key6": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantDeletedTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
"key5": {Values: []*structpb.Value{structpb.NewStringValue("value5")}},
|
||||
"key6": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid-tag-value",
|
||||
req: func() *pbs.RemoveWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{"key": {Values: []*structpb.Value{structpb.NewBoolValue(false)}}},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Tag values must be strings.",
|
||||
},
|
||||
{
|
||||
name: "mixed-invalid-tags",
|
||||
req: func() *pbs.RemoveWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key": {Values: nil},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Tag values must be non-empty.",
|
||||
},
|
||||
{
|
||||
name: "remove-nonexistent-tags",
|
||||
req: func() *pbs.RemoveWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
s.addTagsInRepo(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), worker.PublicId,
|
||||
worker.Version, map[string]*structpb.ListValue{
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
"key5": {Values: []*structpb.Value{structpb.NewStringValue("value5")}},
|
||||
"key6": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
})
|
||||
return &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version + 1,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"no-key": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2")}},
|
||||
"key": {Values: []*structpb.Value{structpb.NewStringValue("value")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Unable to remove worker tags in repo:",
|
||||
},
|
||||
{
|
||||
name: "duplicate-tags",
|
||||
req: func() *pbs.RemoveWorkerTagsRequest {
|
||||
worker := server.TestKmsWorker(t, conn, wrapper)
|
||||
return &pbs.RemoveWorkerTagsRequest{
|
||||
Id: worker.PublicId,
|
||||
Version: worker.Version,
|
||||
ApiTags: map[string]*structpb.ListValue{
|
||||
"key2": {Values: []*structpb.Value{structpb.NewStringValue("value2"), structpb.NewStringValue("value2")}},
|
||||
"key3": {Values: []*structpb.Value{structpb.NewStringValue("value3")}},
|
||||
"key4": {Values: []*structpb.Value{structpb.NewStringValue("value4")}},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
wantErrContains: "Unable to remove worker tags in repo",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := s.RemoveWorkerTags(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), tc.req)
|
||||
if len(tc.wantErrContains) > 0 {
|
||||
assert.Nil(got)
|
||||
assert.Contains(err.Error(), tc.wantErrContains)
|
||||
}
|
||||
if tc.wantDeletedTags != nil {
|
||||
assert.Nil(err)
|
||||
assert.False(equalTags(t, tc.wantDeletedTags, got.GetItem().GetApiTags()))
|
||||
assert.Equal(tc.req.Version+1, got.GetItem().GetVersion())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user