Autor: Comunidade KubeVela
KubeVela atualmente suporta fornecedores de nuvem como AWS, Azure, GCP, Alibaba Cloud, Tencent Cloud, Baidu Cloud e UCloud, e também fornece ferramentas de linha de comando simples e rápidas [1] para introduzir recursos de nuvem de provedores de serviços de nuvem, mas no KubeVela one O suporte aos recursos de nuvem de provedores de serviços de nuvem por si só não é adequado para atender rapidamente às necessidades dos usuários por recursos de nuvem. Este artigo fornece uma solução para apresentar rapidamente os 50 principais recursos de nuvem mais populares na AWS com menos de 100 linhas de código.
Ao mesmo tempo, também esperamos que os usuários se inspirem neste artigo e contribuam com recursos de nuvem de outros provedores de serviços de nuvem.
Onde estão os recursos de nuvem mais populares da AWS?
O site oficial da Terraform fornece módulos Terraform de vários provedores de serviços em nuvem, como os módulos Terraform de recursos de nuvem da AWS[2]. Entre eles, os recursos de nuvem são classificados por popularidade (downloads), por exemplo, AWS VPC tem 18,7 milhões de downloads.
Por meio de uma análise simples, descobrimos que os dados dos 50 principais módulos Terraform da AWS podem ser obtidos solicitando registry.terraform.io/v2/modules?… .
antes do início
O código aceita dois parâmetros passados pelo usuário: • o nome do provedor • a URL dos Módulos Terraform correspondentes ao provedor
Para AWS, o nome do provedor é "aws", e os módulos Terraform correspondentes são a interface de formato json do Terraform Modules [3] (ou seja, pesquise no Terraform Registry [4] pelos 50 recursos de nuvem mais populares quando o provedor for aws) . Antes de executar o código, você precisa confirmar se os links providerName(aws) e Modules estão corretos.
executar código
Em seguida, você pode apresentar rapidamente os 50 principais recursos de nuvem da AWS mais populares em lotes por meio das cerca de 100 linhas de código a seguir (nome do arquivo gen.go).
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/pkg/errors"
)
type TFDownload struct {
Data []DataItem `json:"data"`
Included []IncludedItem `json:"included"`
}
type IncludedItem struct {
Id string `json:"id"`
Attributes Attributes `json:"attributes"`
}
type DataItem struct {
Attributes Attributes `json:"attributes"`
Relationships Relationships `json:"relationships"`
}
type Relationships struct {
LatestVersion RelationshipLatestVersion `json:"latest-version"`
}
type RelationshipLatestVersion struct {
Data RelationshipData `json:"data"`
}
type RelationshipData struct {
Id string `json:"id"`
}
var errNoVariables = errors.New("failed to find main.tf or variables.tf in Terraform configurations")
type Attributes struct {
Name string `json:"name"`
Downloads int `json:"downloads"`
Source string `json:"source"`
Description string `json:"description"`
Verified bool `json:"verified"`
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Please provide the cloud provider name and an official Terraform modules URL")
os.Exit(1)
}
providerName := os.Args[1]
terraformModulesUrl := os.Args[2]
resp, err := http.Get(terraformModulesUrl)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var modules TFDownload
if err := json.Unmarshal(body, &modules); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
if _, err = os.Stat(providerName); err == nil {
if err := os.RemoveAll(providerName); err != nil {
log.Fatal(err)
}
fmt.Printf("Successfully deleted existed directory %s\n", providerName)
}
if _, err = os.Stat(providerName); os.IsNotExist(err) {
if err := os.Mkdir(providerName, 0755); err != nil {
if !os.IsExist(err) {
log.Fatal(err)
}
fmt.Printf("Successfully created directory %s\n", providerName)
}
}
for _, module := range modules.Data {
var description string
for _, attr := range modules.Included {
if module.Relationships.LatestVersion.Data.Id == attr.Id {
description = attr.Attributes.Description
}
}
if description == "" {
description = strings.ToUpper(providerName) + " " + strings.Title(module.Attributes.Name)
}
outputFile := fmt.Sprintf("%s/terraform-%s-%s.yaml", providerName, providerName, module.Attributes.Name)
if _, err := os.Stat(outputFile); !os.IsNotExist(err) {
continue
}
if providerName == "aws" && (module.Attributes.Name == "rds" || module.Attributes.Name == "s3-bucket" ||
module.Attributes.Name == "subnet" || module.Attributes.Name == "vpc") {
continue
}
if err := generateDefinition(providerName, module.Attributes.Name, module.Attributes.Source, "", description); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}
}
func generateDefinition(provider, name, gitURL, path, description string) error {
defYaml := filepath.Join(provider, fmt.Sprintf("terraform-%s-%s.yaml", provider, name))
cmd := fmt.Sprintf("vela def init %s --type component --provider %s --git %s.git --desc \"%s\" -o %s",
name, provider, gitURL, description, defYaml)
if path != "" {
cmd = fmt.Sprintf("%s --path %s", cmd, path)
}
fmt.Println(cmd)
stdout, err := exec.Command("bash", "-c", cmd).CombinedOutput()
if err != nil {
return errors.Wrap(err, string(stdout))
}
fmt.Println(string(stdout))
return nil
复制代码
Executando um pedido:
go run gen.go aws "https://registry.terraform.io/v2/modules?filter%5Bprovider%5D=aws&include=latest-version&page%5Bsize%5D=50&page%5Bnumber%5D=1"
复制代码
Breve Descrição do Código
解析云资源数据
访问用户传入的 URL,将返回的 json 数据解析为 Go 中的结构体。
资源对应的 json 格式如下:
{
"data": [
{
"type": "modules",
"id": "23",
"attributes": {
"downloads": 18440513,
"full-name": "terraform-aws-modules/vpc/aws",
"name": "vpc",
"namespace": "terraform-aws-modules",
"owner-name": "",
"provider-logo-url": "/images/providers/aws.png",
"provider-name": "aws",
"source": "https://github.com/terraform-aws-modules/terraform-aws-vpc",
"verified": true
},
"relationships": {
"latest-version": {
"data": {
"id": "142143",
"type": "module-versions"
}
}
},
"links": {
"self": "/v2/modules/23"
}
},
...
],
"included": [
{
"type": "module-versions",
"id": "36806",
"attributes": {
"created-at": "2020-01-03T11:35:36Z",
"description": "Terraform module Terraform module for creating AWS IAM Roles with heredocs",
"downloads": 260030,
"published-at": "2020-02-06T06:26:08Z",
"source": "",
"tag": "v2.0.0",
"updated-at": "2022-02-22T00:45:44Z",
"version": "2.0.0"
},
"links": {
"self": "/v2/module-versions/36806"
}
},
...
],
...
}
复制代码
在 Modules 对应的 json 数据中,我们只关心两个键值对,即:
• data:包含 Modules 名称及属性的列表 • Included:筛选出的特定版本的 Modules 具体信息
其中,对于 data 中的每个 Module 元素,解析它的属性,Id 和 relationship 中的 latest-version 对应的 id;对于 Included 中的每个 Module 版本元素,解析它的属性和Id。
属性又解析如下五项:
• Name • Downloads • Source • Description • Verified
结构体定义在结构体 TFDownload 中,通过 http 库获取 json 数据,再通过 json.Unmarshal 解析出 Terraform modules 的结构体。
批量生产云资源
1. 新建目录,生成资源所需文件
解析完毕后,在当前目录下新建文件夹,文件夹命名为 provider 名称。 遍历解析后的 data,对于其中每个 Module 元素,执行下述操作,为其生成相应配置文件,定义和相应文档。
2. 生成定义文件
通过下述 vela 指令从模块对应的 github 仓库读取相应信息生成定义文件。
vela def init {ModuleName} --type component --provider {providerName} --git {gitURL} --desc {description} -o {yamlFileName}
复制代码
指令中需要填入的几项由解析好的 Module 结构体传入。
• gitURL: {Module.Attributes.Source}.git
• description: 如果 Included 中存在元素 ID 与模块 relationship 中 latest-version 对应 ID 相同,则 description 为 Included 中对应元素属性的 description;否则 description 为 providerName 与模块名称的拼接
• yamlFileName:terraform-{providerName}-{Module.Attributes.Name}.yaml
Você vai tentar também?
Há também muitos provedores de serviços em nuvem que fornecem módulos avançados do Terraform, como
GCP :registry.terraform.io/namespaces/…
Alibaba Cloud: registry.terraform.io/namespaces/…
Você também deseja apresentar os recursos de nuvem do provedor de serviços de nuvem que você está usando ou gosta do KubeVela?
Links Relacionados
[1] Ferramenta de linha de comando simples e rápida
[2] Módulos Terraform de recursos de nuvem da AWS
registry.terraform.io/namespaces/…
[3] Interface de formato json dos Módulos Terraform
registry.terraform.io/v2/modules?…
[4] Registro Terraform