Resource Metadata
As a protocol, Goten needs to have protocol-like properties. One of the thems is the requirement that resource types of all Services managed by Goten must contain metadata objects. It was already mentioned multiple times, but let’s put a link to the Meta object again https://github.com/cloudwan/goten/blob/main/types/meta.proto.
Resource type managed by Goten must satisfy interface methods
(you can see in the Resource
interface defined in the
runtime/resource/resource.go
file):
GetMetadata() *meta.Meta
EnsureMetadata() *meta.Meta
There is, of course, the option to opt-out, interface Descriptor
has
method SupportsMetadata() bool
. If it returns false, it means
the resource type is not managed by Goten, and will be omitted from
the Goten design! However, it is important to recognize if resource
type is subject to this design or not, and how we can do this, including
programmatically.
To summarize, as protocol, Goten requires resources to satisfy this interface. It is important to note what information is stored in resource metadata in the context of the Goten design:
-
Field
syncing
of type SyncingMeta must always describe which region owns a resource, and which regions have read a copy of it. SyncingMeta must be always populated for each resource, regardless of type. -
Field
services
of type ServicesInfo must tell us which service owns a given resource, and a list of services for which this resource is relevant. Unlike syncing, services may not be necessarily populated, meaning that Service-defining resource type is responsible for explaining how it works in this case. In the future probably it may slightly change:If
services
is not populated at the moment of resource save, it will point to the current service as owning, and allowed services will be a one-element array containing the current service too. This in fact should be assumed by default, but it is not enforced globally, which we will explain now.
First, service meta.goten.com always ensures that the services
field is populated for the following cases:
- Instances of meta.goten.com/Service must have ServicesInfo where:
- Field
owning_service
is equal to the current service itself. - Field
allowed_services
contains the current service, all imported/used services, AND all services using importing this service! Note that this may be dynamically changing, if a new service is deployed, it will update the ServicesInfo fields of all services it uses/imports.
- Field
- Instances of meta.goten.com/Deployment and meta.goten.com/Resource must have their ServicesInfo synchronized with parent meta.goten.com/Service instance.
- Instances of meta.goten.com/Region do not have ServicesInfo typically populated. However, in the SPEKTRA Edge context, we have a public RoleBinding that allows all users to read from this collection (but never write). Because of this private/public nature, there was no need to populate service information there.
Note that this implies that service meta.goten.com is responsible for
syncing ServicesInfo of meta.goten.com/Deployment and
meta.goten.com/Resource instances. It is done by a controller
implemented in the Goten repository: meta-service/controller
directory. It is relatively simple.
However, while meta.goten.com can detect what ServicesInfo should be
populated, this is often not the case at all. For example, when service
iam.edgelq.com receives a request CreateServiceAccount
, it does not
know necessarily for whom this ServiceAccount is at all. Multiple services
may be owning ServiceAccount resources, therefore, but the resource type
itself does not have a dedicated “service” field in its schema. The only
way services can annotate ServiceAccount resources is by providing necessary
metadata information. Furthermore, if some custom service wants to make
the ServiceAccount instance available for others services to see, it may
need to provide multiple items to the allowed_services
array. This should
explain that service information must be determined at the business logic
level. For this reason, it is allowed to have empty service information,
but in many cases, SPEKTRA Edge will enforce their presence, where business
logic requires it.
Then, the situation for the other meta field, syncing
, is much easier.
Value can be determined on the schema level. There already is instruction
in the multi-region design section of the developer guide.
Regions setup always can be defined based on resource name only:
- If it is a regional resource (has a
region/
segment in the name), it strictly tells which region owns it. The list of regions that get a read-only copy is decided on below resource name properties below. - If it contains a well-known policy-holder in the name, then the policy-holder defines what regions get a read copy. If the resource is non-regional, then MultiRegionPolicy also tells what region owns it (default control region).
- If the resource is not subject to MultiRegionPolicy (like Region, or User in iam.edgelq.com), then it is a subject of MultiRegionPolicy defined in the relevant meta.goten.com/Service instance (for this service).
Now the trick is: All policy-holder resources are well-known. Although we try not to hardcode anything anywhere, Goten provides utility functions for detecting if a resource contains a MultiRegionPolicy field in its schema. This also must be defined in the Goten specification. By detecting what resource types are policy-holders, Goten can provide components that can easily extract regional information from a given resource by its name only.
Versioning information does not need to be specified in the resource body. Having instance, it is easily possible to get Descriptor instance, and check API version. All schema references are clear in this regard too, if resource A has a reference field to resource B, then from the reference object we can get the Descriptor instance of B, and get the version. The only place where it is not possible, are meta owner references. Therefore, in the field metadata.owner_references, an instance of each must contain the name, owning service, API version, and region (just in case it is not provided in the name field). When talking about the meta references, it is important to mention other differences compared to schema-level references:
- schema references are owned by a Service that owns resources with references.
- meta owner references are owned by a Service to which references are pointing!
This ownership has implication: when Deployment D1 in Service S1 upgrades from v1 to v2 (for example), and there is some resource X in Deployment D2 from Service S2, and this X has the meta owner reference to some resource owned by D1, then D1 will be responsible for sending an Update request to D2, so meta owner reference is updated.