コード例 #1
0
ファイル: tlsconf.go プロジェクト: trojanspike/ampify
// Set the ``tlsconf.Config`` variable.
func Init() {
	path := runtime.AmpifyRoot + "/environ/local/share/cacerts/ca.cert"
	var err error
	Config, err = GenConfig(path)
	if err != nil {
		runtime.Error("ERROR: Couldn't load %s: %s\n", path, err)
	}
}
コード例 #2
0
ファイル: optparse.go プロジェクト: strogo/ampify
func (op *OptionParser) ParseConfig(filename string, args []string) (err os.Error) {

	data, err := yaml.ParseFile(filename)
	if err != nil {
		return err
	}

	for config, opt := range op.config2options {
		if opt.defined {
			continue
		}
		value, ok := data[config]
		if !ok {
			if opt.requiredConfig {
				runtime.Error("%s: error: required: %s", args[0], opt)
			} else {
				continue
			}
		}
		if opt.valueType == "bool" {
			if value == "true" || value == "on" || value == "yes" {
				*opt.boolValue = true
			} else if value == "false" || value == "off" || value == "no" {
				*opt.boolValue = false
			} else {
				runtime.Error("%s: error: invalid boolean value for %s: %q\n", args[0], config, value)
			}
		} else if opt.valueType == "string" {
			*opt.stringValue = value
		} else if opt.valueType == "int" {
			intValue, err := strconv.Atoi(value)
			if err != nil {
				runtime.Error("%s: error: couldn't convert the %s value %q to an integer\n", args[0], config, value)
			}
			*opt.intValue = intValue
		}
	}

	return nil

}
コード例 #3
0
ファイル: webserver.go プロジェクト: gitreview/ampify
func main() {

	opts := optparse.Parser("Usage: hubproxy [options]\n", "hubproxy 0.0.0")

	port := opts.Int([]string{"-p", "--port"}, 8010,
		"the port number to use [default: 8010]")

	host := opts.String([]string{"--host"}, "localhost",
		"the host to bind to")

	remote := opts.String([]string{"-r", "--remote"}, "ampcentral.appspot.com",
		"the remote host to connect to [default: ampcentral.appspot.com]")

	debug := opts.Bool([]string{"--debug"}, false,
		"enable debug mode")

	os.Args[0] = "hubproxy"
	args := opts.Parse(os.Args)

	if len(args) >= 1 {
		if args[0] == "help" {
			opts.PrintUsage()
			runtime.Exit(1)
		}
	}

	// Initialise the Ampify runtime -- which will run hubproxy on multiple
	// processors if possible.
	runtime.Init()

	// Initialise the TLS config.
	tlsconf.Init()

	debugMode = *debug
	remoteHost = *remote
	remoteAddr = *remote + ":443"
	addr := fmt.Sprintf("%s:%d", *host, *port)

	listener, err := net.Listen("tcp", addr)
	if err != nil {
		runtime.Error("Cannot listen on %s: %v\n", addr, err)
	}

	fmt.Printf("Running hubproxy with %d CPUs on %s\n",
		runtime.CPUCount, addr)

	proxy := &Proxy{}
	http.Serve(listener, proxy)

}
コード例 #4
0
ファイル: run.go プロジェクト: gitreview/ampify
func runProcess(amp, cmd, path, config string, console bool, quit chan bool) {

	var files []*os.File

	if console {
		files = []*os.File{nil, os.Stdout, os.Stderr}
	} else {
		files = []*os.File{nil, nil, nil}
	}

	logging.Info("Running: amp %s %s", cmd, config)

	process, err := os.StartProcess(
		amp,
		[]string{"amp", cmd, config},
		&os.ProcAttr{
			Dir:   path,
			Env:   os.Environ(),
			Files: files,
		})

	if err != nil {
		runtime.StandardError(err)
	}

	waitmsg, err := process.Wait(0)
	if err != nil {
		runtime.StandardError(err)
	}

	if waitmsg.ExitStatus() != 0 {
		runtime.Error("ERROR: Got %s when running `amp %s %s`\n",
			waitmsg, cmd, config)
	}

	quit <- true

}
コード例 #5
0
ファイル: live-server.go プロジェクト: elimisteve/togethr
func main() {

	// Define the options for the command line and config file options parser.
	opts := optparse.Parser(
		"Usage: live-server <config.yaml> [options]\n",
		"live-server 0.0.1")

	debug := opts.Bool([]string{"-d", "--debug"}, false,
		"enable debug mode")

	genConfig := opts.Bool([]string{"-g", "--gen-config"}, false,
		"show the default yaml config")

	frontendHost := opts.StringConfig("frontend-host", "",
		"the host to bind the HTTPS Frontends to")

	frontendPort := opts.IntConfig("frontend-port", 9040,
		"the base port for the HTTPS Frontends [9040]")

	officialHost := opts.StringConfig("offficial-host", "",
		"the official public host for the HTTPS Frontends")

	primaryHosts := opts.StringConfig("primary-hosts", "",
		"limit the primary HTTPS Frontend to the specified host pattern")

	primaryCert := opts.StringConfig("primary-cert", "cert/primary.cert",
		"the path to the primary host's TLS certificate [cert/primary.cert]")

	primaryKey := opts.StringConfig("primary-key", "cert/primary.key",
		"the path to the primary host's TLS key [cert/primary.key]")

	noSecondary := opts.BoolConfig("no-secondary", false,
		"disable the secondary HTTPS Frontend [false]")

	secondaryHosts := opts.StringConfig("secondary-hosts", "",
		"limit the secondary HTTPS Frontend to the specified host pattern")

	secondaryCert := opts.StringConfig("secondary-cert", "cert/secondary.cert",
		"the path to the secondary host's TLS certificate [cert/secondary.cert]")

	secondaryKey := opts.StringConfig("secondary-key", "cert/secondary.key",
		"the path to the secondary host's TLS key [cert/secondary.key]")

	errorDirectory := opts.StringConfig("error-dir", "error",
		"the path to the HTTP error files directory [error]")

	logDirectory := opts.StringConfig("log-dir", "log",
		"the path to the log directory [log]")

	runDirectory := opts.StringConfig("run-dir", "run",
		"the path to the run directory to store locks, pid files, etc. [run]")

	staticDirectory := opts.StringConfig("static-dir", "www",
		"the path to the static files directory [www]")

	staticMaxAge := opts.IntConfig("static-max-age", 86400,
		"max-age cache header value when serving the static files [86400]")

	noLivequery := opts.BoolConfig("no-livequery", false,
		"disable the LiveQuery node and WebSocket/Comet support [false]")

	websocketPrefix := opts.StringConfig("websocket-prefix", "/.live/ws",
		"URL path prefix for WebSocket requests [/.live/ws]")

	cometPrefix := opts.StringConfig("comet-prefix", "/.live/poll",
		"URL path prefix for Comet requests [/.live/poll]")

	livequeryHost := opts.StringConfig("livequery-host", "",
		"the host to bind the LiveQuery node to")

	livequeryPort := opts.IntConfig("livequery-port", 9050,
		"the port (both UDP and TCP) to bind the LiveQuery node to [9050]")

	livequeryExpiry := opts.IntConfig("livequery-expiry", 40,
		"maximum number of seconds a LiveQuery subscription is valid [40]")

	cookieKeyPath := opts.StringConfig("cookie-key", "cert/cookie.key",
		"the path to the file containing the key used to sign cookies [cert/cookie.key]")

	cookieName := opts.StringConfig("cookie-name", "user",
		"the property name of the cookie containing the user id [user]")

	acceptors := opts.StringConfig("acceptor-nodes", "localhost:9060",
		"comma-separated addresses of Acceptor nodes [localhost:9060]")

	acceptorKeyPath := opts.StringConfig("acceptor-key", "cert/acceptor.key",
		"the path to the file containing the Acceptor secret key [cert/acceptor.key]")

	runAcceptor := opts.BoolConfig("run-as-acceptor", false,
		"run as an Acceptor node [false]")

	acceptorIndex := opts.IntConfig("acceptor-index", 0,
		"this node's index in the Acceptor nodes address list [0]")

	leaseExpiry := opts.IntConfig("lease-expiry", 7,
		"maximum number of seconds a lease from an Acceptor node is valid [7]")

	noRedirect := opts.BoolConfig("no-redirect", false,
		"disable the HTTP Redirector [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 [9080]")

	redirectURL := opts.StringConfig("redirect-url", "",
		"the URL that the HTTP Redirector redirects to")

	pingPath := opts.StringConfig("ping-path", "/.ping",
		`URL path for a "ping" request [/.ping]`)

	enableHSTS := opts.BoolConfig("enable-hsts", false,
		"enable HTTP Strict Transport Security (HSTS) on redirects [false]")

	hstsMaxAge := opts.IntConfig("hsts-max-age", 50000000,
		"max-age value of HSTS in number of seconds [50000000]")

	upstreamHost := opts.StringConfig("upstream-host", "localhost",
		"the upstream host to connect to [localhost]")

	upstreamPort := opts.IntConfig("upstream-port", 8080,
		"the upstream port to connect to [8080]")

	upstreamTLS := opts.BoolConfig("upstream-tls", false,
		"use TLS when connecting to upstream [false]")

	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]")

	maintenanceMode := opts.BoolConfig("maintenance", false,
		"start up in maintenance mode [false]")

	extraConfig := opts.StringConfig("extra-config", "",
		"path to a YAML config file with additional options")

	// Parse the command line options.
	os.Args[0] = "live-server"
	args := opts.Parse(os.Args)

	// Print the default YAML config file if the ``-g`` flag was specified.
	if *genConfig {
		opts.PrintDefaultConfigFile("live-server")
		runtime.Exit(0)
	}

	// Setup the console logger early.
	if !*noConsoleLog {
		log.AddConsoleLogger()
		log.ConsoleFilters["ls"] = func(items []interface{}) (bool, []interface{}) {
			return true, items[2 : len(items)-2]
		}
	}

	// Set the debug mode flag if the ``-d`` flag was specified.
	debugMode = *debug

	var instanceDirectory string
	var configPath string
	var err error

	// Assume the parent directory of the config as the instance directory.
	if len(args) >= 1 {
		if args[0] == "help" {
			opts.PrintUsage()
			runtime.Exit(0)
		}
		configPath, err = filepath.Abs(filepath.Clean(args[0]))
		if err != nil {
			runtime.StandardError(err)
		}
		err = opts.ParseConfig(configPath, os.Args)
		if err != nil {
			runtime.StandardError(err)
		}
		instanceDirectory, _ = filepath.Split(configPath)
	} else {
		opts.PrintUsage()
		runtime.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 {
			runtime.StandardError(err)
		}
		extraConfigPath = runtime.JoinPath(instanceDirectory, extraConfigPath)
		err = opts.ParseConfig(extraConfigPath, os.Args)
		if err != nil {
			runtime.StandardError(err)
		}
	}

	// Create the log directory if it doesn't exist.
	logPath := runtime.JoinPath(instanceDirectory, *logDirectory)
	err = os.MkdirAll(logPath, 0755)
	if err != nil {
		runtime.StandardError(err)
	}

	// Create the run directory if it doesn't exist.
	runPath := runtime.JoinPath(instanceDirectory, *runDirectory)
	err = os.MkdirAll(runPath, 0755)
	if err != nil {
		runtime.StandardError(err)
	}

	// Initialise the runtime -- which will run ``live-server`` on multiple
	// processors if possible.
	runtime.Init()

	// Handle running as an Acceptor node if ``--run-as-acceptor`` was
	// specified.
	if *runAcceptor {

		// Exit if the `--acceptor-index`` is negative.
		if *acceptorIndex < 0 {
			runtime.Error("The --acceptor-index cannot be negative.")
		}

		var index int
		var selfAddress string
		var acceptorNodes []string

		// Generate a list of all the acceptor node addresses and exit if we
		// couldn't find the address four ourselves at the given index.
		for _, acceptor := range strings.Split(*acceptors, ",") {
			acceptor = strings.TrimSpace(acceptor)
			if acceptor != "" {
				if index == *acceptorIndex {
					selfAddress = acceptor
				} else {
					acceptorNodes = append(acceptorNodes, acceptor)
				}
			}
			index += 1
		}

		if selfAddress == "" {
			runtime.Error("Couldn't determine the address for the acceptor.")
		}

		// Initialise the process-related resources.
		runtime.InitProcess(fmt.Sprintf("acceptor-%d", *acceptorIndex), runPath)

		return

	}

	// Initialise the process-related resources.
	runtime.InitProcess("live-server", runPath)

	// Ensure that the directory containing static files exists.
	staticPath := runtime.JoinPath(instanceDirectory, *staticDirectory)
	dirInfo, err := os.Stat(staticPath)
	if err == nil {
		if !dirInfo.IsDir() {
			runtime.Error("Static path %q is not a directory", staticPath)
		}
	} else {
		runtime.StandardError(err)
	}

	// Load up all static files into a mapping.
	staticFiles := make(map[string]*StaticFile)
	getFiles(staticPath, staticFiles, "")

	// Pre-format the Cache-Control header for static files.
	staticCache := fmt.Sprintf("public, max-age=%d", *staticMaxAge)
	staticMaxAge64 := time.Duration(*staticMaxAge)

	// Exit if the directory containing the 50x.html files isn't present.
	errorPath := runtime.JoinPath(instanceDirectory, *errorDirectory)
	dirInfo, err = os.Stat(errorPath)
	if err == nil {
		if !dirInfo.IsDir() {
			runtime.Error("Error path %q is not a directory", errorPath)
		}
	} else {
		runtime.StandardError(err)
	}

	// Load the content for the HTTP ``400``, ``500``, ``502`` and ``503``
	// errors.
	error400, error400Length = getErrorInfo(errorPath, "400.html")
	error500, error500Length = getErrorInfo(errorPath, "500.html")
	error502, error502Length = getErrorInfo(errorPath, "502.html")
	error503, error503Length = getErrorInfo(errorPath, "503.html")

	// Initialise the TLS config.
	tlsconf.Init()

	// Setup the file loggers.
	var rotate int

	switch *logRotate {
	case "daily":
		rotate = log.RotateDaily
	case "hourly":
		rotate = log.RotateHourly
	case "never":
		rotate = log.RotateNever
	default:
		runtime.Error("Unknown log rotation format %q", *logRotate)
	}

	_, err = log.AddFileLogger("live-server", logPath, rotate, log.InfoLog)
	if err != nil {
		runtime.Error("Couldn't initialise logfile: %s", err)
	}

	_, err = log.AddFileLogger("error", logPath, rotate, log.ErrorLog)
	if err != nil {
		runtime.Error("Couldn't initialise logfile: %s", err)
	}

	var liveMode bool

	// Setup the live support as long as it hasn't been disabled.
	if !*noLivequery {
		go handleLiveMessages()
		acceptorKey, err = ioutil.ReadFile(runtime.JoinPath(instanceDirectory, *acceptorKeyPath))
		if err != nil {
			runtime.StandardError(err)
		}
		cookieKey, err = ioutil.ReadFile(runtime.JoinPath(instanceDirectory, *cookieKeyPath))
		if err != nil {
			runtime.StandardError(err)
		}
		liveMode = true
		_ = *livequeryHost
		_ = *livequeryPort
		_ = *cookieName
		_ = *leaseExpiry
		livequeryTimeout = (time.Duration(*livequeryExpiry) / 2) * 1000000000
	}

	// Create a container for the Frontend instances.
	frontends := make([]*Frontend, 0)

	// Create a channel which is used to toggle the state of the live-server's
	// maintenance mode based on process signals.
	maintenanceChannel := make(chan bool, 1)

	// Fork a goroutine which toggles the maintenance mode in a single place and
	// thus ensures "thread safety".
	go func() {
		for {
			enabledState := <-maintenanceChannel
			for _, frontend := range frontends {
				if enabledState {
					frontend.maintenanceMode = true
				} else {
					frontend.maintenanceMode = false
				}
			}
		}
	}()

	// Register the signal handlers for SIGUSR1 and SIGUSR2.
	runtime.SignalHandlers[os.SIGUSR1] = func() {
		maintenanceChannel <- true
	}

	runtime.SignalHandlers[os.SIGUSR2] = func() {
		maintenanceChannel <- false
	}

	// Let the user know how many CPUs we're currently running on.
	fmt.Printf("Running live-server with %d CPUs:\n", runtime.CPUCount)

	// If ``--public-address`` hasn't been specified, generate it from the given
	// frontend host and base port values -- assuming ``localhost`` for a blank
	// host.
	publicHost := *officialHost
	if publicHost == "" {
		if *frontendHost == "" {
			publicHost = fmt.Sprintf("localhost:%d", *frontendPort)
		} else {
			publicHost = fmt.Sprintf("%s:%d", *frontendHost, *frontendPort)
		}
	}

	// Setup and run the primary HTTPS Frontend.
	frontends = append(frontends, initFrontend("primary", *frontendHost,
		*frontendPort, publicHost, *primaryHosts, *primaryCert, *primaryKey,
		*cometPrefix, *websocketPrefix, instanceDirectory, *upstreamHost,
		*upstreamPort, *upstreamTLS, *maintenanceMode, liveMode, staticCache,
		staticFiles, staticMaxAge64))

	// Setup and run the secondary HTTPS Frontend.
	if !*noSecondary {
		frontends = append(frontends, initFrontend("secondary", *frontendHost,
			*frontendPort+1, publicHost, *secondaryHosts, *secondaryCert,
			*secondaryKey, *cometPrefix, *websocketPrefix, instanceDirectory,
			*upstreamHost, *upstreamPort, *upstreamTLS, *maintenanceMode,
			liveMode, staticCache, staticFiles, staticMaxAge64))
	}

	// Enter a wait loop if the HTTP Redirector has been disabled.
	if *noRedirect {
		loopForever := make(chan bool, 1)
		<-loopForever
	}

	// Otherwise, setup the HTTP Redirector.
	if *httpHost == "" {
		*httpHost = "localhost"
	}

	if *redirectURL == "" {
		*redirectURL = "https://" + publicHost
	}

	httpAddr := fmt.Sprintf("%s:%d", *httpHost, *httpPort)
	httpListener, err := net.Listen("tcp", httpAddr)
	if err != nil {
		runtime.Error("Cannot listen on %s: %v", httpAddr, err)
	}

	hsts := ""
	if *enableHSTS {
		hsts = fmt.Sprintf("max-age=%d", *hstsMaxAge)
	}

	redirector := &Redirector{
		hsts:     hsts,
		pingPath: *pingPath,
		url:      *redirectURL,
	}

	// Start a goroutine which runs the HTTP redirector.
	go func() {
		err = http.Serve(httpListener, redirector)
		if err != nil {
			runtime.Error("Couldn't serve HTTP Redirector: %s", err)
		}
	}()

	fmt.Printf("* HTTP Redirector running on http://%s:%d -> %s\n",
		*httpHost, *httpPort, *redirectURL)

	// Enter the wait loop for the process to be killed.
	loopForever := make(chan bool, 1)
	<-loopForever

}
コード例 #6
0
ファイル: live-server.go プロジェクト: elimisteve/togethr
// The ``initFrontend`` utility function abstracts away the various checks and
// steps involved in setting up and running a new HTTPS Frontend.
func initFrontend(status, host string, port int, officialHost, validAddress, cert, key, cometPrefix, websocketPrefix, instanceDirectory, upstreamHost string, upstreamPort int, upstreamTLS, maintenanceMode, liveMode bool, staticCache string, staticFiles map[string]*StaticFile, staticMaxAge time.Duration) *Frontend {

	var err error

	// Exit if the config values for the paths of the server's certificate or
	// key haven't been specified.
	if cert == "" {
		runtime.Error("The %s-cert config value hasn't been specified.", status)
	}
	if key == "" {
		runtime.Error("The %s-key config value hasn't been specified.", status)
	}

	// Initialise a fresh TLS Config.
	tlsConfig := &tls.Config{
		NextProtos: []string{"http/1.1"},
		Rand:       rand.Reader,
		Time:       time.Now,
	}

	// Load the certificate and private key into the TLS config.
	certPath := runtime.JoinPath(instanceDirectory, cert)
	keyPath := runtime.JoinPath(instanceDirectory, key)
	tlsConfig.Certificates = make([]tls.Certificate, 1)
	tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(certPath, keyPath)
	if err != nil {
		runtime.Error("Couldn't load %s certificate/key pair: %s", status, err)
	}

	// Instantiate the associated variables and listener for the HTTPS Frontend.
	upstreamAddr := fmt.Sprintf("%s:%d", upstreamHost, upstreamPort)
	frontendAddr := fmt.Sprintf("%s:%d", host, port)
	frontendConn, err := net.Listen("tcp", frontendAddr)
	if err != nil {
		runtime.Error("Cannot listen on %s: %v", frontendAddr, err)
	}

	frontendListener := tls.NewListener(frontendConn, tlsConfig)

	// Compute the variables related to detecting valid hosts.
	var validWildcard bool
	if strings.HasPrefix(validAddress, "*.") {
		validAddress = validAddress[2:]
		validWildcard = true
	}

	// Compute the variables related to redirects.
	redirectURL := "https://" + officialHost
	redirectHTML := []byte(fmt.Sprintf(redirectHTML, redirectURL))

	// Instantiate a ``Frontend`` object for use by the HTTPS Frontend.
	frontend := &Frontend{
		cometPrefix:     cometPrefix,
		liveMode:        liveMode,
		maintenanceMode: maintenanceMode,
		redirectHTML:    redirectHTML,
		redirectURL:     redirectURL,
		staticCache:     staticCache,
		staticFiles:     staticFiles,
		staticMaxAge:    staticMaxAge,
		upstreamAddr:    upstreamAddr,
		upstreamHost:    upstreamHost,
		upstreamTLS:     upstreamTLS,
		validAddress:    validAddress,
		validWildcard:   validWildcard,
		websocketPrefix: websocketPrefix,
	}

	// Start the HTTPS Frontend.
	go func() {
		err = http.Serve(frontendListener, frontend)
		if err != nil {
			runtime.Error("Couldn't serve %s HTTPS Frontend: %s", status, err)
		}
	}()

	var frontendURL string
	if host == "" {
		frontendURL = fmt.Sprintf("https://localhost:%d", port)
	} else {
		frontendURL = fmt.Sprintf("https://%s:%d", host, port)
	}

	fmt.Printf("* HTTPS Frontend %s running on %s\n", status, frontendURL)

	return frontend

}
コード例 #7
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)
	}

}
コード例 #8
0
ファイル: optparse.go プロジェクト: strogo/ampify
func (op *OptionParser) Parse(args []string) (remainder []string) {

	if op.ParseHelp && !op.helpAdded {
		op.Bool([]string{"-h", "--help"}, false, "show this help and exit")
		op.helpAdded = true
	}
	if op.ParseVersion && !op.versionAdded {
		op.Bool([]string{"-v", "--version"}, false, "show the version and exit")
		op.versionAdded = true
	}

	argLength := len(args) - 1

	// Command-line auto-completion support.
	autocomplete := os.Getenv("OPTPARSE_AUTO_COMPLETE")
	if autocomplete != "" {

		compWords := os.Getenv("COMP_WORDS")
		if compWords == "" {
			// zsh's bashcompinit does not pass COMP_WORDS, replace with
			// COMP_LINE for now...
			compWords = os.Getenv("COMP_LINE")
			if compWords == "" {
				runtime.Exit(1)
			}
		}
		compWordsList := strings.Split(compWords, " ", -1)
		compLine := os.Getenv("COMP_LINE")
		compPoint, err := strconv.Atoi(os.Getenv("COMP_POINT"))
		if err != nil {
			runtime.Exit(1)
		}
		compWord, err := strconv.Atoi(os.Getenv("COMP_CWORD"))
		if err != nil {
			runtime.Exit(1)
		}

		prefix := ""
		if compWord > 0 {
			if compWord < len(compWordsList) {
				prefix = compWordsList[compWord]
			}
		}

		// At some point in the future, make autocompletion customisable per
		// option flag and, at that point, make use of these variables.
		_ = compLine
		_ = compPoint

		// Pass to the shell completion if the previous word was a flag
		// expecting some parameter.
		if (compWord - 1) > 0 {
			prev := compWordsList[compWord-1]
			if strings.HasPrefix(prev, "--") {
				opt, ok := op.long2options[prev]
				if ok {
					if opt.dest != "" {
						runtime.Exit(1)
					}
				}
			} else if strings.HasPrefix(prev, "-") {
				opt, ok := op.short2options[prev]
				if ok {
					if opt.dest != "" {
						runtime.Exit(1)
					}
				}
			}
		}

		completions := make([]string, 0)
		for flag, _ := range op.long2options {
			if strings.HasPrefix(flag, prefix) {
				slice.AppendString(&completions, flag)
			}
		}

		for flag, _ := range op.short2options {
			if strings.HasPrefix(flag, prefix) {
				slice.AppendString(&completions, flag)
			}
		}

		fmt.Print(strings.Join(completions, " "))
		runtime.Exit(1)

	}

	if argLength == 0 {
		return
	}

	var opt *option
	var ok bool

	idx := 1

	for {
		arg := args[idx]
		noOpt := true
		if strings.HasPrefix(arg, "--") {
			opt, ok = op.long2options[arg]
			if ok {
				noOpt = false
			}
		} else if strings.HasPrefix(arg, "-") {
			opt, ok = op.short2options[arg]
			if ok {
				noOpt = false
			}
		} else {
			slice.AppendString(&remainder, arg)
			if idx == argLength {
				break
			} else {
				idx += 1
				continue
			}
		}
		if noOpt {
			runtime.Error("%s: error: no such option: %s\n", args[0], arg)
		}
		if opt.dest != "" {
			if idx == argLength {
				runtime.Error("%s: error: %s option requires an argument\n", args[0], arg)
			}
		}
		if opt.valueType == "bool" {
			if opt.longflag == "--help" && op.ParseHelp {
				op.PrintUsage()
				runtime.Exit(1)
			} else if opt.longflag == "--version" && op.ParseVersion {
				fmt.Printf("%s\n", op.Version)
				runtime.Exit(0)
			}
			*opt.boolValue = true
			opt.defined = true
			idx += 1
		} else if opt.valueType == "string" {
			if idx == argLength {
				runtime.Error("%s: error: no value specified for %s\n", args[0], arg)
			}
			*opt.stringValue = args[idx+1]
			opt.defined = true
			idx += 2
		} else if opt.valueType == "int" {
			if idx == argLength {
				runtime.Error("%s: error: no value specified for %s\n", args[0], arg)
			}
			intValue, err := strconv.Atoi(args[idx+1])
			if err != nil {
				runtime.Error("%s: error: couldn't convert %s value '%s' to an integer\n", args[0], arg, args[idx+1])
			}
			*opt.intValue = intValue
			opt.defined = true
			idx += 2
		}
		if idx > argLength {
			break
		}
	}

	for _, opt := range op.options {
		if opt.requiredFlag && !opt.defined {
			runtime.Error("%s: error: required: %s", args[0], opt)
		}
	}

	return

}
コード例 #9
0
ファイル: wifistat.go プロジェクト: tav/wifistat
func main() {

	// Define the options for the command line and config file options parser.
	opts := optparse.Parser(
		"Usage: wifistat <config.yaml> [options]\n",
		"wifistat 0.0.1")

	addr := opts.StringConfig("addr", ":9040",
		"the host:port address for the web server [:9040]")

	csv := opts.StringConfig("csv-dir", "csv",
		"the path to the csv files directory [csv]")

	wifi := opts.StringConfig("wifi-logs-dir", "iaslogs",
		"the path to the Wi-Fi logs directory [iaslogs]")

	membership := opts.BoolConfig("member-analytics", false,
		"enable membership-based analytics")

	devices := opts.StringConfig("devices-url", "",
		"the url key for the devices.csv Google Spreadsheet")

	members := opts.StringConfig("members-url", "",
		"the url key for the members.csv Google Spreadsheet")

	opening := opts.StringConfig("opening-url", "",
		"the url key for the opening.csv Google Spreadsheet")

	// Parse the command line options.
	os.Args[0] = "wifistat"
	_, root, _ := runtime.DefaultOpts("wifistat", opts, os.Args)

	// Compute option variables.
	wifiLogDir = runtime.JoinPath(root, *wifi)
	csvDir = runtime.JoinPath(root, *csv)
	err := os.MkdirAll(csvDir, 0755)
	if err != nil {
		runtime.StandardError(err)
	}

	// Handle member analytics options.
	if *membership {
		enableMemberAnalytics = true
		devicesUrlKey = *devices
		if devicesUrlKey == "" {
			runtime.Error("You need to specify the `devices-url` command-line option.")
		}
		membersUrlKey = *members
		if membersUrlKey == "" {
			runtime.Error("You need to specify the `members-url` command-line option.")
		}
		openingUrlKey = *opening
		if openingUrlKey == "" {
			runtime.Error("You need to specify the `opening-url` command-line option.")
		}
	}

	// Parse the logs.
	parseCsv(false)
	parseWifi()

	// Register the various handlers.
	http.HandleFunc("/", handleRequest)
	http.HandleFunc("/reload", handleReload)

	// Start the web server.
	log.Info("Running wifistat on %s", *addr)
	err = http.ListenAndServe(*addr, nil)
	if err != nil {
		runtime.StandardError(err)
	}

	runtime.Exit(0)

}
コード例 #10
0
ファイル: bolt.go プロジェクト: tav/bolt
func main() {

	// Setup temporary console logging.
	log.DisableConsoleTimestamp()
	log.AddConsoleLogger()

	// Set default values for command-line params.
	boltFilename := "Boltfile"
	genExecutablePath := ""

	recompile := false
	skipNext := true
	maxIdx := len(os.Args) - 1
	newArgs := []string{"bolt"}

	// Extract higher-level command-line arguments.
	for idx, arg := range os.Args {
		if skipNext {
			skipNext = false
			continue
		}
		if arg == "--gen" && idx != maxIdx {
			var err error
			genExecutablePath, err = filepath.Abs(os.Args[idx+1])
			if err != nil {
				runtime.StandardError(err)
			}
			skipNext = true
		} else if arg == "--boltfile" && idx != maxIdx {
			boltFilename = os.Args[idx+1]
			skipNext = true
		} else if arg == "--recompile" {
			recompile = true
		} else {
			newArgs = append(newArgs, arg)
		}
	}

	// Try and find the directory containing the Boltfile.
	boltdir, err := findBoltDir(boltFilename)
	if err != nil {
		if _, ok := err.(*fsutil.NotFound); ok {
			log.Error("Couldn't find Boltfile")
			runtime.Exit(1)
		}
		runtime.StandardError(err)
	}

	// Generate the path to the corresponding temp directory.
	boltpath := filepath.Join(boltdir, boltFilename)
	hash := sha1.New()
	hash.Write([]byte(boltpath))
	digest := fmt.Sprintf("%x", hash.Sum(nil))
	tempdir := filepath.Join(os.TempDir(), "bolt-"+digest)

	// See if the temp directory exists and if not create it.
	exists, err := fsutil.Exists(tempdir)
	if !exists {
		if _, ok := err.(*fsutil.NotFound); !ok {
			runtime.Error("Couldn't access the temp directory: %s: %s", tempdir, err)
		}
		err = os.Mkdir(tempdir, 0744)
		if err != nil {
			runtime.Error("Couldn't create the temp directory: %s: %s", tempdir, err)
		}
	}

	// See if an up-to-date generated binary already exists and, if so, run it.
	binpath := filepath.Join(tempdir, "bolt")
	if !recompile {
		boltstat, _ := os.Stat(boltpath)
		if genExecutablePath == "" {
			binstat, err := os.Stat(binpath)
			if err == nil {
				if boltstat.ModTime().Before(binstat.ModTime()) {
					runBoltExecutable(binpath, boltdir, newArgs)
					return
				}
			}
		}
	}

	// Parse the Boltfile.
	spec, err := parseBoltfile(boltpath, boltdir)
	if err != nil {
		exitForParserErrors(boltFilename, err)
	}

	// Exit if no tasks were found.
	if len(spec.Tasks) == 0 {
		runtime.Error("No tasks were found in %s", boltpath)
	}

	// Fudge the path to the executable that needs to be generated depending on
	// whether --gen-executable was specified or not.
	genOnly := true
	if genExecutablePath == "" {
		genExecutablePath = binpath
		genOnly = false
	}

	// Generate the executable.
	err = genExecutable(genExecutablePath, tempdir, spec)
	if err != nil {
		runtime.StandardError(err)
	}

	// Exit early if --gen-executable was specified.
	if genOnly {
		log.Info("%s successfully compiled to %s", boltFilename, genExecutablePath)
		runtime.Exit(0)
	}

	// Otherwise, run the executable.
	runBoltExecutable(binpath, boltdir, newArgs)

}
コード例 #11
0
ファイル: frontend.go プロジェクト: trojanspike/ampify
func ampFrontend(argv []string, usage string) {

	// Define the options for the command line and config file options parser.
	opts := optparse.Parser(
		"Usage: amp frontend <config.yaml> [options]\n\n    " + usage + "\n")

	httpsHost := opts.StringConfig("https-host", "",
		"the host to bind the HTTPS Frontends to")

	httpsPort := opts.IntConfig("https-port", 9040,
		"the base port for the HTTPS Frontends [9040]")

	officialHost := opts.StringConfig("offficial-host", "",
		"the official public host for the HTTPS Frontends")

	primaryHosts := opts.StringConfig("primary-hosts", "",
		"limit the primary HTTPS Frontend to the specified host pattern")

	primaryCert := opts.StringConfig("primary-cert", "cert/primary.cert",
		"the path to the primary host's TLS certificate [cert/primary.cert]")

	primaryKey := opts.StringConfig("primary-key", "cert/primary.key",
		"the path to the primary host's TLS key [cert/primary.key]")

	noSecondary := opts.BoolConfig("no-secondary", false,
		"disable the secondary HTTPS Frontend [false]")

	secondaryHosts := opts.StringConfig("secondary-hosts", "",
		"limit the secondary HTTPS Frontend to the specified host pattern")

	secondaryCert := opts.StringConfig("secondary-cert", "cert/secondary.cert",
		"the path to the secondary host's TLS certificate [cert/secondary.cert]")

	secondaryKey := opts.StringConfig("secondary-key", "cert/secondary.key",
		"the path to the secondary host's TLS key [cert/secondary.key]")

	errorDirectory := opts.StringConfig("error-dir", "error",
		"the path to the HTTP error files directory [error]")

	staticDirectory := opts.StringConfig("static-dir", "www",
		"the path to the static files directory [www]")

	staticMaxAge := opts.IntConfig("static-max-age", 86400,
		"max-age cache header value when serving the static files [86400]")

	hstsMaxAge := opts.IntConfig("hsts-max-age", 50000000,
		"max-age in seconds for HTTP Strict Transport Security [50000000]")

	noRedirect := opts.BoolConfig("no-redirect", false,
		"disable the HTTP Redirector [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 [9080]")

	httpRedirectURL := opts.StringConfig("redirect-url", "",
		"the URL that the HTTP Redirector redirects to")

	singleNode := opts.StringConfig("single-node", "",
		"the upstream single node address if running without a master")

	masterNodes := opts.StringConfig("master-nodes", "localhost:8060",
		"comma-separated addresses of amp master nodes [localhost:8060]")

	masterCert := opts.StringConfig("master-cert", "cert/master.cert",
		"the path to the amp master certificate [cert/master.cert]")

	ironKeyPath := opts.StringConfig("iron-key", "cert/iron.key",
		"the path to the key used for iron strings [cert/iron.key]")

	maintenanceMode := opts.BoolConfig("maintenance", false,
		"start up in maintenance mode [false]")

	_, instanceDirectory, _ := runtime.DefaultOpts("frontend", opts, argv)

	// Ensure that the directory containing static files exists.
	staticPath := runtime.JoinPath(instanceDirectory, *staticDirectory)
	dirInfo, err := os.Stat(staticPath)
	if err == nil {
		if !dirInfo.IsDirectory() {
			runtime.Error("%q is not a directory", staticPath)
		}
	} else {
		runtime.StandardError(err)
	}

	// Ensure that the directory containing error files exists.
	errorPath := runtime.JoinPath(instanceDirectory, *errorDirectory)
	dirInfo, err = os.Stat(errorPath)
	if err == nil {
		if !dirInfo.IsDirectory() {
			runtime.Error("%q is not a directory", errorPath)
		}
	} else {
		runtime.StandardError(err)
	}

	// If ``--official-host`` hasn't been specified, generate it from the given
	// frontend host and base port values -- assuming ``localhost`` for a blank
	// host.
	publicHost := *officialHost
	if publicHost == "" {
		if *httpsHost == "" {
			publicHost = fmt.Sprintf("localhost:%d", *httpsPort)
		} else {
			publicHost = fmt.Sprintf("%s:%d", *httpsHost, *httpsPort)
		}
	}

	// Compute the HSTS max age header value.
	hsts := fmt.Sprintf("max-age=%d", *hstsMaxAge)

	// Pre-format the Cache-Control header for static files.
	staticCache := fmt.Sprintf("public, max-age=%d", *staticMaxAge)
	staticMaxAge64 := int64(*staticMaxAge)

	// Compute the variables related to redirects.
	redirectURL := "https://" + publicHost
	redirectHTML := []byte(fmt.Sprintf(
		`Please <a href="%s">click here if your browser doesn't redirect</a> automatically.`,
		redirectURL))

	// Compute the path to the Iron key.
	ironPath := runtime.JoinPath(instanceDirectory, *ironKeyPath)

	// Instantiate the master client.
	masterClient, err := master.NewClient(
		*masterNodes, runtime.JoinPath(instanceDirectory, *masterCert))

	if err != nil {
		runtime.StandardError(err)
	}

	var noMaster bool
	if *singleNode != "" {
		noMaster = true
	}

	// Let the user know how many CPUs we're currently running on.
	log.Info("Running the Amp Frontend on %d CPUs.", runtime.CPUCount)

	// Initialise the TLS config.
	tlsconf.Init()

	// Initialise a container for the HTTPSFrontends.
	webFrontends := make([]*server.HTTPSFrontend, 1)

	// Compute the variables related to detecting valid hosts.
	primaryWildcard, primaryAddr := getValidAddr(*primaryHosts)
	secondaryWildcard, secondaryAddr := getValidAddr(*secondaryHosts)

	// Instantiate the primary ``HTTPSFrontend`` object.
	frontend := &server.HTTPSFrontend{
		HSTS:            hsts,
		MaintenanceMode: *maintenanceMode,
		MasterClient:    masterClient,
		NoMaster:        noMaster,
		RedirectHTML:    redirectHTML,
		RedirectURL:     redirectURL,
		SingleNode:      *singleNode,
		StaticCache:     staticCache,
		StaticMaxAge:    staticMaxAge64,
		ValidAddress:    primaryAddr,
		ValidWildcard:   primaryWildcard,
	}

	frontend.LoadAssets(errorPath, ironPath, staticPath)
	frontend.Run(*httpsHost, *httpsPort,
		runtime.JoinPath(instanceDirectory, *primaryCert),
		runtime.JoinPath(instanceDirectory, *primaryKey))

	webFrontends[0] = frontend

	// Setup and run the secondary HTTPSFrontend.
	if !*noSecondary {
		frontend = &server.HTTPSFrontend{
			HSTS:            hsts,
			MaintenanceMode: *maintenanceMode,
			MasterClient:    masterClient,
			NoMaster:        noMaster,
			RedirectHTML:    redirectHTML,
			RedirectURL:     redirectURL,
			SingleNode:      *singleNode,
			StaticCache:     staticCache,
			StaticMaxAge:    staticMaxAge64,
			ValidAddress:    secondaryAddr,
			ValidWildcard:   secondaryWildcard,
		}
		frontend.LoadAssets(errorPath, ironPath, staticPath)
		frontend.Run(*httpsHost, *httpsPort+1,
			runtime.JoinPath(instanceDirectory, *secondaryCert),
			runtime.JoinPath(instanceDirectory, *secondaryKey))
		webFrontends = append(webFrontends, frontend)
	}

	// Create a channel which is used to toggle maintenance mode based on
	// process signals.
	maintenanceChannel := make(chan bool, 1)

	// Fork a goroutine which toggles the maintenance mode in a single place and
	// thus ensures thread safety.
	go func() {
		for {
			enabledState := <-maintenanceChannel
			for _, frontend := range webFrontends {
				if enabledState {
					frontend.MaintenanceMode = true
				} else {
					frontend.LoadAssets(errorPath, ironPath, staticPath)
					frontend.MaintenanceMode = false
				}
			}
		}
	}()

	// Register the signal handlers for SIGUSR1 and SIGUSR2.
	runtime.SignalHandlers[os.SIGUSR1] = func() {
		maintenanceChannel <- true
	}

	runtime.SignalHandlers[os.SIGUSR2] = func() {
		maintenanceChannel <- false
	}

	// Enter a wait loop if the HTTP Redirector has been disabled.
	if *noRedirect {
		loopForever := make(chan bool, 1)
		<-loopForever
	}

	// Otherwise, setup and run the HTTP Redirector.
	if *httpHost == "" {
		*httpHost = "localhost"
	}

	if *httpRedirectURL == "" {
		*httpRedirectURL = "https://" + publicHost
	}

	redirector := &server.HTTPRedirector{*httpRedirectURL}
	redirector.Run(*httpHost, *httpPort)

	// Enter the wait loop for the process to be killed.
	loopForever := make(chan bool, 1)
	<-loopForever

}