Skip to content

Commit

Permalink
allow setting flags via env vars (#124)
Browse files Browse the repository at this point in the history
* feat(config): change defaults, switch flag processing to kingpin

* chore: vendor kingpin as a dependency

* feat(config): auto-detect cluster config from the environment

* chore: clean up definition of flags

* chore: sanitize flags even further

* chore: update changelog with latest flags changes

* fix(aws): fix messed up test name
  • Loading branch information
linki authored Apr 27, 2017
1 parent 82a172a commit da3c17a
Show file tree
Hide file tree
Showing 85 changed files with 14,710 additions and 302 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
Features:
- Improved logging
- Changed the flags to the v0.3 semantics, the following has changed:
1. The TXT registry is used by default and has an owner ID of `default`
2. `--dry-run` is disabled by default
3. The `--compatibility` flag was added and takes a string instead of a boolean
4. The `--in-cluster` flag has been dropped for auto-detection
5. The `--zone` specifier has been replaced by a `--domain-filter` that filters domains by suffix
- Improved logging output
- Generate DNS Name from template for services/ingress if annotation is missing but `--fqdn-template` is specified
- Route 53, Google CloudDNS: Support creation of records in multiple hosted zones.
- Route 53: Support creation of ALIAS records when endpoint target is a ELB/ALB.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ SOURCES = $(shell find . -name '*.go')
IMAGE ?= registry.opensource.zalan.do/teapot/$(BINARY)
VERSION ?= $(shell git describe --tags --always --dirty)
BUILD_FLAGS ?= -v
LDFLAGS ?= -X main.version=$(VERSION) -w -s
LDFLAGS ?= -X github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns.version=$(VERSION) -w -s

build: build/$(BINARY)

Expand Down
16 changes: 12 additions & 4 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package: github.com/kubernetes-incubator/external-dns
import:
- package: github.com/Sirupsen/logrus
version: ~0.11.5
- package: github.com/alecthomas/kingpin
version: ~2.2.4
- package: github.com/aws/aws-sdk-go
version: ~1.7.9
subpackages:
Expand Down
35 changes: 11 additions & 24 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package main

import (
"fmt"
"net/http"
"os"
"os/signal"
Expand All @@ -37,26 +36,13 @@ import (
"github.com/kubernetes-incubator/external-dns/provider"
"github.com/kubernetes-incubator/external-dns/registry"
"github.com/kubernetes-incubator/external-dns/source"
"github.com/spf13/pflag"
)

var (
version = "unknown"
)

func main() {
cfg := externaldns.NewConfig()
if err := cfg.ParseFlags(os.Args); err != nil {
if err == pflag.ErrHelp {
os.Exit(0)
}
if err := cfg.ParseFlags(os.Args[1:]); err != nil {
log.Fatalf("flag parsing error: %v", err)
}
if cfg.Version {
fmt.Println(version)
os.Exit(0)
}

log.Infof("config: %+v", cfg)

if err := validation.ValidateConfig(cfg); err != nil {
Expand Down Expand Up @@ -105,9 +91,9 @@ func main() {
var p provider.Provider
switch cfg.Provider {
case "google":
p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.Domain, cfg.DryRun)
p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DomainFilter, cfg.DryRun)
case "aws":
p, err = provider.NewAWSProvider(cfg.Domain, cfg.DryRun)
p, err = provider.NewAWSProvider(cfg.DomainFilter, cfg.DryRun)
default:
log.Fatalf("unknown dns provider: %s", cfg.Provider)
}
Expand All @@ -120,7 +106,7 @@ func main() {
case "noop":
r, err = registry.NewNoopRegistry(p)
case "txt":
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.RecordOwnerID)
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTOwnerID)
default:
log.Fatalf("unknown registry: %s", cfg.Registry)
}
Expand All @@ -135,7 +121,6 @@ func main() {
}

ctrl := controller.Controller{
Zone: cfg.Zone,
Source: multiSource,
Registry: r,
Policy: policy,
Expand Down Expand Up @@ -167,22 +152,24 @@ func handleSigterm(stopChan chan struct{}) {
}

func newClient(cfg *externaldns.Config) (*kubernetes.Clientset, error) {
if !cfg.InCluster && cfg.KubeConfig == "" {
cfg.KubeConfig = clientcmd.RecommendedHomeFile
if cfg.KubeConfig == "" {
if _, err := os.Stat(clientcmd.RecommendedHomeFile); err == nil {
cfg.KubeConfig = clientcmd.RecommendedHomeFile
}
}

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

log.Infof("targeting cluster at %s", config.Host)

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

log.Infof("Connected to cluster at %s", config.Host)

return client, nil
}

Expand Down
118 changes: 77 additions & 41 deletions pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,56 @@ package externaldns
import (
"time"

"github.com/spf13/pflag"

"k8s.io/client-go/pkg/api/v1"
"github.com/alecthomas/kingpin"
)

var (
defaultMetricsAddress = ":7979"
defaultLogFormat = "text"
version = "unknown"
)

// Config is a project-wide configuration
type Config struct {
InCluster bool
Master string
KubeConfig string
Namespace string
Zone string
Domain string
Sources []string
Namespace string
FqdnTemplate string
Compatibility string
Provider string
GoogleProject string
DomainFilter string
Policy string
Compatibility string
MetricsAddress string
Registry string
TXTOwnerID string
TXTPrefix string
Interval time.Duration
Once bool
DryRun bool
Debug bool
LogFormat string
Version bool
Registry string
RecordOwnerID string
TXTPrefix string
FqdnTemplate string
MetricsAddress string
Debug bool
}

var defaultConfig = &Config{
Master: "",
KubeConfig: "",
Sources: nil,
Namespace: "",
FqdnTemplate: "",
Compatibility: "",
Provider: "",
GoogleProject: "",
DomainFilter: "",
Policy: "sync",
Registry: "txt",
TXTOwnerID: "default",
TXTPrefix: "",
Interval: time.Minute,
Once: false,
DryRun: false,
LogFormat: "text",
MetricsAddress: ":7979",
Debug: false,
}

// NewConfig returns new Config object
Expand All @@ -61,28 +78,47 @@ func NewConfig() *Config {

// ParseFlags adds and parses flags from command line
func (cfg *Config) ParseFlags(args []string) error {
flags := pflag.NewFlagSet("external-dns", pflag.ContinueOnError)
flags.BoolVar(&cfg.InCluster, "in-cluster", false, "whether to use in-cluster config")
flags.StringVar(&cfg.KubeConfig, "kubeconfig", "", "path to a local kubeconfig file")
flags.StringVar(&cfg.Namespace, "namespace", v1.NamespaceAll, "the namespace to look for endpoints; all namespaces by default")
flags.StringVar(&cfg.Zone, "zone", "", "the ID of the hosted zone to target")
flags.StringVar(&cfg.Domain, "domain", "example.org.", "the name of the top-level domain to manage")
flags.StringArrayVar(&cfg.Sources, "source", nil, "the sources to gather endpoints: [service, ingress], e.g. --source service --source ingress")
flags.StringVar(&cfg.Provider, "provider", "", "the DNS provider to materialize the records in: <aws|google>")
flags.StringVar(&cfg.GoogleProject, "google-project", "", "gcloud project to target")
flags.StringVar(&cfg.Policy, "policy", "sync", "the policy to use: <sync|upsert-only>")
flags.StringVar(&cfg.Compatibility, "compatibility", "", "enable to process annotation semantics from legacy implementations: <mate|molecule>")
flags.StringVar(&cfg.MetricsAddress, "metrics-address", defaultMetricsAddress, "address to expose metrics on")
flags.StringVar(&cfg.LogFormat, "log-format", defaultLogFormat, "log format output: <text|json>")
flags.DurationVar(&cfg.Interval, "interval", time.Minute, "interval between synchronizations")
flags.BoolVar(&cfg.Once, "once", false, "run once and exit")
flags.BoolVar(&cfg.DryRun, "dry-run", true, "run without updating DNS provider")
flags.BoolVar(&cfg.Debug, "debug", false, "debug mode")
flags.BoolVar(&cfg.Version, "version", false, "display the version")
flags.StringVar(&cfg.Registry, "registry", "noop", "type of registry for ownership: <noop|txt>")
flags.StringVar(&cfg.RecordOwnerID, "record-owner-id", "", "id for keeping track of the managed records")
flags.StringVar(&cfg.TXTPrefix, "txt-prefix", "", `prefix assigned to DNS name of the associated TXT record; e.g. for --txt-prefix=abc_ [CNAME example.org] <-> [TXT abc_example.org]`)
flags.StringVar(&cfg.FqdnTemplate, "fqdn-template", "", `fallback template to generate DNS name if annotation is missing;
e.g. --fqdn-template={{.Name}}-{{.Namespace}}.example.org will use service/ingress name/namespace`)
return flags.Parse(args)
app := kingpin.New("external-dns", "ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers.")
app.Version(version)
app.DefaultEnvars()

// Flags related to Kubernetes
app.Flag("master", "The Kubernetes API server to connect to (default: auto-detect)").Default(defaultConfig.Master).StringVar(&cfg.Master)
app.Flag("kubeconfig", "Retrieve target cluster configuration from a Kubernetes configuration file (default: auto-detect)").Default(defaultConfig.KubeConfig).StringVar(&cfg.KubeConfig)

// Flags related to processing sources
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress")
app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves (optional)").Default(defaultConfig.FqdnTemplate).StringVar(&cfg.FqdnTemplate)
app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule")

// Flags related to providers
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, google)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "google")
app.Flag("google-project", "When using the Google provider, specify the Google project (required when --provider=google)").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject)
app.Flag("domain-filter", "Limit possible target zones by a domain suffix (optional)").Default(defaultConfig.DomainFilter).StringVar(&cfg.DomainFilter)

// Flags related to policies
app.Flag("policy", "Modify how DNS records are sychronized between sources and providers (default: sync, options: sync, upsert-only)").Default(defaultConfig.Policy).EnumVar(&cfg.Policy, "sync", "upsert-only")

// Flags related to the registry
app.Flag("registry", "The registry implementation to use to keep track of DNS record ownership (default: txt, options: txt, noop)").Default(defaultConfig.Registry).EnumVar(&cfg.Registry, "txt", "noop")
app.Flag("txt-owner-id", "When using the TXT registry, a name that identifies this instance of ExternalDNS (default: default)").Default(defaultConfig.TXTOwnerID).StringVar(&cfg.TXTOwnerID)
app.Flag("txt-prefix", "When using the TXT registry, a custom string that's prefixed to each ownership DNS record (optional)").Default(defaultConfig.TXTPrefix).StringVar(&cfg.TXTPrefix)

// Flags related to the main control loop
app.Flag("interval", "The interval between two consecutive synchronizations in duration format (default: 1m)").Default(defaultConfig.Interval.String()).DurationVar(&cfg.Interval)
app.Flag("once", "When enabled, exits the synchronization loop after the first iteration (default: disabled)").BoolVar(&cfg.Once)
app.Flag("dry-run", "When enabled, prints DNS record changes rather than actually performing them (default: disabled)").BoolVar(&cfg.DryRun)

// Miscellaneous flags
app.Flag("log-format", "The format in which log messages are printed (default: text, options: text, json)").Default(defaultConfig.LogFormat).EnumVar(&cfg.LogFormat, "text", "json")
app.Flag("metrics-address", "Specify were to serve the metrics and health check endpoint (default: :7979)").Default(defaultConfig.MetricsAddress).StringVar(&cfg.MetricsAddress)
app.Flag("debug", "When enabled, increases the logging output for debugging purposes (default: disabled)").BoolVar(&cfg.Debug)

_, err := app.Parse(args)
if err != nil {
return err
}

return nil
}
Loading

0 comments on commit da3c17a

Please sign in to comment.