2015-01-17 01:52:27 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
2015-01-17 01:52:27 +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"
2015-08-11 08:38:27 +00:00
"github.com/spf13/cobra"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
2015-01-17 01:52:27 +00:00
)
2015-02-20 21:28:43 +00:00
const (
expose_long = ` Take a replicated application and expose it as Kubernetes Service .
2015-03-11 17:22:08 +00:00
2015-03-26 02:35:26 +00:00
Looks up a replication controller or service by name and uses the selector for that resource as the
2015-05-13 08:52:25 +00:00
selector for a new Service on the specified port . If no labels are specified , the new service will
re - use the labels from the resource it exposes . `
2015-01-17 01:52:27 +00:00
2015-08-12 16:50:09 +00:00
expose_example = ` # Creates a service for a replicated nginx , which serves on port 80 and connects to the containers on port 8000.
2015-04-30 06:02:16 +00:00
$ kubectl expose rc nginx -- port = 80 -- target - port = 8000
2015-01-17 01:52:27 +00:00
2015-08-11 08:38:27 +00:00
# Creates a service for a replication controller identified by type and name specified in "nginx-controller.yaml" , which serves on port 80 and connects to the containers on port 8000.
$ kubectl expose - f nginx - controller . yaml -- port = 80 -- target - port = 8000
2015-08-12 16:50:09 +00:00
# Creates a second service based on the above service , exposing the container port 8443 as port 443 with the name "nginx-https"
2015-05-13 12:14:44 +00:00
$ kubectl expose service nginx -- port = 443 -- target - port = 8443 -- name = nginx - https
2015-03-26 02:35:26 +00:00
2015-08-12 16:50:09 +00:00
# Create a service for a replicated streaming application on port 4100 balancing UDP traffic and named ' video - stream ' .
2015-05-13 12:14:44 +00:00
$ kubectl expose rc streamer -- port = 4100 -- protocol = udp -- name = video - stream `
2015-02-20 21:28:43 +00:00
)
2015-02-03 17:59:21 +00:00
2015-04-07 18:21:25 +00:00
func NewCmdExposeService ( f * cmdutil . Factory , out io . Writer ) * cobra . Command {
2015-02-20 21:28:43 +00:00
cmd := & cobra . Command {
2015-08-11 08:38:27 +00:00
Use : "expose (-f FILENAME | TYPE NAME) --port=port [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--public-ip=ip] [--type=type]" ,
2015-02-20 21:28:43 +00:00
Short : "Take a replicated application and expose it as Kubernetes Service" ,
Long : expose_long ,
Example : expose_example ,
2015-01-17 01:52:27 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2015-03-09 22:08:16 +00:00
err := RunExpose ( f , out , cmd , args )
2015-04-07 18:21:25 +00:00
cmdutil . CheckErr ( err )
2015-01-17 01:52:27 +00:00
} ,
}
2015-04-07 18:21:25 +00:00
cmdutil . AddPrinterFlags ( cmd )
2015-07-16 21:18:17 +00:00
cmd . Flags ( ) . String ( "generator" , "service/v2" , "The name of the API generator to use. There are 2 generators: 'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named 'default', while it is left unnamed in v2. Default is 'service/v2'." )
2015-02-03 17:59:21 +00:00
cmd . Flags ( ) . String ( "protocol" , "TCP" , "The network protocol for the service to be created. Default is 'tcp'." )
2015-07-17 00:17:43 +00:00
cmd . Flags ( ) . Int ( "port" , - 1 , "The port that the service should serve on. Copied from the resource being exposed, if unspecified" )
2015-03-17 15:49:35 +00:00
cmd . MarkFlagRequired ( "port" )
2015-05-22 21:49:26 +00:00
cmd . Flags ( ) . String ( "type" , "" , "Type for this service: ClusterIP, NodePort, or LoadBalancer. Default is 'ClusterIP' unless --create-external-load-balancer is specified." )
cmd . Flags ( ) . Bool ( "create-external-load-balancer" , false , "If true, create an external load balancer for this service (trumped by --type). Implementation is cloud provider dependent. Default is 'false'." )
2015-02-03 17:59:21 +00:00
cmd . Flags ( ) . String ( "selector" , "" , "A label selector to use for this service. If empty (the default) infer the selector from the replication controller." )
2015-03-16 21:18:17 +00:00
cmd . Flags ( ) . StringP ( "labels" , "l" , "" , "Labels to apply to the service created by this call." )
2015-02-03 17:59:21 +00:00
cmd . Flags ( ) . Bool ( "dry-run" , false , "If true, only print the object that would be sent, without creating it." )
2015-03-26 20:56:36 +00:00
cmd . Flags ( ) . String ( "container-port" , "" , "Synonym for --target-port" )
cmd . Flags ( ) . String ( "target-port" , "" , "Name or number for the port on the container that the service should direct traffic to. Optional." )
2015-02-03 17:59:21 +00:00
cmd . Flags ( ) . String ( "public-ip" , "" , "Name of a public IP address to set for the service. The service will be assigned this IP in addition to its generated service IP." )
cmd . Flags ( ) . String ( "overrides" , "" , "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." )
2015-06-02 10:54:09 +00:00
cmd . Flags ( ) . String ( "name" , "" , "The name for the newly created object." )
2015-07-31 17:34:52 +00:00
cmd . Flags ( ) . String ( "session-affinity" , "" , "If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP'" )
2015-08-11 08:38:27 +00:00
usage := "Filename, directory, or URL to a file identifying the resource to expose a service"
kubectl . AddJsonFilenameFlag ( cmd , usage )
2015-01-17 01:52:27 +00:00
return cmd
}
2015-03-09 22:08:16 +00:00
2015-04-07 18:21:25 +00:00
func RunExpose ( f * cmdutil . Factory , out io . Writer , cmd * cobra . Command , args [ ] string ) error {
2015-08-11 08:38:27 +00:00
namespace , enforceNamespace , err := f . DefaultNamespace ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2015-05-07 15:30:28 +00:00
mapper , typer := f . Object ( )
2015-05-13 12:14:44 +00:00
r := resource . NewBuilder ( mapper , typer , f . ClientMapperForCommand ( ) ) .
ContinueOnError ( ) .
NamespaceParam ( namespace ) . DefaultNamespace ( ) .
2015-08-11 08:38:27 +00:00
FilenameParam ( enforceNamespace , cmdutil . GetFlagStringSlice ( cmd , "filename" ) ... ) .
2015-05-13 12:14:44 +00:00
ResourceTypeOrNameArgs ( false , args ... ) .
Flatten ( ) .
Do ( )
err = r . Err ( )
2015-05-07 15:30:28 +00:00
if err != nil {
return err
}
2015-05-13 12:14:44 +00:00
infos , err := r . Infos ( )
if err != nil {
return err
}
2015-05-26 12:03:11 +00:00
if len ( infos ) > 1 {
return fmt . Errorf ( "multiple resources provided: %v" , args )
}
2015-05-13 12:14:44 +00:00
info := infos [ 0 ]
2015-08-11 08:38:27 +00:00
mapping := info . ResourceMapping ( )
2015-05-13 12:14:44 +00:00
// Get the input object
2015-05-07 15:30:28 +00:00
client , err := f . RESTClient ( mapping )
if err != nil {
return err
}
2015-05-13 12:14:44 +00:00
inputObject , err := resource . NewHelper ( client , mapping ) . Get ( info . Namespace , info . Name )
2015-05-07 15:30:28 +00:00
if err != nil {
return err
}
2015-03-09 22:08:16 +00:00
2015-05-07 15:30:28 +00:00
// Get the generator, setup and validate all required parameters
generatorName := cmdutil . GetFlagString ( cmd , "generator" )
2015-05-05 09:15:01 +00:00
generator , found := f . Generator ( generatorName )
2015-03-09 22:08:16 +00:00
if ! found {
2015-06-02 10:54:09 +00:00
return cmdutil . UsageError ( cmd , fmt . Sprintf ( "generator %q not found." , generatorName ) )
2015-03-09 22:08:16 +00:00
}
names := generator . ParamNames ( )
params := kubectl . MakeParams ( cmd , names )
2015-05-26 12:03:11 +00:00
params [ "default-name" ] = info . Name
2015-04-07 18:21:25 +00:00
if s , found := params [ "selector" ] ; ! found || len ( s ) == 0 || cmdutil . GetFlagInt ( cmd , "port" ) < 1 {
2015-04-01 21:46:33 +00:00
if len ( s ) == 0 {
2015-05-07 15:30:28 +00:00
s , err := f . PodSelectorForObject ( inputObject )
2015-04-01 21:46:33 +00:00
if err != nil {
2015-07-17 00:17:43 +00:00
return cmdutil . UsageError ( cmd , fmt . Sprintf ( "couldn't find selectors via --selector flag or introspection: %s" , err ) )
2015-04-01 21:46:33 +00:00
}
params [ "selector" ] = s
}
2015-05-04 12:17:30 +00:00
noPorts := true
for _ , param := range names {
if param . Name == "port" {
noPorts = false
break
}
}
if cmdutil . GetFlagInt ( cmd , "port" ) < 0 && ! noPorts {
2015-05-07 15:30:28 +00:00
ports , err := f . PortsForObject ( inputObject )
2015-04-01 21:46:33 +00:00
if err != nil {
2015-07-17 00:17:43 +00:00
return cmdutil . UsageError ( cmd , fmt . Sprintf ( "couldn't find port via --port flag or introspection: %s" , err ) )
2015-04-01 21:46:33 +00:00
}
2015-05-13 12:14:44 +00:00
switch len ( ports ) {
case 0 :
2015-07-17 00:17:43 +00:00
return cmdutil . UsageError ( cmd , "couldn't find port via --port flag or introspection" )
2015-05-13 12:14:44 +00:00
case 1 :
params [ "port" ] = ports [ 0 ]
default :
2015-07-17 00:17:43 +00:00
return cmdutil . UsageError ( cmd , fmt . Sprintf ( "multiple ports to choose from: %v, please explicitly specify a port using the --port flag." , ports ) )
2015-04-01 21:46:33 +00:00
}
2015-03-09 22:08:16 +00:00
}
}
2015-04-07 18:21:25 +00:00
if cmdutil . GetFlagBool ( cmd , "create-external-load-balancer" ) {
2015-03-09 22:08:16 +00:00
params [ "create-external-load-balancer" ] = "true"
}
2015-05-13 08:52:25 +00:00
if len ( params [ "labels" ] ) == 0 {
labels , err := f . LabelsForObject ( inputObject )
if err != nil {
return err
}
params [ "labels" ] = kubectl . MakeLabels ( labels )
}
2015-05-22 21:49:26 +00:00
if v := cmdutil . GetFlagString ( cmd , "type" ) ; v != "" {
params [ "type" ] = v
}
2015-03-09 22:08:16 +00:00
err = kubectl . ValidateParams ( names , params )
if err != nil {
return err
}
2015-05-07 15:30:28 +00:00
// Expose new object
2015-05-04 12:17:30 +00:00
object , err := generator . Generate ( params )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2015-04-07 18:21:25 +00:00
inline := cmdutil . GetFlagString ( cmd , "overrides" )
2015-03-09 22:08:16 +00:00
if len ( inline ) > 0 {
2015-05-04 12:17:30 +00:00
object , err = cmdutil . Merge ( object , inline , mapping . Kind )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
}
// TODO: extract this flag to a central location, when such a location exists.
2015-04-07 18:21:25 +00:00
if ! cmdutil . GetFlagBool ( cmd , "dry-run" ) {
2015-08-08 01:52:23 +00:00
resourceMapper := & resource . Mapper { ObjectTyper : typer , RESTMapper : mapper , ClientMapper : f . ClientMapperForCommand ( ) }
2015-05-04 12:17:30 +00:00
info , err := resourceMapper . InfoForObject ( object )
if err != nil {
return err
}
data , err := info . Mapping . Codec . Encode ( object )
if err != nil {
return err
}
_ , err = resource . NewHelper ( info . Client , info . Mapping ) . Create ( namespace , false , data )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
}
2015-05-04 12:17:30 +00:00
return f . PrintObject ( cmd , object , out )
2015-03-09 22:08:16 +00:00
}