syntax = "proto3";
package control;

import "data.proto";

// models
message StorageType {
  enum MediumType {
    NOT_SPECIFIED_MEDIUM_TYPE = 0;
    BLOCK_STORAGE = 1;
    OBJECT_STORAGE = 2;
    HDD = 3;
    SSD = 4;
    NVDIMM = 5;
  }
  
  enum MediumProperty {
    NOT_SPECIFIED_MEDIUM_PROPERTY = 0;
    RANDOM_ACCESS = 1;
    REPLICATED = 2;
    MERGED = 3;
  }

  MediumType type = 1;
  repeated MediumProperty properties = 2;
}

message StoragePolicy {
  string name = 1;
  repeated StorageType stacked_types = 2;
}

message Quota {
  int64 read_iops = 1;
  int64 read_bps = 2;
  int64 write_iops = 3;
  int64 write_bps = 4;
  int64 space = 5;
}

message LabelSelectorRequirement {
  enum LabelSelectorOperator {
    NOT_SPECIFIED_OPERATOR = 0;
    IN = 1;
    NOT_INT = 2;
    EXISTS = 3;
    DOES_NOT_EXIST = 4;
  }

  string key = 1;
  LabelSelectorOperator operator = 2;
  repeated string values = 3;
}

message LabelSelector {
  map<string, string> match_labels = 1;
  repeated LabelSelectorRequirement match_expressions = 2;
}

message KeyValuePair {
  string key = 1;
  string value = 2;
}

message Tenant {
  string name = 1;
  LabelSelector selector = 2;
  repeated KeyValuePair tolerations = 3;
  Quota quota = 4;
}

message Zone {
  string name = 1;
  repeated string endpoints = 2;
}

message ZonesList {
  repeated Zone zones = 1;
}

message ThrottlerRuntimeInfo {
  int32 cpu = 1;
  repeated float loadavg = 2;
  int32 tenant_counts = 3;
}

message Throttler {
  string address = 1;
  ThrottlerRuntimeInfo runtime_info = 2;
}

message MountPoint {
  string name = 1;
  repeated Realm realms = 2;
}

message RealmRuntimeInfo {
  int64 capacity = 1;
  int64 used = 2;
  int64 last_update = 3;
  string software_version = 4;
}

message Realm {
  string name = 1;
  string address = 2;
  StoragePolicy policy = 3;
  RealmRuntimeInfo runtime_info = 4;
  map<string, string> labels = 5;
  repeated KeyValuePair taints = 6;
}

message RealmsList {
  repeated Realm realms = 1;
}

// universe req / resp messages
message ZoneHeartbeatReq {
  Zone zone = 1;
}

message GetZoneReq {
  string name = 1;
}

message DeleteZoneReq {
  string name = 1;
}

message EmptyMessage {}

message GlobZonesReq {
  string pattern = 1;
}

message CreateTenantReq {
  Tenant tenant = 1;
}

message GetTenantReq {
  string name = 1;
}

message DeleteTenantReq {
  string name = 1;
}

message TenantsList {
  repeated Tenant tenants = 1;
}

message GlobTenantsReq {
  string pattern = 1;
}

message WatchZonesReq {
  string pattern = 1;
}

message WatchTenantsReq {
  string pattern = 1;
}

// Universe service
service UniverseService {
  rpc GetZone(GetZoneReq) returns (Zone);
  rpc DeleteZone(DeleteZoneReq) returns (EmptyMessage);
  rpc GetAllZones(EmptyMessage) returns (ZonesList);
  rpc GlobZones(GlobZonesReq) returns (ZonesList);
  rpc WatchZones(WatchZonesReq) returns (stream ZonesList);
  rpc ZoneHeartbeat(ZoneHeartbeatReq) returns (Zone);

  rpc CreateTenant(CreateTenantReq) returns (Tenant);
  rpc GetTenant(GetTenantReq) returns (Tenant);
  rpc DeleteTenant(DeleteTenantReq) returns (EmptyMessage);
  rpc GetAllTenants(EmptyMessage) returns (TenantsList);
  rpc GlobTenants(GlobTenantsReq) returns (TenantsList);
  rpc WatchTenants(WatchTenantsReq) returns (stream TenantsList);
}

// zone req / resp messages
message LocateReq {
  string mount_point = 1;
  string tenant = 2;
  StoragePolicy policy = 3;
  bool create = 4;
  bool merged = 5;
}

message LocateResp {
  MountPoint mount_point = 1;
  Throttler throttler =2;
}

message RemoveMountReq {
  string mount_point = 1;
  string tenant = 2;
}

message GetRealmReq {
  string name = 1;
}

message GlobRealmsReq {
  string pattern = 1;
}

message RealmHeartbeatReq {
  Realm realm = 1;
}

message RealmHeartbeatResp {
}

message ThrottlerHeartbeatReq {
  Throttler throttler = 1;
}

message ThrottlerHeartbeatResp {
  Throttler transfer_target = 1;
}

message WatchRealmsReq {
  string pattern = 1;
}

service ZoneService {
  rpc Locate(LocateReq) returns (MountPoint);
  rpc RemoveMount(RemoveMountReq) returns (EmptyMessage);

  rpc GetRealm(GetRealmReq) returns (Realm);
  rpc GetAllRealms(EmptyMessage) returns (RealmsList);
  rpc GlobRealms(GlobRealmsReq) returns (RealmsList);
  rpc WatchRealms(WatchRealmsReq) returns (stream RealmsList);

  rpc RealmHeartbeat(RealmHeartbeatReq) returns (RealmHeartbeatResp);
  rpc ThrottlerHeartbeat(ThrottlerHeartbeatReq) returns (ThrottlerHeartbeatResp);
}

// realm req / resp messages
message MountReq {
  string name = 1;
  string tenant = 2;
  bool merged = 3;
}

message MountResp {
  MountPoint mount_point = 1;
  string token = 2;
  repeated data.DirEntry entries = 3;
  int64 errno = 4;
}

message UmountReq {
  string name = 1;
  string tenant = 2;
}

message CleanupReq {
  string name = 1;
  string tenant = 2;
}

message MountPointHeartbeatReq {
  string token = 1;
  repeated string open_files = 2;
}

message MountPointHeartbeatResp {
  // expired files since last heartbeat
  repeated string expired_files = 2;
  // lease valid time in ms
  int64 lease_time = 3;
}

// realm control service
service RealmControlService {
  rpc Mount(MountReq) returns (MountResp);
  rpc Umount(UmountReq) returns (EmptyMessage);
  rpc Cleanup(CleanupReq) returns (EmptyMessage);

  rpc Heartbeat(MountPointHeartbeatReq) returns (MountPointHeartbeatResp);
}

// throttler req / resp messages
message ThrottleReq {
  string tenant = 1;
  int64 read_bytes = 2;
  int64 read_io = 3;
  int64 write_bytes = 4;
  int64 write_io = 5;
}

message ThrottleResp {
  int64 read_bytes = 1;
  int64 read_io = 2;
  int64 write_bytes = 3;
  int64 write_io = 4;
  int64 lease_time = 5;
}

message HandoverReq {
  repeated ThrottleReq tenants = 1;
}

// throttler service
service ThrottlingService {
  rpc Throttle(ThrottleReq) returns (ThrottleResp); 

  rpc Handover(HandoverReq) returns (EmptyMessage);
}
