mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
update delete, replace, run cmds
This commit is contained in:
parent
a62a157c48
commit
ecaddbfc36
@ -305,7 +305,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdApply("kubectl", f, out, err),
|
||||
NewCmdPatch(f, out),
|
||||
NewCmdReplace(f, out),
|
||||
NewCmdReplace(f, out, err),
|
||||
NewCmdConvert(f, out),
|
||||
},
|
||||
},
|
||||
|
@ -151,192 +151,6 @@ func stringBody(body string) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(body)))
|
||||
}
|
||||
|
||||
func Example_printMultiContainersReplicationControllerWithWide() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
ctrl := &api.ReplicationController{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "someimage",
|
||||
},
|
||||
{
|
||||
Name: "foo2",
|
||||
Image: "someimage2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: api.ReplicationControllerStatus{
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("output", "wide")
|
||||
err := cmdutil.PrintObject(cmd, ctrl, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
|
||||
// foo 1 1 0 10y foo,foo2 someimage,someimage2 foo=bar
|
||||
}
|
||||
|
||||
func Example_printReplicationController() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
ctrl := &api.ReplicationController{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "someimage",
|
||||
},
|
||||
{
|
||||
Name: "foo2",
|
||||
Image: "someimage",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: api.ReplicationControllerStatus{
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
err := cmdutil.PrintObject(cmd, ctrl, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME DESIRED CURRENT READY AGE
|
||||
// foo 1 1 0 10y
|
||||
}
|
||||
|
||||
func Example_printPodWithWideFormat() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: make([]api.Container, 2),
|
||||
NodeName: nodeName,
|
||||
},
|
||||
Status: api.PodStatus{
|
||||
Phase: "podPhase",
|
||||
ContainerStatuses: []api.ContainerStatus{
|
||||
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
|
||||
{RestartCount: 3},
|
||||
},
|
||||
PodIP: "10.1.1.3",
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("output", "wide")
|
||||
err := cmdutil.PrintObject(cmd, pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE IP NODE
|
||||
// test1 1/2 podPhase 6 10y 10.1.1.3 kubernetes-node-abcd
|
||||
}
|
||||
|
||||
func Example_printPodWithShowLabels() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
Labels: map[string]string{
|
||||
"l1": "key",
|
||||
"l2": "value",
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: make([]api.Container, 2),
|
||||
NodeName: nodeName,
|
||||
},
|
||||
Status: api.PodStatus{
|
||||
Phase: "podPhase",
|
||||
ContainerStatuses: []api.ContainerStatus{
|
||||
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
|
||||
{RestartCount: 3},
|
||||
},
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("show-labels", "true")
|
||||
err := cmdutil.PrintObject(cmd, pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE LABELS
|
||||
// test1 1/2 podPhase 6 10y l1=key,l2=value
|
||||
}
|
||||
|
||||
func newAllPhasePodList() *api.PodList {
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
return &api.PodList{
|
||||
@ -429,37 +243,6 @@ func newAllPhasePodList() *api.PodList {
|
||||
}
|
||||
}
|
||||
|
||||
func Example_printPodShowTerminated() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
podList := newAllPhasePodList()
|
||||
printer, err := cmdutil.PrinterForOptions(cmdutil.ExtractCmdPrintOptions(cmd, false))
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected printer get error: %v\n", err)
|
||||
}
|
||||
for _, pod := range []runtime.Object{podList} {
|
||||
err := printer.PrintObj(pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE
|
||||
// test1 1/2 Pending 6 10y
|
||||
// test2 1/2 Running 6 10y
|
||||
// test3 1/2 Succeeded 6 10y
|
||||
// test4 1/2 Failed 6 10y
|
||||
// test5 1/2 Unknown 6 10y
|
||||
}
|
||||
|
||||
func Example_printServiceWithLabels() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
@ -98,6 +98,8 @@ type DeleteOptions struct {
|
||||
ForceDeletion bool
|
||||
WaitForDeletion bool
|
||||
|
||||
Reaper func(mapping *meta.RESTMapping) (kubectl.Reaper, error)
|
||||
|
||||
GracePeriod int
|
||||
Timeout time.Duration
|
||||
|
||||
@ -107,21 +109,23 @@ type DeleteOptions struct {
|
||||
Mapper meta.RESTMapper
|
||||
Result *resource.Result
|
||||
|
||||
f cmdutil.Factory
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
}
|
||||
|
||||
func NewDeleteOptions() *DeleteOptions {
|
||||
func NewDeleteOptions(out, errout io.Writer) *DeleteOptions {
|
||||
return &DeleteOptions{
|
||||
Cascade: true,
|
||||
GracePeriod: -1,
|
||||
Include3rdParty: true,
|
||||
|
||||
Out: out,
|
||||
ErrOut: errout,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := NewDeleteOptions()
|
||||
options := NewDeleteOptions(out, errOut)
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@ -146,6 +150,7 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
usage := "containing the resource to delete."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, not including uninitialized ones.")
|
||||
@ -156,7 +161,11 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
cmd.Flags().BoolVar(&options.DeleteNow, "now", options.DeleteNow, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
||||
cmd.Flags().BoolVar(&options.ForceDeletion, "force", options.ForceDeletion, "Only used when grace-period=0. If true, immediately remove resources from API and bypass graceful deletion. Note that immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
||||
cmd.Flags().DurationVar(&options.Timeout, "timeout", options.Timeout, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
|
||||
|
||||
// we do not need to wire PrintFlags through this command,
|
||||
// as it does not deal with runtime.Objects, and only accepts the "name" output format
|
||||
cmdutil.AddOutputVarFlagsForMutation(cmd, &options.Output)
|
||||
|
||||
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
return cmd
|
||||
@ -168,6 +177,8 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
|
||||
return err
|
||||
}
|
||||
|
||||
o.Reaper = f.Reaper
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
@ -187,7 +198,6 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
|
||||
o.Result = r
|
||||
o.Mapper = r.Mapper().RESTMapper
|
||||
|
||||
o.f = f
|
||||
// Set up writer
|
||||
o.Out = out
|
||||
o.ErrOut = errOut
|
||||
@ -233,17 +243,20 @@ func (o *DeleteOptions) Validate(cmd *cobra.Command) error {
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) RunDelete() error {
|
||||
shortOutput := o.Output == "name"
|
||||
// By default use a reaper to delete all related resources.
|
||||
if o.Cascade {
|
||||
return ReapResult(o.Result, o.f, o.Out, true, o.IgnoreNotFound, o.Timeout, o.GracePeriod, o.WaitForDeletion, shortOutput, false)
|
||||
// TODO(juanvallejo): although o.Result can be accessed from the options
|
||||
// it is also passed here so that callers of this method outside of the "delete"
|
||||
// command do not have to tack it to the "delete" options as well.
|
||||
// Find a cleaner way to approach this.
|
||||
return o.ReapResult(o.Result, true, false)
|
||||
}
|
||||
return DeleteResult(o.Result, o.Out, o.IgnoreNotFound, o.GracePeriod, shortOutput)
|
||||
return o.DeleteResult(o.Result)
|
||||
}
|
||||
|
||||
func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, waitForDeletion, shortOutput bool, quiet bool) error {
|
||||
func (o *DeleteOptions) ReapResult(r *resource.Result, isDefaultDelete, quiet bool) error {
|
||||
found := 0
|
||||
if ignoreNotFound {
|
||||
if o.IgnoreNotFound {
|
||||
r = r.IgnoreErrors(errors.IsNotFound)
|
||||
}
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
@ -251,29 +264,29 @@ func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultD
|
||||
return err
|
||||
}
|
||||
found++
|
||||
reaper, err := f.Reaper(info.Mapping)
|
||||
reaper, err := o.Reaper(info.Mapping)
|
||||
if err != nil {
|
||||
// If there is no reaper for this resources and the user didn't explicitly ask for stop.
|
||||
if kubectl.IsNoSuchReaperError(err) && isDefaultDelete {
|
||||
// No client side reaper found. Let the server do cascading deletion.
|
||||
return cascadingDeleteResource(info, out, shortOutput, gracePeriod)
|
||||
return o.cascadingDeleteResource(info)
|
||||
}
|
||||
return cmdutil.AddSourceToErr("reaping", info.Source, err)
|
||||
}
|
||||
var options *metav1.DeleteOptions
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
if o.GracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(o.GracePeriod))
|
||||
}
|
||||
if err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil {
|
||||
if err := reaper.Stop(info.Namespace, info.Name, o.Timeout, options); err != nil {
|
||||
return cmdutil.AddSourceToErr("stopping", info.Source, err)
|
||||
}
|
||||
if waitForDeletion {
|
||||
if err := waitForObjectDeletion(info, timeout); err != nil {
|
||||
if o.WaitForDeletion {
|
||||
if err := waitForObjectDeletion(info, o.Timeout); err != nil {
|
||||
return cmdutil.AddSourceToErr("stopping", info.Source, err)
|
||||
}
|
||||
}
|
||||
if !quiet {
|
||||
printDeletion(info, out, shortOutput, gracePeriod)
|
||||
o.PrintObj(info)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -281,14 +294,14 @@ func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultD
|
||||
return err
|
||||
}
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
fmt.Fprintf(o.Out, "No resources found\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteResult(r *resource.Result, out io.Writer, ignoreNotFound bool, gracePeriod int, shortOutput bool) error {
|
||||
func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
|
||||
found := 0
|
||||
if ignoreNotFound {
|
||||
if o.IgnoreNotFound {
|
||||
r = r.IgnoreErrors(errors.IsNotFound)
|
||||
}
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
@ -300,38 +313,38 @@ func DeleteResult(r *resource.Result, out io.Writer, ignoreNotFound bool, graceP
|
||||
// if we're here, it means that cascade=false (not the default), so we should orphan as requested
|
||||
orphan := true
|
||||
options := &metav1.DeleteOptions{}
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
if o.GracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(o.GracePeriod))
|
||||
}
|
||||
options.OrphanDependents = &orphan
|
||||
return deleteResource(info, out, shortOutput, options, gracePeriod)
|
||||
return o.deleteResource(info, options)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
fmt.Fprintf(o.Out, "No resources found\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cascadingDeleteResource(info *resource.Info, out io.Writer, shortOutput bool, gracePeriod int) error {
|
||||
func (o *DeleteOptions) cascadingDeleteResource(info *resource.Info) error {
|
||||
falseVar := false
|
||||
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar}
|
||||
return deleteResource(info, out, shortOutput, deleteOptions, gracePeriod)
|
||||
return o.deleteResource(info, &metav1.DeleteOptions{OrphanDependents: &falseVar})
|
||||
}
|
||||
|
||||
func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, deleteOptions *metav1.DeleteOptions, gracePeriod int) error {
|
||||
func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) error {
|
||||
if err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, deleteOptions); err != nil {
|
||||
return cmdutil.AddSourceToErr("deleting", info.Source, err)
|
||||
}
|
||||
|
||||
printDeletion(info, out, shortOutput, gracePeriod)
|
||||
o.PrintObj(info)
|
||||
return nil
|
||||
}
|
||||
|
||||
// deletion printing is special because they don't have an object to print. This logic mirrors PrintSuccess
|
||||
func printDeletion(info *resource.Info, out io.Writer, shortOutput bool, gracePeriod int) {
|
||||
// deletion printing is special because we do not have an object to print.
|
||||
// This mirrors name printer behavior
|
||||
func (o *DeleteOptions) PrintObj(info *resource.Info) {
|
||||
operation := "deleted"
|
||||
groupKind := info.Mapping.GroupVersionKind
|
||||
kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
|
||||
@ -339,18 +352,18 @@ func printDeletion(info *resource.Info, out io.Writer, shortOutput bool, gracePe
|
||||
kindString = strings.ToLower(groupKind.Kind)
|
||||
}
|
||||
|
||||
if gracePeriod == 0 {
|
||||
if o.GracePeriod == 0 {
|
||||
operation = "force deleted"
|
||||
}
|
||||
|
||||
if shortOutput {
|
||||
if o.Output == "name" {
|
||||
// -o name: prints resource/name
|
||||
fmt.Fprintf(out, "%s/%s\n", kindString, info.Name)
|
||||
fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name)
|
||||
return
|
||||
}
|
||||
|
||||
// understandable output by default
|
||||
fmt.Fprintf(out, "%s \"%s\" %s\n", kindString, info.Name, operation)
|
||||
fmt.Fprintf(o.Out, "%s \"%s\" %s\n", kindString, info.Name, operation)
|
||||
}
|
||||
|
||||
// objectDeletionWaitInterval is the interval to wait between checks for deletion.
|
||||
|
@ -26,13 +26,17 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/kubectl/validation"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -60,8 +64,40 @@ var (
|
||||
kubectl replace --force -f ./pod.json`))
|
||||
)
|
||||
|
||||
func NewCmdReplace(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
type ReplaceOpts struct {
|
||||
PrintFlags *printers.PrintFlags
|
||||
FileNameOptions *resource.FilenameOptions
|
||||
DeleteOptions *DeleteOptions
|
||||
|
||||
PrintObj func(obj runtime.Object) error
|
||||
|
||||
createAnnotation bool
|
||||
changeCause string
|
||||
validate bool
|
||||
|
||||
Schema validation.Schema
|
||||
Builder func() *resource.Builder
|
||||
BuilderArgs []string
|
||||
|
||||
ShouldRecord func(info *resource.Info) bool
|
||||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
}
|
||||
|
||||
func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &ReplaceOpts{
|
||||
PrintFlags: printers.NewPrintFlags("replaced"),
|
||||
|
||||
FileNameOptions: &resource.FilenameOptions{},
|
||||
DeleteOptions: NewDeleteOptions(out, errOut),
|
||||
|
||||
Out: out,
|
||||
ErrOut: errOut,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "replace -f FILENAME",
|
||||
@ -71,19 +107,22 @@ func NewCmdReplace(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Example: replaceExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||
err := RunReplace(f, out, cmd, args, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate(cmd))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.PrintFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to use to replace the resource."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options.FileNameOptions, usage)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmd.Flags().Bool("force", false, "Delete and re-create the specified resource")
|
||||
cmd.Flags().Bool("cascade", false, "Only relevant during a force replace. If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController).")
|
||||
cmd.Flags().Int("grace-period", -1, "Only relevant during a force replace. Period of time in seconds given to the old resource to terminate gracefully. Ignored if negative.")
|
||||
cmd.Flags().Duration("timeout", 0, "Only relevant during a force replace. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
|
||||
cmd.Flags().BoolVar(&options.DeleteOptions.ForceDeletion, "force", options.DeleteOptions.ForceDeletion, "Delete and re-create the specified resource")
|
||||
cmd.Flags().BoolVar(&options.DeleteOptions.Cascade, "cascade", options.DeleteOptions.Cascade, "Only relevant during a force replace. If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController).")
|
||||
cmd.Flags().IntVar(&options.DeleteOptions.GracePeriod, "grace-period", options.DeleteOptions.GracePeriod, "Only relevant during a force replace. Period of time in seconds given to the old resource to terminate gracefully. Ignored if negative.")
|
||||
cmd.Flags().DurationVar(&options.DeleteOptions.Timeout, "timeout", options.DeleteOptions.Timeout, "Only relevant during a force replace. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
@ -91,58 +130,101 @@ func NewCmdReplace(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
func (o *ReplaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
o.validate = cmdutil.GetFlagBool(cmd, "validate")
|
||||
o.changeCause = f.Command(cmd, false)
|
||||
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
|
||||
o.ShouldRecord = func(info *resource.Info) bool {
|
||||
return cmdutil.ShouldRecord(cmd, info)
|
||||
}
|
||||
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = func(obj runtime.Object) error {
|
||||
return printer.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
// complete delete options
|
||||
// TODO(juanvallejo): Turn these fields in a DeleteFlags struct, similar to PrintFlags
|
||||
//Replace will create a resource if it doesn't exist already, so ignore not found error
|
||||
o.DeleteOptions.IgnoreNotFound = true
|
||||
o.DeleteOptions.Reaper = f.Reaper
|
||||
|
||||
if o.PrintFlags.OutputFormat != nil {
|
||||
o.DeleteOptions.Output = *o.PrintFlags.OutputFormat
|
||||
}
|
||||
|
||||
if o.DeleteOptions.GracePeriod == 0 {
|
||||
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
|
||||
// into --grace-period=1 and wait until the object is successfully deleted.
|
||||
o.DeleteOptions.GracePeriod = 1
|
||||
o.DeleteOptions.WaitForDeletion = true
|
||||
}
|
||||
|
||||
schema, err := f.Validator(o.validate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
o.Schema = schema
|
||||
o.Builder = f.NewBuilder
|
||||
o.BuilderArgs = args
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
force := cmdutil.GetFlagBool(cmd, "force")
|
||||
if cmdutil.IsFilenameSliceEmpty(options.Filenames) {
|
||||
return cmdutil.UsageErrorf(cmd, "Must specify --filename to replace")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
|
||||
if force {
|
||||
return forceReplace(f, out, cmd, args, shortOutput, options)
|
||||
}
|
||||
|
||||
if cmdutil.GetFlagInt(cmd, "grace-period") >= 0 {
|
||||
func (o *ReplaceOpts) Validate(cmd *cobra.Command) error {
|
||||
if o.DeleteOptions.GracePeriod >= 0 && !o.DeleteOptions.ForceDeletion {
|
||||
return fmt.Errorf("--grace-period must have --force specified")
|
||||
}
|
||||
|
||||
if cmdutil.GetFlagDuration(cmd, "timeout") != 0 {
|
||||
if o.DeleteOptions.Timeout != 0 && !o.DeleteOptions.ForceDeletion {
|
||||
return fmt.Errorf("--timeout must have --force specified")
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
if cmdutil.IsFilenameSliceEmpty(o.FileNameOptions.Filenames) {
|
||||
return cmdutil.UsageErrorf(cmd, "Must specify --filename to replace")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ReplaceOpts) Run() error {
|
||||
if o.DeleteOptions.ForceDeletion {
|
||||
return o.forceReplace()
|
||||
}
|
||||
|
||||
r := o.Builder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
Schema(o.Schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, o.FileNameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.Visit(func(info *resource.Info, err error) error {
|
||||
return o.Result.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||
}
|
||||
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, f.Command(cmd, false)); err != nil {
|
||||
if o.ShouldRecord(info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, o.changeCause); err != nil {
|
||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||
}
|
||||
}
|
||||
@ -154,23 +236,12 @@ func RunReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
||||
}
|
||||
|
||||
info.Refresh(obj, true)
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, false, "replaced")
|
||||
return nil
|
||||
return o.PrintObj(info.AsVersioned())
|
||||
})
|
||||
}
|
||||
|
||||
func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, shortOutput bool, options *resource.FilenameOptions) error {
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, filename := range options.Filenames {
|
||||
func (o *ReplaceOpts) forceReplace() error {
|
||||
for i, filename := range o.FileNameOptions.Filenames {
|
||||
if filename == "-" {
|
||||
tempDir, err := ioutil.TempDir("", "kubectl_replace_")
|
||||
if err != nil {
|
||||
@ -182,42 +253,30 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.Filenames[i] = tempFilename
|
||||
o.FileNameOptions.Filenames[i] = tempFilename
|
||||
}
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
r := o.Builder().
|
||||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, o.FileNameOptions).
|
||||
ResourceTypeOrNameArgs(false, o.BuilderArgs...).RequireObject(false).
|
||||
Flatten().
|
||||
Do()
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Replace will create a resource if it doesn't exist already, so ignore not found error
|
||||
ignoreNotFound := true
|
||||
timeout := cmdutil.GetFlagDuration(cmd, "timeout")
|
||||
gracePeriod := cmdutil.GetFlagInt(cmd, "grace-period")
|
||||
waitForDeletion := false
|
||||
if gracePeriod == 0 {
|
||||
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
|
||||
// into --grace-period=1 and wait until the object is successfully deleted.
|
||||
gracePeriod = 1
|
||||
waitForDeletion = true
|
||||
}
|
||||
var err error
|
||||
|
||||
// By default use a reaper to delete all related resources.
|
||||
if cmdutil.GetFlagBool(cmd, "cascade") {
|
||||
if o.DeleteOptions.Cascade {
|
||||
glog.Warningf("\"cascade\" is set, kubectl will delete and re-create all resources managed by this resource (e.g. Pods created by a ReplicationController). Consider using \"kubectl rolling-update\" if you want to update a ReplicationController together with its Pods.")
|
||||
err = ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, timeout, gracePeriod, waitForDeletion, shortOutput, false)
|
||||
err = o.DeleteOptions.ReapResult(r, o.DeleteOptions.Cascade, false)
|
||||
} else {
|
||||
err = DeleteResult(r, out, ignoreNotFound, gracePeriod, shortOutput)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
err = o.DeleteOptions.DeleteResult(r)
|
||||
}
|
||||
|
||||
if timeout == 0 {
|
||||
@ -239,12 +298,12 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
return err
|
||||
}
|
||||
|
||||
r = f.NewBuilder().
|
||||
r = o.Builder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
Schema(o.Schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, o.FileNameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
@ -258,12 +317,12 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
return err
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, f.Command(cmd, false)); err != nil {
|
||||
if o.ShouldRecord(info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, o.changeCause); err != nil {
|
||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||
}
|
||||
}
|
||||
@ -275,8 +334,7 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
|
||||
count++
|
||||
info.Refresh(obj, true)
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, false, "replaced")
|
||||
return nil
|
||||
return o.PrintObj(info.AsVersioned())
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -65,7 +65,7 @@ func TestReplaceObject(t *testing.T) {
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdReplace(tf, buf)
|
||||
cmd := NewCmdReplace(tf, buf, buf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -136,7 +136,7 @@ func TestReplaceMultipleObject(t *testing.T) {
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdReplace(tf, buf)
|
||||
cmd := NewCmdReplace(tf, buf, buf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -194,7 +194,7 @@ func TestReplaceDirectory(t *testing.T) {
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdReplace(tf, buf)
|
||||
cmd := NewCmdReplace(tf, buf, buf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy")
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -241,7 +241,7 @@ func TestForceReplaceObjectNotFound(t *testing.T) {
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdReplace(tf, buf)
|
||||
cmd := NewCmdReplace(tf, buf, buf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("force", "true")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
|
@ -90,7 +90,38 @@ type RunObject struct {
|
||||
Mapping *meta.RESTMapping
|
||||
}
|
||||
|
||||
type RunOpts struct {
|
||||
DeleteOptions *DeleteOptions
|
||||
|
||||
DryRun bool
|
||||
|
||||
ArgsLenAtDash int
|
||||
Attach bool
|
||||
Expose bool
|
||||
Generator string
|
||||
Image string
|
||||
Interactive bool
|
||||
LeaveStdinOpen bool
|
||||
Port string
|
||||
Quiet bool
|
||||
Record bool
|
||||
Schedule string
|
||||
TTY bool
|
||||
|
||||
In io.Reader
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
}
|
||||
|
||||
func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
options := &RunOpts{
|
||||
DeleteOptions: NewDeleteOptions(cmdOut, cmdErr),
|
||||
|
||||
In: cmdIn,
|
||||
Out: cmdOut,
|
||||
ErrOut: cmdErr,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "run NAME --image=image [--env=\"key=value\"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -98,11 +129,11 @@ func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *co
|
||||
Long: runLong,
|
||||
Example: runExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
argsLenAtDash := cmd.ArgsLenAtDash()
|
||||
err := RunRun(f, cmdIn, cmdOut, cmdErr, cmd, args, argsLenAtDash)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd))
|
||||
cmdutil.CheckErr(options.Run(f, cmd, args))
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
addRunFlags(cmd)
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
@ -141,9 +172,40 @@ func addRunFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().String("schedule", "", i18n.T("A schedule in the Cron format the job should be run with."))
|
||||
}
|
||||
|
||||
func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error {
|
||||
func (o *RunOpts) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.ArgsLenAtDash = cmd.ArgsLenAtDash()
|
||||
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
o.Expose = cmdutil.GetFlagBool(cmd, "expose")
|
||||
o.Generator = cmdutil.GetFlagString(cmd, "generator")
|
||||
o.Image = cmdutil.GetFlagString(cmd, "image")
|
||||
o.Interactive = cmdutil.GetFlagBool(cmd, "stdin")
|
||||
o.LeaveStdinOpen = cmdutil.GetFlagBool(cmd, "leave-stdin-open")
|
||||
o.Port = cmdutil.GetFlagString(cmd, "port")
|
||||
o.Quiet = cmdutil.GetFlagBool(cmd, "quiet")
|
||||
o.Record = cmdutil.GetRecordFlag(cmd)
|
||||
o.Schedule = cmdutil.GetFlagString(cmd, "schedule")
|
||||
o.TTY = cmdutil.GetFlagBool(cmd, "tty")
|
||||
|
||||
attachFlag := cmd.Flags().Lookup("attach")
|
||||
o.Attach = cmdutil.GetFlagBool(cmd, "attach")
|
||||
if !attachFlag.Changed && o.Interactive {
|
||||
o.Attach = true
|
||||
}
|
||||
|
||||
// complete delete options
|
||||
// TODO(juanvallejo): turn delete options into a DeleteFlags struct, similar to PrintFlags
|
||||
o.DeleteOptions.IgnoreNotFound = true
|
||||
o.DeleteOptions.Timeout = 0
|
||||
o.DeleteOptions.GracePeriod = -1
|
||||
o.DeleteOptions.WaitForDeletion = false
|
||||
o.DeleteOptions.Reaper = f.Reaper
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *RunOpts) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
// Let kubectl run follow rules for `--`, see #13004 issue
|
||||
if len(args) == 0 || argsLenAtDash == 0 {
|
||||
if len(args) == 0 || o.ArgsLenAtDash == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "NAME is required for run")
|
||||
}
|
||||
|
||||
@ -153,7 +215,7 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
}
|
||||
|
||||
// validate image name
|
||||
imageName := cmdutil.GetFlagString(cmd, "image")
|
||||
imageName := o.Image
|
||||
if imageName == "" {
|
||||
return fmt.Errorf("--image is required")
|
||||
}
|
||||
@ -162,16 +224,14 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
return fmt.Errorf("Invalid image name %q: %v", imageName, reference.ErrReferenceInvalidFormat)
|
||||
}
|
||||
|
||||
interactive := cmdutil.GetFlagBool(cmd, "stdin")
|
||||
tty := cmdutil.GetFlagBool(cmd, "tty")
|
||||
if tty && !interactive {
|
||||
if o.TTY && !o.Interactive {
|
||||
return cmdutil.UsageErrorf(cmd, "-i/--stdin is required for containers with -t/--tty=true")
|
||||
}
|
||||
replicas := cmdutil.GetFlagInt(cmd, "replicas")
|
||||
if interactive && replicas != 1 {
|
||||
if o.Interactive && replicas != 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "-i/--stdin requires that replicas is 1, found %d", replicas)
|
||||
}
|
||||
if cmdutil.GetFlagBool(cmd, "expose") && len(cmdutil.GetFlagString(cmd, "port")) == 0 {
|
||||
if o.Expose && len(o.Port) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--port must be set when exposing a service")
|
||||
}
|
||||
|
||||
@ -179,7 +239,7 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
restartPolicy, err := getRestartPolicy(cmd, interactive)
|
||||
restartPolicy, err := getRestartPolicy(cmd, o.Interactive)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -187,19 +247,12 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
return cmdutil.UsageErrorf(cmd, "--restart=%s requires that --replicas=1, found %d", restartPolicy, replicas)
|
||||
}
|
||||
|
||||
attachFlag := cmd.Flags().Lookup("attach")
|
||||
attach := cmdutil.GetFlagBool(cmd, "attach")
|
||||
|
||||
if !attachFlag.Changed && interactive {
|
||||
attach = true
|
||||
}
|
||||
|
||||
remove := cmdutil.GetFlagBool(cmd, "rm")
|
||||
if !attach && remove {
|
||||
if !o.Attach && remove {
|
||||
return cmdutil.UsageErrorf(cmd, "--rm should only be used for attached containers")
|
||||
}
|
||||
|
||||
if attach && cmdutil.GetDryRunFlag(cmd) {
|
||||
if o.Attach && o.DryRun {
|
||||
return cmdutil.UsageErrorf(cmd, "--dry-run can't be used with attached containers options (--attach, --stdin, or --tty)")
|
||||
}
|
||||
|
||||
@ -212,8 +265,8 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
return err
|
||||
}
|
||||
|
||||
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
||||
schedule := cmdutil.GetFlagString(cmd, "schedule")
|
||||
generatorName := o.Generator
|
||||
schedule := o.Schedule
|
||||
if len(schedule) != 0 && len(generatorName) == 0 {
|
||||
generatorName = cmdutil.CronJobV1Beta1GeneratorName
|
||||
}
|
||||
@ -228,12 +281,12 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
}
|
||||
|
||||
// Falling back because the generator was not provided and the default one could be unavailable.
|
||||
generatorNameTemp, err := cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), cmdErr)
|
||||
generatorNameTemp, err := cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), o.ErrOut)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if generatorNameTemp != generatorName {
|
||||
cmdutil.Warning(cmdErr, generatorName, generatorNameTemp)
|
||||
cmdutil.Warning(o.ErrOut, generatorName, generatorNameTemp)
|
||||
} else {
|
||||
generatorName = generatorNameTemp
|
||||
}
|
||||
@ -254,19 +307,19 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
params["env"] = cmdutil.GetFlagStringArray(cmd, "env")
|
||||
|
||||
var createdObjects = []*RunObject{}
|
||||
runObject, err := createGeneratedObject(f, cmd, generator, names, params, cmdutil.GetFlagString(cmd, "overrides"), namespace)
|
||||
runObject, err := o.createGeneratedObject(f, cmd, generator, names, params, cmdutil.GetFlagString(cmd, "overrides"), namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
createdObjects = append(createdObjects, runObject)
|
||||
}
|
||||
allErrs := []error{}
|
||||
if cmdutil.GetFlagBool(cmd, "expose") {
|
||||
if o.Expose {
|
||||
serviceGenerator := cmdutil.GetFlagString(cmd, "service-generator")
|
||||
if len(serviceGenerator) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "No service generator specified")
|
||||
}
|
||||
serviceRunObject, err := generateService(f, cmd, args, serviceGenerator, params, namespace, cmdOut)
|
||||
serviceRunObject, err := o.generateService(f, cmd, serviceGenerator, params, namespace)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
} else {
|
||||
@ -274,20 +327,19 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
}
|
||||
}
|
||||
|
||||
if attach {
|
||||
if o.Attach {
|
||||
if remove {
|
||||
defer removeCreatedObjects(f, createdObjects, cmdOut)
|
||||
defer o.removeCreatedObjects(f, createdObjects)
|
||||
}
|
||||
|
||||
quiet := cmdutil.GetFlagBool(cmd, "quiet")
|
||||
opts := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: cmdIn,
|
||||
Out: cmdOut,
|
||||
Err: cmdErr,
|
||||
Stdin: interactive,
|
||||
TTY: tty,
|
||||
Quiet: quiet,
|
||||
In: o.In,
|
||||
Out: o.Out,
|
||||
Err: o.ErrOut,
|
||||
Stdin: o.Interactive,
|
||||
TTY: o.TTY,
|
||||
Quiet: o.Quiet,
|
||||
},
|
||||
GetPodTimeout: timeout,
|
||||
CommandName: cmd.Parent().CommandPath() + " attach",
|
||||
@ -316,7 +368,7 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
}
|
||||
|
||||
var pod *api.Pod
|
||||
leaveStdinOpen := cmdutil.GetFlagBool(cmd, "leave-stdin-open")
|
||||
leaveStdinOpen := o.LeaveStdinOpen
|
||||
waitForExitCode := !leaveStdinOpen && restartPolicy == api.RestartPolicyNever
|
||||
if waitForExitCode {
|
||||
pod, err = waitForPod(clientset.Core(), attachablePod.Namespace, attachablePod.Name, kubectl.PodCompleted)
|
||||
@ -355,15 +407,15 @@ func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *c
|
||||
if runObject != nil {
|
||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
||||
if outputFormat != "" || cmdutil.GetDryRunFlag(cmd) {
|
||||
return cmdutil.PrintObject(cmd, runObject.Object, cmdOut)
|
||||
return cmdutil.PrintObject(cmd, runObject.Object, o.Out)
|
||||
}
|
||||
cmdutil.PrintSuccess(false, cmdOut, runObject.Object, cmdutil.GetDryRunFlag(cmd), "created")
|
||||
cmdutil.PrintSuccess(false, o.Out, runObject.Object, cmdutil.GetDryRunFlag(cmd), "created")
|
||||
}
|
||||
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
func removeCreatedObjects(f cmdutil.Factory, createdObjects []*RunObject, cmdOut io.Writer) error {
|
||||
func (o *RunOpts) removeCreatedObjects(f cmdutil.Factory, createdObjects []*RunObject) error {
|
||||
for _, obj := range createdObjects {
|
||||
namespace, err := obj.Mapping.MetadataAccessor.Namespace(obj.Object)
|
||||
if err != nil {
|
||||
@ -387,7 +439,7 @@ func removeCreatedObjects(f cmdutil.Factory, createdObjects []*RunObject, cmdOut
|
||||
// asked for us to remove the pod (via --rm) then telling them
|
||||
// its been deleted is unnecessary since that's what they asked
|
||||
// for. We should only print something if the "rm" fails.
|
||||
err = ReapResult(r, f, cmdOut, true, true, 0, -1, false, false, true)
|
||||
err = o.DeleteOptions.ReapResult(r, true, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -502,7 +554,7 @@ func verifyImagePullPolicy(cmd *cobra.Command) error {
|
||||
return cmdutil.UsageErrorf(cmd, "invalid image pull policy: %s", pullPolicy)
|
||||
}
|
||||
|
||||
func generateService(f cmdutil.Factory, cmd *cobra.Command, args []string, serviceGenerator string, paramsIn map[string]interface{}, namespace string, out io.Writer) (*RunObject, error) {
|
||||
func (o *RunOpts) generateService(f cmdutil.Factory, cmd *cobra.Command, serviceGenerator string, paramsIn map[string]interface{}, namespace string) (*RunObject, error) {
|
||||
generators := f.Generators("expose")
|
||||
generator, found := generators[serviceGenerator]
|
||||
if !found {
|
||||
@ -532,27 +584,27 @@ func generateService(f cmdutil.Factory, cmd *cobra.Command, args []string, servi
|
||||
params["default-name"] = name
|
||||
}
|
||||
|
||||
runObject, err := createGeneratedObject(f, cmd, generator, names, params, cmdutil.GetFlagString(cmd, "service-overrides"), namespace)
|
||||
runObject, err := o.createGeneratedObject(f, cmd, generator, names, params, cmdutil.GetFlagString(cmd, "service-overrides"), namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cmdutil.GetFlagString(cmd, "output") != "" || cmdutil.GetDryRunFlag(cmd) {
|
||||
err := cmdutil.PrintObject(cmd, runObject.Object, out)
|
||||
err := cmdutil.PrintObject(cmd, runObject.Object, o.Out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cmdutil.GetFlagString(cmd, "output") == "yaml" {
|
||||
fmt.Fprintln(out, "---")
|
||||
fmt.Fprintln(o.Out, "---")
|
||||
}
|
||||
return runObject, nil
|
||||
}
|
||||
cmdutil.PrintSuccess(false, out, runObject.Object, cmdutil.GetDryRunFlag(cmd), "created")
|
||||
cmdutil.PrintSuccess(false, o.Out, runObject.Object, cmdutil.GetDryRunFlag(cmd), "created")
|
||||
|
||||
return runObject, nil
|
||||
}
|
||||
|
||||
func createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, generator kubectl.Generator, names []kubectl.GeneratorParam, params map[string]interface{}, overrides, namespace string) (*RunObject, error) {
|
||||
func (o *RunOpts) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, generator kubectl.Generator, names []kubectl.GeneratorParam, params map[string]interface{}, overrides, namespace string) (*RunObject, error) {
|
||||
err := kubectl.ValidateParams(names, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -592,12 +644,13 @@ func createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, generator kube
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cmdutil.GetRecordFlag(cmd) || len(annotations[kubectl.ChangeCauseAnnotation]) > 0 {
|
||||
if o.Record || len(annotations[kubectl.ChangeCauseAnnotation]) > 0 {
|
||||
if err := cmdutil.RecordChangeCause(obj, f.Command(cmd, false)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if !cmdutil.GetDryRunFlag(cmd) {
|
||||
|
||||
if !o.DryRun {
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
|
@ -188,12 +188,28 @@ func TestRunArgsFollowDashRules(t *testing.T) {
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
cmd.Flags().Set("image", "nginx")
|
||||
cmd.Flags().Set("generator", "run/v1")
|
||||
err := RunRun(tf, os.Stdin, os.Stdout, os.Stderr, cmd, test.args, test.argsLenAtDash)
|
||||
|
||||
opts := &RunOpts{
|
||||
DeleteOptions: NewDeleteOptions(os.Stdout, os.Stderr),
|
||||
|
||||
In: os.Stdin,
|
||||
Out: os.Stdout,
|
||||
ErrOut: os.Stderr,
|
||||
|
||||
Image: "nginx",
|
||||
Generator: "run/v1",
|
||||
|
||||
ArgsLenAtDash: test.argsLenAtDash,
|
||||
}
|
||||
|
||||
err := opts.Run(tf, cmd, test.args)
|
||||
if test.expectError && err == nil {
|
||||
t.Errorf("unexpected non-error (%s)", test.name)
|
||||
}
|
||||
@ -335,6 +351,18 @@ func TestGenerateService(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
opts := &RunOpts{
|
||||
DeleteOptions: NewDeleteOptions(os.Stdout, os.Stderr),
|
||||
|
||||
Out: buff,
|
||||
ErrOut: buff,
|
||||
|
||||
Port: test.port,
|
||||
Record: false,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{}
|
||||
cmd.Flags().Bool(cmdutil.ApplyAnnotationsFlag, false, "")
|
||||
cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists.")
|
||||
@ -343,7 +371,7 @@ func TestGenerateService(t *testing.T) {
|
||||
addRunFlags(cmd)
|
||||
|
||||
if !test.expectPOST {
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
opts.DryRun = true
|
||||
}
|
||||
|
||||
if len(test.port) > 0 {
|
||||
@ -351,8 +379,7 @@ func TestGenerateService(t *testing.T) {
|
||||
test.params["port"] = test.port
|
||||
}
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
_, err := generateService(tf, cmd, test.args, test.serviceGenerator, test.params, "namespace", buff)
|
||||
_, err := opts.generateService(tf, cmd, test.serviceGenerator, test.params, "namespace")
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Error("unexpected non-error")
|
||||
@ -473,7 +500,12 @@ func TestRunValidations(t *testing.T) {
|
||||
for flagName, flagValue := range test.flags {
|
||||
cmd.Flags().Set(flagName, flagValue)
|
||||
}
|
||||
err := RunRun(tf, inBuf, outBuf, errBuf, cmd, test.args, cmd.ArgsLenAtDash())
|
||||
cmd.Run(cmd, test.args)
|
||||
|
||||
var err error
|
||||
if errBuf.Len() > 0 {
|
||||
err = fmt.Errorf("%v", errBuf.String())
|
||||
}
|
||||
if err != nil && len(test.expectedErr) > 0 {
|
||||
if !strings.Contains(err.Error(), test.expectedErr) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
|
Loading…
Reference in New Issue
Block a user