Allow simple string tagging of instances

https://blueprints.launchpad.net/nova/+spec/tag-instances

This blueprint aims to add support for a simple string tagging mechanism for the instance object in the Nova domain model.

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 Nova’s REST API with the Internet’s common understanding of resource tagging, we can add an API extension that allows normal users to add, remove and list tags for an instance.

Proposed change

No changes to existing metadata, system_metadata or extra_specs functionality are being proposed. This is specfically for adding a new API for normal users to be able to tag their instances with simple strings.

Add a v2[.1] API extension that allows a user to add, remove, and list tags for an instance.

Add a v2[.1] API extension to allow searching for instances based on one or more string tags.

Alternatives

Alternatives to simple string tagging are already available in Nova through the instance metadata key/value pairs API extension. However, these existing approaches suffer from a few issues:

  • The key/value pairs in the existing server metadata API extension are all exposed via the nova-metadata endpoint, and therefore some people think they are limited to being queried only from the 169.254.169.254 address.

  • It is not clear in the API that some metadata key/value pairs are added by the user and some are added by Nova, Glance, or some external system. Part of the idea behind this simple string tagging proposal is to have a way to tag instances that is only for normal users.

  • Finally, and most importantly, the direction that the Glance program is taking is to use simple string tagging for user-side categorization of resources, and to use key/value pairs, hierarchical metadata, and property bags for describing system-side metadata about resources. Property bags are basically enumerated types for metadata, with a key and a constrained list of value choices. The proposed Catalog program will be following a strategy used by the Graffiti project that is designed to handle metadata/catalog data of various formats in a structured way, and leave user-focused taxonomy as simple-string tags only. This blueprint aligns with that direction.

Data model impact

The nova.objects.instance.Instance object would have a new tags field of type nova.objects.fields.ListOfStrings that would be populated on-demand (i.e. not eager-loaded).

A tag shall be defined as a Unicode bytestring no longer than 60 bytes in length. (This length is entirely arbitrary and could be reduced or expanded depending on review discussion…)

The tag is an opaque string and is not intended to be interpreted or even read by the virt drivers. In the REST API changes below, non-URL-safe characters in tags will need to be urlencoded if referred in the URI (for example, doing a DELETE /servers/{server}/tags/{tag}, the {tag} would need to be urlencoded.

Note

Glance already has object tagging functionality, and the database schema in that project uses a VARCHAR(255) length for the tag value. I would greatly prefer to keep a shorter-than-255 length. There are a number of performance reasons (including the fact that MySQL converts all varchar columns to fixed-width columns when doing aggregation and temporary tables containing the varchar columns). In addition, if the tags are UTF-8 (as proposed above), the 255 width will actually be 765 bytes wide (which exacerbates the fixed-width problems on MySQL).

For the database schema, the following table constructs would suffice

CREATE TABLE tags (
    resource_id CHAR(32) NOT NULL PRIMARY KEY,
    tag VARCHAR(80) NOT NULL CHARACTER SET utf8
     COLLATION utf8_ci PRIMARY KEY
);

There shall be a new hard-coded limit of 50 for the number of tags a user can use on a server. No need to make this configurable or use the quota system at this point.

REST API impact

This proposal would add a v2[.1] API extension for retrieving and setting tags against an instance. In addition, it would add an API extension to allow the searching/listing of instances based on one or more string tags.

The tag CRUD operations API extension would look like the following:

Return list of tags for a server

GET /v2/{project_id}/servers/{server_id}/tags

returns

[
    'tag-one',
    'tag-two'
]

JSONSchema document for response

{
    "title": "Server tags",
    "type": "array",
    "items": {
        "type": "string"
    },
}

Replace set of tags on a server

POST /v2/{project_id}/servers/{server_id}/tags

with request payload

[
    'tag-one',
    'tag-three'
]

JSONSchema document for request

{
    "title": "Server tags",
    "type": "array",
    "items": {
        "$ref": "#/definitions/tag"
    },
    "maxItems": 50,
    "definitions": {
        "tag": {
            "type": "string",
            "maxLength": 60
        }
    }
}

Returns a 200 OK. If the number of tags exceeds the limit of tags per server, shall return a 403 Forbidden

Add a single tag on a server

PUT /v2/{project_id}/servers/{server_id}/tags/{tag}

Returns 204 No Content.

If the tag already exists, no error is raised, it just returns the 204 No Content

If the number of tags would exceed the per-server limit, shall return a 403 Forbidden

Remove a single tag on a server

DELETE /v2/{project_id}/servers/{server_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 server

DELETE /v2/{project_id}/servers/{server_id}/tags

Returns 204 No Content.

The API extension that would allow searching/filtering of the GET /servers REST API call would add the following query parameters:

  • tag – One or more strings that will be used to filter results in an AND expression.

  • tag-any – One or more strings that will be used to filter results in an OR expression.

Get all servers having a single tag

GET /v2/{project_id}/servers?tag={tag}

Would return the servers having the {tag} tag. No change is needed to the JSON response for the GET /v2/{project_id}/servers/ call.

Get all servers having either of two tags

GET /v2/{project_id}/servers?tag-any={tag_a}&tag-any={tag_b}

Would return the servers having either the {tag_a} or the {tag_b} tag. No change is needed to the JSON response for the GET /v2/{project_id}/servers/ call.

Get all servers having both tag A and tag B:

GET /v2/{project_id}/servers?tag={tag_a}&tag={tag_b}

Would return the servers having both the {tag_a} AND the {tag_b} tag. No change is needed to the JSON response for the GET /v2/{project_id}/servers/ call.

Mixing of tag and tag-any is perfectly fine. All tag-any tags will be grouped into a single OR’d expression that is AND’d to the expression built from all of the tag tags. For example:

GET /v2/{project_id}/servers?tag=A&tag=B&tag-any=C&tag-any=D

Would yield servers that were tagged with “A”, “B”, and either “C” or “D”.

Security impact

None

Notifications impact

None

Other end user impact

None

Performance Impact

None, though REGEXP-based querying on some fields might be modified to use a faster tag-list filtering query.

Other deployer impact

None

Developer impact

None

Implementation

See Work Items section below.

Assignee(s)

Primary assignee:

jaypipes

Other contributors:

snikitin

Work Items

Changes would be made, in order, to:

  1. the database API layer to add support for CRUD operations on instance tags

  2. the database API layer to add tag-list filtering support to instance_get_all_by_filters

  3. the nova.objects layer to add support for a tags field of the Instance object

  4. the API extension for CRUD operations on the tag list

Dependencies

Soft dependency on specification for adding field type validation to nova objects. I say soft because technically this blueprint can be implemented with the tag string length validation done at the database schema level:

https://blueprints.launchpad.net/nova/+spec/field-type-validation

Note that the above is NOT a hard dependency and the work for this blueprint should not be held up for it. Hard-coded database schema string size limits are usable in this blueprint for the tag string length constraint.

Testing

Would need new Tempest and unit tests.

Documentation Impact

Docs needed for new API extension and usage.

References

Mailing list discussions:

http://lists.openstack.org/pipermail/openstack-dev/2014-April/033222.html http://www.mail-archive.com/openstack-dev@lists.openstack.org/msg23310.html