Skip to content

Commit

Permalink
Kubernetes SD: Introduce ingressAdaptor
Browse files Browse the repository at this point in the history
Signed-off-by: Takashi Kusumi <tkusumi@zlab.co.jp>
  • Loading branch information
tksm committed Aug 20, 2021
1 parent 6634a57 commit 40981c4
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 109 deletions.
140 changes: 31 additions & 109 deletions discovery/kubernetes/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,26 +114,23 @@ func (i *Ingress) process(ctx context.Context, ch chan<- []*targetgroup.Group) b
return true
}

var ia ingressAdaptor
switch ingress := o.(type) {
case *v1.Ingress:
send(ctx, ch, i.buildIngress(ingress))
return true
ia = newIngressAdaptorFromV1(ingress)
case *v1beta1.Ingress:
send(ctx, ch, i.buildIngressV1beta1(ingress))
ia = newIngressAdaptorFromV1beta1(ingress)
default:
level.Error(i.logger).Log("msg", "converting to Ingress object failed", "err",
errors.Errorf("received unexpected object: %v", o))
return true
}

level.Error(i.logger).Log("msg", "converting to Ingress object failed", "err",
errors.Errorf("received unexpected object: %v", o))
send(ctx, ch, i.buildIngress(ia))
return true
}

func ingressSource(s *v1.Ingress) string {
return ingressSourceFromNamespaceAndName(s.Namespace, s.Name)
}

func ingressSourceV1beta1(s *v1beta1.Ingress) string {
return ingressSourceFromNamespaceAndName(s.Namespace, s.Name)
func ingressSource(s ingressAdaptor) string {
return ingressSourceFromNamespaceAndName(s.namespace(), s.name())
}

func ingressSourceFromNamespaceAndName(namespace, name string) string {
Expand All @@ -152,144 +149,69 @@ const (
ingressClassNameLabel = metaLabelPrefix + "ingress_class_name"
)

func ingressLabels(ingress *v1.Ingress) model.LabelSet {
func ingressLabels(ingress ingressAdaptor) model.LabelSet {
// Each label and annotation will create two key-value pairs in the map.
ls := make(model.LabelSet, 2*(len(ingress.Labels)+len(ingress.Annotations))+2)
ls[ingressNameLabel] = lv(ingress.Name)
ls[namespaceLabel] = lv(ingress.Namespace)
if ingress.Spec.IngressClassName != nil {
ls[ingressClassNameLabel] = lv(*ingress.Spec.IngressClassName)
ls := make(model.LabelSet, 2*(len(ingress.labels())+len(ingress.annotations()))+2)
ls[ingressNameLabel] = lv(ingress.name())
ls[namespaceLabel] = lv(ingress.namespace())
if cls := ingress.ingressClassName(); cls != nil {
ls[ingressClassNameLabel] = lv(*cls)
}

for k, v := range ingress.Labels {
for k, v := range ingress.labels() {
ln := strutil.SanitizeLabelName(k)
ls[model.LabelName(ingressLabelPrefix+ln)] = lv(v)
ls[model.LabelName(ingressLabelPresentPrefix+ln)] = presentValue
}

for k, v := range ingress.Annotations {
for k, v := range ingress.annotations() {
ln := strutil.SanitizeLabelName(k)
ls[model.LabelName(ingressAnnotationPrefix+ln)] = lv(v)
ls[model.LabelName(ingressAnnotationPresentPrefix+ln)] = presentValue
}
return ls
}

func ingressLabelsV1beta1(ingress *v1beta1.Ingress) model.LabelSet {
// Each label and annotation will create two key-value pairs in the map.
ls := make(model.LabelSet, 2*(len(ingress.Labels)+len(ingress.Annotations))+2)
ls[ingressNameLabel] = lv(ingress.Name)
ls[namespaceLabel] = lv(ingress.Namespace)
if ingress.Spec.IngressClassName != nil {
ls[ingressClassNameLabel] = lv(*ingress.Spec.IngressClassName)
}

for k, v := range ingress.Labels {
ln := strutil.SanitizeLabelName(k)
ls[model.LabelName(ingressLabelPrefix+ln)] = lv(v)
ls[model.LabelName(ingressLabelPresentPrefix+ln)] = presentValue
}

for k, v := range ingress.Annotations {
ln := strutil.SanitizeLabelName(k)
ls[model.LabelName(ingressAnnotationPrefix+ln)] = lv(v)
ls[model.LabelName(ingressAnnotationPresentPrefix+ln)] = presentValue
}
return ls
}

func pathsFromIngressRule(rv *v1.IngressRuleValue) []string {
if rv.HTTP == nil {
func pathsFromIngressPaths(ingressPaths []string) []string {
if ingressPaths == nil {
return []string{"/"}
}
paths := make([]string, len(rv.HTTP.Paths))
for n, p := range rv.HTTP.Paths {
path := p.Path
if path == "" {
paths := make([]string, len(ingressPaths))
for n, p := range ingressPaths {
path := p
if p == "" {
path = "/"
}
paths[n] = path
}
return paths
}

func pathsFromIngressRuleV1beta1(rv *v1beta1.IngressRuleValue) []string {
if rv.HTTP == nil {
return []string{"/"}
}
paths := make([]string, len(rv.HTTP.Paths))
for n, p := range rv.HTTP.Paths {
path := p.Path
if path == "" {
path = "/"
}
paths[n] = path
}
return paths
}

func (i *Ingress) buildIngress(ingress *v1.Ingress) *targetgroup.Group {
func (i *Ingress) buildIngress(ingress ingressAdaptor) *targetgroup.Group {
tg := &targetgroup.Group{
Source: ingressSource(ingress),
}
tg.Labels = ingressLabels(ingress)

tlsHosts := make(map[string]struct{})
for _, tls := range ingress.Spec.TLS {
for _, host := range tls.Hosts {
tlsHosts[host] = struct{}{}
}
}

for _, rule := range ingress.Spec.Rules {
paths := pathsFromIngressRule(&rule.IngressRuleValue)

scheme := "http"
_, isTLS := tlsHosts[rule.Host]
if isTLS {
scheme = "https"
}

for _, path := range paths {
tg.Targets = append(tg.Targets, model.LabelSet{
model.AddressLabel: lv(rule.Host),
ingressSchemeLabel: lv(scheme),
ingressHostLabel: lv(rule.Host),
ingressPathLabel: lv(path),
})
}
}

return tg
}

func (i *Ingress) buildIngressV1beta1(ingress *v1beta1.Ingress) *targetgroup.Group {
tg := &targetgroup.Group{
Source: ingressSourceV1beta1(ingress),
}
tg.Labels = ingressLabelsV1beta1(ingress)

tlsHosts := make(map[string]struct{})
for _, tls := range ingress.Spec.TLS {
for _, host := range tls.Hosts {
tlsHosts[host] = struct{}{}
}
for _, host := range ingress.tlsHosts() {
tlsHosts[host] = struct{}{}
}

for _, rule := range ingress.Spec.Rules {
paths := pathsFromIngressRuleV1beta1(&rule.IngressRuleValue)
for _, rule := range ingress.rules() {
paths := pathsFromIngressPaths(rule.paths())

scheme := "http"
_, isTLS := tlsHosts[rule.Host]
_, isTLS := tlsHosts[rule.host()]
if isTLS {
scheme = "https"
}

for _, path := range paths {
tg.Targets = append(tg.Targets, model.LabelSet{
model.AddressLabel: lv(rule.Host),
model.AddressLabel: lv(rule.host()),
ingressSchemeLabel: lv(scheme),
ingressHostLabel: lv(rule.Host),
ingressHostLabel: lv(rule.host()),
ingressPathLabel: lv(path),
})
}
Expand Down
145 changes: 145 additions & 0 deletions discovery/kubernetes/ingress_adaptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright 2016 The Prometheus 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 kubernetes

import (
v1 "k8s.io/api/networking/v1"
"k8s.io/api/networking/v1beta1"
)

// ingressAdaptor is an adaptor for the different Ingress versions
type ingressAdaptor interface {
name() string
namespace() string
labels() map[string]string
annotations() map[string]string
tlsHosts() []string
ingressClassName() *string
rules() []ingressRuleAdaptor
}

type ingressRuleAdaptor interface {
paths() []string
host() string
}

// Adaptor for networking.k8s.io/v1
type ingressAdaptorV1 struct {
ingress *v1.Ingress
}

func newIngressAdaptorFromV1(ingress *v1.Ingress) ingressAdaptor {
return &ingressAdaptorV1{ingress: ingress}
}

func (i *ingressAdaptorV1) name() string { return i.ingress.Name }
func (i *ingressAdaptorV1) namespace() string { return i.ingress.Namespace }
func (i *ingressAdaptorV1) labels() map[string]string { return i.ingress.Labels }
func (i *ingressAdaptorV1) annotations() map[string]string { return i.ingress.Annotations }
func (i *ingressAdaptorV1) ingressClassName() *string { return i.ingress.Spec.IngressClassName }

func (i *ingressAdaptorV1) tlsHosts() []string {
var hosts []string
for _, tls := range i.ingress.Spec.TLS {
for _, host := range tls.Hosts {
hosts = append(hosts, host)
}
}
return hosts
}

func (i *ingressAdaptorV1) rules() []ingressRuleAdaptor {
var rules []ingressRuleAdaptor
for _, rule := range i.ingress.Spec.Rules {
rules = append(rules, newIngressRuleAdaptorFromV1(rule))
}
return rules
}

type ingressRuleAdaptorV1 struct {
rule v1.IngressRule
}

func newIngressRuleAdaptorFromV1(rule v1.IngressRule) ingressRuleAdaptor {
return &ingressRuleAdaptorV1{rule: rule}
}

func (i *ingressRuleAdaptorV1) paths() []string {
rv := i.rule.IngressRuleValue
if rv.HTTP == nil {
return nil
}
paths := make([]string, len(rv.HTTP.Paths))
for n, p := range rv.HTTP.Paths {
paths[n] = p.Path
}
return paths
}

func (i *ingressRuleAdaptorV1) host() string { return i.rule.Host }

// Adaptor for networking.k8s.io/v1beta1
type ingressAdaptorV1Beta1 struct {
ingress *v1beta1.Ingress
}

func newIngressAdaptorFromV1beta1(ingress *v1beta1.Ingress) ingressAdaptor {
return &ingressAdaptorV1Beta1{ingress: ingress}
}

func (i *ingressAdaptorV1Beta1) name() string { return i.ingress.Name }
func (i *ingressAdaptorV1Beta1) namespace() string { return i.ingress.Namespace }
func (i *ingressAdaptorV1Beta1) labels() map[string]string { return i.ingress.Labels }
func (i *ingressAdaptorV1Beta1) annotations() map[string]string { return i.ingress.Annotations }
func (i *ingressAdaptorV1Beta1) ingressClassName() *string { return i.ingress.Spec.IngressClassName }

func (i *ingressAdaptorV1Beta1) tlsHosts() []string {
var hosts []string
for _, tls := range i.ingress.Spec.TLS {
for _, host := range tls.Hosts {
hosts = append(hosts, host)
}
}
return hosts
}

func (i *ingressAdaptorV1Beta1) rules() []ingressRuleAdaptor {
var rules []ingressRuleAdaptor
for _, rule := range i.ingress.Spec.Rules {
rules = append(rules, newIngressRuleAdaptorFromV1Beta1(rule))
}
return rules
}

type ingressRuleAdaptorV1Beta1 struct {
rule v1beta1.IngressRule
}

func newIngressRuleAdaptorFromV1Beta1(rule v1beta1.IngressRule) ingressRuleAdaptor {
return &ingressRuleAdaptorV1Beta1{rule: rule}
}

func (i *ingressRuleAdaptorV1Beta1) paths() []string {
rv := i.rule.IngressRuleValue
if rv.HTTP == nil {
return nil
}
paths := make([]string, len(rv.HTTP.Paths))
for n, p := range rv.HTTP.Paths {
paths[n] = p.Path
}
return paths
}

func (i *ingressRuleAdaptorV1Beta1) host() string { return i.rule.Host }

0 comments on commit 40981c4

Please sign in to comment.