diff --git a/.goreleaser.yml b/.goreleaser.yml index c6d5162..5eb8601 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -49,7 +49,7 @@ signs: - "${signature}" - "--detach-sign" - "${artifact}" -release: +release: {} # If you want to manually examine the release before its live, uncomment this line: # draft: true changelog: diff --git a/GNUmakefile b/GNUmakefile index ae1f4cd..a8742de 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -3,7 +3,32 @@ NAMESPACE=tsuru NAME=rpaas BINARY=terraform-provider-${NAME} VERSION=$(shell git describe --tags $(git rev-list --tags --max-count=1) | tr -d v) -OS_ARCH=$(shell go env GOOS)_$(shell go env GOARCH) +UNAME_S := $(shell uname -s) +UNAME_P := $(shell uname -p) +ifeq ($(UNAME_S),Linux) + OS := linux + UNAME_P := $(shell uname -m) +endif +ifeq ($(UNAME_S),Darwin) + OS := darwin + UNAME_P := $(shell uname -m) +endif + +ifeq ($(UNAME_P),x86_64) + ARCH := amd64 +endif + +ifneq ($(filter %86,$(UNAME_P)),) + ARCH := 386 +endif +ifneq ($(filter arm%,$(UNAME_P)),) + ARCH := arm +endif +ifeq ($(UNAME_P),arm64) + ARCH := arm64 +endif + +OS_ARCH=${OS}_${ARCH} TFPLUGINDOCS_VERSION ?= v0.16.0 diff --git a/go.mod b/go.mod index c8b027d..00b442c 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0 github.com/stretchr/testify v1.8.4 github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b - github.com/tsuru/rpaas-operator v0.42.4 + github.com/tsuru/rpaas-operator v0.43.0 k8s.io/apimachinery v0.26.2 ) diff --git a/go.sum b/go.sum index e45bb1f..ed687f4 100644 --- a/go.sum +++ b/go.sum @@ -759,8 +759,8 @@ github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b h1:CWioMVdmtk github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18= github.com/tsuru/nginx-operator v0.15.2-0.20240515194244-a38b4b58e866 h1:aCoSpcfQuMztS/7xFrQ2ml02NxqipXYLMgJonyux6fk= github.com/tsuru/nginx-operator v0.15.2-0.20240515194244-a38b4b58e866/go.mod h1:qdJQVY4buUQymyhcpYO99ZCfLMPRvcB/1ywK3PAh/+Q= -github.com/tsuru/rpaas-operator v0.42.4 h1:txpxiYRDYGWokPzOwfCxWk2dX0N3OVWOZ1ltGi4ICKU= -github.com/tsuru/rpaas-operator v0.42.4/go.mod h1:dxlwKGKICcstTwH0sbrrsb9Shsl2/BdDVo7uh1FWWRQ= +github.com/tsuru/rpaas-operator v0.43.0 h1:QLeNUiDFIrHeVwVlzmVieWoBJfAGgC/9DT1rDuafRl8= +github.com/tsuru/rpaas-operator v0.43.0/go.mod h1:dxlwKGKICcstTwH0sbrrsb9Shsl2/BdDVo7uh1FWWRQ= github.com/tsuru/stern v1.20.2-0.20210928180051-1157b938dc3f h1:9dTZI6bQUVkKAsCnqaDl4V7fKAc5ErVpmX+bzevz3Cg= github.com/tsuru/stern v1.20.2-0.20210928180051-1157b938dc3f/go.mod h1:SUQKJ3CLsVARBwkz5z9IIL8Pj008JNj4U8eF50kkm2c= github.com/tsuru/tablecli v0.0.0-20190131152944-7ded8a3383c6 h1:1XDdWFAjIbCSG1OjN9v9KdWhuM8UtYlFcfHe/Ldkchk= diff --git a/internal/provider/resource_rpaas_block.go b/internal/provider/resource_rpaas_block.go index a8210ae..c400a25 100644 --- a/internal/provider/resource_rpaas_block.go +++ b/internal/provider/resource_rpaas_block.go @@ -157,7 +157,7 @@ func resourceRpaasBlockRead(ctx context.Context, d *schema.ResourceData, meta in var blocks []rpaastypes.Block - rpaasRetry(ctx, d.Timeout(schema.TimeoutRead), func() (*http.Response, error) { + err = rpaasRetry(ctx, d.Timeout(schema.TimeoutRead), func() (*http.Response, error) { bs, nerr := rpaasClient.ListBlocks(ctx, rpaas_client.ListBlocksArgs{Instance: instance}) if nerr != nil { return nil, nerr diff --git a/internal/provider/resource_rpaas_cert_manager.go b/internal/provider/resource_rpaas_cert_manager.go index 5c76e1e..e5a8adc 100644 --- a/internal/provider/resource_rpaas_cert_manager.go +++ b/internal/provider/resource_rpaas_cert_manager.go @@ -46,6 +46,12 @@ func resourceRpaasCertManager() *schema.Resource { ForceNew: true, Description: "Certificate issuer name", }, + "certificate_name": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "Certificate Name, required on new version of RPaaS API", + }, "dns_names": { Type: schema.TypeList, Elem: &schema.Schema{ @@ -68,13 +74,18 @@ func resourceRpaasCertManagerCreate(ctx context.Context, d *schema.ResourceData, return diag.Errorf("Unable to create client for service %s: %v", serviceName, err) } - instance, issuer, dnsNames := d.Get("instance").(string), d.Get("issuer").(string), asSliceOfStrings(d.Get("dns_names")) + instance := d.Get("instance").(string) + issuer := d.Get("issuer").(string) + certificateName := d.Get("certificate_name").(string) + + dnsNames := asSliceOfStrings(d.Get("dns_names")) tflog.Info(ctx, "Create rpaas_cert_manager", map[string]interface{}{ - "service": serviceName, - "instance": instance, - "issuer": issuer, - "dnsNames": dnsNames, + "certificate_name": certificateName, + "service": serviceName, + "instance": instance, + "issuer": issuer, + "dnsNames": dnsNames, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutCreate), func() (*http.Response, error) { @@ -82,6 +93,7 @@ func resourceRpaasCertManagerCreate(ctx context.Context, d *schema.ResourceData, return nil, rpaasClient.UpdateCertManager(ctx, rpaas_client.UpdateCertManagerArgs{ Instance: instance, CertManager: types.CertManager{ + Name: certificateName, Issuer: issuer, DNSNames: dnsNames, }, @@ -92,22 +104,35 @@ func resourceRpaasCertManagerCreate(ctx context.Context, d *schema.ResourceData, return diag.Errorf("could not create Cert Manager request: %v", err) } - d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, issuer)) + var id string + if certificateName == "" { + id = fmt.Sprintf("%s::%s::%s", serviceName, instance, issuer) + } else { + id = fmt.Sprintf("%s::%s::%s::%s", serviceName, instance, issuer, certificateName) + } + + d.SetId(id) return resourceRpaasCertManagerRead(ctx, d, meta) } func resourceRpaasCertManagerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - serviceName, instance, issuer, err := parseCertManagerID(d.Id()) + serviceName, instance, issuer, certificateName, err := parseCertManagerID(d.Id()) if err != nil { return diag.Errorf("Unable to parse CertManager ID: %v", err) } - - d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, issuer)) + var id string + if certificateName == "" { + id = fmt.Sprintf("%s::%s::%s", serviceName, instance, issuer) + } else { + id = fmt.Sprintf("%s::%s::%s::%s", serviceName, instance, issuer, certificateName) + } + d.SetId(id) d.Set("service_name", serviceName) d.Set("instance", instance) d.Set("issuer", issuer) + d.Set("certificate_name", certificateName) rpaasClient, err := provider.RpaasClient.SetService(serviceName) if err != nil { @@ -116,7 +141,7 @@ func resourceRpaasCertManagerRead(ctx context.Context, d *schema.ResourceData, m var requests []types.CertManager - rpaasRetry(ctx, d.Timeout(schema.TimeoutRead), func() (*http.Response, error) { + err = rpaasRetry(ctx, d.Timeout(schema.TimeoutRead), func() (*http.Response, error) { r, nerr := rpaasClient.ListCertManagerRequests(ctx, instance) if nerr != nil { return nil, nerr @@ -130,7 +155,7 @@ func resourceRpaasCertManagerRead(ctx context.Context, d *schema.ResourceData, m return diag.Errorf("could not list Cert Manager requests: %v", err) } - request, found := findCertManagerRequestByIssuer(requests, issuer) + request, found := findCertManagerRequestByIssuerAndName(requests, issuer, certificateName) if !found { log.Printf("[DEBUG] Removing resource (ID: %s) from state as it's not found on RPaaS", d.Id()) d.SetId("") @@ -145,7 +170,7 @@ func resourceRpaasCertManagerRead(ctx context.Context, d *schema.ResourceData, m func resourceRpaasCertManagerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - serviceName, instance, issuer, err := parseCertManagerID(d.Id()) + serviceName, instance, issuer, certificateName, err := parseCertManagerID(d.Id()) if err != nil { return diag.Errorf("Unable to parse CertManager ID: %v", err) } @@ -157,16 +182,18 @@ func resourceRpaasCertManagerUpdate(ctx context.Context, d *schema.ResourceData, dnsNames := asSliceOfStrings(d.Get("dns_names")) tflog.Info(ctx, "Update rpaas_cert_manager", map[string]interface{}{ - "service": serviceName, - "instance": instance, - "issuer": issuer, - "dnsNames": dnsNames, + "certificate_name": certificateName, + "service": serviceName, + "instance": instance, + "issuer": issuer, + "dnsNames": dnsNames, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutUpdate), func() (*http.Response, error) { return nil, rpaasClient.UpdateCertManager(ctx, rpaas_client.UpdateCertManagerArgs{ Instance: instance, CertManager: types.CertManager{ + Name: certificateName, Issuer: issuer, DNSNames: dnsNames, }, @@ -180,25 +207,32 @@ func resourceRpaasCertManagerUpdate(ctx context.Context, d *schema.ResourceData, } func resourceRpaasCertManagerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + serviceName, instance, issuer, certificateName, err := parseCertManagerID(d.Id()) + if err != nil { + return diag.Errorf("Unable to parse CertManager ID: %v", err) + } + provider := meta.(*rpaasProvider) - serviceName := d.Get("service_name").(string) rpaasClient, err := provider.RpaasClient.SetService(serviceName) if err != nil { return diag.Errorf("Unable to create client for service %s: %v", serviceName, err) } - instance, issuer := d.Get("instance").(string), d.Get("issuer").(string) - tflog.Info(ctx, "Delete rpaas_cert_manager", map[string]interface{}{ - "service": serviceName, - "instance": instance, - "issuer": issuer, + "certificate_name": certificateName, + "service": serviceName, + "instance": instance, + "issuer": issuer, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutDelete), func() (*http.Response, error) { log.Printf("[DEBUG] Removing Cert Manager certificate request: {Service: %s, Instance: %s, Issuer: %s}", serviceName, instance, issuer) - return nil, rpaasClient.DeleteCertManager(ctx, instance, issuer) + + if certificateName != "" { + return nil, rpaasClient.DeleteCertManagerByName(ctx, instance, certificateName) + } + return nil, rpaasClient.DeleteCertManagerByIssuer(ctx, instance, issuer) }) if err != nil { @@ -208,9 +242,12 @@ func resourceRpaasCertManagerDelete(ctx context.Context, d *schema.ResourceData, return nil } -func findCertManagerRequestByIssuer(reqs []types.CertManager, issuer string) (*types.CertManager, bool) { +func findCertManagerRequestByIssuerAndName(reqs []types.CertManager, issuer, name string) (*types.CertManager, bool) { for _, r := range reqs { if r.Issuer == issuer { + if name != "" && r.Name != name { + continue + } return &r, true } } @@ -227,13 +264,13 @@ func asSliceOfStrings(data interface{}) []string { return values } -func parseCertManagerID(id string) (serviceName, instance, issuer string, err error) { +func parseCertManagerID(id string) (serviceName, instance, issuer, name string, err error) { splitID := strings.Split(id, "::") - if len(splitID) != 3 { + if len(splitID) > 4 || len(splitID) < 3 { serviceName, instance, issuer, err = parseCertManagerID_legacyV0(id) if err != nil { - err = fmt.Errorf("Could not parse id %q. Format should be \"service::instance::issuer\"", id) + err = fmt.Errorf("Could not parse id %q. Format should be \"service::instance::issuer::certificateName\"", id) } return } @@ -241,6 +278,9 @@ func parseCertManagerID(id string) (serviceName, instance, issuer string, err er serviceName = splitID[0] instance = splitID[1] issuer = splitID[2] + if len(splitID) == 4 { + name = splitID[3] // blank on older versions + } return } diff --git a/internal/provider/resource_rpaas_cert_manager_test.go b/internal/provider/resource_rpaas_cert_manager_test.go index 9e56ed8..b6837e3 100644 --- a/internal/provider/resource_rpaas_cert_manager_test.go +++ b/internal/provider/resource_rpaas_cert_manager_test.go @@ -42,7 +42,7 @@ func TestAccRpaasCertManager_basic(t *testing.T) { certManagers, err := testAPIClient.ListCertManagerRequests(context.Background(), "my-rpaas") assert.NoError(t, err) assert.Len(t, certManagers, 1) - certManager, found := findCertManagerRequestByIssuer(certManagers, "my-custom-issuer") + certManager, found := findCertManagerRequestByIssuerAndName(certManagers, "my-custom-issuer", "") assert.True(t, found) assert.Equal(t, "my-custom-issuer", certManager.Issuer) assert.EqualValues(t, []string{"*.example.com", "my-instance.test"}, certManager.DNSNames) @@ -65,7 +65,7 @@ func TestAccRpaasCertManager_basic(t *testing.T) { certManagers, err := testAPIClient.ListCertManagerRequests(context.Background(), "my-rpaas") assert.NoError(t, err) assert.Len(t, certManagers, 1) - certManager, found := findCertManagerRequestByIssuer(certManagers, "my-custom-issuer") + certManager, found := findCertManagerRequestByIssuerAndName(certManagers, "my-custom-issuer", "") assert.True(t, found) assert.Equal(t, "my-custom-issuer", certManager.Issuer) assert.EqualValues(t, []string{"my-instance.test"}, certManager.DNSNames) @@ -76,6 +76,70 @@ func TestAccRpaasCertManager_basic(t *testing.T) { }) } +func TestAccRpaasCertManager_withName(t *testing.T) { + testAPIClient, testAPIServer := setupTestAPIServer(t) + defer testAPIServer.Stop() + + resourceName := "rpaas_cert_manager.cert-manager-custom-issuer" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + ProviderFactories: testAccProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccRpaasCertManagerConfigWithName("my-custom-issuer", "example.com", `["*.example.com", "my-instance.test"]`), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "id", "rpaasv2::my-rpaas::my-custom-issuer::example.com"), + resource.TestCheckResourceAttr(resourceName, "service_name", "rpaasv2"), + resource.TestCheckResourceAttr(resourceName, "instance", "my-rpaas"), + resource.TestCheckResourceAttr(resourceName, "issuer", "my-custom-issuer"), + resource.TestCheckResourceAttr(resourceName, "certificate_name", "example.com"), + resource.TestCheckResourceAttr(resourceName, "dns_names.#", "2"), + resource.TestCheckResourceAttr(resourceName, "dns_names.0", "*.example.com"), + resource.TestCheckResourceAttr(resourceName, "dns_names.1", "my-instance.test"), + func(s *terraform.State) error { + certManagers, err := testAPIClient.ListCertManagerRequests(context.Background(), "my-rpaas") + assert.NoError(t, err) + assert.Len(t, certManagers, 1) + certManager, found := findCertManagerRequestByIssuerAndName(certManagers, "my-custom-issuer", "") + assert.True(t, found) + assert.Equal(t, "example.com", certManager.Name) + assert.Equal(t, "my-custom-issuer", certManager.Issuer) + assert.EqualValues(t, []string{"*.example.com", "my-instance.test"}, certManager.DNSNames) + return nil + }, + ), + }, + { + // Testing Update + Config: testAccRpaasCertManagerConfigWithName("my-custom-issuer", "example.com", `["my-instance.test"]`), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "id", "rpaasv2::my-rpaas::my-custom-issuer::example.com"), + resource.TestCheckResourceAttr(resourceName, "service_name", "rpaasv2"), + resource.TestCheckResourceAttr(resourceName, "instance", "my-rpaas"), + resource.TestCheckResourceAttr(resourceName, "issuer", "my-custom-issuer"), + resource.TestCheckResourceAttr(resourceName, "certificate_name", "example.com"), + resource.TestCheckResourceAttr(resourceName, "dns_names.#", "1"), + resource.TestCheckResourceAttr(resourceName, "dns_names.0", "my-instance.test"), + func(s *terraform.State) error { + certManagers, err := testAPIClient.ListCertManagerRequests(context.Background(), "my-rpaas") + assert.NoError(t, err) + assert.Len(t, certManagers, 1) + certManager, found := findCertManagerRequestByIssuerAndName(certManagers, "my-custom-issuer", "") + assert.True(t, found) + assert.Equal(t, "my-custom-issuer", certManager.Issuer) + assert.Equal(t, "example.com", certManager.Name) + assert.EqualValues(t, []string{"my-instance.test"}, certManager.DNSNames) + return nil + }), + }, + }, + }) +} + func TestAccRpaasCertManager_import(t *testing.T) { testAPIClient, testAPIServer := setupTestAPIServer(t) defer testAPIServer.Stop() @@ -142,3 +206,14 @@ resource "rpaas_cert_manager" "cert-manager-custom-issuer" { dns_names = %s }`, issuer, dnsNamesArray) } + +func testAccRpaasCertManagerConfigWithName(issuer, name, dnsNamesArray string) string { + return fmt.Sprintf(` +resource "rpaas_cert_manager" "cert-manager-custom-issuer" { + instance = "my-rpaas" + service_name = "rpaasv2" + certificate_name = "%s" + issuer = "%s" + dns_names = %s +}`, name, issuer, dnsNamesArray) +} diff --git a/internal/provider/resource_rpaas_certificate.go b/internal/provider/resource_rpaas_certificate.go index 10b7591..60813ae 100644 --- a/internal/provider/resource_rpaas_certificate.go +++ b/internal/provider/resource_rpaas_certificate.go @@ -117,7 +117,7 @@ func resourceRpaasCertificateRead(ctx context.Context, d *schema.ResourceData, m var info *types.InstanceInfo - rpaasRetry(ctx, d.Timeout(schema.TimeoutRead), func() (*http.Response, error) { + err = rpaasRetry(ctx, d.Timeout(schema.TimeoutRead), func() (*http.Response, error) { i, nerr := rpaasClient.Info(ctx, rpaas_client.InfoArgs{Instance: instance}) if nerr != nil { return nil, nerr