Story #7127
Updated by daviddavis almost 4 years ago
# ## Proposal As a developer, it would be nice to be able to label pulp objects such as repositories. To accomplish this, I propose adding Kubernetes style labels to pulp objects (more information on kubernetes labels here: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/). Labels are arbitrary key value pairs that can be applied to objects and used to query them. For example, I could attach a `label1=foo`, `label2=foo`, and `label3=foobar` to a repository. The repository could then be queried by any of the following methods * `foo=bar`: select all objects that have the foo label set to bar * `foo!=bar`: select all objects that have the foo label set to anything except bar * `foo in (bar, foobar)`: selects all objects with the foo label that contain either the values for bar or foobar * `foo notin (bar, foobar)`: selects all objects with the foo label that don't contain bar or foobar * `foo`: selects all objects that contain the label foo (regardless of value) * `!foo`: selects all objects that don't contain the label foo # ## Use cases In galaxy_ng we need a way to filter repositories based on what they are used for. For example we are going to have the following repositories * `published` - contains locally published collections. Should be searchable. Is the default repo if no repo is provided * `staging` - content waiting for approval. Not searchable * `rejected` - content that has been rejected. Not searchable * `rh-certified` - content synced from automation hub. Contains red hat certified content. Searchable * `community` - content synced from galaxy. Searchable As well as an arbitrary number of repositories named inbound-<namespace_name> for uploading collections. Not searchable. Right now the names for these repos are hard coded as a way for the API to identify which content should go where, however with label support we could add the following labels * searchable= true | false * default=true | false * content-readiness= production | inbound | staging * certification= community | rh-certified | local With these labels we can: * limit search results to repos that match `searchable=true` * separate inbound repos with `content-readiness!=inbound` * identify which repositories contain certified content with `certification=rh-certified` # Design ## API Design ### Filtering Labels can be filtered by passing a urlencoded string to a `label_selector` parameter. Some examples based on [the kubernetes documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api): * `?label_selector=environment%3Dproduction,tier%3Dfrontend` * Evaluates to `environment=production,tier=frontend` * `?label_selector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29` * Evaluates to `environment in (production,qa),tier in (frontend)` Note: Ansible Galaxy and RHUI have agreed that for a first pass, we could just support a subset of operators (ie `=` and `!=`). #### LabelSelectFilter `LabelSelectFilter` would be a `django_filter.Filter` that parses the label_select parameter and then filters the queryset. It can be applied to a Queryset of any model with labels. Note: for an example of a complex `Filter`, [see the `RepositoryVersionFilter`](https://git.io/JIJif). ### LabelSerializer Create a new `LabelSerializer` that can be nested into other model serializers as a field (much like the `CreatedResourceSerializer`). This serializer should be both readable and writable and should enable the following API calls. #### Reading ``` # GET /pulp/api/v3/repositories/file/file/ { ... "labels": {"foo": "bar", "foo2": "baz"}, ... } ``` #### Setting/Updating ``` # POST /pulp/api/v3/repositories/file/file/ name=test labels='[{"foo": "bar"}]' { ... "labels": {"foo": "bar"}, ... } # PUT /pulp/api/v3/repositories/file/file/<uuid>/ labels='[{"foo": "baz"}]' { ... "labels": {"foo": "baz"}, ... } ``` ## Database Design #### Label (extends GenericRelationModel) * **resource** - generic foreign key * **key** - the key of the label * **value** - the value for a label Constraints * `Label` resource and key are unique together * We should also limit key to alphanumerics and a certain number of chars (100?)