Simplify Service Lookup

Since we already know the name and namespace
of the service(s) we want we can just get the
correct one back from the API without filtering
the results.
This commit is contained in:
Ed Robinson 2016-05-26 00:53:51 +01:00
parent e948a013cd
commit 6accb90c47
No known key found for this signature in database
GPG key ID: EC501FCA6421CCF0
3 changed files with 41 additions and 54 deletions

View file

@ -16,12 +16,13 @@ const (
APIEndpoint = "/api/v1" APIEndpoint = "/api/v1"
extentionsEndpoint = "/apis/extensions/v1beta1" extentionsEndpoint = "/apis/extensions/v1beta1"
defaultIngress = "/ingresses" defaultIngress = "/ingresses"
namespaces = "/namespaces/"
) )
// Client is a client for the Kubernetes master. // Client is a client for the Kubernetes master.
type Client interface { type Client interface {
GetIngresses(predicate func(Ingress) bool) ([]Ingress, error) GetIngresses(predicate func(Ingress) bool) ([]Ingress, error)
GetServices(predicate func(Service) bool) ([]Service, error) GetService(name, namespace string) (Service, error)
GetEndpoints(name, namespace string) (Endpoints, error) GetEndpoints(name, namespace string) (Endpoints, error)
WatchAll(stopCh <-chan bool) (chan interface{}, chan error, error) WatchAll(stopCh <-chan bool) (chan interface{}, chan error, error)
} }
@ -77,26 +78,20 @@ func (c *clientImpl) WatchIngresses(stopCh <-chan bool) (chan interface{}, chan
return c.watch(getURL, stopCh) return c.watch(getURL, stopCh)
} }
// GetServices returns all services in the cluster // GetService returns the named service from the named namespace
func (c *clientImpl) GetServices(predicate func(Service) bool) ([]Service, error) { func (c *clientImpl) GetService(name, namespace string) (Service, error) {
getURL := c.endpointURL + APIEndpoint + "/services" getURL := c.endpointURL + APIEndpoint + namespaces + namespace + "/services/" + name
body, err := c.do(c.request(getURL)) body, err := c.do(c.request(getURL))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create services request: GET %q : %v", getURL, err) return Service{}, fmt.Errorf("failed to create services request: GET %q : %v", getURL, err)
} }
var serviceList ServiceList var service Service
if err := json.Unmarshal(body, &serviceList); err != nil { if err := json.Unmarshal(body, &service); err != nil {
return nil, fmt.Errorf("failed to decode list of services resources: %v", err) return Service{}, fmt.Errorf("failed to decode service resource: %v", err)
} }
services := serviceList.Items[:0] return service, nil
for _, service := range serviceList.Items {
if predicate(service) {
services = append(services, service)
}
}
return services, nil
} }
// WatchServices returns all services in the cluster // WatchServices returns all services in the cluster
@ -108,7 +103,7 @@ func (c *clientImpl) WatchServices(stopCh <-chan bool) (chan interface{}, chan e
// GetEndpoints returns the named Endpoints // GetEndpoints returns the named Endpoints
// Endpoints have the same name as the coresponding service // Endpoints have the same name as the coresponding service
func (c *clientImpl) GetEndpoints(name, namespace string) (Endpoints, error) { func (c *clientImpl) GetEndpoints(name, namespace string) (Endpoints, error) {
getURL := c.endpointURL + APIEndpoint + "/namespaces/" + namespace + "/endpoints/" + name getURL := c.endpointURL + APIEndpoint + namespaces + namespace + "/endpoints/" + name
body, err := c.do(c.request(getURL)) body, err := c.do(c.request(getURL))
if err != nil { if err != nil {

View file

@ -190,49 +190,42 @@ func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configur
Rule: ruleType + ":" + pa.Path, Rule: ruleType + ":" + pa.Path,
} }
} }
services, err := k8sClient.GetServices(func(service k8s.Service) bool { service, err := k8sClient.GetService(pa.Backend.ServiceName, i.ObjectMeta.Namespace)
return service.ObjectMeta.Namespace == i.ObjectMeta.Namespace && service.Name == pa.Backend.ServiceName
})
if err != nil { if err != nil {
log.Warnf("Error retrieving services: %v", err) log.Warnf("Error retrieving services: %v", err)
continue
}
if len(services) == 0 {
// no backends found, delete frontend...
delete(templateObjects.Frontends, r.Host+pa.Path) delete(templateObjects.Frontends, r.Host+pa.Path)
log.Warnf("Error retrieving services %s", pa.Backend.ServiceName) log.Warnf("Error retrieving services %s", pa.Backend.ServiceName)
continue
} }
for _, service := range services { protocol := "http"
protocol := "http" for _, port := range service.Spec.Ports {
for _, port := range service.Spec.Ports { if equalPorts(port, pa.Backend.ServicePort) {
if equalPorts(port, pa.Backend.ServicePort) { if port.Port == 443 {
if port.Port == 443 { protocol = "https"
protocol = "https" }
endpoints, err := k8sClient.GetEndpoints(service.ObjectMeta.Name, service.ObjectMeta.Namespace)
if err != nil {
log.Errorf("Error retrieving endpoints: %v", err)
continue
}
if len(endpoints.Subsets) == 0 {
log.Warnf("Endpoints not found for %s/%s, falling back to Service ClusterIP", service.ObjectMeta.Namespace, service.ObjectMeta.Name)
templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{
URL: protocol + "://" + service.Spec.ClusterIP + ":" + strconv.Itoa(port.Port),
Weight: 1,
} }
endpoints, err := k8sClient.GetEndpoints(service.ObjectMeta.Name, service.ObjectMeta.Namespace) } else {
if err != nil { for _, subset := range endpoints.Subsets {
log.Errorf("Error retrieving endpoints: %v", err) for _, address := range subset.Addresses {
continue url := protocol + "://" + address.IP + ":" + strconv.Itoa(endpointPortNumber(port, subset.Ports))
} templateObjects.Backends[r.Host+pa.Path].Servers[url] = types.Server{
if len(endpoints.Subsets) == 0 { URL: url,
log.Warnf("Endpoints not found for %s/%s, falling back to Service ClusterIP", service.ObjectMeta.Namespace, service.ObjectMeta.Name) Weight: 1,
templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{
URL: protocol + "://" + service.Spec.ClusterIP + ":" + strconv.Itoa(port.Port),
Weight: 1,
}
} else {
for _, subset := range endpoints.Subsets {
for _, address := range subset.Addresses {
url := protocol + "://" + address.IP + ":" + strconv.Itoa(endpointPortNumber(port, subset.Ports))
templateObjects.Backends[r.Host+pa.Path].Servers[url] = types.Server{
URL: url,
Weight: 1,
}
} }
} }
} }
break
} }
break
} }
} }
} }

View file

@ -1212,14 +1212,13 @@ func (c clientMock) GetIngresses(predicate func(k8s.Ingress) bool) ([]k8s.Ingres
func (c clientMock) WatchIngresses(predicate func(k8s.Ingress) bool, stopCh <-chan bool) (chan interface{}, chan error, error) { func (c clientMock) WatchIngresses(predicate func(k8s.Ingress) bool, stopCh <-chan bool) (chan interface{}, chan error, error) {
return c.watchChan, make(chan error), nil return c.watchChan, make(chan error), nil
} }
func (c clientMock) GetServices(predicate func(k8s.Service) bool) ([]k8s.Service, error) { func (c clientMock) GetService(name, namespace string) (k8s.Service, error) {
var services []k8s.Service
for _, service := range c.services { for _, service := range c.services {
if predicate(service) { if service.Namespace == namespace && service.Name == name {
services = append(services, service) return service, nil
} }
} }
return services, nil return k8s.Service{}, nil
} }
func (c clientMock) GetEndpoints(name, namespace string) (k8s.Endpoints, error) { func (c clientMock) GetEndpoints(name, namespace string) (k8s.Endpoints, error) {