Merge pull request #34789 from AdoHe/external_service

Automatic merge from submit-queue

create service add create ExternalName service implementation

@kubernetes/kubectl create service add ExternalName support, refer #34731 for more detail.

```release-note
kubectl create service externalname
```
This commit is contained in:
Kubernetes Submit Queue
2016-12-02 07:29:06 -08:00
committed by GitHub
8 changed files with 168 additions and 9 deletions

View File

@@ -40,6 +40,7 @@ func NewCmdCreateService(f cmdutil.Factory, cmdOut, errOut io.Writer) *cobra.Com
cmd.AddCommand(NewCmdCreateServiceClusterIP(f, cmdOut))
cmd.AddCommand(NewCmdCreateServiceNodePort(f, cmdOut))
cmd.AddCommand(NewCmdCreateServiceLoadBalancer(f, cmdOut))
cmd.AddCommand(NewCmdCreateServiceExternalName(f, cmdOut))
return cmd
}
@@ -218,3 +219,64 @@ func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
})
}
var (
serviceExternalNameLong = templates.LongDesc(`
Create an ExternalName service with the specified name.
ExternalName service references to an external DNS address instead of
only pods, which will allow application authors to reference services
that exist off platform, on other clusters, or locally.`)
serviceExternalNameExample = templates.Examples(`
# Create a new ExternalName service named my-ns
kubectl create service externalname my-ns --external-name bar.com`)
)
// NewCmdCreateServiceExternalName is a macro command for creating a ExternalName service
func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "externalname NAME --external-name external.name [--dry-run]",
Short: "Create an ExternalName service.",
Long: serviceExternalNameLong,
Example: serviceExternalNameExample,
Run: func(cmd *cobra.Command, args []string) {
err := CreateExternalNameService(f, cmdOut, cmd, args)
cmdutil.CheckErr(err)
},
}
cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmdutil.AddPrinterFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceExternalNameGeneratorV1Name)
addPortFlags(cmd)
cmd.Flags().String("external-name", "", "external name of service")
cmd.MarkFlagRequired("external-name")
return cmd
}
// CreateExternalNameService is the implementation of the service externalname command
func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
name, err := NameFromCommandArgs(cmd, args)
if err != nil {
return err
}
var generator kubectl.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
case cmdutil.ServiceExternalNameGeneratorV1Name:
generator = &kubectl.ServiceCommonGeneratorV1{
Name: name,
Type: api.ServiceTypeExternalName,
ExternalName: cmdutil.GetFlagString(cmd, "external-name"),
ClusterIP: "",
}
default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
}
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name,
StructuredGenerator: generator,
DryRun: cmdutil.GetDryRunFlag(cmd),
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
})
}

View File

@@ -193,6 +193,7 @@ const (
ServiceNodePortGeneratorV1Name = "service-nodeport/v1"
ServiceClusterIPGeneratorV1Name = "service-clusterip/v1"
ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1"
ServiceExternalNameGeneratorV1Name = "service-externalname/v1"
ServiceAccountV1GeneratorName = "serviceaccount/v1"
HorizontalPodAutoscalerV1Beta1GeneratorName = "horizontalpodautoscaler/v1beta1"
HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1"

View File

@@ -24,14 +24,16 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/validation"
)
type ServiceCommonGeneratorV1 struct {
Name string
TCP []string
Type api.ServiceType
ClusterIP string
NodePort int
Name string
TCP []string
Type api.ServiceType
ClusterIP string
NodePort int
ExternalName string
}
type ServiceClusterIPGeneratorV1 struct {
@@ -46,6 +48,11 @@ type ServiceLoadBalancerGeneratorV1 struct {
ServiceCommonGeneratorV1
}
// TODO: is this really necessary?
type ServiceExternalNameGeneratorV1 struct {
ServiceCommonGeneratorV1
}
func (ServiceClusterIPGeneratorV1) ParamNames() []GeneratorParam {
return []GeneratorParam{
{"name", true},
@@ -67,6 +74,13 @@ func (ServiceLoadBalancerGeneratorV1) ParamNames() []GeneratorParam {
}
}
func (ServiceExternalNameGeneratorV1) ParamNames() []GeneratorParam {
return []GeneratorParam{
{"name", true},
{"externalname", true},
}
}
func parsePorts(portString string) (int32, intstr.IntOrString, error) {
portStringSlice := strings.Split(portString, ":")
@@ -100,9 +114,14 @@ func (s ServiceCommonGeneratorV1) GenerateCommon(params map[string]interface{})
if !isString {
return fmt.Errorf("expected string, saw %v for 'clusterip'", clusterip)
}
externalname, isString := params["externalname"].(string)
if !isString {
return fmt.Errorf("expected string, saw %v for 'externalname'", externalname)
}
s.Name = name
s.TCP = tcpStrings
s.ClusterIP = clusterip
s.ExternalName = externalname
return nil
}
@@ -145,6 +164,19 @@ func (s ServiceClusterIPGeneratorV1) Generate(params map[string]interface{}) (ru
return delegate.StructuredGenerate()
}
func (s ServiceExternalNameGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
err := ValidateParams(s.ParamNames(), params)
if err != nil {
return nil, err
}
delegate := &ServiceCommonGeneratorV1{Type: api.ServiceTypeExternalName, ClusterIP: ""}
err = delegate.GenerateCommon(params)
if err != nil {
return nil, err
}
return delegate.StructuredGenerate()
}
// validate validates required fields are set to support structured generation
func (s ServiceCommonGeneratorV1) validate() error {
if len(s.Name) == 0 {
@@ -159,9 +191,14 @@ func (s ServiceCommonGeneratorV1) validate() error {
if s.ClusterIP == api.ClusterIPNone && len(s.TCP) > 0 {
return fmt.Errorf("can not map ports with clusterip=None")
}
if s.ClusterIP != api.ClusterIPNone && len(s.TCP) == 0 {
if s.ClusterIP != api.ClusterIPNone && len(s.TCP) == 0 && s.Type != api.ServiceTypeExternalName {
return fmt.Errorf("at least one tcp port specifier must be provided")
}
if s.Type == api.ServiceTypeExternalName {
if errs := validation.IsDNS1123Subdomain(s.ExternalName); len(errs) != 0 {
return fmt.Errorf("invalid service external name %s", s.ExternalName)
}
}
return nil
}
@@ -199,9 +236,10 @@ func (s ServiceCommonGeneratorV1) StructuredGenerate() (runtime.Object, error) {
Labels: labels,
},
Spec: api.ServiceSpec{
Type: api.ServiceType(s.Type),
Selector: selector,
Ports: ports,
Type: api.ServiceType(s.Type),
Selector: selector,
Ports: ports,
ExternalName: s.ExternalName,
},
}
if len(s.ClusterIP) > 0 {