一、背景介绍
对于一个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-sdk的Provider创建实例来实现。
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,直接继承扩展即可。实际核心层的逻辑后续有时间再走读。