Merge pull request #6838 from brancz/endpointslice

discovery/kubernetes: EndpointSlice discovery
This commit is contained in:
Frederic Branczyk 2020-08-12 16:42:49 +02:00 committed by GitHub
commit 06e2c2f804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 1121 additions and 19 deletions

View file

@ -28,6 +28,7 @@ import (
config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model"
apiv1 "k8s.io/api/core/v1"
disv1beta1 "k8s.io/api/discovery/v1beta1"
"k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
@ -71,11 +72,12 @@ type Role string
// The valid options for Role.
const (
RoleNode Role = "node"
RolePod Role = "pod"
RoleService Role = "service"
RoleEndpoint Role = "endpoints"
RoleIngress Role = "ingress"
RoleNode Role = "node"
RolePod Role = "pod"
RoleService Role = "service"
RoleEndpoint Role = "endpoints"
RoleEndpointSlice Role = "endpointslice"
RoleIngress Role = "ingress"
)
// UnmarshalYAML implements the yaml.Unmarshaler interface.
@ -84,7 +86,7 @@ func (c *Role) UnmarshalYAML(unmarshal func(interface{}) error) error {
return err
}
switch *c {
case RoleNode, RolePod, RoleService, RoleEndpoint, RoleIngress:
case RoleNode, RolePod, RoleService, RoleEndpoint, RoleEndpointSlice, RoleIngress:
return nil
default:
return errors.Errorf("unknown Kubernetes SD role %q", *c)
@ -101,11 +103,12 @@ type SDConfig struct {
}
type roleSelector struct {
node resourceSelector
pod resourceSelector
service resourceSelector
endpoints resourceSelector
ingress resourceSelector
node resourceSelector
pod resourceSelector
service resourceSelector
endpoints resourceSelector
endpointslice resourceSelector
ingress resourceSelector
}
type SelectorConfig struct {
@ -128,7 +131,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
return err
}
if c.Role == "" {
return errors.Errorf("role missing (one of: pod, service, endpoints, node, ingress)")
return errors.Errorf("role missing (one of: pod, service, endpoints, endpointslice, node, ingress)")
}
err = c.HTTPClientConfig.Validate()
if err != nil {
@ -140,11 +143,12 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
foundSelectorRoles := make(map[Role]struct{})
allowedSelectors := map[Role][]string{
RolePod: {string(RolePod)},
RoleService: {string(RoleService)},
RoleEndpoint: {string(RolePod), string(RoleService), string(RoleEndpoint)},
RoleNode: {string(RoleNode)},
RoleIngress: {string(RoleIngress)},
RolePod: {string(RolePod)},
RoleService: {string(RoleService)},
RoleEndpointSlice: {string(RolePod), string(RoleService), string(RoleEndpointSlice)},
RoleEndpoint: {string(RolePod), string(RoleService), string(RoleEndpoint)},
RoleNode: {string(RoleNode)},
RoleIngress: {string(RoleIngress)},
}
for _, selector := range c.Selectors {
@ -154,7 +158,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
foundSelectorRoles[selector.Role] = struct{}{}
if _, ok := allowedSelectors[c.Role]; !ok {
return errors.Errorf("invalid role: %q, expecting one of: pod, service, endpoints, node or ingress", c.Role)
return errors.Errorf("invalid role: %q, expecting one of: pod, service, endpoints, endpointslice, node or ingress", c.Role)
}
var allowed bool
for _, role := range allowedSelectors[c.Role] {
@ -197,7 +201,7 @@ func init() {
prometheus.MustRegister(eventCount)
// Initialize metric vectors.
for _, role := range []string{"endpoints", "node", "pod", "service", "ingress"} {
for _, role := range []string{"endpointslice", "endpoints", "node", "pod", "service", "ingress"} {
for _, evt := range []string{"add", "delete", "update"} {
eventCount.WithLabelValues(role, evt)
}
@ -286,6 +290,9 @@ func mapSelector(rawSelector []SelectorConfig) roleSelector {
rs := roleSelector{}
for _, resourceSelectorRaw := range rawSelector {
switch resourceSelectorRaw.Role {
case RoleEndpointSlice:
rs.endpointslice.field = resourceSelectorRaw.Field
rs.endpointslice.label = resourceSelectorRaw.Label
case RoleEndpoint:
rs.endpoints.field = resourceSelectorRaw.Field
rs.endpoints.label = resourceSelectorRaw.Label
@ -314,6 +321,58 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
namespaces := d.getNamespaces()
switch d.role {
case RoleEndpointSlice:
for _, namespace := range namespaces {
e := d.client.DiscoveryV1beta1().EndpointSlices(namespace)
elw := &cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
options.FieldSelector = d.selectors.endpointslice.field
options.LabelSelector = d.selectors.endpointslice.label
return e.List(ctx, options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
options.FieldSelector = d.selectors.endpointslice.field
options.LabelSelector = d.selectors.endpointslice.label
return e.Watch(ctx, options)
},
}
s := d.client.CoreV1().Services(namespace)
slw := &cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
options.FieldSelector = d.selectors.service.field
options.LabelSelector = d.selectors.service.label
return s.List(ctx, options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
options.FieldSelector = d.selectors.service.field
options.LabelSelector = d.selectors.service.label
return s.Watch(ctx, options)
},
}
p := d.client.CoreV1().Pods(namespace)
plw := &cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
options.FieldSelector = d.selectors.pod.field
options.LabelSelector = d.selectors.pod.label
return p.List(ctx, options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
options.FieldSelector = d.selectors.pod.field
options.LabelSelector = d.selectors.pod.label
return p.Watch(ctx, options)
},
}
eps := NewEndpointSlice(
log.With(d.logger, "role", "endpointslice"),
cache.NewSharedInformer(slw, &apiv1.Service{}, resyncPeriod),
cache.NewSharedInformer(elw, &disv1beta1.EndpointSlice{}, resyncPeriod),
cache.NewSharedInformer(plw, &apiv1.Pod{}, resyncPeriod),
)
d.discoverers = append(d.discoverers, eps)
go eps.endpointSliceInf.Run(ctx.Done())
go eps.serviceInf.Run(ctx.Done())
go eps.podInf.Run(ctx.Done())
}
case RoleEndpoint:
for _, namespace := range namespaces {
e := d.client.CoreV1().Endpoints(namespace)