mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #33319 from juanvallejo/jvallejo/add-option-to-set-nodeport
Automatic merge from submit-queue Add option to set a service nodeport **Release note**: ```release-note Add kubectl --node-port option for specifying the service nodeport ``` This patch adds the option to set a nodeport when creating a NodePort service. In case of a port allocation error due to a specified port being out of the valid range, the error now includes the valid range. If a `--node-port` value is not specified, it defaults to zero, in which case the allocator will default to its current behavior of assigning an available port. This patch also adds a new helper function in `cmd/util/helpers.go` to retrieve `Int32` cobra flags. **Example** ``` # create a nodeport service with an invalid port $ kubectl create service nodeport mynodeport --tcp=8080:7777 --node-port=1 The Service "mynodeport" is invalid: spec.ports[0].nodePort: Invalid value: 1: provided port is not in the valid range. Valid ports range from 30000-32767 # create a nodeport service with a valid port $ kubectl create service nodeport mynodeport --tcp=8080:7777 --node-port=30000 service "mynodeport" created # create a nodeport service with a port already in use $ kubectl create service nodeport mynodeport --tcp=8080:7777 --node-port=30000 The Service "mynodeport" is invalid: spec.ports[0].nodePort: Invalid value: 3000: provided port is already allocated $ kubectl describe service mynodeport Name: mynodeport Namespace: default Labels: app=mynodeport Selector: app=mynodeport Type: NodePort IP: 172.30.81.254 Port: 8080-7777 8080/TCP NodePort: 8080-7777 30000/TCP Endpoints: <none> Session Affinity: None No events. ``` @fabianofranz
This commit is contained in:
commit
05192d9d57
@ -384,6 +384,7 @@ node-monitor-period
|
|||||||
node-name
|
node-name
|
||||||
node-os-distro
|
node-os-distro
|
||||||
node-path-override
|
node-path-override
|
||||||
|
node-port
|
||||||
node-startup-grace-period
|
node-startup-grace-period
|
||||||
node-status-update-frequency
|
node-status-update-frequency
|
||||||
node-sync-period
|
node-sync-period
|
||||||
|
@ -134,6 +134,7 @@ func NewCmdCreateServiceNodePort(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Co
|
|||||||
cmdutil.AddValidateFlags(cmd)
|
cmdutil.AddValidateFlags(cmd)
|
||||||
cmdutil.AddPrinterFlags(cmd)
|
cmdutil.AddPrinterFlags(cmd)
|
||||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceNodePortGeneratorV1Name)
|
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)
|
addPortFlags(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -152,6 +153,7 @@ func CreateServiceNodePort(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comm
|
|||||||
TCP: cmdutil.GetFlagStringSlice(cmd, "tcp"),
|
TCP: cmdutil.GetFlagStringSlice(cmd, "tcp"),
|
||||||
Type: api.ServiceTypeNodePort,
|
Type: api.ServiceTypeNodePort,
|
||||||
ClusterIP: "",
|
ClusterIP: "",
|
||||||
|
NodePort: cmdutil.GetFlagInt(cmd, "node-port"),
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
|
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
|
||||||
|
@ -296,7 +296,7 @@ func isWatch(cmd *cobra.Command) bool {
|
|||||||
func GetFlagString(cmd *cobra.Command, flag string) string {
|
func GetFlagString(cmd *cobra.Command, flag string) string {
|
||||||
s, err := cmd.Flags().GetString(flag)
|
s, err := cmd.Flags().GetString(flag)
|
||||||
if err != nil {
|
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
|
return s
|
||||||
}
|
}
|
||||||
@ -305,7 +305,7 @@ func GetFlagString(cmd *cobra.Command, flag string) string {
|
|||||||
func GetFlagStringSlice(cmd *cobra.Command, flag string) []string {
|
func GetFlagStringSlice(cmd *cobra.Command, flag string) []string {
|
||||||
s, err := cmd.Flags().GetStringSlice(flag)
|
s, err := cmd.Flags().GetStringSlice(flag)
|
||||||
if err != nil {
|
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
|
return s
|
||||||
}
|
}
|
||||||
@ -331,7 +331,7 @@ func GetWideFlag(cmd *cobra.Command) bool {
|
|||||||
func GetFlagBool(cmd *cobra.Command, flag string) bool {
|
func GetFlagBool(cmd *cobra.Command, flag string) bool {
|
||||||
b, err := cmd.Flags().GetBool(flag)
|
b, err := cmd.Flags().GetBool(flag)
|
||||||
if err != nil {
|
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
|
return b
|
||||||
}
|
}
|
||||||
@ -340,7 +340,7 @@ func GetFlagBool(cmd *cobra.Command, flag string) bool {
|
|||||||
func GetFlagInt(cmd *cobra.Command, flag string) int {
|
func GetFlagInt(cmd *cobra.Command, flag string) int {
|
||||||
i, err := cmd.Flags().GetInt(flag)
|
i, err := cmd.Flags().GetInt(flag)
|
||||||
if err != nil {
|
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
|
return i
|
||||||
}
|
}
|
||||||
@ -349,7 +349,7 @@ func GetFlagInt(cmd *cobra.Command, flag string) int {
|
|||||||
func GetFlagInt64(cmd *cobra.Command, flag string) int64 {
|
func GetFlagInt64(cmd *cobra.Command, flag string) int64 {
|
||||||
i, err := cmd.Flags().GetInt64(flag)
|
i, err := cmd.Flags().GetInt64(flag)
|
||||||
if err != nil {
|
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
|
return i
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ func GetFlagInt64(cmd *cobra.Command, flag string) int64 {
|
|||||||
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
|
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
|
||||||
d, err := cmd.Flags().GetDuration(flag)
|
d, err := cmd.Flags().GetDuration(flag)
|
||||||
if err != nil {
|
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
|
return d
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ type ServiceCommonGeneratorV1 struct {
|
|||||||
TCP []string
|
TCP []string
|
||||||
Type api.ServiceType
|
Type api.ServiceType
|
||||||
ClusterIP string
|
ClusterIP string
|
||||||
|
NodePort int
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceClusterIPGeneratorV1 struct {
|
type ServiceClusterIPGeneratorV1 struct {
|
||||||
@ -56,6 +57,7 @@ func (ServiceNodePortGeneratorV1) ParamNames() []GeneratorParam {
|
|||||||
return []GeneratorParam{
|
return []GeneratorParam{
|
||||||
{"name", true},
|
{"name", true},
|
||||||
{"tcp", true},
|
{"tcp", true},
|
||||||
|
{"nodeport", true},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (ServiceLoadBalancerGeneratorV1) ParamNames() []GeneratorParam {
|
func (ServiceLoadBalancerGeneratorV1) ParamNames() []GeneratorParam {
|
||||||
@ -174,12 +176,14 @@ func (s ServiceCommonGeneratorV1) StructuredGenerate() (runtime.Object, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
portName := strings.Replace(tcpString, ":", "-", -1)
|
portName := strings.Replace(tcpString, ":", "-", -1)
|
||||||
ports = append(ports, api.ServicePort{
|
ports = append(ports, api.ServicePort{
|
||||||
Name: portName,
|
Name: portName,
|
||||||
Port: port,
|
Port: port,
|
||||||
TargetPort: targetPort,
|
TargetPort: targetPort,
|
||||||
Protocol: api.Protocol("TCP"),
|
Protocol: api.Protocol("TCP"),
|
||||||
|
NodePort: int32(s.NodePort),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,11 +37,18 @@ type Interface interface {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrFull = errors.New("range is full")
|
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")
|
ErrAllocated = errors.New("provided port is already allocated")
|
||||||
ErrMismatchedNetwork = errors.New("the provided port range does not match the current port range")
|
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 {
|
type PortAllocator struct {
|
||||||
portRange net.PortRange
|
portRange net.PortRange
|
||||||
|
|
||||||
@ -82,7 +89,9 @@ func (r *PortAllocator) Free() int {
|
|||||||
func (r *PortAllocator) Allocate(port int) error {
|
func (r *PortAllocator) Allocate(port int) error {
|
||||||
ok, offset := r.contains(port)
|
ok, offset := r.contains(port)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNotInRange
|
// include valid port range in error
|
||||||
|
validPorts := r.portRange.String()
|
||||||
|
return &ErrNotInRange{validPorts}
|
||||||
}
|
}
|
||||||
|
|
||||||
allocated, err := r.alloc.Allocate(offset)
|
allocated, err := r.alloc.Allocate(offset)
|
||||||
|
@ -73,16 +73,23 @@ func TestAllocate(t *testing.T) {
|
|||||||
if err := r.Release(released); err != nil {
|
if err := r.Release(released); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := r.Allocate(1); err != ErrNotInRange {
|
|
||||||
|
err = r.Allocate(1)
|
||||||
|
if _, ok := err.(*ErrNotInRange); !ok {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.Allocate(10001); err != ErrAllocated {
|
if err := r.Allocate(10001); err != ErrAllocated {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := r.Allocate(20000); err != ErrNotInRange {
|
|
||||||
|
err = r.Allocate(20000)
|
||||||
|
if _, ok := err.(*ErrNotInRange); !ok {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := r.Allocate(10201); err != ErrNotInRange {
|
|
||||||
|
err = r.Allocate(10201)
|
||||||
|
if _, ok := err.(*ErrNotInRange); !ok {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if f := r.Free(); f != 1 {
|
if f := r.Free(); f != 1 {
|
||||||
|
@ -114,7 +114,7 @@ func (c *Repair) runOnce() error {
|
|||||||
// TODO: send event
|
// TODO: send event
|
||||||
// port is broken, reallocate
|
// 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))
|
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
|
// TODO: send event
|
||||||
// port is broken, reallocate
|
// 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))
|
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))
|
||||||
|
Loading…
Reference in New Issue
Block a user