Skip to content

Commit

Permalink
Merge pull request #6 from prdoyle/auth
Browse files Browse the repository at this point in the history
Handle basic auth
  • Loading branch information
prdoyle authored Nov 16, 2023
2 parents 1c1449f + 5c950a5 commit 35dc0da
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 60 deletions.
2 changes: 1 addition & 1 deletion docs/data-sources/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ Bosk state tree node data source

### Required

- `url` (String) The HTTP address of the node
- `path` (String) When appended to the provider base_url, gives the HTTP address of the node
- `value_json` (String) The JSON-encoded contents of the node
5 changes: 3 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ provider "bosk" {
<!-- schema generated by tfplugindocs -->
## Schema

### Optional
### Required

- `endpoint` (String) Node provider attribute
- `base_url` (String) Specifies the URL of the bosk API. Used as a prefix for all HTTP requests. Does not end with a slash.
- `basic_auth_var_suffix` (String) Selects the environment variables to use for HTTP basic authentication; namely TF_BOSK_USERNAME_xxx and TF_BOSK_PASSWORD_xxx. If you don't want to use basic auth, specify NO_AUTH.
2 changes: 1 addition & 1 deletion docs/resources/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ Bosk state tree node data source

### Required

- `url` (String) The HTTP address of the node
- `path` (String) When appended to the provider base_url, gives the HTTP address of the node
- `value_json` (String) The JSON-encoded contents of the node
52 changes: 47 additions & 5 deletions internal/provider/bosk_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,58 @@ import (

type BoskClient struct {
httpClient *http.Client
urlPrefix string
auth *BasicAuth
}

func NewBoskClient(httpClient *http.Client) *BoskClient {
return &BoskClient{httpClient: httpClient}
type BasicAuth struct {
username string
password string
}

func NewBoskClientWithoutAuth(httpClient *http.Client, urlPrefix string) *BoskClient {
return &BoskClient{
httpClient: httpClient,
urlPrefix: urlPrefix,
auth: nil,
}
}

func NewBoskClient(httpClient *http.Client, urlPrefix string, username string, password string) *BoskClient {
return &BoskClient{
httpClient: httpClient,
urlPrefix: urlPrefix,
auth: &BasicAuth{
username: username,
password: password,
},
}
}

// Portions taken from: https://github.com/hashicorp/terraform-provider-http/blob/main/internal/provider/data_source_http.go
func (client *BoskClient) GetJSONAsString(url string, diag *diag.Diagnostics) string {
httpResp, err := client.httpClient.Get(url)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
diag.AddError("Client Error", fmt.Sprintf("Unable to GET node: %s", err))
diag.AddError("Client Error", fmt.Sprintf("Unable to create HTTP request: %s", err))
return "ERROR"
}

if client.auth != nil {
req.SetBasicAuth(client.auth.username, client.auth.password)
}
httpResp, err := client.httpClient.Do(req)
if err != nil {
diag.AddError("Client Error", fmt.Sprintf("Unable to %v %v: %s", req.Method, url, err))
return "ERROR"
}

defer httpResp.Body.Close()

if httpResp.StatusCode/100 != 2 {
diag.AddError("Client Error", fmt.Sprintf("%v %v returned unexpected status %s", req.Method, url, httpResp.Status))
return "ERROR"
}

bytes, err := io.ReadAll(httpResp.Body)
if err != nil {
diag.AddError(
Expand Down Expand Up @@ -75,6 +111,9 @@ func (client *BoskClient) PutJSONAsString(url string, value string, diag *diag.D
diag.AddError("Client Error", fmt.Sprintf("Unable to create HTTP PUT request: %s", err))
return
}
if client.auth != nil {
req.SetBasicAuth(client.auth.username, client.auth.password)
}

httpResp, err := client.httpClient.Do(req)
if err != nil {
Expand All @@ -91,6 +130,9 @@ func (client *BoskClient) PutJSONAsString(url string, value string, diag *diag.D

func (client *BoskClient) Delete(url string, diag *diag.Diagnostics) {
req, err := http.NewRequest("DELETE", url, nil)
if client.auth != nil {
req.SetBasicAuth(client.auth.username, client.auth.password)
}
if err != nil {
diag.AddError("Client Error", fmt.Sprintf("Unable to create HTTP DELETE request: %s", err))
return
Expand All @@ -105,6 +147,6 @@ func (client *BoskClient) Delete(url string, diag *diag.Diagnostics) {
defer httpResp.Body.Close()

if httpResp.StatusCode/100 != 2 {
diag.AddError("Client Error", fmt.Sprintf("PUT returned unexpected status: %s", httpResp.Status))
diag.AddError("Client Error", fmt.Sprintf("DELETE returned unexpected status: %s", httpResp.Status))
}
}
18 changes: 8 additions & 10 deletions internal/provider/node_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package provider
import (
"context"
"fmt"
"net/http"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
Expand All @@ -28,7 +27,7 @@ type NodeDataSource struct {

// NodeDataSourceModel describes the data source data model.
type NodeDataSourceModel struct {
URL types.String `tfsdk:"url"`
Path types.String `tfsdk:"path"`
Value_json types.String `tfsdk:"value_json"`
}

Expand All @@ -41,8 +40,8 @@ func (d *NodeDataSource) Schema(ctx context.Context, req datasource.SchemaReques
MarkdownDescription: "Bosk state tree node data source",

Attributes: map[string]schema.Attribute{
"url": schema.StringAttribute{ // TODO: Separate base URL versus path?
MarkdownDescription: "The HTTP address of the node",
"path": schema.StringAttribute{
MarkdownDescription: "When appended to the provider base_url, gives the HTTP address of the node",
Required: true,
},
"value_json": schema.StringAttribute{
Expand All @@ -59,18 +58,17 @@ func (d *NodeDataSource) Configure(ctx context.Context, req datasource.Configure
return
}

client, ok := req.ProviderData.(*http.Client)
client, ok := req.ProviderData.(*BoskClient)

if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
fmt.Sprintf("Expected *BoskClient, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

d.client = NewBoskClient(client)
d.client = client
}

func (d *NodeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
Expand All @@ -82,15 +80,15 @@ func (d *NodeDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
return
}

result_json := d.client.GetJSONAsString(data.URL.ValueString(), &resp.Diagnostics)
result_json := d.client.GetJSONAsString(d.client.urlPrefix+data.Path.ValueString(), &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

data.Value_json = types.StringValue(result_json)

tflog.Debug(ctx, "read bosk node datasource", map[string]interface{}{
"url": data.URL.ValueString(),
"path": data.Path.ValueString(),
})

// Save data into Terraform state
Expand Down
13 changes: 10 additions & 3 deletions internal/provider/node_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,27 @@ func TestAccNodeDataSource(t *testing.T) {
}))
defer testServer.Close()

base := baseURL(testServer.URL)
path := "/bosk/path/to/object"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Read testing
{
Config: fmt.Sprintf(`
provider "bosk" {
base_url = "%s"
basic_auth_var_suffix = "NO_AUTH"
}
data "bosk_node" "test" {
url = "%s"
path = "%s"
value_json = jsonencode([])
}
`, testServer.URL),
`, base, path),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.bosk_node.test", "url", testServer.URL),
resource.TestCheckResourceAttr("data.bosk_node.test", "path", path),
resource.TestCheckResourceAttr("data.bosk_node.test", "value_json", "[{\"world\":{\"id\":\"world\"}}]"),
),
},
Expand Down
Loading

0 comments on commit 35dc0da

Please sign in to comment.