From 9d58db522d37e3ec2ddc443a393059b2493002d5 Mon Sep 17 00:00:00 2001 From: Matthew Rich Date: Sat, 20 Apr 2024 23:13:17 -0700 Subject: [PATCH] fix import -resource flag --- cli_test.go | 2 +- cmd/cli/main.go | 27 +++++++++++++++++++++-- go.mod | 1 + go.sum | 2 ++ internal/resource/container.go | 13 +++++++---- internal/resource/declaration.go | 15 +++++-------- internal/resource/document.go | 4 ++++ internal/resource/exec.go | 16 +++++++++----- internal/resource/file.go | 9 +++++++- internal/resource/network_route.go | 14 ++++++++---- internal/resource/package.go | 1 + internal/resource/resource.go | 11 +++++++++ internal/resource/schemas/file.jsonschema | 4 +++- internal/source/decl.go | 16 +++++--------- internal/source/http.go | 13 ++++++++++- 15 files changed, 109 insertions(+), 39 deletions(-) diff --git a/cli_test.go b/cli_test.go index 3c5da76..ec57caa 100644 --- a/cli_test.go +++ b/cli_test.go @@ -18,7 +18,7 @@ func TestCli(t *testing.T) { if _, e := os.Stat("./decl"); errors.Is(e, os.ErrNotExist) { t.Skip("cli not built") } - yaml, cliErr := exec.Command("./decl", "-import-resource", "file://COPYRIGHT").Output() + yaml, cliErr := exec.Command("./decl", "import", "file://COPYRIGHT").Output() slog.Info("TestCli", "err", cliErr) assert.Nil(t, cliErr) assert.NotEqual(t, "", string(yaml)) diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 169626c..5555146 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -25,6 +25,7 @@ var GlobalOformat *string var GlobalQuiet *bool var ImportMerge *bool +var ImportResource *string var ctx context.Context = context.Background() @@ -73,19 +74,24 @@ func LoadSourceURI(uri string) []*resource.Document { if extractErr != nil { log.Fatal(extractErr) } + slog.Info("extract documents", "documents", extractDocuments) return extractDocuments } return []*resource.Document{ resource.NewDocument() } } func ImportSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) { + ImportResource = cmd.String("resource", "", "(uri) Add a resource to the document.") ImportMerge = cmd.Bool("merge", false, "Merge resources into a single document.") cmd.Parse(os.Args[2:]) var encoder resource.Encoder merged := resource.NewDocument() documents := make([]*resource.Document, 0, 100) for _,source := range cmd.Args() { - documents = append(documents, LoadSourceURI(source)...) + loaded := LoadSourceURI(source) + if loaded != nil { + documents = append(documents, loaded...) + } } switch *GlobalOformat { @@ -95,8 +101,20 @@ func ImportSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) { encoder = resource.NewJSONEncoder(output) } + if len(documents) == 0 { + documents = append(documents, resource.NewDocument()) + } + for _,d := range documents { if d != nil { + + if *ImportResource != "" { + slog.Info("ImportResource", "resource", ImportResource) + if addResourceErr := d.AddResource(*ImportResource); addResourceErr != nil { + log.Fatal(addResourceErr) + } + } + if *GlobalQuiet { for _, dr := range d.Resources() { output.Write([]byte(dr.Resource().URI())) @@ -126,10 +144,15 @@ func ApplySubCommand(cmd *flag.FlagSet, output io.Writer) (err error) { var encoder resource.Encoder documents := make([]*resource.Document, 0, 100) for _,source := range cmd.Args() { - documents = append(documents, LoadSourceURI(source)...) + loaded := LoadSourceURI(source) + if loaded != nil { + documents = append(documents, loaded...) + } } + slog.Info("main.Apply()", "documents", documents) for _,d := range documents { + slog.Info("main.Appl()", "doc", d) if e := d.Apply(); e != nil { return e } diff --git a/go.mod b/go.mod index 0bcf966..bf83fb4 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( ) require ( + gitea.rosskeen.house/rosskeen.house/machine v0.0.0-20240404204346-6c7c3faf2814 // indirect github.com/Microsoft/go-winio v0.4.14 // indirect github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 23a606b..3a3bc6f 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +gitea.rosskeen.house/rosskeen.house/machine v0.0.0-20240404204346-6c7c3faf2814 h1:nPMHPc3NB+jsd1OFQlrEiRKPXT7KHd6fYyWItt4jCVs= +gitea.rosskeen.house/rosskeen.house/machine v0.0.0-20240404204346-6c7c3faf2814/go.mod h1:5J2OFjFIBaCfsjcC9kSyycbIL8g/qAJH2A8BnbIig+Y= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= diff --git a/internal/resource/container.go b/internal/resource/container.go index 1d597ac..6037833 100644 --- a/internal/resource/container.go +++ b/internal/resource/container.go @@ -23,6 +23,7 @@ import ( "path/filepath" _ "strings" "encoding/json" + "io" ) type ContainerClient interface { @@ -35,7 +36,6 @@ type ContainerClient interface { } type Container struct { - loader YamlLoader Id string `json:"ID,omitempty" yaml:"ID,omitempty"` Name string `json:"name" yaml:"name"` Path string `json:"path" yaml:"path"` @@ -90,7 +90,6 @@ func NewContainer(containerClientApi ContainerClient) *Container { } } return &Container{ - loader: YamlLoadDecl, apiClient: apiClient, } } @@ -162,8 +161,14 @@ func (c *Container) Apply() error { return nil } -func (c *Container) LoadDecl(yamlFileResourceDeclaration string) error { - return c.loader(yamlFileResourceDeclaration, c) +func (c *Container) Load(r io.Reader) error { + d := NewYAMLDecoder(r) + return d.Decode(c) +} + +func (c *Container) LoadDecl(yamlResourceDeclaration string) error { + d := NewYAMLStringDecoder(yamlResourceDeclaration) + return d.Decode(c) } func (c *Container) Create(ctx context.Context) error { diff --git a/internal/resource/declaration.go b/internal/resource/declaration.go index 83cdfd9..a5f4185 100644 --- a/internal/resource/declaration.go +++ b/internal/resource/declaration.go @@ -9,14 +9,18 @@ import ( "io" "gopkg.in/yaml.v3" "log/slog" + "gitea.rosskeen.house/rosskeen.house/machine" ) type DeclarationType struct { Type TypeName `json:"type" yaml:"type"` + Transition string `json:"transition" yaml:"transition"` } type Declaration struct { + StateMatchine machine.Stater `json:"-" yaml:"-"` Type TypeName `json:"type" yaml:"type"` + Transition string `json:"transition,omitempty" yaml:"transition,omitempty"` Attributes Resource `json:"attributes" yaml:"attributes"` } @@ -28,15 +32,6 @@ type StateTransformer interface { Apply() error } -type YamlLoader func(string, any) error - -func YamlLoadDecl(yamlFileResourceDeclaration string, resource any) error { - if err := yaml.Unmarshal([]byte(yamlFileResourceDeclaration), resource); err != nil { - return err - } - return nil -} - func NewDeclaration() *Declaration { return &Declaration{} } @@ -87,6 +82,7 @@ func (d *Declaration) UnmarshalYAML(value *yaml.Node) error { } d.Type = t.Type + d.Transition = t.Transition newResource, resourceErr := ResourceTypes.New(fmt.Sprintf("%s://", d.Type)) if resourceErr != nil { return resourceErr @@ -111,6 +107,7 @@ func (d *Declaration) UnmarshalJSON(data []byte) error { } d.Type = t.Type + d.Transition = t.Transition newResource, resourceErr := ResourceTypes.New(fmt.Sprintf("%s://", d.Type)) if resourceErr != nil { diff --git a/internal/resource/document.go b/internal/resource/document.go index 817d1e3..db5790b 100644 --- a/internal/resource/document.go +++ b/internal/resource/document.go @@ -60,6 +60,10 @@ func (d *Document) Resources() []Declaration { } func (d *Document) Apply() error { + if d == nil { + panic("Undefined Document") + } + slog.Info("Document.Apply()", "declarations", d) for i := range d.ResourceDecls { if e := d.ResourceDecls[i].Resource().Apply(); e != nil { return e diff --git a/internal/resource/exec.go b/internal/resource/exec.go index d6ad242..57685ba 100644 --- a/internal/resource/exec.go +++ b/internal/resource/exec.go @@ -11,11 +11,11 @@ import ( _ "os" _ "os/exec" "path/filepath" - _ "strings" +_ "strings" + "io" ) type Exec struct { - loader YamlLoader Id string `yaml:"id" json:"id"` CreateTemplate Command `yaml:"create" json:"create"` ReadTemplate Command `yaml:"read" json:"read"` @@ -34,7 +34,7 @@ func init() { } func NewExec() *Exec { - return &Exec{loader: YamlLoadDecl} + return &Exec{} } func (x *Exec) Clone() Resource { @@ -76,8 +76,14 @@ func (x *Exec) Apply() error { return nil } -func (x *Exec) LoadDecl(yamlFileResourceDeclaration string) error { - return x.loader(yamlFileResourceDeclaration, x) +func (x *Exec) Load(r io.Reader) error { + c := NewYAMLDecoder(r) + return c.Decode(x) +} + +func (x *Exec) LoadDecl(yamlResourceDeclaration string) error { + c := NewYAMLStringDecoder(yamlResourceDeclaration) + return c.Decode(x) } func (x *Exec) Type() string { return "exec" } diff --git a/internal/resource/file.go b/internal/resource/file.go index feb51ee..066dc9f 100644 --- a/internal/resource/file.go +++ b/internal/resource/file.go @@ -16,6 +16,7 @@ import ( "strconv" "syscall" "time" + "crypto/sha256" ) type FileType string @@ -53,6 +54,7 @@ type File struct { Mtime time.Time `json:"mtime,omitempty" yaml:"mtime,omitempty"` Content string `json:"content,omitempty" yaml:"content,omitempty"` + Sha256 string `json:"sha256,omitempty" yaml:"sha256,omitempty"` Target string `json:"target,omitempty" yaml:"target,omitempty"` FileType FileType `json:"filetype" yaml:"filetype"` State string `json:"state" yaml:"state"` @@ -90,7 +92,11 @@ func (f *File) SetURI(uri string) error { resourceUri, e := url.Parse(uri) if e == nil { if resourceUri.Scheme == "file" { - f.Path, e = filepath.Abs(filepath.Join(resourceUri.Hostname(), resourceUri.RequestURI())) + if absFilePath, err := filepath.Abs(filepath.Join(resourceUri.Hostname(), resourceUri.RequestURI())); err != nil { + return err + } else { + f.Path = absFilePath + } } else { e = fmt.Errorf("%w: %s is not a file", ErrInvalidResourceURI, uri) } @@ -256,6 +262,7 @@ func (f *File) Read(ctx context.Context) ([]byte, error) { panic(ioErr) } f.Content = string(fileContent) + f.Sha256 = fmt.Sprintf("%x", sha256.Sum256(fileContent)) case SymbolicLinkFile: linkTarget, pathErr := os.Readlink(f.Path) if pathErr != nil { diff --git a/internal/resource/network_route.go b/internal/resource/network_route.go index 6e3a209..b1a77f8 100644 --- a/internal/resource/network_route.go +++ b/internal/resource/network_route.go @@ -9,11 +9,11 @@ import ( "errors" "fmt" "gopkg.in/yaml.v3" - _ "io" + "io" "net/url" "os/exec" "regexp" - _ "strconv" +_ "strconv" "strings" ) @@ -159,8 +159,14 @@ func (n *NetworkRoute) Apply() error { return nil } -func (n *NetworkRoute) LoadDecl(yamlNetworkRouteResourceDeclaration string) error { - return YamlLoadDecl(yamlNetworkRouteResourceDeclaration, n) +func (n *NetworkRoute) Load(r io.Reader) error { + c := NewYAMLDecoder(r) + return c.Decode(n) +} + +func (n *NetworkRoute) LoadDecl(yamlResourceDeclaration string) error { + c := NewYAMLStringDecoder(yamlResourceDeclaration) + return c.Decode(n) } func (n *NetworkRoute) ResolveId(ctx context.Context) string { diff --git a/internal/resource/package.go b/internal/resource/package.go index 68db7eb..3f2d9cd 100644 --- a/internal/resource/package.go +++ b/internal/resource/package.go @@ -200,6 +200,7 @@ func (p *PackageType) NewCRUD() (create *Command, read *Command, update *Command case PackageTypeRpm: case PackageTypePip: case PackageTypeYum: + default: } return nil, nil, nil, nil } diff --git a/internal/resource/resource.go b/internal/resource/resource.go index 2bb803f..8574ede 100644 --- a/internal/resource/resource.go +++ b/internal/resource/resource.go @@ -53,3 +53,14 @@ func NewResource(uri string) Resource { } return nil } +/* +func Machine() { +// start_destroy -> absent -> start_create -> present -> start_destroy + stater := machine.New("absent") + stater.AddStates("absent", "start_create", "present", "start_delete") + stater.AddTransition("creating", "absent", "start_create") + stater.AddTransition("created", "start_create", "present") + stater.AddTransition("deleting", "present", "start_delete") + stater.AddTransition("deleted", "start_delete", "absent") +} +*/ diff --git a/internal/resource/schemas/file.jsonschema b/internal/resource/schemas/file.jsonschema index ad7a045..47118ac 100644 --- a/internal/resource/schemas/file.jsonschema +++ b/internal/resource/schemas/file.jsonschema @@ -6,7 +6,9 @@ "required": [ "path", "filetype" ], "properties": { "path": { - "type": "string" + "type": "string", + "description": "file path", + "minLength": 1 }, "owner": { "type": "string" diff --git a/internal/source/decl.go b/internal/source/decl.go index 8008372..aca1e64 100644 --- a/internal/source/decl.go +++ b/internal/source/decl.go @@ -51,7 +51,7 @@ 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()) + //documents = append(documents, resource.NewDocument()) GzipFileName := regexp.MustCompile(`^.*\.gz$`) @@ -72,28 +72,22 @@ func (d *DeclFile) ExtractResources(filter ResourceSelector) ([]*resource.Docume fileReader = file } decoder := resource.NewYAMLDecoder(fileReader) + slog.Info("ExtractResources()", "documents", documents) index := 0 for { - doc := documents[index] + doc := resource.NewDocument() e := decoder.Decode(doc) if errors.Is(e, io.EOF) { - if len(documents) > 1 { - documents[index] = nil - } break } if e != nil { return documents, e } + slog.Info("ExtractResources()", "res", doc.ResourceDecls[0].Attributes) if validationErr := doc.Validate(); validationErr != nil { return documents, validationErr } -/* - if applyErr := doc.Apply(); applyErr != nil { - return documents, applyErr - } -*/ - documents = append(documents, resource.NewDocument()) + documents = append(documents, doc) index++ } return documents, nil diff --git a/internal/source/http.go b/internal/source/http.go index c4d7f7b..436b3a5 100644 --- a/internal/source/http.go +++ b/internal/source/http.go @@ -5,7 +5,7 @@ package source import ( _ "context" _ "encoding/json" -_ "fmt" + "fmt" _ "gopkg.in/yaml.v3" "net/url" "net/http" @@ -47,6 +47,17 @@ func (h *HTTP) ExtractResources(filter ResourceSelector) ([]*resource.Document, } 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) + } + } + } + hash := sha256.New() sumReadData := iofilter.NewReader(resp.Body, func(p []byte, readn int, readerr error) (n int, err error) { hash.Write(p)