2014-06-06 23:40:48 +00:00
/ *
Copyright 2014 Google Inc . All rights reserved .
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 .
* /
2014-06-23 18:32:11 +00:00
2014-06-06 23:40:48 +00:00
package main
import (
"flag"
"fmt"
2014-06-12 20:41:48 +00:00
"io/ioutil"
2014-06-12 01:13:25 +00:00
"net/url"
2014-06-06 23:40:48 +00:00
"os"
2014-07-25 19:28:20 +00:00
"reflect"
2014-07-23 00:25:06 +00:00
"sort"
2014-06-06 23:40:48 +00:00
"strconv"
2014-06-12 21:13:02 +00:00
"strings"
2014-07-15 04:13:06 +00:00
"text/template"
2014-06-06 23:40:48 +00:00
"time"
2014-08-01 21:14:33 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
2014-06-06 23:40:48 +00:00
kube_client "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
2014-06-26 00:55:43 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubecfg"
2014-06-25 03:51:57 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
2014-07-25 19:28:20 +00:00
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
2014-08-01 05:55:44 +00:00
verflag "github.com/GoogleCloudPlatform/kubernetes/pkg/version/flag"
2014-06-25 03:51:57 +00:00
"github.com/golang/glog"
2014-06-06 23:40:48 +00:00
)
2014-06-07 21:06:28 +00:00
var (
2014-07-25 19:28:20 +00:00
serverVersion = flag . Bool ( "server_version" , false , "Print the server's version number." )
preventSkew = flag . Bool ( "expect_version_match" , false , "Fail if server's version doesn't match own version." )
httpServer = flag . String ( "h" , "" , "The host to connect to." )
config = flag . String ( "c" , "" , "Path to the config file." )
selector = flag . String ( "l" , "" , "Selector (label query) to use for listing" )
updatePeriod = flag . Duration ( "u" , 60 * time . Second , "Update interval period" )
portSpec = flag . String ( "p" , "" , "The port spec, comma-separated list of <external>:<internal>,..." )
servicePort = flag . Int ( "s" , - 1 , "If positive, create and run a corresponding service on this port, only used with 'run'" )
authConfig = flag . String ( "auth" , os . Getenv ( "HOME" ) + "/.kubernetes_auth" , "Path to the auth info file. If missing, prompt the user. Only used if doing https." )
json = flag . Bool ( "json" , false , "If true, print raw JSON for responses" )
yaml = flag . Bool ( "yaml" , false , "If true, print raw YAML for responses" )
verbose = flag . Bool ( "verbose" , false , "If true, print extra information" )
proxy = flag . Bool ( "proxy" , false , "If true, run a proxy to the api server" )
www = flag . String ( "www" , "" , "If -proxy is true, use this directory to serve static files" )
templateFile = flag . String ( "template_file" , "" , "If present, load this file as a golang template and use it for output printing" )
templateStr = flag . String ( "template" , "" , "If present, parse this string as a golang template and use it for output printing" )
2014-06-07 21:06:28 +00:00
)
2014-06-06 23:40:48 +00:00
func usage ( ) {
2014-07-23 00:25:06 +00:00
fmt . Fprintf ( os . Stderr , ` usage : kubecfg - h [ - c config / file . json ] [ - p : , ... , : ] < method >
2014-06-11 22:08:23 +00:00
Kubernetes REST API :
2014-07-23 00:25:06 +00:00
kubecfg [ OPTIONS ] get | list | create | delete | update < % s > [ / < id > ]
2014-06-11 22:08:23 +00:00
Manage replication controllers :
2014-06-26 00:55:43 +00:00
kubecfg [ OPTIONS ] stop | rm | rollingupdate < controller >
kubecfg [ OPTIONS ] run < image > < replicas > < controller >
kubecfg [ OPTIONS ] resize < controller > < replicas >
2014-06-11 22:08:23 +00:00
Options :
2014-07-23 00:25:06 +00:00
` , prettyWireStorage ( ) )
2014-06-11 22:08:23 +00:00
flag . PrintDefaults ( )
2014-06-06 23:40:48 +00:00
}
2014-07-23 00:25:06 +00:00
func prettyWireStorage ( ) string {
types := kubecfg . SupportedWireStorage ( )
sort . Strings ( types )
return strings . Join ( types , "|" )
}
2014-07-20 15:36:20 +00:00
// readConfig reads and parses pod, replicationController, and service
// configuration files. If any errors log and exit non-zero.
2014-06-12 20:41:48 +00:00
func readConfig ( storage string ) [ ] byte {
if len ( * config ) == 0 {
2014-06-25 03:51:57 +00:00
glog . Fatal ( "Need config file (-c)" )
2014-06-12 20:41:48 +00:00
}
data , err := ioutil . ReadFile ( * config )
if err != nil {
2014-07-01 02:45:00 +00:00
glog . Fatalf ( "Unable to read %v: %v\n" , * config , err )
2014-06-12 20:41:48 +00:00
}
2014-06-26 00:55:43 +00:00
data , err = kubecfg . ToWireFormat ( data , storage )
2014-06-12 20:41:48 +00:00
if err != nil {
2014-07-01 02:45:00 +00:00
glog . Fatalf ( "Error parsing %v as an object for %v: %v\n" , * config , storage , err )
2014-06-12 20:41:48 +00:00
}
2014-06-16 03:53:21 +00:00
if * verbose {
2014-06-25 03:51:57 +00:00
glog . Infof ( "Parsed config file successfully; sending:\n%v\n" , string ( data ) )
2014-06-16 03:53:21 +00:00
}
2014-06-12 20:41:48 +00:00
return data
}
2014-06-06 23:40:48 +00:00
func main ( ) {
2014-06-11 22:08:23 +00:00
flag . Usage = func ( ) {
usage ( )
}
2014-07-20 15:36:20 +00:00
flag . Parse ( )
2014-06-25 03:51:57 +00:00
util . InitLogs ( )
defer util . FlushLogs ( )
2014-06-06 23:40:48 +00:00
2014-08-01 05:55:44 +00:00
verflag . PrintAndExitIfRequested ( )
2014-06-06 23:40:48 +00:00
2014-06-12 01:13:25 +00:00
secure := true
2014-06-28 05:48:32 +00:00
var masterServer string
if len ( * httpServer ) > 0 {
masterServer = * httpServer
} else if len ( os . Getenv ( "KUBERNETES_MASTER" ) ) > 0 {
masterServer = os . Getenv ( "KUBERNETES_MASTER" )
} else {
masterServer = "http://localhost:8080"
}
2014-07-08 06:30:18 +00:00
parsedURL , err := url . Parse ( masterServer )
2014-06-12 01:13:25 +00:00
if err != nil {
2014-06-25 03:51:57 +00:00
glog . Fatalf ( "Unable to parse %v as a URL\n" , err )
2014-06-12 01:13:25 +00:00
}
2014-07-08 06:30:18 +00:00
if parsedURL . Scheme != "" && parsedURL . Scheme != "https" {
2014-06-12 01:13:25 +00:00
secure = false
}
2014-06-09 03:29:30 +00:00
2014-06-12 05:25:50 +00:00
var auth * kube_client . AuthInfo
2014-06-12 01:13:25 +00:00
if secure {
2014-07-26 22:00:37 +00:00
auth , err = kubecfg . LoadAuthInfo ( * authConfig , os . Stdin )
2014-06-12 01:13:25 +00:00
if err != nil {
2014-07-01 02:45:00 +00:00
glog . Fatalf ( "Error loading auth: %v" , err )
2014-06-12 01:13:25 +00:00
}
2014-06-06 23:40:48 +00:00
}
2014-07-25 19:28:20 +00:00
client := kube_client . New ( masterServer , auth )
if * serverVersion {
got , err := client . ServerVersion ( )
if err != nil {
fmt . Printf ( "Couldn't read version from server: %v\n" , err )
os . Exit ( 1 )
}
fmt . Printf ( "Server Version: %#v\n" , got )
os . Exit ( 0 )
}
if * preventSkew {
got , err := client . ServerVersion ( )
if err != nil {
fmt . Printf ( "Couldn't read version from server: %v\n" , err )
os . Exit ( 1 )
}
if c , s := version . Get ( ) , * got ; ! reflect . DeepEqual ( c , s ) {
fmt . Printf ( "Server version (%#v) differs from client version (%#v)!\n" , s , c )
os . Exit ( 1 )
}
}
2014-06-24 02:57:54 +00:00
if * proxy {
2014-06-25 03:51:57 +00:00
glog . Info ( "Starting to serve on localhost:8001" )
2014-06-28 05:48:32 +00:00
server := kubecfg . NewProxyServer ( * www , masterServer , auth )
2014-06-25 03:51:57 +00:00
glog . Fatal ( server . Serve ( ) )
2014-06-24 02:57:54 +00:00
}
2014-06-24 05:18:14 +00:00
if len ( flag . Args ( ) ) < 1 {
usage ( )
os . Exit ( 1 )
}
method := flag . Arg ( 0 )
2014-06-28 05:48:32 +00:00
matchFound := executeAPIRequest ( method , client ) || executeControllerRequest ( method , client )
2014-06-11 22:08:23 +00:00
if matchFound == false {
2014-06-25 03:51:57 +00:00
glog . Fatalf ( "Unknown command %s" , method )
2014-06-11 22:08:23 +00:00
}
}
2014-07-23 15:16:41 +00:00
// storagePathFromArg normalizes a path and breaks out the first segment if available
func storagePathFromArg ( arg string ) ( storage , path string , hasSuffix bool ) {
path = strings . Trim ( arg , "/" )
segments := strings . SplitN ( path , "/" , 2 )
storage = segments [ 0 ]
if len ( segments ) > 1 && segments [ 1 ] != "" {
hasSuffix = true
}
return storage , path , hasSuffix
}
//checkStorage returns true if the provided storage is valid
func checkStorage ( storage string ) bool {
for _ , allowed := range kubecfg . SupportedWireStorage ( ) {
if allowed == storage {
return true
}
2014-06-11 22:08:23 +00:00
}
2014-07-23 15:16:41 +00:00
return false
}
2014-06-11 22:08:23 +00:00
2014-07-23 15:16:41 +00:00
func executeAPIRequest ( method string , s * kube_client . Client ) bool {
storage , path , hasSuffix := storagePathFromArg ( flag . Arg ( 1 ) )
validStorage := checkStorage ( storage )
2014-06-21 21:23:14 +00:00
verb := ""
2014-07-23 00:25:06 +00:00
setBody := false
2014-08-01 21:14:33 +00:00
var version uint64
2014-06-10 21:42:59 +00:00
switch method {
2014-07-23 15:16:41 +00:00
case "get" :
verb = "GET"
if ! validStorage || ! hasSuffix {
glog . Fatalf ( "usage: kubecfg [OPTIONS] %s <%s>[/<id>]" , method , prettyWireStorage ( ) )
}
case "list" :
2014-06-21 21:23:14 +00:00
verb = "GET"
2014-07-23 15:16:41 +00:00
if ! validStorage || hasSuffix {
glog . Fatalf ( "usage: kubecfg [OPTIONS] %s <%s>" , method , prettyWireStorage ( ) )
}
2014-06-10 21:42:59 +00:00
case "delete" :
2014-06-21 21:23:14 +00:00
verb = "DELETE"
2014-07-23 15:16:41 +00:00
if ! validStorage || ! hasSuffix {
glog . Fatalf ( "usage: kubecfg [OPTIONS] %s <%s>/<id>" , method , prettyWireStorage ( ) )
2014-07-23 00:25:06 +00:00
}
2014-06-10 21:42:59 +00:00
case "create" :
2014-06-21 21:23:14 +00:00
verb = "POST"
2014-07-23 00:25:06 +00:00
setBody = true
2014-07-23 15:16:41 +00:00
if ! validStorage || hasSuffix {
glog . Fatalf ( "usage: kubecfg [OPTIONS] %s <%s>" , method , prettyWireStorage ( ) )
2014-07-23 00:25:06 +00:00
}
2014-06-10 21:42:59 +00:00
case "update" :
2014-08-01 21:14:33 +00:00
obj , err := s . Verb ( "GET" ) . Path ( path ) . Do ( ) . Get ( )
if err != nil {
glog . Fatalf ( "error obtaining resource version for update: %v" , err )
}
jsonBase , err := api . FindJSONBase ( obj )
if err != nil {
glog . Fatalf ( "error finding json base for update: %v" , err )
}
version = jsonBase . ResourceVersion ( )
2014-06-21 21:23:14 +00:00
verb = "PUT"
2014-07-23 00:25:06 +00:00
setBody = true
2014-07-23 15:16:41 +00:00
if ! validStorage || ! hasSuffix {
glog . Fatalf ( "usage: kubecfg [OPTIONS] %s <%s>/<id>" , method , prettyWireStorage ( ) )
2014-07-23 00:25:06 +00:00
}
2014-06-11 22:08:23 +00:00
default :
return false
}
2014-06-21 21:23:14 +00:00
r := s . Verb ( verb ) .
2014-07-23 00:25:06 +00:00
Path ( path ) .
2014-06-23 00:02:48 +00:00
ParseSelector ( * selector )
2014-07-23 00:25:06 +00:00
if setBody {
2014-08-01 21:14:33 +00:00
if version != 0 {
data := readConfig ( storage )
obj , err := api . Decode ( data )
if err != nil {
glog . Fatalf ( "error setting resource version: %v" , err )
}
jsonBase , err := api . FindJSONBase ( obj )
if err != nil {
glog . Fatalf ( "error setting resource version: %v" , err )
}
jsonBase . SetResourceVersion ( version )
data , err = api . Encode ( obj )
if err != nil {
glog . Fatalf ( "error setting resource version: %v" , err )
}
r . Body ( data )
} else {
r . Body ( readConfig ( storage ) )
}
2014-06-21 21:23:14 +00:00
}
2014-07-01 02:45:00 +00:00
result := r . Do ( )
obj , err := result . Get ( )
2014-06-21 21:23:14 +00:00
if err != nil {
2014-06-25 03:51:57 +00:00
glog . Fatalf ( "Got request error: %v\n" , err )
2014-06-21 21:23:14 +00:00
return false
}
2014-06-26 00:55:43 +00:00
var printer kubecfg . ResourcePrinter
2014-07-15 04:29:31 +00:00
switch {
case * json :
2014-06-26 00:55:43 +00:00
printer = & kubecfg . IdentityPrinter { }
2014-07-15 04:29:31 +00:00
case * yaml :
2014-06-26 00:55:43 +00:00
printer = & kubecfg . YAMLPrinter { }
2014-07-15 04:29:31 +00:00
case len ( * templateFile ) > 0 || len ( * templateStr ) > 0 :
var data [ ] byte
if len ( * templateFile ) > 0 {
var err error
data , err = ioutil . ReadFile ( * templateFile )
if err != nil {
glog . Fatalf ( "Error reading template %s, %v\n" , * templateFile , err )
return false
}
} else {
data = [ ] byte ( * templateStr )
2014-07-15 04:13:06 +00:00
}
tmpl , err := template . New ( "output" ) . Parse ( string ( data ) )
if err != nil {
glog . Fatalf ( "Error parsing template %s, %v\n" , string ( data ) , err )
return false
}
printer = & kubecfg . TemplatePrinter {
Template : tmpl ,
}
2014-07-15 04:29:31 +00:00
default :
2014-06-26 00:55:43 +00:00
printer = & kubecfg . HumanReadablePrinter { }
2014-06-11 22:08:23 +00:00
}
2014-06-21 21:23:14 +00:00
if err = printer . PrintObj ( obj , os . Stdout ) ; err != nil {
2014-07-01 02:45:00 +00:00
body , _ := result . Raw ( )
glog . Fatalf ( "Failed to print: %v\nRaw received object:\n%#v\n\nBody received: %v" , err , obj , string ( body ) )
2014-06-11 22:08:23 +00:00
}
2014-06-21 21:23:14 +00:00
fmt . Print ( "\n" )
2014-06-11 22:08:23 +00:00
return true
}
2014-06-28 05:48:32 +00:00
func executeControllerRequest ( method string , c * kube_client . Client ) bool {
2014-06-11 22:08:23 +00:00
parseController := func ( ) string {
if len ( flag . Args ( ) ) != 2 {
2014-06-26 00:55:43 +00:00
glog . Fatal ( "usage: kubecfg [OPTIONS] stop|rm|rollingupdate <controller>" )
2014-06-11 22:08:23 +00:00
}
return flag . Arg ( 1 )
}
var err error
switch method {
case "stop" :
2014-06-26 00:55:43 +00:00
err = kubecfg . StopController ( parseController ( ) , c )
2014-06-11 22:08:23 +00:00
case "rm" :
2014-06-26 00:55:43 +00:00
err = kubecfg . DeleteController ( parseController ( ) , c )
2014-06-10 21:42:59 +00:00
case "rollingupdate" :
2014-06-26 00:55:43 +00:00
err = kubecfg . Update ( parseController ( ) , c , * updatePeriod )
2014-06-10 21:42:59 +00:00
case "run" :
2014-06-11 22:08:23 +00:00
if len ( flag . Args ( ) ) != 4 {
2014-06-26 00:55:43 +00:00
glog . Fatal ( "usage: kubecfg [OPTIONS] run <image> <replicas> <controller>" )
2014-06-06 23:40:48 +00:00
}
2014-06-11 22:08:23 +00:00
image := flag . Arg ( 1 )
replicas , err := strconv . Atoi ( flag . Arg ( 2 ) )
name := flag . Arg ( 3 )
2014-06-06 23:40:48 +00:00
if err != nil {
2014-07-01 02:45:00 +00:00
glog . Fatalf ( "Error parsing replicas: %v" , err )
2014-06-06 23:40:48 +00:00
}
2014-06-26 00:55:43 +00:00
err = kubecfg . RunController ( image , name , replicas , c , * portSpec , * servicePort )
2014-06-12 17:03:17 +00:00
case "resize" :
args := flag . Args ( )
if len ( args ) < 3 {
2014-06-26 00:55:43 +00:00
glog . Fatal ( "usage: kubecfg resize <controller> <replicas>" )
2014-06-12 17:03:17 +00:00
}
name := args [ 1 ]
replicas , err := strconv . Atoi ( args [ 2 ] )
if err != nil {
2014-07-01 02:45:00 +00:00
glog . Fatalf ( "Error parsing replicas: %v" , err )
2014-06-12 17:03:17 +00:00
}
2014-06-26 00:55:43 +00:00
err = kubecfg . ResizeController ( name , replicas , c )
2014-06-10 21:42:59 +00:00
default :
2014-06-11 22:08:23 +00:00
return false
2014-06-06 23:40:48 +00:00
}
if err != nil {
2014-07-01 02:45:00 +00:00
glog . Fatalf ( "Error: %v" , err )
2014-06-06 23:40:48 +00:00
}
2014-06-11 22:08:23 +00:00
return true
2014-06-06 23:40:48 +00:00
}