Adds update option to plugin command

Fixes issues/2385 - helm install silently updates the plugin, if it pre-existed
pull/2410/head
Sushil Kumar 9 years ago
parent 3e5642a40a
commit 8047237fd3

@ -41,6 +41,7 @@ func newPluginCmd(out io.Writer) *cobra.Command {
newPluginInstallCmd(out), newPluginInstallCmd(out),
newPluginListCmd(out), newPluginListCmd(out),
newPluginRemoveCmd(out), newPluginRemoveCmd(out),
newPluginUpdateCmd(out),
) )
return cmd return cmd
} }

@ -0,0 +1,109 @@
/*
Copyright 2017 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"errors"
"fmt"
"io"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/plugin"
"k8s.io/helm/pkg/plugin/installer"
"path/filepath"
"github.com/spf13/cobra"
)
type pluginUpdateCmd struct {
names []string
home helmpath.Home
out io.Writer
}
func newPluginUpdateCmd(out io.Writer) *cobra.Command {
pcmd := &pluginUpdateCmd{out: out}
cmd := &cobra.Command{
Use: "update <plugin>...",
Short: "update one or more Helm plugins",
PreRunE: func(cmd *cobra.Command, args []string) error {
return pcmd.complete(args)
},
RunE: func(cmd *cobra.Command, args []string) error {
return pcmd.run()
},
}
return cmd
}
func (pcmd *pluginUpdateCmd) complete(args []string) error {
if len(args) == 0 {
return errors.New("please provide plugin name to update")
}
pcmd.names = args
pcmd.home = settings.Home
return nil
}
func (pcmd *pluginUpdateCmd) run() error {
installer.Debug = settings.Debug
plugdirs := pluginDirs(pcmd.home)
debug("loading installed plugins from %s", plugdirs)
plugins, err := findPlugins(plugdirs)
if err != nil {
return err
}
for _, name := range pcmd.names {
if found := findPlugin(plugins, name); found != nil {
if err := updatePlugin(found, pcmd.home); err != nil {
fmt.Fprintf(pcmd.out, "Failed to update plugin %s, got error (%v)\n", name, err)
} else {
fmt.Fprintf(pcmd.out, "Updated plugin: %s\n", name)
}
} else {
fmt.Fprintf(pcmd.out, "Plugin: %s not found\n", name)
}
}
return nil
}
func updatePlugin(p *plugin.Plugin, home helmpath.Home) error {
exactLocation, err := filepath.EvalSymlinks(p.Dir)
if err != nil {
return err
}
absExactLocation, err := filepath.Abs(exactLocation)
if err != nil {
return err
}
i, err := installer.FindSource(absExactLocation, home)
if err != nil {
return err
}
if err := installer.Update(i); err != nil {
return err
}
debug("loading plugin from %s", i.Path())
updatedPlugin, err := plugin.LoadDir(i.Path())
if err != nil {
return err
}
return runHook(updatedPlugin, plugin.Update, home)
}

@ -21,6 +21,8 @@ const (
Install = "install" Install = "install"
// Delete is executed after the plugin is removed. // Delete is executed after the plugin is removed.
Delete = "delete" Delete = "delete"
// Update is executed after the plugin is removed.
Update = "update"
) )
// Hooks is a map of events to commands. // Hooks is a map of events to commands.

@ -36,6 +36,8 @@ type Installer interface {
Install() error Install() error
// Path is the directory of the installed plugin. // Path is the directory of the installed plugin.
Path() string Path() string
// Update updates a plugin to $HELM_HOME.
Update() error
} }
// Install installs a plugin to $HELM_HOME. // Install installs a plugin to $HELM_HOME.
@ -47,6 +49,15 @@ func Install(i Installer) error {
return i.Install() return i.Install()
} }
// Update updates a plugin to $HELM_HOME.
func Update(i Installer) error {
if _, pathErr := os.Stat(i.Path()); os.IsNotExist(pathErr) {
return errors.New("plugin does not exists")
}
return i.Update()
}
// NewForSource determines the correct Installer for the given source. // NewForSource determines the correct Installer for the given source.
func NewForSource(source, version string, home helmpath.Home) (Installer, error) { func NewForSource(source, version string, home helmpath.Home) (Installer, error) {
// Check if source is a local directory // Check if source is a local directory
@ -56,6 +67,15 @@ func NewForSource(source, version string, home helmpath.Home) (Installer, error)
return NewVCSInstaller(source, version, home) return NewVCSInstaller(source, version, home)
} }
// FindSource determines the correct Installer for the given source.
func FindSource(location string, home helmpath.Home) (Installer, error) {
installer, err := existingVCSRepo(location, home)
if err != nil && err.Error() == "Cannot detect VCS" {
return installer, errors.New("cannot get information about plugin source")
}
return installer, err
}
// isLocalReference checks if the source exists on the filesystem. // isLocalReference checks if the source exists on the filesystem.
func isLocalReference(source string) bool { func isLocalReference(source string) bool {
_, err := os.Stat(source) _, err := os.Stat(source)

@ -47,3 +47,9 @@ func (i *LocalInstaller) Install() error {
} }
return i.link(src) return i.link(src)
} }
// Update updates a local repository
func (i *LocalInstaller) Update() error {
debug("local repository is auto-updated")
return nil
}

@ -34,6 +34,18 @@ type VCSInstaller struct {
base base
} }
func existingVCSRepo(location string, home helmpath.Home) (Installer, error) {
repo, err := vcs.NewRepo("", location)
if err != nil {
return nil, err
}
i := &VCSInstaller{
Repo: repo,
base: newBase(repo.Remote(), home),
}
return i, err
}
// NewVCSInstaller creates a new VCSInstaller. // NewVCSInstaller creates a new VCSInstaller.
func NewVCSInstaller(source, version string, home helmpath.Home) (*VCSInstaller, error) { func NewVCSInstaller(source, version string, home helmpath.Home) (*VCSInstaller, error) {
key, err := cache.Key(source) key, err := cache.Key(source)
@ -77,6 +89,18 @@ func (i *VCSInstaller) Install() error {
return i.link(i.Repo.LocalPath()) return i.link(i.Repo.LocalPath())
} }
// Update updates a remote repository
func (i *VCSInstaller) Update() error {
debug("updating %s", i.Repo.Remote())
if err := i.Repo.Update(); err != nil {
return err
}
if !isPlugin(i.Repo.LocalPath()) {
return ErrMissingMetadata
}
return nil
}
func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) { func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) {
if i.Version == "" { if i.Version == "" {
return "", nil return "", nil

Loading…
Cancel
Save