From 1172c45186a44b4911f30ccc82c58a23b475f45f Mon Sep 17 00:00:00 2001 From: Jason-Zhang Date: Tue, 24 Dec 2024 11:14:42 +0800 Subject: [PATCH] feat(cce): add data_source autopilot cluster certificate (#6074) --- .../cce_autopilot_cluster_certificate.md | 108 +++++++ docs/data-sources/cce_cluster_certificate.md | 6 +- huaweicloud/provider.go | 9 +- ..._cce_autopilot_cluster_certificate_test.go | 48 ++++ ...cloud_cce_autopilot_cluster_certificate.go | 267 ++++++++++++++++++ 5 files changed, 431 insertions(+), 7 deletions(-) create mode 100644 docs/data-sources/cce_autopilot_cluster_certificate.md create mode 100644 huaweicloud/services/acceptance/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate_test.go create mode 100644 huaweicloud/services/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate.go diff --git a/docs/data-sources/cce_autopilot_cluster_certificate.md b/docs/data-sources/cce_autopilot_cluster_certificate.md new file mode 100644 index 0000000000..752998c236 --- /dev/null +++ b/docs/data-sources/cce_autopilot_cluster_certificate.md @@ -0,0 +1,108 @@ +--- +subcategory: "Cloud Container Engine Autopilot (CCE Autopilot)" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_cce_autopilot_cluster_certificate" +description: |- + Use this data source to get the certificate of a CCE Autopilot cluster within HuaweiCloud. +--- + +# huaweicloud_cce_autopilot_cluster_certificate + +Use this data source to get the certificate of a CCE Autopilot cluster within HuaweiCloud. + +## Example Usage + +```hcl +variable "cluster_id" {} + +data "huaweicloud_cce_autopilot_cluster_certificate" "test" { + cluster_id = var.cluster_id + duration = 30 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) Specifies the region in which to query the resource. + If omitted, the provider-level region will be used. + +* `cluster_id` - (Required, String) Specifies the cluster ID to which the cluster certificate belongs. + +* `duration` - (Required, Int) Specifies the duration of the cluster certificate. + The unit is days. The valid value in [1, 1825]. If the input value is -1, + it will use the maximum 1825 as `duration` value. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The data source ID. + +* `kube_config_raw` - Raw Kubernetes config to be used by kubectl and other compatible tools. + +* `clusters` - The clusters information of the cluster certificate. + + The [clusters](#clusters_struct) structure is documented below. + +* `users` - The users information of cluster the certificate. + + The [users](#users_struct) structure is documented below. + +* `contexts` - The contexts information of the cluster certificate. + + The [contexts](#contexts_struct) structure is documented below. + +* `current_context` - The current context of the cluster certificate. + + +The `clusters` block supports: + +* `name` - The cluster name of the cluster certificate. + +* `cluster` - The cluster information. + + The [cluster](#clusters_cluster_struct) structure is documented below. + + +The `cluster` block supports: + +* `server` - The server address of the cluster certificate. + +* `certificate_authority_data` - The certificate authority data of the cluster certificate. + +* `insecure_skip_tls_verify` - Whether insecure skip tls verify of the cluster certificate. + + +The `users` block supports: + +* `name` - The user name of the cluster certificate. + The value is fixed to `user`. + +* `user` - The user information. + + The [user](#users_user_struct) structure is documented below. + + +The `user` block supports: + +* `client_certificate_data` - The client certificate data of the cluster certificate. + +* `client_key_data` - The client key data of the cluster certificate. + + +The `contexts` block supports: + +* `name` - The context name of the cluster certificate. + +* `context` - The user information. + + The [context](#contexts_context_struct) structure is documented below. + + +The `context` block supports: + +* `cluster` - The context cluster of the cluster certificate. + +* `user` - The context user of the cluster certificate. diff --git a/docs/data-sources/cce_cluster_certificate.md b/docs/data-sources/cce_cluster_certificate.md index a489319199..f86a72ef94 100644 --- a/docs/data-sources/cce_cluster_certificate.md +++ b/docs/data-sources/cce_cluster_certificate.md @@ -1,8 +1,8 @@ --- subcategory: "Cloud Container Engine (CCE)" -layout: "huaweicloud" -page_title: "HuaweiCloud: huaweicloud_cce_cluster_certificate" -description: "" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_cce_cluster_certificate" +description: "" --- # huaweicloud_cce_cluster_certificate diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 833f8863db..359ca4ca47 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -1224,10 +1224,11 @@ func Provider() *schema.Provider { "huaweicloud_vpc_subnet_ids_v1": vpc.DataSourceVpcSubnetIdsV1(), "huaweicloud_vpc_traffic_mirror_filters": vpc.DataSourceVpcTrafficMirrorFilters(), - "huaweicloud_cce_cluster_v3": cce.DataSourceCCEClusterV3(), - "huaweicloud_cce_node_v3": cce.DataSourceNode(), - "huaweicloud_cce_autopilot_clusters": cceautopilot.DataSourceCceAutopilotClusters(), - "huaweicloud_cce_autopilot_addon_templates": cceautopilot.DataSourceCceAutopilotAddonTemplates(), + "huaweicloud_cce_cluster_v3": cce.DataSourceCCEClusterV3(), + "huaweicloud_cce_node_v3": cce.DataSourceNode(), + "huaweicloud_cce_autopilot_clusters": cceautopilot.DataSourceCceAutopilotClusters(), + "huaweicloud_cce_autopilot_addon_templates": cceautopilot.DataSourceCceAutopilotAddonTemplates(), + "huaweicloud_cce_autopilot_cluster_certificate": cceautopilot.DataSourceCceAutopilotClusterCertificate(), "huaweicloud_dms_product_v1": dms.DataSourceDmsProduct(), "huaweicloud_dms_maintainwindow_v1": dms.DataSourceDmsMaintainWindow(), diff --git a/huaweicloud/services/acceptance/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate_test.go b/huaweicloud/services/acceptance/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate_test.go new file mode 100644 index 0000000000..326037d316 --- /dev/null +++ b/huaweicloud/services/acceptance/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate_test.go @@ -0,0 +1,48 @@ +package cceautopilot + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDataSourceCceAutopilotClusterCertificate_basic(t *testing.T) { + dataSource := "data.huaweicloud_cce_autopilot_cluster_certificate.test" + rName := acceptance.RandomAccResourceNameWithDash() + dc := acceptance.InitDataSourceCheck(dataSource) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acceptance.TestAccPreCheck(t) + }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDataSourceDataSourceCceAutopilotClusterCertificate_basic(rName), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(dataSource, "duration", "30"), + resource.TestCheckResourceAttr(dataSource, "clusters.#", "2"), + resource.TestCheckResourceAttr(dataSource, "users.#", "1"), + resource.TestCheckResourceAttr(dataSource, "contexts.#", "2"), + resource.TestCheckResourceAttrSet(dataSource, "current_context"), + resource.TestCheckResourceAttrSet(dataSource, "kube_config_raw"), + ), + }, + }, + }) +} + +func testDataSourceDataSourceCceAutopilotClusterCertificate_basic(name string) string { + return fmt.Sprintf(` +%[1]s + +data "huaweicloud_cce_autopilot_cluster_certificate" "test" { + cluster_id = huaweicloud_cce_autopilot_cluster.test.id + duration = 30 +} +`, testAccCluster_basic(name)) +} diff --git a/huaweicloud/services/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate.go b/huaweicloud/services/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate.go new file mode 100644 index 0000000000..fa4d135f29 --- /dev/null +++ b/huaweicloud/services/cceautopilot/data_source_huaweicloud_cce_autopilot_cluster_certificate.go @@ -0,0 +1,267 @@ +// Generated by PMS #490 +package cceautopilot + +import ( + "context" + "strings" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/tidwall/gjson" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/helper/httphelper" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/helper/schemas" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +func DataSourceCceAutopilotClusterCertificate() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceCceAutopilotClusterCertificateRead, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: `Specifies the region in which to query the resource. If omitted, the provider-level region will be used.`, + }, + "cluster_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the cluster ID to which the cluster certificate belongs.`, + }, + "duration": { + Type: schema.TypeInt, + Required: true, + Description: `Specifies the duration of the cluster certificate.`, + }, + "kube_config_raw": { + Type: schema.TypeString, + Computed: true, + Description: `Raw Kubernetes config to be used by kubectl and other compatible tools.`, + }, + "clusters": { + Type: schema.TypeList, + Computed: true, + Description: `The clusters information of the cluster certificate.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The cluster name of the cluster certificate.`, + }, + "cluster": { + Type: schema.TypeList, + Computed: true, + Description: `The cluster information.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "server": { + Type: schema.TypeString, + Computed: true, + Description: `The server address of the cluster certificate.`, + }, + "certificate_authority_data": { + Type: schema.TypeString, + Computed: true, + Description: `The certificate authority data of the cluster certificate.`, + }, + "insecure_skip_tls_verify": { + Type: schema.TypeBool, + Computed: true, + Description: `Whether insecure skip tls verify of the cluster certificate.`, + }, + }, + }, + }, + }, + }, + }, + "users": { + Type: schema.TypeList, + Computed: true, + Description: `The users information of cluster the certificate.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The user name of the cluster certificate.`, + }, + "user": { + Type: schema.TypeList, + Computed: true, + Description: `The user information.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_certificate_data": { + Type: schema.TypeString, + Computed: true, + Description: `The client certificate data of the cluster certificate.`, + }, + "client_key_data": { + Type: schema.TypeString, + Computed: true, + Description: `The client key data of the cluster certificate.`, + }, + }, + }, + }, + }, + }, + }, + "contexts": { + Type: schema.TypeList, + Computed: true, + Description: `The contexts information of the cluster certificate.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The context name of the cluster certificate.`, + }, + "context": { + Type: schema.TypeList, + Computed: true, + Description: `The user information.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Computed: true, + Description: `The context cluster of the cluster certificate.`, + }, + "user": { + Type: schema.TypeString, + Computed: true, + Description: `The context user of the cluster certificate.`, + }, + }, + }, + }, + }, + }, + }, + "current_context": { + Type: schema.TypeString, + Computed: true, + Description: `The current context of the cluster certificate.`, + }, + }, + } +} + +type ClusterCertificateDSWrapper struct { + *schemas.ResourceDataWrapper + Config *config.Config +} + +func newClusterCertificateDSWrapper(d *schema.ResourceData, meta interface{}) *ClusterCertificateDSWrapper { + return &ClusterCertificateDSWrapper{ + ResourceDataWrapper: schemas.NewSchemaWrapper(d), + Config: meta.(*config.Config), + } +} + +func dataSourceCceAutopilotClusterCertificateRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + wrapper := newClusterCertificateDSWrapper(d, meta) + creAutKubCluCerRst, err := wrapper.CreateAutopilotKubernetesClusterCert() + if err != nil { + return diag.FromErr(err) + } + + id, err := uuid.GenerateUUID() + if err != nil { + return diag.FromErr(err) + } + d.SetId(id) + + err = wrapper.createAutopilotKubernetesClusterCertToSchema(creAutKubCluCerRst) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +// @API CCE POST /autopilot/v3/projects/{project_id}/clusters/{cluster_id}/clustercert +func (w *ClusterCertificateDSWrapper) CreateAutopilotKubernetesClusterCert() (*gjson.Result, error) { + client, err := w.NewClient(w.Config, "cce") + if err != nil { + return nil, err + } + + uri := "/autopilot/v3/projects/{project_id}/clusters/{cluster_id}/clustercert" + uri = strings.ReplaceAll(uri, "{cluster_id}", w.Get("cluster_id").(string)) + params := map[string]any{ + "duration": w.Get("duration"), + } + params = utils.RemoveNil(params) + return httphelper.New(client). + Method("POST"). + URI(uri). + Body(params). + Request(). + Result() +} + +func (w *ClusterCertificateDSWrapper) createAutopilotKubernetesClusterCertToSchema(body *gjson.Result) error { + d := w.ResourceData + mErr := multierror.Append(nil, + d.Set("region", w.Config.GetRegion(w.ResourceData)), + d.Set("kube_config_raw", utils.JsonToString(body.Value())), + d.Set("clusters", schemas.SliceToList(body.Get("clusters"), + func(clusters gjson.Result) any { + return map[string]any{ + "name": clusters.Get("name").Value(), + "cluster": schemas.SliceToList(clusters.Get("cluster"), + func(cluster gjson.Result) any { + return map[string]any{ + "server": cluster.Get("server").Value(), + "certificate_authority_data": cluster.Get("certificate-authority-data").Value(), + "insecure_skip_tls_verify": cluster.Get("insecure-skip-tls-verify").Value(), + } + }, + ), + } + }, + )), + d.Set("users", schemas.SliceToList(body.Get("users"), + func(users gjson.Result) any { + return map[string]any{ + "name": users.Get("name").Value(), + "user": schemas.SliceToList(users.Get("user"), + func(user gjson.Result) any { + return map[string]any{ + "client_certificate_data": user.Get("client-certificate-data").Value(), + "client_key_data": user.Get("client-key-data").Value(), + } + }, + ), + } + }, + )), + d.Set("contexts", schemas.SliceToList(body.Get("contexts"), + func(contexts gjson.Result) any { + return map[string]any{ + "name": contexts.Get("name").Value(), + "context": schemas.SliceToList(contexts.Get("context"), + func(context gjson.Result) any { + return map[string]any{ + "cluster": context.Get("cluster").Value(), + "user": context.Get("user").Value(), + } + }, + ), + } + }, + )), + d.Set("current_context", body.Get("current-context").Value()), + ) + return mErr.ErrorOrNil() +}