1package main 2 3import ( 4 "flag" 5 "fmt" 6 "os" 7 "path/filepath" 8 "sync" 9 "syscall" 10 11 "github.com/BurntSushi/toml" 12 "github.com/judwhite/go-svc" 13 "github.com/mreiferson/go-options" 14 "github.com/nsqio/nsq/internal/app" 15 "github.com/nsqio/nsq/internal/lg" 16 "github.com/nsqio/nsq/internal/version" 17 "github.com/nsqio/nsq/nsqadmin" 18) 19 20func nsqadminFlagSet(opts *nsqadmin.Options) *flag.FlagSet { 21 flagSet := flag.NewFlagSet("nsqadmin", flag.ExitOnError) 22 23 flagSet.String("config", "", "path to config file") 24 flagSet.Bool("version", false, "print version string") 25 26 logLevel := opts.LogLevel 27 flagSet.Var(&logLevel, "log-level", "set log verbosity: debug, info, warn, error, or fatal") 28 flagSet.String("log-prefix", "[nsqadmin] ", "log message prefix") 29 flagSet.Bool("verbose", false, "[deprecated] has no effect, use --log-level") 30 31 flagSet.String("http-address", opts.HTTPAddress, "<addr>:<port> to listen on for HTTP clients") 32 flagSet.String("base-path", opts.BasePath, "URL base path") 33 34 flagSet.String("graphite-url", opts.GraphiteURL, "graphite HTTP address") 35 flagSet.Bool("proxy-graphite", false, "proxy HTTP requests to graphite") 36 37 flagSet.String("statsd-counter-format", opts.StatsdCounterFormat, "The counter stats key formatting applied by the implementation of statsd. If no formatting is desired, set this to an empty string.") 38 flagSet.String("statsd-gauge-format", opts.StatsdGaugeFormat, "The gauge stats key formatting applied by the implementation of statsd. If no formatting is desired, set this to an empty string.") 39 flagSet.String("statsd-prefix", opts.StatsdPrefix, "prefix used for keys sent to statsd (%s for host replacement, must match nsqd)") 40 flagSet.Duration("statsd-interval", opts.StatsdInterval, "time interval nsqd is configured to push to statsd (must match nsqd)") 41 42 flagSet.String("notification-http-endpoint", "", "HTTP endpoint (fully qualified) to which POST notifications of admin actions will be sent") 43 44 flagSet.Duration("http-client-connect-timeout", opts.HTTPClientConnectTimeout, "timeout for HTTP connect") 45 flagSet.Duration("http-client-request-timeout", opts.HTTPClientRequestTimeout, "timeout for HTTP request") 46 47 flagSet.Bool("http-client-tls-insecure-skip-verify", false, "configure the HTTP client to skip verification of TLS certificates") 48 flagSet.String("http-client-tls-root-ca-file", "", "path to CA file for the HTTP client") 49 flagSet.String("http-client-tls-cert", "", "path to certificate file for the HTTP client") 50 flagSet.String("http-client-tls-key", "", "path to key file for the HTTP client") 51 52 flagSet.String("allow-config-from-cidr", opts.AllowConfigFromCIDR, "A CIDR from which to allow HTTP requests to the /config endpoint") 53 flagSet.String("acl-http-header", opts.AclHttpHeader, "HTTP header to check for authenticated admin users") 54 55 nsqlookupdHTTPAddresses := app.StringArray{} 56 flagSet.Var(&nsqlookupdHTTPAddresses, "lookupd-http-address", "lookupd HTTP address (may be given multiple times)") 57 nsqdHTTPAddresses := app.StringArray{} 58 flagSet.Var(&nsqdHTTPAddresses, "nsqd-http-address", "nsqd HTTP address (may be given multiple times)") 59 adminUsers := app.StringArray{} 60 flagSet.Var(&adminUsers, "admin-user", "admin user (may be given multiple times; if specified, only these users will be able to perform privileged actions; acl-http-header is used to determine the authenticated user)") 61 62 return flagSet 63} 64 65type program struct { 66 once sync.Once 67 nsqadmin *nsqadmin.NSQAdmin 68} 69 70func main() { 71 prg := &program{} 72 if err := svc.Run(prg, syscall.SIGINT, syscall.SIGTERM); err != nil { 73 logFatal("%s", err) 74 } 75} 76 77func (p *program) Init(env svc.Environment) error { 78 if env.IsWindowsService() { 79 dir := filepath.Dir(os.Args[0]) 80 return os.Chdir(dir) 81 } 82 return nil 83} 84 85func (p *program) Start() error { 86 opts := nsqadmin.NewOptions() 87 88 flagSet := nsqadminFlagSet(opts) 89 flagSet.Parse(os.Args[1:]) 90 91 if flagSet.Lookup("version").Value.(flag.Getter).Get().(bool) { 92 fmt.Println(version.String("nsqadmin")) 93 os.Exit(0) 94 } 95 96 var cfg config 97 configFile := flagSet.Lookup("config").Value.String() 98 if configFile != "" { 99 _, err := toml.DecodeFile(configFile, &cfg) 100 if err != nil { 101 logFatal("failed to load config file %s - %s", configFile, err) 102 } 103 } 104 cfg.Validate() 105 106 options.Resolve(opts, flagSet, cfg) 107 nsqadmin, err := nsqadmin.New(opts) 108 if err != nil { 109 logFatal("failed to instantiate nsqadmin - %s", err) 110 } 111 p.nsqadmin = nsqadmin 112 113 go func() { 114 err := p.nsqadmin.Main() 115 if err != nil { 116 p.Stop() 117 os.Exit(1) 118 } 119 }() 120 121 return nil 122} 123 124func (p *program) Stop() error { 125 p.once.Do(func() { 126 p.nsqadmin.Exit() 127 }) 128 return nil 129} 130 131func logFatal(f string, args ...interface{}) { 132 lg.LogFatal("[nsqadmin] ", f, args...) 133} 134