func main() { opts := optparse.Parser( "Usage: ampzero </path/to/instance/directory> [options]\n", "ampzero 0.0.0") debug := opts.Bool([]string{"-d", "--debug"}, false, "enable debug mode") frontendHost := opts.StringConfig("frontend-host", "", "the host to bind the Frontend Server to") frontendPort := opts.IntConfig("frontend-port", 9040, "the port to bind the Frontend Server to [default: 9040]") frontendTLS := opts.BoolConfig("frontend-tls", false, "use TLS (HTTPS) for the Frontend Server [default: false]") certFile := opts.StringConfig("cert-file", "cert/frontend.cert", "the path to the TLS certificate [default: cert/frontend.cert]") keyFile := opts.StringConfig("key-file", "cert/frontend.key", "the path to the TLS key [default: cert/frontend.key]") officialHost := opts.StringConfig("official-host", "", "if set, limit the Frontend Server to the specified host") noRedirect := opts.BoolConfig("no-redirect", false, "disable the HTTP Redirector [default: false]") httpHost := opts.StringConfig("http-host", "", "the host to bind the HTTP Redirector to") httpPort := opts.IntConfig("http-port", 9080, "the port to bind the HTTP Redirector to [default: 9080]") redirectURL := opts.StringConfig("redirect-url", "", "the URL that the HTTP Redirector redirects to") gaeHost := opts.StringConfig("gae-host", "localhost", "the App Engine host to connect to [default: localhost]") gaePort := opts.IntConfig("gae-port", 8080, "the App Engine port to connect to [default: 8080]") gaeTLS := opts.BoolConfig("gae-tls", false, "use TLS when connecting to App Engine [default: false]") logRotate := opts.StringConfig("log-rotate", "never", "specify one of 'hourly', 'daily' or 'never' [default: never]") noConsoleLog := opts.BoolConfig("no-console-log", false, "disable logging to stdout/stderr [default: false]") os.Args[0] = "ampzero" args := opts.Parse(os.Args) var instanceDirectory string if len(args) >= 1 { if args[0] == "help" { opts.PrintUsage() runtime.Exit(0) } instanceDirectory = path.Clean(args[0]) } else { opts.PrintUsage() runtime.Exit(0) } rootInfo, err := os.Stat(instanceDirectory) if err == nil { if !rootInfo.IsDirectory() { runtime.Error("ERROR: %q is not a directory\n", instanceDirectory) } } else { runtime.Error("ERROR: %s\n", err) } configPath := path.Join(instanceDirectory, "ampzero.yaml") _, err = os.Stat(configPath) if err == nil { err = opts.ParseConfig(configPath, os.Args) if err != nil { runtime.Error("ERROR: %s\n", err) } } logPath := path.Join(instanceDirectory, "log") err = os.MkdirAll(logPath, 0755) if err != nil { runtime.Error("ERROR: %s\n", err) } runPath := path.Join(instanceDirectory, "run") err = os.MkdirAll(runPath, 0755) if err != nil { runtime.Error("ERROR: %s\n", err) } _, err = runtime.GetLock(runPath, "ampzero") if err != nil { runtime.Error("ERROR: Couldn't successfully acquire a process lock:\n\n\t%s\n\n", err) } go runtime.CreatePidFile(path.Join(runPath, "ampzero.pid")) if *frontendTLS { var exitProcess bool if len(*certFile) == 0 { fmt.Printf("ERROR: The cert-file config value hasn't been specified.\n") exitProcess = true } if len(*keyFile) == 0 { fmt.Printf("ERROR: The key-file config value hasn't been specified.\n") exitProcess = true } if exitProcess { runtime.Exit(1) } } // Initialise the Ampify runtime -- which will run ``ampzero`` on multiple // processors if possible. runtime.Init() // Initialise the TLS config. tlsconf.Init() debugMode = *debug gaeAddr := fmt.Sprintf("%s:%d", *gaeHost, *gaePort) frontendAddr := fmt.Sprintf("%s:%d", *frontendHost, *frontendPort) frontendConn, err := net.Listen("tcp", frontendAddr) if err != nil { runtime.Error("ERROR: Cannot listen on %s: %v\n", frontendAddr, err) } var frontendListener net.Listener if *frontendTLS { certPath := path.Join(instanceDirectory, *certFile) keyPath := path.Join(instanceDirectory, *keyFile) tlsConfig := &tls.Config{ NextProtos: []string{"http/1.1"}, Rand: rand.Reader, Time: time.Seconds, } tlsConfig.Certificates = make([]tls.Certificate, 1) tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(certPath, keyPath) if err != nil { runtime.Error("ERROR: Couldn't load certificate/key pair: %s\n", err) } frontendListener = tls.NewListener(frontendConn, tlsConfig) } else { frontendListener = frontendConn } var enforceHost bool var officialRedirectURL string var officialRedirectHTML []byte if len(*officialHost) != 0 { enforceHost = true if *frontendTLS { officialRedirectURL = "https://" + *officialHost + "/" } else { officialRedirectURL = "http://" + *officialHost + "/" } officialRedirectHTML = []byte(fmt.Sprintf(redirectHTML, officialRedirectURL)) } var frontendScheme, frontendAddrURL, httpAddrURL string if *frontendTLS { frontendScheme = "https://" } else { frontendScheme = "http://" } if len(*frontendHost) == 0 { frontendAddrURL = fmt.Sprintf("%slocalhost:%d", frontendScheme, *frontendPort) } else { frontendAddrURL = fmt.Sprintf("%s%s:%d", frontendScheme, *frontendHost, *frontendPort) } if len(*httpHost) == 0 { httpAddrURL = fmt.Sprintf("http://localhost:%d", *httpPort) } else { httpAddrURL = fmt.Sprintf("http://%s:%d", *httpHost, *httpPort) } var httpAddr string var httpListener net.Listener if !*noRedirect { if *redirectURL == "" { *redirectURL = frontendAddrURL } httpAddr = fmt.Sprintf("%s:%d", *httpHost, *httpPort) httpListener, err = net.Listen("tcp", httpAddr) if err != nil { runtime.Error("ERROR: Cannot listen on %s: %v\n", httpAddr, err) } } var rotate int switch *logRotate { case "daily": rotate = logging.RotateDaily case "hourly": rotate = logging.RotateHourly case "never": rotate = logging.RotateNever default: runtime.Error("ERROR: Unknown log rotation format %q\n", *logRotate) } if !*noConsoleLog { logging.AddConsoleLogger() logging.AddFilter(filterRequestLog) } _, err = logging.AddFileLogger("ampzero", logPath, rotate) if err != nil { runtime.Error("ERROR: Couldn't initialise logfile: %s\n", err) } fmt.Printf("Running ampzero with %d CPUs:\n", runtime.CPUCount) if !*noRedirect { redirector := &Redirector{url: *redirectURL} go func() { err = http.Serve(httpListener, redirector) if err != nil { runtime.Error("ERROR serving HTTP Redirector: %s\n", err) } }() fmt.Printf("* HTTP Redirector running on %s -> %s\n", httpAddrURL, *redirectURL) } frontend := &Frontend{ gaeAddr: gaeAddr, gaeHost: *gaeHost, gaeTLS: *gaeTLS, officialHost: *officialHost, officialRedirectURL: officialRedirectURL, officialRedirectHTML: officialRedirectHTML, enforceHost: enforceHost, } fmt.Printf("* Frontend Server running on %s\n", frontendAddrURL) err = http.Serve(frontendListener, frontend) if err != nil { runtime.Error("ERROR serving Frontend Server: %s\n", err) } }
func DefaultOpts(name string, opts *optparse.OptionParser, argv []string, consoleFilter logging.Filter) (bool, string, string) { var ( configPath string instanceDirectory string err os.Error ) debug := opts.Bool([]string{"-d", "--debug"}, false, "enable debug mode") genConfig := opts.Bool([]string{"-g", "--gen-config"}, false, "show the default yaml config") runDirectory := opts.StringConfig("run-dir", "run", "the path to the run directory to store locks, pid files, etc. [run]") logDirectory := opts.StringConfig("log-dir", "log", "the path to the log directory [log]") logRotate := opts.StringConfig("log-rotate", "never", "specify one of 'hourly', 'daily' or 'never' [never]") noConsoleLog := opts.BoolConfig("no-console-log", false, "disable server requests being logged to the console [false]") extraConfig := opts.StringConfig("extra-config", "", "path to a YAML config file with additional options") // Parse the command line options. args := opts.Parse(argv) // Print the default YAML config file if the ``-g`` flag was specified. if *genConfig { opts.PrintDefaultConfigFile(name) Exit(0) } // Assume the parent directory of the config as the instance directory. if len(args) >= 1 { configPath, err = filepath.Abs(filepath.Clean(args[0])) if err != nil { StandardError(err) } err = opts.ParseConfig(configPath, os.Args) if err != nil { StandardError(err) } instanceDirectory, _ = filepath.Split(configPath) } else { opts.PrintUsage() Exit(0) } // Load the extra config file with additional options if one has been // specified. if *extraConfig != "" { extraConfigPath, err := filepath.Abs(filepath.Clean(*extraConfig)) if err != nil { StandardError(err) } extraConfigPath = JoinPath(instanceDirectory, extraConfigPath) err = opts.ParseConfig(extraConfigPath, os.Args) if err != nil { StandardError(err) } } // Create the log directory if it doesn't exist. logPath := JoinPath(instanceDirectory, *logDirectory) err = os.MkdirAll(logPath, 0755) if err != nil { StandardError(err) } // Create the run directory if it doesn't exist. runPath := JoinPath(instanceDirectory, *runDirectory) err = os.MkdirAll(runPath, 0755) if err != nil { StandardError(err) } // Setup the file and console logging. var rotate int switch *logRotate { case "daily": rotate = logging.RotateDaily case "hourly": rotate = logging.RotateHourly case "never": rotate = logging.RotateNever default: Error("ERROR: Unknown log rotation format %q\n", *logRotate) } if !*noConsoleLog { logging.AddConsoleLogger() logging.AddConsoleFilter(consoleFilter) } _, err = logging.AddFileLogger(name, logPath, rotate, logging.InfoLog) if err != nil { Error("ERROR: Couldn't initialise logfile: %s\n", err) } _, err = logging.AddFileLogger("error", logPath, rotate, logging.ErrorLog) if err != nil { Error("ERROR: Couldn't initialise logfile: %s\n", err) } // Initialise the runtime -- which will run the process on multiple // processors if possible. Init() // Initialise the process-related resources. InitProcess(name, runPath) return *debug, instanceDirectory, runPath }