terraform {
  required_providers {
    huaweicloud = {
      source  = "huawei.com/provider/huaweicloud"
      version = ">=1.70.1"
    }
  }
}

provider "huaweicloud" {
  region = var.region_id
}

variable "region_id" {
  default     = "cn-north-4"
  description = "资源部署所在Region。请确保和控制台的区域（页面左上方）保持一致。区域ID参考：北京四：cn-north-4。"
  type        = string
  nullable    = false

  validation {
    condition     = contains(["cn-north-4"], var.region_id)
    error_message = "Invalid input, please re-enter."
  }
}

variable "vpc_name" {
  default     = "yolo-web-demo"
  description = "虚拟私有云名称，该模板使用新建VPC，不允许重名。取值范围：1-54个字符，支持中文、英文字母、数字、_（下划线）、-（中划线）、.（点）。默认：yolo-web-demo。"
  type        = string
  nullable    = false
}

variable "security_group_name" {
  default     = "yolo-web-demo"
  description = "安全组名称，该模板新建安全组，安全组规则请参考部署指南进行配置。取值范围：1-64个字符，支持数字、字母、中文、_(下划线)、-（中划线）、.（点）。默认：yolo-web-demo。"
  type        = string
  nullable    = false
}

variable "ecs_name" {
  default     = "yolo-web-demo"
  description = "云服务器实例名称，不支持重名。取值范围：1-64个字符，支持中文、英文字母、数字、_（下划线）、-（中划线）、.（点）。默认：yolo-web-demo。"
  type        = string
  nullable    = false
}

variable "ecs_flavor" {
  default     = "p2s.2xlarge.8"
  description = "云服务器实例规格，支持弹性云服务器 ECS及华为云Flexus 云服务器X实例。Flexus 云服务器X实例规格ID命名规则为x1.?u.?g，例如2vCPUs4GiB规格ID为x1.2u.4g，具体华为云Flexus 云服务器X实例规格请参考控制台。弹性云服务器 ECS规格请参考部署指南配置。默认：p2s.2xlarge.8。"
  type        = string
  nullable    = false

  validation {
    condition     = length(regexall("^([a-z][a-z0-9]{0,3}\\.)(x||[1-9][0-9]{0,1}x)large\\.[1-9][0-9]{0,1}$|^x1e.([1-9]|1[0-6])u.([1-9][0-9]{0,1}|1[0-2][0-8])g$", var.ecs_flavor)) > 0
    error_message = "Invalid input. Please re-enter."
  }
}

variable "ecs_password" {
  default     = ""
  description = "云服务器密码，长度为8-26位，密码至少包含大写字母、小写字母、数字和特殊字符（!@$%^-_=+[{}]:,./?）中的三种。管理员账户默认root。"
  type        = string
  sensitive   = true
  nullable    = false
}

variable "system_disk_size" {
  default     = 100
  description = "云服务器系统盘大小，磁盘类型默认为高IO，单位：GB，取值范围为40-1,024，不支持缩盘。默认：100"
  type        = number
  nullable    = false

  validation {
    condition     = length(regexall("^([4-9][0-9]|[1-9][0-9]{2}|10[01][0-9]|102[0-4]|1024)$", var.system_disk_size)) > 0
    error_message = "Invalid input. Please re-enter."
  }
}

variable "data_disk_size" {
  default     = 500
  description = "云服务器数据盘大小，磁盘类型默认为高IO，单位：GB，取值范围为40-1,024，不支持缩盘。默认：500"
  type        = number
  nullable    = false

  validation {
    condition     = length(regexall("^([4-9][0-9]|[1-9][0-9]{2}|10[01][0-9]|102[0-4]|1024)$", var.data_disk_size)) > 0
    error_message = "Invalid input. Please re-enter."
  }
}

variable "bandwidth_size" {
  default     = 300
  description = "弹性公网带宽大小，该模板计费方式为按流量计费。单位：Mbit/s，取值范围：1-300Mbit/s。默认：300。"
  type        = number
  nullable    = false

  validation {
    condition     = length(regexall("^([1-9][0-9]{0,1}|[1-2][0-9]{2}|300)$", var.bandwidth_size)) > 0
    error_message = "Invalid input. Please re-enter."
  }
}

variable "charging_unit" {
  default     = "month"
  description = "云服务器订购周期类型，仅当charging_mode为prePaid（包年/包月）生效，此时该参数为必填参数。取值范围：month（月），year（年）。默认month。"
  type        = string
  nullable    = false

  validation {
    condition     = contains(["month", "year"], var.charging_unit)
    error_message = "Invalid input, please re-enter."
  }
}

variable "charging_period" {
  default     = 1
  description = "云服务器订购周期，仅当charging_mode为prePaid（包年/包月）生效，此时该参数为必填参数。取值范围：charging_unit=month（周期类型为月）时，取值为1-9；charging_unit=year（周期类型为年）时，取值为1-3。默认订购1月。"
  type        = number
  nullable    = false

  validation {
    condition     = length(regexall("^[1-9]$", var.charging_period)) > 0
    error_message = "Invalid input, please re-enter."
  }
}

variable "cbr_charging_unit" {
  default     = "month"
  description = "云备份订购周期类型，仅当charging_mode为prePaid（包年/包月）生效，此时该参数为必填参数。取值范围：month（月），year（年）。默认month。"
  type        = string
  nullable    = false

  validation {
    condition     = contains(["month", "year"], var.cbr_charging_unit)
    error_message = "Invalid input, please re-enter."
  }
}

variable "cbr_charging_period" {
  default     = 1
  description = "云备份订购周期，仅当charging_mode为prePaid（包年/包月）生效，此时该参数为必填参数。取值范围：charging_unit=month（周期类型为月）时，取值为1-9；cbr_charging_unit=year（周期类型为年）时，取值为1-3。默认订购1月。"
  type        = number
  nullable    = false

  validation {
    condition     = length(regexall("^[1-9]$", var.cbr_charging_period)) > 0
    error_message = "Invalid input, please re-enter."
  }
}

variable "storage_pool_name" {
  default     = "cloud-backup_demo"
  description = "存储库名称。取值范围：1-64个字符组成，包括字母、数字、下划线 (_)、连字符 (-) 和句点 (.)。默认为cloud-backup_demo"
  type        = string
  nullable    = false
}

variable "storage_pool_size" {
  default       = 500
  description   = "存储库大小，以GB为单位，建议存储库容量不小于备份服务器磁盘空间。取值范围：10-10485760。默认500GB。"
  type          = number
  nullable      = false
}

variable "backup_interval" {
  default       = 3
  description   = "备份周期，设置备份任务的执行日期，该模板按天执行。取值范围：1-30。默认3天。"
  type          = number
  nullable      = false
}

variable "backup_time" {
  default     = "14:00"
  description = "备份时间，设置备份任务在一天之内的执行时间点，实际备份时间会+8:00，建议选择无业务或者业务量较少的时间进行备份。取值范围：00:00-23:00，时间取整点。默认14:00，即备份实际为22:00。"
  type        = string
  nullable    = false
}

variable "time_period" {
  default     = 30
  description = "保留备份的持续时间（以天为单位）。取值范围：2-99999。默认30天。"
  type        = number
  nullable    = false
}

locals {
  user_data   = <<-EOF
    #!/bin/bash
    echo 'root:${var.ecs_password}' | chpasswd
    wget -P /home/ https://documentation-samples.obs.cn-north-4.myhuaweicloud.com/solution-as-code-publicbucket/solution-as-code-moudle/quickly-build-a-yolo-training-platform/userdata/install-docker.sh
    bash /home/install-docker.sh
    wget -P /home/ https://documentation-samples.obs.cn-north-4.myhuaweicloud.com/solution-as-code-publicbucket/solution-as-code-moudle/quickly-build-a-yolo-training-platform/userdata/docker-compose-gpu-sac.yml
    cd /home
    docker compose -f docker-compose-gpu-sac.yml up
  EOF
}

resource "huaweicloud_vpc" "vpc" {
  name = var.vpc_name
  cidr = "172.16.0.0/16"
}

resource "huaweicloud_vpc_subnet" "subnet" {
  name       = "${var.vpc_name}-subnet"
  cidr       = "172.16.1.0/24"
  gateway_ip = "172.16.1.1"
  vpc_id     = huaweicloud_vpc.vpc.id
}

resource "huaweicloud_networking_secgroup" "secgroup" {
  name = var.security_group_name
}

resource "huaweicloud_networking_secgroup_rule" "allow_ping" {
  security_group_id = huaweicloud_networking_secgroup.secgroup.id
  description       = "允许ping程序测试Flexus云服务器X实例的连通性"
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "icmp"
  remote_ip_prefix  = "0.0.0.0/0"
}

resource "huaweicloud_networking_secgroup_rule" "ssh" {
  security_group_id = huaweicloud_networking_secgroup.secgroup.id
  description       = "SSH端口，允许远程连接服务器"
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  ports             = 22
  remote_ip_prefix  = "119.8.185.245/32"
}

resource "huaweicloud_vpc_eip" "vpc_eip" {
  name          = "${var.vpc_name}-eip"
  charging_mode = "postPaid"

  bandwidth {
    name        = "${var.vpc_name}-bandwidth"
    share_type  = "PER"
    size        = var.bandwidth_size
    charge_mode = "traffic"
  }

  publicip {
    type = "5_bgp"
  }
}

resource "huaweicloud_compute_instance" "compute_instance" {
  name                        = var.ecs_name
  image_id                    = "fd063947-f849-48cc-a89c-8146684046ad"
  flavor_id                   = var.ecs_flavor
  admin_pass                  = var.ecs_password
  delete_disks_on_termination = true
  charging_mode               = "prePaid"
  period_unit                 = var.charging_unit
  period                      = var.charging_period
  system_disk_type            = "SAS"
  system_disk_size            = var.system_disk_size
  data_disks {
    type = "SAS"
    size = var.data_disk_size
  }

  security_group_ids = [
    huaweicloud_networking_secgroup.secgroup.id
  ]

  agent_list = "hss,ces"
  eip_id     = huaweicloud_vpc_eip.vpc_eip.id

  network {
    uuid = huaweicloud_vpc_subnet.subnet.id
  }

  tags = {
    app = "_sac_yolo"
  }

  user_data = local.user_data
}

resource "huaweicloud_cbr_policy" "cbr_policy" {
  name        = var.storage_pool_name
  type        = "backup"
  time_period = var.time_period
  
  backup_cycle {
    execution_times = ["03:00"]
    interval        = var.backup_interval
  }
}

resource "huaweicloud_cbr_vault" "cbr_vault" {
  name             = var.storage_pool_name
  type             = "server"
  protection_type  = "backup"
  consistent_level = "crash_consistent"
  size             = var.storage_pool_size
  charging_mode    = "prePaid"
  period_unit      = var.cbr_charging_unit
  period           = var.cbr_charging_period

  policy {
    id = huaweicloud_cbr_policy.cbr_policy.id
  }

  resources {
    server_id = huaweicloud_compute_instance.compute_instance.id
  }

  tags = {
    foo = "bar"
  }
}

output "access_instructions" {
  description = ""
  value       = "等待应用下载及部署完毕（约10分钟）后，请在浏览器上输入网址http://${huaweicloud_vpc_eip.vpc_eip.address}:8001进入到登录页面，详细步骤请参考部署指南。"
  depends_on  = [huaweicloud_vpc_eip.vpc_eip]
}
