2014-11-03 03:51:05 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2014-11-03 03:51:05 +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 (
2015-10-07 14:59:08 +00:00
"errors"
2014-11-03 03:51:05 +00:00
"io"
2015-09-10 03:46:11 +00:00
"math"
2015-05-21 20:14:32 +00:00
"os"
2015-09-10 03:46:11 +00:00
"time"
2014-12-03 12:15:48 +00:00
2016-05-20 17:49:56 +00:00
"github.com/renstrom/dedent"
2015-08-05 22:05:17 +00:00
"github.com/spf13/cobra"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
2015-10-18 14:20:28 +00:00
"k8s.io/kubernetes/pkg/api/meta"
2015-09-10 03:46:11 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2015-10-18 14:20:28 +00:00
"k8s.io/kubernetes/pkg/api/validation"
2016-02-12 18:58:43 +00:00
"k8s.io/kubernetes/pkg/client/restclient"
2015-08-05 22:03:47 +00:00
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2015-10-18 14:20:28 +00:00
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
2014-11-03 03:51:05 +00:00
)
2016-05-20 17:49:56 +00:00
var (
logs_example = dedent . Dedent ( `
# Return snapshot logs from pod nginx with only one container
kubectl logs nginx
2014-12-15 11:07:25 +00:00
2016-05-20 17:49:56 +00:00
# Return snapshot of previous terminated ruby container logs from pod web - 1
kubectl logs - p - c ruby web - 1
2015-04-22 22:35:49 +00:00
2016-05-20 17:49:56 +00:00
# Begin streaming the logs of the ruby container in pod web - 1
kubectl logs - f - c ruby web - 1
2015-09-10 03:46:11 +00:00
2016-05-20 17:49:56 +00:00
# Display only the most recent 20 lines of output in pod nginx
kubectl logs -- tail = 20 nginx
2015-09-10 03:46:11 +00:00
2016-05-20 17:49:56 +00:00
# Show all logs from pod nginx written in the last hour
kubectl logs -- since = 1 h nginx ` )
2015-02-20 21:28:43 +00:00
)
2015-02-03 17:59:21 +00:00
2016-08-30 05:27:22 +00:00
const (
2016-08-31 05:17:53 +00:00
logsUsageStr = "expected 'logs POD_NAME [CONTAINER_NAME]'.\nPOD_NAME is a required argument for the logs command"
2016-08-30 05:27:22 +00:00
)
2015-10-07 14:59:08 +00:00
type LogsOptions struct {
2015-10-18 14:20:28 +00:00
Namespace string
ResourceArg string
Options runtime . Object
Mapper meta . RESTMapper
Typer runtime . ObjectTyper
ClientMapper resource . ClientMapper
2015-12-21 05:37:49 +00:00
Decoder runtime . Decoder
2015-10-18 14:20:28 +00:00
2016-02-20 18:53:35 +00:00
Object runtime . Object
2016-02-12 18:58:43 +00:00
LogsForObject func ( object , options runtime . Object ) ( * restclient . Request , error )
2015-10-07 14:59:08 +00:00
Out io . Writer
2015-06-30 00:48:00 +00:00
}
2015-11-24 02:05:45 +00:00
// NewCmdLog creates a new pod logs command
2016-10-13 00:18:39 +00:00
func NewCmdLogs ( f cmdutil . Factory , out io . Writer ) * cobra . Command {
2015-10-18 14:20:28 +00:00
o := & LogsOptions { }
2015-02-20 21:28:43 +00:00
cmd := & cobra . Command {
2015-06-30 00:48:00 +00:00
Use : "logs [-f] [-p] POD [-c CONTAINER]" ,
2016-06-07 17:38:04 +00:00
Short : "Print the logs for a container in a pod" ,
2015-02-20 21:28:43 +00:00
Long : "Print the logs for a container in a pod. If the pod has only one container, the container name is optional." ,
2015-11-24 02:05:45 +00:00
Example : logs_example ,
2015-10-18 14:20:28 +00:00
PreRun : func ( cmd * cobra . Command , args [ ] string ) {
2015-10-07 14:59:08 +00:00
if len ( os . Args ) > 1 && os . Args [ 1 ] == "log" {
printDeprecationWarning ( "logs" , "log" )
}
2015-10-18 14:20:28 +00:00
} ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
2015-10-07 14:59:08 +00:00
cmdutil . CheckErr ( o . Complete ( f , out , cmd , args ) )
if err := o . Validate ( ) ; err != nil {
cmdutil . CheckErr ( cmdutil . UsageError ( cmd , err . Error ( ) ) )
}
2015-11-24 02:05:45 +00:00
_ , err := o . RunLogs ( )
2015-10-18 14:20:28 +00:00
cmdutil . CheckErr ( err )
2015-03-09 22:08:16 +00:00
} ,
2015-05-21 20:14:32 +00:00
Aliases : [ ] string { "log" } ,
2015-03-09 22:08:16 +00:00
}
2015-10-18 14:20:28 +00:00
cmd . Flags ( ) . BoolP ( "follow" , "f" , false , "Specify if the logs should be streamed." )
cmd . Flags ( ) . Bool ( "timestamps" , false , "Include timestamps on each line in the log output" )
cmd . Flags ( ) . Int64 ( "limit-bytes" , 0 , "Maximum bytes of logs to return. Defaults to no limit." )
cmd . Flags ( ) . BoolP ( "previous" , "p" , false , "If true, print the logs for the previous instance of the container in a pod if it exists." )
cmd . Flags ( ) . Int64 ( "tail" , - 1 , "Lines of recent log file to display. Defaults to -1, showing all log lines." )
2015-09-10 03:46:11 +00:00
cmd . Flags ( ) . String ( "since-time" , "" , "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used." )
2015-10-18 14:20:28 +00:00
cmd . Flags ( ) . Duration ( "since" , 0 , "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used." )
cmd . Flags ( ) . StringP ( "container" , "c" , "" , "Print the logs of this container" )
cmd . Flags ( ) . Bool ( "interactive" , false , "If true, prompt the user for input when required." )
cmd . Flags ( ) . MarkDeprecated ( "interactive" , "This flag is no longer respected and there is no replacement." )
2016-03-10 01:27:19 +00:00
cmdutil . AddInclude3rdPartyFlags ( cmd )
2015-03-09 22:08:16 +00:00
return cmd
}
2014-11-25 18:10:32 +00:00
2016-10-13 00:18:39 +00:00
func ( o * LogsOptions ) Complete ( f cmdutil . Factory , out io . Writer , cmd * cobra . Command , args [ ] string ) error {
2015-10-18 14:20:28 +00:00
containerName := cmdutil . GetFlagString ( cmd , "container" )
2015-10-07 14:59:08 +00:00
switch len ( args ) {
case 0 :
2016-08-30 05:27:22 +00:00
return cmdutil . UsageError ( cmd , logsUsageStr )
2015-10-07 14:59:08 +00:00
case 1 :
2015-10-18 14:20:28 +00:00
o . ResourceArg = args [ 0 ]
2015-10-07 14:59:08 +00:00
case 2 :
if cmd . Flag ( "container" ) . Changed {
2016-08-30 05:27:22 +00:00
return cmdutil . UsageError ( cmd , "only one of -c or an inline [CONTAINER] arg is allowed" )
2015-10-07 14:59:08 +00:00
}
2015-10-18 14:20:28 +00:00
o . ResourceArg = args [ 0 ]
containerName = args [ 1 ]
2015-10-07 14:59:08 +00:00
default :
2016-08-30 05:27:22 +00:00
return cmdutil . UsageError ( cmd , logsUsageStr )
2015-09-10 03:46:11 +00:00
}
2015-10-07 14:59:08 +00:00
var err error
2015-10-18 14:20:28 +00:00
o . Namespace , _ , err = f . DefaultNamespace ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2014-12-11 18:39:20 +00:00
2015-10-18 14:20:28 +00:00
logOptions := & api . PodLogOptions {
Container : containerName ,
Follow : cmdutil . GetFlagBool ( cmd , "follow" ) ,
Previous : cmdutil . GetFlagBool ( cmd , "previous" ) ,
Timestamps : cmdutil . GetFlagBool ( cmd , "timestamps" ) ,
}
if sinceTime := cmdutil . GetFlagString ( cmd , "since-time" ) ; len ( sinceTime ) > 0 {
2015-10-07 14:59:08 +00:00
t , err := api . ParseRFC3339 ( sinceTime , unversioned . Now )
if err != nil {
return err
}
2015-10-18 14:20:28 +00:00
logOptions . SinceTime = & t
}
if limit := cmdutil . GetFlagInt64 ( cmd , "limit-bytes" ) ; limit != 0 {
logOptions . LimitBytes = & limit
}
if tail := cmdutil . GetFlagInt64 ( cmd , "tail" ) ; tail != - 1 {
logOptions . TailLines = & tail
}
if sinceSeconds := cmdutil . GetFlagDuration ( cmd , "since" ) ; sinceSeconds != 0 {
// round up to the nearest second
sec := int64 ( math . Ceil ( float64 ( sinceSeconds ) / float64 ( time . Second ) ) )
logOptions . SinceSeconds = & sec
2015-10-07 14:59:08 +00:00
}
2015-10-18 14:20:28 +00:00
o . Options = logOptions
o . LogsForObject = f . LogsForObject
2016-02-20 18:53:35 +00:00
o . ClientMapper = resource . ClientMapperFunc ( f . ClientForMapping )
2015-10-18 14:20:28 +00:00
o . Out = out
2015-10-07 14:59:08 +00:00
2016-09-16 19:50:34 +00:00
mapper , typer := f . Object ( )
2016-02-20 18:53:35 +00:00
decoder := f . Decoder ( true )
if o . Object == nil {
infos , err := resource . NewBuilder ( mapper , typer , o . ClientMapper , decoder ) .
NamespaceParam ( o . Namespace ) . DefaultNamespace ( ) .
ResourceNames ( "pods" , o . ResourceArg ) .
SingleResourceType ( ) .
Do ( ) . Infos ( )
if err != nil {
return err
}
if len ( infos ) != 1 {
return errors . New ( "expected a resource" )
}
o . Object = infos [ 0 ] . Object
}
2015-10-07 14:59:08 +00:00
return nil
}
2015-10-18 14:20:28 +00:00
func ( o LogsOptions ) Validate ( ) error {
if len ( o . ResourceArg ) == 0 {
return errors . New ( "a pod must be specified" )
2015-10-07 14:59:08 +00:00
}
2015-11-24 02:05:45 +00:00
logsOptions , ok := o . Options . ( * api . PodLogOptions )
2015-10-18 14:20:28 +00:00
if ! ok {
2015-11-24 02:05:45 +00:00
return errors . New ( "unexpected logs options object" )
2015-10-07 14:59:08 +00:00
}
2015-11-24 02:05:45 +00:00
if errs := validation . ValidatePodLogOptions ( logsOptions ) ; len ( errs ) > 0 {
2015-11-04 00:08:20 +00:00
return errs . ToAggregate ( )
2015-10-07 14:59:08 +00:00
}
return nil
}
2014-12-11 18:39:20 +00:00
2015-11-24 02:05:45 +00:00
// RunLogs retrieves a pod log
func ( o LogsOptions ) RunLogs ( ) ( int64 , error ) {
2016-02-20 18:53:35 +00:00
req , err := o . LogsForObject ( o . Object , o . Options )
2015-10-18 14:20:28 +00:00
if err != nil {
return 0 , err
2015-09-10 03:46:11 +00:00
}
readCloser , err := req . Stream ( )
2015-03-09 22:08:16 +00:00
if err != nil {
2015-10-18 14:20:28 +00:00
return 0 , err
2015-03-09 22:08:16 +00:00
}
defer readCloser . Close ( )
2015-10-18 14:20:28 +00:00
return io . Copy ( o . Out , readCloser )
2014-11-03 03:51:05 +00:00
}