syntax = "proto3";

package config_center;
option go_package = "github.com/tidbcloud/config-center/proto/config_center;config_center";

import "google/protobuf/empty.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/api/field_behavior.proto";
import "google/api/annotations.proto";

enum ClusterType {
    CLUSTER_TYPE_UNSPECIFIED = 0;
    DEDICATED_TIDB = 1;
    // dedicated ticdc cluster
    TICDC = 2;
    // not used
    TIPROXY = 3;
    CHANGEFEED = 4;
    // shared Resource Pool in NextGen
    SHARED_POOL = 5;
    // premium instance in NextGen
    LOGICAL_CLUSTER = 6;
    // ticdc cluster in NextGen
    TICDC_NG = 7;
    CHANGEFEED_NG = 8;
    // essential/serverless changefeed
    CHANGEFEED_ESSENTIAL = 9;
}

enum Format {
    FORMAT_UNSPECIFIED = 0;
    TOML = 1;
    JSON = 2;
    YAML = 3;
    LINES = 4;
}

enum UpdateStrategy {
    // update strategy is not specified, use default strategy defined in upper service
    UPDATE_STRATEGY_UNSPECIFIED = 0;
    UPDATE_ALL = 1;
    UPDATE_NEW = 2;
}

message ConfigurationTemplate {
    ClusterType cluster_type = 5;
    int64 template_id = 1;
    string template_name = 2;
    string configuration_type = 4;
    map<string,string> tags = 6;
    // use tiup-cluster like configuration representation like "readpool.storage.use-unified-pool = true"
    // https://github.com/pingcap/tiup/blob/v1.14.0/embed/examples/cluster/topology.example.yaml#L52
    map<string,ParamItem> data = 3;
    // AIP-148/AIP-164 compliant timestamp fields
    google.protobuf.Timestamp create_time = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp update_time = 8 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp delete_time = 9 [(google.api.field_behavior) = OUTPUT_ONLY];
}

message ConfigurationFile {
    ClusterType cluster_type = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
    string configuration_filename = 1;
    string configuration_type = 8;
    string belong_to_component = 9;
    Format format = 2;
    int64 template_id = 3;
    map<string, ParamItem> custom_params = 4;
    // full_params is designed for web interaction. there is no stability guarantee
    map<string, ParamItem> full_params = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
    // text is serialized text file content. Will never change before the modifying request
    string text = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
    // AIP-148/AIP-164 compliant timestamp fields
    google.protobuf.Timestamp create_time = 10 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp update_time = 11 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp delete_time = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
}

message ParamItem {
    google.protobuf.Value value = 1;
    string comment = 2;
}

message CreateClusterConfigurationFileRequest {
    ClusterType cluster_type = 1 [(google.api.field_behavior) = REQUIRED];
    string cluster_id = 2 [(google.api.field_behavior) = REQUIRED];
    // string configuration_filename = 3 [(google.api.field_behavior) = REQUIRED];

    ConfigurationFile configuration_file = 3;
    bool validate_only = 4;
    // /Format format = 4;
    // int64 template_id = 5;
    // map<string,ParamItem> custom_params = 6;
}

message BatchCreateClusterConfigurationFilesRequest {
    repeated CreateClusterConfigurationFileRequest requests = 1 [(google.api.field_behavior) = REQUIRED];
    bool validate_only = 2;
}

message BatchCreateClusterConfigurationFilesResponse {
    repeated ConfigurationFile files = 1;
}

message AutoCreateClusterConfigurationFileRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string configuration_filename = 3;
    string configuration_type = 9;
    string belong_to_component = 10;
    Format format = 4;
    string version = 5;
    string cloud_provider = 6;
    string node_instance = 7;
    // auto set tenant related params to custom_params
    optional uint64 tenant_id = 8;
}

message BatchAutoCreateClusterConfigurationFilesRequest {
    repeated AutoCreateClusterConfigurationFileRequest requests = 1;
}

message BatchAutoCreateClusterConfigurationFilesResponse {
    repeated ConfigurationFile files = 1;
}

message GetClusterConfigurationFileRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string configuration_filename = 3;
}

message ListClusterConfigurationFilesRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    optional string configuration_type_filter = 3;
    optional string belong_to_component_filter = 4;
}

message ListClusterConfigurationFilesResponse {
    repeated ConfigurationFile files = 1;
}

message UpsertClusterCustomParamsRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string configuration_filename = 3;

    // params to be inserted or updated
    map<string, ParamItem> upserted_params = 4;
    // bool validate_only = 5;
}

message BatchUpsertClusterCustomParamsRequest {
    repeated UpsertClusterCustomParamsRequest requests = 1;
}

message BatchUpsertClusterCustomParamsResponse {
    repeated ConfigurationFile files = 1;
}

message FromSKU {
    string version = 1;
    string cloud_provider = 2;
    string node_instance = 3;
    uint64 tenant_id = 4;
}

message FromTemplate{
    int64 template_id = 1;
}

message FromTenant{
    uint64 tenant_id = 1;
}

message FromInputValues{
    map<string,ParamItem> custom_params = 1;
}


message CreateClusterConfigFileRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string configuration_filename = 3;

    string configuration_type = 4;
    Format format = 5;
    optional string belong_to_component = 6;
    // string config_version = 7;

    oneof system_template_source {
        FromSKU from_sku = 8;
        FromTemplate from_template = 9;
    }

    // could be empty if inside InitClusterMeta
    oneof custom_params_source {
        FromInputValues from_input_values = 10;
        FromTenant from_tenant = 11;
        FromTemplate from_custom_template = 12;
    }

    bool validate_only = 13;
}

message UpdateClusterConfigurationFileRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string configuration_filename = 3;

    optional string configuration_type = 9;
    optional string belong_to_component = 10;
    optional Format format = 4;
    // specify (system)template_id instead of map from node_instance and version
    optional int64 template_id = 5;

    // optional string version_for_config = 13; todo

    // All custom params should be set, not only the changed ones. Use nil/empty to remain unchanged.
    map<string,ParamItem> custom_params = 6;
    // Used to clear custom_params, custom_params in the request should be nil/empty.
    bool clear_custom_params = 12;

    bool allow_missing = 7;
    optional string previous_text = 8;
    bool validate_only = 11;
}

message BatchUpdateClusterConfigurationFilesRequest {
    ClusterType cluster_type = 3;
    repeated UpdateClusterConfigurationFileRequest requests = 1;
    bool validate_only = 2;
}

message BatchUpdateClusterConfigurationFilesResponse {
    repeated ConfigurationFile files = 1;
}

message AutoUpdateClusterConfigurationFileRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string configuration_filename = 3;

    optional string configuration_type = 10; // required if file does not exists, optional to update existing configuration file
    optional string belong_to_component = 11; // required if file does not exists, optional to update existing configuration file
    optional Format format = 4; // required if file does not exists, optional to update existing configuration file
    string version = 5;
    string cloud_provider = 6;
    string node_instance = 7;
    optional uint64 tenant_id = 8; // tenant_id is only used to generate custom_params if the configuration file does not exist

    optional string previous_text = 9;
}

message BatchAutoUpdateClusterConfigurationFilesRequest {
    ClusterType cluster_type = 2;
    repeated AutoUpdateClusterConfigurationFileRequest requests = 1;
}

message BatchAutoUpdateClusterConfigurationFilesResponse {
    repeated ConfigurationFile files = 1;
}

message DeleteClusterConfigurationFileRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string configuration_filename = 3;
}

message BatchDeleteClusterConfigurationFilesRequest {
    repeated DeleteClusterConfigurationFileRequest requests = 1;
}

message DeleteConfigurationTemplateRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    int64 template_id = 3;
}

message CreateConfigurationTemplateRequest {
    ClusterType cluster_type = 1;
    optional int64 template_id = 5;
    string configuration_type = 2;
    string template_name = 3;
    map<string,ParamItem> data = 4;
    map<string,string> tags = 6;
}

message BatchCreateConfigurationTemplatesRequest {
    repeated CreateConfigurationTemplateRequest requests = 1;
}

message BatchCreateConfigurationTemplatesResponse {
    repeated ConfigurationTemplate templates = 1;
}

message GetConfigurationTemplateRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    int64 template_id = 3;
}

message ListConfigurationTemplatesRequest {
    ClusterType cluster_type = 1;
    optional string config_type = 2;
    map<string,string> tags = 3;
}

message ListConfigurationTemplatesResponse {
    repeated ConfigurationTemplate templates = 1;
}

message SearchDefaultConfigurationTemplateRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    string version = 3;
    string cloud_provider = 4;
    string node_instance = 5;
    optional string region = 6; // internal use, please ignore.
    string tenant_id = 7;
}

message BatchSearchDefaultConfigurationTemplateRequest {
    repeated SearchDefaultConfigurationTemplateRequest requests = 1;
}

message BatchSearchDefaultConfigurationTemplateResponse {
    repeated ConfigurationTemplate templates = 1;
}

message TemplateDefaultCaseBinding {
    ClusterType cluster_type = 1;
    DefaultCase default_case = 2;
    int64 template_id = 3;
}

message ListConfigurationTemplateDefaultCaseBindingsRequest {
    ClusterType cluster_type = 1;
    // configuration_type filter,use empty("") to show all
    string configuration_type = 2;
    // version filter empty(""),use to show all
    string version = 3;
    // cloud_provider filter,use empty("") to show all
    string cloud_provider = 4;
    // node_instance filter,use empty("") to show all
    string node_instance = 5;
    // tenant_id filter,use empty("") to show all
    string tenant_id = 8;
    // exact_match means won't match 'any' value except the specified ones
    bool exact_match = 9;
    // The maximum value of page_size is 200; values above 200 will be coerced to 200.
    int32 page_size = 6;
    int32 page_num = 7;
}

message ListConfigurationTemplateDefaultCaseBindingsResponse {
    repeated TemplateDefaultCaseBinding template_default_case_bindings = 1;
    int64 total = 2;
}

message UpdateDefaultConfigurationTemplateRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    string version = 3;
    // cloud_provider cannot be empty if node_instance is not empty
    string cloud_provider = 4;
    // node_instance could be empty to update default config for all instance except which already has specific binding
    string node_instance = 5;
    // only update in the specified regions if not empty
    repeated string regions = 7;
    string tenant_id = 8;

    int64 template_id = 6;
}

message DeleteDefaultConfigurationTemplateRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    string version = 3;
    string cloud_provider = 4;
    string node_instance = 5;
    repeated string regions = 6;
    string tenant_id = 7;
    int64 template_id = 8;
}

message BatchUpdateDefaultConfigurationTemplateRequest {
    repeated UpdateDefaultConfigurationTemplateRequest requests = 1;
}

message BatchUpdateDefaultConfigurationTemplateResponse {
    repeated ConfigurationTemplate templates = 1;
}

message GetTemplateUsageRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    int64 template_id = 3;
}

message DefaultCase {
    string version = 1;
    string cloud_provider = 2;
    string node_instance = 3;
    string configuration_type = 4;
    string region = 5;
    string tenant_id = 6;
}

message TemplateUsage {
    repeated string cluster_ids = 1;
    repeated DefaultCase default_cases = 2;
}

message MetaProfile {
    ClusterType cluster_type = 1;
    int64 profile_id = 2;
    string profile_name = 3;
    string description = 4;
    map<string,string> tags = 5;
    //string cluster_version = 6;
    map<string,string> component_image_tags = 7;
    map<string,int64> config_custom_templates = 8;
    map<string,string> component_versions = 9;
}

message CreateMetaProfileRequest {
    ClusterType cluster_type = 1;
    optional int64 profile_id = 2;
    string profile_name = 3;
    string description = 4;
    map <string,string> tags = 5;
    map<string,string> component_image_tags = 6;
    map<string,int64> config_custom_templates = 7;
    map<string,string> component_versions = 8;
}

message GetMetaProfileRequest {
    ClusterType cluster_type = 1;
    int64 profile_id = 2;
}

message ListMetaProfilesRequest {
    ClusterType cluster_type = 1;
    map<string,string> tags = 2;
    optional uint64 tenant_id = 3;
    optional string profile_name = 4;
    int32 page_size = 5;
    int32 page = 6;
}

message ListMetaProfilesResponse {
    repeated MetaProfile profiles = 1;
    int64 total = 2;
}

message DeleteMetaProfileRequest {
    ClusterType cluster_type = 1;
    int64 profile_id = 2;
}

message TenantInitialCustomPatams {
    ClusterType cluster_type = 3;
    string configuration_type = 2;
    map<string,ParamItem> initial_params = 1;
}

message GetTenantInitialCustomParamsRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    uint64 tenant_id = 3;
}

message ListTenantInitialCustomParamsRequest {
    ClusterType cluster_type = 1;
    uint64 tenant_id = 2;
}

message ListTenantInitialCustomParamsResponse {
    repeated TenantInitialCustomPatams tenant_initial_custom_params = 1;
}

message UpdateTenantInitialCustomParamsRequest {
    ClusterType cluster_type = 1;
    string configuration_type = 2;
    uint64 tenant_id = 3;
    map<string,ParamItem> initial_params = 4;
}

message BatchUpdateTenantInitialCustomParamsRequest {
    ClusterType cluster_type = 2;
    uint64 tenant_id = 3;
    repeated UpdateTenantInitialCustomParamsRequest requests = 1;
}

message BatchUpdateTenantInitialCustomParamsResponse {
    repeated TenantInitialCustomPatams tenant_initial_custom_params = 1;
}

message CopyConfigurationDictFromOldVersionRequest {
    string from_version = 1;
    string to_version = 2;
}

enum ConfigParamType {
    unknown = 0;
    int = 1;
    string = 2;
    bool = 3;
    float = 4;
    json = 5;
}

message ConfigurationDictItem {
    ClusterType cluster_type = 12;
    string configuration_type = 1;
    string version = 2;
    string param_key = 3;
    google.protobuf.Value default_value = 4;
    ConfigParamType type= 5;
    // optional string verify_expr = 6;
    optional bool hot_reloadable = 7;
    optional string description = 8;
    optional bool need_template = 9;
    string validation = 10;
    string risk_level = 11;
    string updated_by = 13;
    // AIP-148/AIP-164 compliant timestamp fields
    google.protobuf.Timestamp create_time = 14 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp update_time = 15 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp delete_time = 16 [(google.api.field_behavior) = OUTPUT_ONLY];
}

message UpdateConfigurationDictItemReq {
    ClusterType cluster_type = 12;
    string configuration_type = 1;
    string version = 2;
    string param_key = 3;
    optional google.protobuf.Value default_value = 4;
    // ConfigParamType type= 5;
    // optional string verify_expr = 6;
    optional bool hot_reloadable = 7;
    optional string description = 8;
    // optional bool need_template = 9;
    optional string validation = 10;
    optional string risk_level = 11;
    string updated_by = 13;
}

message RemoveOneVersionDictItemsReq {
    ClusterType cluster_type = 2;
    string version = 1;
}

message BatchCreateConfigurationDictRequest {
    repeated ConfigurationDictItem configuration_dict_items = 1;
}

message BatchCreateConfigurationDictResponse {
    repeated ConfigurationDictItem configuration_dict_items = 1;
}

message GetConfigurationDictItemRequest {
    ClusterType cluster_type = 5;
    string configuration_type = 1;
    string param_key = 2;
    string version = 3;
    bool match_partial_version = 4;
}

message ListConfigurationDictItemsRequest {
    ClusterType cluster_type = 8;
    optional string configuration_type = 1;

    // Filter
    optional string version = 2;
    optional string param_key_like = 3;
    repeated string param_key_in = 4;
    bool match_partial_version = 7;

    int64 page = 5;
    int64 page_size = 6;
}

message ListConfigurationDictItemsResponse {
    repeated ConfigurationDictItem configuration_dict_items = 1;

    int64 current = 2;
    int64 total = 3;
}

message ListConfigurationDictVersionsRequest {
    ClusterType cluster_type = 2;
    string config_type = 1;
}

message ListConfigurationDictVersionsResponse {
    repeated string versions = 1;
}

message PurgeDictItemsRequest {
    ClusterType cluster_type = 1;
    string config_type = 2;
    optional string version = 3;

    // Actually perform the purge.
    bool force = 4;
}

message PurgeDictItemsResponse {
    int64 purge_count = 1;
}

// deprecated
message ComponentImage {
    string component_name = 3;
    string version = 4;
    string base_image = 1;
    string tag = 2;
    bool general_availability = 5;
}

message ClusterComponent {
    ClusterType cluster_type = 8;
    string cluster_id = 13;
    string component_name = 1;
    string version = 2;
    string cloud_provider = 3;
    string node_instance = 4;
    string overwrite_image_tag = 5;
    string base_image = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
    string effective_image_tag = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
    UpdateStrategy update_strategy = 9;
    // AIP-148/AIP-164 compliant timestamp fields
    google.protobuf.Timestamp create_time = 10 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp update_time = 11 [(google.api.field_behavior) = OUTPUT_ONLY];
    google.protobuf.Timestamp delete_time = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
}

message CreateClusterComponentRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string component_name = 3;

    string version = 4;
    string cloud_provider = 91; // todo: move to configfile resource
    string node_instance = 92; // todo: move to configfile resource
    // it is suggested to always set overwrite_image_tag to "" explicitly to unset the old value, unless it is expected that final image_tag may be unchanged
    optional string overwrite_image_tag = 5;
    optional UpdateStrategy update_strategy = 6;
    bool validate_only = 7;
    optional uint64 tenant_id = 8;
}

message GetClusterComponentRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string component_name = 3;
}

message ListClusterComponentsRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
}

message ListClusterComponentsResponse {
    repeated ClusterComponent components = 1;
}

message SearchClusterComponentsRequest {
    ClusterType cluster_type = 1 [(google.api.field_behavior) = REQUIRED];
    string component_name = 2;
    repeated string cluster_ids = 3;
    string component_version = 4;
    string image_tag = 5;
    int32 page_size = 6;
    int32 page = 7;
    optional string logical_region = 8;
    bool show_deleted = 9;
}

message SearchClusterComponentsResponse {
    repeated ClusterComponent components = 1;
    int64 total = 2;
}

message UpdateClusterComponentRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    string component_name = 3;
    optional string version = 4;
    optional string cloud_provider = 5;
    optional string node_instance = 6;
    // it is suggested to always set overwrite_image_tag to "" explicitly to unset the old value, unless it is expected that final image_tag may be unchanged
    optional string overwrite_image_tag = 7;
    optional UpdateStrategy update_strategy = 11;
    // create component if not exists, version,cloud_provider,node_instance are required in this case
    bool update_related_configuration_files = 10;
    bool allow_missing = 8;
    bool validate_only = 9;
    optional uint64 tenant_id = 12;
}

message BatchUpdateClusterComponentsRequest {
    ClusterType cluster_type = 3;
    repeated UpdateClusterComponentRequest requests = 1;
    bool validate_only = 2;
}

message BatchUpdateClusterComponentsResponse {
    repeated ClusterComponent components = 1;
}

message GetComponentImageRequest {
    ClusterType cluster_type = 1;
    string component_name = 2;
    string component_version = 3;
    optional uint64 tenant_id = 4;
    //optional string cluster_id = 5;
}

message UpdateComponentImageRequest {
    ClusterType cluster_type = 1;
    string component_name = 2;
    string component_version = 3;
    optional uint64 tenant_id = 4;
    //optional string cluster_id = 5;

    string base_image = 6;
    string tag = 7;
}

message ListComponentImagesRequest {
    ClusterType cluster_type = 1;
    string component_name = 2;
    optional string version = 3;
    optional uint64 tenant_id = 4;
}

message ListComponentImagesResponse {
    repeated ComponentImage images = 1;
}

message DefaultVersion {
    string version = 1;
    // one of "global", "tenant"
    string source = 2;
}

message GetDefaultVersionRequest {
    ClusterType cluster_type = 1;
    string component = 2;
    // cluster_version is used only for DM now, map cluster version to dm version
    optional string cluster_version = 6;
    optional string cloud_provider = 3;
    optional string region = 4;
    optional uint64 tenant_id = 5;
}

message UpdateDefaultVersionRequest {
    ClusterType cluster_type = 1;
    string component = 2;
    // cluster_version is used only for DM now, map cluster version to dm version
    optional string cluster_version = 7;
    optional string cloud_provider = 3;
    // The region must be specified along with the cloud_provider.
    optional string region = 4;
    // When the tenant_id is specified, the cloud_provider and region will be ignored.
    optional uint64 tenant_id = 5;

    string version = 6;
}

message DeleteDefaultVersionRequest {
    ClusterType cluster_type = 1;
    string component = 2;
    // cluster_version is used only for DM now, map cluster version to dm version
    optional string cluster_version = 6;
    optional string cloud_provider = 3;
    optional string region = 4;
    optional uint64 tenant_id = 5;
}

message DefaultVersionRule {
    ClusterType cluster_type = 1;
    string component = 2;
    string cluster_version = 3; // empty means any version
    string cloud_provider = 4; // empty means any cloud_provider
    // The region must be specified along with the cloud_provider.
    string region = 5; // empty means any region of the cloud_provider
    // optional uint64 tenant_id = 6;

    string version = 7; // the target version
}

message ListDefaultVersionRulesRequest {
    ClusterType cluster_type = 1;
    optional string component = 2;
    optional uint64 tenant_id = 3;
}

message ListDefaultVersionRulesResponse {
    repeated DefaultVersionRule rules = 1;
}

message GetClusterMetaRequest {
    ClusterType cluster_type = 1;
    optional string logical_region = 4;
    string cluster_id = 2;
    string main_component = 3; // version of main component will be treated as cluster version
}

message DeleteClusterMetaRequest {
    ClusterType cluster_type = 1;
    optional string logical_region = 3;
    string cluster_id = 2;
}

message BatchDeleteClusterMetaRequest {
    ClusterType cluster_type = 1;
    optional string logical_region = 2;
    repeated string cluster_ids = 3;
}

message ClusterMeta {
    string version = 3;
    repeated ClusterComponent components = 1;
    repeated ConfigurationFile configuration_files = 2;
}

// InitClusterMeta is used to Create ClusterMeta from 0, or add new components/config to existing cluster
message InitClusterMetaRequest {
    ClusterType cluster_type = 1;
    string cluster_id = 2;
    // use values from meta profile to overwrite "overwrite_image_tag" and "custom_params_source" for related components/configFiles
    optional int64 meta_profile_id = 5;
    repeated CreateClusterComponentRequest components = 3;
    repeated CreateClusterConfigFileRequest configuration_files = 4;
    bool validate_only = 6;
}

message UpdateClusterMetaRequest {
    ClusterType cluster_type = 1; // will auto fill blank cluster_type field in component_requests and configuration_file_requests
    optional string logical_region = 7;
    string cluster_id = 2; // will auto fill blank cluster_id field in component_requests and configuration_file_requests
    optional string version = 3; // will auto fill blank version field in component_requests (not configuration_file_requests) if not null
    repeated UpdateClusterComponentRequest component_requests = 4; // only selected components will be updated
    repeated UpdateClusterConfigurationFileRequest configuration_file_requests = 5; // only selected configuration files will be updated
    bool validate_only = 6;
}

message UpdateClusterMetaResponse {
    repeated ClusterComponent modified_components = 1;
    repeated ConfigurationFile modified_configuration_files = 2;
}

message AutoUpdateClusterMetaRequest {
    ClusterType cluster_type = 1; // will auto fill blank cluster_type field in component_requests and configuration_file_requests
    optional string logical_region = 6;
    string cluster_id = 2; // will auto fill blank cluster_id field in component_requests and configuration_file_requests
    optional string version = 3; // will auto fill blank version field in component_requests and configuration_file_requests if not null
    repeated UpdateClusterComponentRequest component_requests = 4; // only selected components will be updated
    repeated AutoUpdateClusterConfigurationFileRequest configuration_file_requests = 5; // only selected configuration files will be updated
}

message AutoUpdateClusterMetaResponse {
    repeated ClusterComponent modified_components = 1;
    repeated ConfigurationFile modified_configuration_files = 2;
}

message ListAvailableVersionsRequest {
    ClusterType cluster_type = 1;
    string component = 2;
}

message ListAvailableVersionsResponse {
    repeated string versions = 1;
}

message ListAvailableInstancesRequest {
    ClusterType cluster_type = 1;
    optional string version = 2;
    optional string config_type = 3;
}

message UniqueInstance {
    string cloud_provider = 1;
    string node_instance = 2;
}

message ListAvailableInstancesResponse {
    repeated UniqueInstance instances = 1;
}

message RegisterRegionalServerRequest {
    ClusterType cluster_type = 1;
    string logical_region = 2;
    string server_address = 3;
    optional bool is_byoc = 4;
}

message ListRegionalServersRequest {
    ClusterType cluster_type = 1;
}

message ListRegionalServersResponse {
    repeated RegionalServer servers = 1;
}

message OfflineRegionalServerRequest {
    ClusterType cluster_type = 1;
    string logical_region = 2;
}

message GetRegionalServerRequest {
    ClusterType cluster_type = 1;
    string logical_region = 2;
}

message SyncRegionalServerRequest {
    ClusterType cluster_type = 1;
    string logical_region = 2;
}

message RegionalServer {
    ClusterType cluster_type = 1;
    string logical_region = 2;
    string server_address = 3;
    string sync_status = 4;
}

// ConfigCenterService is the service to manage cluster configurations and component images
service ConfigCenterService {
    // create a configuration file with given templateID and custom params, won't auto fill any params
    rpc CreateClusterConfigurationFile(CreateClusterConfigurationFileRequest) returns (ConfigurationFile) {}
    // create configuration files with given templateID and custom params, won't auto fill any params
    rpc BatchCreateClusterConfigurationFiles(BatchCreateClusterConfigurationFilesRequest) returns (BatchCreateClusterConfigurationFilesResponse) {}
    // create a configuration file automatically, will auto fill tenant related params to custom_params, auto fill suitable template by version and node_instance 
    // rpc AutoCreateClusterConfigurationFile(AutoCreateClusterConfigurationFileRequest) returns (ConfigurationFile) {}
    // rpc BatchAutoCreateClusterConfigurationFiles(BatchAutoCreateClusterConfigurationFilesRequest) returns (BatchAutoCreateClusterConfigurationFilesResponse) {}
    rpc GetClusterConfigurationFile(GetClusterConfigurationFileRequest) returns (ConfigurationFile) {}
    rpc ListClusterConfigurationFiles(ListClusterConfigurationFilesRequest) returns (ListClusterConfigurationFilesResponse) {}
    rpc UpsertClusterCustomParams(UpsertClusterCustomParamsRequest) returns (ConfigurationFile) {}
    rpc BatchUpsertClusterCustomParams(BatchUpsertClusterCustomParamsRequest) returns (BatchUpsertClusterCustomParamsResponse) {}
    rpc UpdateClusterConfigurationFile(UpdateClusterConfigurationFileRequest) returns (ConfigurationFile) {}
    rpc BatchUpdateClusterConfigurationFiles(BatchUpdateClusterConfigurationFilesRequest) returns (BatchUpdateClusterConfigurationFilesResponse) {}
    // euqal to 1.SearchDefaultConfigurationTemplate as template_id 2.GetTenantInitialCustomParams as custom_params 3.UpdateClusterConfigurationFile with allow_missing=true
    rpc AutoUpdateClusterConfigurationFile(AutoUpdateClusterConfigurationFileRequest) returns (ConfigurationFile) {}
    rpc BatchAutoUpdateClusterConfigurationFiles(BatchAutoUpdateClusterConfigurationFilesRequest) returns (BatchAutoUpdateClusterConfigurationFilesResponse) {}
    rpc DeleteClusterConfigurationFile(DeleteClusterConfigurationFileRequest) returns (google.protobuf.Empty) {}
    rpc BatchDeleteClusterConfigurationFiles(BatchDeleteClusterConfigurationFilesRequest) returns (google.protobuf.Empty) {}

    rpc CreateConfigurationTemplate(CreateConfigurationTemplateRequest) returns (ConfigurationTemplate) {
        option (google.api.http) = {
            post: "/config-center/cluster-types/{cluster_type}/templates"
            body: "*"
        };
    }
    rpc BatchCreateConfigurationTemplates(BatchCreateConfigurationTemplatesRequest) returns (BatchCreateConfigurationTemplatesResponse) {}
    rpc GetConfigurationTemplate(GetConfigurationTemplateRequest) returns (ConfigurationTemplate) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/templates/{template_id}"
        };
    }
    rpc ListConfigurationTemplates(ListConfigurationTemplatesRequest) returns (ListConfigurationTemplatesResponse) {}
    rpc DeleteConfigurationTemplate(DeleteConfigurationTemplateRequest) returns (google.protobuf.Empty) {}
    rpc SearchDefaultConfigurationTemplate(SearchDefaultConfigurationTemplateRequest) returns (ConfigurationTemplate) {}
    rpc BatchSearchDefaultConfigurationTemplate(BatchSearchDefaultConfigurationTemplateRequest) returns (BatchSearchDefaultConfigurationTemplateResponse) {}
    rpc ListConfigurationTemplateDefaultCaseBindings(ListConfigurationTemplateDefaultCaseBindingsRequest) returns (ListConfigurationTemplateDefaultCaseBindingsResponse) {}
    rpc UpdateDefaultConfigurationTemplate(UpdateDefaultConfigurationTemplateRequest) returns (ConfigurationTemplate) {
        option (google.api.http) = {
            put: "/config-center/cluster-types/{cluster_type}/templates/{template_id}/default"
            body: "*"
        };
    }
    rpc DeleteDefaultConfigurationTemplate(DeleteDefaultConfigurationTemplateRequest) returns (google.protobuf.Empty) {
        option (google.api.http) = {
            post: "/config-center/cluster-types/{cluster_type}/templates/{template_id}/default:delete"
            body: "*"
        };
    }
    rpc BatchUpdateDefaultConfigurationTemplate(BatchUpdateDefaultConfigurationTemplateRequest) returns (BatchUpdateDefaultConfigurationTemplateResponse) {}
    rpc GetTemplateUsage(GetTemplateUsageRequest) returns (TemplateUsage) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/templates/{template_id}/usage"
        };
    }

    rpc CreateMetaProfile(CreateMetaProfileRequest) returns (MetaProfile) {}
    rpc GetMetaProfile(GetMetaProfileRequest) returns (MetaProfile) {}
    rpc ListMetaProfiles(ListMetaProfilesRequest) returns (ListMetaProfilesResponse) {}
    rpc DeleteMetaProfile(DeleteMetaProfileRequest) returns (google.protobuf.Empty) {}

    rpc GetTenantInitialCustomParams(GetTenantInitialCustomParamsRequest) returns (TenantInitialCustomPatams) {}
    rpc ListTenantInitialCustomParams(ListTenantInitialCustomParamsRequest) returns (ListTenantInitialCustomParamsResponse) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/tenants/{tenant_id}/initial-custom-params"
        };
    }
    rpc UpdateTenantInitialCustomParams(UpdateTenantInitialCustomParamsRequest) returns (TenantInitialCustomPatams) {}
    rpc BatchUpdateTenantInitialCustomParams(BatchUpdateTenantInitialCustomParamsRequest) returns (BatchUpdateTenantInitialCustomParamsResponse) {
        option (google.api.http) = {
            patch: "/config-center/cluster-types/{cluster_type}/tenants/{tenant_id}/initial-custom-params:batchUpdate"
            body: "*"
        };
    }

    // param_dict related
    rpc CopyConfigurationDictFromOldVersion(CopyConfigurationDictFromOldVersionRequest) returns (google.protobuf.Empty) {}
    rpc BatchCreateConfigurationDictItems(BatchCreateConfigurationDictRequest) returns (BatchCreateConfigurationDictResponse) {}
    rpc GetConfigurationDictItem(GetConfigurationDictItemRequest) returns (ConfigurationDictItem) {}
    rpc ListConfigurationDictItems(ListConfigurationDictItemsRequest) returns (ListConfigurationDictItemsResponse) {}
    rpc ListConfigurationDictVersions(ListConfigurationDictVersionsRequest) returns (ListConfigurationDictVersionsResponse) {}
    rpc UpdateConfigurationDictItem(UpdateConfigurationDictItemReq) returns (ConfigurationDictItem) {}
    rpc PurgeDictItems(PurgeDictItemsRequest) returns (PurgeDictItemsResponse) {}

    // not deprecated now, used by ops and dataflow/cdc
    rpc GetComponentImage(GetComponentImageRequest) returns (ComponentImage) {}
    // only ops portal can use this api
    rpc UpdateComponentImage(UpdateComponentImageRequest) returns (ComponentImage) {
        option (google.api.http) = {
            put: "/config-center/cluster-types/{cluster_type}/component-images/{component_name}"
            body: "*"
        };
    }
    rpc ListComponentImages(ListComponentImagesRequest) returns (ListComponentImagesResponse) {}

    rpc GetClusterComponent(GetClusterComponentRequest) returns (ClusterComponent) {}
    rpc ListClusterComponents(ListClusterComponentsRequest) returns (ListClusterComponentsResponse) {}
    rpc SearchClusterComponents(SearchClusterComponentsRequest) returns (SearchClusterComponentsResponse) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/cluster-components:search"
        };
    }
    rpc UpdateClusterComponent(UpdateClusterComponentRequest) returns (ClusterComponent) {}
    rpc BatchUpdateClusterComponents(BatchUpdateClusterComponentsRequest) returns (BatchUpdateClusterComponentsResponse) {}

    // InitClusterMeta or append new component/configFile. Only create never update. Only return created components/configFiles
    rpc InitClusterMeta(InitClusterMetaRequest) returns (ClusterMeta) {}
    // GetClusterMeta returns components and configurationFiles, will return NotFound error if components number is 0
    rpc GetClusterMeta(GetClusterMetaRequest) returns (ClusterMeta) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/clusters/{cluster_id}/meta"
        };
    }
    rpc DeleteClusterMeta(DeleteClusterMetaRequest) returns (google.protobuf.Empty) {
        option (google.api.http) = {
            delete: "/config-center/cluster-types/{cluster_type}/clusters/{cluster_id}/meta"
        };
    }
    rpc BatchDeleteClusterMeta(BatchDeleteClusterMetaRequest) returns (google.protobuf.Empty) {
        option (google.api.http) = {
            post: "/config-center/cluster-types/{cluster_type}/clusters/meta:batchDelete"
            body: "*"
        };
    }
    // update version to gerneate new image tags, update configuration files manually
    rpc UpdateClusterMeta(UpdateClusterMetaRequest) returns (UpdateClusterMetaResponse) {
        option (google.api.http) = {
            patch: "/config-center/cluster-types/{cluster_type}/clusters/{cluster_id}/meta"
            body: "*"
        };
    }
    // update version to gerneate new image tags and configuration files automatically
    rpc AutoUpdateClusterMeta(AutoUpdateClusterMetaRequest) returns (AutoUpdateClusterMetaResponse) {
        option (google.api.http) = {
            patch: "/config-center/cluster-types/{cluster_type}/clusters/{cluster_id}/meta:autoUpdate"
            body: "*"
        };
    }

    rpc ListAvailableVersions(ListAvailableVersionsRequest) returns (ListAvailableVersionsResponse) {}
    rpc ListAvailableInstances(ListAvailableInstancesRequest) returns (ListAvailableInstancesResponse) {}

    // GetDefaultVersion exists for gitops compatibility, it is recommended to let user(or upper-layer service to choose version from AvailableVersions instead
    rpc GetDefaultVersion(GetDefaultVersionRequest) returns (DefaultVersion) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/default-version"
        };
    }
    rpc UpdateDefaultVersion(UpdateDefaultVersionRequest) returns (DefaultVersion) {
        option (google.api.http) = {
            put: "/config-center/cluster-types/{cluster_type}/default-version"
            body: "*"
        };
    }
    rpc DeleteDefaultVersion(DeleteDefaultVersionRequest) returns (google.protobuf.Empty) {
        option (google.api.http) = {
            delete: "/config-center/cluster-types/{cluster_type}/default-version"
        };
    }
    rpc ListDefaultVersionRules(ListDefaultVersionRulesRequest) returns (ListDefaultVersionRulesResponse) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/default-version-rules"
        };
    }

    rpc RegisterRegionalServer(RegisterRegionalServerRequest) returns (RegionalServer) {
        option (google.api.http) = {
            post: "/config-center/cluster-types/{cluster_type}/regional-servers"
            body: "*"
            additional_bindings {
                post: "/inner/config-center/cluster-types/{cluster_type}/regional-servers"
                body: "*"
            }
        };
    }

    rpc ListRegionalServers(ListRegionalServersRequest) returns (ListRegionalServersResponse) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/regional-servers"
            additional_bindings {
                get: "/inner/config-center/cluster-types/{cluster_type}/regional-servers"
            }
        };
    }

    rpc GetRegionalServer(GetRegionalServerRequest) returns (RegionalServer) {
        option (google.api.http) = {
            get: "/config-center/cluster-types/{cluster_type}/regional-servers/{logical_region}"
            additional_bindings {
                get: "/inner/config-center/cluster-types/{cluster_type}/regional-servers/{logical_region}"
            }
        };
    }

    rpc OfflineRegionalServer(OfflineRegionalServerRequest) returns (google.protobuf.Empty) {
        option (google.api.http) = {
            delete: "/config-center/cluster-types/{cluster_type}/regional-servers/{logical_region}"
            additional_bindings {
                delete: "/inner/config-center/cluster-types/{cluster_type}/regional-servers/{logical_region}"
            }
        };
    }

    rpc SyncRegionalServer(SyncRegionalServerRequest) returns (RegionalServer) {
        option (google.api.http) = {
            post: "/config-center/cluster-types/{cluster_type}/regional-servers/{logical_region}/sync"
            additional_bindings {
                post: "/inner/config-center/cluster-types/{cluster_type}/regional-servers/{logical_region}/sync"
            }
        };
    }
}
