// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

syntax = "proto3";

package chromiumos.test.api;

option go_package = "go.chromium.org/chromiumos/config/go/test/api";

import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "chromiumos/test/api/device_leasing.proto";

service DeviceLeaseService {
  // Lease a device and create a lease.
  rpc LeaseDevice(LeaseDeviceRequest) returns (LeaseDeviceResponse) {};

  // Bulk lease devices and create leases for all of them.
  rpc BulkLeaseDevices(BulkLeaseDevicesRequest)
      returns (BulkLeaseDevicesResponse) {};

  // Release a device lease.
  rpc ReleaseDevice(ReleaseDeviceRequest) returns (ReleaseDeviceResponse) {};

  // Extend a device lease by modifying the expiration time.
  rpc ExtendLease(ExtendLeaseRequest) returns (ExtendLeaseResponse) {};

  // Get a device by device id.
  // Designed to adhere to https://google.aip.dev/131.
  rpc GetDevice(GetDeviceRequest) returns (Device) {};

  // List devices managed by Device Manager.
  // Designed to adhere to https://google.aip.dev/132.
  rpc ListDevices(ListDevicesRequest) returns (ListDevicesResponse) {};

  // List device leases for a given device.
  rpc ListDeviceLeases(ListDeviceLeasesRequest)
      returns (ListDeviceLeasesResponse) {};
}

message Device {
  // In the case of VMs, device id could be the GCE instance name. For physical
  // DUTs we use the IDs we get from UFS.
  string id = 1;
  // dut_id is the asset tag for a Device
  string dut_id = 6;

  DeviceAddress address = 2;
  DeviceType type = 3;
  DeviceState state = 4;

  // This proto contains per-DUT hardware relevant information including labels.
  HardwareRequirements hardware_reqs = 5;
}

message DeviceAddress {
  // IP address of the device.
  // For physical DUTs it can be a hostname.
  string host = 1;
  int32 port = 2;
}

// This is different than device features which are expressed in
// requirements_eq. This is more about virtual, physical, or either initially.
enum DeviceType {
  DEVICE_TYPE_UNSPECIFIED = 0;
  DEVICE_TYPE_VIRTUAL = 1;
  DEVICE_TYPE_PHYSICAL = 2;
}

// The list is not final and can be extended later.
enum DeviceState {
  DEVICE_STATE_UNSPECIFIED = 0;
  // Default state.
  // Device is available to be leased.
  DEVICE_STATE_AVAILABLE = 1;
  // Device is leased.
  DEVICE_STATE_LEASED = 2;
}

message DeviceLeaseRecord {
  // Lease id
  // Should be uniquely generated by UUID4.
  string id = 1;
  // Key specified by client per request.
  // Requests with the same key will be treated as duplicate requests.
  string idempotency_key = 2;

  // Device data.
  // Id (hostname) corresponding to the device name.
  string device_id = 3;
  // DUT ID (asset tag) corresponding to the device name.
  string dut_id = 11;
  // SSH-able address to access the device.
  DeviceAddress device_address = 4;
  // Type of device leased.
  DeviceType device_type = 5;

  // Tracking times.
  // Time when the device was leased.
  google.protobuf.Timestamp leased_time = 6;
  // Time when the device was released by a request or cron.
  google.protobuf.Timestamp released_time = 7;
  // Lease expiration time. The time can be updated several times.
  // The record keeps the last known value.
  google.protobuf.Timestamp expiration_time = 8;
  // Last updated time. The time when the lease was last updated.
  // This will be used as a versioning timestamp
  google.protobuf.Timestamp last_updated_time = 9;

  // Request data.
  // All parameters used to create a device will be saved for further analysis.
  // Possible that the data will be removed later if established as not needed.
  map<string, string> request_parameters = 10;

  // user_payload string-based key-value pairs.
  // This map provides relevant information may interested to users.
  map<string, string> user_payload = 12;
}

message LeaseDeviceRequest {
  // Generated on the client side, shared across retries but pseudo-unique
  // across different logical requests. Requests with the same key will be
  // treated as duplicate of original request, return the same response.
  string idempotency_key = 1;

  // This is the final end user (can be human or robot). Useful for both
  // debugging and analytics. For example, for a tests triggered for a CL,
  // this field could indicate the CL author as they are the end user.
  //
  // For direct invocations like CLI, this is enforced at first entry point
  // but trusted from there.
  //
  // Not to be confused with LUCI auth which is done by the caller assuming
  // the appropriate identity from a permissions perspective — like LUCI
  // project.
  string on_behalf_of = 2;

  // This is the quota the end user is requesting to use. One user can have
  // access to multiple quotas. For example, release, CQ, performance testing,
  // etc.
  string quota_id = 3;

  // Optional with a good default.
  // Important to configure a good max (e.g. 10 min). This will put a ceiling
  // on time wasted if the client dies.
  google.protobuf.Duration lease_duration = 4;

  // The populated requirements will specify what kind of device manager
  // returns. The client can populate both to indicate that they are ok with
  // either a VM or Hardware DUT.
  VMRequirements vm_host_reqs = 5;
  HardwareRequirements hardware_device_reqs = 6;

  // user_payload string-based key-value pairs.
  // This map provides relevant information may interested to users.
  map<string, string> user_payload = 7;
}

message LeaseDeviceResponse {
  DeviceLeaseRecord device_lease = 1;

  // Eventually we will include authentication token to access device for the
  // duration of the lease. Shared and long lived secrets are not good security.
  // Today there is no such enforcement so this is not a regression.

  LeaseDeviceResponseErrorType error_type = 2;
  string error_string = 3;
}

enum LeaseDeviceResponseErrorType {
  LEASE_ERROR_TYPE_NONE = 0;
  LEASE_ERROR_TYPE_DEVICE_NOT_FOUND = 1;
  LEASE_ERROR_TYPE_DEVICE_ALREADY_LEASED = 2;
}

message BulkLeaseDevicesRequest {
  // A list of LeaseDeviceRequests.
  repeated LeaseDeviceRequest lease_device_requests = 1;
}

message BulkLeaseDevicesResponse {
  // One LeaseDeviceResponse for each LeaseDeviceRequest in the
  // BulkLeaseDevicesRequest.
  repeated LeaseDeviceResponse lease_device_responses = 1;

  // Overall error for the bulk request. It is possible for the response to
  // error with partial success of leasing.
  BulkLeaseDevicesResponseErrorType error_type = 2;
  string error_string = 3;
}

enum BulkLeaseDevicesResponseErrorType {
  BULK_LEASE_ERROR_TYPE_NONE = 0;
  // Internal Postgres errors.
  BULK_LEASE_ERROR_TYPE_INTERNAL_DATABASE_ERR = 1;
  // Some Devices failed to be leased. See individual lease request errors.
  BULK_LEASE_ERROR_TYPE_PARTIAL_LEASE_FAILURE = 2;
}

message ReleaseDeviceRequest {
  string lease_id = 1;
}

message ReleaseDeviceResponse {
  string lease_id = 1;
  ReleaseDeviceResponseErrorType error_type = 2;
  string error_string = 3;
}

enum ReleaseDeviceResponseErrorType {
  ERROR_TYPE_NONE = 0;
  ERROR_TYPE_DEVICE_ALREADY_RELEASED = 1;
}

message GetDeviceRequest {
  // The name of the device to retrieve.
  // Format: devices/{device_id}.
  string name = 1;
}

// The response for GetDevice is Device.

message ListDevicesRequest {
  // The parent for which to list devices. Based on collections of pools.
  // If no parent is specified, all devices will be queried.
  // Format: pools/{pool}.
  string parent = 1;

  // The maximum number of devices to return. The service may return fewer than
  // this value. If unspecified, at most 50 devices will be returned.
  int32 page_size = 2;

  // A page token, received from a previous `ListDevices` call. Provide this to
  // retrieve the subsequent page.
  //
  // When paginating, all other parameters provided to `ListDevices` must match
  // the call that provided the page token.
  string page_token = 3;

  // The string filter follows AIP-160 (https://google.aip.dev/160) for the
  // filtering syntax.
  string filter = 4;
}

message ListDevicesResponse {
  // List of devices to be returned.
  repeated Device devices = 1;

  // A token, which can be sent as `page_token` to retrieve the next page. If
  // this field is omitted, there are no subsequent pages.
  string next_page_token = 2;
}

message ListDeviceLeasesRequest {
  oneof id {
    string device_id = 1;  // i.e. DUT name, e.g. chromeos8-rowX-rackY-hostZ.
    string dut_id = 2;     // i.e. Asset ID, e.g. C1234567.
  }
  // The maximum number of leases records to return. The service may return
  // fewer than this value.
  // If unspecified, at most 50 records will be returned.
  int32 page_size = 3;

  // A page token, received from a previous `ListDeviceLeases` call. Provide
  // this to retrieve the subsequent page.
  //
  // When paginating, all other parameters provided to `ListDevices` must match
  // the call that provided the page token.
  string page_token = 4;
}

message ListDeviceLeasesResponse {
  // List of lease records to be returned.
  repeated DeviceLeaseRecord lease_records = 1;

  // A token, which can be sent as `page_token` to retrieve the next page. If
  // this field is omitted, there are no subsequent pages.
  string next_page_token = 2;
}
