mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
add kubectl create --raw -f
This commit is contained in:
parent
060b4b8b84
commit
58f39a15de
@ -936,6 +936,9 @@ run_create_tests() {
|
|||||||
# Post-condition: jsonpath for .metadata.namespace should be empty for object since --namespace was not explicitly specified
|
# Post-condition: jsonpath for .metadata.namespace should be empty for object since --namespace was not explicitly specified
|
||||||
kube::test::if_empty_string "${output_message}"
|
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 nounset
|
||||||
set +o errexit
|
set +o errexit
|
||||||
}
|
}
|
||||||
@ -3674,6 +3677,11 @@ run_kubectl_create_error_tests() {
|
|||||||
fi
|
fi
|
||||||
rm "${ERROR_FILE}"
|
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 nounset
|
||||||
set +o errexit
|
set +o errexit
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,16 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
@ -38,6 +41,7 @@ type CreateOptions struct {
|
|||||||
FilenameOptions resource.FilenameOptions
|
FilenameOptions resource.FilenameOptions
|
||||||
Selector string
|
Selector string
|
||||||
EditBeforeCreate bool
|
EditBeforeCreate bool
|
||||||
|
Raw string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -71,7 +75,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
defaultRunFunc(cmd, args)
|
defaultRunFunc(cmd, args)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cmdutil.CheckErr(ValidateArgs(cmd, args))
|
cmdutil.CheckErr(options.ValidateArgs(cmd, args))
|
||||||
cmdutil.CheckErr(RunCreate(f, cmd, out, errOut, &options))
|
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.AddDryRunFlag(cmd)
|
||||||
cmdutil.AddInclude3rdPartyFlags(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().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
|
// create subcommands
|
||||||
cmd.AddCommand(NewCmdCreateNamespace(f, out))
|
cmd.AddCommand(NewCmdCreateNamespace(f, out))
|
||||||
@ -106,14 +111,65 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateArgs(cmd *cobra.Command, args []string) error {
|
func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, options *CreateOptions) error {
|
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 {
|
if options.EditBeforeCreate {
|
||||||
return RunEditOnCreate(f, out, errOut, cmd, &options.FilenameOptions)
|
return RunEditOnCreate(f, out, errOut, cmd, &options.FilenameOptions)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,8 @@ func TestExtraArgsFail(t *testing.T) {
|
|||||||
|
|
||||||
f, _, _, _ := cmdtesting.NewAPIFactory()
|
f, _, _, _ := cmdtesting.NewAPIFactory()
|
||||||
c := NewCmdCreate(f, buf, errBuf)
|
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")
|
t.Errorf("unexpected non-error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user