Support registering plugin with name only (#5787)

* Support registering plugin with name only

* Make RegisterPlugin backwards compatible

* Add CLI backwards compat command to plugin info and deregister

* Add server-side deprecation warnings if old read/dereg API endpoints are called

* Address feedback
This commit is contained in:
Calvin Leung Huang 2018-11-15 14:33:11 -08:00 committed by GitHub
parent 192c8b5c84
commit e99957aed9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 93 additions and 24 deletions

View File

@ -129,8 +129,9 @@ type GetPluginResponse struct {
SHA256 string `json:"sha256"`
}
// GetPlugin retrieves information about the plugin.
func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) {
path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", i.Type, i.Name)
path := catalogPathByType(i.Type, i.Name)
req := c.c.NewRequest(http.MethodGet, path)
ctx, cancelFunc := context.WithCancel(context.Background())
@ -142,13 +143,13 @@ func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) {
defer resp.Body.Close()
var result struct {
Data GetPluginResponse
Data *GetPluginResponse
}
err = resp.DecodeJSON(&result)
if err != nil {
return nil, err
}
return &result.Data, err
return result.Data, err
}
// RegisterPluginInput is used as input to the RegisterPlugin function.
@ -171,8 +172,9 @@ type RegisterPluginInput struct {
// RegisterPlugin registers the plugin with the given information.
func (c *Sys) RegisterPlugin(i *RegisterPluginInput) error {
path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", i.Type, i.Name)
path := catalogPathByType(i.Type, i.Name)
req := c.c.NewRequest(http.MethodPut, path)
if err := req.SetJSONBody(i); err != nil {
return err
}
@ -198,7 +200,7 @@ type DeregisterPluginInput struct {
// DeregisterPlugin removes the plugin with the given name from the plugin
// catalog.
func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error {
path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", i.Type, i.Name)
path := catalogPathByType(i.Type, i.Name)
req := c.c.NewRequest(http.MethodDelete, path)
ctx, cancelFunc := context.WithCancel(context.Background())
@ -209,3 +211,15 @@ func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error {
}
return err
}
// catalogPathByType is a helper to construct the proper API path by plugin type
func catalogPathByType(pluginType consts.PluginType, name string) string {
path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", pluginType, name)
// Backwards compat, if type is not provided then use old path
if pluginType == consts.PluginTypeUnknown {
path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", name)
}
return path
}

View File

@ -58,14 +58,23 @@ func (c *PluginDeregisterCommand) Run(args []string) int {
return 1
}
var pluginNameRaw, pluginTypeRaw string
args = f.Args()
switch {
case len(args) < 2:
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 2, got %d)", len(args)))
case len(args) < 1:
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1 or 2, got %d)", len(args)))
return 1
case len(args) > 2:
c.UI.Error(fmt.Sprintf("Too many arguments (expected 2, got %d)", len(args)))
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1 or 2, got %d)", len(args)))
return 1
// These cases should come after invalid cases have been checked
case len(args) == 1:
pluginTypeRaw = "unknown"
pluginNameRaw = args[0]
case len(args) == 2:
pluginTypeRaw = args[0]
pluginNameRaw = args[1]
}
client, err := c.Client()
@ -74,12 +83,12 @@ func (c *PluginDeregisterCommand) Run(args []string) int {
return 2
}
pluginType, err := consts.ParsePluginType(strings.TrimSpace(args[0]))
pluginType, err := consts.ParsePluginType(strings.TrimSpace(pluginTypeRaw))
if err != nil {
c.UI.Error(err.Error())
return 2
}
pluginName := strings.TrimSpace(args[1])
pluginName := strings.TrimSpace(pluginNameRaw)
if err := client.Sys().DeregisterPlugin(&api.DeregisterPluginInput{
Name: pluginName,

View File

@ -58,14 +58,23 @@ func (c *PluginInfoCommand) Run(args []string) int {
return 1
}
var pluginNameRaw, pluginTypeRaw string
args = f.Args()
switch {
case len(args) < 2:
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
case len(args) < 1:
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1 or 2, got %d)", len(args)))
return 1
case len(args) > 2:
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1 or 2, got %d)", len(args)))
return 1
// These cases should come after invalid cases have been checked
case len(args) == 1:
pluginTypeRaw = "unknown"
pluginNameRaw = args[0]
case len(args) == 2:
pluginTypeRaw = args[0]
pluginNameRaw = args[1]
}
client, err := c.Client()
@ -74,12 +83,12 @@ func (c *PluginInfoCommand) Run(args []string) int {
return 2
}
pluginType, err := consts.ParsePluginType(strings.TrimSpace(args[0]))
pluginType, err := consts.ParsePluginType(strings.TrimSpace(pluginTypeRaw))
if err != nil {
c.UI.Error(err.Error())
return 2
}
pluginName := strings.TrimSpace(args[1])
pluginName := strings.TrimSpace(pluginNameRaw)
resp, err := client.Sys().GetPlugin(&api.GetPluginInput{
Name: pluginName,
@ -90,6 +99,11 @@ func (c *PluginInfoCommand) Run(args []string) int {
return 2
}
if resp == nil {
c.UI.Error(fmt.Sprintf("No value found for plugin %q", pluginName))
return 2
}
data := map[string]interface{}{
"args": resp.Args,
"builtin": resp.Builtin,

View File

@ -96,17 +96,26 @@ func (c *PluginRegisterCommand) Run(args []string) int {
return 1
}
var pluginNameRaw, pluginTypeRaw string
args = f.Args()
switch {
case len(args) < 2:
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 2, got %d)", len(args)))
case len(args) < 1:
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1 or 2, got %d)", len(args)))
return 1
case len(args) > 2:
c.UI.Error(fmt.Sprintf("Too many arguments (expected 2, got %d)", len(args)))
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1 or 2, got %d)", len(args)))
return 1
case c.flagSHA256 == "":
c.UI.Error("SHA256 is required for all plugins, please provide -sha256")
return 1
// These cases should come after invalid cases have been checked
case len(args) == 1:
pluginTypeRaw = "unknown"
pluginNameRaw = args[0]
case len(args) == 2:
pluginTypeRaw = args[0]
pluginNameRaw = args[1]
}
client, err := c.Client()
@ -115,12 +124,12 @@ func (c *PluginRegisterCommand) Run(args []string) int {
return 2
}
pluginType, err := consts.ParsePluginType(strings.TrimSpace(args[0]))
pluginType, err := consts.ParsePluginType(strings.TrimSpace(pluginTypeRaw))
if err != nil {
c.UI.Error(err.Error())
return 2
}
pluginName := strings.TrimSpace(args[1])
pluginName := strings.TrimSpace(pluginNameRaw)
command := c.flagCommand
if command == "" {

View File

@ -54,6 +54,6 @@ func ParsePluginType(pluginType string) (PluginType, error) {
case "secret":
return PluginTypeSecrets, nil
default:
return PluginTypeUnknown, fmt.Errorf("%s is not a supported plugin type", pluginType)
return PluginTypeUnknown, fmt.Errorf("%q is not a supported plugin type", pluginType)
}
}

View File

@ -349,7 +349,17 @@ func (b *SystemBackend) handlePluginCatalogRead(ctx context.Context, req *logica
return logical.ErrorResponse("missing plugin name"), nil
}
pluginType, err := consts.ParsePluginType(d.Get("type").(string))
pluginTypeStr := d.Get("type").(string)
if pluginTypeStr == "" {
// If the plugin type is not provided (i.e. the old
// sys/plugins/catalog/:name endpoint is being requested) short-circuit here
// and return a warning
resp := &logical.Response{}
resp.AddWarning(fmt.Sprintf("Deprecated API endpoint, cannot read plugin information from catalog for %q", pluginName))
return resp, nil
}
pluginType, err := consts.ParsePluginType(pluginTypeStr)
if err != nil {
return nil, err
}
@ -388,7 +398,20 @@ func (b *SystemBackend) handlePluginCatalogDelete(ctx context.Context, req *logi
if pluginName == "" {
return logical.ErrorResponse("missing plugin name"), nil
}
pluginType, err := consts.ParsePluginType(d.Get("type").(string))
var resp *logical.Response
pluginTypeStr := d.Get("type").(string)
if pluginTypeStr == "" {
// If the plugin type is not provided (i.e. the old
// sys/plugins/catalog/:name endpoint is being requested), set type to
// unknown and let pluginCatalog.Delete proceed. It should handle
// deregistering out of the old storage path (root of core/plugin-catalog)
resp = new(logical.Response)
resp.AddWarning(fmt.Sprintf("Deprecated API endpoint, cannot deregister plugin from catalog for %q", pluginName))
pluginTypeStr = "unknown"
}
pluginType, err := consts.ParsePluginType(pluginTypeStr)
if err != nil {
return nil, err
}
@ -396,7 +419,7 @@ func (b *SystemBackend) handlePluginCatalogDelete(ctx context.Context, req *logi
return nil, err
}
return nil, nil
return resp, nil
}
func (b *SystemBackend) handlePluginReloadUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {