Andrew Kennedy mailto:[email protected] November 2016
This document discusses ways of improving the Brooklyn catalog management, by changing from a flat, versioned namespace, to a hierarchical structure using lexical scoping rules to prevent collisions.
The current Brooklyn catalog mechanism is a simple dictionary, using the catalog identifier as the key and the entity specification or template as the stored data. The entries are also versioned, using semantic versioning rules to assert an ordering, and with special semantics being applied to versions that have the form x.y.z-SNAPSHOT, as in Java artifact versioning using Maven.
Using this schema, each catalog entry must have a lexicographically unique identifier, and references to other entries are made using these unique ids. The identifiers can consist of the ASCII alphanumeric characters as well as the symbols '.-_' but no semantics are applied to the structure of the id itself. This has meant that application designers are forced to develop their own ad-hoc mechanisms for grouping similar entries, and ensuring they do not collide with existing entries that may already be present in the catalog.
For example, a prefix indicating the application the entry forms a part of, or the parent entry that an entity is extending, is often used. For a BOM file containing definitions for a Swarm cluster, these might be named as follows:
items:
- id: swarm-cluster
type: cluster
- id: swarm-node
type: docker-engine
- id: swarm-node-manager
type: swarm-node
- id: swarm-node-manager-tls
type: swarm-node-manager
- id: swarm-node-worker
type: swarm-node
- id: swarm-node-worker-tls
type: swarm-node-worker
- id: swarm-load-balancer
type: haproxy-load-balancer
- id: swarm-load-balancer-managers
type: swarm-load-balancer
- id: swarm-load-balancer-workers
type: swarm-load-balancer
The use of the swarm-
prefix, as well as the convention of using the parent
types identifier as a prefix when extending it, can be seen here. These are
useful practices, and help authors to manage complex blueprints by imposing
a logical and meaningful naming scheme.
However, this scheme is not enforced, and carries no intrinsic meaning to Brooklyn. The author could equally well have chosen a '.' delimited structure with a different prefix, following the conventions of Java package names. The contents of identifier tokens are essentially opaque and their only requirement is uniqueness. The use of UUIDs would perform the same task, albeit with a loss of readability.
Since it is evident that blueprint authors have a need to group related catalog entries together, it would be useful to implement a mechanism for this as part of Brooklyn. If each BOM file had an associated namespace or scope, then all entities defined there would have catalog ids that were associated with that scope. The identifiers would then only require to be unique within that particular scope. This would also require a mechanism to allow referring to catalog entries defined in some other scope. This can be accomplished by making the identifier use an optional prefix that specifies the scope, with the ':' delimiter used to prevent any ambiguity, in a similar fashion to the version suffix.
Our Swarm example then becomes:
namespace: swarm
version: 2.2.0
items:
- id: cluster
type: brooklyn:cluster
- id: node
type: docker:engine
- id: manager
type: node
- id: manager-tls
type: manager
- id: worker
type: node
- id: worker-tls
type: worker
- id: load-balancer
type: library:haproxy
- id: manager-load-balancer
type: load-balancer
- id: worker-load-balancer
type: load-balancer
And, to create a Swarm cluster, the deployment blueprint would then reference
swarm:cluster:2.2.0
as the entity type. This cluster
entity is based on the
brooklyn:cluster
entity, which represents one of the core catalog entries
from Brooklyn itself. The load-balancer
entity is an instance of HAProxy
from the Brooklyn entity library, here represented as the library
namespace.
The docker:engine
entity is another cross-namespace example, using the
engine
catalog entry in the docker
namespace. Compare this to the earlier
example which used docker-engine
as a globally unique catalog entry, using
the same principle to generate the identifier but without the ability to
enforce the semantics.
Note that we have simply introduced a single extra identifier for entries here. That is, entries are defined by the tuple ( namespace, identifier ) where the namespace identifier is unique among the set of namespaces, and the identifier is unique among the set of identifiers in its namespace. This could easily be extended to a multi-level hierarchy, however, where an ordered list of namespace tokens is followed by an identifier. With such a hierarchy of namespaces, the problem of unique names for catalog entries is essentially irrelevant.
Organization specific namespaces can be created as roots to segregate groups of entities and RBAC policies applied to the namespace, rather than each individual entry, to provide multi-tenant capabilities.
- Allow multiple namespaces in one file
- Use directory structure to define
- Import namespaces or individual entries
namespace: docker
version: 2.4.1
import:
- namespace: common
- namespace: library
identifiers:
- haproxy
items:
- id: engine
type: centos-software-process
- id: cluster
type: brooklyn:cluster
brooklyn.children:
- id: etcd
type: etcd:cluster
- id: haproxy
type: haproxy
brooklyn.config:
memberSpec:
$brooklyn:entitySpec:
type: engine