Skip to content

Commit

Permalink
Craft tsuru_certificate_issuer resource
Browse files Browse the repository at this point in the history
  • Loading branch information
wpjunior committed Nov 22, 2024
1 parent fcf21e1 commit 249dda2
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/labstack/echo/v4 v4.9.1
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.9.0
github.com/tsuru/go-tsuruclient v0.0.0-20240409125509-22a1e08326f4
github.com/tsuru/go-tsuruclient v0.0.0-20241122210020-b97d66b89165
github.com/tsuru/tsuru-client v0.0.0-20240325204824-8c0dc602a5be
k8s.io/apimachinery v0.26.2
)
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ github.com/tsuru/gnuflag v0.0.0-20151217162021-86b8c1b864aa h1:JlLQP1xa13a994p/A
github.com/tsuru/gnuflag v0.0.0-20151217162021-86b8c1b864aa/go.mod h1:UibOSvkMFKRe/eiwktAPAvQG8L+p8nYsECJvu3Dgw7I=
github.com/tsuru/go-tsuruclient v0.0.0-20240409125509-22a1e08326f4 h1:MGmG6AxKP8XRe7nQqIQR+Tsb5tCzHnYpYk0tiuXVgxY=
github.com/tsuru/go-tsuruclient v0.0.0-20240409125509-22a1e08326f4/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18=
github.com/tsuru/go-tsuruclient v0.0.0-20241114131333-e45b7f4741d8 h1:qYTfCDEqp1Zc4dT3J4F16eTvrkuXvHkeBTtJZrdvwRw=
github.com/tsuru/go-tsuruclient v0.0.0-20241114131333-e45b7f4741d8/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18=
github.com/tsuru/go-tsuruclient v0.0.0-20241122182258-89f15daca17c h1:JFirEZjWW/PbHqQ4DE7kPfplDxqxmNgZwtU1gi9P0Aw=
github.com/tsuru/go-tsuruclient v0.0.0-20241122182258-89f15daca17c/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18=
github.com/tsuru/go-tsuruclient v0.0.0-20241122182551-a810edb7c845 h1:tQA0PAHmYww0xZ8xlpY5GJ/qDK5IjlHuC0zrBNF0/pY=
github.com/tsuru/go-tsuruclient v0.0.0-20241122182551-a810edb7c845/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18=
github.com/tsuru/go-tsuruclient v0.0.0-20241122210020-b97d66b89165 h1:sDC3Z+/pfdviUdLIH2Tcxa2tVR6FSiTRIR0kWkK8iiQ=
github.com/tsuru/go-tsuruclient v0.0.0-20241122210020-b97d66b89165/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18=
github.com/tsuru/tablecli v0.0.0-20190131152944-7ded8a3383c6 h1:1XDdWFAjIbCSG1OjN9v9KdWhuM8UtYlFcfHe/Ldkchk=
github.com/tsuru/tablecli v0.0.0-20190131152944-7ded8a3383c6/go.mod h1:ztYpOhW+u1k21FEqp7nZNgpWbr0dUKok5lgGCZi+1AQ=
github.com/tsuru/tsuru v0.0.0-20240325190920-410c71393b77 h1:cuWFjNLaemdQZhojqJbb/rOXO97tlcPeLAHg/x+EQGk=
Expand Down
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ func Provider() *schema.Provider {
"tsuru_app_deploy": resourceTsuruApplicationDeploy(),
"tsuru_app": resourceTsuruApplication(),

"tsuru_certificate_issuer": resourceTsuruCertificateIssuer(),

"tsuru_job": resourceTsuruJob(),
"tsuru_job_env": resourceTsuruJobEnvironment(),
"tsuru_job_deploy": resourceTsuruJobDeploy(),
Expand Down
157 changes: 157 additions & 0 deletions internal/provider/resource_tsuru_certificate_issuer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright 2024 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package provider

import (
"context"
"sort"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/tsuru/go-tsuruclient/pkg/tsuru"
)

func resourceTsuruCertificateIssuer() *schema.Resource {
return &schema.Resource{
Description: "Set a issuer to generate certificates to a tsuru application",
CreateContext: resourceTsuruCertificateIssuerSet,
ReadContext: resourceTsuruCertificateIssuerRead,
DeleteContext: resourceTsuruCertificateIssuerUnset,
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(60 * time.Minute),
Update: schema.DefaultTimeout(60 * time.Minute),
Delete: schema.DefaultTimeout(60 * time.Minute),
},
Importer: &schema.ResourceImporter{
StateContext: resourceTsuruApplicationImport,
},
Schema: map[string]*schema.Schema{
"app": {
Type: schema.TypeString,
Description: "Application name",
Required: true,
ForceNew: true,
},

"cname": {
Type: schema.TypeString,
Description: "Application CNAME",
Required: true,
ForceNew: true,
},

"issuer": {
Type: schema.TypeString,
Description: "Certificate Issuer",
Required: true,
ForceNew: true,
},

"router": {
Type: schema.TypeList,
Description: "Routers that are using the certificate",
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"certificate": {
Type: schema.TypeList,
Description: "Certificate Generated by Issuer, filled after the certificate is ready",
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"ready": {
Type: schema.TypeBool,
Description: "If the certificate is ready",
Computed: true,
},
},
}
}

func resourceTsuruCertificateIssuerSet(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
provider := meta.(*tsuruProvider)

app := d.Get("app").(string)
cname := d.Get("cname").(string)
issuer := d.Get("issuer").(string)

_, err := provider.TsuruClient.AppApi.AppSetCertIssuer(context.Background(), app, tsuru.CertIssuerSetData{
Cname: cname,
Issuer: issuer,
})

if err != nil {
return diag.Errorf("unable to set certificate issuer: %v", err)
}

d.SetId(app + "::" + cname + "::" + issuer)

return resourceTsuruCertificateIssuerRead(ctx, d, meta)
}

func resourceTsuruCertificateIssuerUnset(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
provider := meta.(*tsuruProvider)
parts, err := IDtoParts(d.Id(), 3)
if err != nil {
return diag.FromErr(err)
}
app := parts[0]
cname := parts[1]

_, err = provider.TsuruClient.AppApi.AppUnsetCertIssuer(context.Background(), app, cname)

if err != nil {
return diag.Errorf("unable to unset certificate issuer: %v", err)
}

return resourceTsuruCertificateIssuerRead(ctx, d, meta)
}

func resourceTsuruCertificateIssuerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
provider := meta.(*tsuruProvider)
parts, err := IDtoParts(d.Id(), 3)
if err != nil {
return diag.FromErr(err)
}
app := parts[0]
cname := parts[1]
issuer := parts[2]

certificates, _, err := provider.TsuruClient.AppApi.AppGetCertificates(context.Background(), app)
if err != nil {
return diag.FromErr(err)
}

usedRouters := []string{}
usedCertificates := []string{}

for routerName, router := range certificates.Routers {
if cnameInRouter, ok := router.Cnames[cname]; ok {
if cnameInRouter.Issuer == issuer {
usedRouters = append(usedRouters, routerName)

if cnameInRouter.Certificate != "" {
usedCertificates = append(usedCertificates, cnameInRouter.Certificate)
}
}
}
}

sort.Strings(usedRouters)
sort.Strings(usedCertificates)

d.Set("app", app)
d.Set("cname", cname)
d.Set("issuer", issuer)

d.Set("router", usedRouters)
d.Set("certificate", usedCertificates)
d.Set("ready", len(usedCertificates) > 0)

return nil
}
111 changes: 111 additions & 0 deletions internal/provider/resource_tsuru_certificate_issuer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2021 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package provider

import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
echo "github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tsuru/go-tsuruclient/pkg/tsuru"
)

func TestAccTsuruCertificateIssuer(t *testing.T) {
fakeServer := echo.New()
fakeServer.PUT("/1.24/apps/:app/certissuer", func(c echo.Context) error {
p := &tsuru.CertIssuerSetData{}
err := c.Bind(p)
require.NoError(t, err)
assert.Equal(t, "my-app", c.Param("app"))
assert.Equal(t, "my-cname.org", p.Cname)
assert.Equal(t, "lets-encrypt", p.Issuer)

return nil
})

fakeServer.DELETE("/1.24/apps/:app/certissuer", func(c echo.Context) error {
assert.Equal(t, "my-app", c.Param("app"))
assert.Equal(t, "my-cname.org", c.QueryParam("cname"))

return nil
})
fakeServer.GET("/1.24/apps/:app/certificate", func(c echo.Context) error {
assert.Equal(t, "my-app", c.Param("app"))

return c.JSON(http.StatusOK, tsuru.AppCertificates{
Routers: map[string]tsuru.AppCertificatesRouters{
"https-router": {
Cnames: map[string]tsuru.AppCertificatesCnames{
"my-cname.org": {
Issuer: "lets-encrypt",
Certificate: "123",
},

"other-cname.org": {
Issuer: "self-signed",
Certificate: "321",
},
},
},
"other-https-router": {
Cnames: map[string]tsuru.AppCertificatesCnames{
"my-cname.org": {
Issuer: "rapid-ssl",
Certificate: "123",
},

"other-cname.org": {
Issuer: "self-signed",
Certificate: "4321",
},
},
},
},
})
})

fakeServer.HTTPErrorHandler = func(err error, c echo.Context) {
t.Errorf("method=%s, path=%s, err=%s", c.Request().Method, c.Path(), err.Error())
}

server := httptest.NewServer(fakeServer)
os.Setenv("TSURU_TARGET", server.URL)

resourceName := "tsuru_certificate_issuer.cert"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: "tsuru_certificate_issuer.cert",
ProviderFactories: testAccProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccTsuruCertificateIssuer("my-app", "my-cname.org", "lets-encrypt"),
ExpectNonEmptyPlan: false,
Check: resource.ComposeAggregateTestCheckFunc(
testAccResourceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "app", "my-app"),
resource.TestCheckResourceAttr(resourceName, "cname", "my-cname.org"),
resource.TestCheckResourceAttr(resourceName, "issuer", "lets-encrypt"),
),
},
},
})
}

func testAccTsuruCertificateIssuer(app, cname, issuer string) string {
return fmt.Sprintf(`
resource "tsuru_certificate_issuer" "cert" {
app = %q
cname = %q
issuer = %q
}
`, app, cname, issuer)
}

0 comments on commit 249dda2

Please sign in to comment.