aboutsummaryrefslogblamecommitdiff
path: root/src/api/admin/api.rs
blob: 97cde15857d8ca4d2753a54973cb68b34040d0ee (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                              
                          
                         
                   
 
                 

                                    

                  

                                 
                                                           

                                           
                                                    

                        
                                   
 
                                
  
                                                                      










                                                                                    
                                                                  
  


                                                                                 
                                             



                             
 
                             






                            

                                





                   

                            




                      
                                 

                                                        

                       

                                       

                          
 

                               

                             
                              
 
                            

                      

                          



                           

                         
  
 
                       

                               
                          
                              




                             


                           

                         













                                               
                                                 
                         


                                                          

                                                 
                                               
                          
 
                                               


                               
 
                                               

                         
                                               

                          





                                                 
                                               

                                   
                                               


                                     


                                                 




                                 
                                                        














                                                         
                                               







                                  
                                               







                                  
                                               

                                   
                                               

                                     
                           










                                     
                                               

                                                       
                                               
                                                                     
 
                                               
                                  
                                





                                  
                                               

                                   
                                               






                                                     
                                               






                                       
                                               













                                          
                                               

                                                               
                                               



                                                                     
                                               




                                      
                                               







                                             
                                               

                                      
                                               







                                                                     
                                               

                           
                                               

                                                           
                                               







                                  
                                               





                                   
                                               









                                                    
                                               





                                  
                                               







                                          
                                                        











                                  
                                               




                                  
                                               



                                                     
                                               






                                      
                                               



                                                     
                                               

                             
                                       

 
                                               

                                                     
                                               
                                  
                                 




                                   

                      
                                               



                             
                                               







                                                 
                                               

                              
                                               

                                                                 
                                               






                                                 
                                               







                                  
                                               


                                         
                                   

 
                                               
















                                                                 
                                               





                                           
                                               







                                              
                                               







                                     
                                               





                                                        
                                               
                                                           
 
                                               









                                    
                                               

                                
                                          

 
                                               

                                                           
                                               
                                  
                                    



                                                              
                                               








                                           
                                               



                                
                                               

                                












                                               



                                                     
                           
 
                                               
                                                                 
 
                                               
                                                             
 
                                               






                                          
                          
 
                                               
                                                                
 
                                               
                                                            




                                                 
                           
 
                                               
                                  
                                  
                              

                                   

 
                                               
                                                             
 
                                               










                                          
                              
 
                                               
                                  
                                     
                              

                                   

 
                                               
                                                                

                                                 










                                                        



















                                                        































                                               
                                                 


                                                 


                                                        
                                  



















































                                                             






















                                                                       






























































                                                             































                                                    
use std::collections::HashMap;
use std::convert::TryFrom;
use std::net::SocketAddr;
use std::sync::Arc;

use paste::paste;
use serde::{Deserialize, Serialize};

use garage_rpc::*;

use garage_model::garage::Garage;

use garage_api_common::common_error::CommonErrorDerivative;
use garage_api_common::helpers::is_default;

use crate::api_server::{AdminRpc, AdminRpcResponse};
use crate::error::Error;
use crate::macros::*;
use crate::{Admin, RequestHandler};

// This generates the following:
//
// - An enum AdminApiRequest that contains a variant for all endpoints
//
// - An enum AdminApiResponse that contains a variant for all non-special endpoints.
//   This enum is serialized in api_server.rs, without the enum tag,
//   which gives directly the JSON response corresponding to the API call.
//   This enum does not implement Deserialize as its meaning can be ambiguous.
//
// - An enum TaggedAdminApiResponse that contains the same variants, but
//   serializes as a tagged enum. This allows it to be transmitted through
//   Garage RPC and deserialized correctly upon receival.
//   Conversion from untagged to tagged can be done using the `.tagged()` method.
//
// - AdminApiRequest::name() that returns the name of the endpoint
//
// - impl EndpointHandler for AdminApiHandler, that uses the impl EndpointHandler
//   of each request type below for non-special endpoints
admin_endpoints![
	// Special endpoints of the Admin API
	@special Options,
	@special CheckDomain,
	@special Health,
	@special Metrics,

	// Cluster operations
	GetClusterStatus,
	GetClusterHealth,
	ConnectClusterNodes,
	GetClusterLayout,
	UpdateClusterLayout,
	ApplyClusterLayout,
	RevertClusterLayout,

	// Access key operations
	ListKeys,
	GetKeyInfo,
	CreateKey,
	ImportKey,
	UpdateKey,
	DeleteKey,

	// Bucket operations
	ListBuckets,
	GetBucketInfo,
	CreateBucket,
	UpdateBucket,
	DeleteBucket,
	CleanupIncompleteUploads,

	// Operations on permissions for keys on buckets
	AllowBucketKey,
	DenyBucketKey,

	// Operations on bucket aliases
	AddBucketAlias,
	RemoveBucketAlias,

	// Node operations
	CreateMetadataSnapshot,
	GetNodeStatistics,
	GetClusterStatistics,
	LaunchRepairOperation,

	// Worker operations
	ListWorkers,
	GetWorkerInfo,
	GetWorkerVariable,
	SetWorkerVariable,

	// Block operations
	ListBlockErrors,
	GetBlockInfo,
	RetryBlockResync,
	PurgeBlocks,
];

local_admin_endpoints![
	// Node operations
	CreateMetadataSnapshot,
	GetNodeStatistics,
	LaunchRepairOperation,
	// Background workers
	ListWorkers,
	GetWorkerInfo,
	GetWorkerVariable,
	SetWorkerVariable,
	// Block operations
	ListBlockErrors,
	GetBlockInfo,
	RetryBlockResync,
	PurgeBlocks,
];

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MultiRequest<RB> {
	pub node: String,
	pub body: RB,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MultiResponse<RB> {
	pub success: HashMap<String, RB>,
	pub error: HashMap<String, String>,
}

// **********************************************
//      Special endpoints
//
// These endpoints don't have associated *Response structs
// because they directly produce an http::Response
// **********************************************

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OptionsRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CheckDomainRequest {
	pub domain: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricsRequest;

// **********************************************
//      Cluster operations
// **********************************************

// ---- GetClusterStatus ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetClusterStatusRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetClusterStatusResponse {
	pub node: String,
	pub garage_version: String,
	pub garage_features: Option<Vec<String>>,
	pub rust_version: String,
	pub db_engine: String,
	pub layout_version: u64,
	pub nodes: Vec<NodeResp>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct NodeResp {
	pub id: String,
	pub role: Option<NodeRoleResp>,
	pub addr: Option<SocketAddr>,
	pub hostname: Option<String>,
	pub is_up: bool,
	pub last_seen_secs_ago: Option<u64>,
	pub draining: bool,
	#[serde(skip_serializing_if = "Option::is_none")]
	pub data_partition: Option<FreeSpaceResp>,
	#[serde(skip_serializing_if = "Option::is_none")]
	pub metadata_partition: Option<FreeSpaceResp>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeRoleResp {
	pub id: String,
	pub zone: String,
	pub capacity: Option<u64>,
	pub tags: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FreeSpaceResp {
	pub available: u64,
	pub total: u64,
}

// ---- GetClusterHealth ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetClusterHealthRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetClusterHealthResponse {
	pub status: String,
	pub known_nodes: usize,
	pub connected_nodes: usize,
	pub storage_nodes: usize,
	pub storage_nodes_ok: usize,
	pub partitions: usize,
	pub partitions_quorum: usize,
	pub partitions_all_ok: usize,
}

// ---- ConnectClusterNodes ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectClusterNodesRequest(pub Vec<String>);

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectClusterNodesResponse(pub Vec<ConnectNodeResponse>);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConnectNodeResponse {
	pub success: bool,
	pub error: Option<String>,
}

// ---- GetClusterLayout ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetClusterLayoutRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetClusterLayoutResponse {
	pub version: u64,
	pub roles: Vec<NodeRoleResp>,
	pub staged_role_changes: Vec<NodeRoleChange>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeRoleChange {
	pub id: String,
	#[serde(flatten)]
	pub action: NodeRoleChangeEnum,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum NodeRoleChangeEnum {
	#[serde(rename_all = "camelCase")]
	Remove { remove: bool },
	#[serde(rename_all = "camelCase")]
	Update {
		zone: String,
		capacity: Option<u64>,
		tags: Vec<String>,
	},
}

// ---- UpdateClusterLayout ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateClusterLayoutRequest(pub Vec<NodeRoleChange>);

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateClusterLayoutResponse(pub GetClusterLayoutResponse);

// ---- ApplyClusterLayout ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApplyClusterLayoutRequest {
	pub version: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApplyClusterLayoutResponse {
	pub message: Vec<String>,
	pub layout: GetClusterLayoutResponse,
}

// ---- RevertClusterLayout ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RevertClusterLayoutRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RevertClusterLayoutResponse(pub GetClusterLayoutResponse);

// **********************************************
//      Access key operations
// **********************************************

// ---- ListKeys ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListKeysRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListKeysResponse(pub Vec<ListKeysResponseItem>);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListKeysResponseItem {
	pub id: String,
	pub name: String,
}

// ---- GetKeyInfo ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetKeyInfoRequest {
	pub id: Option<String>,
	pub search: Option<String>,
	pub show_secret_key: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetKeyInfoResponse {
	pub name: String,
	pub access_key_id: String,
	#[serde(skip_serializing_if = "is_default")]
	pub secret_access_key: Option<String>,
	pub permissions: KeyPerm,
	pub buckets: Vec<KeyInfoBucketResponse>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct KeyPerm {
	#[serde(default)]
	pub create_bucket: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct KeyInfoBucketResponse {
	pub id: String,
	pub global_aliases: Vec<String>,
	pub local_aliases: Vec<String>,
	pub permissions: ApiBucketKeyPerm,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ApiBucketKeyPerm {
	#[serde(default)]
	pub read: bool,
	#[serde(default)]
	pub write: bool,
	#[serde(default)]
	pub owner: bool,
}

// ---- CreateKey ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateKeyRequest {
	pub name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateKeyResponse(pub GetKeyInfoResponse);

// ---- ImportKey ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ImportKeyRequest {
	pub access_key_id: String,
	pub secret_access_key: String,
	pub name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImportKeyResponse(pub GetKeyInfoResponse);

// ---- UpdateKey ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateKeyRequest {
	pub id: String,
	pub body: UpdateKeyRequestBody,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateKeyResponse(pub GetKeyInfoResponse);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateKeyRequestBody {
	pub name: Option<String>,
	pub allow: Option<KeyPerm>,
	pub deny: Option<KeyPerm>,
}

// ---- DeleteKey ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteKeyRequest {
	pub id: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteKeyResponse;

// **********************************************
//      Bucket operations
// **********************************************

// ---- ListBuckets ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListBucketsRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListBucketsResponse(pub Vec<ListBucketsResponseItem>);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListBucketsResponseItem {
	pub id: String,
	pub global_aliases: Vec<String>,
	pub local_aliases: Vec<BucketLocalAlias>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BucketLocalAlias {
	pub access_key_id: String,
	pub alias: String,
}

// ---- GetBucketInfo ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetBucketInfoRequest {
	pub id: Option<String>,
	pub global_alias: Option<String>,
	pub search: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBucketInfoResponse {
	pub id: String,
	pub global_aliases: Vec<String>,
	pub website_access: bool,
	#[serde(default)]
	pub website_config: Option<GetBucketInfoWebsiteResponse>,
	pub keys: Vec<GetBucketInfoKey>,
	pub objects: i64,
	pub bytes: i64,
	pub unfinished_uploads: i64,
	pub unfinished_multipart_uploads: i64,
	pub unfinished_multipart_upload_parts: i64,
	pub unfinished_multipart_upload_bytes: i64,
	pub quotas: ApiBucketQuotas,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBucketInfoWebsiteResponse {
	pub index_document: String,
	pub error_document: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBucketInfoKey {
	pub access_key_id: String,
	pub name: String,
	pub permissions: ApiBucketKeyPerm,
	pub bucket_local_aliases: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApiBucketQuotas {
	pub max_size: Option<u64>,
	pub max_objects: Option<u64>,
}

// ---- CreateBucket ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateBucketRequest {
	pub global_alias: Option<String>,
	pub local_alias: Option<CreateBucketLocalAlias>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateBucketResponse(pub GetBucketInfoResponse);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateBucketLocalAlias {
	pub access_key_id: String,
	pub alias: String,
	#[serde(default)]
	pub allow: ApiBucketKeyPerm,
}

// ---- UpdateBucket ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateBucketRequest {
	pub id: String,
	pub body: UpdateBucketRequestBody,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateBucketResponse(pub GetBucketInfoResponse);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateBucketRequestBody {
	pub website_access: Option<UpdateBucketWebsiteAccess>,
	pub quotas: Option<ApiBucketQuotas>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateBucketWebsiteAccess {
	pub enabled: bool,
	pub index_document: Option<String>,
	pub error_document: Option<String>,
}

// ---- DeleteBucket ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteBucketRequest {
	pub id: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteBucketResponse;

// ---- CleanupIncompleteUploads ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CleanupIncompleteUploadsRequest {
	pub bucket_id: String,
	pub older_than_secs: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CleanupIncompleteUploadsResponse {
	pub uploads_deleted: u64,
}

// **********************************************
//      Operations on permissions for keys on buckets
// **********************************************

// ---- AllowBucketKey ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AllowBucketKeyRequest(pub BucketKeyPermChangeRequest);

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AllowBucketKeyResponse(pub GetBucketInfoResponse);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BucketKeyPermChangeRequest {
	pub bucket_id: String,
	pub access_key_id: String,
	pub permissions: ApiBucketKeyPerm,
}

// ---- DenyBucketKey ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DenyBucketKeyRequest(pub BucketKeyPermChangeRequest);

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DenyBucketKeyResponse(pub GetBucketInfoResponse);

// **********************************************
//      Operations on bucket aliases
// **********************************************

// ---- AddBucketAlias ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddBucketAliasRequest {
	pub bucket_id: String,
	#[serde(flatten)]
	pub alias: BucketAliasEnum,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddBucketAliasResponse(pub GetBucketInfoResponse);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum BucketAliasEnum {
	#[serde(rename_all = "camelCase")]
	Global { global_alias: String },
	#[serde(rename_all = "camelCase")]
	Local {
		local_alias: String,
		access_key_id: String,
	},
}

// ---- RemoveBucketAlias ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RemoveBucketAliasRequest {
	pub bucket_id: String,
	#[serde(flatten)]
	pub alias: BucketAliasEnum,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoveBucketAliasResponse(pub GetBucketInfoResponse);

// **********************************************
//      Node operations
// **********************************************

// ---- CreateMetadataSnapshot ----

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct LocalCreateMetadataSnapshotRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalCreateMetadataSnapshotResponse;

// ---- GetNodeStatistics ----

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct LocalGetNodeStatisticsRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalGetNodeStatisticsResponse {
	pub freeform: String,
}

// ---- GetClusterStatistics ----

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct GetClusterStatisticsRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetClusterStatisticsResponse {
	pub freeform: String,
}

// ---- LaunchRepairOperation ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalLaunchRepairOperationRequest {
	pub repair_type: RepairType,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum RepairType {
	Tables,
	Blocks,
	Versions,
	MultipartUploads,
	BlockRefs,
	BlockRc,
	Rebalance,
	Scrub(ScrubCommand),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ScrubCommand {
	Start,
	Pause,
	Resume,
	Cancel,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalLaunchRepairOperationResponse;

// **********************************************
//      Worker operations
// **********************************************

// ---- GetWorkerList ----

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct LocalListWorkersRequest {
	#[serde(default)]
	pub busy_only: bool,
	#[serde(default)]
	pub error_only: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalListWorkersResponse(pub Vec<WorkerInfoResp>);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WorkerInfoResp {
	pub id: u64,
	pub name: String,
	pub state: WorkerStateResp,
	pub errors: u64,
	pub consecutive_errors: u64,
	pub last_error: Option<WorkerLastError>,
	pub tranquility: Option<u32>,
	pub progress: Option<String>,
	pub queue_length: Option<u64>,
	pub persistent_errors: Option<u64>,
	pub freeform: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum WorkerStateResp {
	Busy,
	Throttled { duration_secs: f32 },
	Idle,
	Done,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WorkerLastError {
	pub message: String,
	pub secs_ago: u64,
}

// ---- GetWorkerList ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalGetWorkerInfoRequest {
	pub id: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalGetWorkerInfoResponse(pub WorkerInfoResp);

// ---- GetWorkerVariable ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalGetWorkerVariableRequest {
	pub variable: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalGetWorkerVariableResponse(pub HashMap<String, String>);

// ---- SetWorkerVariable ----

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalSetWorkerVariableRequest {
	pub variable: String,
	pub value: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalSetWorkerVariableResponse {
	pub variable: String,
	pub value: String,
}

// **********************************************
//      Block operations
// **********************************************

// ---- ListBlockErrors ----

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct LocalListBlockErrorsRequest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalListBlockErrorsResponse(pub Vec<BlockError>);

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BlockError {
	pub block_hash: String,
	pub refcount: u64,
	pub error_count: u64,
	pub last_try_secs_ago: u64,
	pub next_try_in_secs: u64,
}

// ---- GetBlockInfo ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalGetBlockInfoRequest {
	pub block_hash: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalGetBlockInfoResponse {
	pub block_hash: String,
	pub refcount: u64,
	pub versions: Vec<BlockVersion>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BlockVersion {
	pub version_id: String,
	pub deleted: bool,
	pub garbage_collected: bool,
	pub backlink: Option<BlockVersionBacklink>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum BlockVersionBacklink {
	Object {
		bucket_id: String,
		key: String,
	},
	Upload {
		upload_id: String,
		upload_deleted: bool,
		upload_garbage_collected: bool,
		bucket_id: Option<String>,
		key: Option<String>,
	},
}

// ---- RetryBlockResync ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum LocalRetryBlockResyncRequest {
	#[serde(rename_all = "camelCase")]
	All { all: bool },
	#[serde(rename_all = "camelCase")]
	Blocks { block_hashes: Vec<String> },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalRetryBlockResyncResponse {
	pub count: u64,
}

// ---- PurgeBlocks ----

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalPurgeBlocksRequest(pub Vec<String>);

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalPurgeBlocksResponse {
	pub blocks_purged: u64,
	pub objects_deleted: u64,
	pub uploads_deleted: u64,
	pub versions_deleted: u64,
}