mirror of https://github.com/k3s-io/k3s
kubectl: Allow []byte config fields to be set by the cli
Allows []byte config fields such as 'certificate-authority-data' to be set using `kubectl config set` commands.pull/6/head
parent
2e9bcb8311
commit
4f9d3ace5d
|
@ -3086,6 +3086,7 @@ _kubectl_config_set()
|
|||
flags_with_completion=()
|
||||
flags_completion=()
|
||||
|
||||
flags+=("--set-raw-bytes=")
|
||||
flags+=("--alsologtostderr")
|
||||
flags+=("--api-version=")
|
||||
flags+=("--as=")
|
||||
|
|
|
@ -15,7 +15,13 @@ kubectl config set \- Sets an individual value in a kubeconfig file
|
|||
.PP
|
||||
Sets an individual value in a kubeconfig file
|
||||
PROPERTY\_NAME is a dot delimited name where each token represents either a attribute name or a map key. Map keys may not contain dots.
|
||||
PROPERTY\_VALUE is the new value you wish to set.
|
||||
PROPERTY\_VALUE is the new value you wish to set. Binary fields such as 'certificate\-authority\-data' expect a base64 encoded string unless the \-\-set\-raw\-bytes flag is used.
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\fB\-\-set\-raw\-bytes\fP=false
|
||||
When writing a []byte PROPERTY\_VALUE, write the given string directly without base64 decoding.
|
||||
|
||||
|
||||
.SH OPTIONS INHERITED FROM PARENT COMMANDS
|
||||
|
|
|
@ -41,12 +41,18 @@ Sets an individual value in a kubeconfig file
|
|||
|
||||
Sets an individual value in a kubeconfig file
|
||||
PROPERTY_NAME is a dot delimited name where each token represents either a attribute name or a map key. Map keys may not contain dots.
|
||||
PROPERTY_VALUE is the new value you wish to set.
|
||||
PROPERTY_VALUE is the new value you wish to set. Binary fields such as 'certificate-authority-data' expect a base64 encoded string unless the --set-raw-bytes flag is used.
|
||||
|
||||
```
|
||||
kubectl config set PROPERTY_NAME PROPERTY_VALUE
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--set-raw-bytes[=false]: When writing a []byte PROPERTY_VALUE, write the given string directly without base64 decoding.
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
|
@ -79,7 +85,7 @@ kubectl config set PROPERTY_NAME PROPERTY_VALUE
|
|||
|
||||
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
|
||||
|
||||
###### Auto generated by spf13/cobra on 5-Apr-2016
|
||||
###### Auto generated by spf13/cobra on 14-Apr-2016
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_config_set.md?pixel)]()
|
||||
|
|
|
@ -270,6 +270,26 @@ runTests() {
|
|||
# Passing no arguments to create is an error
|
||||
! kubectl create
|
||||
|
||||
#######################
|
||||
# kubectl config set #
|
||||
#######################
|
||||
|
||||
kube::log::status "Testing kubectl(${version}:config set)"
|
||||
|
||||
kubectl config set-cluster test-cluster --server="https://does-not-work"
|
||||
|
||||
# Get the api cert and add a comment to avoid flag parsing problems
|
||||
cert_data=$(echo "#Comment" && cat "${TMPDIR:-/tmp/}apiserver.crt")
|
||||
|
||||
kubectl config set clusters.test-cluster.certificate-authority-data "$cert_data" --set-raw-bytes
|
||||
r_writen=$(kubectl config view --raw -o jsonpath='{.clusters[?(@.name == "test-cluster")].cluster.certificate-authority-data}')
|
||||
|
||||
encoded=$(echo -n "$cert_data" | base64 --wrap=0)
|
||||
kubectl config set clusters.test-cluster.certificate-authority-data "$encoded"
|
||||
e_writen=$(kubectl config view --raw -o jsonpath='{.clusters[?(@.name == "test-cluster")].cluster.certificate-authority-data}')
|
||||
|
||||
test "$e_writen" == "$r_writen"
|
||||
|
||||
#######################
|
||||
# kubectl local proxy #
|
||||
#######################
|
||||
|
|
|
@ -435,6 +435,76 @@ func TestCertLeavesToken(t *testing.T) {
|
|||
test.run(t)
|
||||
}
|
||||
|
||||
func TestSetBytesBad(t *testing.T) {
|
||||
startingConfig := newRedFederalCowHammerConfig()
|
||||
startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
|
||||
|
||||
test := configCommandTest{
|
||||
args: []string{"set", "clusters.another-cluster.certificate-authority-data", "cadata"},
|
||||
startingConfig: startingConfig,
|
||||
expectedConfig: startingConfig,
|
||||
}
|
||||
|
||||
test.run(t)
|
||||
}
|
||||
|
||||
func TestSetBytes(t *testing.T) {
|
||||
clusterInfoWithCAData := clientcmdapi.NewCluster()
|
||||
clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
|
||||
|
||||
startingConfig := newRedFederalCowHammerConfig()
|
||||
startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
|
||||
|
||||
expectedConfig := newRedFederalCowHammerConfig()
|
||||
expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
|
||||
|
||||
test := configCommandTest{
|
||||
args: []string{"set", "clusters.another-cluster.certificate-authority-data", "cadata", "--set-raw-bytes"},
|
||||
startingConfig: startingConfig,
|
||||
expectedConfig: expectedConfig,
|
||||
}
|
||||
|
||||
test.run(t)
|
||||
}
|
||||
|
||||
func TestSetBase64Bytes(t *testing.T) {
|
||||
clusterInfoWithCAData := clientcmdapi.NewCluster()
|
||||
clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
|
||||
|
||||
startingConfig := newRedFederalCowHammerConfig()
|
||||
startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
|
||||
|
||||
expectedConfig := newRedFederalCowHammerConfig()
|
||||
expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
|
||||
|
||||
test := configCommandTest{
|
||||
args: []string{"set", "clusters.another-cluster.certificate-authority-data", "Y2FkYXRh"},
|
||||
startingConfig: startingConfig,
|
||||
expectedConfig: expectedConfig,
|
||||
}
|
||||
|
||||
test.run(t)
|
||||
}
|
||||
|
||||
func TestUnsetBytes(t *testing.T) {
|
||||
clusterInfoWithCAData := clientcmdapi.NewCluster()
|
||||
clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
|
||||
|
||||
startingConfig := newRedFederalCowHammerConfig()
|
||||
startingConfig.Clusters["another-cluster"] = clusterInfoWithCAData
|
||||
|
||||
expectedConfig := newRedFederalCowHammerConfig()
|
||||
expectedConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
|
||||
|
||||
test := configCommandTest{
|
||||
args: []string{"unset", "clusters.another-cluster.certificate-authority-data"},
|
||||
startingConfig: startingConfig,
|
||||
expectedConfig: expectedConfig,
|
||||
}
|
||||
|
||||
test.run(t)
|
||||
}
|
||||
|
||||
func TestCAClearsInsecure(t *testing.T) {
|
||||
fakeCAFile, _ := ioutil.TempFile("", "ca-file")
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -24,6 +25,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/flag"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -35,11 +38,12 @@ type setOptions struct {
|
|||
configAccess ConfigAccess
|
||||
propertyName string
|
||||
propertyValue string
|
||||
setRawBytes flag.Tristate
|
||||
}
|
||||
|
||||
const set_long = `Sets an individual value in a kubeconfig file
|
||||
PROPERTY_NAME is a dot delimited name where each token represents either a attribute name or a map key. Map keys may not contain dots.
|
||||
PROPERTY_VALUE is the new value you wish to set.`
|
||||
PROPERTY_VALUE is the new value you wish to set. Binary fields such as 'certificate-authority-data' expect a base64 encoded string unless the --set-raw-bytes flag is used.`
|
||||
|
||||
func NewCmdConfigSet(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
||||
options := &setOptions{configAccess: configAccess}
|
||||
|
@ -62,6 +66,8 @@ func NewCmdConfigSet(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
f := cmd.Flags().VarPF(&options.setRawBytes, "set-raw-bytes", "", "When writing a []byte PROPERTY_VALUE, write the given string directly without base64 decoding.")
|
||||
f.NoOptDefVal = "true"
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -79,7 +85,13 @@ func (o setOptions) run() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = modifyConfig(reflect.ValueOf(config), steps, o.propertyValue, false)
|
||||
|
||||
setRawBytes := false
|
||||
if o.setRawBytes.Provided() {
|
||||
setRawBytes = o.setRawBytes.Value()
|
||||
}
|
||||
|
||||
err = modifyConfig(reflect.ValueOf(config), steps, o.propertyValue, false, setRawBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -115,7 +127,7 @@ func (o setOptions) validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue string, unset bool) error {
|
||||
func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue string, unset bool, setRawBytes bool) error {
|
||||
currStep := steps.pop()
|
||||
|
||||
actualCurrValue := curr
|
||||
|
@ -145,7 +157,7 @@ func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue stri
|
|||
actualCurrValue.SetMapIndex(mapKey, currMapValue)
|
||||
}
|
||||
|
||||
err := modifyConfig(currMapValue, steps, propertyValue, unset)
|
||||
err := modifyConfig(currMapValue, steps, propertyValue, unset, setRawBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -159,6 +171,31 @@ func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue stri
|
|||
actualCurrValue.SetString(propertyValue)
|
||||
return nil
|
||||
|
||||
case reflect.Slice:
|
||||
if steps.moreStepsRemaining() {
|
||||
return fmt.Errorf("can't have more steps after bytes. %v", steps)
|
||||
}
|
||||
innerKind := actualCurrValue.Type().Elem().Kind()
|
||||
if innerKind != reflect.Uint8 {
|
||||
return fmt.Errorf("unrecognized slice type. %v", innerKind)
|
||||
}
|
||||
|
||||
if unset {
|
||||
actualCurrValue.Set(reflect.Zero(actualCurrValue.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
if setRawBytes {
|
||||
actualCurrValue.SetBytes([]byte(propertyValue))
|
||||
} else {
|
||||
val, err := base64.StdEncoding.DecodeString(propertyValue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding input value: %v", err)
|
||||
}
|
||||
actualCurrValue.SetBytes(val)
|
||||
}
|
||||
return nil
|
||||
|
||||
case reflect.Bool:
|
||||
if steps.moreStepsRemaining() {
|
||||
return fmt.Errorf("can't have more steps after a bool. %v", steps)
|
||||
|
@ -196,7 +233,7 @@ func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue stri
|
|||
return nil
|
||||
}
|
||||
|
||||
return modifyConfig(currFieldValue.Addr(), steps, propertyValue, unset)
|
||||
return modifyConfig(currFieldValue.Addr(), steps, propertyValue, unset, setRawBytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ func (o unsetOptions) run() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = modifyConfig(reflect.ValueOf(config), steps, "", true)
|
||||
err = modifyConfig(reflect.ValueOf(config), steps, "", true, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue