From 708ff9a87d1ac7981b2867abcd446f9bf481067d Mon Sep 17 00:00:00 2001 From: Calvin Zhang Date: Mon, 23 Dec 2024 10:03:27 -0800 Subject: [PATCH] feat: supported onprem (#9) --- README.md | 26 ++++++------------------- docs/index.md | 6 ++++-- internal/provider/provider.go | 33 ++++++++++++++------------------ internal/timeplus/client.go | 18 ++++++++--------- internal/timeplus/header.go | 22 +++++++++++++++++++++ internal/timeplus/stream.go | 4 ---- internal/timeplus/stream_test.go | 2 +- 7 files changed, 55 insertions(+), 56 deletions(-) create mode 100644 internal/timeplus/header.go diff --git a/README.md b/README.md index e40c302..dd8048d 100644 --- a/README.md +++ b/README.md @@ -21,20 +21,6 @@ The Timeplus provider for Terraform is a plugin that enables full lifecycle mana go install ``` -## Adding Dependencies - -This provider uses [Go modules](https://github.com/golang/go/wiki/Modules). -Please see the Go documentation for the most up to date information about using Go modules. - -To add a new dependency `github.com/author/dependency` to your Terraform provider: - -```shell -go get github.com/author/dependency -go mod tidy -``` - -Then commit the changes to `go.mod` and `go.sum`. - ## Using the provider To use the provider, simply add it to your terraform file, for example: @@ -50,10 +36,10 @@ terraform { } provider "timeplus" { - # the workspace ID can be found in the URL https://us.timeplus.cloud/ - workspace = "my-workspace-id" - # API key is required to use the provider - api_key = "my-api-key" + endpoint = "http://localhost:8000" + workspace = "default" + username = "proton" + password = "proton@t+" } ``` @@ -84,5 +70,5 @@ To generate or update documentation, run `go generate`. ## Useful documentations for provider development -* Timeplus document web site: https://docs.timeplus.com/ -* Terraform plugin framework doc: https://developer.hashicorp.com/terraform/plugin/framework +- Timeplus document web site: https://docs.timeplus.com/ +- Terraform plugin framework doc: https://developer.hashicorp.com/terraform/plugin/framework diff --git a/docs/index.md b/docs/index.md index fd69aff..d009dd7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -36,9 +36,11 @@ provider "timeplus" { ### Required -- `api_key` (String, Sensitive) The API key to be used to call Timeplus API. - `workspace` (String) The ID of the workspace in which the provider manages resources. ### Optional -- `endpoint` (String) The base URL endpoint for connecting to the Timeplus workspace. When it's not set, `https://us.timeplus.cloud` will be used. +- `api_key` (String, Sensitive) [Cloud] The API key to be used to call Timeplus Enterprise Cloud. +- `endpoint` (String) The base URL endpoint for connecting to the Timeplus workspace. When it's not set, `https://us-west-2.timeplus.cloud` will be used. +- `password` (String, Sensitive) [Onprem] The password. +- `username` (String) [Onprem] The username. diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 74c4441..ffe9955 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -32,12 +32,8 @@ type TimeplusProviderModel struct { Endpoint types.String `tfsdk:"endpoint"` Workspace types.String `tfsdk:"workspace"` ApiKey types.String `tfsdk:"api_key"` - - // Ideally we should read this from stream definitions. However, there are 2 limitations - // 1. Proton cluster (e.g. replica = 3) doesn't allow stream with relicatoin_refactor equals other number (e.g. 2) - // 2. Proton get/list stream endpoint doesn't return relicatoin_refactor of the stream - // Thus, we currently define this `replicas` as a provider setting - Replicas types.Int64 `tfsdk:"replicas"` + Username types.String `tfsdk:"username"` + Password types.String `tfsdk:"password"` } func (p *TimeplusProvider) Metadata(ctx context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) { @@ -52,7 +48,7 @@ func (p *TimeplusProvider) Schema(ctx context.Context, req provider.SchemaReques Use the navigation to the left to read about the available resources.`, Attributes: map[string]schema.Attribute{ "endpoint": schema.StringAttribute{ - MarkdownDescription: "The base URL endpoint for connecting to the Timeplus workspace. When it's not set, `https://us.timeplus.cloud` will be used.", + MarkdownDescription: "The base URL endpoint for connecting to the Timeplus workspace. When it's not set, `https://us-west-2.timeplus.cloud` will be used.", Optional: true, Validators: []validator.String{myValidator.URL()}, }, @@ -61,14 +57,19 @@ Use the navigation to the left to read about the available resources.`, Required: true, }, "api_key": schema.StringAttribute{ - MarkdownDescription: "The API key to be used to call Timeplus API.", - Required: true, + MarkdownDescription: "[Cloud] The API key to be used to call Timeplus Enterprise Cloud.", + Optional: true, Sensitive: true, }, - "replicas": schema.Int64Attribute{ - MarkdownDescription: "Number of Proton replicas", - Required: false, + "username": schema.StringAttribute{ + MarkdownDescription: "[Onprem] The username.", + Optional: true, + Sensitive: false, + }, + "password": schema.StringAttribute{ + MarkdownDescription: "[Onprem] The password.", Optional: true, + Sensitive: true, }, }, } @@ -83,14 +84,8 @@ func (p *TimeplusProvider) Configure(ctx context.Context, req provider.Configure return } - var replicas *int - if !(data.Replicas.IsNull() || data.Replicas.IsUnknown()) { - valInt := int(*data.Replicas.ValueInt64Pointer()) - replicas = &valInt - } - // Configuration values are now available. - client, err := timeplus.NewClient(data.Workspace.ValueString(), data.ApiKey.ValueString(), replicas, timeplus.ClientOptions{ + client, err := timeplus.NewClient(data.Workspace.ValueString(), data.ApiKey.ValueString(), data.Username.ValueString(), data.Password.ValueString(), timeplus.ClientOptions{ BaseURL: data.Endpoint.ValueString(), }) if err != nil { diff --git a/internal/timeplus/client.go b/internal/timeplus/client.go index 2cc7d97..ee94e75 100644 --- a/internal/timeplus/client.go +++ b/internal/timeplus/client.go @@ -19,9 +19,8 @@ type resource interface { type Client struct { *http.Client - baseURL *url.URL - apiKey string - replicas *int + baseURL *url.URL + header http.Header } // optional configurations for the client @@ -37,11 +36,11 @@ func (o *ClientOptions) merge(other ClientOptions) { func DefaultOptions() ClientOptions { return ClientOptions{ - BaseURL: "https://us.timeplus.cloud", + BaseURL: "https://us-west-2.timeplus.cloud", } } -func NewClient(workspaceID string, apiKey string, replicas *int, opts ClientOptions) (*Client, error) { +func NewClient(workspaceID string, apiKey, username, password string, opts ClientOptions) (*Client, error) { ops := DefaultOptions() ops.merge(opts) @@ -52,10 +51,9 @@ func NewClient(workspaceID string, apiKey string, replicas *int, opts ClientOpti baseURL = baseURL.JoinPath(workspaceID, "api", "v1beta2") return &Client{ - Client: http.DefaultClient, - baseURL: baseURL, - apiKey: apiKey, - replicas: replicas, + Client: http.DefaultClient, + baseURL: baseURL, + header: NewHeader(apiKey, username, password), }, nil } @@ -119,7 +117,7 @@ func (c *Client) newRequest(method, url string, body io.Reader) (*http.Request, if err != nil { return nil, err } - req.Header.Set("Authorization", "ApiKey "+c.apiKey) + req.Header = c.header return req, nil } diff --git a/internal/timeplus/header.go b/internal/timeplus/header.go new file mode 100644 index 0000000..3527124 --- /dev/null +++ b/internal/timeplus/header.go @@ -0,0 +1,22 @@ +package timeplus + +import ( + "encoding/base64" + "net/http" +) + +// NewHeader creates a standard Timeplus HTTP header. +func NewHeader(apikey, username, password string) http.Header { + header := http.Header{} + + header.Add("Content-Type", "application/json") + + if len(username)+len(password) > 0 { + auth := username + ":" + password + header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth))) + } else if len(apikey) > 0 { + header.Add("X-Api-Key", apikey) + } + + return header +} diff --git a/internal/timeplus/stream.go b/internal/timeplus/stream.go index 234050e..4720422 100644 --- a/internal/timeplus/stream.go +++ b/internal/timeplus/stream.go @@ -84,10 +84,6 @@ func (Stream) resourcePath() string { } func (c *Client) CreateStream(s *Stream) error { - if c.replicas != nil { - s.ReplicationFactor = *c.replicas - } - if err := c.post(s); err != nil { return err } diff --git a/internal/timeplus/stream_test.go b/internal/timeplus/stream_test.go index ee1f6e7..6a07b3b 100644 --- a/internal/timeplus/stream_test.go +++ b/internal/timeplus/stream_test.go @@ -16,7 +16,7 @@ func newClient(t *testing.T) *timeplus.Client { } else { t.Logf("found API key: %s[=== scrubbed ===]", apiKey[:8]) } - c, err := timeplus.NewClient("latest", apiKey, timeplus.ClientOptions{ + c, err := timeplus.NewClient("latest", apiKey, "", "", timeplus.ClientOptions{ BaseURL: "https://dev.timeplus.cloud", }) if err != nil {