Skip to content

Commit

Permalink
Merge pull request #9 from nullstone-io/C294-intro-autogen-subdomains
Browse files Browse the repository at this point in the history
squash merge C294-intro-autogen-subdomains
  • Loading branch information
ssickles authored Apr 23, 2021
2 parents 49a0e14 + d107fff commit 7b26ec6
Show file tree
Hide file tree
Showing 9 changed files with 393 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ require (
github.com/hashicorp/terraform-plugin-sdk/v2 v2.3.0
github.com/nullstone-io/module v0.2.3
github.com/stretchr/testify v1.5.1
gopkg.in/nullstone-io/go-api-client.v0 v0.0.0-20210419161255-60ff46ef629c
gopkg.in/nullstone-io/go-api-client.v0 v0.0.0-20210422145113-1def18026731
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/nullstone-io/go-api-client.v0 v0.0.0-20210419161255-60ff46ef629c h1:X7CI5hCviuyx66WuO3Hcic4DH+o/fFVKKRuZdHBpneg=
gopkg.in/nullstone-io/go-api-client.v0 v0.0.0-20210419161255-60ff46ef629c/go.mod h1:6z3xyBE0tWngWi5equdUPGtEKClza3g5hpSkQKWLid8=
gopkg.in/nullstone-io/go-api-client.v0 v0.0.0-20210422145113-1def18026731 h1:Xvwk1m7Zqjl+pueoSGlh9ylN0fv1xCVMsMQvqRO5DdA=
gopkg.in/nullstone-io/go-api-client.v0 v0.0.0-20210422145113-1def18026731/go.mod h1:6z3xyBE0tWngWi5equdUPGtEKClza3g5hpSkQKWLid8=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
96 changes: 96 additions & 0 deletions internal/provider/data_domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package provider

import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov5/tftypes"
"gopkg.in/nullstone-io/go-api-client.v0"
"strconv"
)

type dataDomain struct {
p *provider
}

func newDataDomain(p *provider) (*dataDomain, error) {
if p == nil {
return nil, fmt.Errorf("a provider is required")
}
return &dataDomain{p: p}, nil
}

func (*dataDomain) Schema(ctx context.Context) *tfprotov5.Schema {
return &tfprotov5.Schema{
Version: 1,
Block: &tfprotov5.SchemaBlock{
Description: "Data source to read a nullstone domain.",
DescriptionKind: tfprotov5.StringKindMarkdown,
Attributes: []*tfprotov5.SchemaAttribute{
deprecatedIDAttribute(),
{
Name: "stack",
Type: tftypes.String,
Description: "The domain belongs to this stack",
Required: true,
DescriptionKind: tfprotov5.StringKindMarkdown,
},
{
Name: "block",
Type: tftypes.String,
Description: "The domain belongs to this block (in the specified stack)",
Required: true,
DescriptionKind: tfprotov5.StringKindMarkdown,
},
{
Name: "dns_name",
Type: tftypes.String,
Description: "The DNS name defined on the domain",
Computed: true,
DescriptionKind: tfprotov5.StringKindMarkdown,
},
},
},
}
}

func (d *dataDomain) Validate(ctx context.Context, config map[string]tftypes.Value) ([]*tfprotov5.Diagnostic, error) {
return nil, nil
}

func (d *dataDomain) Read(ctx context.Context, config map[string]tftypes.Value) (map[string]tftypes.Value, []*tfprotov5.Diagnostic, error) {
nsConfig := d.p.NsConfig
nsClient := api.Client{Config: nsConfig}

diags := make([]*tfprotov5.Diagnostic, 0)

stack := extractStringFromConfig(config, "stack")
block := extractStringFromConfig(config, "block")

var domainId int
var dnsName string

domain, err := nsClient.Domains().Get(stack, block)
if err != nil {
diags = append(diags, &tfprotov5.Diagnostic{
Severity: tfprotov5.DiagnosticSeverityError,
Summary: "Unable to find nullstone domain.",
Detail: err.Error(),
})
} else if domain != nil {
domainId = domain.Id
dnsName = domain.DnsName
} else {
diags = append(diags, &tfprotov5.Diagnostic{
Severity: tfprotov5.DiagnosticSeverityError,
Summary: fmt.Sprintf("The domain in the stack %q and block %q does not exist in nullstone.", stack, block),
})
}

return map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, strconv.Itoa(domainId)),
"stack": tftypes.NewValue(tftypes.String, stack),
"block": tftypes.NewValue(tftypes.String, block),
"dns_name": tftypes.NewValue(tftypes.String, dnsName),
}, diags, nil
}
72 changes: 72 additions & 0 deletions internal/provider/data_domain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package provider

import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"net/http"
"regexp"
"testing"
)

func TestDataDomain(t *testing.T) {
t.Run("fails to find non-existent domain", func(t *testing.T) {
tfconfig := fmt.Sprintf(`
provider "ns" {
organization = "org0"
}
data "ns_domain" "domain" {
stack = "global"
block = "nullstone-io"
}
`)

checks := resource.ComposeTestCheckFunc()

getNsConfig, closeNsFn := mockNs(http.NotFoundHandler())
defer closeNsFn()
getTfeConfig, _ := mockTfe(nil)

resource.UnitTest(t, resource.TestCase{
ProtoV5ProviderFactories: protoV5ProviderFactories(getNsConfig, getTfeConfig),
Steps: []resource.TestStep{
{
Config: tfconfig,
Check: checks,
ExpectError: regexp.MustCompile(`The domain in the stack "global" and block "nullstone-io" does not exist in nullstone.`),
},
},
})
})

t.Run("sets up attributes properly", func(t *testing.T) {
tfconfig := fmt.Sprintf(`
provider "ns" {
organization = "org0"
}
data "ns_domain" "domain" {
stack = "global"
block = "nullstone-io"
}
`)

checks := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.ns_domain.domain", `stack`, "global"),
resource.TestCheckResourceAttr("data.ns_domain.domain", `block`, "nullstone-io"),
resource.TestCheckResourceAttr("data.ns_domain.domain", `dns_name`, "nullstone.io"),
)

getNsConfig, closeNsFn := mockNs(mockNsServerWithDomains())
defer closeNsFn()
getTfeConfig, _ := mockTfe(nil)

resource.UnitTest(t, resource.TestCase{
ProtoV5ProviderFactories: protoV5ProviderFactories(getNsConfig, getTfeConfig),
Steps: []resource.TestStep{
{
Config: tfconfig,
Check: checks,
},
},
})
})
}
96 changes: 96 additions & 0 deletions internal/provider/data_subdomain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package provider

import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov5/tftypes"
"gopkg.in/nullstone-io/go-api-client.v0"
"strconv"
)

type dataSubdomain struct {
p *provider
}

func newDataSubdomain(p *provider) (*dataSubdomain, error) {
if p == nil {
return nil, fmt.Errorf("a provider is required")
}
return &dataSubdomain{p: p}, nil
}

func (*dataSubdomain) Schema(ctx context.Context) *tfprotov5.Schema {
return &tfprotov5.Schema{
Version: 1,
Block: &tfprotov5.SchemaBlock{
Description: "Data source to read a nullstone subdomain.",
DescriptionKind: tfprotov5.StringKindMarkdown,
Attributes: []*tfprotov5.SchemaAttribute{
deprecatedIDAttribute(),
{
Name: "stack",
Type: tftypes.String,
Description: "The subdomain belongs to this stack",
Required: true,
DescriptionKind: tfprotov5.StringKindMarkdown,
},
{
Name: "block",
Type: tftypes.String,
Description: "The subdomain belongs to this block (in the specified stack)",
Required: true,
DescriptionKind: tfprotov5.StringKindMarkdown,
},
{
Name: "dns_name",
Type: tftypes.String,
Description: "The DNS name defined on the subdomain",
Computed: true,
DescriptionKind: tfprotov5.StringKindMarkdown,
},
},
},
}
}

func (d *dataSubdomain) Validate(ctx context.Context, config map[string]tftypes.Value) ([]*tfprotov5.Diagnostic, error) {
return nil, nil
}

func (d *dataSubdomain) Read(ctx context.Context, config map[string]tftypes.Value) (map[string]tftypes.Value, []*tfprotov5.Diagnostic, error) {
nsConfig := d.p.NsConfig
nsClient := api.Client{Config: nsConfig}

diags := make([]*tfprotov5.Diagnostic, 0)

stack := extractStringFromConfig(config, "stack")
block := extractStringFromConfig(config, "block")

var subdomainId int
var dnsName string

subdomain, err := nsClient.Subdomains().Get(stack, block)
if err != nil {
diags = append(diags, &tfprotov5.Diagnostic{
Severity: tfprotov5.DiagnosticSeverityError,
Summary: "Unable to find nullstone subdomain.",
Detail: err.Error(),
})
} else if subdomain != nil {
subdomainId = subdomain.Id
dnsName = subdomain.DnsName
} else {
diags = append(diags, &tfprotov5.Diagnostic{
Severity: tfprotov5.DiagnosticSeverityError,
Summary: fmt.Sprintf("The subdomain in the stack %q and block %q does not exist in nullstone.", stack, block),
})
}

return map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, strconv.Itoa(subdomainId)),
"stack": tftypes.NewValue(tftypes.String, stack),
"block": tftypes.NewValue(tftypes.String, block),
"dns_name": tftypes.NewValue(tftypes.String, dnsName),
}, diags, nil
}
72 changes: 72 additions & 0 deletions internal/provider/data_subdomain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package provider

import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"net/http"
"regexp"
"testing"
)

func TestDataSubdomain(t *testing.T) {
t.Run("fails to find non-existent subdomain", func(t *testing.T) {
tfconfig := fmt.Sprintf(`
provider "ns" {
organization = "org0"
}
data "ns_subdomain" "subdomain" {
stack = "demo"
block = "api-subdomain"
}
`)

checks := resource.ComposeTestCheckFunc()

getNsConfig, closeNsFn := mockNs(http.NotFoundHandler())
defer closeNsFn()
getTfeConfig, _ := mockTfe(nil)

resource.UnitTest(t, resource.TestCase{
ProtoV5ProviderFactories: protoV5ProviderFactories(getNsConfig, getTfeConfig),
Steps: []resource.TestStep{
{
Config: tfconfig,
Check: checks,
ExpectError: regexp.MustCompile(`The subdomain in the stack "demo" and block "api-subdomain" does not exist in nullstone.`),
},
},
})
})

t.Run("sets up attributes properly", func(t *testing.T) {
tfconfig := fmt.Sprintf(`
provider "ns" {
organization = "org0"
}
data "ns_subdomain" "subdomain" {
stack = "demo"
block = "api-subdomain"
}
`)

checks := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.ns_subdomain.subdomain", `stack`, "demo"),
resource.TestCheckResourceAttr("data.ns_subdomain.subdomain", `block`, "api-subdomain"),
resource.TestCheckResourceAttr("data.ns_subdomain.subdomain", `dns_name`, "api"),
)

getNsConfig, closeNsFn := mockNs(mockNsServerWithSubdomains())
defer closeNsFn()
getTfeConfig, _ := mockTfe(nil)

resource.UnitTest(t, resource.TestCase{
ProtoV5ProviderFactories: protoV5ProviderFactories(getNsConfig, getTfeConfig),
Steps: []resource.TestStep{
{
Config: tfconfig,
Check: checks,
},
},
})
})
}
25 changes: 25 additions & 0 deletions internal/provider/domain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package provider

import (
"encoding/json"
"github.com/gorilla/mux"
"gopkg.in/nullstone-io/go-api-client.v0/types"
"net/http"
)

func mockNsServerWithDomains() http.Handler {
router := mux.NewRouter()
router.
Methods(http.MethodGet).
Path("/orgs/{orgName}/stacks/{stackName}/domains/{domainName}").
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
domain := types.Domain{
DnsName: "nullstone.io",
OrgName: "org0",
StackName: "global",
}
raw, _ := json.Marshal(domain)
w.Write(raw)
})
return router
}
4 changes: 4 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ func New(version string, getNsConfig func() api.Config, getTfeConfig func() *tfe
// data sources
s.MustRegisterDataSource("ns_workspace", newDataWorkspace)
s.MustRegisterDataSource("ns_connection", newDataConnection)
s.MustRegisterDataSource("ns_subdomain", newDataSubdomain)
s.MustRegisterDataSource("ns_domain", newDataDomain)

// resources
s.MustRegisterDataSource("ns_autogen_subdomain", newDataAutogenSubdomain)
s.MustRegisterResource("ns_autogen_subdomain", newResourceAutogenSubdomain)
s.MustRegisterResource("ns_autogen_subdomain_delegation", newResourceAutogenSubdomainDelegation)
Expand Down
Loading

0 comments on commit 7b26ec6

Please sign in to comment.