-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1693 from LuxChanLu/gloo-proxy
feat: add gloo proxy source
- Loading branch information
Showing
7 changed files
with
643 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# Configuring ExternalDNS to use the Gloo Proxy Source | ||
This tutorial describes how to configure ExternalDNS to use the Gloo Proxy source. | ||
It is meant to supplement the other provider-specific setup tutorials. | ||
|
||
### Manifest (for clusters without RBAC enabled) | ||
```yaml | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: external-dns | ||
spec: | ||
strategy: | ||
type: Recreate | ||
selector: | ||
matchLabels: | ||
app: external-dns | ||
template: | ||
metadata: | ||
labels: | ||
app: external-dns | ||
spec: | ||
containers: | ||
- name: external-dns | ||
# update this to the desired external-dns version | ||
image: k8s.gcr.io/external-dns/external-dns:v0.7.6 | ||
args: | ||
- --source=gloo-proxy | ||
- --gloo-namespace=custom-gloo-system # gloo system namespace. Omit to use the default (gloo-system) | ||
- --provider=aws | ||
- --registry=txt | ||
- --txt-owner-id=my-identifier | ||
``` | ||
### Manifest (for clusters with RBAC enabled) | ||
Could be change if you have mulitple sources | ||
```yaml | ||
apiVersion: v1 | ||
kind: ServiceAccount | ||
metadata: | ||
name: external-dns | ||
--- | ||
apiVersion: rbac.authorization.k8s.io/v1beta1 | ||
kind: ClusterRole | ||
metadata: | ||
name: external-dns | ||
rules: | ||
- apiGroups: [""] | ||
resources: ["services","endpoints","pods"] | ||
verbs: ["get","watch","list"] | ||
- apiGroups: [""] | ||
resources: ["nodes"] | ||
verbs: ["list","watch"] | ||
- apiGroups: ["gloo.solo.io"] | ||
resources: ["proxies"] | ||
verbs: ["get","watch","list"] | ||
- apiGroups: ["gateway.solo.io"] | ||
resources: ["virtualservices"] | ||
verbs: ["get", "list", "watch"] | ||
--- | ||
apiVersion: rbac.authorization.k8s.io/v1beta1 | ||
kind: ClusterRoleBinding | ||
metadata: | ||
name: external-dns-viewer | ||
roleRef: | ||
apiGroup: rbac.authorization.k8s.io | ||
kind: ClusterRole | ||
name: external-dns | ||
subjects: | ||
- kind: ServiceAccount | ||
name: external-dns | ||
namespace: default | ||
--- | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: external-dns | ||
spec: | ||
strategy: | ||
type: Recreate | ||
selector: | ||
matchLabels: | ||
app: external-dns | ||
template: | ||
metadata: | ||
labels: | ||
app: external-dns | ||
spec: | ||
serviceAccountName: external-dns | ||
containers: | ||
- name: external-dns | ||
# update this to the desired external-dns version | ||
image: k8s.gcr.io/external-dns/external-dns:v0.7.6 | ||
args: | ||
- --source=gloo-proxy | ||
- --gloo-namespace=custom-gloo-system # gloo system namespace. Omit to use the default (gloo-system) | ||
- --provider=aws | ||
- --registry=txt | ||
- --txt-owner-id=my-identifier | ||
``` | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
/* | ||
Copyright 2020n The Kubernetes 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 source | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"strings" | ||
|
||
log "github.com/sirupsen/logrus" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/client-go/dynamic" | ||
"k8s.io/client-go/kubernetes" | ||
|
||
"sigs.k8s.io/external-dns/endpoint" | ||
) | ||
|
||
var ( | ||
proxyGVR = schema.GroupVersionResource{ | ||
Group: "gloo.solo.io", | ||
Version: "v1", | ||
Resource: "proxies", | ||
} | ||
virtualServiceGVR = schema.GroupVersionResource{ | ||
Group: "gateway.solo.io", | ||
Version: "v1", | ||
Resource: "virtualservices", | ||
} | ||
) | ||
|
||
// Basic redefinition of "Proxy" CRD : https://github.com/solo-io/gloo/blob/v1.4.6/projects/gloo/pkg/api/v1/proxy.pb.go | ||
type proxy struct { | ||
metav1.TypeMeta `json:",inline"` | ||
Metadata metav1.ObjectMeta `json:"metadata,omitempty"` | ||
Spec proxySpec `json:"spec,omitempty"` | ||
} | ||
|
||
type proxySpec struct { | ||
Listeners []proxySpecListener `json:"listeners,omitempty"` | ||
} | ||
|
||
type proxySpecListener struct { | ||
HTTPListener proxySpecHTTPListener `json:"httpListener,omitempty"` | ||
} | ||
|
||
type proxySpecHTTPListener struct { | ||
VirtualHosts []proxyVirtualHost `json:"virtualHosts,omitempty"` | ||
} | ||
|
||
type proxyVirtualHost struct { | ||
Domains []string `json:"domains,omitempty"` | ||
Metadata proxyVirtualHostMetadata `json:"metadata,omitempty"` | ||
} | ||
|
||
type proxyVirtualHostMetadata struct { | ||
Source []proxyVirtualHostMetadataSource `json:"sources,omitempty"` | ||
} | ||
|
||
type proxyVirtualHostMetadataSource struct { | ||
Kind string `json:"kind,omitempty"` | ||
Name string `json:"name,omitempty"` | ||
Namespace string `json:"namespace,omitempty"` | ||
} | ||
|
||
type glooSource struct { | ||
dynamicKubeClient dynamic.Interface | ||
kubeClient kubernetes.Interface | ||
glooNamespace string | ||
} | ||
|
||
// NewGlooSource creates a new glooSource with the given config | ||
func NewGlooSource(dynamicKubeClient dynamic.Interface, kubeClient kubernetes.Interface, glooNamespace string) (Source, error) { | ||
return &glooSource{ | ||
dynamicKubeClient, | ||
kubeClient, | ||
glooNamespace, | ||
}, nil | ||
} | ||
|
||
func (gs *glooSource) AddEventHandler(ctx context.Context, handler func()) { | ||
} | ||
|
||
// Endpoints returns endpoint objects | ||
func (gs *glooSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) { | ||
endpoints := []*endpoint.Endpoint{} | ||
|
||
proxies, err := gs.dynamicKubeClient.Resource(proxyGVR).Namespace(gs.glooNamespace).List(ctx, metav1.ListOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, obj := range proxies.Items { | ||
proxy := proxy{} | ||
jsonString, err := obj.MarshalJSON() | ||
if err != nil { | ||
return nil, err | ||
} | ||
err = json.Unmarshal(jsonString, &proxy) | ||
if err != nil { | ||
return nil, err | ||
} | ||
log.Debugf("Gloo: Find %s proxy", proxy.Metadata.Name) | ||
proxyTargets, err := gs.proxyTargets(ctx, proxy.Metadata.Name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
log.Debugf("Gloo[%s]: Find %d target(s) (%+v)", proxy.Metadata.Name, len(proxyTargets), proxyTargets) | ||
proxyEndpoints, err := gs.generateEndpointsFromProxy(ctx, &proxy, proxyTargets) | ||
if err != nil { | ||
return nil, err | ||
} | ||
log.Debugf("Gloo[%s]: Generate %d endpoint(s)", proxy.Metadata.Name, len(proxyEndpoints)) | ||
endpoints = append(endpoints, proxyEndpoints...) | ||
} | ||
return endpoints, nil | ||
} | ||
|
||
func (gs *glooSource) generateEndpointsFromProxy(ctx context.Context, proxy *proxy, targets endpoint.Targets) ([]*endpoint.Endpoint, error) { | ||
endpoints := []*endpoint.Endpoint{} | ||
for _, listener := range proxy.Spec.Listeners { | ||
for _, virtualHost := range listener.HTTPListener.VirtualHosts { | ||
annotations, err := gs.annotationsFromProxySource(ctx, virtualHost) | ||
if err != nil { | ||
return nil, err | ||
} | ||
ttl, err := getTTLFromAnnotations(annotations) | ||
if err != nil { | ||
return nil, err | ||
} | ||
providerSpecific, setIdentifier := getProviderSpecificAnnotations(annotations) | ||
for _, domain := range virtualHost.Domains { | ||
endpoints = append(endpoints, endpointsForHostname(strings.TrimSuffix(domain, "."), targets, ttl, providerSpecific, setIdentifier)...) | ||
} | ||
} | ||
} | ||
return endpoints, nil | ||
} | ||
|
||
func (gs *glooSource) annotationsFromProxySource(ctx context.Context, virtualHost proxyVirtualHost) (map[string]string, error) { | ||
annotations := map[string]string{} | ||
for _, src := range virtualHost.Metadata.Source { | ||
kind := sourceKind(src.Kind) | ||
if kind != nil { | ||
source, err := gs.dynamicKubeClient.Resource(*kind).Namespace(src.Namespace).Get(ctx, src.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for key, value := range source.GetAnnotations() { | ||
annotations[key] = value | ||
} | ||
} | ||
} | ||
return annotations, nil | ||
} | ||
|
||
func (gs *glooSource) proxyTargets(ctx context.Context, name string) (endpoint.Targets, error) { | ||
svc, err := gs.kubeClient.CoreV1().Services(gs.glooNamespace).Get(ctx, name, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var targets endpoint.Targets | ||
switch svc.Spec.Type { | ||
case corev1.ServiceTypeLoadBalancer: | ||
for _, lb := range svc.Status.LoadBalancer.Ingress { | ||
if lb.IP != "" { | ||
targets = append(targets, lb.IP) | ||
} | ||
if lb.Hostname != "" { | ||
targets = append(targets, lb.Hostname) | ||
} | ||
} | ||
default: | ||
log.WithField("gateway", name).WithField("service", svc).Warn("Gloo: Proxy service type not supported") | ||
} | ||
return targets, nil | ||
} | ||
|
||
func sourceKind(kind string) *schema.GroupVersionResource { | ||
switch kind { | ||
case "*v1.VirtualService": | ||
return &virtualServiceGVR | ||
} | ||
return nil | ||
} |
Oops, something went wrong.