add http resource create method
Some checks failed
Lint / golangci-lint (push) Failing after 9m54s
Declarative Tests / test (push) Successful in 1m21s

This commit is contained in:
Matthew Rich 2024-04-10 12:38:12 -07:00
parent 01eaf00bb6
commit 11a55e27d0
5 changed files with 193 additions and 20 deletions

View File

@ -11,6 +11,9 @@ _ "errors"
"net/url"
"net/http"
_ "os"
"encoding/json"
"strings"
"log/slog"
)
func init() {
@ -20,19 +23,26 @@ func init() {
func HTTPFactory(u *url.URL) Resource {
h := NewHTTP()
h.Endpoint = u.String()
return h
}
type HTTPHeader struct {
Name string `yaml:"name" json:"name"`
Value string `yaml:"value" json"value"`
}
// Manage the state of an HTTP endpoint
type HTTP struct {
client *http.Client `yaml:"-" json:"-"`
Endpoint string `yaml:"endpoint" json:"endpoint"`
Headers []HTTPHeader `yaml:"headers,omitempty", json:"headers,omitempty"`
Body string `yaml:"body,omitempty" json:"body,omitempty"`
State string `yaml:"state" json:"state"`
}
func NewHTTP() *HTTP {
return &HTTP{}
return &HTTP{ client: &http.Client{} }
}
func (h *HTTP) URI() string {
@ -47,36 +57,77 @@ func (h *HTTP) SetURI(uri string) error {
return nil
}
func (h *HTTP) JSON() ([]byte, error) {
return json.Marshal(h)
}
func (h *HTTP) Validate() error {
return fmt.Errorf("failed")
s := NewSchema(h.Type())
jsonDoc, jsonErr := h.JSON()
if jsonErr == nil {
return s.Validate(string(jsonDoc))
}
return jsonErr
}
func (h *HTTP) Apply() error {
switch h.State {
case "absent":
case "present":
}
return nil
_,e := h.Read(context.Background())
if e == nil {
h.State = "present"
}
return e
}
func (h *HTTP) Load(r io.Reader) error {
c := NewYAMLDecoder(r)
return c.Decode(h)
c := NewYAMLDecoder(r)
return c.Decode(h)
}
func (h *HTTP) LoadDecl(yamlResourceDeclaration string) error {
c := NewYAMLStringDecoder(yamlResourceDeclaration)
return c.Decode(h)
slog.Info("LoadDecl()", "yaml", yamlResourceDeclaration)
c := NewYAMLStringDecoder(yamlResourceDeclaration)
return c.Decode(h)
}
func (h *HTTP) ResolveId(ctx context.Context) string {
return h.Endpoint
}
func (h *HTTP) Create() error {
body := strings.NewReader(h.Body)
req, reqErr := http.NewRequest("POST", h.Endpoint, body)
if reqErr != nil {
return reqErr
}
for _,header := range h.Headers {
req.Header.Add(header.Name, header.Value)
}
resp, err := h.client.Do(req)
defer resp.Body.Close()
if err != nil {
return err
}
return err
}
func (h *HTTP) Read(ctx context.Context) ([]byte, error) {
resp, err := http.Get(h.Endpoint)
req, reqErr := http.NewRequestWithContext(ctx, "GET", h.Endpoint, nil)
if reqErr != nil {
return nil, reqErr
}
slog.Info("HTTP.Read() ", "request", req, "err", reqErr)
if len(h.Headers) > 0 {
for _,header := range h.Headers {
req.Header.Add(header.Name, header.Value)
}
}
resp, err := h.client.Do(req)
if err != nil {
return nil, err
}
@ -90,6 +141,5 @@ func (h *HTTP) Read(ctx context.Context) ([]byte, error) {
}
func (h *HTTP) Type() string {
u, _ := url.Parse(h.Endpoint)
return u.Scheme
return "http"
}

View File

@ -3,23 +3,97 @@
package resource
import (
_ "context"
"context"
_ "encoding/json"
_ "fmt"
"fmt"
"github.com/stretchr/testify/assert"
_ "gopkg.in/yaml.v3"
_ "io"
"io"
_ "log"
_ "net/http"
_ "net/http/httptest"
"net/http"
"net/http/httptest"
_ "net/url"
_ "os"
_ "path/filepath"
_ "strings"
"testing"
"regexp"
)
func TestNewHTTPResource(t *testing.T) {
f := NewHTTP()
assert.NotNil(t, f)
h := NewHTTP()
assert.NotNil(t, h)
}
func TestHTTPDecode(t *testing.T) {
h := NewHTTP()
assert.NotNil(t, h)
decl:=`
endpoint: "https://example.foo"
body: |-
test body
`
assert.Nil(t, h.LoadDecl(decl))
assert.Equal(t, "test body", h.Body)
}
func TestHTTPRead(t *testing.T) {
h := NewHTTP()
assert.NotNil(t, h)
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
assert.Equal(t, req.URL.String(), "/resource/user/foo")
rw.Write([]byte(`
type: "user"
attributes:
name: "foo"
gecos: "foo user"
`))
}))
defer server.Close()
decl := fmt.Sprintf(`
endpoint: "%s/resource/user/foo"
`, server.URL)
assert.Nil(t, h.LoadDecl(decl))
_,e := h.Read(context.Background())
assert.Nil(t, e)
assert.Greater(t, len(h.Body), 0)
assert.Nil(t, h.Validate())
}
func TestHTTPCreate(t *testing.T) {
userdecl := `
type: "user"
attributes:
name: "foo"
gecos: "foo user"
`
h := NewHTTP()
assert.NotNil(t, h)
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
assert.Equal(t, req.URL.String(), "/resource/user")
body, err := io.ReadAll(req.Body)
assert.Nil(t, err)
assert.Equal(t, userdecl, string(body))
}))
defer server.Close()
re := regexp.MustCompile(`(?m)^(.*)$`)
decl := fmt.Sprintf(`
endpoint: "%s/resource/user"
headers:
- name: "content-type"
value: "application/yaml"
body: |
%s
`, server.URL, re.ReplaceAllString(userdecl, " $1"))
assert.Nil(t, h.LoadDecl(decl))
assert.Greater(t, len(h.Body), 0)
e := h.Create()
assert.Nil(t, e)
}

View File

@ -12,6 +12,7 @@
"oneOf": [
{ "$ref": "package-declaration.jsonschema" },
{ "$ref": "file-declaration.jsonschema" },
{ "$ref": "http-declaration.jsonschema" },
{ "$ref": "user-declaration.jsonschema" },
{ "$ref": "exec-declaration.jsonschema" },
{ "$ref": "network_route-declaration.jsonschema" }

View File

@ -0,0 +1,17 @@
{
"$id": "http-declaration.jsonschema",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "http-declaration",
"type": "object",
"required": [ "type", "attributes" ],
"properties": {
"type": {
"type": "string",
"description": "Resource type name.",
"enum": [ "http" ]
},
"attributes": {
"$ref": "http.jsonschema"
}
}
}

View File

@ -0,0 +1,31 @@
{
"$id": "http.jsonschema",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "http",
"type": "object",
"required": [ "endpoint" ],
"properties": {
"endpoint": {
"type": "string"
},
"headers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "HTTP header name"
},
"value": {
"type": "string",
"description": "HTTP header value"
}
}
}
},
"body": {
"type": "string"
}
}
}