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

pull/7779/head
s-christoff 5 years ago committed by GitHub
parent 68499f0204
commit f9956c1c46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,7 @@
package authmethodcreate package authmethodcreate
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"io" "io"
@ -33,6 +34,7 @@ type cmd struct {
k8sHost string k8sHost string
k8sCACert string k8sCACert string
k8sServiceAccountJWT string k8sServiceAccountJWT string
config string
showMeta bool showMeta bool
format string format string
@ -105,6 +107,14 @@ func (c *cmd) init() {
authmethod.PrettyFormat, authmethod.PrettyFormat,
fmt.Sprintf("Output format {%s}", strings.Join(authmethod.GetSupportedFormats(), "|")), 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{} c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags()) flags.Merge(c.flags, c.http.ClientFlags())
@ -141,6 +151,24 @@ func (c *cmd) Run(args []string) int {
Description: c.description, 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.authMethodType == "kubernetes" {
if c.k8sHost == "" { if c.k8sHost == "" {
c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag")) c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag"))

@ -2,6 +2,7 @@ package authmethodcreate
import ( import (
"encoding/json" "encoding/json"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -282,7 +283,7 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
cmd := New(ui) cmd := New(ui)
code := cmd.Run(args) code := cmd.Run(args)
require.Equal(t, code, 0) require.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String()) require.Empty(t, ui.ErrorWriter.String())
got := getTestMethod(t, client, name) 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 { func getTestMethod(t *testing.T, client *api.Client, methodName string) *api.ACLAuthMethod {
t.Helper() t.Helper()
@ -357,4 +448,5 @@ func getTestName(t *testing.T) string {
id, err := uuid.GenerateUUID() id, err := uuid.GenerateUUID()
require.NoError(t, err) require.NoError(t, err)
return "test-" + id return "test-" + id
} }

@ -1,6 +1,7 @@
package authmethodupdate package authmethodupdate
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"io" "io"
@ -29,7 +30,7 @@ type cmd struct {
displayName string displayName string
description string description string
config string
k8sHost string k8sHost string
k8sCACert string k8sCACert string
k8sServiceAccountJWT string k8sServiceAccountJWT string
@ -73,6 +74,15 @@ func (c *cmd) init() {
"A description of the auth method.", "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.flags.StringVar(
&c.k8sHost, &c.k8sHost,
"kubernetes-host", "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 "+ 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 "+ "information with what is provided to the command. Instead overwrite all fields "+
"with the exception of the name which is immutable.") "with the exception of the name which is immutable.")
c.flags.StringVar( c.flags.StringVar(
&c.format, &c.format,
"format", "format",
@ -158,7 +169,21 @@ func (c *cmd) Run(args []string) int {
DisplayName: c.displayName, DisplayName: c.displayName,
Description: c.description, 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 currentAuthMethod.Type == "kubernetes" {
if c.k8sHost == "" { if c.k8sHost == "" {
c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag")) c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag"))
@ -180,12 +205,26 @@ func (c *cmd) Run(args []string) int {
} else { } else {
methodCopy := *currentAuthMethod methodCopy := *currentAuthMethod
method = &methodCopy method = &methodCopy
if c.description != "" {
method.Description = c.description
}
if c.displayName != "" { if c.displayName != "" {
method.DisplayName = c.displayName method.DisplayName = c.displayName
} }
if c.description != "" { if c.config != "" {
method.Description = c.description 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 { if method.Config == nil {
method.Config = make(map[string]interface{}) method.Config = make(map[string]interface{})

@ -2,6 +2,7 @@ package authmethodupdate
import ( import (
"encoding/json" "encoding/json"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "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 { func getTestMethod(t *testing.T, client *api.Client, methodName string) *api.ACLAuthMethod {
t.Helper() t.Helper()
@ -766,4 +899,5 @@ func getTestName(t *testing.T) string {
id, err := uuid.GenerateUUID() id, err := uuid.GenerateUUID()
require.NoError(t, err) require.NoError(t, err)
return "test-" + id return "test-" + id
} }

Loading…
Cancel
Save