diff --git a/specs/pike/approved/node-aggregate.rst b/specs/pike/approved/node-aggregate.rst new file mode 100644 index 0000000..3ce1d0c --- /dev/null +++ b/specs/pike/approved/node-aggregate.rst @@ -0,0 +1,248 @@ +.. + This work is licensed under a Creative Commons Attribution 3.0 Unported + License. + + http://creativecommons.org/licenses/by/3.0/legalcode + +=============== +Node Aggregates +=============== + +https://blueprints.launchpad.net/mogan/+spec/node-aggregate + +This introduces the concept of aggregate into Mogan, which is quite like Nova +host aggregate, but we are based on baremetal nodes. Node aggregate allows the +partition of baremetal nodes into logical groups for server distribution. + + +Problem description +=================== + +Currently Mogan only have a concept of availability zones which is for +providing isolation and redundancy from other availability zones. We need a +mechanism to further partitioning baremetal nodes. + +Use Cases +--------- + +* As a cloud operator, I want to classify baremetal nodes based on the + location like rack, row, cage, zone, DC. + +* As a cloud operator, I want to classify baremetal nodes based on the + hardware specs like with GPU, FPGA, ceph storage backend. + + +Proposed change +=============== + +* A new mogan.objects.aggregate.Aggregate object would be added to the object +model. + +* Add a set of API that only allow admins to create, delete, and list +aggregates, also admins should be able to add nodes to the specific aggregate +and remove nodes from it. + +* When do resources update we will cache the resource providers and the map of +aggregates with resource providers. Add a node list API for admins which will +derive resource providers from the cache. + +* Before scheduling, mogan will handle the flavor resource_aggregates matching +with node aggregate metadata, then got a list of aggregates, and pass it to +placement with `member_of` parameter when listing resource providers:: + + /resource_providers?member_of=in:{agg1_uuid},{agg2_uuid},{agg3_uuid} + +Alternatives +------------ + +None + +Data model impact +----------------- + +The proposed change will be adding the following fields to the aggregate +object with their data type and default value for migrations. + ++-----------------------+--------------+ +| Field Name | Field Type | ++=======================+==============+ +| id | Integer | ++-----------------------+--------------+ +| uuid | UUID | ++-----------------------+--------------+ +| name | String | ++-----------------------+--------------+ +| metadata | DictOfStrings| ++-----------------------+--------------+ + +For the database schema, the following table constructs would suffice :: + + op.create_table( + 'aggregates', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.PrimaryKeyConstraint('id'), + mysql_ENGINE='InnoDB', + mysql_DEFAULT_CHARSET='UTF8' + ) + + op.create_table( + 'aggregate_metadata', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), primary_key=True, nullable=False), + sa.Column('key', sa.String(length=255), nullable=False), + sa.Column('value', sa.String(length=255), nullable=False), + sa.Column('aggregate_id', sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.ForeignKeyConstraint(['aggregate_id'], + ['aggregate.id']), + mysql_ENGINE='InnoDB', + mysql_DEFAULT_CHARSET='UTF8' + ) + +REST API impact +--------------- + +- To create a new aggregate, a user will :: + + POST /v1/aggregates + + With a body containing the JSON description of the aggregate. + + JSON Schema:: + + { + "type": "object", + "properties": { + "name": {"type": "string", "minLength": 1, "maxLength": 255}, + "metadata": { + 'type': 'object', + 'patternProperties': { + '^[a-zA-Z0-9-_:. ]{1,255}$': { + 'type': 'string', 'maxLength': 255 + } + }, + 'additionalProperties': False + }, + }, + "required": ["name"], + "additionalProperties": False, + } + +- To list aggregates, a user will :: + + GET /v1/aggregates + +- To show aggregate details, a user will :: + + GET /v1/aggregates/{aggregate_id} + +- To update aggregate, a user will :: + + PATCH /v1/aggregates/{aggregate_id} + + With a body containing the JSON description of the fileds to be updated. + + Example Update Aggregate: JSON request:: + + [ + { + "op": "replace", + "path": "/name", + "value": "foo" + }, + { + "op": "add", + "path": "/metadata/k1", + "value": "v1" + } + ] + +- To delete an aggregate, a user will :: + + DELETE /v1/aggregates/{aggregate_id} + +- To add nodes to an aggregate, a user will :: + + POST /v1/aggregates/{aggregate_id}/nodes + + With a body containing a list of node uuid to be added to the aggregate. + +- To remove node from an aggregate, a user will :: + + DELETE /v1/aggregates/{aggregate_id}/nodes/{node} + +- To get nodes from an aggregate, a user will :: + + GET /v1/aggregates/{aggregate_id}/nodes + +Security impact +--------------- + +None + +Notifications impact +-------------------- + +None + +Other end user impact +--------------------- + +None + +Performance Impact +------------------ + +None + +Other deployer impact +--------------------- + +None + +Developer impact +---------------- + +None + +Implementation +============== + +Assignee(s) +----------- + +Primary assignee: + + +Work Items +---------- + +* Add aggregate object. +* Add APIs that allows an admin to add, remove, and list node aggregates. +* Add APIs that allows an admin to add/remove nodes to an aggregate. +* Add new CLIs to manage node aggregates. + +Dependencies +============ + +None + +Testing +======= + +Unit Testing will be added. + +Documentation Impact +==================== + +Docs about node aggregates will be added. + +References +========== + +None