dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
/ *
Copyright 2020 The Kubernetes Authors .
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 dualstack
import (
"context"
2020-10-29 14:03:30 -04:00
"encoding/json"
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
"fmt"
"net"
"reflect"
"strings"
"testing"
"time"
2020-10-29 14:03:30 -04:00
jsonpatch "github.com/evanphx/json-patch"
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020-10-29 14:03:30 -04:00
"k8s.io/apimachinery/pkg/types"
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/test/integration/framework"
netutils "k8s.io/utils/net"
)
// TestCreateServiceSingleStackIPv4 test the Service dualstackness in an IPv4 SingleStack cluster
func TestCreateServiceSingleStackIPv4 ( t * testing . T ) {
// Create an IPv4 single stack control-plane
serviceCIDR := "10.0.0.0/16"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
var testcases = [ ] struct {
name string
serviceType v1 . ServiceType
clusterIPs [ ] string
ipFamilies [ ] v1 . IPFamily
ipFamilyPolicy v1 . IPFamilyPolicyType
expectedIPFamilies [ ] v1 . IPFamily
expectError bool
} {
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : nil ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : nil ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : nil ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectError : true ,
} ,
}
for i , tc := range testcases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "svc-test-%d" , i ) , // use different services for each test
} ,
Spec : v1 . ServiceSpec {
Type : tc . serviceType ,
ClusterIPs : tc . clusterIPs ,
IPFamilies : tc . ipFamilies ,
IPFamilyPolicy : & tc . ipFamilyPolicy ,
Ports : [ ] v1 . ServicePort {
{
Port : 443 ,
TargetPort : intstr . FromInt ( 443 ) ,
} ,
} ,
} ,
}
// create the service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if ( err != nil ) != tc . expectError {
t . Errorf ( "Test failed expected result: %v received %v " , tc . expectError , err )
}
// if no error was expected validate the service otherwise return
if err != nil {
return
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Errorf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , tc . expectedIPFamilies ) ; err != nil {
t . Errorf ( "Unexpected error validating the service %s\n%+v\n%v" , svc . Name , svc , err )
}
} )
}
}
// TestCreateServiceDualStackIPv6 test the Service dualstackness in an IPv6 only DualStack cluster
func TestCreateServiceDualStackIPv6 ( t * testing . T ) {
// Create an IPv6 only dual stack control-plane
serviceCIDR := "2001:db8:1::/48"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
var testcases = [ ] struct {
name string
serviceType v1 . ServiceType
clusterIPs [ ] string
ipFamilies [ ] v1 . IPFamily
expectedIPFamilies [ ] v1 . IPFamily
ipFamilyPolicy v1 . IPFamilyPolicyType
expectError bool
} {
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : true ,
} ,
}
for i , tc := range testcases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "svc-test-%d" , i ) , // use different services for each test
} ,
Spec : v1 . ServiceSpec {
Type : tc . serviceType ,
ClusterIPs : tc . clusterIPs ,
IPFamilies : tc . ipFamilies ,
IPFamilyPolicy : & tc . ipFamilyPolicy ,
Ports : [ ] v1 . ServicePort {
{
Name : fmt . Sprintf ( "port-test-%d" , i ) ,
Port : 443 ,
TargetPort : intstr . IntOrString { IntVal : 443 } ,
Protocol : "TCP" ,
} ,
} ,
} ,
}
// create the service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if ( err != nil ) != tc . expectError {
t . Errorf ( "Test failed expected result: %v received %v " , tc . expectError , err )
}
// if no error was expected validate the service otherwise return
if err != nil {
return
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Errorf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , tc . expectedIPFamilies ) ; err != nil {
t . Errorf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
} )
}
}
// TestCreateServiceDualStackIPv4IPv6 test the Service dualstackness in a IPv4IPv6 DualStack cluster
func TestCreateServiceDualStackIPv4IPv6 ( t * testing . T ) {
// Create an IPv4IPv6 dual stack control-plane
serviceCIDR := "10.0.0.0/16"
secondaryServiceCIDR := "2001:db8:1::/48"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-08-19 19:16:14 -04:00
_ , secCidr , err := netutils . ParseCIDRSloppy ( secondaryServiceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . SecondaryServiceIPRange = * secCidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
var testcases = [ ] struct {
name string
serviceType v1 . ServiceType
clusterIPs [ ] string
ipFamilies [ ] v1 . IPFamily
expectedIPFamilies [ ] v1 . IPFamily
ipFamilyPolicy v1 . IPFamilyPolicyType
expectError bool
} {
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
}
for i , tc := range testcases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "svc-test-%d" , i ) , // use different services for each test
} ,
Spec : v1 . ServiceSpec {
Type : tc . serviceType ,
ClusterIPs : tc . clusterIPs ,
IPFamilies : tc . ipFamilies ,
IPFamilyPolicy : & tc . ipFamilyPolicy ,
Ports : [ ] v1 . ServicePort {
{
Port : 443 ,
TargetPort : intstr . FromInt ( 443 ) ,
} ,
} ,
} ,
}
// create a service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if ( err != nil ) != tc . expectError {
t . Errorf ( "Test failed expected result: %v received %v " , tc . expectError , err )
}
// if no error was expected validate the service otherwise return
if err != nil {
return
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Errorf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , tc . expectedIPFamilies ) ; err != nil {
t . Errorf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
} )
}
}
// TestCreateServiceDualStackIPv6IPv4 test the Service dualstackness in a IPv6IPv4 DualStack cluster
func TestCreateServiceDualStackIPv6IPv4 ( t * testing . T ) {
// Create an IPv6IPv4 dual stack control-plane
serviceCIDR := "2001:db8:1::/48"
secondaryServiceCIDR := "10.0.0.0/16"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-08-19 19:16:14 -04:00
_ , secCidr , err := netutils . ParseCIDRSloppy ( secondaryServiceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . SecondaryServiceIPRange = * secCidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
// verify client is working
if err := wait . PollImmediate ( 5 * time . Second , 2 * time . Minute , func ( ) ( bool , error ) {
_ , err = client . CoreV1 ( ) . Endpoints ( "default" ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil {
t . Logf ( "error fetching endpoints: %v" , err )
return false , nil
}
return true , nil
} ) ; err != nil {
t . Errorf ( "server without enabled endpoints failed to register: %v" , err )
}
var testcases = [ ] struct {
name string
serviceType v1 . ServiceType
clusterIPs [ ] string
ipFamilies [ ] v1 . IPFamily
expectedIPFamilies [ ] v1 . IPFamily
ipFamilyPolicy v1 . IPFamilyPolicyType
expectError bool
} {
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : nil ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicySingleStack ,
expectError : true ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyPreferDualStack ,
expectError : false ,
} ,
{
name : "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack" ,
serviceType : v1 . ServiceTypeClusterIP ,
clusterIPs : [ ] string { } ,
ipFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
expectedIPFamilies : [ ] v1 . IPFamily { v1 . IPv6Protocol , v1 . IPv4Protocol } ,
ipFamilyPolicy : v1 . IPFamilyPolicyRequireDualStack ,
expectError : false ,
} ,
}
for i , tc := range testcases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : fmt . Sprintf ( "svc-test-%d" , i ) , // use different services for each test
} ,
Spec : v1 . ServiceSpec {
Type : tc . serviceType ,
ClusterIPs : tc . clusterIPs ,
IPFamilies : tc . ipFamilies ,
IPFamilyPolicy : & tc . ipFamilyPolicy ,
Ports : [ ] v1 . ServicePort {
{
Port : 443 ,
TargetPort : intstr . FromInt ( 443 ) ,
} ,
} ,
} ,
}
// create a service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if ( err != nil ) != tc . expectError {
t . Errorf ( "Test failed expected result: %v received %v " , tc . expectError , err )
}
// if no error was expected validate the service otherwise return
if err != nil {
return
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Errorf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , tc . expectedIPFamilies ) ; err != nil {
t . Errorf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
} )
}
}
// TestUpgradeDowngrade tests upgrading and downgrading a service from/to dual-stack
func TestUpgradeDowngrade ( t * testing . T ) {
// Create an IPv4IPv6 dual stack control-plane
serviceCIDR := "10.0.0.0/16"
secondaryServiceCIDR := "2001:db8:1::/48"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-08-19 19:16:14 -04:00
_ , secCidr , err := netutils . ParseCIDRSloppy ( secondaryServiceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . SecondaryServiceIPRange = * secCidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
upgradeServiceName := "svc-upgrade"
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : upgradeServiceName ,
} ,
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeClusterIP ,
Ports : [ ] v1 . ServicePort {
{
Port : 443 ,
TargetPort : intstr . FromInt ( 443 ) ,
} ,
} ,
} ,
}
// create a service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error while creating service:%v" , err )
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , [ ] v1 . IPFamily { v1 . IPv4Protocol } /* default cluster config */ ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
// upgrade it
requireDualStack := v1 . IPFamilyPolicyRequireDualStack
svc . Spec . IPFamilyPolicy = & requireDualStack
upgraded , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , svc , metav1 . UpdateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error upgrading service to dual stack. %v" , err )
}
if err := validateServiceAndClusterIPFamily ( upgraded , [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } /* +1 family */ ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service(after upgrade) %s %v" , svc . Name , err )
}
// downgrade it
singleStack := v1 . IPFamilyPolicySingleStack
upgraded . Spec . IPFamilyPolicy = & singleStack
upgraded . Spec . ClusterIPs = upgraded . Spec . ClusterIPs [ 0 : 1 ]
upgraded . Spec . IPFamilies = upgraded . Spec . IPFamilies [ 0 : 1 ]
downgraded , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , upgraded , metav1 . UpdateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error downgrading service to single stack. %v" , err )
}
if err := validateServiceAndClusterIPFamily ( downgraded , [ ] v1 . IPFamily { v1 . IPv4Protocol } /* -1 family */ ) ; err != nil {
t . Fatalf ( "unexpected error validating the service(after downgrade) %s %v" , svc . Name , err )
}
// run test again this time without removing secondary IPFamily or ClusterIP
downgraded . Spec . IPFamilyPolicy = & requireDualStack
upgradedAgain , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , downgraded , metav1 . UpdateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error upgrading service to dual stack. %v" , err )
}
if err := validateServiceAndClusterIPFamily ( upgradedAgain , [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } /* +1 family */ ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service(after upgrade) %s %v" , svc . Name , err )
}
upgradedAgain . Spec . IPFamilyPolicy = & singleStack
// api-server automatically removes the secondary ClusterIP and IPFamily
// when a servie is downgraded.
downgradedAgain , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , upgradedAgain , metav1 . UpdateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error downgrading service to single stack. %v" , err )
}
if err := validateServiceAndClusterIPFamily ( downgradedAgain , [ ] v1 . IPFamily { v1 . IPv4Protocol } /* -1 family */ ) ; err != nil {
t . Fatalf ( "unexpected error validating the service(after downgrade) %s %v" , svc . Name , err )
}
}
// TestConvertToFromExternalName tests the compatibility with old clients that
// may not clear ClusterIPs
func TestConvertToFromExternalName ( t * testing . T ) {
// Create an IPv4IPv6 dual stack control-plane
serviceCIDR := "10.0.0.0/16"
secondaryServiceCIDR := "2001:db8:1::/48"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-08-19 19:16:14 -04:00
_ , secCidr , err := netutils . ParseCIDRSloppy ( secondaryServiceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . SecondaryServiceIPRange = * secCidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
serviceName := "svc-ext-name"
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : serviceName ,
} ,
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeClusterIP ,
Ports : [ ] v1 . ServicePort {
{
Port : 443 ,
TargetPort : intstr . FromInt ( 443 ) ,
} ,
} ,
} ,
}
// create a service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error while creating service:%v" , err )
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , [ ] v1 . IPFamily { v1 . IPv4Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
// convert to ExternalName
svc . Spec . Type = v1 . ServiceTypeExternalName
svc . Spec . ClusterIP = "" // not clearing ClusterIPs
svc . Spec . ExternalName = "something.somewhere"
externalNameSvc , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , svc , metav1 . UpdateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error converting service to external name. %v" , err )
}
if len ( externalNameSvc . Spec . ClusterIPs ) > 0 || len ( externalNameSvc . Spec . ClusterIP ) > 0 || len ( externalNameSvc . Spec . IPFamilies ) > 0 {
t . Fatalf ( "unpexpected externalname service with ClusterIPs %v or ClusterIP %v or IPFamilies %v" , externalNameSvc . Spec . ClusterIPs , externalNameSvc . Spec . ClusterIP , externalNameSvc . Spec . IPFamilies )
}
// convert to a ClusterIP service
externalNameSvc . Spec . Type = v1 . ServiceTypeClusterIP
externalNameSvc . Spec . ExternalName = ""
clusterIPSvc , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , externalNameSvc , metav1 . UpdateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error converting service to ClusterIP. %v" , err )
}
if err := validateServiceAndClusterIPFamily ( clusterIPSvc , [ ] v1 . IPFamily { v1 . IPv4Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
}
// TestPreferDualStack preferDualstack on create and update
func TestPreferDualStack ( t * testing . T ) {
// Create an IPv4IPv6 dual stack control-plane
serviceCIDR := "10.0.0.0/16"
secondaryServiceCIDR := "2001:db8:1::/48"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-08-19 19:16:14 -04:00
_ , secCidr , err := netutils . ParseCIDRSloppy ( secondaryServiceCIDR )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . SecondaryServiceIPRange = * secCidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
preferDualStack := v1 . IPFamilyPolicyPreferDualStack
serviceName := "svc-upgrade"
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : serviceName ,
} ,
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeClusterIP ,
IPFamilyPolicy : & preferDualStack ,
Ports : [ ] v1 . ServicePort {
{
Port : 443 ,
TargetPort : intstr . FromInt ( 443 ) ,
} ,
} ,
} ,
}
// create a service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error while creating service:%v" , err )
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
// update it
svc . Spec . Selector = map [ string ] string { "foo" : "bar" }
upgraded , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , svc , metav1 . UpdateOptions { } )
if err != nil {
t . Fatalf ( "unexpected error upgrading service to dual stack. %v" , err )
}
if err := validateServiceAndClusterIPFamily ( upgraded , [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service(after upgrade) %s %v" , svc . Name , err )
}
}
2020-10-29 14:03:30 -04:00
type labelsForMergePatch struct {
Labels map [ string ] string ` json:"lables,omitempty" `
}
// tests an update service while dualstack flag is off
func TestServiceUpdate ( t * testing . T ) {
// Create an IPv4 single stack control-plane
serviceCIDR := "10.0.0.0/16"
2021-05-25 01:26:28 -04:00
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
2020-10-29 14:03:30 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
2021-05-25 04:10:48 -04:00
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
2020-10-29 14:03:30 -04:00
defer closeFn ( )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
serviceName := "test-service"
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : serviceName ,
} ,
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeClusterIP ,
Ports : [ ] v1 . ServicePort {
{
Port : 443 ,
TargetPort : intstr . FromInt ( 443 ) ,
} ,
} ,
} ,
}
// create the service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
// if no error was expected validate the service otherwise return
if err != nil {
t . Errorf ( "unexpected error creating service:%v" , err )
return
}
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Errorf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
// update using put
svc . Labels = map [ string ] string { "x" : "y" }
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Update ( context . TODO ( ) , svc , metav1 . UpdateOptions { } )
if err != nil {
t . Errorf ( "Unexpected error updating the service %s %v" , svc . Name , err )
}
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
// update using StrategicMergePatchType
labels := labelsForMergePatch {
Labels : map [ string ] string { "foo" : "bar" } ,
}
patchBytes , err := json . Marshal ( & labels )
if err != nil {
t . Fatalf ( "failed to json.Marshal labels: %v" , err )
}
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Patch ( context . TODO ( ) , svc . Name , types . StrategicMergePatchType , patchBytes , metav1 . PatchOptions { } )
if err != nil {
t . Fatalf ( "unexpected error patching service using strategic merge patch. %v" , err )
}
current , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
// update using json patch
toUpdate := current . DeepCopy ( )
currentJSON , err := json . Marshal ( current )
if err != nil {
t . Fatalf ( "unexpected error marshal current service. %v" , err )
}
toUpdate . Labels = map [ string ] string { "alpha" : "bravo" }
toUpdateJSON , err := json . Marshal ( toUpdate )
if err != nil {
t . Fatalf ( "unexpected error marshal toupdate service. %v" , err )
}
patchBytes , err = jsonpatch . CreateMergePatch ( currentJSON , toUpdateJSON )
if err != nil {
t . Fatalf ( "unexpected error creating json patch. %v" , err )
}
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Patch ( context . TODO ( ) , svc . Name , types . MergePatchType , patchBytes , metav1 . PatchOptions { } )
if err != nil {
t . Fatalf ( "unexpected error patching service using merge patch. %v" , err )
}
// validate the service was created correctly if it was not expected to fail
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
}
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
// validateServiceAndClusterIPFamily checks that the service has the expected IPFamilies
func validateServiceAndClusterIPFamily ( svc * v1 . Service , expectedIPFamilies [ ] v1 . IPFamily ) error {
// create a slice for the errors
var errstrings [ ] string
if svc . Spec . IPFamilies == nil {
return fmt . Errorf ( "service ip family nil for service %s/%s" , svc . Namespace , svc . Name )
}
if ! reflect . DeepEqual ( svc . Spec . IPFamilies , expectedIPFamilies ) {
return fmt . Errorf ( "ip families mismatch for service: %s/%s, expected: %s, actual: %s" , svc . Namespace , svc . Name , expectedIPFamilies , svc . Spec . IPFamilies )
}
if len ( svc . Spec . ClusterIPs ) == 0 {
return fmt . Errorf ( "svc %s is invalid it does not have ClusterIP" , svc . Name )
}
// not headless
if len ( svc . Spec . ClusterIPs ) > 0 && svc . Spec . ClusterIPs [ 0 ] != v1 . ClusterIPNone {
if len ( svc . Spec . ClusterIPs ) != len ( svc . Spec . IPFamilies ) {
return fmt . Errorf ( "svc %v is invalid len(ClusterIPs:%v) != len(IPFamilies:%v)" , svc . Name , svc . Spec . ClusterIPs , svc . Spec . IPFamilies )
}
}
for j , ip := range svc . Spec . ClusterIPs {
// we should never be here
if ip == v1 . ClusterIPNone && len ( svc . Spec . ClusterIPs ) > 1 {
errstrings = append ( errstrings , fmt . Sprintf ( "Error validating Service: %s, None is used with +1 clusterIPs (%v)" , svc . Name , svc . Spec . ClusterIPs ) )
}
if ip == v1 . ClusterIPNone {
break // the service is headless. the rest of family check is pointless
}
// the clusterIP assigned should have the same IPFamily requested
if netutils . IsIPv6String ( ip ) != ( expectedIPFamilies [ j ] == v1 . IPv6Protocol ) {
errstrings = append ( errstrings , fmt . Sprintf ( "got unexpected service ip %s, should belong to %s ip family" , ip , expectedIPFamilies [ j ] ) )
}
}
if len ( errstrings ) > 0 {
errstrings = append ( errstrings , fmt . Sprintf ( "Error validating Service: %s, ClusterIPs: %v Expected IPFamilies %v" , svc . Name , svc . Spec . ClusterIPs , expectedIPFamilies ) )
return fmt . Errorf ( strings . Join ( errstrings , "\n" ) )
}
return nil
}
2021-06-22 13:40:09 -04:00
func TestUpgradeServicePreferToDualStack ( t * testing . T ) {
// Create an IPv4 only dual stack control-plane
serviceCIDR := "192.168.0.0/24"
cfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
2021-06-22 13:40:09 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . ServiceIPRange = * cidr
_ , s , closeFn := framework . RunAnAPIServer ( cfg )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
preferDualStack := v1 . IPFamilyPolicyPreferDualStack
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : "svc-prefer-dual" ,
} ,
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeClusterIP ,
ClusterIPs : nil ,
IPFamilies : nil ,
IPFamilyPolicy : & preferDualStack ,
Ports : [ ] v1 . ServicePort {
{
Name : "svc-port-1" ,
Port : 443 ,
TargetPort : intstr . IntOrString { IntVal : 443 } ,
Protocol : "TCP" ,
} ,
} ,
} ,
}
// create the service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , [ ] v1 . IPFamily { v1 . IPv4Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
// reconfigure the apiserver to be dual-stack
closeFn ( )
secondaryServiceCIDR := "2001:db8:1::/48"
2021-08-19 19:16:14 -04:00
_ , secCidr , err := netutils . ParseCIDRSloppy ( secondaryServiceCIDR )
2021-06-22 13:40:09 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
cfg . ExtraConfig . SecondaryServiceIPRange = * secCidr
_ , s , closeFn = framework . RunAnAPIServer ( cfg )
defer closeFn ( )
client = clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
// service should remain single stack
if err = validateServiceAndClusterIPFamily ( svc , [ ] v1 . IPFamily { v1 . IPv4Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
}
func TestDowngradeServicePreferToDualStack ( t * testing . T ) {
// Create a dual stack control-plane
serviceCIDR := "192.168.0.0/24"
secondaryServiceCIDR := "2001:db8:1::/48"
2021-09-24 19:30:22 -04:00
2021-06-22 13:40:09 -04:00
dualStackCfg := framework . NewIntegrationTestControlPlaneConfig ( )
2021-08-19 19:16:14 -04:00
_ , cidr , err := netutils . ParseCIDRSloppy ( serviceCIDR )
2021-06-22 13:40:09 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
dualStackCfg . ExtraConfig . ServiceIPRange = * cidr
2021-08-19 19:16:14 -04:00
_ , secCidr , err := netutils . ParseCIDRSloppy ( secondaryServiceCIDR )
2021-06-22 13:40:09 -04:00
if err != nil {
t . Fatalf ( "bad cidr: %v" , err )
}
dualStackCfg . ExtraConfig . SecondaryServiceIPRange = * secCidr
_ , s , closeFn := framework . RunAnAPIServer ( dualStackCfg )
client := clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
preferDualStack := v1 . IPFamilyPolicyPreferDualStack
svc := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : "svc-prefer-dual01" ,
} ,
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeClusterIP ,
ClusterIPs : nil ,
IPFamilies : nil ,
IPFamilyPolicy : & preferDualStack ,
Ports : [ ] v1 . ServicePort {
{
Name : "svc-port-1" ,
Port : 443 ,
TargetPort : intstr . IntOrString { IntVal : 443 } ,
Protocol : "TCP" ,
} ,
} ,
} ,
}
// create the service
_ , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Create ( context . TODO ( ) , svc , metav1 . CreateOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
// validate the service was created correctly if it was not expected to fail
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
if err := validateServiceAndClusterIPFamily ( svc , [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
// reconfigure the apiserver to be sinlge stack
closeFn ( )
// reset secondary
var emptyCidr net . IPNet
dualStackCfg . ExtraConfig . SecondaryServiceIPRange = emptyCidr
_ , s , closeFn = framework . RunAnAPIServer ( dualStackCfg )
defer closeFn ( )
client = clientset . NewForConfigOrDie ( & restclient . Config { Host : s . URL } )
// Wait until the default "kubernetes" service is created.
if err = wait . Poll ( 250 * time . Millisecond , time . Minute , func ( ) ( bool , error ) {
_ , err := client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , "kubernetes" , metav1 . GetOptions { } )
if err != nil && ! apierrors . IsNotFound ( err ) {
return false , err
}
return ! apierrors . IsNotFound ( err ) , nil
} ) ; err != nil {
t . Fatalf ( "creating kubernetes service timed out" )
}
// validate the service is still there.
svc , err = client . CoreV1 ( ) . Services ( metav1 . NamespaceDefault ) . Get ( context . TODO ( ) , svc . Name , metav1 . GetOptions { } )
if err != nil {
t . Fatalf ( "Unexpected error to get the service %s %v" , svc . Name , err )
}
2021-06-25 17:24:49 -04:00
// service should remain dual stack
2021-06-22 13:40:09 -04:00
if err = validateServiceAndClusterIPFamily ( svc , [ ] v1 . IPFamily { v1 . IPv4Protocol , v1 . IPv6Protocol } ) ; err != nil {
t . Fatalf ( "Unexpected error validating the service %s %v" , svc . Name , err )
}
}
2021-08-20 17:13:03 -04:00
type serviceMergePatch struct {
Spec specMergePatch ` json:"spec,omitempty" `
}
type specMergePatch struct {
Type v1 . ServiceType ` json:"type,omitempty" `
ExternalName string ` json:"externalName,omitempty" `
}
// tests success when converting ClusterIP:Headless service to ExternalName
func Test_ServiceChangeTypeHeadlessToExternalNameWithPatch ( t * testing . T ) {
controlPlaneConfig := framework . NewIntegrationTestControlPlaneConfig ( )
_ , server , closeFn := framework . RunAnAPIServer ( controlPlaneConfig )
defer closeFn ( )
config := restclient . Config { Host : server . URL }
client , err := clientset . NewForConfig ( & config )
if err != nil {
t . Fatalf ( "Error creating clientset: %v" , err )
}
ns := framework . CreateTestingNamespace ( "test-service-allocate-node-ports" , server , t )
defer framework . DeleteTestingNamespace ( ns , server , t )
service := & v1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : "test-123" ,
} ,
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeClusterIP ,
ClusterIP : "None" ,
Selector : map [ string ] string { "foo" : "bar" } ,
} ,
}
service , err = client . CoreV1 ( ) . Services ( ns . Name ) . Create ( context . TODO ( ) , service , metav1 . CreateOptions { } )
if err != nil {
t . Fatalf ( "Error creating test service: %v" , err )
}
serviceMergePatch := serviceMergePatch {
Spec : specMergePatch {
Type : v1 . ServiceTypeExternalName ,
ExternalName : "foo.bar" ,
} ,
}
patchBytes , err := json . Marshal ( & serviceMergePatch )
if err != nil {
t . Fatalf ( "failed to json.Marshal ports: %v" , err )
}
_ , err = client . CoreV1 ( ) . Services ( ns . Name ) . Patch ( context . TODO ( ) , service . Name , types . StrategicMergePatchType , patchBytes , metav1 . PatchOptions { } )
if err != nil {
t . Fatalf ( "unexpected error patching service using strategic merge patch. %v" , err )
}
}