resource "tencentcloud_instance" "cvm1" {instance_name = "my-cvm"availability_zone = "ap-guangzhou-4"instance_type = "SA2.MEDIUM2"instance_charge_type = "POSTPAID_BY_HOUR"image_id = "img-9qrfy1xt"allocate_public_ip = trueinternet_max_bandwidth_out = 10}
terraform apply
时,已声明的资源会发起创建流程。在创建完毕后,若您改动这段代码中的配置,并再次执行命令 terraform apply
,将会发起更新流程。执行命令 terraform destroy
则会进入销毁流程。Provider/ResourceMap
字段,添加名为 tencentcloud_instance
的资源结构体,按照 HCL 定义参数样板 (Schema),代码如下:package tencentcloudimport ("github.com/hashicorp/terraform-plugin-sdk/helper/schema""github.com/hashicorp/terraform-plugin-sdk/terraform")func Provider() *schema.Provider {return &schema.Provider{ResourcesMap: map[string]*schema.Resource{"tencentcloud_xxx": { /* 其他声明好的资源 */ },"tencentcloud_yyy": { /* 其他声明好的资源 */ },"tencentcloud_instance": {Schema: map[string]*schema.Schema{"instance_name": {Optional: true, // 可选字段Type: schema.TypeString, // 字段类型Description: "Instance Name.",},"availability_zone": {Required: true, // 必填字段Type: schema.TypeString,ForceNew: true, // 当这个字段更改,提交变更后资源销毁重建,因为服务器实例无法切换可用区。Description: "Instance available zone.",},"instance_type": {Optional: true,Type: schema.TypeString,Description: "Instance Type.",},"instance_charge_type": {Optional: true,Type: schema.TypeString,Description: "Instance charge type.",},"image_id": {Required: true,Type: schema.TypeString,Description: "Instance OS image Id.",},"allocate_public_ip": {Optional: true,Type: schema.TypeBool, // 布尔类型Description: "Specify whether to allocate public IP.",},"internet_max_bandwidth_out": {Optional: true,Type: schema.TypeInt, // 整数类型Description: "Specify maximum bandwith.",},},},},}}
apply
/ plan
/ destroy
时触发资源的增、删、改和同步逻辑也需要您自行定义。Terraform SDK (v1) 中定义了资源的 CRUD 四种方法:Create
执行 terraform apply
且为新建时调用。Read
执行 terraform plan / import
时调用,用来同步远端状态。Update
执行 terraform apply
且为更新时调用。Delete
执行 terraform destroy
时调用。schema.Resource
结构体中添加这四个方法,代码如下:package tencentcloudimport ("github.com/hashicorp/terraform-plugin-sdk/helper/schema""github.com/hashicorp/terraform-plugin-sdk/terraform")func Provider() *schema.Provider {return &schema.Provider{ResourcesMap: map[string]*schema.Resource{"tencentcloud_xxx": { /* 其他声明好的资源 */ },"tencentcloud_yyy": { /* 其他声明好的资源 */ },"tencentcloud_instance": {Create: resourceTencentCloudInstanceCreate,Read: resourceTencentCloudInstanceRead,Update: resourceTencentCloudInstanceUpdate,Delete: resourceTencentCloudInstanceDelete,Schema: map[string]*schema.Schema{// 上文写好的声明,略},},},}}func resourceTencentCloudInstanceCreate (d *schema.ResouceData, m interface{}) error {instanceName := d.Get("instance_name").(string)instanceType := d.Get("instance_type").(string)// ...// terraform apply 新建资源的时候执行instanceId := createInstance(¶m{Name: &instanceName,Type: &instanceType,// ...})// 创建完成后,给资源设置唯一 Idd.SetId(instanceId)// 资源创建完毕后,需要再次同步远端状态,验证是否一致return resourceTencentCloudInstanceRead(d, m)}func resourceTencentCloudInstanceRead (d *schema.ResouceData, m interface{}) error {// terraform plan 时和 terraform 创建/更新资源完毕时执行instanceId := d.Id() // Create 中设置的 IdinstanceInfo := getInstance(instanceId)d.Set("instance_name", instanceInfo.Name)d.Set("instance_type", instanceInfo.Type)return nil}func resourceTencentCloudInstanceUpdate (d *schema.ResouceData, m interface{}) error {// terraform apply 更新已有资源时执行updateParam := ¶m{}// 逐项检查字段是否更新,组合更新参数if d.HasChange("instance_name") {name := d.Get("instance_name").(string)updateParam.Name = &name}if d.HasChange("instance_type") {insType := d.Get("instance_type").(string)updateParam.Type = &insType}// ...updateInstance(d.Id(), updateParam)// 资源创建完毕后,需要再次同步远端状态,验证是否一致return resourceTencentCloudInstanceRead(d, m)}func resourceTencentCloudInstanceDelete (d *schema.ResouceData, m interface{}) error {// terraform destroy 时执行destroyInstance(d.Id())return nil}
d.Get
参数可以获取 HCL 字段的值,d.Set
可以回写(同步)这些值,此外每个资源创建完毕后还要调用 d.SetId
设置资源的唯一索引,以保证后续操作和远程真实资源的映射关系一致。plan apply destroy
即可正常调用,接下来您可以发起云 API 调用,真实地操作资源。
云服务器的 CVM 的 CRUD 接口分别为:package mainimport (cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312")func resourceTencentCloudInstanceCreate(d *schema.ResourceData, meta interface{}) error {// 从 HCL 中读取字段的值instanceName := d.Get("instance_name").(string)instanceType := d.Get("instance_type").(string)imageId := d.Get("image_id").(string)instanceChargeType := d.Get("instance_charge_type").(string)zone := d.Get("availability_zone").(string)allocatePublicIp := d.Get("allocate_public_ip").(bool)internetBandWith := int64(d.Get("internet_max_bandwidth_out").(int))client, _ := cvm.NewClient(credential, "ap-guangzhou")request := cvm.NewRunInstancesRequest()// 组合创建 CVM 所需的参数request.InstanceName = &instanceNamerequest.InstanceType = &instanceTyperequest.ImageId = &imageIdrequest.InstanceChargeType = &instanceChargeTyperequest.Placement = &cvm.Placement {Zone: &zone,}request.InternetAccessible = &cvm.InternetAccessible {InternetMaxBandwidthOut: &internetBandWith,PublicIpAssigned: &allocatePublicIp,}// 发起调用id, err := client.RunInstances(request)if err != nil {return err}// 将创建返回的 ID 设置为资源 IDd.SetId(id)// 回写状态return resourceTencentCloudInstanceRead(d, meta)}
package mainimport (cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312")func resourceTencentCloudInstanceRead(d *schema.ResourceData, meta interface{}) error {// Create 中设置或导入时拿到的 IDid := d.Id()client, _ := cvm.NewClient(credential, "ap-guangzhou")request, _ := cvm.NewDescribeInstancesRequest()request.InstanceIds = []*string{&id}response, err := client.DescribeInstances(request)if err != nil {return err}if len(response.Response.InstanceSet) == 0 {return fmt.Errorf("instance %s not exists.", id)}instance := response.Response.InstanceSet[0]d.Set("instance_name", instance.InstanceName)d.Set("instance_type", instance.InstanceType)// d.Set 回写其他如 `image_id` `instance_charge_type` `availability_zone` 等字段,略return nil}func resourceTencentCloudInstanceUpdate(d *schema.ResourceData, meta interface{}) error {id := d.Id()client, _ := cvm.NewClient(credential, "ap-guangzhou")request, _ := cvm.NewModifyInstancesAttributeRequest()request.InstanceIds = []*string{&id}// 检查字段是否变更且添加参数if d.HasChange("instance_name") {name := d.Get("instance_name").(string)request.InstanceName = &name}// 处理其他 HasChange 字段,略_, err := client.ModifyInstanceAttribute(request)if err != nil {return err}return resourceTencentCloudInstanceRead(d, meta)}func resourceTencentCloudInstanceDelete(d *schema.ResourceData, meta interface{}) error {id := d.Id()client, _ := cvm.NewClient(credential, "ap-guangzhou")request, _ := cvm.NewTerminateInstancesRequest()request.InstanceIds = []*string{&id}_, err := client.TerminateInstances(request)if err != nil {return err}return nil}
terraform import <type>.<index> <id>
,例如:terraform import tencentcloud_instance.cvm1 ins-abcd1234
ins-abcd1234
输入,回想我们已实现的 Read 方法,可以得知:当 Id 确定时,可以根据 Id 查询远端资源的详细配置,自动将配置同步到本地。所以我们只需要在 schema.Resource 中声明 Importer
表示该资源可以被导入,后续同步操作由 Read 接管:package tencentcloudimport ("github.com/hashicorp/terraform-plugin-sdk/helper/schema""github.com/hashicorp/terraform-plugin-sdk/terraform")func Provider() *schema.Provider {return &schema.Provider{ResourcesMap: map[string]*schema.Resource{"tencentcloud_xxx": { /* 其他声明好的资源 */ },"tencentcloud_yyy": { /* 其他声明好的资源 */ },"tencentcloud_instance": {Create: resourceTencentCloudInstanceCreate,Read: resourceTencentCloudInstanceRead,Update: resourceTencentCloudInstanceUpdate,Delete: resourceTencentCloudInstanceDelete,Schema: map[string]*schema.Schema{// 上文写好的声明,略},// 绝大部分情况,只需要添加 schema.ImportStatePassthrough 即可Importer: &schema.ResourceImporter{State: schema.ImportStatePassthrough,},},},}}
TencentOS Server 3.2 (Final)
,但是实际传递给 API 的参数却是它的 ID img-9qrfy1xt
,如何通过镜像名称获取对应的 ID 呢?这时候就可以借助 DataSource 来查询并引用了:data "tencentcloud_images" "fav_os" {filters = {image_name: "TencentOS Server 3.2",image_type: "PUBLIC_IMAGE"}}resource "tencentcloud_instance" "cvm1" {image_id = data.tencentcloud_images.fav_os.images.0.image_id}
image_id
写成对 data.tencentcloud_images.fav_os
的引用,Terraform 就会先读取 DataSource 的信息,再将结果计算求值。相比于静态的写法,编写 DataSource 能有效地将带有依赖的资源组织起来。Provider/DataSourceMap
字段,添加名为 tencentcloud_images
的结构体(所有 DataSource 名字都应该以 s
结尾),按照 HCL 定义参数样板 (Schema):package tencentcloudimport ("github.com/hashicorp/terraform-plugin-sdk/helper/schema""github.com/hashicorp/terraform-plugin-sdk/terraform")func Provider() *schema.Provider {return &schema.Provider{DataSourceMap: map[string]*schema.Resource{"tencentcloud_xxxs": { /* 其他声明好的数据源 */ },"tencentcloud_yyys": { /* 其他声明好的数据源 */ },"tencentcloud_images": {Schema: map[string]*schema.Schema{"filters": {Optional: true,Type: schema.TypeMap, // 定义为 Map 类型Description: "Query filter",},// 用来将结果以 JSON 的形式保存在本地。// TencentCloud Provider 约定每个 DataSource 都应带有 `result_output_file`"result_output_file": {Optional: true,Type: schema.TypeString,Description: "Used for store as local file.",},"result": {Computed: true, // Computed 可以表示该字段会进行被动更新Type: schema.TypeList,Description: "",Elem: &schema.Resource{Schema: map[string]*schema.Schema{"id": {Type: schema.TypeString,Computed: true,Description: "Image Id.",},"name": {Type: schema.,Computed: true,Description: "Image name.",},},},},},},},}}
package tencentcloudimport ("encoding/json""github.com/hashicorp/terraform-plugin-sdk/helper/schema""github.com/hashicorp/terraform-plugin-sdk/terraform")const ImgNameFilterKey = "image-name"func Provider() *schema.Provider {return &schema.Provider{DataSourceMap: map[string]*schema.Resource{"tencentcloud_xxxs": { /* 其他声明好的数据源 */ },"tencentcloud_yyys": { /* 其他声明好的数据源 */ },"tencentcloud_images": {Schema: map[string]*schema.Schema{ /* 略 */},Read: func(d *schema.ResourceData, meta interface{}) {// 声明 Client 和 requestclient, _ := cvm.NewClient(credential, "ap-guangzhou")request := cvm.NewDescribeImagesRequest()// 获取 Filters ,为 Map 类型filters := d.Get("filters").(map[string]interface{})// 检查 filters["name"] 并添加参数if name, ok := filters["name"].(string); ok {request.Filters = append(request.Filters, &cvm.Filter{Name: &ImgNameFilterKey,Values: []*string{&name}})}// 发起调用response, err := client.DescribeImages(request)if err != nil {return err}// 组装 `result` 字段并写入imageSet := response.Response.ImageSetresult := make([]map[string]interface{}, 0, len(imageSet))for i := range imageSet {item := imageSet[i]result = append(result, map[string]interface{}{"id": *item.Id,"name": *item.Name,})}d.Set("result", result)// 如果 `result_output_file` 有定义,则往指定文件写入结果if v, ok := d.GetOk("result_output_file"); ok {writeToFile(v.(string), result)}return nil}},},}}
tencentcloud_images
的编写,后续可以使用这个 DataSource ,查询特定的 OS 镜像。
本页内容是否解决了您的问题?