main.go 4.21 KB
Newer Older
ideahitme's avatar
ideahitme committed
1 2
/*
Copyright 2017 The Kubernetes Authors.
3

ideahitme's avatar
ideahitme committed
4 5 6
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
7

ideahitme's avatar
ideahitme committed
8
    http://www.apache.org/licenses/LICENSE-2.0
9

ideahitme's avatar
ideahitme committed
10 11 12 13 14 15 16
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.
*/

17 18 19 20 21 22 23 24 25 26 27
package main

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
28
	"github.com/prometheus/client_golang/prometheus/promhttp"
29

30 31 32
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"

33
	"github.com/kubernetes-incubator/external-dns/controller"
34 35
	"github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns"
	"github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns/validation"
36
	"github.com/kubernetes-incubator/external-dns/plan"
37
	"github.com/kubernetes-incubator/external-dns/provider"
Yerken's avatar
Yerken committed
38
	"github.com/kubernetes-incubator/external-dns/registry"
39
	"github.com/kubernetes-incubator/external-dns/source"
40
	"github.com/spf13/pflag"
41 42
)

43 44 45 46
var (
	version = "unknown"
)

47
func main() {
48
	cfg := externaldns.NewConfig()
ideahitme's avatar
ideahitme committed
49
	if err := cfg.ParseFlags(os.Args); err != nil {
50 51 52
		if err == pflag.ErrHelp {
			os.Exit(0)
		}
ideahitme's avatar
ideahitme committed
53 54
		log.Fatalf("flag parsing error: %v", err)
	}
55 56 57 58 59
	if cfg.Version {
		fmt.Println(version)
		os.Exit(0)
	}

60
	if err := validation.ValidateConfig(cfg); err != nil {
61
		log.Fatalf("config validation failed: %v", err)
62 63
	}

ideahitme's avatar
ideahitme committed
64
	if cfg.LogFormat == "json" {
65 66
		log.SetFormatter(&log.JSONFormatter{})
	}
67
	if cfg.DryRun {
ideahitme's avatar
ideahitme committed
68
		log.Info("running in dry-run mode. No changes to DNS records will be made.")
69
	}
ideahitme's avatar
ideahitme committed
70
	if cfg.Debug {
71 72 73 74 75
		log.SetLevel(log.DebugLevel)
	}

	stopChan := make(chan struct{}, 1)

76
	go serveMetrics(cfg.MetricsAddress)
77 78
	go handleSigterm(stopChan)

79 80 81 82 83
	client, err := newClient(cfg)
	if err != nil {
		log.Fatal(err)
	}

84
	source.Register("service", source.NewServiceSource(client, cfg.Namespace, cfg.Compatibility))
85 86
	source.Register("ingress", source.NewIngressSource(client, cfg.Namespace))

87 88 89 90 91 92
	sources, err := source.LookupMultiple(cfg.Sources)
	if err != nil {
		log.Fatal(err)
	}

	multiSource := source.NewMultiSource(sources)
93

94 95
	var p provider.Provider
	switch cfg.Provider {
96
	case "google":
97
		p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DryRun)
98
	case "aws":
99
		p, err = provider.NewAWSProvider(cfg.DryRun)
100
	default:
101
		log.Fatalf("unknown dns provider: %s", cfg.Provider)
102
	}
103 104 105 106
	if err != nil {
		log.Fatal(err)
	}

Yerken's avatar
Yerken committed
107 108 109 110 111 112 113 114 115 116
	var r registry.Registry
	switch cfg.Registry {
	case "noop":
		r, err = registry.NewNoopRegistry(p)
	case "txt":
		r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.RecordOwnerID)
	default:
		log.Fatalf("unknown registry: %s", cfg.Registry)
	}

Yerken's avatar
Yerken committed
117 118 119 120
	if err != nil {
		log.Fatal(err)
	}

121 122 123 124 125
	policy, exists := plan.Policies[cfg.Policy]
	if !exists {
		log.Fatalf("unknown policy: %s", cfg.Policy)
	}

126
	ctrl := controller.Controller{
127
		Zone:     cfg.Zone,
128
		Source:   multiSource,
Yerken's avatar
Yerken committed
129
		Registry: r,
130
		Policy:   policy,
131
		Interval: cfg.Interval,
132 133
	}

134
	if cfg.Once {
135 136 137 138 139 140
		err := ctrl.RunOnce()
		if err != nil {
			log.Fatal(err)
		}

		os.Exit(0)
141 142
	}

143
	ctrl.Run(stopChan)
144 145 146 147 148 149 150 151 152 153 154 155 156
	for {
		log.Infoln("pod waiting to be deleted")
		time.Sleep(time.Second * 30)
	}
}

func handleSigterm(stopChan chan struct{}) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM)
	<-signals
	log.Infoln("received SIGTERM. Terminating...")
	close(stopChan)
}
157 158 159 160 161 162 163 164 165 166 167

func newClient(cfg *externaldns.Config) (*kubernetes.Clientset, error) {
	if !cfg.InCluster && cfg.KubeConfig == "" {
		cfg.KubeConfig = clientcmd.RecommendedHomeFile
	}

	config, err := clientcmd.BuildConfigFromFlags("", cfg.KubeConfig)
	if err != nil {
		return nil, err
	}

ideahitme's avatar
ideahitme committed
168
	log.Infof("targeting cluster at %s", config.Host)
169 170 171 172 173 174 175 176

	client, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return client, nil
}
177 178 179 180 181 182 183 184 185 186 187

func serveMetrics(address string) {
	http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	http.Handle("/metrics", promhttp.Handler())

	log.Fatal(http.ListenAndServe(address, nil))
}