/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * These .proto interfaces are private and unstable.
 * Please see http://wiki.apache.org/hadoop/Compatibility
 * for what changes are allowed for an *unstable* .proto interface.
 */
syntax = "proto2";
option java_package = "org.apache.hadoop.hdds.protocol.proto";
option java_outer_classname = "HddsProtos";
option java_generic_services = true;
option java_generate_equals_and_hash = true;
package hadoop.hdds;

message UUID {
   required int64 mostSigBits = 1;
   required int64 leastSigBits = 2;
}

message DatanodeIDProto {
    required UUID uuid = 1;
}

message DatanodeDetailsProto {
    // deprecated, please use DatanodeIDProto instead
    optional string uuid = 1;  // UUID assigned to the Datanode.
    required string ipAddress = 2;     // IP address
    required string hostName = 3;      // hostname
    repeated Port ports = 4;
    optional string certSerialId = 5;   // Certificate serial id.
    // network name, can be Ip address or host name, depends
    optional string networkName = 6;
    optional string networkLocation = 7; // Network topology location
    optional NodeOperationalState persistedOpState = 8; // The Operational state persisted in the datanode.id file
    optional int64 persistedOpStateExpiry = 9; // The seconds after the epoch when the OpState should expire
    optional int32 currentVersion = 10;  // Current datanode wire version
    // TODO(runzhiwang): when uuid is gone, specify 1 as the index of uuid128 and mark as required
    optional UUID uuid128 = 100; // UUID with 128 bits assigned to the Datanode.
    optional uint32 level = 101;
    // TODO: Replace UUID with DatanodeID and  make it required
    optional DatanodeIDProto id = 102;
}

/**
 The DatanodeDetailsProto is a basic type that will be shared by many Proto,
 to reduce the number of fields transferred by ProtoBuf, only need to extend
 DatanodeDetailsProto for registering DataNode with SCM and Recon.
*/
message ExtendedDatanodeDetailsProto {
    required DatanodeDetailsProto datanodeDetails = 1;
    optional string version = 2;
    optional int64 setupTime = 3;
    optional string revision = 4;
    optional string buildDate = 5; // unused, reserved for compatibility
}

message MoveDataNodePairProto {
    required DatanodeDetailsProto src = 1;
    required DatanodeDetailsProto tgt = 2;
}

/**
 Proto message encapsulating information required to uniquely identify a
 OzoneManager.
*/
message OzoneManagerDetailsProto {
    required string uuid = 1;          // UUID assigned to the OzoneManager.
    required string ipAddress = 2;     // IP address of OM.
    required string hostName = 3;      // Hostname of OM.
    repeated Port ports = 4;
}

message ScmNodeDetailsProto {
    required string scmNodeId = 1;     // SCM Node Id.
    required string clusterId = 2;     // Cluster Id of SCM cluster.
    required string hostName = 3;      // Hostname of SCM.
}

message NodeDetailsProto {
    required string uuid = 1;
    required string clusterId = 2;
    required string hostName = 3;
    required NodeType nodeType = 4;
}

message Port {
    required string name = 1;
    required uint32 value = 2;
}

message PipelineID {
  // deprecated, please use uuid128 instead
  optional string id = 1;
  // TODO(runzhiwang): when id is gone, specify 1 as the index of uuid128 and mark as required
  optional UUID uuid128 = 100;
}

message ContainerID {
    required uint64 id = 1;
}

enum PipelineState {
    PIPELINE_ALLOCATED = 1;
    PIPELINE_OPEN = 2;
    PIPELINE_DORMANT = 3;
    PIPELINE_CLOSED = 4;
}

message Pipeline {
    repeated DatanodeDetailsProto members = 1;
    // TODO: remove the state and leaderID from this class
    optional PipelineState state = 2 [default = PIPELINE_ALLOCATED];
    optional ReplicationType type = 3 [default = STAND_ALONE];
    optional ReplicationFactor factor = 4 [default = ONE];
    required PipelineID id = 5;
    // TODO: Deprecate this and replace with leaderDatanodeID
    optional string leaderID = 6;
    repeated uint32 memberOrders = 7;
    optional uint64 creationTimeStamp = 8;
    // TODO: Deprecate this and replace with suggestedLeaderDatanodeID
    optional UUID suggestedLeaderID = 9;
    repeated uint32 memberReplicaIndexes = 10;
    optional ECReplicationConfig ecReplicationConfig = 11;

    // TODO: Replace UUID with DatanodeIDProto
    optional UUID leaderID128 = 100;

    optional DatanodeIDProto leaderDatanodeID = 101;
    optional DatanodeIDProto suggestedLeaderDatanodeID = 102;
}

message KeyValue {
    required string key = 1;
    optional string value = 2;
}

/**
 * Types of storage media.
 */
enum StorageTypeProto {
  DISK = 1;
  SSD = 2;
  ARCHIVE = 3;
  RAM_DISK = 4;
  PROVIDED = 5;
}

/**
 * Type of the node.
 */
enum NodeType {
    OM = 1;         // Ozone Manager
    SCM = 2;        // Storage Container Manager
    DATANODE = 3;   // DataNode
    RECON = 4;      // Recon
}

// Should we rename NodeState to DatanodeState?
/**
 * Enum that represents the Node State. This is used in calls to getNodeList
 * and getNodeCount.
 */
enum NodeState {
    HEALTHY = 1;
    STALE = 2;
    DEAD = 3;
    HEALTHY_READONLY = 6;
}

enum NodeOperationalState {
    IN_SERVICE = 1;
    ENTERING_MAINTENANCE = 2;
    IN_MAINTENANCE = 3;
    DECOMMISSIONING = 4;
    DECOMMISSIONED = 5;
}

enum QueryScope {
    CLUSTER = 1;
    POOL = 2;
}

message Node {
    required DatanodeDetailsProto nodeID = 1;
    repeated NodeState nodeStates = 2;
    repeated NodeOperationalState nodeOperationalStates = 3;
    optional int32 totalVolumeCount = 4;
    optional int32 healthyVolumeCount = 5;
    repeated string failedVolumes = 6;
}

message NodePool {
    repeated Node nodes = 1;
}

message DatanodeUsageInfoProto {
    optional int64 capacity = 1; // ozone capacity after subtracting reserved space from fs capacity
    optional int64 used = 2; // space used by ozone as calculated by DU
    optional int64 remaining = 3; // space available to ozone after adjusting reserved space
    optional DatanodeDetailsProto node = 4;
    optional int64 containerCount = 5;
    optional int64 committed = 6;
    optional int64 freeSpaceToSpare = 7;
    optional int64 pipelineCount = 8;
    optional int64 reserved = 9;
    // Raw filesystem stats
    optional int64 fsCapacity = 10;
    optional int64 fsAvailable = 11;
}

/**
 * LifeCycleState for SCM object creation state machine:
 *    ->Allocated: allocated on SCM but client has not started creating it yet.
 *    ->Creating: allocated and assigned to client to create but not ack-ed yet.
 *    ->Open: allocated on SCM and created on datanodes and ack-ed by a client.
 *    ->Close: container closed due to space all used or error.
 *    ->Timeout -> container failed to create on datanodes or ack-ed by client.
 *    ->Deleting(TBD) -> container will be deleted after timeout.
 * 1. ALLOCATE-ed containers on SCM can't serve key/block related operation
 *    until ACK-ed explicitly which changes the state to OPEN.
 * 2. Only OPEN/CLOSED containers can serve key/block related operation.
 * 3. ALLOCATE-ed containers that are not ACK-ed timely will be TIMEOUT and
 *    CLEANUP asynchronously.
 */

enum LifeCycleState {
    OPEN = 1;
    CLOSING = 2;
    QUASI_CLOSED = 3;
    CLOSED = 4;
    DELETING = 5;
    DELETED = 6; // object is deleted.
    RECOVERING = 7;
}

enum LifeCycleEvent {
    FINALIZE = 1;
    QUASI_CLOSE = 2;
    CLOSE = 3; // !!Event after this has not been used yet.
    FORCE_CLOSE = 4;
    DELETE = 5;
    CLEANUP = 6;
}

message ContainerInfoProto {
    // Replace int64 with ContainerID message
    required int64 containerID = 1;
    required LifeCycleState state = 2;
    optional PipelineID pipelineID = 3;
    required uint64 usedBytes = 4;
    required uint64 numberOfKeys = 5;
    optional int64 stateEnterTime = 6;
    required string owner = 7;
    optional int64 deleteTransactionId = 8;
    optional int64 sequenceId = 9;
    optional ReplicationFactor replicationFactor  = 10;
    required ReplicationType replicationType  = 11;
    optional ECReplicationConfig ecReplicationConfig = 12;
    optional bool suppressed = 13;
}

message ContainerWithPipeline {
  required ContainerInfoProto containerInfo = 1;
  required Pipeline pipeline = 2;
}

message GetScmInfoRequestProto {
    optional string traceID = 1;
}

message GetScmInfoResponseProto {
    required string clusterId = 1;
    required string scmId = 2;
    repeated string peerRoles = 3;
}

message AddScmRequestProto {
    required string clusterId = 1;
    required string scmId = 2;
    required string ratisAddr = 3;
}

message AddScmResponseProto {
    required bool success = 1;
    optional string scmId = 2;
}

message RemoveScmRequestProto {
    required string clusterId = 1;
    required string scmId = 2;
    required string ratisAddr = 3;
}

message RemoveScmResponseProto {
    required bool success = 1;
    optional string scmId = 2;
}

enum ReplicationType {
    RATIS = 1;
    STAND_ALONE = 2;
    CHAINED = 3;
    EC = 4;
    NONE = -1; // Invalid Type
}

enum ReplicationFactor {
    ONE = 1;
    THREE = 3;
    ZERO = 0; // Invalid Factor
}

message ECReplicationConfig {
    required int32 data = 1;
    required int32 parity = 2;
    required string codec = 3;
    required int32 ecChunkSize = 4;
}

message DefaultReplicationConfig {
    required ReplicationType type = 1;
    optional ReplicationFactor factor = 2;
    optional ECReplicationConfig ecReplicationConfig = 3;
}

enum ScmOps {
    allocateBlock = 1;
    keyBlocksInfoList = 2;
    getScmInfo = 3;
    deleteBlock = 4;
    createReplicationPipeline = 5;
    allocateContainer = 6;
    getContainer = 7;
    getContainerWithPipeline = 8;
    listContainer = 9;
    deleteContainer = 10;
    queryNode = 11;
}

message ExcludeListProto {
    // TODO: Replace with DatanodeID
    repeated string datanodes = 1;
    // Replace int64 with ContainerID message
    repeated int64 containerIds = 2;
    repeated PipelineID pipelineIds = 3;
}

/**
 * Block ID that uniquely identify a block by SCM.
 */
message ContainerBlockID {
    // Replace int64 with ContainerID message
    required int64 containerID = 1;
    required int64 localID = 2;
}

message SecretKeyProto {
    required uint32 keyId = 1;
    required uint64 expiryDate = 2;
    required bytes privateKeyBytes = 3;
    required bytes publicKeyBytes = 4;
}

/**
 * Security token identifier
 */
message TokenProto {
  required bytes identifier = 1;
  required bytes password = 2;
  required string kind = 3;
  required string service = 4;
}

/**
 * Information for the Hdds block token.
 * When adding further fields, make sure they are optional as they would
 * otherwise not be backwards compatible.
 */
message BlockTokenSecretProto {
    /**
     * File access permissions mode.
     */
    enum AccessModeProto {
        READ = 1;
        WRITE = 2;
        COPY = 3;
        DELETE = 4;
    }
    required string ownerId = 1;
    required string blockId = 2;
    required uint64 expiryDate = 3;
    optional string omCertSerialId = 4 [deprecated=true];
    repeated AccessModeProto modes = 5;
    required uint64 maxLength = 6;
    optional UUID secretKeyId = 7;
}

message BlockID {
    required ContainerBlockID containerBlockID = 1;
    optional uint64 blockCommitSequenceId = 2 [default = 0];
}

message UpgradeFinalizationStatus {
    enum Status {
        ALREADY_FINALIZED = 1;
        STARTING_FINALIZATION = 2;
        FINALIZATION_IN_PROGRESS = 3;
        FINALIZATION_DONE = 4;
        FINALIZATION_REQUIRED = 5;
    }
    required Status status = 1;
    repeated string messages = 2;
}

/**
 * Information for Certificate Revocation List.
 */
message CRLInfoProto {
    required string x509CRL = 1;
    required uint64 creationTimestamp = 2;
    required int64 crlSequenceID = 3;
}

/**
 * Information for X509 Certificate.
 */
message CertInfoProto {
    required string x509Certificate = 1;
    required uint64 timestamp = 2;
}

message ContainerReplicaHistoryListProto {
    repeated ContainerReplicaHistoryProto replicaHistory = 1;
}

message ContainerReplicaHistoryProto {
    required string uuid = 1;
    required int64 firstSeenTime = 2;
    required int64 lastSeenTime = 3;
    required int64 bcsId = 4;
    optional string state = 5;
    optional int64 dataChecksum = 6;
}

message SCMContainerReplicaProto {
    required int64 containerID = 1;
    required string state = 2;
    required DatanodeDetailsProto datanodeDetails = 3;
    required string placeOfBirth = 4;
    required int64 sequenceID = 5;
    required int64 keyCount = 6;
    required int64 bytesUsed = 7;
    optional int64 replicaIndex = 8;
    optional int64 dataChecksum = 9;
}

message KeyContainerIDList {
    required string key = 1;
    repeated ContainerID container = 2;
}

message KeyIntValue {
    required string key = 1;
    optional int64 value = 2;
}

message ReplicationManagerReportProto {
    required int64 timestamp = 1;
    repeated KeyIntValue stat = 2;
    repeated KeyContainerIDList statSample = 3;
    optional int32 sampleLimit = 4 [default = 100];
}

message ContainerBalancerConfigurationProto {
    optional string utilizationThreshold = 5;
    optional int32 datanodesInvolvedMaxPercentagePerIteration = 6;
    optional int64 sizeMovedMaxPerIteration = 7;
    optional int64 sizeEnteringTargetMax = 8;
    optional int64 sizeLeavingSourceMax = 9;
    optional int32 iterations = 10;
    optional string excludeContainers = 11;
    optional int64 moveTimeout = 12;
    optional int64 balancingIterationInterval = 13;
    optional string includeDatanodes = 14;
    optional string excludeDatanodes = 15;
    optional bool moveNetworkTopologyEnable = 16;
    optional bool triggerDuBeforeMoveEnable = 17;

    required bool shouldRun = 18;
    optional int32 nextIterationIndex = 19;
    optional int64 moveReplicationTimeout = 20;
    optional string includeContainers = 21;
    optional bool includeNonStandardContainers = 22;
}

message TransferLeadershipRequestProto {
    required string newLeaderId = 1;
}

message TransferLeadershipResponseProto {
}

message DeletedBlocksTransactionInfo {
    optional int64 txID = 1;
    optional int64 containerID = 2;
    repeated int64 localID = 3;
    optional int32 count = 4;
}

message DeletedBlocksTransactionSummary {
    optional uint64 totalTransactionCount = 1;
    optional uint64 totalBlockCount = 2;
    optional uint64 totalBlockSize = 3;
    optional uint64 totalBlockReplicatedSize = 4;
}

message CompactionFileInfoProto {
    optional string fileName = 1;
    optional string startKey = 2;
    optional string endKey = 3;
    optional string columnFamily = 4;
    optional bool pruned = 5;
}

message CompactionLogEntryProto {
    optional uint64 dbSequenceNumber = 1;
    optional uint64 compactionTime = 2;
    repeated CompactionFileInfoProto inputFileIntoList = 3;
    repeated CompactionFileInfoProto outputFileIntoList = 4;
    optional string compactionReason = 5;
}

message NodeTopology {
    optional string name = 1;
    optional string location = 2;
    optional uint32 cost = 3;
    optional uint32 level = 4;
}

message NetworkNode {
    optional DatanodeDetailsProto datanodeDetails = 1;
    optional InnerNode innerNode = 3;
}

message ChildrenMap {
    optional string networkName = 1;
    optional NetworkNode networkNode = 2;
}

message InnerNode {
    optional NodeTopology nodeTopology = 1;
    optional uint32 numOfLeaves = 2;
    repeated ChildrenMap childrenMap = 3;
}

message DiskBalancerConfigurationProto {
    optional double threshold = 1;
    optional uint64 diskBandwidthInMB = 2;
    optional int32 parallelThread = 3;
    optional bool stopAfterDiskEven = 4;
    optional string containerStates = 5;
}

enum DiskBalancerRunningStatus {
    RUNNING = 1;
    STOPPED = 2;
    PAUSED = 3;
}

message VolumeReportProto {
    optional string storageId = 1;
    optional string storagePath = 2;
    optional uint64 totalCapacity = 3;
    optional uint64 usedSpace = 4;
    optional uint64 committedBytes = 5;
    optional uint64 effectiveUsedSpace = 6;
    optional double utilization = 7;
    optional uint64 ozoneAvailable = 8;
}

message DatanodeDiskBalancerInfoProto {
    required DatanodeDetailsProto node = 1;
    required double currentVolumeDensitySum = 2;
    optional DiskBalancerRunningStatus runningStatus = 3;
    optional DiskBalancerConfigurationProto diskBalancerConf = 4;
    optional uint64 successMoveCount = 5;
    optional uint64 failureMoveCount = 6;
    optional uint64 bytesToMove = 7;
    optional uint64 bytesMoved = 8;
    optional double idealUsage = 9;
    repeated VolumeReportProto volumeInfo = 10;
}
