Skip to content

Commit

Permalink
Merge pull request #35 from planetscale/provider-docs-and-validators
Browse files Browse the repository at this point in the history
Accept all args as provider config, use validators, some provider docs.
  • Loading branch information
aybabtme authored Oct 12, 2023
2 parents 3354e79 + cc0ec09 commit d12d6e7
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 23 deletions.
6 changes: 6 additions & 0 deletions doc/dependency_decisions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,9 @@
:why:
:versions: []
:when: 2023-09-25 21:56:32.197702000 Z
- - :approve
- github.com/hashicorp/terraform-plugin-framework-validators
- :who:
:why:
:versions: []
:when: 2023-10-11 21:59:00.000000000 Z
15 changes: 12 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
page_title: "planetscale Provider"
subcategory: ""
description: |-
The PlanetScale provider allows using the OpenAPI surface of our public API. To use this provider, one of the following are required:
access token credentials, configured or stored in the environment variable PLANETSCALE_ACCESS_TOKENservice token credentials, configured or stored in the environment variables PLANETSCALE_SERVICE_TOKEN_NAME and PLANETSCALE_SERVICE_TOKEN
Note that the provider is not production ready and only for early testing at this time.
---

# planetscale Provider

The PlanetScale provider allows using the OpenAPI surface of our public API. To use this provider, one of the following are required:

- access token credentials, configured or stored in the environment variable `PLANETSCALE_ACCESS_TOKEN`
- service token credentials, configured or stored in the environment variables `PLANETSCALE_SERVICE_TOKEN_NAME` and `PLANETSCALE_SERVICE_TOKEN`

Note that the provider is not production ready and only for early testing at this time.

## Example Usage

Expand All @@ -31,5 +38,7 @@ provider "planetscale" {

### Optional

- `endpoint` (String) Example provider attribute
- `service_token_name` (String) Name of the service token to use
- `access_token` (String, Sensitive) Name of the service token to use. Alternatively, use `PLANETSCALE_SERVICE_TOKEN_NAME`. Mutually exclusive with `service_token_name` and `service_token`.
- `endpoint` (String) If set, points the API client to a different endpoint than `https:://api.planetscale.com/v1`.
- `service_token` (String, Sensitive) Value of the service token to use. Alternatively, use `PLANETSCALE_SERVICE_TOKEN`. Mutually exclusive with `access_token`.
- `service_token_name` (String) Name of the service token to use. Alternatively, use `PLANETSCALE_SERVICE_TOKEN_NAME`. Mutually exclusive with `access_token`.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ require (
github.com/go-openapi/loads v0.21.2
github.com/go-openapi/spec v0.20.9
github.com/hashicorp/terraform-plugin-docs v0.16.0
github.com/hashicorp/terraform-plugin-framework v1.3.3
github.com/hashicorp/terraform-plugin-framework v1.3.5
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
github.com/hashicorp/terraform-plugin-go v0.18.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.5.1
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,10 @@ github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQH
github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o=
github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI=
github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA=
github.com/hashicorp/terraform-plugin-framework v1.3.3 h1:D18BlA8gdV4+W8WKhUqxudiYomPZHv94FFzyoSCKC8Q=
github.com/hashicorp/terraform-plugin-framework v1.3.3/go.mod h1:2gGDpWiTI0irr9NSTLFAKlTi6KwGti3AoU19rFqU30o=
github.com/hashicorp/terraform-plugin-framework v1.3.5 h1:FJ6s3CVWVAxlhiF/jhy6hzs4AnPHiflsp9KgzTGl1wo=
github.com/hashicorp/terraform-plugin-framework v1.3.5/go.mod h1:2gGDpWiTI0irr9NSTLFAKlTi6KwGti3AoU19rFqU30o=
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc=
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg=
github.com/hashicorp/terraform-plugin-go v0.18.0 h1:IwTkOS9cOW1ehLd/rG0y+u/TGLK9y6fGoBjXVUquzpE=
github.com/hashicorp/terraform-plugin-go v0.18.0/go.mod h1:l7VK+2u5Kf2y+A+742GX0ouLut3gttudmvMgN0PA74Y=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
Expand Down
81 changes: 66 additions & 15 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import (
"net/url"
"os"

"github.com/hashicorp/terraform-plugin-framework-validators/providervalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
Expand All @@ -20,33 +23,71 @@ import (
"golang.org/x/oauth2"
)

var _ provider.Provider = &PlanetScaleProvider{}
var _ provider.ProviderWithConfigValidators = &PlanetScaleProvider{}

type PlanetScaleProvider struct {
version string
debug bool
}

type PlanetScaleProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`

ServiceTokenName types.String `tfsdk:"service_token_name"`
AccessToken types.String `tfsdk:"access_token"`

ServiceTokenName types.String `tfsdk:"service_token_name"`
ServiceTokenValue types.String `tfsdk:"service_token_value"`
}

func (p *PlanetScaleProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "planetscale"
resp.Version = p.version
}

func (p *PlanetScaleProvider) ConfigValidators(context.Context) []provider.ConfigValidator {
return []provider.ConfigValidator{
providervalidator.Conflicting(path.MatchRoot("access_token"), path.MatchRoot("service_token")),
providervalidator.Conflicting(path.MatchRoot("access_token"), path.MatchRoot("service_token_name")),
providervalidator.RequiredTogether(path.MatchRoot("service_token"), path.MatchRoot("service_token_name")),
}
}

func (p *PlanetScaleProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: `The PlanetScale provider allows using the OpenAPI surface of our public API. To use this provider, one of the following are required:
- access token credentials, configured or stored in the environment variable ` + "`PLANETSCALE_ACCESS_TOKEN`" + `
- service token credentials, configured or stored in the environment variables ` + "`PLANETSCALE_SERVICE_TOKEN_NAME`" + ` and ` + "`PLANETSCALE_SERVICE_TOKEN`" + `
Note that the provider is not production ready and only for early testing at this time.`,
Attributes: map[string]schema.Attribute{
"endpoint": schema.StringAttribute{
MarkdownDescription: "Example provider attribute",
MarkdownDescription: "If set, points the API client to a different endpoint than `https:://api.planetscale.com/v1`.",
Optional: true,
},
"access_token": schema.StringAttribute{
MarkdownDescription: "Name of the service token to use. Alternatively, use `PLANETSCALE_SERVICE_TOKEN_NAME`. Mutually exclusive with `service_token_name` and `service_token`.",
Optional: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.ConflictsWith(path.MatchRoot("service_token_name")),
stringvalidator.ConflictsWith(path.MatchRoot("service_token")),
},
},
"service_token_name": schema.StringAttribute{
MarkdownDescription: "Name of the service token to use",
MarkdownDescription: "Name of the service token to use. Alternatively, use `PLANETSCALE_SERVICE_TOKEN_NAME`. Mutually exclusive with `access_token`.",
Optional: true,
Validators: []validator.String{
stringvalidator.ConflictsWith(path.MatchRoot("access_token_name")),
},
},
"service_token": schema.StringAttribute{
MarkdownDescription: "Value of the service token to use. Alternatively, use `PLANETSCALE_SERVICE_TOKEN`. Mutually exclusive with `access_token`.",
Optional: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.ConflictsWith(path.MatchRoot("access_token_name")),
},
},
},
}
Expand All @@ -60,15 +101,20 @@ func (p *PlanetScaleProvider) Configure(ctx context.Context, req provider.Config
}

var (
initrt http.RoundTripper
rt http.RoundTripper
baseURL *url.URL
)
if !p.debug {
initrt = http.DefaultTransport
} else {
initrt = debugRoundTripper(func(req, res []byte) {
tflog.Debug(ctx, "roundtripper", map[string]interface{}{
"req": string(req),
"res": string(res),
})
}, http.DefaultTransport)
rt http.RoundTripper
baseURL *url.URL
)
}
if !data.Endpoint.IsNull() {
u, err := url.Parse(data.Endpoint.ValueString())
if err != nil {
Expand All @@ -78,13 +124,10 @@ func (p *PlanetScaleProvider) Configure(ctx context.Context, req provider.Config
baseURL = u
}
var (
accessToken = os.Getenv("PLANETSCALE_ACCESS_TOKEN")
serviceTokenName = os.Getenv("PLANETSCALE_SERVICE_TOKEN_NAME")
serviceTokenValue = os.Getenv("PLANETSCALE_SERVICE_TOKEN")
accessToken = stringValueOrDefault(data.AccessToken, os.Getenv("PLANETSCALE_ACCESS_TOKEN"))
serviceTokenName = stringValueOrDefault(data.ServiceTokenName, os.Getenv("PLANETSCALE_SERVICE_TOKEN_NAME"))
serviceTokenValue = stringValueOrDefault(data.ServiceTokenValue, os.Getenv("PLANETSCALE_SERVICE_TOKEN"))
)
if !data.ServiceTokenName.IsNull() {
serviceTokenName = data.ServiceTokenName.ValueString()
}
switch {
case accessToken != "" && serviceTokenName == "" && serviceTokenValue == "":
tok := &oauth2.Token{AccessToken: accessToken}
Expand All @@ -104,7 +147,7 @@ func (p *PlanetScaleProvider) Configure(ctx context.Context, req provider.Config
resp.Diagnostics.AddError("Incomplete PlanetScale service token credentials.",
"Both of `PLANETSCALE_SERVICE_TOKEN_NAME` and `PLANETSCALE_SERVICE_TOKEN` must be set.")
default:
resp.Diagnostics.AddError("Ambiguous PlanetScale credentials.", "You must set only either of an access token or a service token, but not both:\n"+
resp.Diagnostics.AddError("Ambiguous PlanetScale credentials.", "You must set only an access token or a service token, but not both:\n"+
"- `PLANETSCALE_ACCESS_TOKEN`\n"+
"- `PLANETSCALE_SERVICE_TOKEN_NAME` and `PLANETSCALE_SERVICE_TOKEN`")
}
Expand Down Expand Up @@ -149,10 +192,11 @@ func (p *PlanetScaleProvider) DataSources(ctx context.Context) []func() datasour
}
}

func New(version string) func() provider.Provider {
func New(version string, debug bool) func() provider.Provider {
return func() provider.Provider {
return &PlanetScaleProvider{
version: version,
debug: debug,
}
}
}
Expand Down Expand Up @@ -211,3 +255,10 @@ func stringValueIfKnown(v basetypes.StringValue) *string {
}
return v.ValueStringPointer()
}

func stringValueOrDefault(v basetypes.StringValue, def string) string {
if v.IsUnknown() || v.IsNull() {
return def
}
return v.ValueString()
}
2 changes: 1 addition & 1 deletion internal/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"planetscale": providerserver.NewProtocol6WithError(New("test")()),
"planetscale": providerserver.NewProtocol6WithError(New("test", false)()),
}

func testAccPreCheck(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func main() {
Debug: debug,
}

err := providerserver.Serve(context.Background(), provider.New(version), opts)
err := providerserver.Serve(context.Background(), provider.New(version, debug), opts)

if err != nil {
log.Fatal(err.Error())
Expand Down

0 comments on commit d12d6e7

Please sign in to comment.