Example #1
0
func (ic *GenericController) createServers(data []interface{}, upstreams map[string]*ingress.Backend) map[string]*ingress.Server {
	servers := make(map[string]*ingress.Server)
	ngxProxy := *proxy.ParseAnnotations(ic.cfg.Backend.BackendDefaults(), nil)

	upsDefaults := ic.cfg.Backend.BackendDefaults()

	// default server
	servers[defServerName] = &ingress.Server{
		Hostname: defServerName,
		Locations: []*ingress.Location{
			{
				Path:         rootLocation,
				IsDefBackend: true,
				Backend:      ic.getDefaultUpstream().Name,
				Proxy:        ngxProxy,
			},
		}}

	// initialize all the servers
	for _, ingIf := range data {
		ing := ingIf.(*extensions.Ingress)
		// check if ssl passthrough is configured
		sslpt, err := sslpassthrough.ParseAnnotations(upsDefaults, ing)
		if err != nil {
			glog.V(5).Infof("error reading ssl passthrough annotation in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		for _, rule := range ing.Spec.Rules {
			host := rule.Host
			if host == "" {
				host = defServerName
			}
			if _, ok := servers[host]; ok {
				// server already configured
				continue
			}
			servers[host] = &ingress.Server{
				Hostname: host,
				Locations: []*ingress.Location{
					{
						Path:         rootLocation,
						IsDefBackend: true,
						Backend:      ic.getDefaultUpstream().Name,
						Proxy:        ngxProxy,
					},
				}, SSLPassthrough: sslpt}
		}
	}

	// configure default location and SSL
	for _, ingIf := range data {
		ing := ingIf.(*extensions.Ingress)

		for _, rule := range ing.Spec.Rules {
			host := rule.Host
			if host == "" {
				host = defServerName
			}

			// only add a certificate if the server does not have one previously configured
			// TODO: TLS without secret?
			if len(ing.Spec.TLS) > 0 && servers[host].SSLCertificate == "" && ing.Spec.TLS[0].SecretName != "" {
				key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Spec.TLS[0].SecretName)
				bc, exists := ic.sslCertTracker.Get(key)
				if exists {
					cert := bc.(*ingress.SSLCert)
					if isHostValid(host, cert) {
						servers[host].SSLCertificate = cert.PemFileName
						servers[host].SSLPemChecksum = cert.PemSHA
					}
				} else {
					glog.Warningf("secret %v does not exists", key)
				}
			}

			if ing.Spec.Backend != nil {
				defUpstream := fmt.Sprintf("%v-%v-%v", ing.GetNamespace(), ing.Spec.Backend.ServiceName, ing.Spec.Backend.ServicePort.String())
				if backendUpstream, ok := upstreams[defUpstream]; ok {
					if host == "" || host == defServerName {
						ic.recorder.Eventf(ing, api.EventTypeWarning, "MAPPING", "error: rules with Spec.Backend are allowed only with hostnames")
						continue
					}
					servers[host].Locations[0].Backend = backendUpstream.Name
				}
			}
		}
	}

	return servers
}
Example #2
0
// getBackendServers returns a list of Upstream and Server to be used by the backend
// An upstream can be used in multiple servers if the namespace, service name and port are the same
func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress.Server) {
	ings := ic.ingLister.Store.List()
	sort.Sort(ingressByRevision(ings))

	upstreams := ic.createUpstreams(ings)
	servers := ic.createServers(ings, upstreams)

	upsDefaults := ic.cfg.Backend.BackendDefaults()

	for _, ingIf := range ings {
		ing := ingIf.(*extensions.Ingress)

		nginxAuth, err := auth.ParseAnnotations(ing, auth.DefAuthDirectory, ic.getSecret)
		glog.V(5).Infof("auth annotation: %v", nginxAuth)
		if err != nil {
			glog.V(5).Infof("error reading authentication in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		rl, err := ratelimit.ParseAnnotations(ing)
		glog.V(5).Infof("rate limit annotation: %v", rl)
		if err != nil {
			glog.V(5).Infof("error reading rate limit annotation in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		locRew, err := rewrite.ParseAnnotations(upsDefaults, ing)
		if err != nil {
			glog.V(5).Infof("error parsing rewrite annotations for Ingress rule %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		wl, err := ipwhitelist.ParseAnnotations(upsDefaults, ing)
		glog.V(5).Infof("white list annotation: %v", wl)
		if err != nil {
			glog.V(5).Infof("error reading white list annotation in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		eCORS, err := cors.ParseAnnotations(ing)
		if err != nil {
			glog.V(5).Infof("error reading CORS annotation in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		ra, err := authreq.ParseAnnotations(ing)
		glog.V(5).Infof("auth request annotation: %v", ra)
		if err != nil {
			glog.V(5).Infof("error reading auth request annotation in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		prx := proxy.ParseAnnotations(upsDefaults, ing)
		glog.V(5).Infof("proxy timeouts annotation: %v", prx)

		certAuth, err := authtls.ParseAnnotations(ing, ic.getAuthCertificate)
		glog.V(5).Infof("auth request annotation: %v", certAuth)
		if err != nil {
			glog.V(5).Infof("error reading certificate auth annotation in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
		}

		for _, rule := range ing.Spec.Rules {
			host := rule.Host
			if host == "" {
				host = defServerName
			}
			server := servers[host]
			if server == nil {
				server = servers[defServerName]
			}

			// use default upstream
			defBackend := upstreams[defUpstreamName]
			// we need to check if the spec contains the default backend
			if ing.Spec.Backend != nil {
				glog.V(3).Infof("ingress rule %v/%v defines a default Backend %v/%v",
					ing.Namespace,
					ing.Name,
					ing.Spec.Backend.ServiceName,
					ing.Spec.Backend.ServicePort.String())

				name := fmt.Sprintf("%v-%v-%v",
					ing.GetNamespace(),
					ing.Spec.Backend.ServiceName,
					ing.Spec.Backend.ServicePort.String())

				if defUps, ok := upstreams[name]; ok {
					defBackend = defUps
				}
			}

			if rule.HTTP == nil &&
				len(ing.Spec.TLS) == 0 &&
				host != defServerName {
				glog.V(3).Infof("ingress rule %v/%v does not contains HTTP or TLS rules. using default backend", ing.Namespace, ing.Name)
				server.Locations[0].Backend = defBackend.Name
				continue
			}

			for _, path := range rule.HTTP.Paths {
				upsName := fmt.Sprintf("%v-%v-%v",
					ing.GetNamespace(),
					path.Backend.ServiceName,
					path.Backend.ServicePort.String())

				ups := upstreams[upsName]

				// if there's no path defined we assume /
				nginxPath := rootLocation
				if path.Path != "" {
					nginxPath = path.Path
				}

				addLoc := true
				for _, loc := range server.Locations {
					if loc.Path == nginxPath {
						addLoc = false

						if !loc.IsDefBackend {
							glog.V(3).Infof("avoiding replacement of ingress rule %v/%v location %v upstream %v (%v)", ing.Namespace, ing.Name, loc.Path, ups.Name, loc.Backend)
							break
						}

						glog.V(3).Infof("replacing ingress rule %v/%v location %v upstream %v (%v)", ing.Namespace, ing.Name, loc.Path, ups.Name, loc.Backend)
						loc.Backend = ups.Name
						loc.IsDefBackend = false
						loc.BasicDigestAuth = *nginxAuth
						loc.RateLimit = *rl
						loc.Redirect = *locRew
						loc.Whitelist = *wl
						loc.Backend = ups.Name
						loc.EnableCORS = eCORS
						loc.ExternalAuth = ra
						loc.Proxy = *prx
						loc.CertificateAuth = *certAuth
						break
					}
				}
				// is a new location
				if addLoc {
					glog.V(3).Infof("adding location %v in ingress rule %v/%v upstream %v", nginxPath, ing.Namespace, ing.Name, ups.Name)
					server.Locations = append(server.Locations, &ingress.Location{
						Path:            nginxPath,
						Backend:         ups.Name,
						IsDefBackend:    false,
						BasicDigestAuth: *nginxAuth,
						RateLimit:       *rl,
						Redirect:        *locRew,
						Whitelist:       *wl,
						EnableCORS:      eCORS,
						ExternalAuth:    ra,
						Proxy:           *prx,
						CertificateAuth: *certAuth,
					})
				}
			}
		}
	}

	// TODO: find a way to make this more readable
	// The structs must be ordered to always generate the same file
	// if the content does not change.
	aUpstreams := make([]*ingress.Backend, 0, len(upstreams))
	for _, value := range upstreams {
		if len(value.Endpoints) == 0 {
			glog.V(3).Infof("upstream %v does not have any active endpoints. Using default backend", value.Name)
			value.Endpoints = append(value.Endpoints, newDefaultServer())
		}
		sort.Sort(ingress.EndpointByAddrPort(value.Endpoints))
		aUpstreams = append(aUpstreams, value)
	}
	sort.Sort(ingress.BackendByNameServers(aUpstreams))

	aServers := make([]*ingress.Server, 0, len(servers))
	for _, value := range servers {
		sort.Sort(ingress.LocationByPath(value.Locations))
		aServers = append(aServers, value)
	}
	sort.Sort(ingress.ServerByName(aServers))

	return aUpstreams, aServers
}