Add Tags to Neutron Resources

https://blueprints.launchpad.net/neutron/+spec/add-tags-to-core-resources

Neutron resources in current DB model do not contain any tags, and don’t have a generic consistent way to add tags or/and any other data by the user. Tagging resources can be used by external systems or any other clients of the Neutron REST API (and NOT backend drivers).

The following use cases refer to adding tags to networks, but the same can be applicable to any other Neutron resource:

  1. Ability to map different networks in different OpenStack locations to one logically same network (for Multi site OpenStack)
  2. Ability to map Id’s from different management/orchestration systems to OpenStack networks in mixed environments, for example for project Kuryr, map docker network id to neutron network id
  3. Leverage tags by deployment tools
  4. allow operators to tag information about provider networks (e.g. high-bandwith, low-latency, etc)
  5. new features like get-me-a-network or a similar port scheduler could choose a network for a port based on tags

Problem Description

In most popular REST API interfaces, objects in the domain model can be “tagged” with zero or more simple strings. These strings may then be used to group and categorize objects in the domain model.

In order to align Neutron’s REST API with the Internet’s common understanding of resource tagging, we can add an API that allows normal users to add, remove and list tags for a neutron resource.

Proposed Change

This spec is for adding a new way for API users to be able to tag their neutron resources with simple strings.

Add an API that allows a user to add, remove, and list tags for a resource.

Similar to the approved nova spec tag instances, and in accordance to these guidelines.

This spec proposes to support adding tags to Neutron resources which are not meant to be interpreted by any specific backend implementation. In the proposed implementation tags will only be visible in the API level and not be available in the plugin level.

Data Model Impact

The tag is an opaque string and is not intended to be interpreted or even read by the Neutron backends.

For the database schema, the following table constructs would suffice:

CREATE TABLE tags (
    standard_attribute_id BIGINT NOT NULL FOREIGN KEY,
    tag VARCHAR(60) NOT NULL CHARACTER SET utf8
     COLLATION utf8_ci PRIMARY KEY,
);

For example adding a tag “blue” to network with standard_attribute_id 16 will introduce the following entry:

standard_attribute_id : 16 tag: “blue”

REST API examples can be found in the next section.

In this table schema the tag is a string value attached to this resource.

Neutron implementation now have a common resource object for every type which is saved in the DB. view common neutron object for more details. standard_attribute_id reference the Neutron resource entry in that common table for every tag entry we add. Adding this references in the entry can help us keep data integrity and make sure that all references for a specific resource are deleted when the resource itself is deleted.

Authorization to manage the tag equates with that for the resource which the tag is attached.

REST API Impact

The tag CRUD operations API would look like the following:

A list of tags for the specified network returns with the network details information

GET /v2.0/networks/{network_id}

Response

{
    'id': {network_id},

    ... other network resource properties ...

    'tags': ['foo', 'bar', 'baz']
}

Get only a list of tags for the specified network

GET /V2.0/networks/{network_id}.json?fields=tags

Response

{
    'tags': ['foo', 'bar', 'baz']
}

Replace set of tags on a network

PUT /v2.0/networks/{network_id}/tags

with request payload

{
    'tags': ['foo', 'bar', 'baz']
}

Response

{
    'tags': ['foo', 'bar', 'baz']
}

If the number of tags exceeds the limit of tags per network, shall return a 400 Bad Request (tags limit is either hard coded or configurable in neutron conf file)

Add a single tag on a network

PUT /v2.0/networks/{network_id}/tags/{tag}

Returns 201 Created.

If the tag already exists, no error is raised, it just returns the 409 Conflict

Check if a tag exists or not on a network

GET /v2.0/networks/{network_id}/tags/{tag}

Returns 204 No Content if tag exist on a network.

Returns 404 Not Found if tag doesn’t exist on a network.

Remove a single tag on a network

DELETE /v2.0/networks/{network_id}/tags/{tag}

Returns 204 No Content upon success. Returns a 404 Not Found if you attempt to delete a tag that does not exist.

Remove all tags on a network

DELETE /v2.0/networks/{network_id}/tags

Returns 204 No Content.

The API that would allow searching/filtering of the GET /v2.0/networks REST API call would add the following query parameters:

  • tags
  • tags-any
  • not-tags
  • not-tags-any

To request the list of networks that have a single tag, tags argument should be set to the desired tag name. Example:

GET /v2.0/networks?tags=red

To request the list of networks that have two or more tags, the tags argument should be set to the list of tags, separated by commas. In this situation the tags given must all be present for a network to be included in the query result. Example that returns networks that have the “red” and “blue” tags:

GET /v2.0/networks?tags=red,blue

To request the list of networks that have one or more of a list of given tags, the tags-any argument should be set to the list of tags, separated by commas. In this situation as long as one of the given tags is present the network will be included in the query result. Example that returns the networks that have the “red” or the “blue” tag:

GET /v2.0/networks?tags-any=red,blue

To request the list of networks that do not have one or more tags, the not-tags argument should be set to the list of tags, separated by commas. In this situation only the networks that do not have any of the given tags will be included in the query results. Example that returns the networks that do not have the “red” nor the “blue” tag:

GET /v2.0/networks?not-tags=red,blue

To request the list of networks that do not have at least one of a list of tags, the not-tags-any argument should be set to the list of tags, separated by commas. In this situation only the networks that do not have at least one of the given tags will be included in the query result. Example that returns the networks that do not have the “red” tag, or do not have the “blue” tag:

GET /v2.0/networks?not-tags-any=red,blue

The tags, tags-any, not-tags and not-tags-any arguments can be combined to build more complex queries. Example:

GET /v2.0/networks?tags=red,blue&tags-any=green,orange
The above example returns any networks that have the “red” and “blue” tags,
plus at least one of “green” and “orange”.

Complex queries may have contradictory parameters. Example:

GET /v2.0/networks?tags=blue&not-tags=blue

In this case we should let Neutron find these networks. Obviously there are no such networks and Neutron will return an empty list.

CLI Examples

The following examples are used to illustrate how the CLI for adding/deleting/searching tags might look like:

neutron tag-create --resource-type network --resource <network-id-or-name> --tag blue
neutron tag-delete --resource-type network --resource <network-id-or-name> --tag blue
neutron net-list --tag blue

References