Signed-off-by: Goutham Veeramachaneni <cs14btech11014@iith.ac.in>pull/3152/head
commit
3f0267c548
@ -0,0 +1,185 @@ |
||||
// 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 ( |
||||
"fmt" |
||||
|
||||
"github.com/go-kit/kit/log" |
||||
"github.com/go-kit/kit/log/level" |
||||
"github.com/prometheus/common/model" |
||||
"github.com/prometheus/prometheus/config" |
||||
"github.com/prometheus/prometheus/util/strutil" |
||||
"golang.org/x/net/context" |
||||
"k8s.io/client-go/pkg/apis/extensions/v1beta1" |
||||
"k8s.io/client-go/tools/cache" |
||||
) |
||||
|
||||
// Ingress implements discovery of Kubernetes ingresss.
|
||||
type Ingress struct { |
||||
logger log.Logger |
||||
informer cache.SharedInformer |
||||
store cache.Store |
||||
} |
||||
|
||||
// NewIngress returns a new ingress discovery.
|
||||
func NewIngress(l log.Logger, inf cache.SharedInformer) *Ingress { |
||||
return &Ingress{logger: l, informer: inf, store: inf.GetStore()} |
||||
} |
||||
|
||||
// Run implements the TargetProvider interface.
|
||||
func (s *Ingress) Run(ctx context.Context, ch chan<- []*config.TargetGroup) { |
||||
// Send full initial set of pod targets.
|
||||
var initial []*config.TargetGroup |
||||
for _, o := range s.store.List() { |
||||
tg := s.buildIngress(o.(*v1beta1.Ingress)) |
||||
initial = append(initial, tg) |
||||
} |
||||
select { |
||||
case <-ctx.Done(): |
||||
return |
||||
case ch <- initial: |
||||
} |
||||
|
||||
// Send target groups for ingress updates.
|
||||
send := func(tg *config.TargetGroup) { |
||||
select { |
||||
case <-ctx.Done(): |
||||
case ch <- []*config.TargetGroup{tg}: |
||||
} |
||||
} |
||||
s.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ |
||||
AddFunc: func(o interface{}) { |
||||
eventCount.WithLabelValues("ingress", "add").Inc() |
||||
|
||||
ingress, err := convertToIngress(o) |
||||
if err != nil { |
||||
level.Error(s.logger).Log("msg", "converting to Ingress object failed", "err", err.Error()) |
||||
return |
||||
} |
||||
send(s.buildIngress(ingress)) |
||||
}, |
||||
DeleteFunc: func(o interface{}) { |
||||
eventCount.WithLabelValues("ingress", "delete").Inc() |
||||
|
||||
ingress, err := convertToIngress(o) |
||||
if err != nil { |
||||
level.Error(s.logger).Log("msg", "converting to Ingress object failed", "err", err.Error()) |
||||
return |
||||
} |
||||
send(&config.TargetGroup{Source: ingressSource(ingress)}) |
||||
}, |
||||
UpdateFunc: func(_, o interface{}) { |
||||
eventCount.WithLabelValues("ingress", "update").Inc() |
||||
|
||||
ingress, err := convertToIngress(o) |
||||
if err != nil { |
||||
level.Error(s.logger).Log("msg", "converting to Ingress object failed", "err", err.Error()) |
||||
return |
||||
} |
||||
send(s.buildIngress(ingress)) |
||||
}, |
||||
}) |
||||
|
||||
// Block until the target provider is explicitly canceled.
|
||||
<-ctx.Done() |
||||
} |
||||
|
||||
func convertToIngress(o interface{}) (*v1beta1.Ingress, error) { |
||||
ingress, ok := o.(*v1beta1.Ingress) |
||||
if ok { |
||||
return ingress, nil |
||||
} |
||||
|
||||
deletedState, ok := o.(cache.DeletedFinalStateUnknown) |
||||
if !ok { |
||||
return nil, fmt.Errorf("Received unexpected object: %v", o) |
||||
} |
||||
ingress, ok = deletedState.Obj.(*v1beta1.Ingress) |
||||
if !ok { |
||||
return nil, fmt.Errorf("DeletedFinalStateUnknown contained non-Ingress object: %v", deletedState.Obj) |
||||
} |
||||
return ingress, nil |
||||
} |
||||
|
||||
func ingressSource(s *v1beta1.Ingress) string { |
||||
return "ingress/" + s.Namespace + "/" + s.Name |
||||
} |
||||
|
||||
const ( |
||||
ingressNameLabel = metaLabelPrefix + "ingress_name" |
||||
ingressLabelPrefix = metaLabelPrefix + "ingress_label_" |
||||
ingressAnnotationPrefix = metaLabelPrefix + "ingress_annotation_" |
||||
ingressSchemeLabel = metaLabelPrefix + "ingress_scheme" |
||||
ingressHostLabel = metaLabelPrefix + "ingress_host" |
||||
ingressPathLabel = metaLabelPrefix + "ingress_path" |
||||
) |
||||
|
||||
func ingressLabels(ingress *v1beta1.Ingress) model.LabelSet { |
||||
ls := make(model.LabelSet, len(ingress.Labels)+len(ingress.Annotations)+2) |
||||
ls[ingressNameLabel] = lv(ingress.Name) |
||||
ls[namespaceLabel] = lv(ingress.Namespace) |
||||
|
||||
for k, v := range ingress.Labels { |
||||
ln := strutil.SanitizeLabelName(ingressLabelPrefix + k) |
||||
ls[model.LabelName(ln)] = lv(v) |
||||
} |
||||
|
||||
for k, v := range ingress.Annotations { |
||||
ln := strutil.SanitizeLabelName(ingressAnnotationPrefix + k) |
||||
ls[model.LabelName(ln)] = lv(v) |
||||
} |
||||
return ls |
||||
} |
||||
|
||||
func pathsFromIngressRule(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 (s *Ingress) buildIngress(ingress *v1beta1.Ingress) *config.TargetGroup { |
||||
tg := &config.TargetGroup{ |
||||
Source: ingressSource(ingress), |
||||
} |
||||
tg.Labels = ingressLabels(ingress) |
||||
|
||||
schema := "http" |
||||
if ingress.Spec.TLS != nil { |
||||
schema = "https" |
||||
} |
||||
for _, rule := range ingress.Spec.Rules { |
||||
paths := pathsFromIngressRule(&rule.IngressRuleValue) |
||||
|
||||
for _, path := range paths { |
||||
tg.Targets = append(tg.Targets, model.LabelSet{ |
||||
model.AddressLabel: lv(rule.Host), |
||||
ingressSchemeLabel: lv(schema), |
||||
ingressHostLabel: lv(rule.Host), |
||||
ingressPathLabel: lv(path), |
||||
}) |
||||
} |
||||
} |
||||
|
||||
return tg |
||||
} |
||||
@ -0,0 +1,136 @@ |
||||
// 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 ( |
||||
"testing" |
||||
|
||||
"github.com/prometheus/common/model" |
||||
"github.com/prometheus/prometheus/config" |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
"k8s.io/client-go/pkg/apis/extensions/v1beta1" |
||||
) |
||||
|
||||
func ingressStoreKeyFunc(obj interface{}) (string, error) { |
||||
return obj.(*v1beta1.Ingress).ObjectMeta.Name, nil |
||||
} |
||||
|
||||
func newFakeIngressInformer() *fakeInformer { |
||||
return newFakeInformer(ingressStoreKeyFunc) |
||||
} |
||||
|
||||
func makeTestIngressDiscovery() (*Ingress, *fakeInformer) { |
||||
i := newFakeIngressInformer() |
||||
return NewIngress(nil, i), i |
||||
} |
||||
|
||||
func makeIngress(tls []v1beta1.IngressTLS) *v1beta1.Ingress { |
||||
return &v1beta1.Ingress{ |
||||
ObjectMeta: metav1.ObjectMeta{ |
||||
Name: "testingress", |
||||
Namespace: "default", |
||||
Labels: map[string]string{"testlabel": "testvalue"}, |
||||
Annotations: map[string]string{"testannotation": "testannotationvalue"}, |
||||
}, |
||||
Spec: v1beta1.IngressSpec{ |
||||
TLS: tls, |
||||
Rules: []v1beta1.IngressRule{ |
||||
{ |
||||
Host: "example.com", |
||||
IngressRuleValue: v1beta1.IngressRuleValue{ |
||||
HTTP: &v1beta1.HTTPIngressRuleValue{ |
||||
Paths: []v1beta1.HTTPIngressPath{ |
||||
{Path: "/"}, |
||||
{Path: "/foo"}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
// No backend config, ignored
|
||||
Host: "nobackend.example.com", |
||||
IngressRuleValue: v1beta1.IngressRuleValue{ |
||||
HTTP: &v1beta1.HTTPIngressRuleValue{}, |
||||
}, |
||||
}, |
||||
{ |
||||
Host: "test.example.com", |
||||
IngressRuleValue: v1beta1.IngressRuleValue{ |
||||
HTTP: &v1beta1.HTTPIngressRuleValue{ |
||||
Paths: []v1beta1.HTTPIngressPath{{}}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func expectedTargetGroups(tls bool) []*config.TargetGroup { |
||||
scheme := "http" |
||||
if tls { |
||||
scheme = "https" |
||||
} |
||||
return []*config.TargetGroup{ |
||||
{ |
||||
Targets: []model.LabelSet{ |
||||
{ |
||||
"__meta_kubernetes_ingress_scheme": lv(scheme), |
||||
"__meta_kubernetes_ingress_host": "example.com", |
||||
"__meta_kubernetes_ingress_path": "/", |
||||
"__address__": "example.com", |
||||
}, |
||||
{ |
||||
"__meta_kubernetes_ingress_scheme": lv(scheme), |
||||
"__meta_kubernetes_ingress_host": "example.com", |
||||
"__meta_kubernetes_ingress_path": "/foo", |
||||
"__address__": "example.com", |
||||
}, |
||||
{ |
||||
"__meta_kubernetes_ingress_scheme": lv(scheme), |
||||
"__meta_kubernetes_ingress_host": "test.example.com", |
||||
"__address__": "test.example.com", |
||||
"__meta_kubernetes_ingress_path": "/", |
||||
}, |
||||
}, |
||||
Labels: model.LabelSet{ |
||||
"__meta_kubernetes_ingress_name": "testingress", |
||||
"__meta_kubernetes_namespace": "default", |
||||
"__meta_kubernetes_ingress_label_testlabel": "testvalue", |
||||
"__meta_kubernetes_ingress_annotation_testannotation": "testannotationvalue", |
||||
}, |
||||
Source: "ingress/default/testingress", |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func TestIngressDiscoveryInitial(t *testing.T) { |
||||
n, i := makeTestIngressDiscovery() |
||||
i.GetStore().Add(makeIngress(nil)) |
||||
|
||||
k8sDiscoveryTest{ |
||||
discovery: n, |
||||
expectedInitial: expectedTargetGroups(false), |
||||
}.Run(t) |
||||
} |
||||
|
||||
func TestIngressDiscoveryInitialTLS(t *testing.T) { |
||||
n, i := makeTestIngressDiscovery() |
||||
i.GetStore().Add(makeIngress([]v1beta1.IngressTLS{{}})) |
||||
|
||||
k8sDiscoveryTest{ |
||||
discovery: n, |
||||
expectedInitial: expectedTargetGroups(true), |
||||
}.Run(t) |
||||
} |
||||
@ -0,0 +1,75 @@ |
||||
// Copyright 2017 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 pool |
||||
|
||||
import "sync" |
||||
|
||||
// BytesPool is a bucketed pool for variably sized byte slices.
|
||||
type BytesPool struct { |
||||
buckets []sync.Pool |
||||
sizes []int |
||||
} |
||||
|
||||
// NewBytesPool returns a new BytesPool with size buckets for minSize to maxSize
|
||||
// increasing by the given factor.
|
||||
func NewBytesPool(minSize, maxSize int, factor float64) *BytesPool { |
||||
if minSize < 1 { |
||||
panic("invalid minimum pool size") |
||||
} |
||||
if maxSize < 1 { |
||||
panic("invalid maximum pool size") |
||||
} |
||||
if factor < 1 { |
||||
panic("invalid factor") |
||||
} |
||||
|
||||
var sizes []int |
||||
|
||||
for s := minSize; s <= maxSize; s = int(float64(s) * factor) { |
||||
sizes = append(sizes, s) |
||||
} |
||||
|
||||
p := &BytesPool{ |
||||
buckets: make([]sync.Pool, len(sizes)), |
||||
sizes: sizes, |
||||
} |
||||
|
||||
return p |
||||
} |
||||
|
||||
// Get returns a new byte slices that fits the given size.
|
||||
func (p *BytesPool) Get(sz int) []byte { |
||||
for i, bktSize := range p.sizes { |
||||
if sz > bktSize { |
||||
continue |
||||
} |
||||
b, ok := p.buckets[i].Get().([]byte) |
||||
if !ok { |
||||
b = make([]byte, 0, bktSize) |
||||
} |
||||
return b |
||||
} |
||||
return make([]byte, 0, sz) |
||||
} |
||||
|
||||
// Put returns a byte slice to the right bucket in the pool.
|
||||
func (p *BytesPool) Put(b []byte) { |
||||
for i, bktSize := range p.sizes { |
||||
if cap(b) > bktSize { |
||||
continue |
||||
} |
||||
p.buckets[i].Put(b[:0]) |
||||
return |
||||
} |
||||
} |
||||
Loading…
Reference in new issue