Skip to content

Commit

Permalink
feat: add installed platform
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <[email protected]>
  • Loading branch information
knqyf263 committed May 13, 2024
1 parent ddbed50 commit b69a5a8
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 50 deletions.
6 changes: 3 additions & 3 deletions pkg/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ func NewPluginCommand() *cobra.Command {
}
cmd.AddCommand(
&cobra.Command{
Use: "install URL | FILE_PATH",
Use: "install NAME | URL | FILE_PATH",
Aliases: []string{"i"},
Short: "Install a plugin",
SilenceErrors: true,
Expand Down Expand Up @@ -810,7 +810,7 @@ func NewPluginCommand() *cobra.Command {
Use: "search [KEYWORD]",
SilenceErrors: true,
DisableFlagsInUseLine: true,
Short: "Run a plugin on the fly",
Short: "List available plugins and search among them",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return plugin.Search(cmd.Context(), args)
Expand All @@ -823,7 +823,7 @@ func NewPluginCommand() *cobra.Command {
DisableFlagsInUseLine: true,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if err := plugin.Upgrade(cmd.Context(), args, plugin.Options{}); err != nil {
if err := plugin.Upgrade(cmd.Context(), args); err != nil {
return xerrors.Errorf("plugin upgrade error: %w", err)
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/plugin/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"context"
"errors"
"fmt"
"github.com/samber/lo"
"os"
"path/filepath"
"strings"

"github.com/samber/lo"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"

Expand Down
12 changes: 6 additions & 6 deletions pkg/plugin/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ func TestManager_Search(t *testing.T) {
name: "all plugins",
args: nil,
dir: "testdata",
want: `NAME TYPE DESCRIPTION MAINTAINER
foo output A foo plugin aquasecurity
bar generic A bar plugin aquasecurity
test generic A test plugin aquasecurity
want: `NAME DESCRIPTION MAINTAINER OUTPUT
foo A foo plugin aquasecurity
bar A bar plugin aquasecurity
test A test plugin aquasecurity
`,
},
{
name: "keyword",
args: []string{"bar"},
dir: "testdata",
want: `NAME TYPE DESCRIPTION MAINTAINER
bar generic A bar plugin aquasecurity
want: `NAME DESCRIPTION MAINTAINER OUTPUT
bar A bar plugin aquasecurity
`,
},
{
Expand Down
52 changes: 36 additions & 16 deletions pkg/plugin/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ import (
"path/filepath"
"strings"

v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/samber/lo"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"

"github.com/aquasecurity/trivy/pkg/downloader"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)

var defaultManager = NewManager()
const configFile = "plugin.yaml"

var (
pluginsRelativeDir = filepath.Join(".trivy", "plugins")

defaultManager = NewManager()
)

type ManagerOption func(indexer *Manager)

Expand Down Expand Up @@ -59,21 +67,19 @@ func NewManager(opts ...ManagerOption) *Manager {
func Install(ctx context.Context, name string, opts Options) (Plugin, error) {
return defaultManager.Install(ctx, name, opts)
}
func Upgrade(ctx context.Context, names []string, opts Options) error {
return defaultManager.Upgrade(ctx, names, opts)
}
func Start(ctx context.Context, name string, opts Options) (Wait, error) {
return defaultManager.Start(ctx, name, opts)
}
func RunWithURL(ctx context.Context, name string, opts Options) error {
return defaultManager.RunWithURL(ctx, name, opts)
}
func Uninstall(ctx context.Context, name string) error { return defaultManager.Uninstall(ctx, name) }
func Information(name string) error { return defaultManager.Information(name) }
func List(ctx context.Context) error { return defaultManager.List(ctx) }
func Update(ctx context.Context) error { return defaultManager.Update(ctx) }
func Search(ctx context.Context, args []string) error { return defaultManager.Search(ctx, args) }
func LoadAll(ctx context.Context) ([]Plugin, error) { return defaultManager.LoadAll(ctx) }
func Upgrade(ctx context.Context, names []string) error { return defaultManager.Upgrade(ctx, names) }
func Uninstall(ctx context.Context, name string) error { return defaultManager.Uninstall(ctx, name) }
func Information(name string) error { return defaultManager.Information(name) }
func List(ctx context.Context) error { return defaultManager.List(ctx) }
func Update(ctx context.Context) error { return defaultManager.Update(ctx) }
func Search(ctx context.Context, args []string) error { return defaultManager.Search(ctx, args) }
func LoadAll(ctx context.Context) ([]Plugin, error) { return defaultManager.LoadAll(ctx) }

// Install installs a plugin
func (m *Manager) Install(ctx context.Context, name string, opts Options) (Plugin, error) {
Expand Down Expand Up @@ -107,8 +113,14 @@ func (m *Manager) install(ctx context.Context, src string, opts Options) (Plugin
}

// Copy plugin.yaml into the plugin dir
if _, err = fsutils.CopyFile(filepath.Join(tempDir, configFile), filepath.Join(plugin.Dir(), configFile)); err != nil {
return Plugin{}, xerrors.Errorf("failed to copy plugin.yaml: %w", err)
f, err := os.Create(filepath.Join(plugin.Dir(), configFile))
if err != nil {
return Plugin{}, xerrors.Errorf("failed to create plugin.yaml: %w", err)
}
defer f.Close()

if err = yaml.NewEncoder(f).Encode(plugin); err != nil {
return Plugin{}, xerrors.Errorf("yaml encode error: %w", err)
}

return plugin, nil
Expand Down Expand Up @@ -173,7 +185,7 @@ func (m *Manager) list(ctx context.Context) (string, error) {
}

// Upgrade upgrades an existing plugins
func (m *Manager) Upgrade(ctx context.Context, names []string, opts Options) error {
func (m *Manager) Upgrade(ctx context.Context, names []string) error {
if len(names) == 0 {
plugins, err := m.LoadAll(ctx)
if err != nil {
Expand All @@ -185,22 +197,30 @@ func (m *Manager) Upgrade(ctx context.Context, names []string, opts Options) err
names = lo.Map(plugins, func(p Plugin, _ int) string { return p.Name })
}
for _, name := range names {
if err := m.upgrade(ctx, name, opts); err != nil {
if err := m.upgrade(ctx, name); err != nil {
return xerrors.Errorf("unable to upgrade '%s' plugin: %w", name, err)
}
}
return nil
}

func (m *Manager) upgrade(ctx context.Context, name string, opts Options) error {
func (m *Manager) upgrade(ctx context.Context, name string) error {
plugin, err := m.load(name)
if err != nil {
return xerrors.Errorf("plugin load error: %w", err)
}

logger := log.With("name", name)
logger.InfoContext(ctx, "Upgrading plugin...")
updated, err := m.install(ctx, plugin.Repository, opts)
updated, err := m.install(ctx, plugin.Repository, Options{
// Use the current installed platform
Platform: ftypes.Platform{
Platform: &v1.Platform{
OS: plugin.Installed.Platform.OS,
Architecture: plugin.Installed.Platform.Arch,
},
},
})
if err != nil {
return xerrors.Errorf("unable to perform an upgrade installation: %w", err)
}
Expand Down
21 changes: 12 additions & 9 deletions pkg/plugin/plugin_test.go → pkg/plugin/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ func TestManager_Install(t *testing.T) {
Bin: "./test.sh",
},
},
Installed: plugin.Installed{
Platform: plugin.Selector{
OS: "linux",
Arch: "amd64",
},
},
}

tests := []struct {
Expand Down Expand Up @@ -427,7 +433,11 @@ func TestManager_Upgrade(t *testing.T) {
repository: testdata/test_plugin
version: "0.0.5"
usage: test
description: A simple test plugin`
description: A simple test plugin
installed:
platform:
os: linux
arch: amd64`

err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginMetadata), os.ModePerm)
require.NoError(t, err)
Expand All @@ -438,14 +448,7 @@ description: A simple test plugin`
verifyVersion(t, ctx, pluginName, "0.0.5")

// Upgrade the existing plugin
err = plugin.NewManager().Upgrade(ctx, nil, plugin.Options{
Platform: ftypes.Platform{
Platform: &v1.Platform{
Architecture: "amd64",
OS: "linux",
},
},
})
err = plugin.NewManager().Upgrade(ctx, nil)
require.NoError(t, err)

// verify plugin updated
Expand Down
29 changes: 17 additions & 12 deletions pkg/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"runtime"

"github.com/samber/lo"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/downloader"
Expand All @@ -18,10 +19,6 @@ import (
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
)

const configFile = "plugin.yaml"

var pluginsRelativeDir = filepath.Join(".trivy", "plugins")

// Plugin represents a plugin.
type Plugin struct {
Name string `yaml:"name"`
Expand All @@ -31,10 +28,17 @@ type Plugin struct {
Description string `yaml:"description"`
Platforms []Platform `yaml:"platforms"`

// Installed holds the metadata about installation
Installed Installed `yaml:"installed"`

// dir points to the directory where the plugin is installed
dir string
}

type Installed struct {
Platform Selector `yaml:"platform"`
}

// Platform represents where the execution file exists per platform.
type Platform struct {
Selector *Selector
Expand All @@ -44,8 +48,8 @@ type Platform struct {

// Selector represents the environment.
type Selector struct {
OS string
Arch string
OS string `yaml:"os"`
Arch string `yaml:"arch"`
}

type Options struct {
Expand All @@ -54,7 +58,7 @@ type Options struct {
Platform ftypes.Platform
}

func (p Plugin) Cmd(ctx context.Context, opts Options) (*exec.Cmd, error) {
func (p *Plugin) Cmd(ctx context.Context, opts Options) (*exec.Cmd, error) {
platform, err := p.selectPlatform(ctx, opts)
if err != nil {
return nil, xerrors.Errorf("platform selection error: %w", err)
Expand All @@ -79,7 +83,7 @@ type Wait func() error
// Start starts the plugin
//
// After a successful call to Start the Wait method must be called.
func (p Plugin) Start(ctx context.Context, opts Options) (Wait, error) {
func (p *Plugin) Start(ctx context.Context, opts Options) (Wait, error) {
cmd, err := p.Cmd(ctx, opts)
if err != nil {
return nil, xerrors.Errorf("cmd: %w", err)
Expand All @@ -92,7 +96,7 @@ func (p Plugin) Start(ctx context.Context, opts Options) (Wait, error) {
}

// Run runs the plugin
func (p Plugin) Run(ctx context.Context, opts Options) error {
func (p *Plugin) Run(ctx context.Context, opts Options) error {
cmd, err := p.Cmd(ctx, opts)
if err != nil {
return xerrors.Errorf("cmd: %w", err)
Expand All @@ -113,7 +117,7 @@ func (p Plugin) Run(ctx context.Context, opts Options) error {
return nil
}

func (p Plugin) selectPlatform(ctx context.Context, opts Options) (Platform, error) {
func (p *Plugin) selectPlatform(ctx context.Context, opts Options) (Platform, error) {
// These values are only filled in during unit tests.
goos := runtime.GOOS
if opts.Platform.Platform != nil && opts.Platform.OS != "" {
Expand All @@ -140,12 +144,13 @@ func (p Plugin) selectPlatform(ctx context.Context, opts Options) (Platform, err
return Platform{}, xerrors.New("platform not found")
}

func (p Plugin) install(ctx context.Context, dst, pwd string, opts Options) error {
func (p *Plugin) install(ctx context.Context, dst, pwd string, opts Options) error {
log.DebugContext(ctx, "Installing the plugin...", log.String("path", dst))
platform, err := p.selectPlatform(ctx, opts)
if err != nil {
return xerrors.Errorf("platform selection error: %w", err)
}
p.Installed.Platform = lo.FromPtr(platform.Selector)

log.DebugContext(ctx, "Downloading the execution file...", log.String("uri", platform.URI))
if err = downloader.Download(ctx, platform.URI, dst, pwd); err != nil {
Expand All @@ -154,7 +159,7 @@ func (p Plugin) install(ctx context.Context, dst, pwd string, opts Options) erro
return nil
}

func (p Plugin) Dir() string {
func (p *Plugin) Dir() string {
if p.dir != "" {
return p.dir
}
Expand Down
4 changes: 1 addition & 3 deletions pkg/plugin/testdata/plugin/index.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
- name: foo
type: output
output: true
maintainer: aquasecurity
description: A foo plugin
repository: github.com/aquasecurity/trivy-plugin-foo
- name: bar
type: generic
maintainer: aquasecurity
description: A bar plugin
repository: github.com/aquasecurity/trivy-plugin-bar
- name: test
type: generic
maintainer: aquasecurity
description: A test plugin
repository: testdata/test_plugin

0 comments on commit b69a5a8

Please sign in to comment.