forked from ebhomengo/niki
420 lines
14 KiB
Go
420 lines
14 KiB
Go
|
// Copyright © 2024 Ory Corp
|
||
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
|
||
|
// Copyright 2018 go-dockerclient authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package docker
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
)
|
||
|
|
||
|
// PluginPrivilege represents a privilege for a plugin.
|
||
|
type PluginPrivilege struct {
|
||
|
Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
|
||
|
Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
|
||
|
Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"`
|
||
|
}
|
||
|
|
||
|
// InstallPluginOptions specify parameters to the InstallPlugins function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type InstallPluginOptions struct {
|
||
|
Remote string
|
||
|
Name string
|
||
|
Plugins []PluginPrivilege `qs:"-"`
|
||
|
|
||
|
Auth AuthConfiguration
|
||
|
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// InstallPlugins installs a plugin or returns an error in case of failure.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) InstallPlugins(opts InstallPluginOptions) error {
|
||
|
path := "/plugins/pull?" + queryString(opts)
|
||
|
resp, err := c.do("POST", path, doOptions{
|
||
|
data: opts.Plugins,
|
||
|
context: opts.Context,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// PluginSettings stores plugin settings.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginSettings struct {
|
||
|
Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
|
||
|
Args []string `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"`
|
||
|
Devices []string `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginInterface stores plugin interface.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginInterface struct {
|
||
|
Types []string `json:"Types,omitempty" yaml:"Types,omitempty" toml:"Types,omitempty"`
|
||
|
Socket string `json:"Socket,omitempty" yaml:"Socket,omitempty" toml:"Socket,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginNetwork stores plugin network type.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginNetwork struct {
|
||
|
Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginLinux stores plugin linux setting.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginLinux struct {
|
||
|
Capabilities []string `json:"Capabilities,omitempty" yaml:"Capabilities,omitempty" toml:"Capabilities,omitempty"`
|
||
|
AllowAllDevices bool `json:"AllowAllDevices,omitempty" yaml:"AllowAllDevices,omitempty" toml:"AllowAllDevices,omitempty"`
|
||
|
Devices []PluginLinuxDevices `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginLinuxDevices stores plugin linux device setting.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginLinuxDevices struct {
|
||
|
Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
|
||
|
Description string `json:"Documentation,omitempty" yaml:"Documentation,omitempty" toml:"Documentation,omitempty"`
|
||
|
Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"`
|
||
|
Path string `json:"Path,omitempty" yaml:"Path,omitempty" toml:"Path,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginEnv stores plugin environment.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginEnv struct {
|
||
|
Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
|
||
|
Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
|
||
|
Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"`
|
||
|
Value string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginArgs stores plugin arguments.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginArgs struct {
|
||
|
Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
|
||
|
Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
|
||
|
Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"`
|
||
|
Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginUser stores plugin user.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginUser struct {
|
||
|
UID int32 `json:"UID,omitempty" yaml:"UID,omitempty" toml:"UID,omitempty"`
|
||
|
GID int32 `json:"GID,omitempty" yaml:"GID,omitempty" toml:"GID,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginConfig stores plugin config.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginConfig struct {
|
||
|
Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
|
||
|
Documentation string
|
||
|
Interface PluginInterface `json:"Interface,omitempty" yaml:"Interface,omitempty" toml:"Interface,omitempty"`
|
||
|
Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty" toml:"Entrypoint,omitempty"`
|
||
|
WorkDir string `json:"WorkDir,omitempty" yaml:"WorkDir,omitempty" toml:"WorkDir,omitempty"`
|
||
|
User PluginUser `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"`
|
||
|
Network PluginNetwork `json:"Network,omitempty" yaml:"Network,omitempty" toml:"Network,omitempty"`
|
||
|
Linux PluginLinux `json:"Linux,omitempty" yaml:"Linux,omitempty" toml:"Linux,omitempty"`
|
||
|
PropagatedMount string `json:"PropagatedMount,omitempty" yaml:"PropagatedMount,omitempty" toml:"PropagatedMount,omitempty"`
|
||
|
Mounts []Mount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"`
|
||
|
Env []PluginEnv `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
|
||
|
Args PluginArgs `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PluginDetail specify results from the ListPlugins function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PluginDetail struct {
|
||
|
ID string `json:"Id,omitempty" yaml:"Id,omitempty" toml:"Id,omitempty"`
|
||
|
Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
|
||
|
Tag string `json:"Tag,omitempty" yaml:"Tag,omitempty" toml:"Tag,omitempty"`
|
||
|
Active bool `json:"Active,omitempty" yaml:"Active,omitempty" toml:"Active,omitempty"`
|
||
|
Settings PluginSettings `json:"Settings,omitempty" yaml:"Settings,omitempty" toml:"Settings,omitempty"`
|
||
|
Config PluginConfig `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"`
|
||
|
}
|
||
|
|
||
|
// ListPlugins returns pluginDetails or an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) ListPlugins(ctx context.Context) ([]PluginDetail, error) {
|
||
|
resp, err := c.do("GET", "/plugins", doOptions{
|
||
|
context: ctx,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
pluginDetails := make([]PluginDetail, 0)
|
||
|
if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return pluginDetails, nil
|
||
|
}
|
||
|
|
||
|
// ListFilteredPluginsOptions specify parameters to the ListFilteredPlugins function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type ListFilteredPluginsOptions struct {
|
||
|
Filters map[string][]string
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// ListFilteredPlugins returns pluginDetails or an error.
|
||
|
//
|
||
|
// See https://goo.gl/rmdmWg for more details.
|
||
|
func (c *Client) ListFilteredPlugins(opts ListFilteredPluginsOptions) ([]PluginDetail, error) {
|
||
|
path := "/plugins/json?" + queryString(opts)
|
||
|
resp, err := c.do("GET", path, doOptions{
|
||
|
context: opts.Context,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
pluginDetails := make([]PluginDetail, 0)
|
||
|
if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return pluginDetails, nil
|
||
|
}
|
||
|
|
||
|
// GetPluginPrivileges returns pulginPrivileges or an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) GetPluginPrivileges(name string, ctx context.Context) ([]PluginPrivilege, error) {
|
||
|
resp, err := c.do("GET", "/plugins/privileges?remote="+name, doOptions{
|
||
|
context: ctx,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
var pluginPrivileges []PluginPrivilege
|
||
|
if err := json.NewDecoder(resp.Body).Decode(&pluginPrivileges); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return pluginPrivileges, nil
|
||
|
}
|
||
|
|
||
|
// InspectPlugins returns a pluginDetail or an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) InspectPlugins(name string, ctx context.Context) (*PluginDetail, error) {
|
||
|
resp, err := c.do("GET", "/plugins/"+name+"/json", doOptions{
|
||
|
context: ctx,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
if err != nil {
|
||
|
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||
|
return nil, &NoSuchPlugin{ID: name}
|
||
|
}
|
||
|
return nil, err
|
||
|
}
|
||
|
resp.Body.Close()
|
||
|
var pluginDetail PluginDetail
|
||
|
if err := json.NewDecoder(resp.Body).Decode(&pluginDetail); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &pluginDetail, nil
|
||
|
}
|
||
|
|
||
|
// RemovePluginOptions specify parameters to the RemovePlugin function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type RemovePluginOptions struct {
|
||
|
// The Name of the plugin.
|
||
|
Name string `qs:"-"`
|
||
|
|
||
|
Force bool `qs:"force"`
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// RemovePlugin returns a PluginDetail or an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) RemovePlugin(opts RemovePluginOptions) (*PluginDetail, error) {
|
||
|
path := "/plugins/" + opts.Name + "?" + queryString(opts)
|
||
|
resp, err := c.do("DELETE", path, doOptions{context: opts.Context})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
if err != nil {
|
||
|
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||
|
return nil, &NoSuchPlugin{ID: opts.Name}
|
||
|
}
|
||
|
return nil, err
|
||
|
}
|
||
|
resp.Body.Close()
|
||
|
var pluginDetail PluginDetail
|
||
|
if err := json.NewDecoder(resp.Body).Decode(&pluginDetail); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &pluginDetail, nil
|
||
|
}
|
||
|
|
||
|
// EnablePluginOptions specify parameters to the EnablePlugin function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type EnablePluginOptions struct {
|
||
|
// The Name of the plugin.
|
||
|
Name string `qs:"-"`
|
||
|
Timeout int64 `qs:"timeout"`
|
||
|
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// EnablePlugin enables plugin that opts point or returns an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) EnablePlugin(opts EnablePluginOptions) error {
|
||
|
path := "/plugins/" + opts.Name + "/enable?" + queryString(opts)
|
||
|
resp, err := c.do("POST", path, doOptions{context: opts.Context})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// DisablePluginOptions specify parameters to the DisablePlugin function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type DisablePluginOptions struct {
|
||
|
// The Name of the plugin.
|
||
|
Name string `qs:"-"`
|
||
|
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// DisablePlugin disables plugin that opts point or returns an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) DisablePlugin(opts DisablePluginOptions) error {
|
||
|
path := "/plugins/" + opts.Name + "/disable"
|
||
|
resp, err := c.do("POST", path, doOptions{context: opts.Context})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// CreatePluginOptions specify parameters to the CreatePlugin function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type CreatePluginOptions struct {
|
||
|
// The Name of the plugin.
|
||
|
Name string `qs:"name"`
|
||
|
// Path to tar containing plugin
|
||
|
Path string `qs:"-"`
|
||
|
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// CreatePlugin creates plugin that opts point or returns an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) CreatePlugin(opts CreatePluginOptions) (string, error) {
|
||
|
path := "/plugins/create?" + queryString(opts)
|
||
|
resp, err := c.do("POST", path, doOptions{
|
||
|
data: opts.Path,
|
||
|
context: opts.Context})
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
containerNameBytes, err := io.ReadAll(resp.Body)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return string(containerNameBytes), nil
|
||
|
}
|
||
|
|
||
|
// PushPluginOptions specify parameters to PushPlugin function.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type PushPluginOptions struct {
|
||
|
// The Name of the plugin.
|
||
|
Name string
|
||
|
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// PushPlugin pushes plugin that opts point or returns an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) PushPlugin(opts PushPluginOptions) error {
|
||
|
path := "/plugins/" + opts.Name + "/push"
|
||
|
resp, err := c.do("POST", path, doOptions{context: opts.Context})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// ConfigurePluginOptions specify parameters to the ConfigurePlugin
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
type ConfigurePluginOptions struct {
|
||
|
// The Name of the plugin.
|
||
|
Name string `qs:"name"`
|
||
|
Envs []string
|
||
|
|
||
|
Context context.Context
|
||
|
}
|
||
|
|
||
|
// ConfigurePlugin configures plugin that opts point or returns an error.
|
||
|
//
|
||
|
// See https://goo.gl/C4t7Tz for more details.
|
||
|
func (c *Client) ConfigurePlugin(opts ConfigurePluginOptions) error {
|
||
|
path := "/plugins/" + opts.Name + "/set"
|
||
|
resp, err := c.do("POST", path, doOptions{
|
||
|
data: opts.Envs,
|
||
|
context: opts.Context,
|
||
|
})
|
||
|
if err != nil {
|
||
|
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||
|
return &NoSuchPlugin{ID: opts.Name}
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// NoSuchPlugin is the error returned when a given plugin does not exist.
|
||
|
type NoSuchPlugin struct {
|
||
|
ID string
|
||
|
Err error
|
||
|
}
|
||
|
|
||
|
func (err *NoSuchPlugin) Error() string {
|
||
|
if err.Err != nil {
|
||
|
return err.Err.Error()
|
||
|
}
|
||
|
return "No such plugin: " + err.ID
|
||
|
}
|