Skip to content

Commit

Permalink
feat: allow additional methods in http datasource
Browse files Browse the repository at this point in the history
This adds support for additional http methods for the http datasource.
Fixes #13169

Signed-off-by: Henrik Gerdes <[email protected]>
  • Loading branch information
hegerdes authored and lbajolet-hashicorp committed Oct 29, 2024
1 parent 6e417bb commit 6c40bfb
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 4 deletions.
36 changes: 33 additions & 3 deletions datasource/http/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ import (

type Config struct {
common.PackerConfig `mapstructure:",squash"`
// The URL to request data from. This URL must respond with a `200 OK` response and a `text/*` or `application/json` Content-Type.
// The URL to request data from. This URL must respond with a `2xx` range response code and a `text/*` or `application/json` Content-Type.
Url string `mapstructure:"url" required:"true"`
// HTTP method used for the request. Supported methods are `HEAD`, `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS`, `PATCH`. Default is `GET`.
Method string `mapstructure:"method" required:"false"`
// A map of strings representing additional HTTP headers to include in the request.
RequestHeaders map[string]string `mapstructure:"request_headers" required:"false"`
// HTTP request payload send with the request. Default is empty.
RequestBody string `mapstructure:"request_body" required:"false"`
}

type Datasource struct {
Expand Down Expand Up @@ -62,6 +66,26 @@ func (d *Datasource) Configure(raws ...interface{}) error {
fmt.Errorf("the `url` must be specified"))
}

// Default to GET if no method is specified
if d.config.Method == "" {
d.config.Method = "GET"
}

// Check if the input is in the list of allowed methods
validMethod := false
allowedMethods := []string{"HEAD", "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"}
for _, method := range allowedMethods {
if method == d.config.Method {
validMethod = true
break
}
}
if !validMethod {
errs = packersdk.MultiErrorAppend(
errs,
fmt.Errorf("the `method` must be one of %v", allowedMethods))
}

if errs != nil && len(errs.Errors) > 0 {
return errs
}
Expand Down Expand Up @@ -102,10 +126,16 @@ func isContentTypeText(contentType string) bool {
// https://github.com/hashicorp/terraform-provider-http/blob/main/internal/provider/data_source.go
func (d *Datasource) Execute() (cty.Value, error) {
ctx := context.TODO()
url, headers := d.config.Url, d.config.RequestHeaders
url, method, headers := d.config.Url, d.config.Method, d.config.RequestHeaders
client := &http.Client{}

req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
// Create request body if it is provided
var requestBody io.Reader
if d.config.RequestBody != "" {
requestBody = strings.NewReader(d.config.RequestBody)
}

req, err := http.NewRequestWithContext(ctx, method, url, requestBody)
// TODO: How to make a test case for this?
if err != nil {
fmt.Println("Error creating http request")
Expand Down
4 changes: 4 additions & 0 deletions datasource/http/data.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions datasource/http/data_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var testDatasourceEmptyUrl string
//go:embed test-fixtures/404_url.pkr.hcl
var testDatasource404Url string

//go:embed test-fixtures/invalid_method.pkr.hcl
var testDatasourceInvalidMethod string

func TestHttpDataSource(t *testing.T) {
tests := []struct {
Name string
Expand All @@ -49,6 +52,14 @@ func TestHttpDataSource(t *testing.T) {
"error": "the `url` must be specified",
},
},
{
Name: "method_is_invalid",
Path: testDatasourceInvalidMethod,
Error: true,
Outputs: map[string]string{
"error": "the `method` must be one of [HEAD GET POST PUT DELETE OPTIONS PATCH]",
},
},
{
Name: "404_url",
Path: testDatasource404Url,
Expand Down
26 changes: 26 additions & 0 deletions datasource/http/test-fixtures/invalid_method.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
source "null" "example" {
communicator = "none"
}

data "http" "basic" {
url = "https://www.packer.io/"
method = "NONEEXISTING"
}

locals {
url = "${data.http.basic.url}"
body = "${data.http.basic.body}" != ""
}

build {
name = "mybuild"
sources = [
"source.null.example"
]
provisioner "shell-local" {
inline = [
"echo url is ${local.url}",
"echo body is ${local.body}"
]
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<!-- Code generated from the comments of the Config struct in datasource/http/data.go; DO NOT EDIT MANUALLY -->

- `method` (string) - HTTP method used for the request. Supported methods are `HEAD`, `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS`, `PATCH`. Default is `GET`.

- `request_headers` (map[string]string) - A map of strings representing additional HTTP headers to include in the request.

- `request_body` (string) - HTTP request payload send with the request. Default is empty.

<!-- End of code generated from the comments of the Config struct in datasource/http/data.go; -->
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- Code generated from the comments of the Config struct in datasource/http/data.go; DO NOT EDIT MANUALLY -->

- `url` (string) - The URL to request data from. This URL must respond with a `200 OK` response and a `text/*` or `application/json` Content-Type.
- `url` (string) - The URL to request data from. This URL must respond with a `2xx` range response code and a `text/*` or `application/json` Content-Type.

<!-- End of code generated from the comments of the Config struct in datasource/http/data.go; -->

0 comments on commit 6c40bfb

Please sign in to comment.