Ejemplo n.º 1
0
func ampNode(argv []string, usage string) {

	opts := optparse.Parser(
		"Usage: amp node <config.yaml> [options]\n\n    " + usage + "\n")

	nodeHost := opts.StringConfig("node-host", "",
		"the host to bind this node to")

	nodePort := opts.IntConfig("node-port", 8050,
		"the port to bind this node to [8050]")

	ctrlHost := opts.StringConfig("control-host", "",
		"the host to bind the nodule control socket to")

	ctrlPort := opts.IntConfig("control-port", 8051,
		"the port to bind the nodule control socket to [8051]")

	nodules := opts.StringConfig("nodules", "*",
		"comma-separated list of nodules to initialise [*]")

	nodulePaths := opts.StringConfig("nodule-paths", ".",
		"comma-separated list of nodule container directories [nodule]")

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

	masterKeyPath := opts.StringConfig("master-key", "cert/master.key",
		"the path to the file containing the amp master public key [cert/master.key]")

	debug, _, runPath := runtime.DefaultOpts("node", opts, argv, nil)

	masterClient, err := master.NewClient(*masterNodes, *masterKeyPath)

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

	logging.AddConsoleFilter(nodule.FilterConsoleLog)

	node, err := nodule.NewHost(
		runPath, *nodeHost, *nodePort, *ctrlHost, *ctrlPort, *nodules,
		strings.SplitN(*nodulePaths, ",", -1), masterClient)

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

	err = node.Run(debug)
	logging.Wait()

	if err != nil {
		runtime.Exit(1)
	}

}
Ejemplo n.º 2
0
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

}