Skip to content

[ROX-12622] : Add create collection service#3600

Merged
charmik-redhat merged 3 commits intomasterfrom
ROX-12622/charmik/create-collection-endpoint
Oct 31, 2022
Merged

[ROX-12622] : Add create collection service#3600
charmik-redhat merged 3 commits intomasterfrom
ROX-12622/charmik/create-collection-endpoint

Conversation

@charmik-redhat
Copy link
Copy Markdown
Contributor

@charmik-redhat charmik-redhat commented Oct 27, 2022

Description

Added REST endpoint for creating a new collection.

Checklist

  • Investigated and inspected CI test results
  • Unit test and regression tests added
  • [ ] Evaluated and added CHANGELOG entry if required
  • [ ] Determined and documented upgrade steps
  • Documented user facing changes (create PR based on openshift/openshift-docs and merge into rhacs-docs)

If any of these don't apply, please comment below.

Testing Performed

Unit tests added.

In addition to reviewing your code, reviewers must also review your testing
instructions and make sure they are sufficient.

Copy link
Copy Markdown
Contributor

@keyallis keyallis left a comment

Choose a reason for hiding this comment

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

The service layer should be pretty slim, left some review comments of things you can trim down on since the functionality will be in the datastore layer

Comment on lines +103 to +112
nameQuery := search.NewQueryBuilder().AddExactMatches(search.CollectionName, request.GetName()).ProtoQuery()
c, err := s.datastore.Count(ctx, nameQuery)
if err != nil {
return nil, err
}
if c != 0 {
return nil, errors.Wrap(errox.AlreadyExists, "A collection with that name already exists")
}
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.

Datastore level will certify that the name is not already in use

}

collection := &storage.ResourceCollection{
Id: uuid.NewV4().String(),
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.

Datastore level will assign the ID

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Don't see that in datastore's AddCollection implementation. Is that something currently in review? Or I can add this line to datastore level.

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.

Comment on lines +121 to +122
CreatedAt: protoconv.ConvertTimeToTimestamp(time.Now()),
CreatedBy: creator,
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.

We should also be setting the UpdatedAt and UpdatedBy fields

Comment on lines +117 to +139
collection := &storage.ResourceCollection{
Id: uuid.NewV4().String(),
Name: request.GetName(),
Description: request.GetDescription(),
CreatedAt: protoconv.ConvertTimeToTimestamp(time.Now()),
CreatedBy: creator,
ResourceSelectors: request.GetResourceSelectors(),
}
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.

This creation could be abstracted out into standalone function that takes a request object and just fills out the fields since that operation will need to be done for Add, DryRun, Update


return &storage.SlimUser{
Id: ctxIdentity.UID(),
Name: ctxIdentity.FullName(),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@keyallis @md2119
Identity has FullName and FriendlyName among other things. Is it correct to set the name to FullName here?

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.

There is func for that UserFromContext(ctx context.Context)

@ghost
Copy link
Copy Markdown

ghost commented Oct 27, 2022

Images are ready for the commit at d1cf445.

To use with deploy scripts, first export MAIN_IMAGE_TAG=3.72.x-451-gd1cf445861.

@charmik-redhat charmik-redhat force-pushed the ROX-12622/charmik/create-collection-endpoint branch from 997d790 to a866a3e Compare October 28, 2022 17:58
Copy link
Copy Markdown
Contributor

@keyallis keyallis left a comment

Choose a reason for hiding this comment

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

Just one comment on future work but otherwise LGTM

Comment on lines +121 to +139
func collectionRequestToCollection(ctx context.Context, request collectionRequest, isCreate bool) (*storage.ResourceCollection, error) {
user := utils.UserFromContext(ctx)
if user == nil {
return nil, errors.New("User identity not provided")
}

timeNow := protoconv.ConvertTimeToTimestamp(time.Now())

collection := &storage.ResourceCollection{
Name: request.GetName(),
Description: request.GetDescription(),
LastUpdated: timeNow,
UpdatedBy: user,
ResourceSelectors: request.GetResourceSelectors(),
}
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.

You might have to do some digging to figure out a clean way of doing this (maybe generics!) but for future work we need to also include the Id field population in the object creation for Update requests

Copy link
Copy Markdown
Contributor Author

@charmik-redhat charmik-redhat Oct 28, 2022

Choose a reason for hiding this comment

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

Ah yes, I will add an idGetter func() string to the arguments, and update can then pass func() {return request.GetId() } as that func.

About generics, I thought to do it using generics, but since we are calling functions GetName, GetDescription, etc on the passed obj, if I call them on generic type R, compilation would fail. The solution for that is to constrain the generic type using an interface. In this case the constraining interface would look like

type collectionRequest interface {
    *v1.CreateCollectionRequest | *v1.DryRunCollectionRequest | *v1.UpdateCollectionRequest
}

func [R collectionRequest] collectionRequestToCollection(ctx context, request R, isCreate bool) {...}

However, this fails to compile too since go 1.18 doesn't have a good support for union of structs within a constraining interface. Since *v1.CreateCollectionRequest and others are structs and not interfaces themselves, GetName, etc are still not accessible from collectionRequest.

The workaround for this is to then add those methods to the constraining interface as well, which makes the interface look like

type collectionRequest interface {
	*v1.CreateCollectionRequest

	GetName() string
	GetDescription() string
	GetResourceSelectors() []*storage.ResourceSelector
	GetEmbeddedCollectionIds() []string
}

This works, but then I still had to put those methods in the interface. so I just avoided the generics altogether for this case.

Copy link
Copy Markdown
Contributor

@md2119 md2119 left a comment

Choose a reason for hiding this comment

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

Some minor comments, otherwise lgtm.

// CreateCollection creates a new collection from the given request
func (s *serviceImpl) CreateCollection(ctx context.Context, request *v1.CreateCollectionRequest) (*v1.CreateCollectionResponse, error) {
if !features.ObjectCollections.Enabled() {
return nil, 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.

return error

func collectionRequestToCollection(ctx context.Context, request collectionRequest, isCreate bool) (*storage.ResourceCollection, error) {
user := utils.UserFromContext(ctx)
if user == nil {
return nil, errors.New("User identity not provided")
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.

because it implied from the context could not determine user identity seems more appropriate

Description: request.GetDescription(),
LastUpdated: timeNow,
UpdatedBy: user,
ResourceSelectors: request.GetResourceSelectors(),
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.

valid resource selectors are non-empty

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added an error on empty resource selectors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines +104 to +102
if request.GetName() == "" {
return nil, errors.Wrap(errox.InvalidArgs, "Collection name should not be empty")
}
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.

move this into collectionRequestToCollection(...)

@charmik-redhat charmik-redhat force-pushed the ROX-12622/charmik/create-collection-endpoint branch from a866a3e to d1cf445 Compare October 31, 2022 17:33
Comment on lines +144 to +146
} else if getID != nil {
collection.Id = getID()
}
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.

implying getID wrt isCreate is confusing. Strongly recommend dropping this check and explicitly basing the condition on create and update workflow.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah, I merged this PR before noticing the comment. I will add it in my Delete collections service PR. Should I change to something like below?

if isCreate {...}
else {
    if getID == nil {
        return nil, err
    }
    collection.Id = getID()
}

@charmik-redhat charmik-redhat merged commit 3f9b423 into master Oct 31, 2022
@charmik-redhat charmik-redhat deleted the ROX-12622/charmik/create-collection-endpoint branch October 31, 2022 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants