diff options
author | 2016-03-18 20:57:35 +0000 | |
---|---|---|
committer | 2016-03-18 20:57:35 +0000 | |
commit | 3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d (patch) | |
tree | fae74c33cfed05de603785294593275f1901c861 /main.go | |
download | coredns-3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d.tar.gz coredns-3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d.tar.zst coredns-3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d.zip |
First commit
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/main.go b/main.go new file mode 100644 index 000000000..d35b0a5ee --- /dev/null +++ b/main.go @@ -0,0 +1,232 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "runtime" + "strconv" + "strings" + "time" + + "github.com/miekg/coredns/core" + "github.com/miekg/coredns/core/https" + "github.com/xenolf/lego/acme" + "gopkg.in/natefinch/lumberjack.v2" +) + +func init() { + core.TrapSignals() + setVersion() + flag.BoolVar(&https.Agreed, "agree", false, "Agree to Let's Encrypt Subscriber Agreement") + flag.StringVar(&https.CAUrl, "ca", "https://acme-v01.api.letsencrypt.org/directory", "Certificate authority ACME server") + flag.StringVar(&conf, "conf", "", "Configuration file to use (default="+core.DefaultConfigFile+")") + flag.StringVar(&cpu, "cpu", "100%", "CPU cap") + flag.StringVar(&https.DefaultEmail, "email", "", "Default Let's Encrypt account email address") + flag.DurationVar(&core.GracefulTimeout, "grace", 5*time.Second, "Maximum duration of graceful shutdown") + flag.StringVar(&core.Host, "host", core.DefaultHost, "Default host") + flag.StringVar(&logfile, "log", "", "Process log file") + flag.StringVar(&core.PidFile, "pidfile", "", "Path to write pid file") + flag.StringVar(&core.Port, "port", core.DefaultPort, "Default port") + flag.BoolVar(&core.Quiet, "quiet", false, "Quiet mode (no initialization output)") + flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate") + flag.StringVar(&core.Root, "root", core.DefaultRoot, "Root path to default site") + flag.BoolVar(&version, "version", false, "Show version") +} + +func main() { + flag.Parse() // called here in main() to allow other packages to set flags in their inits + + core.AppName = appName + core.AppVersion = appVersion + acme.UserAgent = appName + "/" + appVersion + + // set up process log before anything bad happens + switch logfile { + case "stdout": + log.SetOutput(os.Stdout) + case "stderr": + log.SetOutput(os.Stderr) + case "": + log.SetOutput(ioutil.Discard) + default: + log.SetOutput(&lumberjack.Logger{ + Filename: logfile, + MaxSize: 100, + MaxAge: 14, + MaxBackups: 10, + }) + } + + if revoke != "" { + err := https.Revoke(revoke) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Revoked certificate for %s\n", revoke) + os.Exit(0) + } + if version { + fmt.Printf("%s %s\n", appName, appVersion) + if devBuild && gitShortStat != "" { + fmt.Printf("%s\n%s\n", gitShortStat, gitFilesModified) + } + os.Exit(0) + } + + // Set CPU cap + err := setCPU(cpu) + if err != nil { + mustLogFatal(err) + } + + // Get Corefile input + caddyfile, err := core.LoadCaddyfile(loadCaddyfile) + if err != nil { + mustLogFatal(err) + } + + // Start your engines + err = core.Start(caddyfile) + if err != nil { + mustLogFatal(err) + } + + // Twiddle your thumbs + core.Wait() +} + +// mustLogFatal just wraps log.Fatal() in a way that ensures the +// output is always printed to stderr so the user can see it +// if the user is still there, even if the process log was not +// enabled. If this process is a restart, however, and the user +// might not be there anymore, this just logs to the process log +// and exits. +func mustLogFatal(args ...interface{}) { + if !core.IsRestart() { + log.SetOutput(os.Stderr) + } + log.Fatal(args...) +} + +func loadCaddyfile() (core.Input, error) { + // Try -conf flag + if conf != "" { + if conf == "stdin" { + return core.CaddyfileFromPipe(os.Stdin) + } + + contents, err := ioutil.ReadFile(conf) + if err != nil { + return nil, err + } + + return core.CaddyfileInput{ + Contents: contents, + Filepath: conf, + RealFile: true, + }, nil + } + + // command line args + if flag.NArg() > 0 { + confBody := core.Host + ":" + core.Port + "\n" + strings.Join(flag.Args(), "\n") + return core.CaddyfileInput{ + Contents: []byte(confBody), + Filepath: "args", + }, nil + } + + // Caddyfile in cwd + contents, err := ioutil.ReadFile(core.DefaultConfigFile) + if err != nil { + if os.IsNotExist(err) { + return core.DefaultInput(), nil + } + return nil, err + } + return core.CaddyfileInput{ + Contents: contents, + Filepath: core.DefaultConfigFile, + RealFile: true, + }, nil +} + +// setCPU parses string cpu and sets GOMAXPROCS +// according to its value. It accepts either +// a number (e.g. 3) or a percent (e.g. 50%). +func setCPU(cpu string) error { + var numCPU int + + availCPU := runtime.NumCPU() + + if strings.HasSuffix(cpu, "%") { + // Percent + var percent float32 + pctStr := cpu[:len(cpu)-1] + pctInt, err := strconv.Atoi(pctStr) + if err != nil || pctInt < 1 || pctInt > 100 { + return errors.New("invalid CPU value: percentage must be between 1-100") + } + percent = float32(pctInt) / 100 + numCPU = int(float32(availCPU) * percent) + } else { + // Number + num, err := strconv.Atoi(cpu) + if err != nil || num < 1 { + return errors.New("invalid CPU value: provide a number or percent greater than 0") + } + numCPU = num + } + + if numCPU > availCPU { + numCPU = availCPU + } + + runtime.GOMAXPROCS(numCPU) + return nil +} + +// setVersion figures out the version information based on +// variables set by -ldflags. +func setVersion() { + // A development build is one that's not at a tag or has uncommitted changes + devBuild = gitTag == "" || gitShortStat != "" + + // Only set the appVersion if -ldflags was used + if gitNearestTag != "" || gitTag != "" { + if devBuild && gitNearestTag != "" { + appVersion = fmt.Sprintf("%s (+%s %s)", + strings.TrimPrefix(gitNearestTag, "v"), gitCommit, buildDate) + } else if gitTag != "" { + appVersion = strings.TrimPrefix(gitTag, "v") + } + } +} + +const appName = "Caddy" + +// Flags that control program flow or startup +var ( + conf string + cpu string + logfile string + revoke string + version bool +) + +// Build information obtained with the help of -ldflags +var ( + appVersion = "(untracked dev build)" // inferred at startup + devBuild = true // inferred at startup + + buildDate string // date -u + gitTag string // git describe --exact-match HEAD 2> /dev/null + gitNearestTag string // git describe --abbrev=0 --tags HEAD + gitCommit string // git rev-parse HEAD + gitShortStat string // git diff-index --shortstat + gitFilesModified string // git diff-index --name-only HEAD +) |