cli: Add -config flag to "acl authmethod update/create" (#7776)

This commit is contained in:
s-christoff 2020-05-04 16:21:28 -05:00 committed by GitHub
parent c74575d446
commit 2535cb85eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 301 additions and 8 deletions

View File

@ -1,6 +1,7 @@
package authmethodcreate
import (
"encoding/json"
"flag"
"fmt"
"io"
@ -33,6 +34,7 @@ type cmd struct {
k8sHost string
k8sCACert string
k8sServiceAccountJWT string
config string
showMeta bool
format string
@ -105,6 +107,14 @@ func (c *cmd) init() {
authmethod.PrettyFormat,
fmt.Sprintf("Output format {%s}", strings.Join(authmethod.GetSupportedFormats(), "|")),
)
c.flags.StringVar(
&c.config,
"config",
"",
"The configuration for the auth method. Must be JSON. May be prefixed with '@' "+
"to indicate that the value is a file path to load the config from. '-' may also be "+
"given to indicate that the config is available on stdin",
)
c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags())
@ -141,6 +151,24 @@ func (c *cmd) Run(args []string) int {
Description: c.description,
}
if c.config != "" {
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
c.UI.Error(fmt.Sprintf("Cannot use command line arguments with '-config' flags"))
return 1
}
data, err := helpers.LoadDataSource(c.config, c.testStdin)
if err != nil {
c.UI.Error(fmt.Sprintf("Error loading configuration file: %v", err))
return 1
}
err = json.Unmarshal([]byte(data), &newAuthMethod.Config)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing JSON configuration file: %v", err))
return 1
}
}
if c.authMethodType == "kubernetes" {
if c.k8sHost == "" {
c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag"))

View File

@ -2,6 +2,7 @@ package authmethodcreate
import (
"encoding/json"
"io"
"io/ioutil"
"os"
"path/filepath"
@ -282,7 +283,7 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
cmd := New(ui)
code := cmd.Run(args)
require.Equal(t, code, 0)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
got := getTestMethod(t, client, name)
@ -334,6 +335,96 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
})
}
func TestAuthMethodCreateCommand_config(t *testing.T) {
t.Parallel()
testDir := testutil.TempDir(t, "auth-method")
defer os.RemoveAll(testDir)
a := agent.NewTestAgent(t, `
primary_datacenter = "dc1"
acl {
enabled = true
tokens {
master = "root"
}
}`)
defer a.Shutdown()
testrpc.WaitForLeader(t, a.RPC, "dc1")
client := a.Client()
checkMethod := func(t *testing.T, methodName string) {
method, _, err := client.ACL().AuthMethodRead(
methodName,
&api.QueryOptions{Token: "root"},
)
require.NoError(t, err)
require.NotNil(t, method)
require.Equal(t, "foo", method.Config["SessionID"])
}
t.Run("config file", func(t *testing.T) {
configFile := filepath.Join(testDir, "config.json")
jsonConfig := `{"SessionID":"foo"}`
require.NoError(t, ioutil.WriteFile(configFile, []byte(jsonConfig), 0644))
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-token=root",
"-type=testing",
"-name=test",
"-config=@" + configFile,
}
ui := cli.NewMockUi()
cmd := New(ui)
code := cmd.Run(args)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
checkMethod(t, "test")
})
t.Run("config std-in", func(t *testing.T) {
stdinR, stdinW := io.Pipe()
ui := cli.NewMockUi()
cmd := New(ui)
cmd.testStdin = stdinR
go func() {
stdinW.Write([]byte(`{"SessionID":"foo"}`))
stdinW.Close()
}()
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-token=root",
"-type=testing",
"-name=test2",
"-config=-",
}
code := cmd.Run(args)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
checkMethod(t, "test2")
})
t.Run("config string", func(t *testing.T) {
ui := cli.NewMockUi()
cmd := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-token=root",
"-type=testing",
"-name=test3",
"-config=" + `{"SessionID":"foo"}`,
}
code := cmd.Run(args)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
checkMethod(t, "test3")
})
}
func getTestMethod(t *testing.T, client *api.Client, methodName string) *api.ACLAuthMethod {
t.Helper()
@ -357,4 +448,5 @@ func getTestName(t *testing.T) string {
id, err := uuid.GenerateUUID()
require.NoError(t, err)
return "test-" + id
}

View File

@ -1,6 +1,7 @@
package authmethodupdate
import (
"encoding/json"
"flag"
"fmt"
"io"
@ -27,9 +28,9 @@ type cmd struct {
name string
displayName string
description string
displayName string
description string
config string
k8sHost string
k8sCACert string
k8sServiceAccountJWT string
@ -73,6 +74,15 @@ func (c *cmd) init() {
"A description of the auth method.",
)
c.flags.StringVar(
&c.config,
"config",
"",
"The configuration for the auth method. Must be JSON. The config is updated as one field"+
"May be prefixed with '@' to indicate that the value is a file path to load the config from. "+
"'-' may also be given to indicate that the config are available on stdin. ",
)
c.flags.StringVar(
&c.k8sHost,
"kubernetes-host",
@ -100,6 +110,7 @@ func (c *cmd) init() {
c.flags.BoolVar(&c.noMerge, "no-merge", false, "Do not merge the current auth method "+
"information with what is provided to the command. Instead overwrite all fields "+
"with the exception of the name which is immutable.")
c.flags.StringVar(
&c.format,
"format",
@ -158,7 +169,21 @@ func (c *cmd) Run(args []string) int {
DisplayName: c.displayName,
Description: c.description,
}
if c.config != "" {
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
c.UI.Error(fmt.Sprintf("Cannot use command line arguments with '-config' flag"))
return 1
}
data, err := helpers.LoadDataSource(c.config, c.testStdin)
if err != nil {
c.UI.Error(fmt.Sprintf("Error loading configuration file: %v", err))
return 1
}
if err := json.Unmarshal([]byte(data), &method.Config); err != nil {
c.UI.Error(fmt.Sprintf("Error parsing JSON for auth method config: %v", err))
return 1
}
}
if currentAuthMethod.Type == "kubernetes" {
if c.k8sHost == "" {
c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag"))
@ -180,12 +205,26 @@ func (c *cmd) Run(args []string) int {
} else {
methodCopy := *currentAuthMethod
method = &methodCopy
if c.description != "" {
method.Description = c.description
}
if c.displayName != "" {
method.DisplayName = c.displayName
}
if c.description != "" {
method.Description = c.description
if c.config != "" {
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
c.UI.Error(fmt.Sprintf("Cannot use command line arguments with '-config' flag"))
return 1
}
data, err := helpers.LoadDataSource(c.config, c.testStdin)
if err != nil {
c.UI.Error(fmt.Sprintf("Error loading configuration file: %v", err))
return 1
}
if err := json.Unmarshal([]byte(data), &method.Config); err != nil {
c.UI.Error(fmt.Sprintf("Error parsing JSON for auth method config: %v", err))
return 1
}
}
if method.Config == nil {
method.Config = make(map[string]interface{})

View File

@ -2,6 +2,7 @@ package authmethodupdate
import (
"encoding/json"
"io"
"io/ioutil"
"os"
"path/filepath"
@ -743,6 +744,138 @@ func TestAuthMethodUpdateCommand_k8s_noMerge(t *testing.T) {
})
}
func TestAuthMethodUpdateCommand_config(t *testing.T) {
t.Parallel()
testDir := testutil.TempDir(t, "auth-method")
defer os.RemoveAll(testDir)
a := agent.NewTestAgent(t, `
primary_datacenter = "dc1"
acl {
enabled = true
tokens {
master = "root"
}
}`)
defer a.Shutdown()
testrpc.WaitForLeader(t, a.RPC, "dc1")
client := a.Client()
createAuthMethod := func(t *testing.T) string {
id, err := uuid.GenerateUUID()
require.NoError(t, err)
methodName := "test" + id
_, _, err = client.ACL().AuthMethodCreate(
&api.ACLAuthMethod{
Name: methodName,
Type: "testing",
Description: "test",
Config: map[string]interface{}{
"SessionID": "big",
},
},
&api.WriteOptions{Token: "root"},
)
require.NoError(t, err)
return methodName
}
readUpdate := func(t *testing.T, methodName string) {
method, _, err := client.ACL().AuthMethodRead(
methodName,
&api.QueryOptions{Token: "root"},
)
require.NoError(t, err)
require.NotNil(t, method)
require.Equal(t, "update", method.Config["SessionID"])
}
t.Run("config file", func(t *testing.T) {
methodName := createAuthMethod(t)
configFile := filepath.Join(testDir, "config.json")
jsonConfig := `{"SessionID":"update"}`
require.NoError(t, ioutil.WriteFile(configFile, []byte(jsonConfig), 0644))
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-token=root",
"-name=" + methodName,
"-no-merge=true",
"-config=@" + configFile,
}
ui := cli.NewMockUi()
cmd := New(ui)
code := cmd.Run(args)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
readUpdate(t, methodName)
})
t.Run("config stdin", func(t *testing.T) {
methodName := createAuthMethod(t)
ui := cli.NewMockUi()
cmd := New(ui)
stdinR, stdinW := io.Pipe()
cmd.testStdin = stdinR
go func() {
stdinW.Write([]byte(`{"SessionID":"update"}`))
stdinW.Close()
}()
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-token=root",
"-name=" + methodName,
"-no-merge=true",
"-config=-",
}
code := cmd.Run(args)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
readUpdate(t, methodName)
})
t.Run("config string", func(t *testing.T) {
methodName := createAuthMethod(t)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-token=root",
"-name=" + methodName,
"-no-merge=true",
"-config=" + `{"SessionID":"update"}`,
}
ui := cli.NewMockUi()
cmd := New(ui)
code := cmd.Run(args)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
readUpdate(t, methodName)
})
t.Run("config with no merge", func(t *testing.T) {
methodName := createAuthMethod(t)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-token=root",
"-name=" + methodName,
"-no-merge=false",
"-config=" + `{"SessionID":"update"}`,
}
ui := cli.NewMockUi()
cmd := New(ui)
code := cmd.Run(args)
require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String())
readUpdate(t, methodName)
})
}
func getTestMethod(t *testing.T, client *api.Client, methodName string) *api.ACLAuthMethod {
t.Helper()
@ -766,4 +899,5 @@ func getTestName(t *testing.T) string {
id, err := uuid.GenerateUUID()
require.NoError(t, err)
return "test-" + id
}