示例#1
0
文件: ampzero.go 项目: strogo/ampify
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)
	}

}
示例#2
0
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

}