mirror of https://github.com/docker/cli.git
Add a field to the config file for plugin use.
This is a bit manual (as the unit test attests) so we may find we want to add some helpers/accessors, but this is enough to let plugins use it and to preserve the information through round-trips. Signed-off-by: Ian Campbell <ijc@docker.com>
This commit is contained in:
parent
3ddb3133f5
commit
4eb642be46
|
@ -49,6 +49,7 @@ type ConfigFile struct {
|
||||||
Kubernetes *KubernetesConfig `json:"kubernetes,omitempty"`
|
Kubernetes *KubernetesConfig `json:"kubernetes,omitempty"`
|
||||||
CurrentContext string `json:"currentContext,omitempty"`
|
CurrentContext string `json:"currentContext,omitempty"`
|
||||||
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
||||||
|
Plugins map[string]json.RawMessage `json:"plugins,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyConfig contains proxy configuration settings
|
// ProxyConfig contains proxy configuration settings
|
||||||
|
@ -70,6 +71,7 @@ func New(fn string) *ConfigFile {
|
||||||
AuthConfigs: make(map[string]types.AuthConfig),
|
AuthConfigs: make(map[string]types.AuthConfig),
|
||||||
HTTPHeaders: make(map[string]string),
|
HTTPHeaders: make(map[string]string),
|
||||||
Filename: fn,
|
Filename: fn,
|
||||||
|
Plugins: make(map[string]json.RawMessage),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package configfile
|
package configfile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -9,6 +11,7 @@ import (
|
||||||
"github.com/docker/cli/cli/config/types"
|
"github.com/docker/cli/cli/config/types"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
is "gotest.tools/assert/cmp"
|
is "gotest.tools/assert/cmp"
|
||||||
|
"gotest.tools/golden"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeAuth(t *testing.T) {
|
func TestEncodeAuth(t *testing.T) {
|
||||||
|
@ -429,3 +432,64 @@ func TestSave(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
|
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPluginConfig(t *testing.T) {
|
||||||
|
configFile := New("test-plugin")
|
||||||
|
defer os.Remove("test-plugin")
|
||||||
|
|
||||||
|
type PluginConfig1 struct {
|
||||||
|
Data1 string `json:"data1"`
|
||||||
|
Data2 int `json:"data2"`
|
||||||
|
}
|
||||||
|
type PluginConfig2 struct {
|
||||||
|
Data3 string `json:"data3"`
|
||||||
|
}
|
||||||
|
p1 := PluginConfig1{
|
||||||
|
Data1: "some string",
|
||||||
|
Data2: 42,
|
||||||
|
}
|
||||||
|
p2 := PluginConfig2{
|
||||||
|
Data3: "some other string",
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin1, err := json.MarshalIndent(p1, "", "\t")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
configFile.Plugins["plugin1"] = plugin1
|
||||||
|
|
||||||
|
plugin2, err := json.MarshalIndent(p2, "", "\t")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
configFile.Plugins["plugin2"] = plugin2
|
||||||
|
|
||||||
|
// Save a config file with some plugin config
|
||||||
|
err = configFile.Save()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
// Read it back and check it has the expected content
|
||||||
|
cfg, err := ioutil.ReadFile("test-plugin")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
golden.Assert(t, string(cfg), "plugin-config.golden")
|
||||||
|
|
||||||
|
// Load it, resave and check again that the content is
|
||||||
|
// preserved through a load/save cycle.
|
||||||
|
configFile2 := New("test-plugin2")
|
||||||
|
defer os.Remove("test-plugin2")
|
||||||
|
assert.NilError(t, configFile2.LoadFromReader(bytes.NewReader(cfg)))
|
||||||
|
err = configFile2.Save()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
cfg, err = ioutil.ReadFile("test-plugin2")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
golden.Assert(t, string(cfg), "plugin-config.golden")
|
||||||
|
|
||||||
|
// Check that the contents was retained properly
|
||||||
|
var p1bis PluginConfig1
|
||||||
|
assert.Assert(t, is.Contains(configFile2.Plugins, "plugin1"))
|
||||||
|
err = json.Unmarshal(configFile2.Plugins["plugin1"], &p1bis)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.DeepEqual(t, p1, p1bis)
|
||||||
|
|
||||||
|
var p2bis PluginConfig2
|
||||||
|
assert.Assert(t, is.Contains(configFile2.Plugins, "plugin2"))
|
||||||
|
err = json.Unmarshal(configFile2.Plugins["plugin2"], &p2bis)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.DeepEqual(t, p2, p2bis)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"auths": {},
|
||||||
|
"plugins": {
|
||||||
|
"plugin1": {
|
||||||
|
"data1": "some string",
|
||||||
|
"data2": 42
|
||||||
|
},
|
||||||
|
"plugin2": {
|
||||||
|
"data3": "some other string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,6 +75,18 @@ A plugin is required to support all of the global options of the
|
||||||
top-level CLI, i.e. those listed by `man docker 1` with the exception
|
top-level CLI, i.e. those listed by `man docker 1` with the exception
|
||||||
of `-v`.
|
of `-v`.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Plugins are expected to make use of existing global configuration
|
||||||
|
where it makes sense and likewise to consider extending the global
|
||||||
|
configuration (by patching `docker/cli` to add new fields) where that
|
||||||
|
is sensible.
|
||||||
|
|
||||||
|
Where plugins unavoidably require specific configuration the
|
||||||
|
`.plugins.«name»` key in the global `config.json` is reserved for
|
||||||
|
their use. However the preference should be for shared/global
|
||||||
|
configuration whenever that makes sense.
|
||||||
|
|
||||||
## Connecting to the docker engine
|
## Connecting to the docker engine
|
||||||
|
|
||||||
For consistency plugins should prefer to dial the engine by using the
|
For consistency plugins should prefer to dial the engine by using the
|
||||||
|
|
Loading…
Reference in New Issue