add support for file resource access/mod times
All checks were successful
Declarative Tests / test (push) Successful in 53s

This commit is contained in:
Matthew Rich 2024-03-24 18:36:21 -07:00
parent 0f82fde55d
commit ce95306eb1
6 changed files with 77 additions and 25 deletions

View File

@ -125,24 +125,6 @@ func (c *Container) LoadDecl(yamlFileResourceDeclaration string) error {
return c.loader(yamlFileResourceDeclaration, c) return c.loader(yamlFileResourceDeclaration, c)
} }
/*
apiClient, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
panic(err)
}
defer apiClient.Close()
containers, err := apiClient.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
panic(err)
}
for _, ctr := range containers {
fmt.Printf("%s %s (status: %s)\n", ctr.ID, ctr.Image, ctr.Status)
}
}
*/
func (c *Container) Create(ctx context.Context) error { func (c *Container) Create(ctx context.Context) error {
numberOfEnvironmentVariables := len(c.Environment) numberOfEnvironmentVariables := len(c.Environment)
config := &container.Config { config := &container.Config {

View File

@ -1,4 +1,6 @@
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved. // Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
//
package resource package resource
import ( import (

View File

@ -6,7 +6,7 @@ package resource
import ( import (
"context" "context"
"fmt" "fmt"
_ "log" "log/slog"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -73,11 +73,12 @@ func (d *Declaration) Resource() Resource {
} }
func (d *Declaration) SetURI(uri string) error { func (d *Declaration) SetURI(uri string) error {
slog.Info("SetURI()", "uri", uri)
d.Implementation = NewResource(uri) d.Implementation = NewResource(uri)
if d.Implementation == nil { if d.Implementation == nil {
panic("unknown resource") panic("unknown resource")
} }
d.Type = d.Implementation.Type() d.Type = d.Implementation.Type()
d.Implementation.Read(context.Background()) // fix d.Implementation.Read(context.Background()) // fix context
return nil return nil
} }

View File

@ -10,6 +10,8 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"time"
"syscall"
) )
func TestNewDocumentLoader(t *testing.T) { func TestNewDocumentLoader(t *testing.T) {
@ -71,6 +73,15 @@ func TestDocumentGenerator(t *testing.T) {
err := os.WriteFile(file, []byte(fileContent), 0644) err := os.WriteFile(file, []byte(fileContent), 0644)
assert.Nil(t, err) assert.Nil(t, err)
info,statErr := os.Stat(file)
assert.Nil(t, statErr)
mTime := info.ModTime()
stat, ok := info.Sys().(*syscall.Stat_t)
assert.True(t, ok)
aTime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
cTime := time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec))
expected := fmt.Sprintf(` expected := fmt.Sprintf(`
resources: resources:
- type: file - type: file
@ -81,9 +92,12 @@ resources:
mode: "0644" mode: "0644"
content: | content: |
%s %s
atime: %s
ctime: %s
mtime: %s
filetype: "regular" filetype: "regular"
state: present state: present
`, file, fileContent) `, file, fileContent, aTime.Format(time.RFC3339Nano), cTime.Format(time.RFC3339Nano), mTime.Format(time.RFC3339Nano))
var documentYaml strings.Builder var documentYaml strings.Builder
d := NewDocument() d := NewDocument()
@ -101,7 +115,7 @@ resources:
assert.Equal(t, nil, ey) assert.Equal(t, nil, ey)
assert.Greater(t, documentYaml.Len(), 0) assert.Greater(t, documentYaml.Len(), 0)
assert.YAMLEq(t, documentYaml.String(), expected) assert.YAMLEq(t, expected, documentYaml.String())
} }
func TestDocumentAddResource(t *testing.T) { func TestDocumentAddResource(t *testing.T) {

View File

@ -15,6 +15,7 @@ import (
"strconv" "strconv"
"path/filepath" "path/filepath"
"net/url" "net/url"
"time"
) )
type FileType string type FileType string
@ -46,6 +47,11 @@ type File struct {
Owner string `yaml:"owner"` Owner string `yaml:"owner"`
Group string `yaml:"group"` Group string `yaml:"group"`
Mode string `yaml:"mode"` Mode string `yaml:"mode"`
Atime time.Time `yaml:"atime",omitempty`
Ctime time.Time `yaml:"ctime",omitempty`
Mtime time.Time `yaml:"mtime",omitempty`
Content string `yaml:"content",omitempty` Content string `yaml:"content",omitempty`
FileType FileType `yaml:"filetype"` FileType FileType `yaml:"filetype"`
State string `yaml:"state"` State string `yaml:"state"`
@ -114,6 +120,11 @@ func (f *File) Apply() error {
if writeErr != nil { if writeErr != nil {
return writeErr return writeErr
} }
if ! f.Mtime.IsZero() && ! f.Atime.IsZero() {
if chtimesErr := os.Chtimes(f.Path, f.Atime, f.Mtime); chtimesErr != nil {
return chtimesErr
}
}
} }
if chownErr := os.Chown(f.Path, uid, gid); chownErr != nil { if chownErr := os.Chown(f.Path, uid, gid); chownErr != nil {
@ -152,7 +163,12 @@ func (f *File) Read(ctx context.Context) ([]byte, error) {
panic(e) panic(e)
} }
f.Mtime = info.ModTime()
if stat, ok := info.Sys().(*syscall.Stat_t); ok { if stat, ok := info.Sys().(*syscall.Stat_t); ok {
f.Atime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
f.Ctime = time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec))
userId := strconv.Itoa(int(stat.Uid)) userId := strconv.Itoa(int(stat.Uid))
groupId := strconv.Itoa(int(stat.Gid)) groupId := strconv.Itoa(int(stat.Gid))
fileUser, userErr := user.LookupId(userId) fileUser, userErr := user.LookupId(userId)

View File

@ -16,6 +16,8 @@ import (
"path/filepath" "path/filepath"
_ "strings" _ "strings"
"testing" "testing"
"time"
"syscall"
) )
func TestNewFileResource(t *testing.T) { func TestNewFileResource(t *testing.T) {
@ -35,17 +37,22 @@ func TestReadFile(t *testing.T) {
ctx := context.Background() ctx := context.Background()
file, _ := filepath.Abs(filepath.Join(TempDir, "fooread.txt")) file, _ := filepath.Abs(filepath.Join(TempDir, "fooread.txt"))
decl := fmt.Sprintf(` declarationAttributes := `
path: "%s" path: "%s"
owner: "nobody" owner: "nobody"
group: "nobody" group: "nobody"
mode: "0600" mode: "0600"
atime: 2001-12-15T01:01:01.000000001Z
ctime: %s
mtime: 2001-12-15T01:01:01.000000001Z
content: |- content: |-
test line 1 test line 1
test line 2 test line 2
filetype: "regular" filetype: "regular"
state: present state: present
`, file) `
decl := fmt.Sprintf(declarationAttributes, file, "2001-12-15T01:01:01.000000001Z")
testFile := NewFile() testFile := NewFile()
e := testFile.LoadDecl(decl) e := testFile.LoadDecl(decl)
@ -59,7 +66,15 @@ func TestReadFile(t *testing.T) {
r, e := f.Read(ctx) r, e := f.Read(ctx)
assert.Equal(t, nil, e) assert.Equal(t, nil, e)
assert.Equal(t, "nobody", f.Owner) assert.Equal(t, "nobody", f.Owner)
assert.YAMLEq(t, decl, string(r))
info,statErr := os.Stat(file)
assert.Nil(t, statErr)
stat, ok := info.Sys().(*syscall.Stat_t)
assert.True(t, ok)
cTime := time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec))
expected := fmt.Sprintf(declarationAttributes, file, cTime.Format(time.RFC3339Nano))
assert.YAMLEq(t, expected, string(r))
} }
func TestCreateFile(t *testing.T) { func TestCreateFile(t *testing.T) {
@ -130,3 +145,25 @@ func TestFileDirectory(t *testing.T) {
assert.Nil(t, deleteErr) assert.Nil(t, deleteErr)
assert.NoDirExists(t, file) assert.NoDirExists(t, file)
} }
func TestFileTimes(t *testing.T) {
file, _ := filepath.Abs(filepath.Join(TempDir, "testtimes.txt"))
decl := fmt.Sprintf(`
path: "%s"
owner: "nobody"
group: "nobody"
mtime: 2001-12-15T01:01:01.1Z
mode: "0600"
filtetype: "regular"
state: "present"
`, file)
expectedTime, timeErr := time.Parse(time.RFC3339, "2001-12-15T01:01:01.1Z")
assert.Nil(t, timeErr)
f := NewFile()
e := f.LoadDecl(decl)
assert.Nil(t, e)
assert.Equal(t, "nobody", f.Owner)
assert.True(t, f.Mtime.Equal(expectedTime))
}