2015-01-12 23:30:52 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2015-01-12 23:30:52 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package cmd
import (
"fmt"
"io"
2016-08-09 19:05:44 +00:00
"github.com/docker/distribution/reference"
2017-02-21 16:19:13 +00:00
"github.com/spf13/cobra"
2016-08-09 19:05:44 +00:00
2017-01-13 17:48:50 +00:00
"k8s.io/apimachinery/pkg/api/errors"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
2018-02-05 11:50:54 +00:00
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/watch"
2017-11-08 22:34:54 +00:00
api "k8s.io/kubernetes/pkg/apis/core"
2016-10-21 22:24:05 +00:00
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubectl"
2016-10-07 22:24:42 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2015-08-05 22:03:47 +00:00
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2015-08-21 02:35:28 +00:00
"k8s.io/kubernetes/pkg/kubectl/resource"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2016-08-08 17:56:19 +00:00
"k8s.io/kubernetes/pkg/util/interrupt"
2017-07-19 05:58:53 +00:00
uexec "k8s.io/utils/exec"
2015-01-12 23:30:52 +00:00
)
2016-05-20 17:49:56 +00:00
var (
2017-02-16 03:47:00 +00:00
runLong = templates . LongDesc ( i18n . T ( `
2016-05-20 17:49:56 +00:00
Create and run a particular image , possibly replicated .
2016-10-07 22:24:42 +00:00
2017-03-15 03:49:10 +00:00
Creates a deployment or job to manage the created container ( s ) . ` ) )
2016-10-07 22:24:42 +00:00
2017-02-16 03:47:00 +00:00
runExample = templates . Examples ( i18n . T ( `
2016-05-20 17:49:56 +00:00
# Start a single instance of nginx .
kubectl run nginx -- image = nginx
2015-01-12 23:30:52 +00:00
2016-05-20 17:49:56 +00:00
# Start a single instance of hazelcast and let the container expose port 5701 .
kubectl run hazelcast -- image = hazelcast -- port = 5701
2015-09-01 03:03:29 +00:00
2016-05-20 17:49:56 +00:00
# Start a single instance of hazelcast and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default" in the container .
kubectl run hazelcast -- image = hazelcast -- env = "DNS_DOMAIN=cluster" -- env = "POD_NAMESPACE=default"
2015-09-01 03:03:29 +00:00
2017-07-31 06:41:50 +00:00
# Start a single instance of hazelcast and set labels "app=hazelcast" and "env=prod" in the container .
kubectl run hazelcast -- image = nginx -- labels = "app=hazelcast,env=prod"
2016-05-20 17:49:56 +00:00
# Start a replicated instance of nginx .
kubectl run nginx -- image = nginx -- replicas = 5
2015-01-12 23:30:52 +00:00
2016-05-20 17:49:56 +00:00
# Dry run . Print the corresponding API objects without creating them .
kubectl run nginx -- image = nginx -- dry - run
2015-01-15 00:58:12 +00:00
2016-05-20 17:49:56 +00:00
# Start a single instance of nginx , but overload the spec of the deployment with a partial set of values parsed from JSON .
kubectl run nginx -- image = nginx -- overrides = ' { "apiVersion" : "v1" , "spec" : { ... } } '
2015-08-12 05:48:00 +00:00
2016-05-20 17:49:56 +00:00
# Start a pod of busybox and keep it in the foreground , don ' t restart it if it exits .
kubectl run - i - t busybox -- image = busybox -- restart = Never
2015-08-12 05:48:00 +00:00
2016-05-20 17:49:56 +00:00
# Start the nginx container using the default command , but use custom arguments ( arg1 . . argN ) for that command .
kubectl run nginx -- image = nginx -- < arg1 > < arg2 > ... < argN >
2015-08-12 05:48:00 +00:00
2016-05-20 17:49:56 +00:00
# Start the nginx container using a different command and custom arguments .
kubectl run nginx -- image = nginx -- command -- < cmd > < arg1 > ... < argN >
2015-11-13 01:07:21 +00:00
2016-05-20 17:49:56 +00:00
# Start the perl container to compute π to 2000 places and print it out .
2016-05-18 08:11:35 +00:00
kubectl run pi -- image = perl -- restart = OnFailure -- perl - Mbignum = bpi - wle ' print bpi ( 2000 ) '
2016-11-01 22:46:23 +00:00
# Start the cron job to compute π to 2000 places and print it out every 5 minutes .
2017-03-15 03:49:10 +00:00
kubectl run pi -- schedule = "0/5 * * * ?" -- image = perl -- restart = OnFailure -- perl - Mbignum = bpi - wle ' print bpi ( 2000 ) ' ` ) )
2015-02-20 21:28:43 +00:00
)
2015-02-03 17:59:21 +00:00
2017-04-27 08:22:43 +00:00
type RunObject struct {
Object runtime . Object
Kind string
Mapping * meta . RESTMapping
}
2018-04-09 23:13:50 +00:00
type RunOpts struct {
2018-04-14 00:28:28 +00:00
DeleteFlags * DeleteFlags
2018-04-09 23:13:50 +00:00
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
}
2016-10-13 00:18:39 +00:00
func NewCmdRun ( f cmdutil . Factory , cmdIn io . Reader , cmdOut , cmdErr io . Writer ) * cobra . Command {
2018-04-09 23:13:50 +00:00
options := & RunOpts {
2018-04-14 00:28:28 +00:00
DeleteFlags : NewDeleteFlags ( "to use to replace the resource." ) ,
2018-04-09 23:13:50 +00:00
In : cmdIn ,
Out : cmdOut ,
ErrOut : cmdErr ,
}
2015-02-20 21:28:43 +00:00
cmd := & cobra . Command {
2017-10-11 06:26:02 +00:00
Use : "run NAME --image=image [--env=\"key=value\"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]" ,
DisableFlagsInUseLine : true ,
2017-01-25 01:00:32 +00:00
Short : i18n . T ( "Run a particular image on the cluster" ) ,
2017-02-16 03:47:00 +00:00
Long : runLong ,
Example : runExample ,
2015-01-12 23:30:52 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2018-04-09 23:13:50 +00:00
cmdutil . CheckErr ( options . Complete ( f , cmd ) )
cmdutil . CheckErr ( options . Run ( f , cmd , args ) )
2015-01-12 23:30:52 +00:00
} ,
}
2018-04-09 23:13:50 +00:00
2018-04-14 00:28:28 +00:00
options . DeleteFlags . AddFlags ( cmd )
2015-04-07 18:21:25 +00:00
cmdutil . AddPrinterFlags ( cmd )
2015-10-20 18:27:26 +00:00
addRunFlags ( cmd )
2015-11-04 21:47:08 +00:00
cmdutil . AddApplyAnnotationFlags ( cmd )
2016-01-22 18:33:23 +00:00
cmdutil . AddRecordFlag ( cmd )
2017-02-21 16:19:13 +00:00
cmdutil . AddPodRunningTimeoutFlag ( cmd , defaultPodAttachTimeout )
2015-10-20 18:27:26 +00:00
return cmd
}
func addRunFlags ( cmd * cobra . Command ) {
2016-05-11 00:26:39 +00:00
cmdutil . AddDryRunFlag ( cmd )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "generator" , "" , i18n . T ( "The name of the API generator to use, see http://kubernetes.io/docs/user-guide/kubectl-conventions/#generators for a list." ) )
cmd . Flags ( ) . String ( "image" , "" , i18n . T ( "The image for the container to run." ) )
2015-03-17 15:49:35 +00:00
cmd . MarkFlagRequired ( "image" )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "image-pull-policy" , "" , i18n . T ( "The image pull policy for the container. If left empty, this value will not be specified by the client and defaulted by the server" ) )
2015-02-03 17:59:21 +00:00
cmd . Flags ( ) . IntP ( "replicas" , "r" , 1 , "Number of replicas to create for this container. Default is 1." )
2015-12-10 02:36:25 +00:00
cmd . Flags ( ) . Bool ( "rm" , false , "If true, delete resources created in this command for attached containers." )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "overrides" , "" , i18n . T ( "An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field." ) )
2017-06-13 21:53:09 +00:00
cmd . Flags ( ) . StringArray ( "env" , [ ] string { } , "Environment variables to set in the container" )
2017-05-24 00:32:00 +00:00
cmd . Flags ( ) . String ( "serviceaccount" , "" , "Service account to set in the pod spec" )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "port" , "" , i18n . T ( "The port that this container exposes. If --expose is true, this is also the port used by the service that is created." ) )
2015-04-29 23:54:23 +00:00
cmd . Flags ( ) . Int ( "hostport" , - 1 , "The host port mapping for the container port. To demonstrate a single-machine container." )
2017-07-31 06:41:50 +00:00
cmd . Flags ( ) . StringP ( "labels" , "l" , "" , "Comma separated labels to apply to the pod(s). Will override previous values." )
2015-08-04 19:54:17 +00:00
cmd . Flags ( ) . BoolP ( "stdin" , "i" , false , "Keep stdin open on the container(s) in the pod, even if nothing is attached." )
2016-04-16 00:12:42 +00:00
cmd . Flags ( ) . BoolP ( "tty" , "t" , false , "Allocated a TTY for each container in the pod." )
2016-08-08 18:25:10 +00:00
cmd . Flags ( ) . Bool ( "attach" , false , "If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--stdin' is set, in which case the default is true. With '--restart=Never' the exit code of the container process is returned." )
2015-10-06 15:31:48 +00:00
cmd . Flags ( ) . Bool ( "leave-stdin-open" , false , "If the pod is started in interactive mode or with stdin, leave stdin open after the first attach completes. By default, stdin will be closed after the first attach completes." )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "restart" , "Always" , i18n . T ( "The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a deployment is created, if set to 'OnFailure' a job is created, if set to 'Never', a regular pod is created. For the latter two --replicas must be 1. Default 'Always', for CronJobs `Never`." ) )
2015-08-12 05:48:00 +00:00
cmd . Flags ( ) . Bool ( "command" , false , "If true and extra arguments are present, use them as the 'command' field in the container, rather than the 'args' field which is the default." )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "requests" , "" , i18n . T ( "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges." ) )
cmd . Flags ( ) . String ( "limits" , "" , i18n . T ( "The resource requirement limits for this container. For example, 'cpu=200m,memory=512Mi'. Note that server side components may assign limits depending on the server configuration, such as limit ranges." ) )
2015-10-20 18:27:26 +00:00
cmd . Flags ( ) . Bool ( "expose" , false , "If true, a public, external service is created for the container(s) which are run" )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "service-generator" , "service/v2" , i18n . T ( "The name of the generator to use for creating a service. Only used if --expose is true" ) )
cmd . Flags ( ) . String ( "service-overrides" , "" , i18n . T ( "An inline JSON override for the generated service object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field. Only used if --expose is true." ) )
2016-07-11 21:40:19 +00:00
cmd . Flags ( ) . Bool ( "quiet" , false , "If true, suppress prompt messages." )
2017-02-07 06:26:44 +00:00
cmd . Flags ( ) . String ( "schedule" , "" , i18n . T ( "A schedule in the Cron format the job should be run with." ) )
2015-01-12 23:30:52 +00:00
}
2015-03-09 22:08:16 +00:00
2018-04-09 23:13:50 +00:00
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
}
2018-04-14 00:28:28 +00:00
deleteOpts := o . DeleteFlags . ToOptions ( o . Out , o . ErrOut )
deleteOpts . IgnoreNotFound = true
deleteOpts . WaitForDeletion = false
deleteOpts . GracePeriod = - 1
deleteOpts . Reaper = f . Reaper
o . DeleteOptions = deleteOpts
2018-04-09 23:13:50 +00:00
return nil
}
func ( o * RunOpts ) Run ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
2015-09-14 12:18:42 +00:00
// Let kubectl run follow rules for `--`, see #13004 issue
2018-04-09 23:13:50 +00:00
if len ( args ) == 0 || o . ArgsLenAtDash == 0 {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "NAME is required for run" )
2015-03-09 22:08:16 +00:00
}
2017-02-21 16:19:13 +00:00
timeout , err := cmdutil . GetPodRunningTimeoutFlag ( cmd )
if err != nil {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "%v" , err )
2017-02-21 16:19:13 +00:00
}
2016-08-09 19:05:44 +00:00
// validate image name
2018-04-09 23:13:50 +00:00
imageName := o . Image
2017-07-24 08:31:22 +00:00
if imageName == "" {
return fmt . Errorf ( "--image is required" )
}
2016-08-09 19:05:44 +00:00
validImageRef := reference . ReferenceRegexp . MatchString ( imageName )
if ! validImageRef {
return fmt . Errorf ( "Invalid image name %q: %v" , imageName , reference . ErrReferenceInvalidFormat )
}
2018-04-09 23:13:50 +00:00
if o . TTY && ! o . Interactive {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "-i/--stdin is required for containers with -t/--tty=true" )
2015-08-04 19:54:17 +00:00
}
replicas := cmdutil . GetFlagInt ( cmd , "replicas" )
2018-04-09 23:13:50 +00:00
if o . Interactive && replicas != 1 {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "-i/--stdin requires that replicas is 1, found %d" , replicas )
2015-08-04 19:54:17 +00:00
}
2018-04-09 23:13:50 +00:00
if o . Expose && len ( o . Port ) == 0 {
2017-08-17 06:30:46 +00:00
return cmdutil . UsageErrorf ( cmd , "--port must be set when exposing a service" )
}
2015-08-04 19:54:17 +00:00
2015-06-26 20:49:34 +00:00
namespace , _ , err := f . DefaultNamespace ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2018-04-09 23:13:50 +00:00
restartPolicy , err := getRestartPolicy ( cmd , o . Interactive )
2015-08-04 19:54:17 +00:00
if err != nil {
return err
}
if restartPolicy != api . RestartPolicyAlways && replicas != 1 {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "--restart=%s requires that --replicas=1, found %d" , restartPolicy , replicas )
2015-08-04 19:54:17 +00:00
}
2015-10-20 18:27:26 +00:00
2016-10-27 22:05:26 +00:00
remove := cmdutil . GetFlagBool ( cmd , "rm" )
2018-04-09 23:13:50 +00:00
if ! o . Attach && remove {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "--rm should only be used for attached containers" )
2016-10-27 22:05:26 +00:00
}
2018-04-09 23:13:50 +00:00
if o . Attach && o . DryRun {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "--dry-run can't be used with attached containers options (--attach, --stdin, or --tty)" )
2016-10-27 22:05:26 +00:00
}
2016-08-17 03:26:27 +00:00
if err := verifyImagePullPolicy ( cmd ) ; err != nil {
return err
}
2017-03-08 10:11:29 +00:00
clientset , err := f . ClientSet ( )
if err != nil {
return err
}
2018-04-09 23:13:50 +00:00
generatorName := o . Generator
schedule := o . Schedule
2016-05-18 08:11:35 +00:00
if len ( schedule ) != 0 && len ( generatorName ) == 0 {
2018-04-10 19:14:29 +00:00
generatorName = cmdutil . CronJobV1Beta1GeneratorName
2016-05-18 08:11:35 +00:00
}
2015-08-04 19:54:17 +00:00
if len ( generatorName ) == 0 {
2016-05-06 09:39:44 +00:00
switch restartPolicy {
case api . RestartPolicyAlways :
2018-04-10 19:14:29 +00:00
generatorName = cmdutil . DeploymentV1Beta1GeneratorName
2016-05-06 09:39:44 +00:00
case api . RestartPolicyOnFailure :
2018-04-10 19:14:29 +00:00
generatorName = cmdutil . JobV1GeneratorName
2016-05-06 09:39:44 +00:00
case api . RestartPolicyNever :
2017-03-08 10:11:29 +00:00
generatorName = cmdutil . RunPodV1GeneratorName
2015-08-04 19:54:17 +00:00
}
2017-03-08 10:11:29 +00:00
2018-04-10 19:14:29 +00:00
// Falling back because the generator was not provided and the default one could be unavailable.
2018-04-09 23:13:50 +00:00
generatorNameTemp , err := cmdutil . FallbackGeneratorNameIfNecessary ( generatorName , clientset . Discovery ( ) , o . ErrOut )
2018-04-10 19:14:29 +00:00
if err != nil {
return err
}
if generatorNameTemp != generatorName {
2018-04-09 23:13:50 +00:00
cmdutil . Warning ( o . ErrOut , generatorName , generatorNameTemp )
2018-04-10 19:14:29 +00:00
} else {
generatorName = generatorNameTemp
}
2017-10-12 04:27:42 +00:00
}
2017-03-10 11:07:50 +00:00
2015-11-19 18:14:10 +00:00
generators := f . Generators ( "run" )
generator , found := generators [ generatorName ]
2015-03-09 22:08:16 +00:00
if ! found {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "generator %q not found" , generatorName )
2015-03-09 22:08:16 +00:00
}
names := generator . ParamNames ( )
params := kubectl . MakeParams ( cmd , names )
params [ "name" ] = args [ 0 ]
2015-08-12 05:48:00 +00:00
if len ( args ) > 1 {
params [ "args" ] = args [ 1 : ]
}
2015-09-01 03:03:29 +00:00
2017-06-13 21:53:09 +00:00
params [ "env" ] = cmdutil . GetFlagStringArray ( cmd , "env" )
2015-09-01 03:03:29 +00:00
2018-03-28 03:34:08 +00:00
var createdObjects = [ ] * RunObject { }
2018-04-09 23:13:50 +00:00
runObject , err := o . createGeneratedObject ( f , cmd , generator , names , params , cmdutil . GetFlagString ( cmd , "overrides" ) , namespace )
2016-01-29 09:12:59 +00:00
if err != nil {
2018-03-28 03:25:55 +00:00
return err
2018-02-05 11:50:54 +00:00
} else {
2018-03-28 03:34:08 +00:00
createdObjects = append ( createdObjects , runObject )
2016-01-29 09:12:59 +00:00
}
2018-03-28 03:25:55 +00:00
allErrs := [ ] error { }
2018-04-09 23:13:50 +00:00
if o . Expose {
2015-10-20 18:27:26 +00:00
serviceGenerator := cmdutil . GetFlagString ( cmd , "service-generator" )
if len ( serviceGenerator ) == 0 {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "No service generator specified" )
2015-10-20 18:27:26 +00:00
}
2018-04-09 23:13:50 +00:00
serviceRunObject , err := o . generateService ( f , cmd , serviceGenerator , params , namespace )
2017-04-27 08:22:43 +00:00
if err != nil {
2018-02-05 11:50:54 +00:00
allErrs = append ( allErrs , err )
} else {
2018-03-28 03:34:08 +00:00
createdObjects = append ( createdObjects , serviceRunObject )
2015-03-09 22:08:16 +00:00
}
}
2018-04-09 23:13:50 +00:00
if o . Attach {
2018-04-12 17:58:00 +00:00
if remove {
2018-04-09 23:13:50 +00:00
defer o . removeCreatedObjects ( f , createdObjects )
2018-04-12 17:58:00 +00:00
}
2015-08-04 19:54:17 +00:00
opts := & AttachOptions {
2016-07-15 19:56:42 +00:00
StreamOptions : StreamOptions {
2018-04-09 23:13:50 +00:00
In : o . In ,
Out : o . Out ,
Err : o . ErrOut ,
Stdin : o . Interactive ,
TTY : o . TTY ,
Quiet : o . Quiet ,
2016-07-15 19:56:42 +00:00
} ,
2017-02-21 16:19:13 +00:00
GetPodTimeout : timeout ,
CommandName : cmd . Parent ( ) . CommandPath ( ) + " attach" ,
2016-06-13 08:00:39 +00:00
2015-08-04 19:54:17 +00:00
Attach : & DefaultRemoteAttach { } ,
}
config , err := f . ClientConfig ( )
if err != nil {
return err
}
opts . Config = config
2016-09-06 18:23:54 +00:00
clientset , err := f . ClientSet ( )
if err != nil {
return err
}
opts . PodClient = clientset . Core ( )
2015-10-22 17:34:19 +00:00
2017-04-27 08:22:43 +00:00
attachablePod , err := f . AttachablePodForObject ( runObject . Object , opts . GetPodTimeout )
2015-10-22 17:34:19 +00:00
if err != nil {
return err
2015-08-04 19:54:17 +00:00
}
2017-03-17 13:55:46 +00:00
err = handleAttachPod ( f , clientset . Core ( ) , attachablePod . Namespace , attachablePod . Name , opts )
2015-12-10 02:36:25 +00:00
if err != nil {
return err
}
2016-08-08 18:25:10 +00:00
var pod * api . Pod
2018-04-09 23:13:50 +00:00
leaveStdinOpen := o . LeaveStdinOpen
2016-08-08 18:25:10 +00:00
waitForExitCode := ! leaveStdinOpen && restartPolicy == api . RestartPolicyNever
if waitForExitCode {
2018-01-30 14:12:39 +00:00
pod , err = waitForPod ( clientset . Core ( ) , attachablePod . Namespace , attachablePod . Name , kubectl . PodCompleted )
2016-08-08 18:25:10 +00:00
if err != nil {
return err
}
}
// after removal is done, return successfully if we are not interested in the exit code
if ! waitForExitCode {
return nil
}
switch pod . Status . Phase {
case api . PodSucceeded :
return nil
case api . PodFailed :
unknownRcErr := fmt . Errorf ( "pod %s/%s failed with unknown exit code" , pod . Namespace , pod . Name )
if len ( pod . Status . ContainerStatuses ) == 0 || pod . Status . ContainerStatuses [ 0 ] . State . Terminated == nil {
return unknownRcErr
}
// assume here that we have at most one status because kubectl-run only creates one container per pod
rc := pod . Status . ContainerStatuses [ 0 ] . State . Terminated . ExitCode
if rc == 0 {
return unknownRcErr
}
return uexec . CodeExitError {
2017-07-07 02:46:22 +00:00
Err : fmt . Errorf ( "pod %s/%s terminated (%s)\n%s" , pod . Namespace , pod . Name , pod . Status . ContainerStatuses [ 0 ] . State . Terminated . Reason , pod . Status . ContainerStatuses [ 0 ] . State . Terminated . Message ) ,
2016-08-08 18:25:10 +00:00
Code : int ( rc ) ,
}
default :
return fmt . Errorf ( "pod %s/%s left in phase %s" , pod . Namespace , pod . Name , pod . Status . Phase )
2015-12-10 02:36:25 +00:00
}
2017-06-14 21:14:42 +00:00
2015-08-04 19:54:17 +00:00
}
2018-02-05 11:50:54 +00:00
if runObject != nil {
outputFormat := cmdutil . GetFlagString ( cmd , "output" )
if outputFormat != "" || cmdutil . GetDryRunFlag ( cmd ) {
2018-04-09 23:13:50 +00:00
return cmdutil . PrintObject ( cmd , runObject . Object , o . Out )
2018-02-05 11:50:54 +00:00
}
2018-04-09 23:13:50 +00:00
cmdutil . PrintSuccess ( false , o . Out , runObject . Object , cmdutil . GetDryRunFlag ( cmd ) , "created" )
2015-09-01 13:30:15 +00:00
}
2018-02-05 11:50:54 +00:00
return utilerrors . NewAggregate ( allErrs )
2015-08-04 19:54:17 +00:00
}
2018-04-09 23:13:50 +00:00
func ( o * RunOpts ) removeCreatedObjects ( f cmdutil . Factory , createdObjects [ ] * RunObject ) error {
2018-04-12 17:58:00 +00:00
for _ , obj := range createdObjects {
namespace , err := obj . Mapping . MetadataAccessor . Namespace ( obj . Object )
if err != nil {
return err
}
var name string
name , err = obj . Mapping . MetadataAccessor . Name ( obj . Object )
if err != nil {
return err
}
r := f . NewBuilder ( ) .
Internal ( ) .
ContinueOnError ( ) .
NamespaceParam ( namespace ) . DefaultNamespace ( ) .
ResourceNames ( obj . Mapping . Resource , name ) .
Flatten ( ) .
Do ( )
// Note: we pass in "true" for the "quiet" parameter because
// ReadResult will only print one thing based on the "quiet"
// flag, and that's the "pod xxx deleted" message. If they
// 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.
2018-04-09 23:13:50 +00:00
err = o . DeleteOptions . ReapResult ( r , true , true )
2018-04-12 17:58:00 +00:00
if err != nil {
return err
}
}
return nil
}
2016-11-19 20:42:04 +00:00
// waitForPod watches the given pod until the exitCondition is true
func waitForPod ( podClient coreclient . PodsGetter , ns , name string , exitCondition watch . ConditionFunc ) ( * api . Pod , error ) {
2017-01-22 03:36:02 +00:00
w , err := podClient . Pods ( ns ) . Watch ( metav1 . SingleObject ( metav1 . ObjectMeta { Name : name } ) )
2016-08-08 18:25:10 +00:00
if err != nil {
return nil , err
}
2016-08-08 17:56:19 +00:00
intr := interrupt . New ( nil , w . Stop )
var result * api . Pod
2016-10-03 15:41:49 +00:00
err = intr . Run ( func ( ) error {
2016-08-08 17:56:19 +00:00
ev , err := watch . Until ( 0 , w , func ( ev watch . Event ) ( bool , error ) {
2016-11-19 20:42:04 +00:00
return exitCondition ( ev )
2016-08-08 17:56:19 +00:00
} )
2017-04-12 22:00:50 +00:00
if ev != nil {
result = ev . Object . ( * api . Pod )
}
2016-08-08 17:56:19 +00:00
return err
} )
2016-08-08 18:25:10 +00:00
2017-08-07 01:36:00 +00:00
// Fix generic not found error.
2016-08-08 17:56:19 +00:00
if err != nil && errors . IsNotFound ( err ) {
2017-08-07 01:36:00 +00:00
err = errors . NewNotFound ( api . Resource ( "pods" ) , name )
2016-08-08 17:56:19 +00:00
}
2017-08-07 01:36:00 +00:00
return result , err
2015-08-04 19:54:17 +00:00
}
2017-03-17 13:55:46 +00:00
func handleAttachPod ( f cmdutil . Factory , podClient coreclient . PodsGetter , ns , name string , opts * AttachOptions ) error {
2018-01-30 14:12:39 +00:00
pod , err := waitForPod ( podClient , ns , name , kubectl . PodRunningAndReady )
if err != nil && err != kubectl . ErrPodCompleted {
2015-08-04 19:54:17 +00:00
return err
}
2017-08-07 04:13:22 +00:00
2016-08-08 18:25:10 +00:00
if pod . Status . Phase == api . PodSucceeded || pod . Status . Phase == api . PodFailed {
2017-08-07 04:13:22 +00:00
return logOpts ( f , pod , opts )
2015-09-02 03:54:10 +00:00
}
2016-09-06 18:23:54 +00:00
2016-09-08 15:50:53 +00:00
opts . PodClient = podClient
2016-08-08 18:25:10 +00:00
opts . PodName = name
opts . Namespace = ns
2017-08-07 04:13:22 +00:00
2016-09-07 17:25:35 +00:00
// TODO: opts.Run sets opts.Err to nil, we need to find a better way
stderr := opts . Err
2015-09-29 19:43:15 +00:00
if err := opts . Run ( ) ; err != nil {
2016-09-07 17:25:35 +00:00
fmt . Fprintf ( stderr , "Error attaching, falling back to logs: %v\n" , err )
2017-08-07 04:13:22 +00:00
return logOpts ( f , pod , opts )
}
return nil
}
// logOpts logs output from opts to the pods log.
func logOpts ( f cmdutil . Factory , pod * api . Pod , opts * AttachOptions ) error {
ctrName , err := opts . GetContainerName ( pod )
if err != nil {
return err
}
req , err := f . LogsForObject ( pod , & api . PodLogOptions { Container : ctrName } , opts . GetPodTimeout )
if err != nil {
return err
}
readCloser , err := req . Stream ( )
if err != nil {
return err
}
defer readCloser . Close ( )
_ , err = io . Copy ( opts . Out , readCloser )
if err != nil {
2015-10-18 14:20:28 +00:00
return err
2015-09-29 19:43:15 +00:00
}
return nil
2015-03-09 22:08:16 +00:00
}
2015-08-04 19:54:17 +00:00
func getRestartPolicy ( cmd * cobra . Command , interactive bool ) ( api . RestartPolicy , error ) {
restart := cmdutil . GetFlagString ( cmd , "restart" )
if len ( restart ) == 0 {
if interactive {
return api . RestartPolicyOnFailure , nil
} else {
return api . RestartPolicyAlways , nil
}
}
switch api . RestartPolicy ( restart ) {
case api . RestartPolicyAlways :
return api . RestartPolicyAlways , nil
case api . RestartPolicyOnFailure :
return api . RestartPolicyOnFailure , nil
case api . RestartPolicyNever :
return api . RestartPolicyNever , nil
}
2018-01-10 01:00:35 +00:00
return "" , cmdutil . UsageErrorf ( cmd , "invalid restart policy: %s" , restart )
2015-08-04 19:54:17 +00:00
}
2015-10-20 18:27:26 +00:00
2016-08-17 03:26:27 +00:00
func verifyImagePullPolicy ( cmd * cobra . Command ) error {
pullPolicy := cmdutil . GetFlagString ( cmd , "image-pull-policy" )
switch api . PullPolicy ( pullPolicy ) {
case api . PullAlways , api . PullIfNotPresent , api . PullNever :
return nil
case "" :
return nil
}
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "invalid image pull policy: %s" , pullPolicy )
2016-08-17 03:26:27 +00:00
}
2018-04-09 23:13:50 +00:00
func ( o * RunOpts ) generateService ( f cmdutil . Factory , cmd * cobra . Command , serviceGenerator string , paramsIn map [ string ] interface { } , namespace string ) ( * RunObject , error ) {
2015-11-19 18:14:10 +00:00
generators := f . Generators ( "expose" )
generator , found := generators [ serviceGenerator ]
2015-10-20 18:27:26 +00:00
if ! found {
2017-04-27 08:22:43 +00:00
return nil , fmt . Errorf ( "missing service generator: %s" , serviceGenerator )
2015-10-20 18:27:26 +00:00
}
names := generator . ParamNames ( )
params := map [ string ] interface { } { }
for key , value := range paramsIn {
_ , isString := value . ( string )
if isString {
params [ key ] = value
}
}
name , found := params [ "name" ]
if ! found || len ( name . ( string ) ) == 0 {
2017-04-27 08:22:43 +00:00
return nil , fmt . Errorf ( "name is a required parameter" )
2015-10-20 18:27:26 +00:00
}
selector , found := params [ "labels" ]
if ! found || len ( selector . ( string ) ) == 0 {
selector = fmt . Sprintf ( "run=%s" , name . ( string ) )
}
params [ "selector" ] = selector
if defaultName , found := params [ "default-name" ] ; ! found || len ( defaultName . ( string ) ) == 0 {
params [ "default-name" ] = name
}
2018-04-09 23:13:50 +00:00
runObject , err := o . createGeneratedObject ( f , cmd , generator , names , params , cmdutil . GetFlagString ( cmd , "service-overrides" ) , namespace )
2015-10-20 18:27:26 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2016-07-07 15:43:02 +00:00
if cmdutil . GetFlagString ( cmd , "output" ) != "" || cmdutil . GetDryRunFlag ( cmd ) {
2018-04-09 23:13:50 +00:00
err := cmdutil . PrintObject ( cmd , runObject . Object , o . Out )
2017-03-24 09:01:51 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2017-03-24 09:01:51 +00:00
}
if cmdutil . GetFlagString ( cmd , "output" ) == "yaml" {
2018-04-09 23:13:50 +00:00
fmt . Fprintln ( o . Out , "---" )
2017-03-24 09:01:51 +00:00
}
2017-04-27 08:22:43 +00:00
return runObject , nil
2015-10-20 18:27:26 +00:00
}
2018-04-09 23:13:50 +00:00
cmdutil . PrintSuccess ( false , o . Out , runObject . Object , cmdutil . GetDryRunFlag ( cmd ) , "created" )
2015-10-20 18:27:26 +00:00
2017-04-27 08:22:43 +00:00
return runObject , nil
2015-10-20 18:27:26 +00:00
}
2018-04-09 23:13:50 +00:00
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 ) {
2015-10-20 18:27:26 +00:00
err := kubectl . ValidateParams ( names , params )
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2015-11-19 18:14:10 +00:00
// TODO: Validate flag usage against selected generator. More tricky since --expose was added.
2015-10-20 18:27:26 +00:00
obj , err := generator . Generate ( params )
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2016-09-16 19:50:34 +00:00
mapper , typer := f . Object ( )
2016-05-21 04:15:31 +00:00
groupVersionKinds , _ , err := typer . ObjectKinds ( obj )
2015-10-20 18:27:26 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2016-05-21 04:15:31 +00:00
groupVersionKind := groupVersionKinds [ 0 ]
2015-10-20 18:27:26 +00:00
if len ( overrides ) > 0 {
2018-02-21 17:10:38 +00:00
codec := runtime . NewCodec ( cmdutil . InternalVersionJSONEncoder ( ) , cmdutil . InternalVersionDecoder ( ) )
2017-03-17 13:55:46 +00:00
obj , err = cmdutil . Merge ( codec , obj , overrides )
2015-10-20 18:27:26 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
}
2015-11-20 12:38:32 +00:00
mapping , err := mapper . RESTMapping ( groupVersionKind . GroupKind ( ) , groupVersionKind . Version )
2015-10-20 18:27:26 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2015-12-21 05:37:49 +00:00
client , err := f . ClientForMapping ( mapping )
2015-10-20 18:27:26 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2016-01-22 18:33:23 +00:00
annotations , err := mapping . MetadataAccessor . Annotations ( obj )
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2016-01-22 18:33:23 +00:00
}
2018-04-09 23:13:50 +00:00
if o . Record || len ( annotations [ kubectl . ChangeCauseAnnotation ] ) > 0 {
2017-02-25 15:40:50 +00:00
if err := cmdutil . RecordChangeCause ( obj , f . Command ( cmd , false ) ) ; err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2016-01-22 18:33:23 +00:00
}
}
2018-04-09 23:13:50 +00:00
if ! o . DryRun {
2015-12-21 05:37:49 +00:00
resourceMapper := & resource . Mapper {
ObjectTyper : typer ,
RESTMapper : mapper ,
ClientMapper : resource . ClientMapperFunc ( f . ClientForMapping ) ,
2018-02-21 17:10:38 +00:00
Decoder : cmdutil . InternalVersionDecoder ( ) ,
2015-12-21 05:37:49 +00:00
}
2016-03-11 04:49:00 +00:00
info , err := resourceMapper . InfoForObject ( obj , nil )
2015-10-20 18:27:26 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2018-02-21 17:10:38 +00:00
if err := kubectl . CreateOrUpdateAnnotation ( cmdutil . GetFlagBool ( cmd , cmdutil . ApplyAnnotationsFlag ) , info , cmdutil . InternalVersionJSONEncoder ( ) ) ; err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
2015-10-28 16:43:21 +00:00
obj , err = resource . NewHelper ( client , mapping ) . Create ( namespace , false , info . Object )
2015-10-20 18:27:26 +00:00
if err != nil {
2017-04-27 08:22:43 +00:00
return nil , err
2015-10-20 18:27:26 +00:00
}
}
2017-04-27 08:22:43 +00:00
return & RunObject {
Object : obj ,
Kind : groupVersionKind . Kind ,
Mapping : mapping ,
} , nil
2015-10-20 18:27:26 +00:00
}