add kubectl create --raw -f

This commit is contained in:
David Eads 2017-10-19 11:00:50 -04:00
parent 060b4b8b84
commit 58f39a15de
3 changed files with 69 additions and 4 deletions

View File

@ -936,6 +936,9 @@ run_create_tests() {
# Post-condition: jsonpath for .metadata.namespace should be empty for object since --namespace was not explicitly specified
kube::test::if_empty_string "${output_message}"
kubectl create configmap tester-create-cm -o json --dry-run | kubectl create "${kube_flags[@]}" --raw /api/v1/namespaces/default/configmaps -f -
kubectl delete -ndefault "${kube_flags[@]}" configmap tester-create-cm
set +o nounset
set +o errexit
}
@ -3674,6 +3677,11 @@ run_kubectl_create_error_tests() {
fi
rm "${ERROR_FILE}"
# Posting a pod to namespaces should fail. Also tests --raw forcing the post location
[ "$( kubectl convert -f test/fixtures/doc-yaml/admin/limitrange/valid-pod.yaml -o json | kubectl create "${kube_flags[@]}" --raw /api/v1/namespaces -f - --v=8 2>&1 | grep 'cannot be handled as a Namespace: converting (v1.Pod)')" ]
[ "$( kubectl create "${kube_flags[@]}" --raw /api/v1/namespaces -f test/fixtures/doc-yaml/admin/limitrange/valid-pod.yaml --edit 2>&1 | grep 'raw and --edit are mutually exclusive')" ]
set +o nounset
set +o errexit
}

View File

@ -19,13 +19,16 @@ package cmd
import (
"fmt"
"io"
"os"
"runtime"
"strings"
"github.com/spf13/cobra"
"net/url"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -38,6 +41,7 @@ type CreateOptions struct {
FilenameOptions resource.FilenameOptions
Selector string
EditBeforeCreate bool
Raw string
}
var (
@ -71,7 +75,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
defaultRunFunc(cmd, args)
return
}
cmdutil.CheckErr(ValidateArgs(cmd, args))
cmdutil.CheckErr(options.ValidateArgs(cmd, args))
cmdutil.CheckErr(RunCreate(f, cmd, out, errOut, &options))
},
}
@ -89,6 +93,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddInclude3rdPartyFlags(cmd)
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().StringVar(&options.Raw, "raw", options.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.")
// create subcommands
cmd.AddCommand(NewCmdCreateNamespace(f, out))
@ -106,14 +111,65 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
return cmd
}
func ValidateArgs(cmd *cobra.Command, args []string) error {
func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}
if len(o.Raw) > 0 {
if o.EditBeforeCreate {
return cmdutil.UsageErrorf(cmd, "--raw and --edit are mutually exclusive")
}
if len(o.FilenameOptions.Filenames) != 1 {
return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin")
}
if strings.HasPrefix(o.FilenameOptions.Filenames[0], "http") {
return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url")
}
if o.FilenameOptions.Recursive {
return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive")
}
if len(o.Selector) > 0 {
return cmdutil.UsageErrorf(cmd, "--raw and --selector (-l) are mutually exclusive")
}
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
}
if _, err := url.ParseRequestURI(o.Raw); err != nil {
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
}
}
return nil
}
func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, options *CreateOptions) error {
// raw only makes sense for a single file resource multiple objects aren't likely to do what you want.
// the validator enforces this, so
if len(options.Raw) > 0 {
restClient, err := f.RESTClient()
if err != nil {
return err
}
var data io.ReadCloser
if options.FilenameOptions.Filenames[0] == "-" {
data = os.Stdin
} else {
data, err = os.Open(options.FilenameOptions.Filenames[0])
if err != nil {
return err
}
}
// TODO post content with stream. Right now it ignores body content
bytes, err := restClient.Post().RequestURI(options.Raw).Body(data).DoRaw()
if err != nil {
return err
}
fmt.Fprintf(out, "%v", string(bytes))
return nil
}
if options.EditBeforeCreate {
return RunEditOnCreate(f, out, errOut, cmd, &options.FilenameOptions)
}

View File

@ -33,7 +33,8 @@ func TestExtraArgsFail(t *testing.T) {
f, _, _, _ := cmdtesting.NewAPIFactory()
c := NewCmdCreate(f, buf, errBuf)
if ValidateArgs(c, []string{"rc"}) == nil {
options := CreateOptions{}
if options.ValidateArgs(c, []string{"rc"}) == nil {
t.Errorf("unexpected non-error")
}
}