mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 02:41:25 +00:00
Merge pull request #25826 from freehan/svcsourcerange
Automatic merge from submit-queue promote sourceRange into service spec @thockin one more for your pile I will add docs at `http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md` cc: @justinsb Fixes: #20392
This commit is contained in:
commit
a550cf16b9
@ -19175,6 +19175,13 @@
|
||||
"loadBalancerIP": {
|
||||
"type": "string",
|
||||
"description": "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature."
|
||||
},
|
||||
"loadBalancerSourceRanges": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the feature.\" More info: http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1320,7 +1320,7 @@ Examples:<br>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-05-02 18:47:14 UTC
|
||||
Last updated 2016-05-23 07:07:20 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -7770,6 +7770,13 @@ The resulting set of endpoints can be viewed as:<br>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">loadBalancerSourceRanges</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the feature." More info: <a href="http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md">http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -7984,7 +7991,7 @@ The resulting set of endpoints can be viewed as:<br>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-05-24 11:53:20 UTC
|
||||
Last updated 2016-05-26 18:58:49 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -3007,6 +3007,13 @@ func DeepCopy_api_ServiceSpec(in ServiceSpec, out *ServiceSpec, c *conversion.Cl
|
||||
}
|
||||
out.LoadBalancerIP = in.LoadBalancerIP
|
||||
out.SessionAffinity = in.SessionAffinity
|
||||
if in.LoadBalancerSourceRanges != nil {
|
||||
in, out := in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.LoadBalancerSourceRanges = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
||||
)
|
||||
|
||||
@ -37,18 +38,31 @@ func IsAllowAll(ipnets netsets.IPNet) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetLoadBalancerSourceRanges verifies and parses the AnnotationLoadBalancerSourceRangesKey annotation from a service,
|
||||
// GetLoadBalancerSourceRanges first try to parse and verify LoadBalancerSourceRanges field from a service.
|
||||
// If the field is not specified, turn to parse and verify the AnnotationLoadBalancerSourceRangesKey annotation from a service,
|
||||
// extracting the source ranges to allow, and if not present returns a default (allow-all) value.
|
||||
func GetLoadBalancerSourceRanges(annotations map[string]string) (netsets.IPNet, error) {
|
||||
val := annotations[AnnotationLoadBalancerSourceRangesKey]
|
||||
val = strings.TrimSpace(val)
|
||||
if val == "" {
|
||||
val = defaultLoadBalancerSourceRanges
|
||||
}
|
||||
specs := strings.Split(val, ",")
|
||||
ipnets, err := netsets.ParseIPNets(specs...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Service annotation %s:%s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", AnnotationLoadBalancerSourceRangesKey, val)
|
||||
func GetLoadBalancerSourceRanges(service *api.Service) (netsets.IPNet, error) {
|
||||
var ipnets netsets.IPNet
|
||||
var err error
|
||||
// if SourceRange field is specified, ignore sourceRange annotation
|
||||
if len(service.Spec.LoadBalancerSourceRanges) > 0 {
|
||||
specs := service.Spec.LoadBalancerSourceRanges
|
||||
ipnets, err = netsets.ParseIPNets(specs...)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("service.Spec.LoadBalancerSourceRanges: %v is not valid. Expecting a list of IP ranges. For example, 10.0.0.0/24. Error msg: %v", specs, err)
|
||||
}
|
||||
} else {
|
||||
val := service.Annotations[AnnotationLoadBalancerSourceRangesKey]
|
||||
val = strings.TrimSpace(val)
|
||||
if val == "" {
|
||||
val = defaultLoadBalancerSourceRanges
|
||||
}
|
||||
specs := strings.Split(val, ",")
|
||||
ipnets, err = netsets.ParseIPNets(specs...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", AnnotationLoadBalancerSourceRangesKey, val)
|
||||
}
|
||||
}
|
||||
return ipnets, nil
|
||||
}
|
||||
|
@ -19,14 +19,24 @@ package service
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TestGetLoadBalancerSourceRanges(t *testing.T) {
|
||||
checkError := func(v string) {
|
||||
annotations := make(map[string]string)
|
||||
annotations[AnnotationLoadBalancerSourceRangesKey] = v
|
||||
_, err := GetLoadBalancerSourceRanges(annotations)
|
||||
svc := api.Service{}
|
||||
svc.Annotations = annotations
|
||||
_, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error parsing: %q", v)
|
||||
}
|
||||
svc = api.Service{}
|
||||
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
|
||||
_, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error parsing: %q", v)
|
||||
}
|
||||
@ -41,7 +51,15 @@ func TestGetLoadBalancerSourceRanges(t *testing.T) {
|
||||
checkOK := func(v string) netsets.IPNet {
|
||||
annotations := make(map[string]string)
|
||||
annotations[AnnotationLoadBalancerSourceRangesKey] = v
|
||||
cidrs, err := GetLoadBalancerSourceRanges(annotations)
|
||||
svc := api.Service{}
|
||||
svc.Annotations = annotations
|
||||
cidrs, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing: %q", v)
|
||||
}
|
||||
svc = api.Service{}
|
||||
svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",")
|
||||
cidrs, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing: %q", v)
|
||||
}
|
||||
@ -63,7 +81,27 @@ func TestGetLoadBalancerSourceRanges(t *testing.T) {
|
||||
if len(cidrs) != 2 {
|
||||
t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice())
|
||||
}
|
||||
cidrs = checkOK("")
|
||||
// check LoadBalancerSourceRanges not specified
|
||||
svc := api.Service{}
|
||||
cidrs, err := GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
if !IsAllowAll(cidrs) {
|
||||
t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice())
|
||||
}
|
||||
// check SourceRanges annotation is empty
|
||||
annotations := make(map[string]string)
|
||||
annotations[AnnotationLoadBalancerSourceRangesKey] = ""
|
||||
svc = api.Service{}
|
||||
svc.Annotations = annotations
|
||||
cidrs, err = GetLoadBalancerSourceRanges(&svc)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if len(cidrs) != 1 {
|
||||
t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice())
|
||||
}
|
||||
|
@ -31819,7 +31819,7 @@ func (x *ServiceSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [7]bool
|
||||
var yyq2 [8]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[0] = x.Type != ""
|
||||
@ -31827,9 +31827,10 @@ func (x *ServiceSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
yyq2[4] = len(x.ExternalIPs) != 0
|
||||
yyq2[5] = x.LoadBalancerIP != ""
|
||||
yyq2[6] = x.SessionAffinity != ""
|
||||
yyq2[7] = len(x.LoadBalancerSourceRanges) != 0
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(7)
|
||||
r.EncodeArrayStart(8)
|
||||
} else {
|
||||
yynn2 = 2
|
||||
for _, b := range yyq2 {
|
||||
@ -32007,6 +32008,39 @@ func (x *ServiceSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
x.SessionAffinity.CodecEncodeSelf(e)
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[7] {
|
||||
if x.LoadBalancerSourceRanges == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym25 := z.EncBinary()
|
||||
_ = yym25
|
||||
if false {
|
||||
} else {
|
||||
z.F.EncSliceStringV(x.LoadBalancerSourceRanges, false, e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.EncodeNil()
|
||||
}
|
||||
} else {
|
||||
if yyq2[7] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("loadBalancerSourceRanges"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
if x.LoadBalancerSourceRanges == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym26 := z.EncBinary()
|
||||
_ = yym26
|
||||
if false {
|
||||
} else {
|
||||
z.F.EncSliceStringV(x.LoadBalancerSourceRanges, false, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
@ -32128,6 +32162,18 @@ func (x *ServiceSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.SessionAffinity = ServiceAffinity(r.DecodeString())
|
||||
}
|
||||
case "loadBalancerSourceRanges":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.LoadBalancerSourceRanges = nil
|
||||
} else {
|
||||
yyv14 := &x.LoadBalancerSourceRanges
|
||||
yym15 := z.DecBinary()
|
||||
_ = yym15
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecSliceStringX(yyv14, false, d)
|
||||
}
|
||||
}
|
||||
default:
|
||||
z.DecStructFieldNotFound(-1, yys3)
|
||||
} // end switch yys3
|
||||
@ -32139,16 +32185,16 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj14 int
|
||||
var yyb14 bool
|
||||
var yyhl14 bool = l >= 0
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
var yyj16 int
|
||||
var yyb16 bool
|
||||
var yyhl16 bool = l >= 0
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb14 {
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -32158,13 +32204,13 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.Type = ServiceType(r.DecodeString())
|
||||
}
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb14 {
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -32172,21 +32218,21 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Ports = nil
|
||||
} else {
|
||||
yyv16 := &x.Ports
|
||||
yym17 := z.DecBinary()
|
||||
_ = yym17
|
||||
yyv18 := &x.Ports
|
||||
yym19 := z.DecBinary()
|
||||
_ = yym19
|
||||
if false {
|
||||
} else {
|
||||
h.decSliceServicePort((*[]ServicePort)(yyv16), d)
|
||||
h.decSliceServicePort((*[]ServicePort)(yyv18), d)
|
||||
}
|
||||
}
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb14 {
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -32194,21 +32240,21 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Selector = nil
|
||||
} else {
|
||||
yyv18 := &x.Selector
|
||||
yym19 := z.DecBinary()
|
||||
_ = yym19
|
||||
yyv20 := &x.Selector
|
||||
yym21 := z.DecBinary()
|
||||
_ = yym21
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecMapStringStringX(yyv18, false, d)
|
||||
z.F.DecMapStringStringX(yyv20, false, d)
|
||||
}
|
||||
}
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb14 {
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -32218,13 +32264,13 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.ClusterIP = string(r.DecodeString())
|
||||
}
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb14 {
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -32232,21 +32278,21 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
if r.TryDecodeAsNil() {
|
||||
x.ExternalIPs = nil
|
||||
} else {
|
||||
yyv21 := &x.ExternalIPs
|
||||
yym22 := z.DecBinary()
|
||||
_ = yym22
|
||||
yyv23 := &x.ExternalIPs
|
||||
yym24 := z.DecBinary()
|
||||
_ = yym24
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecSliceStringX(yyv21, false, d)
|
||||
z.F.DecSliceStringX(yyv23, false, d)
|
||||
}
|
||||
}
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb14 {
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -32256,13 +32302,13 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.LoadBalancerIP = string(r.DecodeString())
|
||||
}
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb14 {
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -32272,18 +32318,40 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.SessionAffinity = ServiceAffinity(r.DecodeString())
|
||||
}
|
||||
for {
|
||||
yyj14++
|
||||
if yyhl14 {
|
||||
yyb14 = yyj14 > l
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.LoadBalancerSourceRanges = nil
|
||||
} else {
|
||||
yyv27 := &x.LoadBalancerSourceRanges
|
||||
yym28 := z.DecBinary()
|
||||
_ = yym28
|
||||
if false {
|
||||
} else {
|
||||
yyb14 = r.CheckBreak()
|
||||
z.F.DecSliceStringX(yyv27, false, d)
|
||||
}
|
||||
if yyb14 {
|
||||
}
|
||||
for {
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj14-1, "")
|
||||
z.DecStructFieldNotFound(yyj16-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
@ -55630,7 +55698,7 @@ func (x codecSelfer1234) decSliceService(v *[]Service, d *codec1978.Decoder) {
|
||||
|
||||
yyrg1 := len(yyv1) > 0
|
||||
yyv21 := yyv1
|
||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 384)
|
||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 408)
|
||||
if yyrt1 {
|
||||
if yyrl1 <= cap(yyv1) {
|
||||
yyv1 = yyv1[:yyrl1]
|
||||
|
@ -1751,8 +1751,13 @@ type ServiceSpec struct {
|
||||
// This field will be ignored if the cloud-provider does not support the feature.
|
||||
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
|
||||
|
||||
// Required: Supports "ClientIP" and "None". Used to maintain session affinity.
|
||||
// Optional: Supports "ClientIP" and "None". Used to maintain session affinity.
|
||||
SessionAffinity ServiceAffinity `json:"sessionAffinity,omitempty"`
|
||||
|
||||
// Optional: If specified and supported by the platform, this will restrict traffic through the cloud-provider
|
||||
// load-balancer will be restricted to the specified client IPs. This field will be ignored if the
|
||||
// cloud-provider does not support the feature."
|
||||
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"`
|
||||
}
|
||||
|
||||
type ServicePort struct {
|
||||
|
@ -6588,6 +6588,13 @@ func autoConvert_v1_ServiceSpec_To_api_ServiceSpec(in *ServiceSpec, out *api.Ser
|
||||
}
|
||||
out.SessionAffinity = api.ServiceAffinity(in.SessionAffinity)
|
||||
out.LoadBalancerIP = in.LoadBalancerIP
|
||||
if in.LoadBalancerSourceRanges != nil {
|
||||
in, out := &in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
} else {
|
||||
out.LoadBalancerSourceRanges = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -6623,6 +6630,13 @@ func autoConvert_api_ServiceSpec_To_v1_ServiceSpec(in *api.ServiceSpec, out *Ser
|
||||
}
|
||||
out.LoadBalancerIP = in.LoadBalancerIP
|
||||
out.SessionAffinity = ServiceAffinity(in.SessionAffinity)
|
||||
if in.LoadBalancerSourceRanges != nil {
|
||||
in, out := &in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
} else {
|
||||
out.LoadBalancerSourceRanges = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -2968,6 +2968,13 @@ func DeepCopy_v1_ServiceSpec(in ServiceSpec, out *ServiceSpec, c *conversion.Clo
|
||||
}
|
||||
out.SessionAffinity = in.SessionAffinity
|
||||
out.LoadBalancerIP = in.LoadBalancerIP
|
||||
if in.LoadBalancerSourceRanges != nil {
|
||||
in, out := in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.LoadBalancerSourceRanges = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -7158,6 +7158,21 @@ func (m *ServiceSpec) MarshalTo(data []byte) (int, error) {
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.LoadBalancerIP)))
|
||||
i += copy(data[i:], m.LoadBalancerIP)
|
||||
if len(m.LoadBalancerSourceRanges) > 0 {
|
||||
for _, s := range m.LoadBalancerSourceRanges {
|
||||
data[i] = 0x4a
|
||||
i++
|
||||
l = len(s)
|
||||
for l >= 1<<7 {
|
||||
data[i] = uint8(uint64(l)&0x7f | 0x80)
|
||||
l >>= 7
|
||||
i++
|
||||
}
|
||||
data[i] = uint8(l)
|
||||
i++
|
||||
i += copy(data[i:], s)
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@ -9941,6 +9956,12 @@ func (m *ServiceSpec) Size() (n int) {
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = len(m.LoadBalancerIP)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
if len(m.LoadBalancerSourceRanges) > 0 {
|
||||
for _, s := range m.LoadBalancerSourceRanges {
|
||||
l = len(s)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@ -32508,6 +32529,35 @@ func (m *ServiceSpec) Unmarshal(data []byte) error {
|
||||
}
|
||||
m.LoadBalancerIP = string(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 9:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LoadBalancerSourceRanges", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.LoadBalancerSourceRanges = append(m.LoadBalancerSourceRanges, string(data[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(data[iNdEx:])
|
||||
|
@ -2701,6 +2701,12 @@ message ServiceSpec {
|
||||
// the loadBalancerIP when a load balancer is created.
|
||||
// This field will be ignored if the cloud-provider does not support the feature.
|
||||
optional string loadBalancerIP = 8;
|
||||
|
||||
// If specified and supported by the platform, this will restrict traffic through the cloud-provider
|
||||
// load-balancer will be restricted to the specified client IPs. This field will be ignored if the
|
||||
// cloud-provider does not support the feature."
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md
|
||||
repeated string loadBalancerSourceRanges = 9;
|
||||
}
|
||||
|
||||
// ServiceStatus represents the current status of a service.
|
||||
|
@ -31128,7 +31128,7 @@ func (x *ServiceSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [8]bool
|
||||
var yyq2 [9]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[1] = len(x.Selector) != 0
|
||||
@ -31138,9 +31138,10 @@ func (x *ServiceSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
yyq2[5] = len(x.DeprecatedPublicIPs) != 0
|
||||
yyq2[6] = x.SessionAffinity != ""
|
||||
yyq2[7] = x.LoadBalancerIP != ""
|
||||
yyq2[8] = len(x.LoadBalancerSourceRanges) != 0
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(8)
|
||||
r.EncodeArrayStart(9)
|
||||
} else {
|
||||
yynn2 = 1
|
||||
for _, b := range yyq2 {
|
||||
@ -31357,6 +31358,39 @@ func (x *ServiceSpec) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[8] {
|
||||
if x.LoadBalancerSourceRanges == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym28 := z.EncBinary()
|
||||
_ = yym28
|
||||
if false {
|
||||
} else {
|
||||
z.F.EncSliceStringV(x.LoadBalancerSourceRanges, false, e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.EncodeNil()
|
||||
}
|
||||
} else {
|
||||
if yyq2[8] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("loadBalancerSourceRanges"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
if x.LoadBalancerSourceRanges == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
yym29 := z.EncBinary()
|
||||
_ = yym29
|
||||
if false {
|
||||
} else {
|
||||
z.F.EncSliceStringV(x.LoadBalancerSourceRanges, false, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
@ -31490,6 +31524,18 @@ func (x *ServiceSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.LoadBalancerIP = string(r.DecodeString())
|
||||
}
|
||||
case "loadBalancerSourceRanges":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.LoadBalancerSourceRanges = nil
|
||||
} else {
|
||||
yyv16 := &x.LoadBalancerSourceRanges
|
||||
yym17 := z.DecBinary()
|
||||
_ = yym17
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecSliceStringX(yyv16, false, d)
|
||||
}
|
||||
}
|
||||
default:
|
||||
z.DecStructFieldNotFound(-1, yys3)
|
||||
} // end switch yys3
|
||||
@ -31501,16 +31547,16 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj16 int
|
||||
var yyb16 bool
|
||||
var yyhl16 bool = l >= 0
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
var yyj18 int
|
||||
var yyb18 bool
|
||||
var yyhl18 bool = l >= 0
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -31518,21 +31564,21 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Ports = nil
|
||||
} else {
|
||||
yyv17 := &x.Ports
|
||||
yym18 := z.DecBinary()
|
||||
_ = yym18
|
||||
yyv19 := &x.Ports
|
||||
yym20 := z.DecBinary()
|
||||
_ = yym20
|
||||
if false {
|
||||
} else {
|
||||
h.decSliceServicePort((*[]ServicePort)(yyv17), d)
|
||||
h.decSliceServicePort((*[]ServicePort)(yyv19), d)
|
||||
}
|
||||
}
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -31540,21 +31586,21 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Selector = nil
|
||||
} else {
|
||||
yyv19 := &x.Selector
|
||||
yym20 := z.DecBinary()
|
||||
_ = yym20
|
||||
yyv21 := &x.Selector
|
||||
yym22 := z.DecBinary()
|
||||
_ = yym22
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecMapStringStringX(yyv19, false, d)
|
||||
z.F.DecMapStringStringX(yyv21, false, d)
|
||||
}
|
||||
}
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -31564,13 +31610,13 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.ClusterIP = string(r.DecodeString())
|
||||
}
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -31580,13 +31626,13 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.Type = ServiceType(r.DecodeString())
|
||||
}
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -31594,29 +31640,7 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
if r.TryDecodeAsNil() {
|
||||
x.ExternalIPs = nil
|
||||
} else {
|
||||
yyv23 := &x.ExternalIPs
|
||||
yym24 := z.DecBinary()
|
||||
_ = yym24
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecSliceStringX(yyv23, false, d)
|
||||
}
|
||||
}
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.DeprecatedPublicIPs = nil
|
||||
} else {
|
||||
yyv25 := &x.DeprecatedPublicIPs
|
||||
yyv25 := &x.ExternalIPs
|
||||
yym26 := z.DecBinary()
|
||||
_ = yym26
|
||||
if false {
|
||||
@ -31624,13 +31648,35 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
z.F.DecSliceStringX(yyv25, false, d)
|
||||
}
|
||||
}
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.DeprecatedPublicIPs = nil
|
||||
} else {
|
||||
yyv27 := &x.DeprecatedPublicIPs
|
||||
yym28 := z.DecBinary()
|
||||
_ = yym28
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecSliceStringX(yyv27, false, d)
|
||||
}
|
||||
}
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -31640,13 +31686,13 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.SessionAffinity = ServiceAffinity(r.DecodeString())
|
||||
}
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb16 {
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
@ -31656,18 +31702,40 @@ func (x *ServiceSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
||||
} else {
|
||||
x.LoadBalancerIP = string(r.DecodeString())
|
||||
}
|
||||
for {
|
||||
yyj16++
|
||||
if yyhl16 {
|
||||
yyb16 = yyj16 > l
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb18 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.LoadBalancerSourceRanges = nil
|
||||
} else {
|
||||
yyv31 := &x.LoadBalancerSourceRanges
|
||||
yym32 := z.DecBinary()
|
||||
_ = yym32
|
||||
if false {
|
||||
} else {
|
||||
yyb16 = r.CheckBreak()
|
||||
z.F.DecSliceStringX(yyv31, false, d)
|
||||
}
|
||||
if yyb16 {
|
||||
}
|
||||
for {
|
||||
yyj18++
|
||||
if yyhl18 {
|
||||
yyb18 = yyj18 > l
|
||||
} else {
|
||||
yyb18 = r.CheckBreak()
|
||||
}
|
||||
if yyb18 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj16-1, "")
|
||||
z.DecStructFieldNotFound(yyj18-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
@ -55921,7 +55989,7 @@ func (x codecSelfer1234) decSliceService(v *[]Service, d *codec1978.Decoder) {
|
||||
|
||||
yyrg1 := len(yyv1) > 0
|
||||
yyv21 := yyv1
|
||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 408)
|
||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 432)
|
||||
if yyrt1 {
|
||||
if yyrl1 <= cap(yyv1) {
|
||||
yyv1 = yyv1[:yyrl1]
|
||||
|
@ -2092,6 +2092,12 @@ type ServiceSpec struct {
|
||||
// the loadBalancerIP when a load balancer is created.
|
||||
// This field will be ignored if the cloud-provider does not support the feature.
|
||||
LoadBalancerIP string `json:"loadBalancerIP,omitempty" protobuf:"bytes,8,opt,name=loadBalancerIP"`
|
||||
|
||||
// If specified and supported by the platform, this will restrict traffic through the cloud-provider
|
||||
// load-balancer will be restricted to the specified client IPs. This field will be ignored if the
|
||||
// cloud-provider does not support the feature."
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md
|
||||
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty" protobuf:"bytes,9,opt,name=loadBalancerSourceRanges"`
|
||||
}
|
||||
|
||||
// ServicePort contains information on service's port.
|
||||
|
@ -1598,15 +1598,16 @@ func (ServiceProxyOptions) SwaggerDoc() map[string]string {
|
||||
}
|
||||
|
||||
var map_ServiceSpec = map[string]string{
|
||||
"": "ServiceSpec describes the attributes that a user creates on a service.",
|
||||
"ports": "The list of ports that are exposed by this service. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"selector": "This service will route traffic to pods having labels matching this selector. Label keys and values that must match in order to receive traffic for this service. If empty, all pods are selected, if not specified, endpoints must be manually specified. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#overview",
|
||||
"clusterIP": "ClusterIP is usually assigned by the master and is the IP address of the service. If specified, it will be allocated to the service if it is unused or else creation of the service will fail. Valid values are None, empty string (\"\"), or a valid IP address. 'None' can be specified for a headless service when proxying is not required. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"type": "Type of exposed service. Must be ClusterIP, NodePort, or LoadBalancer. Defaults to ClusterIP. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#external-services",
|
||||
"externalIPs": "externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. A previous form of this functionality exists as the deprecatedPublicIPs field. When using this field, callers should also clear the deprecatedPublicIPs field.",
|
||||
"deprecatedPublicIPs": "deprecatedPublicIPs is deprecated and replaced by the externalIPs field with almost the exact same semantics. This field is retained in the v1 API for compatibility until at least 8/20/2016. It will be removed from any new API revisions. If both deprecatedPublicIPs *and* externalIPs are set, deprecatedPublicIPs is used.",
|
||||
"sessionAffinity": "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"loadBalancerIP": "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature.",
|
||||
"": "ServiceSpec describes the attributes that a user creates on a service.",
|
||||
"ports": "The list of ports that are exposed by this service. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"selector": "This service will route traffic to pods having labels matching this selector. Label keys and values that must match in order to receive traffic for this service. If empty, all pods are selected, if not specified, endpoints must be manually specified. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#overview",
|
||||
"clusterIP": "ClusterIP is usually assigned by the master and is the IP address of the service. If specified, it will be allocated to the service if it is unused or else creation of the service will fail. Valid values are None, empty string (\"\"), or a valid IP address. 'None' can be specified for a headless service when proxying is not required. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"type": "Type of exposed service. Must be ClusterIP, NodePort, or LoadBalancer. Defaults to ClusterIP. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#external-services",
|
||||
"externalIPs": "externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. A previous form of this functionality exists as the deprecatedPublicIPs field. When using this field, callers should also clear the deprecatedPublicIPs field.",
|
||||
"deprecatedPublicIPs": "deprecatedPublicIPs is deprecated and replaced by the externalIPs field with almost the exact same semantics. This field is retained in the v1 API for compatibility until at least 8/20/2016. It will be removed from any new API revisions. If both deprecatedPublicIPs *and* externalIPs are set, deprecatedPublicIPs is used.",
|
||||
"sessionAffinity": "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"loadBalancerIP": "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature.",
|
||||
"loadBalancerSourceRanges": "If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. This field will be ignored if the cloud-provider does not support the feature.\" More info: http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md",
|
||||
}
|
||||
|
||||
func (ServiceSpec) SwaggerDoc() map[string]string {
|
||||
|
@ -2080,12 +2080,26 @@ func ValidateService(service *api.Service) field.ErrorList {
|
||||
nodePorts[key] = true
|
||||
}
|
||||
|
||||
_, err := apiservice.GetLoadBalancerSourceRanges(service.Annotations)
|
||||
if err != nil {
|
||||
v := service.Annotations[apiservice.AnnotationLoadBalancerSourceRangesKey]
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata", "annotations").Key(apiservice.AnnotationLoadBalancerSourceRangesKey), v, "must be a comma separated list of CIDRs e.g. 192.168.0.0/16,10.0.0.0/8"))
|
||||
// Validate SourceRange field and annotation
|
||||
_, ok := service.Annotations[apiservice.AnnotationLoadBalancerSourceRangesKey]
|
||||
if len(service.Spec.LoadBalancerSourceRanges) > 0 || ok {
|
||||
var fieldPath *field.Path
|
||||
var val string
|
||||
if len(service.Spec.LoadBalancerSourceRanges) > 0 {
|
||||
fieldPath = specPath.Child("LoadBalancerSourceRanges")
|
||||
val = fmt.Sprintf("%v", service.Spec.LoadBalancerSourceRanges)
|
||||
} else {
|
||||
fieldPath = field.NewPath("metadata", "annotations").Key(apiservice.AnnotationLoadBalancerSourceRangesKey)
|
||||
val = service.Annotations[apiservice.AnnotationLoadBalancerSourceRangesKey]
|
||||
}
|
||||
if service.Spec.Type != api.ServiceTypeLoadBalancer {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, "", "may only be used when `type` is 'LoadBalancer'"))
|
||||
}
|
||||
_, err := apiservice.GetLoadBalancerSourceRanges(service)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, val, "must be a list of IP ranges. For example, 10.240.0.0/24,10.250.0.0/24 "))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@ -3472,6 +3472,7 @@ func TestValidateService(t *testing.T) {
|
||||
{
|
||||
name: "valid LoadBalancer source range annotation",
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
s.Annotations[service.AnnotationLoadBalancerSourceRangesKey] = "1.2.3.4/8, 5.6.7.8/16"
|
||||
},
|
||||
numErrs: 0,
|
||||
@ -3479,6 +3480,7 @@ func TestValidateService(t *testing.T) {
|
||||
{
|
||||
name: "empty LoadBalancer source range annotation",
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
s.Annotations[service.AnnotationLoadBalancerSourceRangesKey] = ""
|
||||
},
|
||||
numErrs: 0,
|
||||
@ -3488,15 +3490,47 @@ func TestValidateService(t *testing.T) {
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Annotations[service.AnnotationLoadBalancerSourceRangesKey] = "foo.bar"
|
||||
},
|
||||
numErrs: 1,
|
||||
numErrs: 2,
|
||||
},
|
||||
{
|
||||
name: "invalid LoadBalancer source range annotation (invalid CIDR)",
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
s.Annotations[service.AnnotationLoadBalancerSourceRangesKey] = "1.2.3.4/33"
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "invalid source range for non LoadBalancer type service",
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Spec.LoadBalancerSourceRanges = []string{"1.2.3.4/8", "5.6.7.8/16"}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "valid LoadBalancer source range",
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
s.Spec.LoadBalancerSourceRanges = []string{"1.2.3.4/8", "5.6.7.8/16"}
|
||||
},
|
||||
numErrs: 0,
|
||||
},
|
||||
{
|
||||
name: "empty LoadBalancer source range",
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
s.Spec.LoadBalancerSourceRanges = []string{" "}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "invalid LoadBalancer source range",
|
||||
tweakSvc: func(s *api.Service) {
|
||||
s.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
s.Spec.LoadBalancerSourceRanges = []string{"foo.bar"}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
@ -84,7 +84,7 @@ type LoadBalancer interface {
|
||||
GetLoadBalancer(service *api.Service) (status *api.LoadBalancerStatus, exists bool, err error)
|
||||
// EnsureLoadBalancer creates a new load balancer 'name', or updates the existing one. Returns the status of the balancer
|
||||
// Implementations must treat the *api.Service parameter as read-only and not modify it.
|
||||
EnsureLoadBalancer(service *api.Service, hosts []string, annotations map[string]string) (*api.LoadBalancerStatus, error)
|
||||
EnsureLoadBalancer(service *api.Service, hosts []string) (*api.LoadBalancerStatus, error)
|
||||
// UpdateLoadBalancer updates hosts under the specified load balancer.
|
||||
// Implementations must treat the *api.Service parameter as read-only and not modify it.
|
||||
UpdateLoadBalancer(service *api.Service, hosts []string) error
|
||||
|
@ -2120,9 +2120,9 @@ func buildListener(port api.ServicePort, annotations map[string]string) (*elb.Li
|
||||
}
|
||||
|
||||
// EnsureLoadBalancer implements LoadBalancer.EnsureLoadBalancer
|
||||
func (s *AWSCloud) EnsureLoadBalancer(apiService *api.Service, hosts []string, annotations map[string]string) (*api.LoadBalancerStatus, error) {
|
||||
func (s *AWSCloud) EnsureLoadBalancer(apiService *api.Service, hosts []string) (*api.LoadBalancerStatus, error) {
|
||||
glog.V(2).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)",
|
||||
apiService.Namespace, apiService.Name, s.region, apiService.Spec.LoadBalancerIP, apiService.Spec.Ports, hosts, annotations)
|
||||
apiService.Namespace, apiService.Name, s.region, apiService.Spec.LoadBalancerIP, apiService.Spec.Ports, hosts, apiService.Annotations)
|
||||
|
||||
if apiService.Spec.SessionAffinity != api.ServiceAffinityNone {
|
||||
// ELB supports sticky sessions, but only when configured for HTTP/HTTPS
|
||||
@ -2143,7 +2143,7 @@ func (s *AWSCloud) EnsureLoadBalancer(apiService *api.Service, hosts []string, a
|
||||
glog.Errorf("Ignoring port without NodePort defined: %v", port)
|
||||
continue
|
||||
}
|
||||
listener, err := buildListener(port, annotations)
|
||||
listener, err := buildListener(port, apiService.Annotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -2159,14 +2159,14 @@ func (s *AWSCloud) EnsureLoadBalancer(apiService *api.Service, hosts []string, a
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sourceRanges, err := service.GetLoadBalancerSourceRanges(annotations)
|
||||
sourceRanges, err := service.GetLoadBalancerSourceRanges(apiService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Determine if this is tagged as an Internal ELB
|
||||
internalELB := false
|
||||
internalAnnotation := annotations[ServiceAnnotationLoadBalancerInternal]
|
||||
internalAnnotation := apiService.Annotations[ServiceAnnotationLoadBalancerInternal]
|
||||
if internalAnnotation != "" {
|
||||
if internalAnnotation != "0.0.0.0/0" {
|
||||
return nil, fmt.Errorf("annotation %q=%q detected, but the only value supported currently is 0.0.0.0/0", ServiceAnnotationLoadBalancerInternal, internalAnnotation)
|
||||
|
@ -1197,7 +1197,7 @@ func TestDescribeLoadBalancerOnEnsure(t *testing.T) {
|
||||
c, _ := newAWSCloud(strings.NewReader("[global]"), awsServices)
|
||||
awsServices.elb.expectDescribeLoadBalancers("aid")
|
||||
|
||||
c.EnsureLoadBalancer(&api.Service{ObjectMeta: api.ObjectMeta{Name: "myservice", UID: "id"}}, []string{}, map[string]string{})
|
||||
c.EnsureLoadBalancer(&api.Service{ObjectMeta: api.ObjectMeta{Name: "myservice", UID: "id"}}, []string{})
|
||||
}
|
||||
|
||||
func TestBuildListener(t *testing.T) {
|
||||
|
@ -130,7 +130,7 @@ func (f *FakeCloud) GetLoadBalancer(service *api.Service) (*api.LoadBalancerStat
|
||||
|
||||
// EnsureLoadBalancer is a test-spy implementation of LoadBalancer.EnsureLoadBalancer.
|
||||
// It adds an entry "create" into the internal method call record.
|
||||
func (f *FakeCloud) EnsureLoadBalancer(service *api.Service, hosts []string, annotations map[string]string) (*api.LoadBalancerStatus, error) {
|
||||
func (f *FakeCloud) EnsureLoadBalancer(service *api.Service, hosts []string) (*api.LoadBalancerStatus, error) {
|
||||
f.addCall("create")
|
||||
if f.Balancers == nil {
|
||||
f.Balancers = make(map[string]FakeBalancer)
|
||||
|
@ -480,7 +480,7 @@ func isHTTPErrorCode(err error, code int) bool {
|
||||
// Due to an interesting series of design decisions, this handles both creating
|
||||
// new load balancers and updating existing load balancers, recognizing when
|
||||
// each is needed.
|
||||
func (gce *GCECloud) EnsureLoadBalancer(apiService *api.Service, hostNames []string, annotations map[string]string) (*api.LoadBalancerStatus, error) {
|
||||
func (gce *GCECloud) EnsureLoadBalancer(apiService *api.Service, hostNames []string) (*api.LoadBalancerStatus, error) {
|
||||
if len(hostNames) == 0 {
|
||||
return nil, fmt.Errorf("Cannot EnsureLoadBalancer() with no hosts")
|
||||
}
|
||||
@ -501,7 +501,7 @@ func (gce *GCECloud) EnsureLoadBalancer(apiService *api.Service, hostNames []str
|
||||
affinityType := apiService.Spec.SessionAffinity
|
||||
|
||||
serviceName := types.NamespacedName{Namespace: apiService.Namespace, Name: apiService.Name}
|
||||
glog.V(2).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)", loadBalancerName, gce.region, loadBalancerIP, portStr, hosts, serviceName, annotations)
|
||||
glog.V(2).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)", loadBalancerName, gce.region, loadBalancerIP, portStr, hosts, serviceName, apiService.Annotations)
|
||||
|
||||
// Check if the forwarding rule exists, and if so, what its IP is.
|
||||
fwdRuleExists, fwdRuleNeedsUpdate, fwdRuleIP, err := gce.forwardingRuleNeedsUpdate(loadBalancerName, gce.region, loadBalancerIP, ports)
|
||||
@ -611,7 +611,7 @@ func (gce *GCECloud) EnsureLoadBalancer(apiService *api.Service, hostNames []str
|
||||
// is because the forwarding rule is used as the indicator that the load
|
||||
// balancer is fully created - it's what getLoadBalancer checks for.
|
||||
// Check if user specified the allow source range
|
||||
sourceRanges, err := service.GetLoadBalancerSourceRanges(annotations)
|
||||
sourceRanges, err := service.GetLoadBalancerSourceRanges(apiService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -666,8 +666,8 @@ func (lb *LoadBalancer) GetLoadBalancer(service *api.Service) (*api.LoadBalancer
|
||||
// a list of regions (from config) and query/create loadbalancers in
|
||||
// each region.
|
||||
|
||||
func (lb *LoadBalancer) EnsureLoadBalancer(apiService *api.Service, hosts []string, annotations map[string]string) (*api.LoadBalancerStatus, error) {
|
||||
glog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v)", apiService.Namespace, apiService.Name, apiService.Spec.LoadBalancerIP, apiService.Spec.Ports, hosts, annotations)
|
||||
func (lb *LoadBalancer) EnsureLoadBalancer(apiService *api.Service, hosts []string) (*api.LoadBalancerStatus, error) {
|
||||
glog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v)", apiService.Namespace, apiService.Name, apiService.Spec.LoadBalancerIP, apiService.Spec.Ports, hosts, apiService.Annotations)
|
||||
|
||||
ports := apiService.Spec.Ports
|
||||
if len(ports) > 1 {
|
||||
@ -693,7 +693,7 @@ func (lb *LoadBalancer) EnsureLoadBalancer(apiService *api.Service, hosts []stri
|
||||
return nil, fmt.Errorf("unsupported load balancer affinity: %v", affinity)
|
||||
}
|
||||
|
||||
sourceRanges, err := service.GetLoadBalancerSourceRanges(annotations)
|
||||
sourceRanges, err := service.GetLoadBalancerSourceRanges(apiService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ func (s *ServiceController) createLoadBalancer(service *api.Service) error {
|
||||
// - Only one protocol supported per service
|
||||
// - Not all cloud providers support all protocols and the next step is expected to return
|
||||
// an error for unsupported protocols
|
||||
status, err := s.balancer.EnsureLoadBalancer(service, hostsFromNodeList(&nodes), service.ObjectMeta.Annotations)
|
||||
status, err := s.balancer.EnsureLoadBalancer(service, hostsFromNodeList(&nodes))
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/service"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
@ -167,6 +168,18 @@ See http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md for more d
|
||||
makePortsString(obj.Spec.Ports, true))
|
||||
out.Write([]byte(msg))
|
||||
}
|
||||
|
||||
_, ok := obj.Annotations[service.AnnotationLoadBalancerSourceRangesKey]
|
||||
if ok {
|
||||
msg := fmt.Sprintf(
|
||||
`You are using service annotation [service.beta.kubernetes.io/load-balancer-source-ranges].
|
||||
It has been promoted to field [loadBalancerSourceRanges] in service spec. This annotation will be deprecated in the future.
|
||||
Please use the loadBalancerSourceRanges field instead.
|
||||
|
||||
See http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md for more details.
|
||||
`)
|
||||
out.Write([]byte(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user