diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index f28a9f843c1..dfa32bb20c4 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -384,6 +384,7 @@ node-monitor-period node-name node-os-distro node-path-override +node-port node-startup-grace-period node-status-update-frequency node-sync-period diff --git a/pkg/kubectl/cmd/create_service.go b/pkg/kubectl/cmd/create_service.go index 61658c42280..115f4c54a89 100644 --- a/pkg/kubectl/cmd/create_service.go +++ b/pkg/kubectl/cmd/create_service.go @@ -134,6 +134,7 @@ func NewCmdCreateServiceNodePort(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Co cmdutil.AddValidateFlags(cmd) cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceNodePortGeneratorV1Name) + cmd.Flags().Int("node-port", 0, "Port used to expose the service on each node in a cluster.") addPortFlags(cmd) return cmd } @@ -152,6 +153,7 @@ func CreateServiceNodePort(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comm TCP: cmdutil.GetFlagStringSlice(cmd, "tcp"), Type: api.ServiceTypeNodePort, ClusterIP: "", + NodePort: cmdutil.GetFlagInt(cmd, "node-port"), } default: return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) diff --git a/pkg/kubectl/cmd/util/helpers.go b/pkg/kubectl/cmd/util/helpers.go index d3e3124905a..975e4c38c96 100644 --- a/pkg/kubectl/cmd/util/helpers.go +++ b/pkg/kubectl/cmd/util/helpers.go @@ -296,7 +296,7 @@ func isWatch(cmd *cobra.Command) bool { func GetFlagString(cmd *cobra.Command, flag string) string { s, err := cmd.Flags().GetString(flag) if err != nil { - glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err) + glog.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) } return s } @@ -305,7 +305,7 @@ func GetFlagString(cmd *cobra.Command, flag string) string { func GetFlagStringSlice(cmd *cobra.Command, flag string) []string { s, err := cmd.Flags().GetStringSlice(flag) if err != nil { - glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err) + glog.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) } return s } @@ -331,7 +331,7 @@ func GetWideFlag(cmd *cobra.Command) bool { func GetFlagBool(cmd *cobra.Command, flag string) bool { b, err := cmd.Flags().GetBool(flag) if err != nil { - glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err) + glog.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) } return b } @@ -340,7 +340,7 @@ func GetFlagBool(cmd *cobra.Command, flag string) bool { func GetFlagInt(cmd *cobra.Command, flag string) int { i, err := cmd.Flags().GetInt(flag) if err != nil { - glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err) + glog.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) } return i } @@ -349,7 +349,7 @@ func GetFlagInt(cmd *cobra.Command, flag string) int { func GetFlagInt64(cmd *cobra.Command, flag string) int64 { i, err := cmd.Flags().GetInt64(flag) if err != nil { - glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err) + glog.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) } return i } @@ -357,7 +357,7 @@ func GetFlagInt64(cmd *cobra.Command, flag string) int64 { func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration { d, err := cmd.Flags().GetDuration(flag) if err != nil { - glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err) + glog.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) } return d } diff --git a/pkg/kubectl/service_basic.go b/pkg/kubectl/service_basic.go index ee080aae3a9..9f1c3d2b6e4 100644 --- a/pkg/kubectl/service_basic.go +++ b/pkg/kubectl/service_basic.go @@ -31,6 +31,7 @@ type ServiceCommonGeneratorV1 struct { TCP []string Type api.ServiceType ClusterIP string + NodePort int } type ServiceClusterIPGeneratorV1 struct { @@ -56,6 +57,7 @@ func (ServiceNodePortGeneratorV1) ParamNames() []GeneratorParam { return []GeneratorParam{ {"name", true}, {"tcp", true}, + {"nodeport", true}, } } func (ServiceLoadBalancerGeneratorV1) ParamNames() []GeneratorParam { @@ -174,12 +176,14 @@ func (s ServiceCommonGeneratorV1) StructuredGenerate() (runtime.Object, error) { if err != nil { return nil, err } + portName := strings.Replace(tcpString, ":", "-", -1) ports = append(ports, api.ServicePort{ Name: portName, Port: port, TargetPort: targetPort, Protocol: api.Protocol("TCP"), + NodePort: int32(s.NodePort), }) } diff --git a/pkg/registry/core/service/portallocator/allocator.go b/pkg/registry/core/service/portallocator/allocator.go index 92a28777599..8e3d42be08c 100644 --- a/pkg/registry/core/service/portallocator/allocator.go +++ b/pkg/registry/core/service/portallocator/allocator.go @@ -37,11 +37,18 @@ type Interface interface { var ( ErrFull = errors.New("range is full") - ErrNotInRange = errors.New("provided port is not in the valid range") ErrAllocated = errors.New("provided port is already allocated") ErrMismatchedNetwork = errors.New("the provided port range does not match the current port range") ) +type ErrNotInRange struct { + ValidPorts string +} + +func (e *ErrNotInRange) Error() string { + return fmt.Sprintf("provided port is not in the valid range. The range of valid ports is %s", e.ValidPorts) +} + type PortAllocator struct { portRange net.PortRange @@ -82,7 +89,9 @@ func (r *PortAllocator) Free() int { func (r *PortAllocator) Allocate(port int) error { ok, offset := r.contains(port) if !ok { - return ErrNotInRange + // include valid port range in error + validPorts := r.portRange.String() + return &ErrNotInRange{validPorts} } allocated, err := r.alloc.Allocate(offset) diff --git a/pkg/registry/core/service/portallocator/allocator_test.go b/pkg/registry/core/service/portallocator/allocator_test.go index d060528b2ce..7386172b5e1 100644 --- a/pkg/registry/core/service/portallocator/allocator_test.go +++ b/pkg/registry/core/service/portallocator/allocator_test.go @@ -73,16 +73,23 @@ func TestAllocate(t *testing.T) { if err := r.Release(released); err != nil { t.Fatal(err) } - if err := r.Allocate(1); err != ErrNotInRange { + + err = r.Allocate(1) + if _, ok := err.(*ErrNotInRange); !ok { t.Fatal(err) } + if err := r.Allocate(10001); err != ErrAllocated { t.Fatal(err) } - if err := r.Allocate(20000); err != ErrNotInRange { + + err = r.Allocate(20000) + if _, ok := err.(*ErrNotInRange); !ok { t.Fatal(err) } - if err := r.Allocate(10201); err != ErrNotInRange { + + err = r.Allocate(10201) + if _, ok := err.(*ErrNotInRange); !ok { t.Fatal(err) } if f := r.Free(); f != 1 { diff --git a/pkg/registry/core/service/portallocator/controller/repair.go b/pkg/registry/core/service/portallocator/controller/repair.go index c91a9985ac6..b072fde703f 100644 --- a/pkg/registry/core/service/portallocator/controller/repair.go +++ b/pkg/registry/core/service/portallocator/controller/repair.go @@ -114,7 +114,7 @@ func (c *Repair) runOnce() error { // TODO: send event // port is broken, reallocate runtime.HandleError(fmt.Errorf("the port %d for service %s/%s was assigned to multiple services; please recreate", port, svc.Name, svc.Namespace)) - case portallocator.ErrNotInRange: + case err.(*portallocator.ErrNotInRange): // TODO: send event // port is broken, reallocate runtime.HandleError(fmt.Errorf("the port %d for service %s/%s is not within the port range %v; please recreate", port, svc.Name, svc.Namespace, c.portRange))