ingress-nginx-helm/controllers/nginx-third-party/utils.go
2016-03-24 03:06:19 -03:00

214 lines
5.2 KiB
Go

/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 main
import (
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"k8s.io/contrib/ingress/controllers/nginx-third-party/nginx"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/unversioned"
)
const (
httpPort = "80"
httpsPort = "443"
)
var (
errMissingPodInfo = fmt.Errorf("Unable to get POD information")
errInvalidKind = fmt.Errorf("Please check the field Kind, only ReplicationController or DaemonSet are allowed")
)
// StoreToIngressLister makes a Store that lists Ingress.
// TODO: use cache/listers post 1.1.
type StoreToIngressLister struct {
cache.Store
}
// List lists all Ingress' in the store.
func (s *StoreToIngressLister) List() (ing extensions.IngressList, err error) {
for _, m := range s.Store.List() {
ing.Items = append(ing.Items, *(m.(*extensions.Ingress)))
}
return ing, nil
}
// StoreToConfigMapLister makes a Store that lists existing ConfigMap.
type StoreToConfigMapLister struct {
cache.Store
}
// getLBDetails returns runtime information about the pod (name, IP) and replication
// controller or daemonset (namespace and name).
// This is required to watch for changes in annotations or configuration (ConfigMap)
func getLBDetails(kubeClient *unversioned.Client) (rc *lbInfo, err error) {
podIP := os.Getenv("POD_IP")
podName := os.Getenv("POD_NAME")
podNs := os.Getenv("POD_NAMESPACE")
pod, _ := kubeClient.Pods(podNs).Get(podName)
if pod == nil {
return nil, errMissingPodInfo
}
annotations := pod.Annotations["kubernetes.io/created-by"]
var sref api.SerializedReference
err = json.Unmarshal([]byte(annotations), &sref)
if err != nil {
return nil, err
}
rc = &lbInfo{
ObjectName: sref.Reference.Name,
PodIP: podIP,
Podname: podName,
PodNamespace: podNs,
}
switch sref.Reference.Kind {
case "ReplicationController":
rc.DeployType = &api.ReplicationController{}
return rc, nil
case "DaemonSet":
rc.DeployType = &extensions.DaemonSet{}
return rc, nil
default:
return nil, errInvalidKind
}
}
func getService(kubeClient *unversioned.Client, name string) (nginx.Service, error) {
if name == "" {
return nginx.Service{}, fmt.Errorf("Empty string is not a valid service name")
}
parts := strings.Split(name, "/")
if len(parts) != 2 {
glog.Fatalf("Please check the service format (namespace/name) in service %v", name)
}
defaultPort, err := getServicePorts(kubeClient, parts[0], parts[1])
if err != nil {
return nginx.Service{}, fmt.Errorf("Error obtaining service %v: %v", name, err)
}
return nginx.Service{
ServiceName: parts[1],
ServicePort: defaultPort[0], //TODO: which port?
Namespace: parts[0],
}, nil
}
// getServicePorts returns the ports defined in a service spec
func getServicePorts(kubeClient *unversioned.Client, ns, name string) (ports []string, err error) {
var svc *api.Service
glog.Infof("Checking service %v/%v", ns, name)
svc, err = kubeClient.Services(ns).Get(name)
if err != nil {
return
}
for _, p := range svc.Spec.Ports {
if p.Port != 0 {
ports = append(ports, strconv.Itoa(p.Port))
break
}
}
glog.Infof("Ports for %v/%v : %v", ns, name, ports)
return
}
func getTCPServices(kubeClient *unversioned.Client, tcpServices string) []nginx.Service {
svcs := []nginx.Service{}
for _, svc := range strings.Split(tcpServices, ",") {
if svc == "" {
continue
}
namePort := strings.Split(svc, ":")
if len(namePort) == 2 {
tcpSvc, err := getService(kubeClient, namePort[0])
if err != nil {
glog.Errorf("%s", err)
continue
}
// the exposed TCP service cannot use 80 or 443 as ports
if namePort[1] == httpPort || namePort[1] == httpsPort {
glog.Errorf("The TCP service %v cannot use ports 80 or 443 (it creates a conflict with nginx)", svc)
continue
}
tcpSvc.ExposedPort = namePort[1]
svcs = append(svcs, tcpSvc)
} else {
glog.Errorf("TCP services should take the form namespace/name:port not %v from %v", namePort, svc)
}
}
return svcs
}
func isHostValid(host string, cns []string) bool {
for _, cn := range cns {
if matchHostnames(cn, host) {
return true
}
}
return false
}
func matchHostnames(pattern, host string) bool {
host = strings.TrimSuffix(host, ".")
pattern = strings.TrimSuffix(pattern, ".")
if len(pattern) == 0 || len(host) == 0 {
return false
}
patternParts := strings.Split(pattern, ".")
hostParts := strings.Split(host, ".")
if len(patternParts) != len(hostParts) {
return false
}
for i, patternPart := range patternParts {
if i == 0 && patternPart == "*" {
continue
}
if patternPart != hostParts[i] {
return false
}
}
return true
}