diff --git a/README.md b/README.md index beab6dd..d4bcae7 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ supported for the TLS-required NVMe path. - `ktls-utils` with `tlshd` active for NVMe/TCP - `nvme-cli` for PSK generation and validation - configfs mounted at `/sys/kernel/config` -- an LVM volume group dedicated to kouja; do not point kouja at the root VG +- one or more LVM volume groups dedicated to kouja; do not point kouja at the root VG - a server certificate, server private key, and client CA for mTLS ### Initiator nodes @@ -288,6 +288,37 @@ targets: The VGs listed under `storage.vgs` are registered on startup. An administrator can also register one through the admin API. +### Multiple storage classes on one host + +A single agent can serve several LVM backends. Map a stable class name to each +volume group, for example the NVMe, SSD, and HDD pools on one physical machine: + +```yaml +storage: + headroom_percent: 5 + headroom_min_bytes: 1073741824 + wipe_timeout_seconds: 1800 + classes: + nvme: kouja-nvme + ssd: kouja-ssd + hdd: kouja-hdd +``` + +The VGs referenced by `classes` are added to the first-start registration set. + +```sh +sudo vgcreate kouja-nvme /dev/disk/by-id/ +sudo vgcreate kouja-ssd /dev/disk/by-id/ +sudo vgcreate kouja-hdd /dev/disk/by-id/ +``` + +Callers select a class in the API with `storage_class`, or in Kubernetes with +the StorageClass parameter `class`. The agent resolves the class to its VG and +reports the class on capacity and volume responses. A raw `vg` parameter still +works for existing callers; when no class map is configured, the VG name is +used as its own class. The VG remains the durable backend identity; the class +is the selection and presentation label. + ## API quick start All API calls require a client certificate trusted by the agent. A caller with @@ -301,6 +332,25 @@ CURL=(curl --http2 --cacert ca.crt --cert admin.crt --key admin.key) "${CURL[@]}" https://storage.example:9443/healthz "${CURL[@]}" https://storage.example:9443/v1/info "${CURL[@]}" https://storage.example:9443/v1/capacity +"${CURL[@]}" https://storage.example:9443/v1/storage-classes +``` + +`GET /v1/storage-classes` is available to any authenticated client, not only +administrators. It returns the configured class name, backing VG, availability, +and capacity: + +```json +{ + "classes": [ + { + "name": "hdd", + "vgName": "kouja-hdd", + "vgState": "active", + "allocatableBytes": "264241152", + "maxVolumeBytes": "264241152" + } + ] +} ``` Create and export a 1 GiB iSCSI volume: @@ -345,6 +395,8 @@ POST /v1/volumes/{id}:rotate-credential DELETE /v1/volumes/{id} GET /v1/volumes GET /v1/volumes/{id}/credential +GET /v1/capacity +GET /v1/storage-classes POST /v1/admin/vgs GET /v1/admin/vgs POST /v1/admin/drift/{id}:resolve diff --git a/cmd/kouja-agent/main.go b/cmd/kouja-agent/main.go index 778f2aa..22eb59c 100644 --- a/cmd/kouja-agent/main.go +++ b/cmd/kouja-agent/main.go @@ -89,7 +89,7 @@ func run() error { ) iscsi := target.NewISCSI(target.NewConfigFS("")) nvme := target.NewNVMe(target.NewConfigFS("")) - if err := agent.InitializeVGs(context.Background(), store, lvmBackend, cfg.Storage.VGs); err != nil { + if err := agent.InitializeVGs(context.Background(), store, lvmBackend, cfg.EffectiveVGs()); err != nil { return err } @@ -112,22 +112,24 @@ func run() error { cfg.Admission.CapacityRequestsPerSec, ) volumeService := agent.NewVolumeService(store, lvmBackend, manager, credentials, agent.ServiceOptions{ - HostUUID: hostUUID, - AgentVersion: agentVersion, - APIVersion: apiVersion, - ISCSIEnabled: cfg.Targets.ISCSI.Enabled, - ISCSIPrefix: cfg.Targets.ISCSI.IQNPrefix, - ISCSIPortals: cfg.Targets.ISCSI.Portals, - NVMeEnabled: cfg.Targets.NVMeTCP.Enabled, - NVMePrefix: cfg.Targets.NVMeTCP.NQNPrefix, - NVMePortals: cfg.Targets.NVMeTCP.Portals, - Ready: ready.Load, - Admission: admission, + HostUUID: hostUUID, + AgentVersion: agentVersion, + APIVersion: apiVersion, + ISCSIEnabled: cfg.Targets.ISCSI.Enabled, + ISCSIPrefix: cfg.Targets.ISCSI.IQNPrefix, + ISCSIPortals: cfg.Targets.ISCSI.Portals, + NVMeEnabled: cfg.Targets.NVMeTCP.Enabled, + NVMePrefix: cfg.Targets.NVMeTCP.NQNPrefix, + NVMePortals: cfg.Targets.NVMeTCP.Portals, + Ready: ready.Load, + Admission: admission, + StorageClasses: cfg.Storage.Classes, }) adminService := agent.NewAdminService(store, lvmBackend, agent.WithTargetExporters(map[string]target.Exporter{"iscsi": iscsi, "nvme-tcp": nvme}), agent.WithCredentialManager(credentials), agent.WithDriftRetrier(manager), + agent.WithStorageClasses(cfg.Storage.Classes), ) server, err := agent.NewServer(cfg, volumeService, adminService, agent.WithReadiness(ready.Load), agent.WithMetrics(metrics)) diff --git a/deploy/install/install.sh b/deploy/install/install.sh index 21637b8..6a55aba 100755 --- a/deploy/install/install.sh +++ b/deploy/install/install.sh @@ -37,6 +37,7 @@ storage: headroom_min_bytes: 1073741824 wipe_timeout_seconds: 1800 vgs: [] + classes: {} targets: iscsi: enabled: true diff --git a/deploy/kubernetes/csi/kouja-csi.yaml b/deploy/kubernetes/csi/kouja-csi.yaml index 1c24adb..a9bb3a2 100644 --- a/deploy/kubernetes/csi/kouja-csi.yaml +++ b/deploy/kubernetes/csi/kouja-csi.yaml @@ -105,6 +105,8 @@ spec: volumeLifecycleModes: - Persistent --- +# The parameters can select a raw LVM VG (`vg`) or a host-configured storage +# class (`class`, for example nvme/ssd/hdd). Use one or the other. apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: diff --git a/docs/csi.md b/docs/csi.md index 68be032..864552d 100644 --- a/docs/csi.md +++ b/docs/csi.md @@ -129,7 +129,8 @@ Parameters: | Parameter | Required | Meaning | |---|---|---| -| `vg` | yes | Registered LVM volume group on the selected kouja host. | +| `class` | one of `class`/`vg` | Storage class configured on the agent, for example `nvme`, `ssd`, or `hdd`. The agent maps it to a registered LVM volume group. | +| `vg` | one of `class`/`vg` | Registered LVM volume group on the selected kouja host. Use this for existing deployments or when no class mapping exists. | | `protocol` | no | `iscsi` (default) or `nvme-tcp`. The NVMe path requires TLS 1.3 PSK support on the target and `tlshd` on the node. | | `initiator` | yes for attach | IQN for iSCSI or NQN for NVMe-oF/TCP. It must match the node plugin's initiator. | | `csi.storage.k8s.io/fstype` | no | `ext4` (default in the example). `xfs` is accepted by the node formatter only when `mkfs.xfs` is present in the node image. | @@ -140,6 +141,38 @@ The initiator value is passed through the PV's volume context. A production deployment should derive it from the CSINode annotation described in the design rather than storing a single cluster-wide IQN. +To expose multiple backends from the same host, map classes on the agent and +reference them from separate Kubernetes StorageClasses: + +```yaml +# agent /etc/kouja/config.yaml +storage: + classes: + nvme: kouja-nvme + ssd: kouja-ssd + hdd: kouja-hdd +--- +# Kubernetes +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: kouja-hdd +provisioner: kouja.csi.voidstarit.com +parameters: + class: hdd + protocol: iscsi + initiator: iqn.2026-11.io.kouja:kind-node +reclaimPolicy: Delete +allowVolumeExpansion: true +volumeBindingMode: Immediate +``` + +The controller filters hosts by the capacity response's storage class, so a +PVC is only placed on an agent that advertises that class. A class that is not +mapped on the agent falls back to the raw VG name for backward compatibility. +Clients can inspect the available classes with `GET /v1/storage-classes`; the +response includes the backing VG, availability, and current capacity. + ## Controller flags ```text @@ -155,7 +188,7 @@ design rather than storing a single cluster-wide IQN. `--hosts` may contain one or more agent endpoints. The controller calls `GetInfo` and `GetCapacity` to select a ready host that supports the requested -protocol and has enough allocatable space in the requested VG. +protocol and has enough allocatable space in the requested class or VG. ## Deployment notes diff --git a/docs/designs/kouja.md b/docs/designs/kouja.md index 387c7cc..0dad97b 100644 --- a/docs/designs/kouja.md +++ b/docs/designs/kouja.md @@ -208,6 +208,7 @@ Key request fields: * `ResizeVolumeRequest`: `size_bytes`, `allow_shrink` (default false). * `DeleteVolumeRequest`: `force` (default false). * `GetCapacityResponse`: one entry per registered VG with `vg_name`, `vg_uuid`, `vg_state`, `total_bytes`, `free_bytes`, `allocatable_bytes`, `extent_size_bytes`, `max_volume_bytes`, and `observed_at`. +* `ListStorageClassesResponse`: one entry per configured class with `name`, backing VG, state, and the same capacity fields. * `ImportVolumeRequest`: `volume_id`, `owner`, `vg`, `lv_uuid` (LVM UUID) or `lv_name`, `size_bytes`, `export_spec`, `target_name`, `lun` or `nsid`, `credential` (oneof CHAP or TLS-PSK), `allow_active_sessions`. * `GrantCredentialRequest`: `volume_id`, `node_id`, `node_caller_id`, `expires_at`. @@ -260,7 +261,7 @@ HTTP paths: * `POST /v1/volumes/{volume_id}:export`, `POST /v1/volumes/{volume_id}:unexport` * `POST /v1/volumes/{volume_id}:resize`, `DELETE /v1/volumes/{volume_id}` * `GET /v1/volumes/{volume_id}/credential`, `POST /v1/volumes/{volume_id}:rotate-credential` -* `GET /v1/capacity`, `GET /v1/info` +* `GET /v1/capacity`, `GET /v1/storage-classes`, `GET /v1/info` * `POST /v1/admin/vgs`, `DELETE /v1/admin/vgs/{vg_name}`, `GET /v1/admin/vgs` * `POST /v1/admin/import`, `POST /v1/admin/drift/{volume_id}:resolve`, `GET /v1/admin/orphans` * `POST /v1/admin/ownership:transfer`, `DELETE /v1/admin/volumes/{volume_id}` @@ -644,13 +645,13 @@ Credentials are encrypted at rest with AES-256-GCM. Each row stores a unique non * `vg_state` and `observed_at`. * The agent queries LVM on each request and does not persist a capacity cache. -`CreateVolume` requires `vg`. The agent serializes the capacity check and the LVM allocation with a per-VG lock. The per-VG lock prevents racing kouja allocations. `ResourceExhausted` is returned when the actual LVM allocation fails or the request exceeds the current allocatable size. The CSI driver tries the next eligible host up to three times. +`CreateVolume` requires either a configured `storage_class` or a raw `vg`. The agent resolves a class to its VG and serializes the capacity check and the LVM allocation with a per-VG lock. The per-VG lock prevents racing kouja allocations. `ResourceExhausted` is returned when the actual LVM allocation fails or the request exceeds the current allocatable size. The CSI driver tries the next eligible host up to three times. The CSI driver selects a host by: 1. Resolving the StorageClass SRV record. 2. Calling `GetInfo` and `GetCapacity` on every endpoint in parallel, with a 2-second timeout. -3. Filtering to hosts that are ready, support the requested protocol, have the requested VG, have `vg_state=active`, and have `allocatable_bytes >= requested size` and `max_volume_bytes >= requested size`. +3. Filtering to hosts that are ready, support the requested protocol, have the requested class or VG, have `vg_state=active`, and have `allocatable_bytes >= requested size` and `max_volume_bytes >= requested size`. 4. Choosing the host with the largest `allocatable_bytes`; ties break by host UUID. 5. Calling `CreateVolume`; on `ResourceExhausted`, removing that host and trying the next. 6. Caching the inventory for at most 10 seconds; the cache is invalidated on an unreachable host or a `ResourceExhausted` response. @@ -670,12 +671,12 @@ The driver name is `kouja.csi.voidstarit.com`. It advertises these capabilities: `CreateVolume`: -1. Parse the StorageClass parameters: `srvRecord`, `vg` (required), `protocol`, optional `wipe`. +1. Parse the StorageClass parameters: `srvRecord`, `class` or `vg` (one required), `protocol`, optional `wipe`. 2. Derive a stable placement key from the CSI request name and StorageClass. 3. Look up a `KoujaVolumePlacement` custom resource with `resourceVersion` compare-and-swap; the external-provisioner supplies leader election. If it exists and is `Bound`, use that host. If it is `Pending`, query the recorded host; if the volume exists, bind it; if not, resume the create on that host. If it is `Failed`, follow the recorded retry path. If the host is unreachable, return `Unavailable` and do not create on another host. -4. If no record exists, resolve the SRV record, select a host by capacity, and write a `Pending` placement record with the selected host and an idempotency key before calling `CreateVolume` with `export=false`, the size, the VG, and `wipe`. +4. If no record exists, resolve the SRV record, select a host by capacity, and write a `Pending` placement record with the selected host and an idempotency key before calling `CreateVolume` with `export=false`, the size, the class or VG, and `wipe`. 5. On success, update the record to `Bound` with the returned `host_uuid` and `resource_uuid`. On failure, delete the pending record or mark it `Failed` with the error; a retry resolves the record before creating. -6. Return `v1::` as the volume handle and the actual capacity. The volume context includes the host UUID, resource UUID, protocol, VG, control endpoint, and portal. +6. Return `v1::` as the volume handle and the actual capacity. The volume context includes the host UUID, resource UUID, protocol, class, VG, control endpoint, and portal. If the pending record cannot be written, the driver does not call `CreateVolume`. If the response is lost, the pending record identifies the host and idempotency key, and a retry queries that host before creating anywhere else. The driver never returns a handle that is not durably recorded. @@ -705,7 +706,7 @@ If the pending record cannot be written, the driver does not call `CreateVolume` `DeleteVolume` calls `DeleteVolume` with `force=false`. `SESSION_ACTIVE` is returned as a retryable error. An administrator can force-delete through the API if the consumer is gone. -`GetCapacity` sums `allocatable_bytes` across ready hosts that match the StorageClass SRV record, protocol, and required VG. It returns the sum as `available_capacity` and the maximum of `max_volume_bytes` as `maximum_volume_size`. It does not reserve capacity. +`GetCapacity` sums `allocatable_bytes` across ready hosts that match the StorageClass SRV record, protocol, and required class or VG. It returns the sum as `available_capacity` and the maximum of `max_volume_bytes` as `maximum_volume_size`. It does not reserve capacity. Node topology is empty. The first version assumes every Kubernetes node can reach every portal returned by the SRV record. An operator who needs network zones scopes the SRV record per zone and creates one StorageClass per zone. @@ -809,6 +810,7 @@ storage: headroom_min_bytes: 1073741824 wipe_timeout_seconds: 1800 # base; deadline is max(base, 1 second per GiB) vgs: [] # names to seed on first start; the admin API is authoritative afterward + classes: {} # optional class -> VG mappings, e.g. nvme: vg-nvme targets: iscsi: enabled: true @@ -1478,6 +1480,9 @@ message RotateCredentialResponse { string credential = 1; string operation_id = message Capacity { string vg_name = 1; string vg_uuid = 2; string vg_state = 3; int64 total_bytes = 4; int64 free_bytes = 5; int64 allocatable_bytes = 6; int64 extent_size_bytes = 7; int64 max_volume_bytes = 8; google.protobuf.Timestamp observed_at = 9; } message GetCapacityRequest {} message GetCapacityResponse { repeated Capacity vgs = 1; } +message ListStorageClassesRequest {} +message StorageClass { string name = 1; string vg_name = 2; string vg_uuid = 3; string vg_state = 4; int64 total_bytes = 5; int64 free_bytes = 6; int64 allocatable_bytes = 7; int64 extent_size_bytes = 8; int64 max_volume_bytes = 9; google.protobuf.Timestamp observed_at = 10; } +message ListStorageClassesResponse { repeated StorageClass classes = 1; } message GetInfoRequest {} message GetInfoResponse { string host_uuid = 1; string agent_version = 2; string api_version = 3; repeated Protocol protocols = 4; repeated string auth_modes = 5; bool ready = 6; } @@ -1515,6 +1520,7 @@ service VolumeService { rpc GetCredential(GetCredentialRequest) returns (GetCredentialResponse) { option (google.api.http) = { get: "/v1/volumes/{volume_id}/credential" }; } rpc RotateCredential(RotateCredentialRequest) returns (RotateCredentialResponse) { option (google.api.http) = { post: "/v1/volumes/{volume_id}:rotate-credential" body: "*" }; } rpc GetCapacity(GetCapacityRequest) returns (GetCapacityResponse) { option (google.api.http) = { get: "/v1/capacity" }; } + rpc ListStorageClasses(ListStorageClassesRequest) returns (ListStorageClassesResponse) { option (google.api.http) = { get: "/v1/storage-classes" }; } rpc GetInfo(GetInfoRequest) returns (GetInfoResponse) { option (google.api.http) = { get: "/v1/info" }; } } diff --git a/docs/e2e.md b/docs/e2e.md index c328de1..e674fb2 100644 --- a/docs/e2e.md +++ b/docs/e2e.md @@ -27,6 +27,32 @@ The agent used SQLite state, an mTLS gRPC/HTTP listener, a loop-backed LVM VG, t The final two-VM test used the agent binary built after the operation-journal tombstone-retirement fix, so a stale delete operation from a previous volume cannot replay against a new volume. +## Multiple storage classes on one host + +A separate two-VM QEMU/KVM run validated the class-aware backend selection: + +* The storage host had two loop-backed LVM VGs, `kouja-nvme` and `kouja-hdd`, + configured only through `storage.classes`: + `nvme: kouja-nvme` and `hdd: kouja-hdd`. +* `GET /v1/capacity` returned both VGs with `storageClass: nvme` and + `storageClass: hdd`. +* `GET /v1/storage-classes`, called with a non-admin caller certificate, + returned both classes with their backing VGs and active capacity. +* Creating a volume with `storageClass: hdd` and no `vg` produced an LV in + `kouja-hdd`, and the API response reported `storageClass: hdd`. +* The consumer logged into the iSCSI target with CHAP, wrote 8 MiB, read it + back, and matched the MD5 (`class-hdd-iscsi-write-read-ok`). +* Deleting while the session was active returned `SESSION_ACTIVE`; after logout + the delete succeeded and left no LV, backstore, or target. +* Creating a volume with `storageClass: nvme` landed in `kouja-nvme`. + A request with `storageClass: nvme` and `vg: kouja-hdd` was rejected with + `InvalidArgument`. +* A CSI controller pointed at the agent selected the `hdd` class for + `GetCapacity`, created and published a volume, returned + `storage_class: hdd` in the volume context, and completed an 8 MiB write/read + through the publish context before unpublish and delete + (`csi-class-publish-write-read-ok`). + ## NVMe/TCP TLS `TestNVMeTLSAdapterLifecycle` passed on the storage VM: diff --git a/gen/kouja/v1/common.pb.go b/gen/kouja/v1/common.pb.go index 3f2aa18..8124f20 100644 --- a/gen/kouja/v1/common.pb.go +++ b/gen/kouja/v1/common.pb.go @@ -393,8 +393,11 @@ type Volume struct { CreatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` LegacyIdentity map[string]string `protobuf:"bytes,13,rep,name=legacy_identity,json=legacyIdentity,proto3" json:"legacy_identity,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Storage class selected for this volume. The LVM volume group remains the + // canonical backend identity; this is the policy/category label. + StorageClass string `protobuf:"bytes,14,opt,name=storage_class,json=storageClass,proto3" json:"storage_class,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Volume) Reset() { @@ -518,6 +521,13 @@ func (x *Volume) GetLegacyIdentity() map[string]string { return nil } +func (x *Volume) GetStorageClass() string { + if x != nil { + return x.StorageClass + } + return "" +} + type Export struct { state protoimpl.MessageState `protogen:"open.v1"` Protocol Protocol `protobuf:"varint,1,opt,name=protocol,proto3,enum=kouja.v1.Protocol" json:"protocol,omitempty"` @@ -761,8 +771,11 @@ type Capacity struct { ExtentSizeBytes int64 `protobuf:"varint,7,opt,name=extent_size_bytes,json=extentSizeBytes,proto3" json:"extent_size_bytes,omitempty"` MaxVolumeBytes int64 `protobuf:"varint,8,opt,name=max_volume_bytes,json=maxVolumeBytes,proto3" json:"max_volume_bytes,omitempty"` ObservedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=observed_at,json=observedAt,proto3" json:"observed_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Storage class configured for this volume group, or the VG name when no + // explicit class mapping exists. + StorageClass string `protobuf:"bytes,10,opt,name=storage_class,json=storageClass,proto3" json:"storage_class,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Capacity) Reset() { @@ -858,6 +871,13 @@ func (x *Capacity) GetObservedAt() *timestamppb.Timestamp { return nil } +func (x *Capacity) GetStorageClass() string { + if x != nil { + return x.StorageClass + } + return "" +} + var File_kouja_v1_common_proto protoreflect.FileDescriptor var file_kouja_v1_common_proto_rawDesc = []byte{ @@ -865,7 +885,7 @@ var file_kouja_v1_common_proto_rawDesc = []byte{ 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0xfa, 0x04, 0x0a, 0x06, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x14, 0x0a, + 0x74, 0x6f, 0x22, 0x9f, 0x05, 0x0a, 0x06, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, @@ -900,163 +920,168 @@ var file_kouja_v1_common_proto_rawDesc = []byte{ 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x6c, 0x65, - 0x67, 0x61, 0x63, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x41, 0x0a, 0x13, - 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0xbf, 0x02, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, - 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, - 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x75, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6c, 0x75, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x73, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6e, 0x73, 0x69, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x67, 0x61, 0x63, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x23, 0x0a, 0x0d, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbf, 0x02, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, + 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1f, 0x0a, + 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x6c, 0x75, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6c, 0x75, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x73, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x6e, 0x73, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6b, 0x6f, + 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0d, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x16, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xdc, 0x03, 0x0a, 0x0b, 0x4f, 0x62, 0x73, 0x65, 0x72, + 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x76, 0x5f, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x76, 0x50, 0x72, + 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x11, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x0a, + 0x11, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, + 0x6c, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x61, 0x63, 0x6c, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3b, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x22, 0xdc, 0x03, 0x0a, 0x0b, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x76, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x76, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, - 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x6f, - 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x74, - 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x73, - 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x10, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x6c, 0x5f, 0x70, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x63, 0x6c, 0x50, - 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x0e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x3b, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x12, - 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, - 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x64, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x6f, - 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6f, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x22, 0xd7, 0x02, 0x0a, 0x08, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x17, 0x0a, - 0x07, 0x76, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x76, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x76, 0x67, 0x5f, 0x75, 0x75, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x67, 0x55, 0x75, 0x69, 0x64, 0x12, - 0x19, 0x0a, 0x08, 0x76, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x76, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x66, - 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x6c, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, - 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, - 0x74, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d, - 0x61, 0x78, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x3b, 0x0a, - 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, - 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x41, 0x74, 0x2a, 0x4f, 0x0a, 0x08, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, - 0x4f, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x49, 0x53, 0x43, - 0x53, 0x49, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, - 0x5f, 0x4e, 0x56, 0x4d, 0x45, 0x5f, 0x54, 0x43, 0x50, 0x10, 0x02, 0x2a, 0x9a, 0x02, 0x0a, 0x0b, - 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x56, - 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x4f, 0x4c, - 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x49, - 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, - 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, - 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, - 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, - 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x4f, 0x4c, 0x55, 0x4d, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x49, 0x5a, 0x49, 0x4e, 0x47, - 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x18, 0x0a, - 0x14, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, - 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x07, 0x12, 0x17, 0x0a, 0x13, 0x56, 0x4f, 0x4c, 0x55, 0x4d, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x08, - 0x12, 0x16, 0x0a, 0x12, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, - 0x5f, 0x44, 0x52, 0x49, 0x46, 0x54, 0x10, 0x09, 0x2a, 0xce, 0x01, 0x0a, 0x0b, 0x45, 0x78, 0x70, - 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x50, 0x4f, - 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x49, 0x4e, 0x47, - 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1c, 0x0a, - 0x18, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, - 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x45, - 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x45, 0x58, - 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x58, 0x50, 0x4f, - 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, - 0x05, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x44, 0x52, 0x49, 0x46, 0x54, 0x10, 0x06, 0x2a, 0x7a, 0x0a, 0x0c, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x53, - 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x45, 0x53, 0x53, - 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x01, - 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, - 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x2a, 0x93, 0x02, 0x0a, 0x0b, 0x44, 0x72, 0x69, 0x66, 0x74, 0x52, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, - 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x56, 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, - 0x1e, 0x0a, 0x1a, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x4d, 0x49, 0x53, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x02, 0x12, - 0x1e, 0x0a, 0x1a, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, - 0x21, 0x0a, 0x1d, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, - 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, - 0x4f, 0x4e, 0x5f, 0x41, 0x43, 0x4c, 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x05, 0x12, - 0x23, 0x0a, 0x1f, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4d, 0x49, 0x53, 0x4d, 0x41, 0x54, - 0x43, 0x48, 0x10, 0x06, 0x12, 0x25, 0x0a, 0x21, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, - 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, - 0x44, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x07, 0x2a, 0xf3, 0x01, 0x0a, 0x0d, - 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, - 0x1a, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, - 0x1a, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, - 0x1d, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, - 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, - 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, - 0x44, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, - 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x54, 0x52, 0x59, 0x10, 0x05, 0x12, 0x22, 0x0a, - 0x1e, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x52, 0x45, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x10, - 0x06, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x76, 0x6f, 0x69, 0x64, 0x73, 0x74, 0x61, 0x72, 0x69, 0x74, 0x2f, 0x6b, 0x6f, 0x75, 0x6a, 0x61, - 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x76, 0x31, 0x3b, 0x6b, 0x6f, - 0x75, 0x6a, 0x61, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, + 0x12, 0x3b, 0x0a, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0a, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xfc, 0x02, 0x0a, 0x08, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, + 0x74, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x76, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x76, + 0x67, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x67, + 0x55, 0x75, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x2b, 0x0a, 0x11, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x61, 0x6c, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x53, + 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x2a, 0x4f, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x12, 0x18, 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x52, + 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x49, 0x53, 0x43, 0x53, 0x49, 0x10, 0x01, 0x12, 0x15, + 0x0a, 0x11, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4e, 0x56, 0x4d, 0x45, 0x5f, + 0x54, 0x43, 0x50, 0x10, 0x02, 0x2a, 0x9a, 0x02, 0x0a, 0x0b, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1a, + 0x0a, 0x16, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, + 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x4f, + 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, + 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, + 0x04, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x52, 0x45, 0x53, 0x49, 0x5a, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, + 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, 0x4c, + 0x45, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x4f, 0x4c, 0x55, 0x4d, + 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, + 0x07, 0x12, 0x17, 0x0a, 0x13, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x08, 0x12, 0x16, 0x0a, 0x12, 0x56, 0x4f, + 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x52, 0x49, 0x46, 0x54, + 0x10, 0x09, 0x2a, 0xce, 0x01, 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, + 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, + 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, + 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x50, 0x4f, 0x52, + 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, + 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, + 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x45, + 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x52, 0x49, 0x46, + 0x54, 0x10, 0x06, 0x2a, 0x7a, 0x0a, 0x0c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, + 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x2a, + 0x93, 0x02, 0x0a, 0x0b, 0x44, 0x72, 0x69, 0x66, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, + 0x1c, 0x0a, 0x18, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, + 0x16, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x56, + 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x52, 0x49, + 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x4d, + 0x49, 0x53, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x52, 0x49, + 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, + 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x21, 0x0a, 0x1d, 0x44, 0x52, 0x49, + 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x50, + 0x41, 0x43, 0x45, 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, + 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x41, 0x43, 0x4c, + 0x5f, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x52, 0x49, + 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, + 0x54, 0x4f, 0x52, 0x5f, 0x4d, 0x49, 0x53, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x06, 0x12, 0x25, + 0x0a, 0x21, 0x44, 0x52, 0x49, 0x46, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, + 0x4e, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x45, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x10, 0x07, 0x2a, 0xf3, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x1a, 0x52, 0x45, 0x53, 0x4f, 0x4c, + 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x52, 0x45, 0x53, 0x4f, 0x4c, + 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x53, 0x4f, 0x4c, + 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x41, + 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x45, + 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x52, + 0x4b, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, + 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, + 0x41, 0x52, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x18, 0x0a, + 0x14, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x52, 0x45, 0x54, 0x52, 0x59, 0x10, 0x05, 0x12, 0x22, 0x0a, 0x1e, 0x52, 0x45, 0x53, 0x4f, 0x4c, + 0x56, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x43, 0x52, 0x45, 0x41, + 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x10, 0x06, 0x42, 0x32, 0x5a, 0x30, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6f, 0x69, 0x64, 0x73, 0x74, + 0x61, 0x72, 0x69, 0x74, 0x2f, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6b, + 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x76, 0x31, 0x3b, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x76, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/gen/kouja/v1/volume.pb.go b/gen/kouja/v1/volume.pb.go index 56f8099..a2bf2ae 100644 --- a/gen/kouja/v1/volume.pb.go +++ b/gen/kouja/v1/volume.pb.go @@ -10,6 +10,7 @@ import ( _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -32,8 +33,11 @@ type CreateVolumeRequest struct { Wipe bool `protobuf:"varint,7,opt,name=wipe,proto3" json:"wipe,omitempty"` RequestId string `protobuf:"bytes,8,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` IncludeCredential *bool `protobuf:"varint,9,opt,name=include_credential,json=includeCredential,proto3,oneof" json:"include_credential,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Optional host storage class. When set, the agent resolves it to the + // configured LVM volume group. vg remains supported for compatibility. + StorageClass string `protobuf:"bytes,10,opt,name=storage_class,json=storageClass,proto3" json:"storage_class,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CreateVolumeRequest) Reset() { @@ -129,6 +133,13 @@ func (x *CreateVolumeRequest) GetIncludeCredential() bool { return false } +func (x *CreateVolumeRequest) GetStorageClass() string { + if x != nil { + return x.StorageClass + } + return "" +} + type CreateVolumeResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Volume *Volume `protobuf:"bytes,1,opt,name=volume,proto3" json:"volume,omitempty"` @@ -1280,6 +1291,203 @@ func (x *GetCapacityResponse) GetVgs() []*Capacity { return nil } +type ListStorageClassesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListStorageClassesRequest) Reset() { + *x = ListStorageClassesRequest{} + mi := &file_kouja_v1_volume_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListStorageClassesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListStorageClassesRequest) ProtoMessage() {} + +func (x *ListStorageClassesRequest) ProtoReflect() protoreflect.Message { + mi := &file_kouja_v1_volume_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListStorageClassesRequest.ProtoReflect.Descriptor instead. +func (*ListStorageClassesRequest) Descriptor() ([]byte, []int) { + return file_kouja_v1_volume_proto_rawDescGZIP(), []int{20} +} + +type StorageClass struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Stable class name configured on the agent. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + VgName string `protobuf:"bytes,2,opt,name=vg_name,json=vgName,proto3" json:"vg_name,omitempty"` + VgUuid string `protobuf:"bytes,3,opt,name=vg_uuid,json=vgUuid,proto3" json:"vg_uuid,omitempty"` + VgState string `protobuf:"bytes,4,opt,name=vg_state,json=vgState,proto3" json:"vg_state,omitempty"` + TotalBytes int64 `protobuf:"varint,5,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"` + FreeBytes int64 `protobuf:"varint,6,opt,name=free_bytes,json=freeBytes,proto3" json:"free_bytes,omitempty"` + AllocatableBytes int64 `protobuf:"varint,7,opt,name=allocatable_bytes,json=allocatableBytes,proto3" json:"allocatable_bytes,omitempty"` + ExtentSizeBytes int64 `protobuf:"varint,8,opt,name=extent_size_bytes,json=extentSizeBytes,proto3" json:"extent_size_bytes,omitempty"` + MaxVolumeBytes int64 `protobuf:"varint,9,opt,name=max_volume_bytes,json=maxVolumeBytes,proto3" json:"max_volume_bytes,omitempty"` + ObservedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=observed_at,json=observedAt,proto3" json:"observed_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StorageClass) Reset() { + *x = StorageClass{} + mi := &file_kouja_v1_volume_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StorageClass) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageClass) ProtoMessage() {} + +func (x *StorageClass) ProtoReflect() protoreflect.Message { + mi := &file_kouja_v1_volume_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageClass.ProtoReflect.Descriptor instead. +func (*StorageClass) Descriptor() ([]byte, []int) { + return file_kouja_v1_volume_proto_rawDescGZIP(), []int{21} +} + +func (x *StorageClass) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *StorageClass) GetVgName() string { + if x != nil { + return x.VgName + } + return "" +} + +func (x *StorageClass) GetVgUuid() string { + if x != nil { + return x.VgUuid + } + return "" +} + +func (x *StorageClass) GetVgState() string { + if x != nil { + return x.VgState + } + return "" +} + +func (x *StorageClass) GetTotalBytes() int64 { + if x != nil { + return x.TotalBytes + } + return 0 +} + +func (x *StorageClass) GetFreeBytes() int64 { + if x != nil { + return x.FreeBytes + } + return 0 +} + +func (x *StorageClass) GetAllocatableBytes() int64 { + if x != nil { + return x.AllocatableBytes + } + return 0 +} + +func (x *StorageClass) GetExtentSizeBytes() int64 { + if x != nil { + return x.ExtentSizeBytes + } + return 0 +} + +func (x *StorageClass) GetMaxVolumeBytes() int64 { + if x != nil { + return x.MaxVolumeBytes + } + return 0 +} + +func (x *StorageClass) GetObservedAt() *timestamppb.Timestamp { + if x != nil { + return x.ObservedAt + } + return nil +} + +type ListStorageClassesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Classes []*StorageClass `protobuf:"bytes,1,rep,name=classes,proto3" json:"classes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListStorageClassesResponse) Reset() { + *x = ListStorageClassesResponse{} + mi := &file_kouja_v1_volume_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListStorageClassesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListStorageClassesResponse) ProtoMessage() {} + +func (x *ListStorageClassesResponse) ProtoReflect() protoreflect.Message { + mi := &file_kouja_v1_volume_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListStorageClassesResponse.ProtoReflect.Descriptor instead. +func (*ListStorageClassesResponse) Descriptor() ([]byte, []int) { + return file_kouja_v1_volume_proto_rawDescGZIP(), []int{22} +} + +func (x *ListStorageClassesResponse) GetClasses() []*StorageClass { + if x != nil { + return x.Classes + } + return nil +} + type GetInfoRequest struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -1288,7 +1496,7 @@ type GetInfoRequest struct { func (x *GetInfoRequest) Reset() { *x = GetInfoRequest{} - mi := &file_kouja_v1_volume_proto_msgTypes[20] + mi := &file_kouja_v1_volume_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1300,7 +1508,7 @@ func (x *GetInfoRequest) String() string { func (*GetInfoRequest) ProtoMessage() {} func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { - mi := &file_kouja_v1_volume_proto_msgTypes[20] + mi := &file_kouja_v1_volume_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1313,7 +1521,7 @@ func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoRequest.ProtoReflect.Descriptor instead. func (*GetInfoRequest) Descriptor() ([]byte, []int) { - return file_kouja_v1_volume_proto_rawDescGZIP(), []int{20} + return file_kouja_v1_volume_proto_rawDescGZIP(), []int{23} } type GetInfoResponse struct { @@ -1330,7 +1538,7 @@ type GetInfoResponse struct { func (x *GetInfoResponse) Reset() { *x = GetInfoResponse{} - mi := &file_kouja_v1_volume_proto_msgTypes[21] + mi := &file_kouja_v1_volume_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1342,7 +1550,7 @@ func (x *GetInfoResponse) String() string { func (*GetInfoResponse) ProtoMessage() {} func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { - mi := &file_kouja_v1_volume_proto_msgTypes[21] + mi := &file_kouja_v1_volume_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1355,7 +1563,7 @@ func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoResponse.ProtoReflect.Descriptor instead. func (*GetInfoResponse) Descriptor() ([]byte, []int) { - return file_kouja_v1_volume_proto_rawDescGZIP(), []int{21} + return file_kouja_v1_volume_proto_rawDescGZIP(), []int{24} } func (x *GetInfoResponse) GetHostUuid() string { @@ -1407,284 +1615,326 @@ var file_kouja_v1_volume_proto_rawDesc = []byte{ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x15, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd5, 0x02, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, - 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, - 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x76, 0x67, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x76, 0x67, 0x12, 0x1b, 0x0a, 0x06, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, - 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, - 0x61, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x69, 0x70, 0x65, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x77, 0x69, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x12, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, - 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xac, - 0x01, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, + 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x15, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfa, 0x02, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, + 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x76, + 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x76, 0x67, 0x12, 0x1b, 0x0a, 0x06, 0x65, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x65, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, + 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x69, 0x70, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x77, 0x69, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x12, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, + 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x15, 0x0a, + 0x13, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x22, 0xac, 0x01, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, + 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, + 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x22, 0x87, 0x02, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, + 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x5f, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x10, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x74, 0x74, 0x61, + 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xac, 0x01, + 0x0a, 0x14, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, + 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x12, 0x28, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x69, 0x0a, 0x15, + 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0xae, 0x01, 0x0a, 0x16, 0x55, 0x6e, 0x65, 0x78, + 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x06, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, + 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x06, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x93, 0x01, 0x0a, 0x13, 0x52, 0x65, 0x73, + 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x73, 0x68, 0x72, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x53, 0x68, 0x72, 0x69, 0x6e, 0x6b, 0x12, + 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x84, + 0x02, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, - 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, - 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x87, 0x02, - 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, - 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, - 0x2b, 0x0a, 0x11, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x6f, 0x74, 0x61, - 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, - 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, - 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xac, 0x01, 0x0a, 0x14, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x28, 0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x72, + 0x65, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x11, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x67, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, + 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x58, + 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x2f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x22, 0xfb, 0x01, 0x0a, 0x11, 0x47, 0x65, + 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x2a, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, - 0x6d, 0x65, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, - 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x69, 0x0a, 0x15, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, - 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x64, 0x22, 0xae, 0x01, 0x0a, 0x16, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, - 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, - 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x06, - 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x49, 0x64, 0x22, 0x93, 0x01, 0x0a, 0x13, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, - 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x69, 0x7a, - 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, - 0x73, 0x68, 0x72, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x53, 0x68, 0x72, 0x69, 0x6e, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x84, 0x02, 0x0a, 0x14, 0x52, 0x65, 0x73, - 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x28, 0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x6d, 0x65, 0x52, 0x07, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x08, 0x6f, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x12, 0x28, + 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3a, 0x0a, 0x0d, 0x64, 0x72, 0x69, 0x66, + 0x74, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x72, 0x69, 0x66, 0x74, + 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0c, 0x64, 0x72, 0x69, 0x66, 0x74, 0x52, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x50, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, + 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x69, 0x0a, 0x13, 0x4c, 0x69, 0x73, + 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2a, 0x0a, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x65, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, - 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x5f, - 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x2d, - 0x0a, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x72, 0x65, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x21, 0x0a, - 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, - 0x67, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x58, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x49, 0x64, 0x22, 0x2f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x49, 0x64, 0x22, 0xfb, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x64, 0x65, 0x73, - 0x69, 0x72, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, - 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x07, 0x64, 0x65, - 0x73, 0x69, 0x72, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, - 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x12, 0x3a, 0x0a, 0x0d, 0x64, 0x72, 0x69, 0x66, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x73, - 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, - 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x72, 0x69, 0x66, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, - 0x52, 0x0c, 0x64, 0x72, 0x69, 0x66, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x22, 0x50, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, - 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0x69, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x76, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x6f, - 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x07, 0x76, - 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, - 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x49, - 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x22, 0x8a, 0x01, 0x0a, 0x15, 0x47, 0x65, - 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x55, 0x0a, 0x17, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1d, - 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x7c, 0x0a, - 0x18, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, + 0x75, 0x6d, 0x65, 0x52, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, + 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x49, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x22, + 0x8a, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, + 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x47, - 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x3b, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x76, 0x67, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, 0x03, 0x76, 0x67, 0x73, 0x22, 0x10, - 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0xdb, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x75, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x55, 0x75, 0x69, - 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6b, 0x6f, 0x75, - 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x09, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, - 0x68, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, - 0x75, 0x74, 0x68, 0x4d, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, - 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x32, 0xe9, - 0x09, 0x0a, 0x0d, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x65, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x12, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, - 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x78, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x6f, 0x72, - 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x3a, 0x01, - 0x2a, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, - 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x65, 0x78, 0x70, 0x6f, 0x72, - 0x74, 0x12, 0x80, 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x3a, - 0x01, 0x2a, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, - 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x75, 0x6e, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x78, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x56, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x73, 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x3a, 0x01, 0x2a, 0x22, 0x1e, - 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x6e, - 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1d, - 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, - 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, - 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x65, - 0x0a, 0x09, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1a, 0x2e, 0x6b, 0x6f, - 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, - 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x5f, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x76, - 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x7c, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1e, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, - 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, - 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x12, 0x8f, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x21, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, - 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6b, - 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x3a, 0x01, 0x2a, 0x22, 0x29, 0x2f, 0x76, 0x31, - 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x2d, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x60, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, - 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x76, 0x31, 0x2f, - 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x50, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, - 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, - 0x12, 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6f, 0x69, 0x64, 0x73, 0x74, 0x61, - 0x72, 0x69, 0x74, 0x2f, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6b, 0x6f, - 0x75, 0x6a, 0x61, 0x2f, 0x76, 0x31, 0x3b, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x76, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x55, 0x0a, 0x17, + 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, + 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x22, 0x7c, 0x0a, 0x18, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, + 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x61, + 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, + 0x0a, 0x03, 0x76, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6b, 0x6f, + 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, + 0x03, 0x76, 0x67, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0xef, 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x76, 0x67, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x17, 0x0a, 0x07, 0x76, 0x67, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x76, 0x67, 0x55, 0x75, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x67, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x67, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, + 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x66, 0x72, 0x65, 0x65, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, + 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, + 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x56, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x64, 0x41, 0x74, 0x22, 0x4e, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x30, 0x0a, 0x07, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x52, 0x07, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x65, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xdb, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f, 0x73, + 0x74, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, + 0x73, 0x74, 0x55, 0x75, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, + 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x09, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, + 0x12, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x1d, + 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x4d, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x14, 0x0a, + 0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, + 0x61, 0x64, 0x79, 0x32, 0xe7, 0x0a, 0x0a, 0x0d, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x65, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, + 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x78, 0x0a, 0x0c, + 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1d, 0x2e, 0x6b, + 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x6f, + 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, + 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x23, 0x3a, 0x01, 0x2a, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, + 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x3a, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x80, 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x65, 0x78, 0x70, + 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, + 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, 0x6c, + 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x6f, 0x75, + 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x25, 0x3a, 0x01, 0x2a, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, + 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, + 0x3a, 0x75, 0x6e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x78, 0x0a, 0x0c, 0x52, 0x65, 0x73, + 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, + 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, + 0x3a, 0x01, 0x2a, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, + 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x73, + 0x69, 0x7a, 0x65, 0x12, 0x6e, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, + 0x75, 0x6d, 0x65, 0x12, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, + 0x69, 0x64, 0x7d, 0x12, 0x65, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x12, 0x1a, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6b, + 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x5f, 0x0a, 0x0b, 0x4c, 0x69, + 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, + 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, + 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x7c, 0x0a, 0x0d, 0x47, + 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1e, 0x2e, 0x6b, + 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, + 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x73, 0x2f, 0x7b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x8f, 0x01, 0x0a, 0x10, 0x52, 0x6f, + 0x74, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x21, + 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x22, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, + 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x3a, 0x01, 0x2a, + 0x22, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x76, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x60, 0x0a, 0x0b, 0x47, + 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x2e, 0x6b, 0x6f, 0x75, + 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, + 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x7c, 0x0a, + 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x12, 0x50, 0x0a, 0x07, 0x47, + 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x19, 0x2e, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x0a, 0x12, 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x32, 0x5a, + 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6f, 0x69, 0x64, + 0x73, 0x74, 0x61, 0x72, 0x69, 0x74, 0x2f, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x67, 0x65, 0x6e, + 0x2f, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x2f, 0x76, 0x31, 0x3b, 0x6b, 0x6f, 0x75, 0x6a, 0x61, 0x76, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1699,83 +1949,91 @@ func file_kouja_v1_volume_proto_rawDescGZIP() []byte { return file_kouja_v1_volume_proto_rawDescData } -var file_kouja_v1_volume_proto_msgTypes = make([]protoimpl.MessageInfo, 22) +var file_kouja_v1_volume_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_kouja_v1_volume_proto_goTypes = []any{ - (*CreateVolumeRequest)(nil), // 0: kouja.v1.CreateVolumeRequest - (*CreateVolumeResponse)(nil), // 1: kouja.v1.CreateVolumeResponse - (*ExportVolumeRequest)(nil), // 2: kouja.v1.ExportVolumeRequest - (*ExportVolumeResponse)(nil), // 3: kouja.v1.ExportVolumeResponse - (*UnexportVolumeRequest)(nil), // 4: kouja.v1.UnexportVolumeRequest - (*UnexportVolumeResponse)(nil), // 5: kouja.v1.UnexportVolumeResponse - (*ResizeVolumeRequest)(nil), // 6: kouja.v1.ResizeVolumeRequest - (*ResizeVolumeResponse)(nil), // 7: kouja.v1.ResizeVolumeResponse - (*DeleteVolumeRequest)(nil), // 8: kouja.v1.DeleteVolumeRequest - (*DeleteVolumeResponse)(nil), // 9: kouja.v1.DeleteVolumeResponse - (*GetVolumeRequest)(nil), // 10: kouja.v1.GetVolumeRequest - (*GetVolumeResponse)(nil), // 11: kouja.v1.GetVolumeResponse - (*ListVolumesRequest)(nil), // 12: kouja.v1.ListVolumesRequest - (*ListVolumesResponse)(nil), // 13: kouja.v1.ListVolumesResponse - (*GetCredentialRequest)(nil), // 14: kouja.v1.GetCredentialRequest - (*GetCredentialResponse)(nil), // 15: kouja.v1.GetCredentialResponse - (*RotateCredentialRequest)(nil), // 16: kouja.v1.RotateCredentialRequest - (*RotateCredentialResponse)(nil), // 17: kouja.v1.RotateCredentialResponse - (*GetCapacityRequest)(nil), // 18: kouja.v1.GetCapacityRequest - (*GetCapacityResponse)(nil), // 19: kouja.v1.GetCapacityResponse - (*GetInfoRequest)(nil), // 20: kouja.v1.GetInfoRequest - (*GetInfoResponse)(nil), // 21: kouja.v1.GetInfoResponse - (Protocol)(0), // 22: kouja.v1.Protocol - (*Volume)(nil), // 23: kouja.v1.Volume - (*Export)(nil), // 24: kouja.v1.Export - (*Observation)(nil), // 25: kouja.v1.Observation - (DriftReason)(0), // 26: kouja.v1.DriftReason - (*Capacity)(nil), // 27: kouja.v1.Capacity + (*CreateVolumeRequest)(nil), // 0: kouja.v1.CreateVolumeRequest + (*CreateVolumeResponse)(nil), // 1: kouja.v1.CreateVolumeResponse + (*ExportVolumeRequest)(nil), // 2: kouja.v1.ExportVolumeRequest + (*ExportVolumeResponse)(nil), // 3: kouja.v1.ExportVolumeResponse + (*UnexportVolumeRequest)(nil), // 4: kouja.v1.UnexportVolumeRequest + (*UnexportVolumeResponse)(nil), // 5: kouja.v1.UnexportVolumeResponse + (*ResizeVolumeRequest)(nil), // 6: kouja.v1.ResizeVolumeRequest + (*ResizeVolumeResponse)(nil), // 7: kouja.v1.ResizeVolumeResponse + (*DeleteVolumeRequest)(nil), // 8: kouja.v1.DeleteVolumeRequest + (*DeleteVolumeResponse)(nil), // 9: kouja.v1.DeleteVolumeResponse + (*GetVolumeRequest)(nil), // 10: kouja.v1.GetVolumeRequest + (*GetVolumeResponse)(nil), // 11: kouja.v1.GetVolumeResponse + (*ListVolumesRequest)(nil), // 12: kouja.v1.ListVolumesRequest + (*ListVolumesResponse)(nil), // 13: kouja.v1.ListVolumesResponse + (*GetCredentialRequest)(nil), // 14: kouja.v1.GetCredentialRequest + (*GetCredentialResponse)(nil), // 15: kouja.v1.GetCredentialResponse + (*RotateCredentialRequest)(nil), // 16: kouja.v1.RotateCredentialRequest + (*RotateCredentialResponse)(nil), // 17: kouja.v1.RotateCredentialResponse + (*GetCapacityRequest)(nil), // 18: kouja.v1.GetCapacityRequest + (*GetCapacityResponse)(nil), // 19: kouja.v1.GetCapacityResponse + (*ListStorageClassesRequest)(nil), // 20: kouja.v1.ListStorageClassesRequest + (*StorageClass)(nil), // 21: kouja.v1.StorageClass + (*ListStorageClassesResponse)(nil), // 22: kouja.v1.ListStorageClassesResponse + (*GetInfoRequest)(nil), // 23: kouja.v1.GetInfoRequest + (*GetInfoResponse)(nil), // 24: kouja.v1.GetInfoResponse + (Protocol)(0), // 25: kouja.v1.Protocol + (*Volume)(nil), // 26: kouja.v1.Volume + (*Export)(nil), // 27: kouja.v1.Export + (*Observation)(nil), // 28: kouja.v1.Observation + (DriftReason)(0), // 29: kouja.v1.DriftReason + (*Capacity)(nil), // 30: kouja.v1.Capacity + (*timestamppb.Timestamp)(nil), // 31: google.protobuf.Timestamp } var file_kouja_v1_volume_proto_depIdxs = []int32{ - 22, // 0: kouja.v1.CreateVolumeRequest.protocol:type_name -> kouja.v1.Protocol - 23, // 1: kouja.v1.CreateVolumeResponse.volume:type_name -> kouja.v1.Volume - 24, // 2: kouja.v1.CreateVolumeResponse.export:type_name -> kouja.v1.Export - 22, // 3: kouja.v1.ExportVolumeRequest.protocol:type_name -> kouja.v1.Protocol - 23, // 4: kouja.v1.ExportVolumeResponse.volume:type_name -> kouja.v1.Volume - 24, // 5: kouja.v1.ExportVolumeResponse.export:type_name -> kouja.v1.Export - 23, // 6: kouja.v1.UnexportVolumeResponse.volume:type_name -> kouja.v1.Volume - 24, // 7: kouja.v1.UnexportVolumeResponse.export:type_name -> kouja.v1.Export - 23, // 8: kouja.v1.ResizeVolumeResponse.volume:type_name -> kouja.v1.Volume - 24, // 9: kouja.v1.ResizeVolumeResponse.export:type_name -> kouja.v1.Export - 23, // 10: kouja.v1.GetVolumeResponse.desired:type_name -> kouja.v1.Volume - 25, // 11: kouja.v1.GetVolumeResponse.observed:type_name -> kouja.v1.Observation - 24, // 12: kouja.v1.GetVolumeResponse.export:type_name -> kouja.v1.Export - 26, // 13: kouja.v1.GetVolumeResponse.drift_reasons:type_name -> kouja.v1.DriftReason - 23, // 14: kouja.v1.ListVolumesResponse.volumes:type_name -> kouja.v1.Volume - 22, // 15: kouja.v1.GetCredentialResponse.protocol:type_name -> kouja.v1.Protocol - 27, // 16: kouja.v1.GetCapacityResponse.vgs:type_name -> kouja.v1.Capacity - 22, // 17: kouja.v1.GetInfoResponse.protocols:type_name -> kouja.v1.Protocol - 0, // 18: kouja.v1.VolumeService.CreateVolume:input_type -> kouja.v1.CreateVolumeRequest - 2, // 19: kouja.v1.VolumeService.ExportVolume:input_type -> kouja.v1.ExportVolumeRequest - 4, // 20: kouja.v1.VolumeService.UnexportVolume:input_type -> kouja.v1.UnexportVolumeRequest - 6, // 21: kouja.v1.VolumeService.ResizeVolume:input_type -> kouja.v1.ResizeVolumeRequest - 8, // 22: kouja.v1.VolumeService.DeleteVolume:input_type -> kouja.v1.DeleteVolumeRequest - 10, // 23: kouja.v1.VolumeService.GetVolume:input_type -> kouja.v1.GetVolumeRequest - 12, // 24: kouja.v1.VolumeService.ListVolumes:input_type -> kouja.v1.ListVolumesRequest - 14, // 25: kouja.v1.VolumeService.GetCredential:input_type -> kouja.v1.GetCredentialRequest - 16, // 26: kouja.v1.VolumeService.RotateCredential:input_type -> kouja.v1.RotateCredentialRequest - 18, // 27: kouja.v1.VolumeService.GetCapacity:input_type -> kouja.v1.GetCapacityRequest - 20, // 28: kouja.v1.VolumeService.GetInfo:input_type -> kouja.v1.GetInfoRequest - 1, // 29: kouja.v1.VolumeService.CreateVolume:output_type -> kouja.v1.CreateVolumeResponse - 3, // 30: kouja.v1.VolumeService.ExportVolume:output_type -> kouja.v1.ExportVolumeResponse - 5, // 31: kouja.v1.VolumeService.UnexportVolume:output_type -> kouja.v1.UnexportVolumeResponse - 7, // 32: kouja.v1.VolumeService.ResizeVolume:output_type -> kouja.v1.ResizeVolumeResponse - 9, // 33: kouja.v1.VolumeService.DeleteVolume:output_type -> kouja.v1.DeleteVolumeResponse - 11, // 34: kouja.v1.VolumeService.GetVolume:output_type -> kouja.v1.GetVolumeResponse - 13, // 35: kouja.v1.VolumeService.ListVolumes:output_type -> kouja.v1.ListVolumesResponse - 15, // 36: kouja.v1.VolumeService.GetCredential:output_type -> kouja.v1.GetCredentialResponse - 17, // 37: kouja.v1.VolumeService.RotateCredential:output_type -> kouja.v1.RotateCredentialResponse - 19, // 38: kouja.v1.VolumeService.GetCapacity:output_type -> kouja.v1.GetCapacityResponse - 21, // 39: kouja.v1.VolumeService.GetInfo:output_type -> kouja.v1.GetInfoResponse - 29, // [29:40] is the sub-list for method output_type - 18, // [18:29] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 25, // 0: kouja.v1.CreateVolumeRequest.protocol:type_name -> kouja.v1.Protocol + 26, // 1: kouja.v1.CreateVolumeResponse.volume:type_name -> kouja.v1.Volume + 27, // 2: kouja.v1.CreateVolumeResponse.export:type_name -> kouja.v1.Export + 25, // 3: kouja.v1.ExportVolumeRequest.protocol:type_name -> kouja.v1.Protocol + 26, // 4: kouja.v1.ExportVolumeResponse.volume:type_name -> kouja.v1.Volume + 27, // 5: kouja.v1.ExportVolumeResponse.export:type_name -> kouja.v1.Export + 26, // 6: kouja.v1.UnexportVolumeResponse.volume:type_name -> kouja.v1.Volume + 27, // 7: kouja.v1.UnexportVolumeResponse.export:type_name -> kouja.v1.Export + 26, // 8: kouja.v1.ResizeVolumeResponse.volume:type_name -> kouja.v1.Volume + 27, // 9: kouja.v1.ResizeVolumeResponse.export:type_name -> kouja.v1.Export + 26, // 10: kouja.v1.GetVolumeResponse.desired:type_name -> kouja.v1.Volume + 28, // 11: kouja.v1.GetVolumeResponse.observed:type_name -> kouja.v1.Observation + 27, // 12: kouja.v1.GetVolumeResponse.export:type_name -> kouja.v1.Export + 29, // 13: kouja.v1.GetVolumeResponse.drift_reasons:type_name -> kouja.v1.DriftReason + 26, // 14: kouja.v1.ListVolumesResponse.volumes:type_name -> kouja.v1.Volume + 25, // 15: kouja.v1.GetCredentialResponse.protocol:type_name -> kouja.v1.Protocol + 30, // 16: kouja.v1.GetCapacityResponse.vgs:type_name -> kouja.v1.Capacity + 31, // 17: kouja.v1.StorageClass.observed_at:type_name -> google.protobuf.Timestamp + 21, // 18: kouja.v1.ListStorageClassesResponse.classes:type_name -> kouja.v1.StorageClass + 25, // 19: kouja.v1.GetInfoResponse.protocols:type_name -> kouja.v1.Protocol + 0, // 20: kouja.v1.VolumeService.CreateVolume:input_type -> kouja.v1.CreateVolumeRequest + 2, // 21: kouja.v1.VolumeService.ExportVolume:input_type -> kouja.v1.ExportVolumeRequest + 4, // 22: kouja.v1.VolumeService.UnexportVolume:input_type -> kouja.v1.UnexportVolumeRequest + 6, // 23: kouja.v1.VolumeService.ResizeVolume:input_type -> kouja.v1.ResizeVolumeRequest + 8, // 24: kouja.v1.VolumeService.DeleteVolume:input_type -> kouja.v1.DeleteVolumeRequest + 10, // 25: kouja.v1.VolumeService.GetVolume:input_type -> kouja.v1.GetVolumeRequest + 12, // 26: kouja.v1.VolumeService.ListVolumes:input_type -> kouja.v1.ListVolumesRequest + 14, // 27: kouja.v1.VolumeService.GetCredential:input_type -> kouja.v1.GetCredentialRequest + 16, // 28: kouja.v1.VolumeService.RotateCredential:input_type -> kouja.v1.RotateCredentialRequest + 18, // 29: kouja.v1.VolumeService.GetCapacity:input_type -> kouja.v1.GetCapacityRequest + 20, // 30: kouja.v1.VolumeService.ListStorageClasses:input_type -> kouja.v1.ListStorageClassesRequest + 23, // 31: kouja.v1.VolumeService.GetInfo:input_type -> kouja.v1.GetInfoRequest + 1, // 32: kouja.v1.VolumeService.CreateVolume:output_type -> kouja.v1.CreateVolumeResponse + 3, // 33: kouja.v1.VolumeService.ExportVolume:output_type -> kouja.v1.ExportVolumeResponse + 5, // 34: kouja.v1.VolumeService.UnexportVolume:output_type -> kouja.v1.UnexportVolumeResponse + 7, // 35: kouja.v1.VolumeService.ResizeVolume:output_type -> kouja.v1.ResizeVolumeResponse + 9, // 36: kouja.v1.VolumeService.DeleteVolume:output_type -> kouja.v1.DeleteVolumeResponse + 11, // 37: kouja.v1.VolumeService.GetVolume:output_type -> kouja.v1.GetVolumeResponse + 13, // 38: kouja.v1.VolumeService.ListVolumes:output_type -> kouja.v1.ListVolumesResponse + 15, // 39: kouja.v1.VolumeService.GetCredential:output_type -> kouja.v1.GetCredentialResponse + 17, // 40: kouja.v1.VolumeService.RotateCredential:output_type -> kouja.v1.RotateCredentialResponse + 19, // 41: kouja.v1.VolumeService.GetCapacity:output_type -> kouja.v1.GetCapacityResponse + 22, // 42: kouja.v1.VolumeService.ListStorageClasses:output_type -> kouja.v1.ListStorageClassesResponse + 24, // 43: kouja.v1.VolumeService.GetInfo:output_type -> kouja.v1.GetInfoResponse + 32, // [32:44] is the sub-list for method output_type + 20, // [20:32] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_kouja_v1_volume_proto_init() } @@ -1791,7 +2049,7 @@ func file_kouja_v1_volume_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_kouja_v1_volume_proto_rawDesc, NumEnums: 0, - NumMessages: 22, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/kouja/v1/volume.pb.gw.go b/gen/kouja/v1/volume.pb.gw.go index b36accf..bbf9fff 100644 --- a/gen/kouja/v1/volume.pb.gw.go +++ b/gen/kouja/v1/volume.pb.gw.go @@ -413,6 +413,24 @@ func local_request_VolumeService_GetCapacity_0(ctx context.Context, marshaler ru return msg, metadata, err } +func request_VolumeService_ListStorageClasses_0(ctx context.Context, marshaler runtime.Marshaler, client VolumeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListStorageClassesRequest + metadata runtime.ServerMetadata + ) + msg, err := client.ListStorageClasses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_VolumeService_ListStorageClasses_0(ctx context.Context, marshaler runtime.Marshaler, server VolumeServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListStorageClassesRequest + metadata runtime.ServerMetadata + ) + msg, err := server.ListStorageClasses(ctx, &protoReq) + return msg, metadata, err +} + func request_VolumeService_GetInfo_0(ctx context.Context, marshaler runtime.Marshaler, client VolumeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq GetInfoRequest @@ -637,6 +655,26 @@ func RegisterVolumeServiceHandlerServer(ctx context.Context, mux *runtime.ServeM } forward_VolumeService_GetCapacity_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_VolumeService_ListStorageClasses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/kouja.v1.VolumeService/ListStorageClasses", runtime.WithHTTPPathPattern("/v1/storage-classes")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_VolumeService_ListStorageClasses_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_VolumeService_ListStorageClasses_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodGet, pattern_VolumeService_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -867,6 +905,23 @@ func RegisterVolumeServiceHandlerClient(ctx context.Context, mux *runtime.ServeM } forward_VolumeService_GetCapacity_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_VolumeService_ListStorageClasses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/kouja.v1.VolumeService/ListStorageClasses", runtime.WithHTTPPathPattern("/v1/storage-classes")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_VolumeService_ListStorageClasses_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_VolumeService_ListStorageClasses_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodGet, pattern_VolumeService_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -888,29 +943,31 @@ func RegisterVolumeServiceHandlerClient(ctx context.Context, mux *runtime.ServeM } var ( - pattern_VolumeService_CreateVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "volumes"}, "")) - pattern_VolumeService_ExportVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "export")) - pattern_VolumeService_UnexportVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "unexport")) - pattern_VolumeService_ResizeVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "resize")) - pattern_VolumeService_DeleteVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "")) - pattern_VolumeService_GetVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "")) - pattern_VolumeService_ListVolumes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "volumes"}, "")) - pattern_VolumeService_GetCredential_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1", "volumes", "volume_id", "credential"}, "")) - pattern_VolumeService_RotateCredential_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "rotate-credential")) - pattern_VolumeService_GetCapacity_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "capacity"}, "")) - pattern_VolumeService_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "info"}, "")) + pattern_VolumeService_CreateVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "volumes"}, "")) + pattern_VolumeService_ExportVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "export")) + pattern_VolumeService_UnexportVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "unexport")) + pattern_VolumeService_ResizeVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "resize")) + pattern_VolumeService_DeleteVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "")) + pattern_VolumeService_GetVolume_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "")) + pattern_VolumeService_ListVolumes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "volumes"}, "")) + pattern_VolumeService_GetCredential_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1", "volumes", "volume_id", "credential"}, "")) + pattern_VolumeService_RotateCredential_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "volumes", "volume_id"}, "rotate-credential")) + pattern_VolumeService_GetCapacity_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "capacity"}, "")) + pattern_VolumeService_ListStorageClasses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "storage-classes"}, "")) + pattern_VolumeService_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "info"}, "")) ) var ( - forward_VolumeService_CreateVolume_0 = runtime.ForwardResponseMessage - forward_VolumeService_ExportVolume_0 = runtime.ForwardResponseMessage - forward_VolumeService_UnexportVolume_0 = runtime.ForwardResponseMessage - forward_VolumeService_ResizeVolume_0 = runtime.ForwardResponseMessage - forward_VolumeService_DeleteVolume_0 = runtime.ForwardResponseMessage - forward_VolumeService_GetVolume_0 = runtime.ForwardResponseMessage - forward_VolumeService_ListVolumes_0 = runtime.ForwardResponseMessage - forward_VolumeService_GetCredential_0 = runtime.ForwardResponseMessage - forward_VolumeService_RotateCredential_0 = runtime.ForwardResponseMessage - forward_VolumeService_GetCapacity_0 = runtime.ForwardResponseMessage - forward_VolumeService_GetInfo_0 = runtime.ForwardResponseMessage + forward_VolumeService_CreateVolume_0 = runtime.ForwardResponseMessage + forward_VolumeService_ExportVolume_0 = runtime.ForwardResponseMessage + forward_VolumeService_UnexportVolume_0 = runtime.ForwardResponseMessage + forward_VolumeService_ResizeVolume_0 = runtime.ForwardResponseMessage + forward_VolumeService_DeleteVolume_0 = runtime.ForwardResponseMessage + forward_VolumeService_GetVolume_0 = runtime.ForwardResponseMessage + forward_VolumeService_ListVolumes_0 = runtime.ForwardResponseMessage + forward_VolumeService_GetCredential_0 = runtime.ForwardResponseMessage + forward_VolumeService_RotateCredential_0 = runtime.ForwardResponseMessage + forward_VolumeService_GetCapacity_0 = runtime.ForwardResponseMessage + forward_VolumeService_ListStorageClasses_0 = runtime.ForwardResponseMessage + forward_VolumeService_GetInfo_0 = runtime.ForwardResponseMessage ) diff --git a/gen/kouja/v1/volume_grpc.pb.go b/gen/kouja/v1/volume_grpc.pb.go index 5203a8f..ed08911 100644 --- a/gen/kouja/v1/volume_grpc.pb.go +++ b/gen/kouja/v1/volume_grpc.pb.go @@ -19,17 +19,18 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - VolumeService_CreateVolume_FullMethodName = "/kouja.v1.VolumeService/CreateVolume" - VolumeService_ExportVolume_FullMethodName = "/kouja.v1.VolumeService/ExportVolume" - VolumeService_UnexportVolume_FullMethodName = "/kouja.v1.VolumeService/UnexportVolume" - VolumeService_ResizeVolume_FullMethodName = "/kouja.v1.VolumeService/ResizeVolume" - VolumeService_DeleteVolume_FullMethodName = "/kouja.v1.VolumeService/DeleteVolume" - VolumeService_GetVolume_FullMethodName = "/kouja.v1.VolumeService/GetVolume" - VolumeService_ListVolumes_FullMethodName = "/kouja.v1.VolumeService/ListVolumes" - VolumeService_GetCredential_FullMethodName = "/kouja.v1.VolumeService/GetCredential" - VolumeService_RotateCredential_FullMethodName = "/kouja.v1.VolumeService/RotateCredential" - VolumeService_GetCapacity_FullMethodName = "/kouja.v1.VolumeService/GetCapacity" - VolumeService_GetInfo_FullMethodName = "/kouja.v1.VolumeService/GetInfo" + VolumeService_CreateVolume_FullMethodName = "/kouja.v1.VolumeService/CreateVolume" + VolumeService_ExportVolume_FullMethodName = "/kouja.v1.VolumeService/ExportVolume" + VolumeService_UnexportVolume_FullMethodName = "/kouja.v1.VolumeService/UnexportVolume" + VolumeService_ResizeVolume_FullMethodName = "/kouja.v1.VolumeService/ResizeVolume" + VolumeService_DeleteVolume_FullMethodName = "/kouja.v1.VolumeService/DeleteVolume" + VolumeService_GetVolume_FullMethodName = "/kouja.v1.VolumeService/GetVolume" + VolumeService_ListVolumes_FullMethodName = "/kouja.v1.VolumeService/ListVolumes" + VolumeService_GetCredential_FullMethodName = "/kouja.v1.VolumeService/GetCredential" + VolumeService_RotateCredential_FullMethodName = "/kouja.v1.VolumeService/RotateCredential" + VolumeService_GetCapacity_FullMethodName = "/kouja.v1.VolumeService/GetCapacity" + VolumeService_ListStorageClasses_FullMethodName = "/kouja.v1.VolumeService/ListStorageClasses" + VolumeService_GetInfo_FullMethodName = "/kouja.v1.VolumeService/GetInfo" ) // VolumeServiceClient is the client API for VolumeService service. @@ -46,6 +47,7 @@ type VolumeServiceClient interface { GetCredential(ctx context.Context, in *GetCredentialRequest, opts ...grpc.CallOption) (*GetCredentialResponse, error) RotateCredential(ctx context.Context, in *RotateCredentialRequest, opts ...grpc.CallOption) (*RotateCredentialResponse, error) GetCapacity(ctx context.Context, in *GetCapacityRequest, opts ...grpc.CallOption) (*GetCapacityResponse, error) + ListStorageClasses(ctx context.Context, in *ListStorageClassesRequest, opts ...grpc.CallOption) (*ListStorageClassesResponse, error) GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error) } @@ -157,6 +159,16 @@ func (c *volumeServiceClient) GetCapacity(ctx context.Context, in *GetCapacityRe return out, nil } +func (c *volumeServiceClient) ListStorageClasses(ctx context.Context, in *ListStorageClassesRequest, opts ...grpc.CallOption) (*ListStorageClassesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListStorageClassesResponse) + err := c.cc.Invoke(ctx, VolumeService_ListStorageClasses_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *volumeServiceClient) GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetInfoResponse) @@ -181,6 +193,7 @@ type VolumeServiceServer interface { GetCredential(context.Context, *GetCredentialRequest) (*GetCredentialResponse, error) RotateCredential(context.Context, *RotateCredentialRequest) (*RotateCredentialResponse, error) GetCapacity(context.Context, *GetCapacityRequest) (*GetCapacityResponse, error) + ListStorageClasses(context.Context, *ListStorageClassesRequest) (*ListStorageClassesResponse, error) GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error) mustEmbedUnimplementedVolumeServiceServer() } @@ -222,6 +235,9 @@ func (UnimplementedVolumeServiceServer) RotateCredential(context.Context, *Rotat func (UnimplementedVolumeServiceServer) GetCapacity(context.Context, *GetCapacityRequest) (*GetCapacityResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetCapacity not implemented") } +func (UnimplementedVolumeServiceServer) ListStorageClasses(context.Context, *ListStorageClassesRequest) (*ListStorageClassesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListStorageClasses not implemented") +} func (UnimplementedVolumeServiceServer) GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetInfo not implemented") } @@ -426,6 +442,24 @@ func _VolumeService_GetCapacity_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _VolumeService_ListStorageClasses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListStorageClassesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VolumeServiceServer).ListStorageClasses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: VolumeService_ListStorageClasses_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VolumeServiceServer).ListStorageClasses(ctx, req.(*ListStorageClassesRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _VolumeService_GetInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetInfoRequest) if err := dec(in); err != nil { @@ -491,6 +525,10 @@ var VolumeService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetCapacity", Handler: _VolumeService_GetCapacity_Handler, }, + { + MethodName: "ListStorageClasses", + Handler: _VolumeService_ListStorageClasses_Handler, + }, { MethodName: "GetInfo", Handler: _VolumeService_GetInfo_Handler, diff --git a/internal/agent/admin_service.go b/internal/agent/admin_service.go index fbc4f3f..6b053e6 100644 --- a/internal/agent/admin_service.go +++ b/internal/agent/admin_service.go @@ -32,6 +32,7 @@ type AdminService struct { exporters map[string]target.Exporter creds credential.Manager retrier DriftRetrier + classes map[string]string } type AdminOption func(*AdminService) @@ -54,6 +55,12 @@ func WithDriftRetrier(retrier DriftRetrier) AdminOption { } } +func WithStorageClasses(classes map[string]string) AdminOption { + return func(service *AdminService) { + service.classes = classes + } +} + func NewAdminService(store *state.Store, lvmBackend lvm.Backend, options ...AdminOption) *AdminService { service := &AdminService{store: store, lvm: lvmBackend, exporters: make(map[string]target.Exporter)} for _, option := range options { @@ -89,7 +96,7 @@ func (service *AdminService) RegisterVG(ctx context.Context, request *koujav1.Re return nil, statusError(err) } return &koujav1.RegisterVGResponse{ - Capacity: toProtoCapacity(capacity), RequestId: requestID(ctx, request.GetRequestId()), + Capacity: service.capacityProto(capacity), RequestId: requestID(ctx, request.GetRequestId()), }, nil } @@ -129,10 +136,11 @@ func (service *AdminService) ListVGs(ctx context.Context, _ *koujav1.ListVGsRequ if err != nil { response.Vgs = append(response.Vgs, &koujav1.Capacity{ VgName: vg.Name, VgUuid: vg.UUID, VgState: "unavailable", + StorageClass: storageClassForVG(service.classes, vg.Name), }) continue } - response.Vgs = append(response.Vgs, toProtoCapacity(capacity)) + response.Vgs = append(response.Vgs, service.capacityProto(capacity)) } return response, nil } @@ -305,7 +313,7 @@ func (service *AdminService) ResolveDrift(ctx context.Context, request *koujav1. return nil, err } return &koujav1.ResolveDriftResponse{ - Volume: toProtoVolume(volume), OperationId: operationID, + Volume: service.volumeProto(volume), OperationId: operationID, RequestId: requestID(ctx, request.GetRequestId()), }, nil case koujav1.ResolveAction_RESOLVE_ACTION_RETRY: @@ -317,14 +325,14 @@ func (service *AdminService) ResolveDrift(ctx context.Context, request *koujav1. return nil, statusError(err) } return &koujav1.ResolveDriftResponse{ - Volume: toProtoVolume(result.Volume), OperationId: result.OperationID, + Volume: service.volumeProto(result.Volume), OperationId: result.OperationID, RequestId: requestID(ctx, request.GetRequestId()), }, nil default: return nil, status.Error(codes.InvalidArgument, "unsupported resolve action") } return &koujav1.ResolveDriftResponse{ - Volume: toProtoVolume(volume), OperationId: operationID, + Volume: service.volumeProto(volume), OperationId: operationID, RequestId: requestID(ctx, request.GetRequestId()), }, nil } @@ -475,6 +483,18 @@ func (service *AdminService) updateDrift(ctx context.Context, volume state.Volum }) } +func (service *AdminService) volumeProto(volume state.Volume) *koujav1.Volume { + proto := toProtoVolume(volume) + proto.StorageClass = storageClassForVG(service.classes, volume.VGName) + return proto +} + +func (service *AdminService) capacityProto(capacity lvm.Capacity) *koujav1.Capacity { + proto := toProtoCapacity(capacity) + proto.StorageClass = storageClassForVG(service.classes, capacity.VGName) + return proto +} + func (service *AdminService) markDeleted(ctx context.Context, volume state.Volume, export *state.Export, operationID, requestID string, now time.Time) error { return service.store.Transact(ctx, func(tx state.Tx) error { if err := tx.PutTombstone(state.Tombstone{ diff --git a/internal/agent/storage_class.go b/internal/agent/storage_class.go new file mode 100644 index 0000000..1d13bd3 --- /dev/null +++ b/internal/agent/storage_class.go @@ -0,0 +1,50 @@ +package agent + +import ( + "fmt" + "strings" +) + +// storageClassForVG returns the configured class for an LVM volume group. A +// VG without an explicit class is its own class for compatibility with +// deployments that select storage by VG name. +func storageClassForVG(classes map[string]string, vg string) string { + for class, mapped := range classes { + if mapped == vg { + return class + } + } + return vg +} + +// resolveStorageClass maps a requested storage class to its LVM volume group. +// Callers may use either a configured class, a raw VG name, or both as long as +// they agree. +func resolveStorageClass(classes map[string]string, class, vg string) (string, string, error) { + class = strings.TrimSpace(class) + vg = strings.TrimSpace(vg) + if class == "" && vg == "" { + return "", "", fmt.Errorf("storage_class or vg is required") + } + if class == "" { + if !vgNamePattern.MatchString(vg) { + return "", "", fmt.Errorf("invalid vg %q", vg) + } + return storageClassForVG(classes, vg), vg, nil + } + if !vgNamePattern.MatchString(class) { + return "", "", fmt.Errorf("invalid storage_class %q", class) + } + if mapped, ok := classes[class]; ok { + if vg != "" && vg != mapped { + return "", "", fmt.Errorf("storage_class %q maps to vg %q, not %q", class, mapped, vg) + } + return class, mapped, nil + } + if vg != "" && vg != class { + return "", "", fmt.Errorf("unknown storage_class %q and vg %q do not match", class, vg) + } + // A class without a mapping is treated as a raw VG name. This preserves + // the original API and CSI behavior for deployments without class config. + return class, class, nil +} diff --git a/internal/agent/storage_class_test.go b/internal/agent/storage_class_test.go new file mode 100644 index 0000000..6b1b652 --- /dev/null +++ b/internal/agent/storage_class_test.go @@ -0,0 +1,97 @@ +package agent + +import ( + "context" + "encoding/json" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/voidstarit/kouja/gen/kouja/v1" + "github.com/voidstarit/kouja/internal/lvm" + "github.com/voidstarit/kouja/internal/operations" + "github.com/voidstarit/kouja/internal/state" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var _ = Describe("storage class selection", func() { + classes := map[string]string{"nvme": "vg-nvme", "ssd": "vg-ssd", "hdd": "vg-hdd"} + + It("resolves a class to its configured VG", func() { + class, vg, err := resolveStorageClass(classes, "ssd", "") + Expect(err).NotTo(HaveOccurred()) + Expect(class).To(Equal("ssd")) + Expect(vg).To(Equal("vg-ssd")) + }) + + It("accepts a raw VG when no class mapping exists", func() { + class, vg, err := resolveStorageClass(nil, "vg-raw", "") + Expect(err).NotTo(HaveOccurred()) + Expect(class).To(Equal("vg-raw")) + Expect(vg).To(Equal("vg-raw")) + }) + + It("rejects a class and VG that disagree", func() { + _, _, err := resolveStorageClass(classes, "nvme", "vg-hdd") + Expect(err).To(MatchError(ContainSubstring("maps to vg"))) + }) + + It("reports the class for capacity belonging to a mapped VG", func() { + store := newAgentStore(GinkgoTB()) + now := time.Now().UTC() + Expect(store.Transact(context.Background(), func(tx state.Tx) error { + return tx.PutVG(state.VG{Name: "vg-nvme", UUID: "vg-uuid", State: "active", RegisteredAt: now, UpdatedAt: now}) + })).To(Succeed()) + service := NewVolumeService(store, &fakeLVM{capacity: lvm.Capacity{ + VGName: "vg-nvme", VGUUID: "vg-uuid", VGState: "active", + TotalBytes: 10 << 30, FreeBytes: 8 << 30, AllocatableBytes: 7 << 30, + }}, &fakeRunner{}, &fakeCredentialManager{}, ServiceOptions{StorageClasses: classes}) + + response, err := service.GetCapacity(context.Background(), &koujav1.GetCapacityRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(response.GetVgs()).To(HaveLen(1)) + Expect(response.GetVgs()[0].GetStorageClass()).To(Equal("nvme")) + Expect(response.GetVgs()[0].GetVgName()).To(Equal("vg-nvme")) + + classes, err := service.ListStorageClasses(context.Background(), &koujav1.ListStorageClassesRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(classes.GetClasses()).To(HaveLen(1)) + Expect(classes.GetClasses()[0].GetName()).To(Equal("nvme")) + Expect(classes.GetClasses()[0].GetVgName()).To(Equal("vg-nvme")) + Expect(classes.GetClasses()[0].GetAllocatableBytes()).To(Equal(int64(7 << 30))) + }) + + It("stores the selected VG and returns the selected class on create", func() { + store := newAgentStore(GinkgoTB()) + now := time.Now().UTC() + runner := &fakeRunner{result: operations.Result{Volume: state.Volume{ + Owner: "spiffe://kouja/caller/one", VolumeID: "vol1", ResourceUUID: "resource-1", + VGName: "vg-nvme", RequestedSizeBytes: 1 << 20, ActualSizeBytes: 1 << 20, + State: "available", CreatedAt: now, UpdatedAt: now, + }}} + service := NewVolumeService(store, &fakeLVM{}, runner, &fakeCredentialManager{}, ServiceOptions{ + StorageClasses: classes, + }) + export := false + response, err := service.CreateVolume(callerContext("spiffe://kouja/caller/one"), &koujav1.CreateVolumeRequest{ + VolumeId: "vol1", SizeBytes: 1 << 20, StorageClass: "nvme", Export: &export, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(response.GetVolume().GetStorageClass()).To(Equal("nvme")) + var intent operations.CreateIntent + Expect(json.Unmarshal(runner.request.Intent, &intent)).To(Succeed()) + Expect(intent.VG).To(Equal("vg-nvme")) + }) + + It("returns InvalidArgument for an invalid class mapping", func() { + service := NewVolumeService(newAgentStore(GinkgoTB()), &fakeLVM{}, &fakeRunner{}, &fakeCredentialManager{}, ServiceOptions{ + StorageClasses: classes, + }) + export := false + _, err := service.CreateVolume(callerContext("spiffe://kouja/caller/one"), &koujav1.CreateVolumeRequest{ + VolumeId: "vol1", SizeBytes: 1 << 20, StorageClass: "nvme", Vg: "vg-hdd", Export: &export, + }) + Expect(status.Code(err)).To(Equal(codes.InvalidArgument)) + }) +}) diff --git a/internal/agent/volume_service.go b/internal/agent/volume_service.go index 658bb50..b208fcd 100644 --- a/internal/agent/volume_service.go +++ b/internal/agent/volume_service.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net" + "sort" "strconv" "strings" @@ -38,6 +39,8 @@ type ServiceOptions struct { NVMePortals []config.Portal Ready func() bool Admission *Admission + // StorageClasses maps a stable class name to an LVM volume group. + StorageClasses map[string]string } type VolumeService struct { @@ -66,8 +69,12 @@ func (service *VolumeService) CreateVolume(ctx context.Context, request *koujav1 if request.GetWipe() { return nil, status.Error(codes.Unimplemented, "wipe is a stage 3 operation") } - if request.GetVolumeId() == "" || request.GetSizeBytes() <= 0 || request.GetVg() == "" { - return nil, status.Error(codes.InvalidArgument, "volume_id, positive size_bytes, and vg are required") + if request.GetVolumeId() == "" || request.GetSizeBytes() <= 0 { + return nil, status.Error(codes.InvalidArgument, "volume_id and positive size_bytes are required") + } + _, vg, resolveErr := resolveStorageClass(service.options.StorageClasses, request.GetStorageClass(), request.GetVg()) + if resolveErr != nil { + return nil, status.Error(codes.InvalidArgument, resolveErr.Error()) } export := request.Export == nil || request.GetExport() protocol := request.GetProtocol() @@ -117,7 +124,7 @@ func (service *VolumeService) CreateVolume(ctx context.Context, request *koujav1 intent := operations.CreateIntent{ ResourceUUID: resourceUUID, SizeBytes: request.GetSizeBytes(), - VG: request.GetVg(), + VG: vg, Export: export, Protocol: protocolName, Initiator: request.GetInitiator(), @@ -139,7 +146,7 @@ func (service *VolumeService) CreateVolume(ctx context.Context, request *koujav1 return nil, statusError(err) } response := &koujav1.CreateVolumeResponse{ - Volume: toProtoVolume(result.Volume), + Volume: service.volumeProto(result.Volume), OperationId: result.OperationID, RequestId: requestID(ctx, request.GetRequestId()), } @@ -206,7 +213,7 @@ func (service *VolumeService) ExportVolume(ctx context.Context, request *koujav1 return nil, statusError(err) } return &koujav1.ExportVolumeResponse{ - Volume: toProtoVolume(result.Volume), Export: toProtoExport(result.Export, state.ExportObservation{}), + Volume: service.volumeProto(result.Volume), Export: toProtoExport(result.Export, state.ExportObservation{}), OperationId: result.OperationID, RequestId: requestID(ctx, request.GetRequestId()), }, nil } @@ -233,7 +240,7 @@ func (service *VolumeService) UnexportVolume(ctx context.Context, request *kouja return nil, statusError(err) } return &koujav1.UnexportVolumeResponse{ - Volume: toProtoVolume(result.Volume), Export: toProtoExport(result.Export, state.ExportObservation{}), + Volume: service.volumeProto(result.Volume), Export: toProtoExport(result.Export, state.ExportObservation{}), OperationId: result.OperationID, RequestId: requestID(ctx, request.GetRequestId()), }, nil } @@ -262,7 +269,7 @@ func (service *VolumeService) ResizeVolume(ctx context.Context, request *koujav1 return nil, statusError(err) } response := &koujav1.ResizeVolumeResponse{ - Volume: toProtoVolume(result.Volume), RescanRequired: true, + Volume: service.volumeProto(result.Volume), RescanRequired: true, OperationId: result.OperationID, RequestId: requestID(ctx, request.GetRequestId()), } if result.Export.VolumeID != "" { @@ -305,7 +312,7 @@ func (service *VolumeService) GetVolume(ctx context.Context, request *koujav1.Ge return nil, statusError(err) } response := &koujav1.GetVolumeResponse{ - Desired: toProtoVolume(volume), + Desired: service.volumeProto(volume), OperationId: volume.LastOperationID, } export, exportErr := service.getExport(ctx, identity.Owner, request.GetVolumeId()) @@ -352,7 +359,7 @@ func (service *VolumeService) ListVolumes(ctx context.Context, request *koujav1. } response := &koujav1.ListVolumesResponse{Volumes: make([]*koujav1.Volume, 0, len(volumes))} for _, volume := range volumes { - response.Volumes = append(response.Volumes, toProtoVolume(volume)) + response.Volumes = append(response.Volumes, service.volumeProto(volume)) } if len(volumes) == limit { response.NextPageToken = volumes[len(volumes)-1].VolumeID @@ -439,14 +446,36 @@ func (service *VolumeService) GetCapacity(ctx context.Context, _ *koujav1.GetCap for _, vg := range vgs { capacity, err := service.lvm.Capacity(ctx, vg.Name) if err != nil { - response.Vgs = append(response.Vgs, &koujav1.Capacity{VgName: vg.Name, VgUuid: vg.UUID, VgState: "unavailable"}) + response.Vgs = append(response.Vgs, &koujav1.Capacity{ + VgName: vg.Name, VgUuid: vg.UUID, VgState: "unavailable", + StorageClass: storageClassForVG(service.options.StorageClasses, vg.Name), + }) continue } - response.Vgs = append(response.Vgs, toProtoCapacity(capacity)) + response.Vgs = append(response.Vgs, service.capacityProto(capacity)) } return response, nil } +func (service *VolumeService) ListStorageClasses(ctx context.Context, _ *koujav1.ListStorageClassesRequest) (*koujav1.ListStorageClassesResponse, error) { + capacity, err := service.GetCapacity(ctx, &koujav1.GetCapacityRequest{}) + if err != nil { + return nil, err + } + response := &koujav1.ListStorageClassesResponse{Classes: make([]*koujav1.StorageClass, 0, len(capacity.GetVgs()))} + for _, vg := range capacity.GetVgs() { + response.Classes = append(response.Classes, &koujav1.StorageClass{ + Name: vg.GetStorageClass(), VgName: vg.GetVgName(), VgUuid: vg.GetVgUuid(), VgState: vg.GetVgState(), + TotalBytes: vg.GetTotalBytes(), FreeBytes: vg.GetFreeBytes(), AllocatableBytes: vg.GetAllocatableBytes(), + ExtentSizeBytes: vg.GetExtentSizeBytes(), MaxVolumeBytes: vg.GetMaxVolumeBytes(), ObservedAt: vg.GetObservedAt(), + }) + } + sort.Slice(response.Classes, func(i, j int) bool { + return response.Classes[i].GetName() < response.Classes[j].GetName() + }) + return response, nil +} + func (service *VolumeService) GetInfo(context.Context, *koujav1.GetInfoRequest) (*koujav1.GetInfoResponse, error) { protocols := make([]koujav1.Protocol, 0, 2) if service.options.ISCSIEnabled { @@ -604,6 +633,18 @@ func protocolProto(protocol credential.Protocol) koujav1.Protocol { } } +func (service *VolumeService) volumeProto(volume state.Volume) *koujav1.Volume { + proto := toProtoVolume(volume) + proto.StorageClass = storageClassForVG(service.options.StorageClasses, volume.VGName) + return proto +} + +func (service *VolumeService) capacityProto(capacity lvm.Capacity) *koujav1.Capacity { + proto := toProtoCapacity(capacity) + proto.StorageClass = storageClassForVG(service.options.StorageClasses, capacity.VGName) + return proto +} + func toProtoVolume(volume state.Volume) *koujav1.Volume { return &koujav1.Volume{ Owner: volume.Owner, VolumeId: volume.VolumeID, ResourceUuid: volume.ResourceUUID, diff --git a/internal/config/config.go b/internal/config/config.go index c8bc6a2..6198bb2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "regexp" + "sort" "strings" "gopkg.in/yaml.v3" @@ -41,10 +42,39 @@ type TLSConfig struct { } type StorageConfig struct { - HeadroomPercent int64 `yaml:"headroom_percent"` - HeadroomMinBytes int64 `yaml:"headroom_min_bytes"` - WipeTimeoutSeconds int `yaml:"wipe_timeout_seconds"` - VGs []string `yaml:"vgs"` + HeadroomPercent int64 `yaml:"headroom_percent"` + HeadroomMinBytes int64 `yaml:"headroom_min_bytes"` + WipeTimeoutSeconds int `yaml:"wipe_timeout_seconds"` + VGs []string `yaml:"vgs"` + Classes map[string]string `yaml:"classes"` +} + +// EffectiveVGs returns the explicit VGs plus every VG referenced by a storage +// class, deduplicated and in a deterministic order. +func (cfg *Config) EffectiveVGs() []string { + seen := make(map[string]struct{}, len(cfg.Storage.VGs)+len(cfg.Storage.Classes)) + result := make([]string, 0, len(cfg.Storage.VGs)+len(cfg.Storage.Classes)) + for _, vg := range cfg.Storage.VGs { + if _, ok := seen[vg]; ok { + continue + } + seen[vg] = struct{}{} + result = append(result, vg) + } + classes := make([]string, 0, len(cfg.Storage.Classes)) + for class := range cfg.Storage.Classes { + classes = append(classes, class) + } + sort.Strings(classes) + for _, class := range classes { + vg := cfg.Storage.Classes[class] + if _, ok := seen[vg]; ok { + continue + } + seen[vg] = struct{}{} + result = append(result, vg) + } + return result } type TargetsConfig struct { @@ -237,6 +267,19 @@ func (cfg *Config) Validate() error { return fmt.Errorf("%w: invalid storage.vgs entry %q", ErrInvalid, vg) } } + classVGs := make(map[string]string, len(cfg.Storage.Classes)) + for class, vg := range cfg.Storage.Classes { + if !vgNamePattern.MatchString(class) { + return fmt.Errorf("%w: invalid storage.classes name %q", ErrInvalid, class) + } + if !vgNamePattern.MatchString(vg) { + return fmt.Errorf("%w: invalid storage.classes.%s VG %q", ErrInvalid, class, vg) + } + if other, ok := classVGs[vg]; ok { + return fmt.Errorf("%w: storage classes %q and %q reference the same VG %q", ErrInvalid, other, class, vg) + } + classVGs[vg] = class + } if cfg.Targets.ISCSI.Enabled { if err := validateTargetPortals("targets.iscsi", cfg.Targets.ISCSI.IQNPrefix, cfg.Targets.ISCSI.Portals); err != nil { return err diff --git a/internal/config/storage_class_test.go b/internal/config/storage_class_test.go new file mode 100644 index 0000000..2092e37 --- /dev/null +++ b/internal/config/storage_class_test.go @@ -0,0 +1,40 @@ +package config + +import ( + "strings" + + . "github.com/onsi/ginkgo/v2" + gomega "github.com/onsi/gomega" +) + +var _ = Describe("storage classes", func() { + It("maps class names to VGs and includes them in the startup seed", func() { + cfg, err := Parse([]byte(strings.Replace(validConfig, " vgs: [vg1]", ` vgs: [vg1] + classes: + nvme: vg-nvme + ssd: vg1 + hdd: vg-hdd`, 1))) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Expect(cfg.Storage.Classes).To(gomega.Equal(map[string]string{ + "nvme": "vg-nvme", + "ssd": "vg1", + "hdd": "vg-hdd", + })) + gomega.Expect(cfg.EffectiveVGs()).To(gomega.Equal([]string{"vg1", "vg-hdd", "vg-nvme"})) + }) + + It("rejects two classes for the same VG", func() { + _, err := Parse([]byte(strings.Replace(validConfig, " vgs: [vg1]", ` vgs: [] + classes: + nvme: vg1 + ssd: vg1`, 1))) + gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("reference the same VG"))) + }) + + It("rejects invalid class names", func() { + _, err := Parse([]byte(strings.Replace(validConfig, " vgs: [vg1]", ` vgs: [] + classes: + "bad class": vg1`, 1))) + gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("invalid storage.classes name"))) + }) +}) diff --git a/internal/csi/controller.go b/internal/csi/controller.go index 46d61a5..05d8d99 100644 --- a/internal/csi/controller.go +++ b/internal/csi/controller.go @@ -91,9 +91,13 @@ func (controller *Controller) CreateVolume(ctx context.Context, request *csipb.C if request.GetName() == "" || request.GetCapacityRange().GetRequiredBytes() <= 0 { return nil, status.Error(codes.InvalidArgument, "name and positive required_bytes are required") } - vg := request.GetParameters()["vg"] - if vg == "" { - return nil, status.Error(codes.InvalidArgument, "storage class parameter vg is required") + storageClass := strings.TrimSpace(request.GetParameters()["class"]) + if storageClass == "" { + storageClass = strings.TrimSpace(request.GetParameters()["storageClass"]) + } + vg := strings.TrimSpace(request.GetParameters()["vg"]) + if storageClass == "" && vg == "" { + return nil, status.Error(codes.InvalidArgument, "storage class parameter class or vg is required") } protocol := request.GetParameters()["protocol"] if protocol == "" { @@ -123,7 +127,7 @@ func (controller *Controller) CreateVolume(ctx context.Context, request *csipb.C } } if host == nil { - host, err = controller.selectHost(ctx, vg, protocol, size) + host, err = controller.selectHost(ctx, storageClass, vg, protocol, size) if err != nil { return nil, err } @@ -133,14 +137,14 @@ func (controller *Controller) CreateVolume(ctx context.Context, request *csipb.C volumeID = record.VolumeID } if controller.placement != nil && !recorded { - if err := controller.placement.Pending(ctx, placementKey, Host{UUID: host.uuid, Endpoint: host.endpoint}, volumeID); err != nil { + if err := controller.placement.Pending(ctx, placementKey, Host{UUID: host.uuid, Endpoint: host.endpoint}, volumeID, storageClass); err != nil { return nil, status.Errorf(codes.Internal, "record volume placement: %v", err) } recorded = true } export := false response, err := host.volume.CreateVolume(ctx, &koujav1.CreateVolumeRequest{ - VolumeId: volumeID, SizeBytes: size, Vg: vg, + VolumeId: volumeID, SizeBytes: size, Vg: vg, StorageClass: storageClass, Export: &export, Protocol: protocolValue(protocol), RequestId: volumeID, }) if err != nil { @@ -167,9 +171,17 @@ func (controller *Controller) createResponse(request *csipb.CreateVolumeRequest, if fsType == "" { fsType = request.GetParameters()["csi.storage.k8s.io/fstype"] } + storageClass := volume.GetStorageClass() + if storageClass == "" { + storageClass = request.GetParameters()["class"] + } + if storageClass == "" { + storageClass = volume.GetVgName() + } volumeContext := map[string]string{ "endpoint": host.endpoint, "host_uuid": host.uuid, "volume_id": volume.GetVolumeId(), - "vg": volume.GetVgName(), "protocol": protocol, "fsType": fsType, + "vg": volume.GetVgName(), "storage_class": storageClass, + "protocol": protocol, "fsType": fsType, } if initiator := request.GetParameters()["initiator"]; initiator != "" { volumeContext["initiator"] = initiator @@ -449,7 +461,11 @@ func (controller *Controller) ListVolumes(ctx context.Context, request *csipb.Li func (controller *Controller) GetCapacity(ctx context.Context, request *csipb.GetCapacityRequest) (*csipb.GetCapacityResponse, error) { var available, maximum int64 - requestedVG := request.GetParameters()["vg"] + storageClass := strings.TrimSpace(request.GetParameters()["class"]) + if storageClass == "" { + storageClass = strings.TrimSpace(request.GetParameters()["storageClass"]) + } + requestedVG := strings.TrimSpace(request.GetParameters()["vg"]) controller.mu.RLock() hosts := append([]*hostClient(nil), controller.hosts...) controller.mu.RUnlock() @@ -459,7 +475,7 @@ func (controller *Controller) GetCapacity(ctx context.Context, request *csipb.Ge continue } for _, capacity := range response.GetVgs() { - if requestedVG != "" && capacity.GetVgName() != requestedVG { + if !capacityMatches(capacity, storageClass, requestedVG) { continue } available += capacity.GetAllocatableBytes() @@ -536,7 +552,7 @@ func (controller *Controller) ControllerGetVolume(ctx context.Context, request * }, Status: condition}, nil } -func (controller *Controller) selectHost(ctx context.Context, vg, protocol string, size int64) (*hostClient, error) { +func (controller *Controller) selectHost(ctx context.Context, storageClass, vg, protocol string, size int64) (*hostClient, error) { controller.mu.RLock() hosts := append([]*hostClient(nil), controller.hosts...) controller.mu.RUnlock() @@ -555,7 +571,7 @@ func (controller *Controller) selectHost(ctx context.Context, vg, protocol strin continue } for _, value := range capacity.GetVgs() { - if value.GetVgName() == vg && value.GetAllocatableBytes() >= size { + if capacityMatches(value, storageClass, vg) && value.GetAllocatableBytes() >= size { return host, nil } } @@ -566,6 +582,21 @@ func (controller *Controller) selectHost(ctx context.Context, vg, protocol strin return nil, status.Error(codes.ResourceExhausted, "no kouja host has sufficient capacity") } +func capacityMatches(capacity *koujav1.Capacity, storageClass, vg string) bool { + if vg != "" && capacity.GetVgName() != vg { + return false + } + if storageClass == "" { + return true + } + if class := capacity.GetStorageClass(); class != "" { + return class == storageClass + } + // Older agents do not return a class. In that case the class can only be + // the VG name, matching the pre-class API contract. + return capacity.GetVgName() == storageClass +} + func supportsProtocol(ctx context.Context, host *hostClient, protocol string) bool { info, err := host.volume.GetInfo(ctx, &koujav1.GetInfoRequest{}) if err != nil { diff --git a/internal/csi/controller_test.go b/internal/csi/controller_test.go index 49acaa6..1dccd11 100644 --- a/internal/csi/controller_test.go +++ b/internal/csi/controller_test.go @@ -220,9 +220,11 @@ func (placement *fakePlacement) List(context.Context) ([]PlacementRecord, error) return result, nil } -func (placement *fakePlacement) Pending(_ context.Context, key string, host Host, volumeID string) error { +func (placement *fakePlacement) Pending(_ context.Context, key string, host Host, volumeID, storageClass string) error { placement.pending++ - placement.records[key] = PlacementRecord{Key: key, HostUUID: host.UUID, VolumeID: volumeID, Phase: "Pending"} + placement.records[key] = PlacementRecord{ + Key: key, HostUUID: host.UUID, VolumeID: volumeID, StorageClass: storageClass, Phase: "Pending", + } return nil } diff --git a/internal/csi/placement.go b/internal/csi/placement.go index 5fa8b31..edb450a 100644 --- a/internal/csi/placement.go +++ b/internal/csi/placement.go @@ -79,7 +79,7 @@ func (placement *KubernetesPlacement) List(ctx context.Context) ([]PlacementReco return records, nil } -func (placement *KubernetesPlacement) Pending(ctx context.Context, key string, host Host, volumeID string) error { +func (placement *KubernetesPlacement) Pending(ctx context.Context, key string, host Host, volumeID, storageClass string) error { object := &unstructured.Unstructured{Object: map[string]any{ "apiVersion": "kouja.io/v1alpha1", "kind": "KoujaVolumePlacement", @@ -87,7 +87,7 @@ func (placement *KubernetesPlacement) Pending(ctx context.Context, key string, h "spec": map[string]any{ "placementKey": key, "csiVolumeName": key, - "storageClass": "", + "storageClass": storageClass, "hostUuid": host.UUID, "volumeId": volumeID, "idempotencyKey": volumeID, diff --git a/internal/csi/placement_test.go b/internal/csi/placement_test.go index 0a959f1..37f3512 100644 --- a/internal/csi/placement_test.go +++ b/internal/csi/placement_test.go @@ -25,14 +25,14 @@ func bddTestKubernetesPlacementLifecycle(t testing.TB) { if _, err := placement.Get(ctx, key); !errors.Is(err, ErrPlacementNotFound) { t.Fatalf("missing placement: %v", err) } - if err := placement.Pending(ctx, key, Host{UUID: "host-1", Endpoint: "10.0.0.1:9443"}, key); err != nil { + if err := placement.Pending(ctx, key, Host{UUID: "host-1", Endpoint: "10.0.0.1:9443"}, key, "nvme"); err != nil { t.Fatalf("pending: %v", err) } record, err := placement.Get(ctx, key) if err != nil { t.Fatalf("get pending: %v", err) } - if record.HostUUID != "host-1" || record.VolumeID != key || record.Phase != "Pending" { + if record.HostUUID != "host-1" || record.VolumeID != key || record.StorageClass != "nvme" || record.Phase != "Pending" { t.Fatalf("pending record: %#v", record) } if err := placement.Bind(ctx, key, "resource-1"); err != nil { diff --git a/internal/csi/storage_class_test.go b/internal/csi/storage_class_test.go new file mode 100644 index 0000000..53a549d --- /dev/null +++ b/internal/csi/storage_class_test.go @@ -0,0 +1,61 @@ +package csi + +import ( + "context" + + csipb "github.com/container-storage-interface/spec/lib/go/csi" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + koujav1 "github.com/voidstarit/kouja/gen/kouja/v1" +) + +var _ = Describe("CSI storage classes", func() { + newCapacity := func() *koujav1.GetCapacityResponse { + return &koujav1.GetCapacityResponse{Vgs: []*koujav1.Capacity{ + {VgName: "vg-nvme", StorageClass: "nvme", VgState: "active", AllocatableBytes: 2 << 30, MaxVolumeBytes: 2 << 30}, + {VgName: "vg-hdd", StorageClass: "hdd", VgState: "active", AllocatableBytes: 3 << 30, MaxVolumeBytes: 3 << 30}, + }} + } + + It("selects a host by class without requiring a VG parameter", func() { + controller, volume, _, _, _ := newTestController() + volume.capacity = newCapacity() + volume.createFn = func(request *koujav1.CreateVolumeRequest) (*koujav1.CreateVolumeResponse, error) { + return &koujav1.CreateVolumeResponse{Volume: &koujav1.Volume{ + VolumeId: request.GetVolumeId(), ResourceUuid: "resource-1", VgName: "vg-nvme", + StorageClass: request.GetStorageClass(), ActualSizeBytes: request.GetSizeBytes(), + }}, nil + } + response, err := controller.CreateVolume(context.Background(), &csipb.CreateVolumeRequest{ + Name: "vol-class", + CapacityRange: &csipb.CapacityRange{RequiredBytes: 1 << 30}, + Parameters: map[string]string{"class": "nvme", "protocol": "iscsi"}, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(volume.lastCreate.GetStorageClass()).To(Equal("nvme")) + Expect(volume.lastCreate.GetVg()).To(BeEmpty()) + Expect(response.GetVolume().GetVolumeContext()["storage_class"]).To(Equal("nvme")) + Expect(response.GetVolume().GetVolumeContext()["vg"]).To(Equal("vg-nvme")) + }) + + It("filters capacity by class", func() { + controller, volume, _, _, _ := newTestController() + volume.capacity = newCapacity() + response, err := controller.GetCapacity(context.Background(), &csipb.GetCapacityRequest{ + Parameters: map[string]string{"class": "hdd"}, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(response.GetAvailableCapacity()).To(Equal(int64(3 << 30))) + Expect(response.GetMaximumVolumeSize().GetValue()).To(Equal(int64(3 << 30))) + }) + + It("still filters capacity by a raw VG", func() { + controller, volume, _, _, _ := newTestController() + volume.capacity = newCapacity() + response, err := controller.GetCapacity(context.Background(), &csipb.GetCapacityRequest{ + Parameters: map[string]string{"vg": "vg-nvme"}, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(response.GetAvailableCapacity()).To(Equal(int64(2 << 30))) + }) +}) diff --git a/internal/csi/types.go b/internal/csi/types.go index 5e2def1..9f537f7 100644 --- a/internal/csi/types.go +++ b/internal/csi/types.go @@ -69,7 +69,7 @@ type Inventory interface { type Placement interface { Get(ctx context.Context, key string) (PlacementRecord, error) List(ctx context.Context) ([]PlacementRecord, error) - Pending(ctx context.Context, key string, host Host, volumeID string) error + Pending(ctx context.Context, key string, host Host, volumeID, storageClass string) error Bind(ctx context.Context, key string, resourceUUID string) error Fail(ctx context.Context, key string, err error) error Delete(ctx context.Context, key string) error diff --git a/proto/kouja/v1/common.proto b/proto/kouja/v1/common.proto index b1541dc..fbbfcbe 100644 --- a/proto/kouja/v1/common.proto +++ b/proto/kouja/v1/common.proto @@ -77,6 +77,9 @@ message Volume { google.protobuf.Timestamp created_at = 11; google.protobuf.Timestamp updated_at = 12; map legacy_identity = 13; + // Storage class selected for this volume. The LVM volume group remains the + // canonical backend identity; this is the policy/category label. + string storage_class = 14; } message Export { @@ -115,4 +118,7 @@ message Capacity { int64 extent_size_bytes = 7; int64 max_volume_bytes = 8; google.protobuf.Timestamp observed_at = 9; + // Storage class configured for this volume group, or the VG name when no + // explicit class mapping exists. + string storage_class = 10; } diff --git a/proto/kouja/v1/volume.proto b/proto/kouja/v1/volume.proto index 5b5a544..8dc327d 100644 --- a/proto/kouja/v1/volume.proto +++ b/proto/kouja/v1/volume.proto @@ -5,6 +5,7 @@ package kouja.v1; option go_package = "github.com/voidstarit/kouja/gen/kouja/v1;koujav1"; import "google/api/annotations.proto"; +import "google/protobuf/timestamp.proto"; import "kouja/v1/common.proto"; message CreateVolumeRequest { @@ -17,6 +18,9 @@ message CreateVolumeRequest { bool wipe = 7; string request_id = 8; optional bool include_credential = 9; + // Optional host storage class. When set, the agent resolves it to the + // configured LVM volume group. vg remains supported for compatibility. + string storage_class = 10; } message CreateVolumeResponse { @@ -136,6 +140,26 @@ message GetCapacityResponse { repeated Capacity vgs = 1; } +message ListStorageClassesRequest {} + +message StorageClass { + // Stable class name configured on the agent. + string name = 1; + string vg_name = 2; + string vg_uuid = 3; + string vg_state = 4; + int64 total_bytes = 5; + int64 free_bytes = 6; + int64 allocatable_bytes = 7; + int64 extent_size_bytes = 8; + int64 max_volume_bytes = 9; + google.protobuf.Timestamp observed_at = 10; +} + +message ListStorageClassesResponse { + repeated StorageClass classes = 1; +} + message GetInfoRequest {} message GetInfoResponse { @@ -178,6 +202,9 @@ service VolumeService { rpc GetCapacity(GetCapacityRequest) returns (GetCapacityResponse) { option (google.api.http) = { get: "/v1/capacity" }; } + rpc ListStorageClasses(ListStorageClassesRequest) returns (ListStorageClassesResponse) { + option (google.api.http) = { get: "/v1/storage-classes" }; + } rpc GetInfo(GetInfoRequest) returns (GetInfoResponse) { option (google.api.http) = { get: "/v1/info" }; }