diff --git a/internal/resource/document.go b/internal/resource/document.go index 2fd8c9a..aad2b0d 100644 --- a/internal/resource/document.go +++ b/internal/resource/document.go @@ -76,7 +76,7 @@ func (d *Document) Apply() error { } slog.Info("Document.Apply()", "declarations", d) for i := range d.ResourceDecls { - if e := d.ResourceDecls[i].Resource().Apply(); e != nil { + if e := d.ResourceDecls[i].Apply(); e != nil { return e } } diff --git a/internal/resource/file.go b/internal/resource/file.go index 61ac861..0bc0e8e 100644 --- a/internal/resource/file.go +++ b/internal/resource/file.go @@ -114,6 +114,7 @@ func (f *File) StateMachine() machine.Stater { func (f *File) Notify(m *machine.EventMessage) { ctx := context.Background() + slog.Info("Notify()", "file", f, "m", m) switch m.On { case machine.ENTERSTATEEVENT: switch m.Dest { @@ -276,6 +277,7 @@ func (f *File) Create(ctx context.Context) error { if chownErr := os.Chown(f.Path, uid, gid); chownErr != nil { return chownErr } + f.State = "present" return nil } diff --git a/internal/source/decl.go b/internal/source/decl.go index aca1e64..41959d7 100644 --- a/internal/source/decl.go +++ b/internal/source/decl.go @@ -10,8 +10,9 @@ _ "gopkg.in/yaml.v3" "net/url" "path/filepath" "decl/internal/resource" + "decl/internal/transport" "regexp" - "os" +_ "os" "io" "compress/gzip" "errors" @@ -20,6 +21,7 @@ _ "gopkg.in/yaml.v3" type DeclFile struct { Path string `yaml:"path" json:"path"` + transport *transport.Reader `yaml:"-" json:"-"` } func NewDeclFile() *DeclFile { @@ -30,6 +32,7 @@ func init() { SourceTypes.Register([]string{"decl"}, func(u *url.URL) DocSource { t := NewDeclFile() t.Path,_ = filepath.Abs(filepath.Join(u.Hostname(), u.RequestURI())) + t.transport,_ = transport.NewReader(u) return t }) @@ -41,6 +44,7 @@ func init() { } else { t.Path = filepath.Join(u.Hostname(), u.Path) } + t.transport,_ = transport.NewReader(u) return t }) @@ -51,26 +55,24 @@ func (d *DeclFile) Type() string { return "decl" } func (d *DeclFile) ExtractResources(filter ResourceSelector) ([]*resource.Document, error) { documents := make([]*resource.Document, 0, 100) - //documents = append(documents, resource.NewDocument()) GzipFileName := regexp.MustCompile(`^.*\.gz$`) - - file, fileErr := os.Open(d.Path) - if fileErr != nil { - return documents, fileErr - } + + defer d.transport.Close() + var fileReader io.Reader if GzipFileName.FindString(d.Path) == d.Path { slog.Info("decompressing gzip", "path", d.Path) - zr, err := gzip.NewReader(file) + zr, err := gzip.NewReader(d.transport) if err != nil { return documents, err } fileReader = zr } else { - fileReader = file + fileReader = d.transport } + decoder := resource.NewYAMLDecoder(fileReader) slog.Info("ExtractResources()", "documents", documents) index := 0 diff --git a/internal/source/http.go b/internal/source/http.go index 07c5cc2..6f71577 100644 --- a/internal/source/http.go +++ b/internal/source/http.go @@ -5,14 +5,15 @@ package source import ( _ "context" _ "encoding/json" - "fmt" +_ "fmt" _ "gopkg.in/yaml.v3" "net/url" - "net/http" +_ "net/http" _ "path/filepath" "decl/internal/resource" "decl/internal/iofilter" "decl/internal/signature" + "decl/internal/transport" _ "os" "io" "errors" @@ -21,6 +22,7 @@ _ "os" type HTTP struct { Endpoint string `yaml:"endpoint" json:"endpoint"` + transport *transport.Reader `yaml:"-" json:"-"` } func NewHTTP() *HTTP { @@ -31,6 +33,7 @@ func init() { SourceTypes.Register([]string{"http","https"}, func(u *url.URL) DocSource { t := NewHTTP() t.Endpoint = u.String() + t.transport,_ = transport.NewReader(u) return t }) } @@ -40,25 +43,11 @@ func (d *HTTP) Type() string { return "http" } func (h *HTTP) ExtractResources(filter ResourceSelector) ([]*resource.Document, error) { documents := make([]*resource.Document, 0, 100) - resp, err := http.Get(h.Endpoint) - if err != nil { - return documents, err - } - defer resp.Body.Close() - documentSignature := resp.Header.Get("Signature") - if documentSignature == "" { - signatureResp, signatureErr := http.Get(fmt.Sprintf("%s.sig", h.Endpoint)) - if signatureErr == nil { - defer signatureResp.Body.Close() - readSignatureBody, readSignatureErr := io.ReadAll(resp.Body) - if readSignatureErr == nil { - documentSignature = string(readSignatureBody) - } - } - } + defer h.transport.Close() + documentSignature := h.transport.Signature() hash := sha256.New() - sumReadData := iofilter.NewReader(resp.Body, func(p []byte, readn int, readerr error) (n int, err error) { + sumReadData := iofilter.NewReader(h.transport, func(p []byte, readn int, readerr error) (n int, err error) { hash.Write(p) return }) diff --git a/internal/source/tar.go b/internal/source/tar.go index 3769504..e8dfe66 100644 --- a/internal/source/tar.go +++ b/internal/source/tar.go @@ -10,15 +10,17 @@ _ "gopkg.in/yaml.v3" "net/url" "path/filepath" "decl/internal/resource" + "decl/internal/transport" "compress/gzip" "archive/tar" "regexp" - "os" +_ "os" "io" ) type Tar struct { Path string `yaml:"path" json:"path"` + transport *transport.Reader `yaml:"-" json:"-"` } func NewTar() *Tar { @@ -29,6 +31,7 @@ func init() { SourceTypes.Register([]string{"tar"}, func(u *url.URL) DocSource { t := NewTar() t.Path,_ = filepath.Abs(filepath.Join(u.Hostname(), u.Path)) + t.transport,_ = transport.NewReader(u) return t }) @@ -40,6 +43,7 @@ func init() { } else { t.Path = filepath.Join(u.Hostname(), u.Path) } + t.transport,_ = transport.NewReader(u) return t }) @@ -56,14 +60,12 @@ func (t *Tar) ExtractResources(filter ResourceSelector) ([]*resource.Document, e TarGzipFileName := regexp.MustCompile(`^.*\.(tar\.gz|tgz)$`) TarFileName := regexp.MustCompile(`^.*\.tar$`) - file, fileErr := os.Open(t.Path) - if fileErr != nil { - return documents, fileErr - } + defer t.transport.Close() + var gzipReader io.Reader switch t.Path { case TarGzipFileName.FindString(t.Path): - zr, err := gzip.NewReader(file) + zr, err := gzip.NewReader(t.transport) if err != nil { return documents, err } @@ -72,7 +74,7 @@ func (t *Tar) ExtractResources(filter ResourceSelector) ([]*resource.Document, e case TarFileName.FindString(t.Path): var fileReader io.Reader if gzipReader == nil { - fileReader = file + fileReader = t.transport } else { fileReader = gzipReader } diff --git a/internal/transport/transport.go b/internal/transport/transport.go new file mode 100644 index 0000000..f8c29e5 --- /dev/null +++ b/internal/transport/transport.go @@ -0,0 +1,72 @@ +// Copyright 2024 Matthew Rich . All rights reserved. + +package transport + +import ( +_ "errors" + "fmt" + "net/url" + "net/http" +_ "strings" + "path/filepath" + "io" + "os" +) + +type Reader struct { + uri *url.URL + handle any + stream io.ReadCloser +} + +func NewReader(u *url.URL) (*Reader, error) { + var e error + r := &Reader{ uri: u } + switch u.Scheme { + case "http", "https": + resp, err := http.Get(u.String()) + r.handle = resp + r.stream = resp.Body + e = err + case "file": + fallthrough + default: + path := filepath.Join(u.Hostname(), u.RequestURI()) + file, err := os.Open(path) + r.handle = file + r.stream = file + e = err + } + return r, e +} + +type Writer struct { + +} + +func NewWriter(url *url.URL) (*Writer, error) { + return nil, nil +} + +func (r *Reader) Read(b []byte) (int, error) { + return r.stream.Read(b) +} + +func (r *Reader) Close() error { + return r.stream.Close() +} + +func (r *Reader) Signature() string { + documentSignature := r.handle.(*http.Response).Header.Get("Signature") + if documentSignature == "" { + signatureResp, signatureErr := http.Get(fmt.Sprintf("%s.sig", r.uri.String())) + if signatureErr == nil { + defer signatureResp.Body.Close() + readSignatureBody, readSignatureErr := io.ReadAll(signatureResp.Body) + if readSignatureErr == nil { + documentSignature = string(readSignatureBody) + } + } + } + return documentSignature +} diff --git a/internal/transport/transport_test.go b/internal/transport/transport_test.go new file mode 100644 index 0000000..b20c4dc --- /dev/null +++ b/internal/transport/transport_test.go @@ -0,0 +1,40 @@ +// Copyright 2024 Matthew Rich . All rights reserved. + +package transport + +import ( + "github.com/stretchr/testify/assert" + "net/url" + "testing" + "fmt" + "os" + "log" +) + +var TempDir string + +func TestMain(m *testing.M) { + var err error + TempDir, err = os.MkdirTemp("", "testtransportfile") + if err != nil || TempDir == "" { + log.Fatal(err) + } + + rc := m.Run() + + os.RemoveAll(TempDir) + os.Exit(rc) +} + +func TestNewTransportReader(t *testing.T) { + path := fmt.Sprintf("%s/foo", TempDir) + u, e := url.Parse(fmt.Sprintf("file://%s", path)) + assert.Nil(t, e) + + writeErr := os.WriteFile(path, []byte("test"), 0644) + assert.Nil(t, writeErr) + + reader, err := NewReader(u) + assert.Nil(t, err) + assert.NotNil(t, reader) +}