add http resource create method
This commit is contained in:
parent
01eaf00bb6
commit
11a55e27d0
@ -11,6 +11,9 @@ _ "errors"
|
|||||||
"net/url"
|
"net/url"
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "os"
|
_ "os"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"log/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -20,19 +23,26 @@ func init() {
|
|||||||
|
|
||||||
func HTTPFactory(u *url.URL) Resource {
|
func HTTPFactory(u *url.URL) Resource {
|
||||||
h := NewHTTP()
|
h := NewHTTP()
|
||||||
|
h.Endpoint = u.String()
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HTTPHeader struct {
|
||||||
|
Name string `yaml:"name" json:"name"`
|
||||||
|
Value string `yaml:"value" json"value"`
|
||||||
|
}
|
||||||
|
|
||||||
// Manage the state of an HTTP endpoint
|
// Manage the state of an HTTP endpoint
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
|
client *http.Client `yaml:"-" json:"-"`
|
||||||
Endpoint string `yaml:"endpoint" json:"endpoint"`
|
Endpoint string `yaml:"endpoint" json:"endpoint"`
|
||||||
|
Headers []HTTPHeader `yaml:"headers,omitempty", json:"headers,omitempty"`
|
||||||
Body string `yaml:"body,omitempty" json:"body,omitempty"`
|
Body string `yaml:"body,omitempty" json:"body,omitempty"`
|
||||||
State string `yaml:"state" json:"state"`
|
State string `yaml:"state" json:"state"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTP() *HTTP {
|
func NewHTTP() *HTTP {
|
||||||
return &HTTP{}
|
return &HTTP{ client: &http.Client{} }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) URI() string {
|
func (h *HTTP) URI() string {
|
||||||
@ -47,36 +57,77 @@ func (h *HTTP) SetURI(uri string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HTTP) JSON() ([]byte, error) {
|
||||||
|
return json.Marshal(h)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *HTTP) Validate() error {
|
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 {
|
func (h *HTTP) Apply() error {
|
||||||
|
|
||||||
switch h.State {
|
switch h.State {
|
||||||
case "absent":
|
case "absent":
|
||||||
case "present":
|
case "present":
|
||||||
}
|
}
|
||||||
|
_,e := h.Read(context.Background())
|
||||||
return nil
|
if e == nil {
|
||||||
|
h.State = "present"
|
||||||
|
}
|
||||||
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) Load(r io.Reader) error {
|
func (h *HTTP) Load(r io.Reader) error {
|
||||||
c := NewYAMLDecoder(r)
|
c := NewYAMLDecoder(r)
|
||||||
return c.Decode(h)
|
return c.Decode(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) LoadDecl(yamlResourceDeclaration string) error {
|
func (h *HTTP) LoadDecl(yamlResourceDeclaration string) error {
|
||||||
c := NewYAMLStringDecoder(yamlResourceDeclaration)
|
slog.Info("LoadDecl()", "yaml", yamlResourceDeclaration)
|
||||||
return c.Decode(h)
|
c := NewYAMLStringDecoder(yamlResourceDeclaration)
|
||||||
|
return c.Decode(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) ResolveId(ctx context.Context) string {
|
func (h *HTTP) ResolveId(ctx context.Context) string {
|
||||||
return h.Endpoint
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -90,6 +141,5 @@ func (h *HTTP) Read(ctx context.Context) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) Type() string {
|
func (h *HTTP) Type() string {
|
||||||
u, _ := url.Parse(h.Endpoint)
|
return "http"
|
||||||
return u.Scheme
|
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,97 @@
|
|||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "context"
|
"context"
|
||||||
_ "encoding/json"
|
_ "encoding/json"
|
||||||
_ "fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
_ "gopkg.in/yaml.v3"
|
_ "gopkg.in/yaml.v3"
|
||||||
_ "io"
|
"io"
|
||||||
_ "log"
|
_ "log"
|
||||||
_ "net/http"
|
"net/http"
|
||||||
_ "net/http/httptest"
|
"net/http/httptest"
|
||||||
_ "net/url"
|
_ "net/url"
|
||||||
_ "os"
|
_ "os"
|
||||||
_ "path/filepath"
|
_ "path/filepath"
|
||||||
_ "strings"
|
_ "strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewHTTPResource(t *testing.T) {
|
func TestNewHTTPResource(t *testing.T) {
|
||||||
f := NewHTTP()
|
h := NewHTTP()
|
||||||
assert.NotNil(t, f)
|
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)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
"oneOf": [
|
"oneOf": [
|
||||||
{ "$ref": "package-declaration.jsonschema" },
|
{ "$ref": "package-declaration.jsonschema" },
|
||||||
{ "$ref": "file-declaration.jsonschema" },
|
{ "$ref": "file-declaration.jsonschema" },
|
||||||
|
{ "$ref": "http-declaration.jsonschema" },
|
||||||
{ "$ref": "user-declaration.jsonschema" },
|
{ "$ref": "user-declaration.jsonschema" },
|
||||||
{ "$ref": "exec-declaration.jsonschema" },
|
{ "$ref": "exec-declaration.jsonschema" },
|
||||||
{ "$ref": "network_route-declaration.jsonschema" }
|
{ "$ref": "network_route-declaration.jsonschema" }
|
||||||
|
17
internal/resource/schemas/http-declaration.jsonschema
Normal file
17
internal/resource/schemas/http-declaration.jsonschema
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
internal/resource/schemas/http.jsonschema
Normal file
31
internal/resource/schemas/http.jsonschema
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user