From cc3434c7e35102fd4ed02564c9800d25dae3fe13 Mon Sep 17 00:00:00 2001 From: Matthew Rich Date: Sat, 28 Sep 2024 01:04:00 -0700 Subject: [PATCH] add resource tests --- cli_test.go | 61 +++++++++++++++++++++ internal/resource/container.go | 98 +++++++++++++++++----------------- internal/resource/resource.go | 6 +++ 3 files changed, 117 insertions(+), 48 deletions(-) diff --git a/cli_test.go b/cli_test.go index 512f4d8..2f09759 100644 --- a/cli_test.go +++ b/cli_test.go @@ -178,3 +178,64 @@ func TestCliExportTar(t *testing.T) { assert.Equal(t, []byte("data"), contents) } } + +func TestResourcesRead(t *testing.T) { + if _, e := os.Stat("./jx"); errors.Is(e, os.ErrNotExist) { + t.Skip("cli not built") + } + + assert.Nil(t, TempDir.CreateFile("testread", "data")) + +resources := fmt.Sprintf(` +resources: +- type: file + transition: read + attributes: + path: %s +- type: user + transition: read + attributes: + name: nobody +- type: group + transition: read + attributes: + name: wheel +- type: container + transition: read + attributes: + name: builder +- type: container-network + transition: read + attributes: + name: default +- type: container-image + transition: read + attributes: + name: nginx:latest +- type: http + transition: read + attributes: + endpoint: https://gitea.rosskeen.house +- type: route + transition: read + attributes: + to: 0.0.0.0 + gateway: 172.17.0.1 + interface: eth0 + proto: static + scope: global + rtid: all + routetype: local + metric: 100 +`, TempDir.FilePath("testread")) + + assert.Nil(t, TempDir.CreateFile("resources.jx.yaml", resources)) + + yaml, cliErr := exec.Command("./jx", "apply", TempDir.FilePath("resources.jx.yaml")).Output() + if cliErr != nil { + slog.Info("Debug CLI error", "error", cliErr, "stderr", cliErr.(*exec.ExitError).Stderr) + } + assert.Nil(t, cliErr) + assert.NotEqual(t, "", string(yaml)) + assert.Greater(t, len(yaml), 0) +} diff --git a/internal/resource/container.go b/internal/resource/container.go index af158d4..ac6599f 100644 --- a/internal/resource/container.go +++ b/internal/resource/container.go @@ -46,35 +46,35 @@ type ContainerClient interface { } type Container struct { - *Common `yaml:",inline" json:",inline"` - stater machine.Stater `yaml:"-" json:"-"` - Id string `json:"ID,omitempty" yaml:"ID,omitempty"` - Name string `json:"name" yaml:"name"` -// Path string `json:"path" yaml:"path"` - Cmd []string `json:"cmd,omitempty" yaml:"cmd,omitempty"` - Entrypoint strslice.StrSlice `json:"entrypoint,omitempty" yaml:"entrypoint,omitempty"` - Args []string `json:"args,omitempty" yaml:"args,omitempty"` - Ports []string `json:"ports,omitempty" yaml:"ports,omitempty"` - Environment map[string]string `json:"environment" yaml:"environment"` - Image string `json:"image" yaml:"image"` - ResolvConfPath string `json:"resolvconfpath" yaml:"resolvconfpath"` - HostnamePath string `json:"hostnamepath" yaml:"hostnamepath"` - HostsPath string `json:"hostpath" yaml:"hostspath"` - LogPath string `json:"logpath" yaml:"logpath"` - Created string `json:"created" yaml:"created"` - ContainerState types.ContainerState `json:"containerstate" yaml:"containerstate"` - RestartCount int `json:"restartcount" yaml:"restartcount"` - Driver string `json:"driver" yaml:"driver"` - Platform string `json:"platform" yaml:"platform"` - MountLabel string `json:"mountlabel" yaml:"mountlabel"` - ProcessLabel string `json:"processlabel" yaml:"processlabel"` - AppArmorProfile string `json:"apparmorprofile" yaml:"apparmorprofile"` - ExecIDs []string `json:"execids" yaml:"execids"` - HostConfig container.HostConfig `json:"hostconfig" yaml:"hostconfig"` - GraphDriver types.GraphDriverData `json:"graphdriver" yaml:"graphdriver"` - SizeRw *int64 `json:",omitempty" yaml:",omitempty"` - SizeRootFs *int64 `json:",omitempty" yaml:",omitempty"` - Networks []string `json:"networks,omitempty" yaml:"networks,omitempty"` + *Common `yaml:",inline" json:",inline"` + stater machine.Stater `yaml:"-" json:"-"` + Id string `json:"ID,omitempty" yaml:"ID,omitempty"` + Name string `json:"name" yaml:"name"` +// Path string `json:"path" yaml:"path"` + Cmd []string `json:"cmd,omitempty" yaml:"cmd,omitempty"` + Entrypoint strslice.StrSlice `json:"entrypoint,omitempty" yaml:"entrypoint,omitempty"` + Args []string `json:"args,omitempty" yaml:"args,omitempty"` + Ports []string `json:"ports,omitempty" yaml:"ports,omitempty"` + Environment map[string]string `json:"environment" yaml:"environment"` + Image string `json:"image" yaml:"image"` + ResolvConfPath string `json:"resolvconfpath" yaml:"resolvconfpath"` + HostnamePath string `json:"hostnamepath" yaml:"hostnamepath"` + HostsPath string `json:"hostpath" yaml:"hostspath"` + LogPath string `json:"logpath" yaml:"logpath"` + Created string `json:"created" yaml:"created"` + ContainerState types.ContainerState `json:"containerstate" yaml:"containerstate"` + RestartCount int `json:"restartcount" yaml:"restartcount"` + Driver string `json:"driver" yaml:"driver"` + Platform string `json:"platform" yaml:"platform"` + MountLabel string `json:"mountlabel" yaml:"mountlabel"` + ProcessLabel string `json:"processlabel" yaml:"processlabel"` + AppArmorProfile string `json:"apparmorprofile" yaml:"apparmorprofile"` + ExecIDs []string `json:"execids" yaml:"execids"` + HostConfig container.HostConfig `json:"hostconfig" yaml:"hostconfig"` + GraphDriver types.GraphDriverData `json:"graphdriver" yaml:"graphdriver"` + SizeRw *int64 `json:",omitempty" yaml:",omitempty"` + SizeRootFs *int64 `json:",omitempty" yaml:",omitempty"` + Networks []string `json:"networks,omitempty" yaml:"networks,omitempty"` /* Mounts []MountPoint Config *container.Config @@ -92,6 +92,7 @@ func init() { ResourceTypes.Register([]string{"container"}, func(u *url.URL) data.Resource { c := NewContainer(nil) c.Name = filepath.Join(u.Hostname(), u.Path) + c.Common.SetParsedURI(u) return c }) } @@ -106,7 +107,7 @@ func NewContainer(containerClientApi ContainerClient) *Container { } } return &Container{ - Common: &Common{ resourceType: ContainerTypeName }, + Common: NewCommon(ContainerTypeName, false), apiClient: apiClient, } } @@ -155,24 +156,6 @@ func (c *Container) StateMachine() machine.Stater { return c.stater } -/* -func (c *Container) URI() string { - return fmt.Sprintf("container://%s", c.Id) -} - -func (c *Container) SetURI(uri string) error { - resourceUri, e := url.Parse(uri) - if e == nil { - if resourceUri.Scheme == c.Type() { - c.Name, e = filepath.Abs(filepath.Join(resourceUri.Hostname(), resourceUri.RequestURI())) - } else { - e = fmt.Errorf("%w: %s is not a %s", ErrInvalidResourceURI, uri, c.Type()) - } - } - return e -} -*/ - func (c *Container) UseConfig(config data.ConfigurationValueGetter) { c.config = config } @@ -190,6 +173,16 @@ func (c *Container) Notify(m *machine.EventMessage) { switch m.On { case machine.ENTERSTATEEVENT: switch m.Dest { + case "start_stat": + if statErr := c.ReadStat(); statErr == nil { + if triggerErr := c.StateMachine().Trigger("exists"); triggerErr == nil { + return + } + } else { + if triggerErr := c.StateMachine().Trigger("notexists"); triggerErr == nil { + return + } + } case "start_read": if _,readErr := c.Read(ctx); readErr == nil { if triggerErr := c.stater.Trigger("state_read"); triggerErr == nil { @@ -237,6 +230,10 @@ func (c *Container) Notify(m *machine.EventMessage) { } } +func (c *Container) ReadStat() (err error) { + return +} + func (c *Container) Apply() error { ctx := context.Background() switch c.Common.State { @@ -421,9 +418,14 @@ func (c *Container) Delete(ctx context.Context) error { return err } +func (c *Container) URI() string { + return fmt.Sprintf("%s://%s", c.Type(), c.Name) +} + func (c *Container) Type() string { return "container" } func (c *Container) ResolveId(ctx context.Context) string { + c.Common.SetURI(c.URI()) filterArgs := filters.NewArgs() filterArgs.Add("name", "/"+c.Name) containers, err := c.apiClient.ContainerList(ctx, container.ListOptions{ diff --git a/internal/resource/resource.go b/internal/resource/resource.go index 1b740a5..7b14668 100644 --- a/internal/resource/resource.go +++ b/internal/resource/resource.go @@ -219,6 +219,12 @@ func ProcessMachine(sub machine.Subscriber) machine.Stater { if e := stater.AddSubscription("update", sub); e != nil { return nil } + + stater.AddTransition("stat", machine.States("*"), "start_stat") + if e := stater.AddSubscription("stat", sub); e != nil { + return nil + } + stater.AddTransition("updated", machine.States("start_update"), "present") stater.AddTransition("delete", machine.States("*"), "start_delete") if e := stater.AddSubscription("delete", sub); e != nil {