Skip to content

Commit

Permalink
Merge pull request #2095 from ripienaar/2094
Browse files Browse the repository at this point in the history
(#2094) Add basic plugins watcher maintenance
  • Loading branch information
ripienaar authored Dec 7, 2023
2 parents e495bb0 + a1afd53 commit 88c4922
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 7 deletions.
1 change: 0 additions & 1 deletion aagent/watchers/archivewatcher/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@ func (w *Watcher) untar(s io.Reader, t string) error {
}

nfo := header.FileInfo()
w.Debugf("untar: %s", path)
if nfo.IsDir() {
err = os.MkdirAll(path, nfo.Mode())
if err != nil {
Expand Down
13 changes: 8 additions & 5 deletions aagent/watchers/pluginswatcher/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ type ManagedPlugin struct {
Name string `json:"name" yaml:"name"`
NamePrefix string `json:"-" yaml:"-"`
Source string `json:"source" yaml:"source"`
Username string `json:"username" yaml:"username"`
Password string `json:"password" yaml:"password"`
Username string `json:"username,omitempty" yaml:"username"`
Password string `json:"password,omitempty" yaml:"password"`
ContentChecksumsChecksum string `json:"verify_checksum" yaml:"verify_checksum" mapstructure:"verify_checksum"`
ArchiveChecksum string `json:"checksum" yaml:"checksum" mapstructure:"checksum"`
Matcher string `json:"match" yaml:"match" mapstructure:"match"`
Governor string `json:"governor" yaml:"governor" mapstructure:"governor"`
Matcher string `json:"match,omitempty" yaml:"match" mapstructure:"match"`
Governor string `json:"governor,omitempty" yaml:"governor" mapstructure:"governor"`

Interval string `json:"-"`
Target string `json:"-"`
Expand Down Expand Up @@ -364,7 +364,10 @@ func (w *Watcher) purgeUnknownPlugins(ctx context.Context, desired []*ManagedPlu
}

w.Debugf("Sleeping for 2 seconds to allow manager to exit")
iu.InterruptibleSleep(ctx, 2*time.Second)
err = iu.InterruptibleSleep(ctx, 2*time.Second)
if err != nil {
return false, err
}

target = w.targetDirForManagedPlugin(m)
err = os.RemoveAll(target)
Expand Down
150 changes: 150 additions & 0 deletions cmd/machine_plugins_add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright (c) 2023, R.I. Pienaar and the Choria Project contributors
//
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"encoding/json"
"fmt"
"net/url"
"os"
"strings"
"sync"

"github.com/choria-io/go-choria/aagent/watchers/pluginswatcher"
"github.com/choria-io/go-choria/config"
iu "github.com/choria-io/go-choria/internal/util"
"github.com/sirupsen/logrus"
)

type mPluginsAddCommand struct {
command

matcher string
matcherIsSet bool
governor string
governorIsSet bool
pluginUrl *url.URL
manifest string
checksum string
verifyChecksum string
name string
}

func (c *mPluginsAddCommand) Setup() (err error) {
if machine, ok := cmdWithFullCommand("machine plugins"); ok {
c.cmd = machine.Cmd().Command("add", "Add or Update a reference to a plugin to the Plugins Watcher manifest")
c.cmd.Arg("name", "Unique name for this plugin").Required().StringVar(&c.name)
c.cmd.Arg("plugin", "The URL to the tar file holding the plugin").Required().URLVar(&c.pluginUrl)
c.cmd.Arg("checksum", "SHA256 checksum of the archive").Required().StringVar(&c.checksum)
c.cmd.Arg("verify-checksum", "SHA256 checksum of the verification file").Required().StringVar(&c.verifyChecksum)
c.cmd.Flag("manifest", "Path to the manifest to edit").Default("plugins.json").StringVar(&c.manifest)
c.cmd.Flag("matcher", "Limit deployment using an expression").IsSetByUser(&c.matcherIsSet).StringVar(&c.matcher)
c.cmd.Flag("governor", "Limit deployment using a Governor").IsSetByUser(&c.governorIsSet).StringVar(&c.governor)
}

return nil
}

func init() {
cli.commands = append(cli.commands, &mPluginsAddCommand{})
}

func (c *mPluginsAddCommand) Configure() error {
if debug {
logrus.SetOutput(os.Stdout)
logrus.SetLevel(logrus.DebugLevel)
logrus.Debug("Logging at debug level due to CLI override")
}

cfg, err = config.NewDefaultConfig()
if err != nil {
return err
}

cfg.Choria.SecurityProvider = "file"
cfg.DisableSecurityProviderVerify = true

return err
}

func (c *mPluginsAddCommand) Run(wg *sync.WaitGroup) (err error) {
defer wg.Done()

var manifest []*pluginswatcher.ManagedPlugin

if iu.FileExist(c.manifest) {
dat, err := os.ReadFile(c.manifest)
if err != nil {
return err
}

err = json.Unmarshal(dat, &manifest)
if err != nil {
return err
}
}

user := c.pluginUrl.User
c.pluginUrl.User = nil
var found bool

for _, p := range manifest {
if p.Name == c.name {
c.updatePlugin(p, user)
found = true

fmt.Printf("Updating plugin %s\n", p.Name)
}
}

if !found {
p := &pluginswatcher.ManagedPlugin{}
c.updatePlugin(p, user)

name := strings.Split(c.pluginUrl.Path[1:], "-")
if len(name) == 0 {
return fmt.Errorf("could not determine name, please pass --name")
}
p.Name = name[0]

fmt.Printf("Adding plugin %s\n", p.Name)
manifest = append(manifest, p)
}

dat, err := json.MarshalIndent(manifest, "", " ")
if err != nil {
return err
}

err = os.WriteFile(c.manifest, dat, 0600)
if err != nil {
return err
}

fmt.Printf("Use the pack command to sign the %s manifest\n", c.manifest)

return nil
}

func (c *mPluginsAddCommand) updatePlugin(plugin *pluginswatcher.ManagedPlugin, user *url.Userinfo) {
plugin.Source = c.pluginUrl.String()
plugin.ArchiveChecksum = c.checksum
plugin.ContentChecksumsChecksum = c.verifyChecksum

if c.governorIsSet {
plugin.Governor = c.governor
}
if c.matcherIsSet {
plugin.Matcher = c.matcher
}
if user != nil {
plugin.Username = user.Username()
plugin.Password, _ = user.Password()
}

if c.name != "" {
plugin.Name = c.name
}
}
2 changes: 1 addition & 1 deletion cmd/machine_plugins_pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type mPluginsPackCommand struct {

func (r *mPluginsPackCommand) Setup() (err error) {
if machine, ok := cmdWithFullCommand("machine plugins"); ok {
r.cmd = machine.Cmd().Command("pack", "Encodes and signs data for the plugins watcher")
r.cmd = machine.Cmd().Command("pack", "Encodes and signs data for the plugins Watcher")
r.cmd.Arg("source", "File containing the plugins definition").Required().ExistingFileVar(&r.source)
r.cmd.Arg("seed", "The ed25519 seed file to encode with").StringVar(&r.key)
r.cmd.Flag("force", "Do not warn about no ed25519 key and support writing empty files").BoolVar(&r.force)
Expand Down
102 changes: 102 additions & 0 deletions cmd/machine_plugins_rm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) 2023, R.I. Pienaar and the Choria Project contributors
//
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"encoding/json"
"fmt"
"os"
"sync"

"github.com/choria-io/go-choria/aagent/watchers/pluginswatcher"
"github.com/choria-io/go-choria/config"
"github.com/sirupsen/logrus"
)

type mPluginsRmCommand struct {
command

name string
manifest string
}

func (c *mPluginsRmCommand) Setup() (err error) {
if machine, ok := cmdWithFullCommand("machine plugins"); ok {
c.cmd = machine.Cmd().Command("rm", "Removes references to a plugin from the Plugins Watcher manifest")
c.cmd.Arg("name", "Plugin name to remove from the manifest").Required().StringVar(&c.name)
c.cmd.Flag("manifest", "Path to the manifest to edit").Default("plugins.json").ExistingFileVar(&c.manifest)
}

return nil
}

func init() {
cli.commands = append(cli.commands, &mPluginsRmCommand{})
}

func (c *mPluginsRmCommand) Configure() error {
if debug {
logrus.SetOutput(os.Stdout)
logrus.SetLevel(logrus.DebugLevel)
logrus.Debug("Logging at debug level due to CLI override")
}

cfg, err = config.NewDefaultConfig()
if err != nil {
return err
}

cfg.Choria.SecurityProvider = "file"
cfg.DisableSecurityProviderVerify = true

return err
}

func (c *mPluginsRmCommand) Run(wg *sync.WaitGroup) (err error) {
defer wg.Done()

var manifest []*pluginswatcher.ManagedPlugin

dat, err := os.ReadFile(c.manifest)
if err != nil {
return err
}

err = json.Unmarshal(dat, &manifest)
if err != nil {
return err
}

var found bool
newManifest := []*pluginswatcher.ManagedPlugin{}

for _, p := range manifest {
if p.Name == c.name {
fmt.Printf("Removing plugin %s\n", c.name)
found = true
continue
}

newManifest = append(newManifest, p)
}

if !found {
return fmt.Errorf("no plugin named %s found", c.name)
}

dat, err = json.MarshalIndent(newManifest, "", " ")
if err != nil {
return err
}

err = os.WriteFile(c.manifest, dat, 0600)
if err != nil {
return err
}

fmt.Printf("Use the pack command to sign the %s manifest\n", c.manifest)

return nil
}

0 comments on commit 88c4922

Please sign in to comment.