| // Copyright 2017 The LUCI Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| syntax = "proto3"; |
| |
| package cipd; |
| |
| option go_package = "go.chromium.org/luci/cipd/api/cipd/v1;api"; |
| |
| import "google/protobuf/empty.proto"; |
| import "google/protobuf/struct.proto"; |
| import "google/protobuf/timestamp.proto"; |
| import "google/rpc/status.proto"; |
| import "go.chromium.org/luci/cipd/api/cipd/v1/cas.proto"; |
| |
| |
| // Manages CIPD packages and their associated metadata. |
| // |
| // A package is a named collection of one or more versions of a group of files. |
| // A package should typically be used for a single software component or |
| // dataset, not a conglomeration. A package instance is a concrete incarnation |
| // of a such version: it is a real file, and it is identified by its SHA256 (or |
| // SHA1 for older packages) digest, represented by ObjectRef proto in the |
| // protocol. |
| // |
| // A particular serialization of ObjectRef proto into a string is referred to |
| // as "instance ID" and it is used to identify package instances (mostly in |
| // the interface exposed by the CIPD command line client, but also in |
| // ResolveVersion RPC): |
| // * For legacy reasons SHA1 digests are encoded with lowercase hex encoding, |
| // which always results in 40 char ASCII strings). |
| // * Other digests are encoded using base64(digest + []byte{ref.HashAlgo}), |
| // where 'base64' is URL-safe and unpadded and '+' is concatenation. |
| // For SHA256 digests this results in 44 char ASCII strings that end with C. |
| // |
| // Instance files themselves are zip archives with some additional metadata. |
| // They are produced and consumed by cipd CLI client, and the backend mostly |
| // doesn't care about their internal structure. |
| // |
| // Package names look like rootless file system paths (e.g. "a/b/c"). The |
| // identifier of a package is always the full path. There's no notion of |
| // "relative paths", or "..", or any other similar constructs. The name of the |
| // last path component has no intrinsic significance either, though it is often |
| // used to denote a platform the package is intended for. For example |
| // "infra/tools/cipd/linux-amd64" package is intended for Linux running on amd64 |
| // architecture. This is just a convention, and it is not enforced nor |
| // understood by the backend. |
| // |
| // Each element of the package namespace (known as "package path prefix" or just |
| // "prefix") can have some metadata attached to it. Currently it includes only |
| // an access control list (ACL) that specifies what roles are granted to what |
| // users for the given prefix and all packages underneath it. |
| // |
| // For example, granting READER role to user@example.com in ACL associated with |
| // prefix "a/b/c" gives user@example.com permission to read all package |
| // instances of "a/b/c" and any packages below it (e.g. "a/b/c/d"). See Role |
| // enum for list of roles. |
| // |
| // There's no finer permission granularity inside the package itself, e.g. it is |
| // not possible to allow to read some particular package instance, without |
| // allowing to read all instances of the package. |
| service Repository { |
| // Returns metadata associated with the given prefix. |
| // |
| // Requires the caller to have OWNER role for the requested prefix or any of |
| // parent prefixes, or be in a special global "cipd-prefixes-viewers" group, |
| // otherwise the call fails with PERMISSION_DENIED error. |
| // |
| // If the caller has OWNER permission in any of parent prefixes, but the |
| // requested prefix has no metadata associated with it, the call fails with |
| // NOT_FOUND error. |
| rpc GetPrefixMetadata(PrefixRequest) returns (PrefixMetadata); |
| |
| // Returns metadata associated with the given prefix and all parent prefixes. |
| // |
| // Requires the caller to have OWNER role for the requested prefix or any of |
| // parent prefixes, or be in a special global "cipd-prefixes-viewers" group, |
| // otherwise the call fails with PERMISSION_DENIED error. |
| // |
| // Note that if the caller has permission to see the metadata for the |
| // requested prefix, they will also see metadata for all parent prefixes, |
| // since it is needed to assemble the final metadata for the prefix (it |
| // includes inherited properties from all parent prefixes). |
| rpc GetInheritedPrefixMetadata(PrefixRequest) returns (InheritedPrefixMetadata); |
| |
| // Updates or creates metadata associated with the given prefix. |
| // |
| // Requires the caller to have OWNER role for the requested prefix or any of |
| // parent prefixes, otherwise the call fails with PERMISSION_DENIED error. |
| // |
| // This method checks 'fingerprint' field of the PrefixMetadata object. If the |
| // metadata for the given prefix already exists, and the fingerprint in the |
| // request doesn't match the current fingerprint, the request fails with |
| // FAILED_PRECONDITION error. |
| // |
| // If the metadata doesn't exist yet, its fingerprint is assumed to be empty |
| // string. So pass empty fingerprint when creating initial metadata objects. |
| // |
| // If the caller passes empty fingerprint, but the metadata already exists, |
| // the request fails with ALREADY_EXISTS error. |
| // |
| // Note that there's no way to delete metadata once it was created. Passing |
| // empty PrefixMetadata object is the best that can be done. |
| // |
| // On success returns PrefixMetadata object with the updated fingerprint. |
| rpc UpdatePrefixMetadata(PrefixMetadata) returns (PrefixMetadata); |
| |
| // Returns a set of roles the caller has in the given prefix. |
| // |
| // Unlike GetPrefixMetadata call that requires special permissions (since it |
| // returns a lot of detailed information), GetRolesInPrefix can be called by |
| // anyone. |
| // |
| // It understands and expands roles inheritance, e.g. if the caller is an |
| // OWNER, the result will also contain WRITER and READER (as they are implied |
| // by being an OWNER). |
| // |
| // Returns empty set of roles if the caller has no permissions to access the |
| // prefix at all or such prefix doesn't exist. |
| rpc GetRolesInPrefix(PrefixRequest) returns (RolesInPrefixResponse); |
| |
| // Lists packages and subprefixes registered under the prefix. |
| // |
| // Lists either only direct descendants or recursively all descendants. The |
| // result is sorted lexicographically. |
| // |
| // For example, for packages ["a", "a/b", "a/c/d", "a/c/e/f"], listing of "a" |
| // will be: |
| // * {packages: ["a/b"], prefixes: ["a/c"]} if listing non-recursively. |
| // * {packages: ["a/b", "a/c/d", "a/c/e/f"], prefixes: ["a/c", "a/c/e"]} if |
| // listing recursively. |
| // |
| // Returns only packages and prefixes visible to the caller. This applies even |
| // when listing a prefix the caller has no direct read access to. For example, |
| // recursively listing the root prefix will return all packages the caller has |
| // read access to (no matter when in the hierarchy they are located), even if |
| // the caller has no READER permission in the root. It works as if the caller |
| // can freely browse the repository that contains only the packages they can |
| // see and nothing else. |
| rpc ListPrefix(ListPrefixRequest) returns (ListPrefixResponse); |
| |
| // HidePackage marks the package as hidden. |
| // |
| // This removes it from the ListPrefix results, but doesn't otherwise affect |
| // its usage (e.g. it is still fetchable). |
| // |
| // Requires OWNER role for the package prefix. Returns PERMISSION_DENIED |
| // otherwise. |
| rpc HidePackage(PackageRequest) returns (google.protobuf.Empty); |
| |
| // UnhidePackage marks the package as visible again. |
| // |
| // It's reverse of HidePackage. |
| // |
| // Requires OWNER role for the package prefix. Returns PERMISSION_DENIED |
| // otherwise. |
| rpc UnhidePackage(PackageRequest) returns (google.protobuf.Empty); |
| |
| // DeletePackage removes the package (along with all its instances, tags, refs |
| // etc) from the repository. |
| // |
| // There's no undo. Once the package is deleted, it is gone forever. |
| // |
| // This operation has a potential to break various pinned historical CIPD |
| // ensure files and thus should not be used casually, only in extreme cases. |
| // Consider just hiding the package instead of deleting it. |
| // |
| // For the reasons above, the operation requires admin access: only owners of |
| // the repository root can delete packages. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a root owner. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package doesn't exist. |
| rpc DeletePackage(PackageRequest) returns (google.protobuf.Empty); |
| |
| // Registers a package instance in the repository (if it was uploaded to the |
| // storage already and wasn't registered yet) or initiates a new upload |
| // operation. |
| // |
| // Callers are expected to execute the following protocol: |
| // 1. Attempt to register a package instance by calling RegisterInstance. |
| // 2. On NOT_UPLOADED status, upload the package data and finalize the |
| // upload operation using Storage RPC service and upload_op from the |
| // response. |
| // 3. Once the upload operation is finalized, call RegisterInstance again, |
| // it should succeed with status REGISTERED now. |
| // |
| // If such instance is already registered by someone else, returns |
| // ALREADY_REGISTERED status. This is not an error. |
| // |
| // Callers must have roles WRITER or OWNER for the package prefix. Returns |
| // PERMISSION_DENIED otherwise. |
| rpc RegisterInstance(Instance) returns (RegisterInstanceResponse); |
| |
| // Lists instances of a package, most recent first. |
| // |
| // Callers must have roles READER (or above) for the package prefix. Returns |
| // PERMISSION_DENIED otherwise. |
| // |
| // If the package doesn't exist, returns NOT_FOUND. |
| rpc ListInstances(ListInstancesRequest) returns (ListInstancesResponse); |
| |
| // Returns package instances that have all given tags attached. |
| // |
| // Queries only instances of some particular package (i.e. this is not a |
| // global query). |
| // |
| // Callers must have roles READER (or above) for the package prefix. Returns |
| // PERMISSION_DENIED otherwise. |
| // |
| // If the package doesn't exist, returns NOT_FOUND. |
| rpc SearchInstances(SearchInstancesRequest) returns (SearchInstancesResponse); |
| |
| // Creates a new ref or moves an existing one. |
| // |
| // A ref is a mutable named pointer to some existing package instance that |
| // can be used as a version identifier. For example, "latest" or "stable". |
| // |
| // Refs are namespaced to some particular package. E.g. "latest" ref in |
| // packages "A" and "B" are completely different entities not related to each |
| // other. |
| // |
| // Pointing a ref to an instance generally makes the instance "discoverable". |
| // For that reason the ref can be set only to instances that successfully |
| // passed all post-registration processing. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a WRITER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package or the instance the ref points to doesn't exist. |
| // FAILED_PRECONDITION if the instance is still being processed. |
| // ABORTED if the instance has some failed processors associated with it, |
| // such instance is effectively broken and should not be used. |
| rpc CreateRef(Ref) returns (google.protobuf.Empty); |
| |
| // Removes a ref. |
| // |
| // Not a failure if there's no such ref. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a WRITER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package doesn't exist. |
| rpc DeleteRef(DeleteRefRequest) returns (google.protobuf.Empty); |
| |
| // Lists refs defined in a package, most recently modified first. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a READER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package doesn't exist. |
| rpc ListRefs(ListRefsRequest) returns (ListRefsResponse); |
| |
| // Attaches one or more tags to an instance. |
| // |
| // Silently skips already attached tags. |
| // |
| // Tags are "key:value" pairs associated with a concrete package instance. |
| // They can be used for querying registered instances and for version |
| // resolution: if a tag is attached to one and only one instance of a package, |
| // the tag uniquely identifies this instance and such tag can be used as an |
| // alias of the instance ID. |
| // |
| // Tags generally should be assumed globally namespaced (e.g. it makes sense |
| // to query for all registered instances with a given tag, across all |
| // packages), and they don't have to be unique: same tag may be attached to |
| // multiple instances (of the same or different packages). |
| // |
| // Additionally, tags (unlike refs) are intended to be mostly static, since |
| // they usually relate to some properties of package instances, which are |
| // static entities. This is particularity important for tags used for version |
| // resolution. |
| // |
| // Attaching a tag to an instance generally makes the instance "discoverable". |
| // For that reason tags can be attached only to instances that successfully |
| // passed all post-registration processing. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a WRITER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package or the instance doesn't exist. |
| // FAILED_PRECONDITION if the instance is still being processed. |
| // ABORTED if the instance has some failed processors associated with it, |
| // such instance is effectively broken and should not be used. |
| rpc AttachTags(AttachTagsRequest) returns (google.protobuf.Empty); |
| |
| // Detaches one or more tags if they were attached. |
| // |
| // This call should not be used routinely, since tags are assumed to be |
| // static (and thus not detachable). |
| // |
| // It is occasionally useful for fixing screw ups though. For that reason, |
| // DetachTags is allowed only by OWNERS of a prefix (not WRITERS, like |
| // AttachTags). |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not an OWNER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package or the instance doesn't exist. |
| rpc DetachTags(DetachTagsRequest) returns (google.protobuf.Empty); |
| |
| // Attaches one or more metadata entries to an instance. |
| // |
| // An instance metadata entry is a key-value pair, where the key is a |
| // lowercase string and the value is an arbitrary blob up to 512 Kb in size. |
| // |
| // A single key can have multiple different values associated with it. |
| // Completely identical key-value pairs are deduplicated: attaching already |
| // attached metadata is a noop. Thus all metadata of an instance is a |
| // multimap, where a key maps to a set of unique values. |
| // |
| // A metadata entry is identified by its fingerprint: a hash of concatenated |
| // key and value (see InstanceMetadata message for details). It can be used, |
| // for example, to point to an entry to detach in DetachMetadata. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a WRITER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package or the instance doesn't exist. |
| // FAILED_PRECONDITION if the instance is still being processed. |
| // ABORTED if the instance has some failed processors associated with it, |
| // such instance is effectively broken and should not be used. |
| rpc AttachMetadata(AttachMetadataRequest) returns (google.protobuf.Empty); |
| |
| // Detaches one or more metadata entries if they were attached. |
| // |
| // Entries are identified by their fingerprints. They can either be calculated |
| // from a key-value pair by the client (see InstanceMetadata message for |
| // details), by the server (if InstanceMetadata messages inside |
| // DetachMetadataRequest have 'key' and 'value' populated, but not |
| // 'fingerprint') or taken from some existing InstanceMetadata message (e.g. |
| // from inside a ListMetadataResponse). |
| // |
| // Detaching metadata that doesn't exist is a noop. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not an OWNER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package or the instance doesn't exist. |
| rpc DetachMetadata(DetachMetadataRequest) returns (google.protobuf.Empty); |
| |
| // Lists metadata entries attached to an instance. |
| // |
| // Either returns all metadata or only entries with requested keys. The list |
| // is sorted by the registration time of metadata entries (the most recent |
| // first). |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a READER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the package or the instance doesn't exist. |
| rpc ListMetadata(ListMetadataRequest) returns (ListMetadataResponse); |
| |
| // Takes a version string and resolves it into a concrete package instance. |
| // |
| // A version string can be any of: |
| // * A string-encoded instance ID, e.g. "abcdef....". |
| // * A ref name, e.g. "latest". |
| // * A tag, e.g. "version:1.10.3". |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a READER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if there's no such package or version. |
| // FAILED_PRECONDITION if the tag resolves to multiple instances. |
| rpc ResolveVersion(ResolveVersionRequest) returns (Instance); |
| |
| // Produces a signed URL that can be used to fetch the package instance file. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a READER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if there's no such instance. |
| rpc GetInstanceURL(GetInstanceURLRequest) returns (ObjectURL); |
| |
| // Returns information about a package instance. |
| // |
| // Depending on fields set in the request, returns details such as when the |
| // instance was registered and by whom, refs pointing to it, tags attached to |
| // it, state of all processors that handled it (if any). |
| // |
| // May also be used as a simple instance presence check, if all describe_* |
| // fields in the request are false. If the request succeeds, then the |
| // instance exists. |
| // |
| // Returns: |
| // PERMISSION_DENIED if the caller is not a READER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| // NOT_FOUND if the instance doesn't exist. |
| rpc DescribeInstance(DescribeInstanceRequest) returns (DescribeInstanceResponse); |
| |
| // Returns information about a CIPD client package. |
| // |
| // Used by the client self-update procedure. |
| // |
| // Returns: |
| // NOT_FOUND if the package or the instance doesn't exist. |
| // FAILED_PRECONDITION if the instance is still being processed. |
| // ABORTED if the instance has some failed processors associated with it, |
| // such instance is effectively broken and should not be used. |
| rpc DescribeClient(DescribeClientRequest) returns (DescribeClientResponse); |
| |
| // Returns information about binaries extracted from bootstrap packages under |
| // some prefix. |
| // |
| // This is a niche functionality used by some LUCI systems. |
| // |
| // Unlike other RPC methods here, it operates with a bunch of packages at |
| // once. Errors that relate to a particular package instance (instead of the |
| // request as a whole) are returned as google.rpc.Status inside the |
| // corresponding BootstrapFile entry in DescribeBootstrapBundleResponse. |
| // Possible statuses communicated that way: |
| // NOT_FOUND if the requested version of the package doesn't exist. |
| // FAILED_PRECONDITION if the instance is still being processed or it is not |
| // a bootstrap package at all. |
| // ABORTED if the instance has failed processors associated with it, |
| // such instance is effectively broken and should not be used. |
| // |
| // NOTE: The CIPD package server implements a REST endpoint which can be used |
| // to retrieve the contents of bootstrap packages: |
| // |
| // GET /bootstrap/<package>/+/<version> |
| // |
| // which will serve a 302 redirect to a signed url for the `file` contents. |
| // |
| // Returns: |
| // OK if the request was accepted and (perhaps partially) processed. |
| // NOT_FOUND if none of the requested instances exist. |
| // PERMISSION_DENIED if the caller is not a READER for the prefix. |
| // INVALID_ARGUMENT if the request is malformed. |
| rpc DescribeBootstrapBundle(DescribeBootstrapBundleRequest) returns (DescribeBootstrapBundleResponse); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| // Roles used in package prefix ACLs. |
| // |
| // A user can have one or more such roles for a package prefix. They get |
| // inherited by all subprefixes. |
| enum Role { |
| ROLE_UNSPECIFIED = 0; |
| |
| // Readers can fetch package instances and package metadata (e.g. list of |
| // instances, all tags, all refs), but not prefix metadata (e.g. ACLs). |
| READER = 1; |
| |
| // Writers can do everything that readers can, plus create new packages, |
| // upload package instances, attach tags, move refs. |
| WRITER = 2; |
| |
| // Owners can do everything that writers can, plus read prefix metadata for |
| // all parent prefixes and all subprefixes, and modify prefix metadata for |
| // all subprefixes. |
| OWNER = 3; |
| } |
| |
| |
| message PrefixRequest { |
| // A prefix within the repository, e.g. "a/b/c". |
| string prefix = 1; |
| } |
| |
| |
| // PrefixMetadata is metadata defined at some concrete package prefix. |
| // |
| // It applies to this prefix and all subprefixes, recursively. |
| message PrefixMetadata { |
| message ACL { |
| // Role that this ACL describes. |
| Role role = 1; |
| // Users and groups that have the specified role. |
| // |
| // Each entry has a form "<kind>:<value>", e.g "group:..." or "user:...". |
| repeated string principals = 2; |
| } |
| |
| // Prefix this metadata is defined at, e.g. "a/b/c". |
| // |
| // Note: there's no metadata at the root, so prefix must never be "". |
| string prefix = 1; |
| |
| // An opaque string that identifies a particular version of this metadata. |
| // |
| // Used by UpdatePrefixMetadata to prevent an accidental overwrite of changes. |
| string fingerprint = 2; |
| |
| // When the metadata was modified the last time. |
| // |
| // Managed by the server, ignored when passed to UpdatePrefixMetadata. |
| google.protobuf.Timestamp update_time = 3; |
| |
| // Identity string of whoever modified the metadata the last time. |
| // |
| // Managed by the server, ignored when passed to UpdatePrefixMetadata. |
| string update_user = 4; |
| |
| // ACLs that apply to this prefix and all subprefixes, as a mapping from |
| // a role to a list of users and groups that have it. |
| repeated ACL acls = 5; |
| } |
| |
| |
| message InheritedPrefixMetadata { |
| // Per-prefix metadata that applies to a prefix, ordered by prefix length. |
| // |
| // For example, when requesting metadata for prefix "a/b/c/d" the reply may |
| // contain entries for "a", "a/b", "a/b/c/d" (in that order, with "a/b/c" |
| // skipped in this example as not having any metadata attached). |
| repeated PrefixMetadata per_prefix_metadata = 1; |
| } |
| |
| |
| message RolesInPrefixResponse { |
| message RoleInPrefix { |
| Role role = 1; |
| } |
| |
| // Unordered set or roles the caller has in the requested prefix. |
| repeated RoleInPrefix roles = 1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message ListPrefixRequest { |
| // A prefix within the repository to list, e.g. "a/b/c". Empty prefix is also |
| // accepted: it means "root of the repository". |
| string prefix = 1; |
| // If false, list only direct descendants of the prefix, otherwise all. |
| bool recursive = 2; |
| // If true, include hidden packages in the result. |
| bool include_hidden = 3; |
| } |
| |
| |
| message ListPrefixResponse { |
| // Lexicographically sorted list of full packages names. |
| repeated string packages = 1; |
| // Lexicographically sorted list of child prefixes (without trailing '/'). |
| repeated string prefixes = 2; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| // PackageRequest names a package and nothing else. |
| message PackageRequest { |
| string package = 1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| // RegistrationStatus is part of RegisterInstance RPC response. |
| enum RegistrationStatus { |
| REGISTRATION_STATUS_UNSPECIFIED = 0; |
| |
| REGISTERED = 1; // the instance was successfully registered just now |
| ALREADY_REGISTERED = 2; // the instance already exists, this is OK |
| NOT_UPLOADED = 3; // the instance should be uploaded to Storage first |
| } |
| |
| |
| // Instance is a pointer to an instance of some package. |
| message Instance { |
| // A name of the package, e.g. "a/b/c/d". |
| string package = 1; |
| // A reference to the instance file in the storage. |
| ObjectRef instance = 2; |
| // User who registered the instance (output only). |
| string registered_by = 3; |
| // When the instance was registered (output only). |
| google.protobuf.Timestamp registered_ts = 4; |
| } |
| |
| |
| message RegisterInstanceResponse { |
| // Outcome of the operation, see the enum for possibilities. |
| // |
| // Defines what other fields are present. |
| RegistrationStatus status = 1; |
| |
| // For statuses REGISTERED and ALREADY_REGISTERED contains details about the |
| // instance. Not set for NOT_UPLOADED status. |
| Instance instance = 2; |
| |
| // For status NOT_UPLOADED contains a new upload operation that can be used |
| // together with Storage service to upload the instance file. Not set for |
| // other statuses. |
| UploadOperation upload_op = 3; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message ListInstancesRequest { |
| // Name of a package to list instances of. |
| string package = 1; |
| |
| // Number of instances to return on one page, default is 100. |
| int32 page_size = 20; |
| |
| // Value of 'next_page_token' from the previous response. |
| // |
| // Can be used to resume fetching. |
| string page_token = 21; |
| } |
| |
| |
| message ListInstancesResponse { |
| // Package instances, sorted by registration time, most recent first. |
| repeated Instance instances = 1; |
| |
| // Value to pass as 'page_token' in ListInstancesRequest to resume fetching or |
| // empty string if there's no more results. |
| string next_page_token = 20; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message SearchInstancesRequest { |
| // Name of a package to query instances of (required). |
| string package = 1; |
| |
| // Tags to look for (the found instances have ALL these tags attached). |
| // |
| // Due to internal limitations, the query is most efficient only when it |
| // specifies one tag to filter by. All additional tags are checked in a |
| // separate step after the initial query. For that reason when searching for |
| // multiple tags it is better to specify the most limiting tags first. |
| repeated Tag tags = 2; |
| |
| // Number of instances to return on one page, default is 100. |
| int32 page_size = 20; |
| |
| // Value of 'next_page_token' from the previous response. |
| // |
| // Can be used to resume fetching. |
| string page_token = 21; |
| } |
| |
| |
| message SearchInstancesResponse { |
| // Package instances, sorted by registration time, most recent first. |
| repeated Instance instances = 1; |
| |
| // Value to pass as 'page_token' in SearchInstancesRequest to resume fetching |
| // or empty string if there's no more results. |
| string next_page_token = 20; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| // Ref is a mutable named pointer to some package instance that can be used |
| // as a version identifier. |
| message Ref { |
| // Name of the ref, e.g. "latest". |
| string name = 1; |
| // Name of the package where the ref is defined. |
| string package = 2; |
| // A package instance the ref is pointing to. |
| ObjectRef instance = 3; |
| |
| // User who modified this ref the last time (output only). |
| string modified_by = 4; |
| // When the ref was modified the last time (output only). |
| google.protobuf.Timestamp modified_ts = 5; |
| } |
| |
| |
| message DeleteRefRequest { |
| // Name of the ref, e.g. "latest". |
| string name = 1; |
| // Name of the package where the ref is defined. |
| string package = 2; |
| } |
| |
| |
| message ListRefsRequest { |
| // Name of a package to list refs of. |
| string package = 1; |
| } |
| |
| |
| message ListRefsResponse { |
| // Package refs, sorted by modification time, most recently touched first. |
| repeated Ref refs = 1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| // Tag is a key:value pair attached to some instance. |
| // |
| // Keys don't have to be unique, only the full pair should. For example, |
| // it is fine to have "version:1" and "version:2" tags attached to the same |
| // instance. |
| // |
| // The total length of the tag (as "key:value" pair) should be less that 400 |
| // bytes. |
| message Tag { |
| // Key is a lowercase string matching [a-z0-9_\-]+. |
| string key = 1; |
| // Value is a string matching [A-Za-z0-9$()*+,\-./:;<=>@\\_{}~ ]+. |
| string value = 2; |
| |
| // User that attached this tag (output only). |
| string attached_by = 3; |
| // When the tag was attached (output only). |
| google.protobuf.Timestamp attached_ts = 4; |
| } |
| |
| |
| message AttachTagsRequest { |
| // The package that holds the instance we attach tags to. |
| string package = 1; |
| // The instance we attach tags to. |
| ObjectRef instance = 2; |
| // One or more tags to attach (order doesn't matter). |
| repeated Tag tags = 3; |
| } |
| |
| |
| message DetachTagsRequest { |
| // The package that holds the instance we detach tags from. |
| string package = 1; |
| // The instance we detach tags from. |
| ObjectRef instance = 2; |
| // One or more tags to detach (order doesn't matter). |
| repeated Tag tags = 3; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message InstanceMetadata { |
| // Key is a lowercase string matching [a-z0-9_\-]{1,400}. |
| string key = 1; |
| // Value is an arbitrary byte blob smaller than 512 Kb. |
| bytes value = 2; |
| // Optional MIME content type of the metadata value, primarily for UI. |
| string content_type = 3; |
| |
| // Fingerprint identifies this metadata entry. |
| // |
| // It is the first 16 bytes of SHA256("<key>:<value>") in lowercase hex |
| // encoding (i.e. it is 32 lowercase hex characters). |
| // |
| // Populated by the server in all responses. Ignored in AttachMetadataRequest, |
| // optionally used in DetachMetadataRequest. |
| string fingerprint = 4; |
| |
| // User that attached this metadata (output only). |
| string attached_by = 5; |
| // When the metadata was attached (output only). |
| google.protobuf.Timestamp attached_ts = 6; |
| } |
| |
| |
| message AttachMetadataRequest { |
| // The package that holds the instance we attach metadata to. |
| string package = 1; |
| // The instance we attach metadata to. |
| ObjectRef instance = 2; |
| // One or more metadata entries to attach. |
| repeated InstanceMetadata metadata = 3; |
| } |
| |
| |
| message DetachMetadataRequest { |
| // The package that holds the instance we detach metadata from. |
| string package = 1; |
| // The instance we detach metadata from. |
| ObjectRef instance = 2; |
| // Entries to detach: only 'fingerprint' or 'key'+'value' are used. |
| repeated InstanceMetadata metadata = 3; |
| } |
| |
| |
| message ListMetadataRequest { |
| // The package that holds the instance we list metadata of. |
| string package = 1; |
| // The instance to list metadata of. |
| ObjectRef instance = 2; |
| // Metadata keys to limit the listing to or empty to list all metadata. |
| repeated string keys = 3; |
| |
| // Number of results to return on one page. Ignored for now. |
| int32 page_size = 20; |
| // Value of 'next_page_token' from the previous response. |
| string page_token = 21; |
| } |
| |
| |
| message ListMetadataResponse { |
| // Discovered metadata ordered by 'attached_ts' (the most recent first). |
| repeated InstanceMetadata metadata = 1; |
| // Value to pass as 'page_token' in ListMetadataRequest to resume fetching or |
| // an empty string if there's no more results. |
| string next_page_token = 20; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message ResolveVersionRequest { |
| // The package that contains the instance we are resolving version of. |
| string package = 1; |
| // The version string to resolve, see ResolveVersion for details. |
| string version = 2; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message GetInstanceURLRequest { |
| // The package that holds the instance we want to get URL of. |
| string package = 1; |
| // The instance we want to get URL of. |
| ObjectRef instance = 2; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| // Processor describes a state of some post-registration processing step |
| // performed on an instance. |
| message Processor { |
| enum State { |
| STATE_UNSPECIFIED = 0; |
| PENDING = 1; |
| SUCCEEDED = 2; |
| FAILED = 3; |
| } |
| |
| // Internal identifier of the processor, e.g. "cipd_client_binary:v1" |
| string id = 1; |
| // The state of this processor, see the enum. |
| State state = 2; |
| // When the processor finished running (successfully or not). |
| google.protobuf.Timestamp finished_ts = 3; |
| // For SUCCEEDED state, result of the processing. |
| google.protobuf.Struct result = 4; |
| // For FAILED state, the error message. |
| string error = 5; |
| } |
| |
| |
| message DescribeInstanceRequest { |
| // The package that holds the instance we want to get the info for. |
| string package = 1; |
| // The instance we want to get the info for. |
| ObjectRef instance = 2; |
| |
| // Whether the response should include "refs" field. |
| bool describe_refs = 3; |
| // Whether the response should include "tags" field. |
| bool describe_tags = 4; |
| // Whether the response should include "processors" field. |
| bool describe_processors = 5; |
| } |
| |
| |
| message DescribeInstanceResponse { |
| // The instance with all output fields filled in. |
| Instance instance = 1; |
| |
| // Refs pointing to the instance, sorted by modification time, most recent |
| // first. |
| // |
| // Present only if the request has describe_refs == true. |
| repeated Ref refs = 2; |
| |
| // Tags attached to the instance, sorted by the tag key first, and then |
| // by the timestamp (most recent first). |
| // |
| // Present only if the request has describe_tags == true. |
| repeated Tag tags = 3; |
| |
| // State of the processors that handled the instance (if any), sorted by their |
| // ID. |
| // |
| // Present only if the request has describe_processors == true. |
| repeated Processor processors = 4; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message DescribeClientRequest { |
| // The CIPD client package we want to get info about. |
| // |
| // For example 'infra/tools/cipd/linux-amd64'. |
| string package = 1; |
| |
| // The client instance we want to get the info about. |
| ObjectRef instance = 2; |
| } |
| |
| |
| message DescribeClientResponse { |
| // The instance with all output fields filled in. |
| Instance instance = 1; |
| |
| // Reference to the extracted client binary in the storage. |
| // |
| // The hash algo here always matches the algo used when uploading the client |
| // package file. |
| // |
| // Clients should expect to find an algo here that they do not support (if |
| // the server was updated to support a better algo). They should pick the best |
| // algo they support from client_ref_aliases list and use it for validation. |
| // |
| // Thus this field is mostly FYI. |
| ObjectRef client_ref = 2; |
| |
| // Signed URL pointing to the extracted client binary in the storage. |
| ObjectURL client_binary = 3; |
| |
| // Size of the client binary in bytes. |
| int64 client_size = 4; |
| |
| // SHA1 digest of the client binary (as hex string). |
| // |
| // Used only by old clients and present here for backward compatibility |
| // reasons. |
| // |
| // Newer clients must verify one of client_ref_aliases instead. |
| string legacy_sha1 = 5; |
| |
| // Contains hashes of the client binary calculated using ALL algos supported |
| // by the server at the time the client package was uploaded. |
| // |
| // The callers that want to verify the client binary hash should pick the best |
| // algo they understand. |
| // |
| // The list at least includes 'client_ref' itself and SHA1 hash (matching |
| // legacy_sha1). The order is undefined. |
| repeated ObjectRef client_ref_aliases = 6; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| message DescribeBootstrapBundleRequest { |
| // The package prefix that contains the bootstrap packages being described. |
| string prefix = 1; |
| |
| // If given, specifies exactly what packages to examine. |
| // |
| // Examined package names will be formed as "<prefix>/<variant>". |
| // |
| // Based on existing package naming conventions, `variants` usually would be |
| // an enumeration of platforms (e.g. ["linux-amd64", "mac-amd64", ...]). |
| // |
| // If empty, the CIPD backend will describe all packages directly under the |
| // prefix (if any). If there are no packages under the prefix, the request |
| // fails with NOT_FOUND. |
| repeated string variants = 2; |
| |
| // The package version to describe, see ResolveVersion for details. |
| // |
| // Applies to all packages matching `prefix` + `variants`. |
| // |
| // If *all* packages lack this version, the request fails with NOT_FOUND. |
| // |
| // If only some packages lack this version, their corresponding BootstrapFile |
| // entries in DescribeBootstrapBundleRequest will have google.rpc.Status set |
| // to NOT_FOUND. |
| string version = 3; |
| } |
| |
| |
| message DescribeBootstrapBundleResponse { |
| message BootstrapFile { |
| string package = 1; // the package the file was extracted from |
| google.rpc.Status status = 2; // not OK on errors related to this package |
| ObjectRef instance = 3; // the resolved package instance |
| ObjectRef file = 4; // the extracted file in the CAS |
| string name = 5; // the name of the extracted file |
| int64 size = 6; // its size in bytes |
| } |
| repeated BootstrapFile files = 1; |
| } |