IaC

Terraform Provider如何解析.tf文件

Posted by Shi Hai's Blog on October 31, 2022

一、背景介绍

对于一个Terraform文件(.tf),相关providers是如何对资源Resource结构进行管理、资源映射到代码和最终应用?如下方的k8s provider创建kubernetes_cluster_role的实例,是如何解析k8s资源信息?

resource "kubernetes_cluster_role" "example" {
  metadata {
    name = "terraform-example"
  }

  rule {
    api_groups = [""]
    resources  = ["namespaces", "pods"]
    verbs      = ["get", "list", "watch"]
  }
}

二、代码流走读

2.1 主要执行逻辑

terraform provider的实现是通过调用terraform-plugin-sdkProvider创建实例来实现。
provider中最终要的一个环节实际是管理Resource资源,配置文件中所有被管理的资源对象均被抽象为Resouce资源。而Resource资源中的属性类型则被抽象为Schema结构体。下方代码就是kubernetes cluster role资源的定义逻辑。而对资源管理过程则有各种xxxContext函数进行管理。

kubernetes/resource_kubernetes_cluster_role.go

// k8s ClusterRole资源定义
func resourceKubernetesClusterRole() *schema.Resource {
    return &schema.Resource{
        CreateContext: resourceKubernetesClusterRoleCreate,
        ReadContext:   resourceKubernetesClusterRoleRead,
        UpdateContext: resourceKubernetesClusterRoleUpdate,
        DeleteContext: resourceKubernetesClusterRoleDelete,
        Importer: &schema.ResourceImporter{
            StateContext: schema.ImportStatePassthroughContext,
        },

        Schema: map[string]*schema.Schema{
            "metadata": metadataSchemaRBAC("clusterRole", false, false),
            "rule": {
                // 定义配置中资源属性类型及调用ResourceData.Get函数时的返回类型
                Type:      schema.TypeList,
                Description: "List of PolicyRules for this ClusterRole",
                Optional:    true,
                Computed:    true,
                MinItems:    1,
                Elem: &schema.Resource{
                    Schema: policyRuleSchema(),
                },
            },
        ......
}

k8s provider主要的代码执行流程图如下所示。

2.2 配置资源到代码解析

如实例中的cluster role定义是怎么映射到代码调用中?

  rule {
    api_groups = [""]
    resources  = ["namespaces", "pods"]
    verbs      = ["get", "list", "watch"]
  }

当对rule资源定义了Type: schema.TypeList后,实际的资源获取过程依赖于schema.ResourceData.Get(),如获取到k8s_cluster_role中的rule资源数据,则实际函数调用过程是:

	cRole := api.ClusterRole{
		ObjectMeta: metadata,
     // 通过调用d.Get("rule")获取所有rule资源定义信息
		Rules:      expandClusterRoleRules(d.Get("rule").([]interface{})),
	}

d.get("rule")会查询到所有rule集合信息并在expandClusterRoleRules()中对rule资源集合进行处理和转换。

三、terraform对provider的管理

TODO: terraform和terraform-plugin-sdk已经对HCL语言逻辑做了设计和封装实现,要增加provider,直接继承扩展即可。实际核心层的逻辑后续有时间再走读。

四、参考文献k

  1. kubernetes_cluster_role