Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C294 intro autogen subdomains #9

Merged
merged 4 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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