Fix available controller assumption about port 443

k3s-v1.15.3
Mehdy Bohlool 2019-04-07 17:32:10 -07:00
parent c1076ba05a
commit e6f5f4f61b
2 changed files with 51 additions and 18 deletions

View File

@ -185,17 +185,20 @@ func (c *AvailableConditionController) sync(key string) error {
} }
if service.Spec.Type == v1.ServiceTypeClusterIP { if service.Spec.Type == v1.ServiceTypeClusterIP {
// if we have a cluster IP service, it must be listening on 443 and we can check that // if we have a cluster IP service, it must be listening on configured port and we can check that
servicePort := apiService.Spec.Service.Port
portName := ""
foundPort := false foundPort := false
for _, port := range service.Spec.Ports { for _, port := range service.Spec.Ports {
if port.Port == 443 { if port.Port == servicePort {
foundPort = true foundPort = true
portName = port.Name
} }
} }
if !foundPort { if !foundPort {
availableCondition.Status = apiregistration.ConditionFalse availableCondition.Status = apiregistration.ConditionFalse
availableCondition.Reason = "ServicePortError" availableCondition.Reason = "ServicePortError"
availableCondition.Message = fmt.Sprintf("service/%s in %q is not listening on port 443", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace) availableCondition.Message = fmt.Sprintf("service/%s in %q is not listening on port %d", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace, apiService.Spec.Service.Port)
apiregistration.SetAPIServiceCondition(apiService, availableCondition) apiregistration.SetAPIServiceCondition(apiService, availableCondition)
_, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService)
return err return err
@ -219,15 +222,19 @@ func (c *AvailableConditionController) sync(key string) error {
} }
hasActiveEndpoints := false hasActiveEndpoints := false
for _, subset := range endpoints.Subsets { for _, subset := range endpoints.Subsets {
if len(subset.Addresses) > 0 { if len(subset.Addresses) == 0 {
continue
}
for _, endpointPort := range subset.Ports {
if endpointPort.Name == portName {
hasActiveEndpoints = true hasActiveEndpoints = true
break }
} }
} }
if !hasActiveEndpoints { if !hasActiveEndpoints {
availableCondition.Status = apiregistration.ConditionFalse availableCondition.Status = apiregistration.ConditionFalse
availableCondition.Reason = "MissingEndpoints" availableCondition.Reason = "MissingEndpoints"
availableCondition.Message = fmt.Sprintf("endpoints for service/%s in %q have no addresses", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace) availableCondition.Message = fmt.Sprintf("endpoints for service/%s in %q have no addresses with port name %q", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace, portName)
apiregistration.SetAPIServiceCondition(apiService, availableCondition) apiregistration.SetAPIServiceCondition(apiService, availableCondition)
_, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService)
return err return err

View File

@ -17,6 +17,7 @@ limitations under the License.
package apiserver package apiserver
import ( import (
"fmt"
"testing" "testing"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
@ -31,13 +32,18 @@ import (
listers "k8s.io/kube-aggregator/pkg/client/listers/apiregistration/internalversion" listers "k8s.io/kube-aggregator/pkg/client/listers/apiregistration/internalversion"
) )
const (
testServicePort = 1234
testServicePortName = "testPort"
)
func newEndpoints(namespace, name string) *v1.Endpoints { func newEndpoints(namespace, name string) *v1.Endpoints {
return &v1.Endpoints{ return &v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}, ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name},
} }
} }
func newEndpointsWithAddress(namespace, name string) *v1.Endpoints { func newEndpointsWithAddress(namespace, name string, port int32, portName string) *v1.Endpoints {
return &v1.Endpoints{ return &v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}, ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name},
Subsets: []v1.EndpointSubset{ Subsets: []v1.EndpointSubset{
@ -47,18 +53,24 @@ func newEndpointsWithAddress(namespace, name string) *v1.Endpoints {
IP: "val", IP: "val",
}, },
}, },
Ports: []v1.EndpointPort{
{
Name: portName,
Port: port,
},
},
}, },
}, },
} }
} }
func newService(namespace, name string) *v1.Service { func newService(namespace, name string, port int32, portName string) *v1.Service {
return &v1.Service{ return &v1.Service{
ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}, ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name},
Spec: v1.ServiceSpec{ Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP, Type: v1.ServiceTypeClusterIP,
Ports: []v1.ServicePort{ Ports: []v1.ServicePort{
{Port: 443}, {Port: port, Name: portName},
}, },
}, },
} }
@ -77,6 +89,7 @@ func newRemoteAPIService(name string) *apiregistration.APIService {
Service: &apiregistration.ServiceReference{ Service: &apiregistration.ServiceReference{
Namespace: "foo", Namespace: "foo",
Name: "bar", Name: "bar",
Port: testServicePort,
}, },
}, },
} }
@ -107,7 +120,7 @@ func TestSync(t *testing.T) {
name: "no service", name: "no service",
apiServiceName: "remote.group", apiServiceName: "remote.group",
apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")}, apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")},
services: []*v1.Service{newService("foo", "not-bar")}, services: []*v1.Service{newService("foo", "not-bar", testServicePort, testServicePortName)},
expectedAvailability: apiregistration.APIServiceCondition{ expectedAvailability: apiregistration.APIServiceCondition{
Type: apiregistration.Available, Type: apiregistration.Available,
Status: apiregistration.ConditionFalse, Status: apiregistration.ConditionFalse,
@ -128,19 +141,19 @@ func TestSync(t *testing.T) {
}, },
}, },
}}, }},
endpoints: []*v1.Endpoints{newEndpointsWithAddress("foo", "bar")}, endpoints: []*v1.Endpoints{newEndpointsWithAddress("foo", "bar", testServicePort, testServicePortName)},
expectedAvailability: apiregistration.APIServiceCondition{ expectedAvailability: apiregistration.APIServiceCondition{
Type: apiregistration.Available, Type: apiregistration.Available,
Status: apiregistration.ConditionFalse, Status: apiregistration.ConditionFalse,
Reason: "ServicePortError", Reason: "ServicePortError",
Message: `service/bar in "foo" is not listening on port 443`, Message: fmt.Sprintf(`service/bar in "foo" is not listening on port %d`, testServicePort),
}, },
}, },
{ {
name: "no endpoints", name: "no endpoints",
apiServiceName: "remote.group", apiServiceName: "remote.group",
apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")}, apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")},
services: []*v1.Service{newService("foo", "bar")}, services: []*v1.Service{newService("foo", "bar", testServicePort, testServicePortName)},
expectedAvailability: apiregistration.APIServiceCondition{ expectedAvailability: apiregistration.APIServiceCondition{
Type: apiregistration.Available, Type: apiregistration.Available,
Status: apiregistration.ConditionFalse, Status: apiregistration.ConditionFalse,
@ -152,21 +165,34 @@ func TestSync(t *testing.T) {
name: "missing endpoints", name: "missing endpoints",
apiServiceName: "remote.group", apiServiceName: "remote.group",
apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")}, apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")},
services: []*v1.Service{newService("foo", "bar")}, services: []*v1.Service{newService("foo", "bar", testServicePort, testServicePortName)},
endpoints: []*v1.Endpoints{newEndpoints("foo", "bar")}, endpoints: []*v1.Endpoints{newEndpoints("foo", "bar")},
expectedAvailability: apiregistration.APIServiceCondition{ expectedAvailability: apiregistration.APIServiceCondition{
Type: apiregistration.Available, Type: apiregistration.Available,
Status: apiregistration.ConditionFalse, Status: apiregistration.ConditionFalse,
Reason: "MissingEndpoints", Reason: "MissingEndpoints",
Message: `endpoints for service/bar in "foo" have no addresses`, Message: `endpoints for service/bar in "foo" have no addresses with port name "testPort"`,
},
},
{
name: "wrong endpoint port name",
apiServiceName: "remote.group",
apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")},
services: []*v1.Service{newService("foo", "bar", testServicePort, testServicePortName)},
endpoints: []*v1.Endpoints{newEndpointsWithAddress("foo", "bar", testServicePort, "wrongName")},
expectedAvailability: apiregistration.APIServiceCondition{
Type: apiregistration.Available,
Status: apiregistration.ConditionFalse,
Reason: "MissingEndpoints",
Message: fmt.Sprintf(`endpoints for service/bar in "foo" have no addresses with port name "%s"`, testServicePortName),
}, },
}, },
{ {
name: "remote", name: "remote",
apiServiceName: "remote.group", apiServiceName: "remote.group",
apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")}, apiServices: []*apiregistration.APIService{newRemoteAPIService("remote.group")},
services: []*v1.Service{newService("foo", "bar")}, services: []*v1.Service{newService("foo", "bar", testServicePort, testServicePortName)},
endpoints: []*v1.Endpoints{newEndpointsWithAddress("foo", "bar")}, endpoints: []*v1.Endpoints{newEndpointsWithAddress("foo", "bar", testServicePort, testServicePortName)},
expectedAvailability: apiregistration.APIServiceCondition{ expectedAvailability: apiregistration.APIServiceCondition{
Type: apiregistration.Available, Type: apiregistration.Available,
Status: apiregistration.ConditionTrue, Status: apiregistration.ConditionTrue,