예제 #1
0
파일: app.go 프로젝트: rfistman/camlistore
// ListenAddress returns the host:[port] network address, derived from the environment,
// that the application should listen on.
func ListenAddress() (string, error) {
	baseURL := os.Getenv("CAMLI_APP_BACKEND_URL")
	if baseURL == "" {
		return "", errors.New("CAMLI_APP_BACKEND_URL is undefined")
	}
	return netutil.HostPort(baseURL)
}
예제 #2
0
// gceDeployHandler conditionally returns an http.Handler for a GCE launcher,
// configured to run at /prefix/ (the trailing slash can be omitted).
// If CAMLI_GCE_CLIENTID is not set, the launcher-config.json file, if present,
// is used instead of environment variables to initialize the launcher. If a
// launcher isn't enabled, gceDeployHandler returns nil. If another error occurs,
// log.Fatal is called.
func gceDeployHandler(prefix string) http.Handler {
	hostPort, err := netutil.HostPort("https://" + *httpsAddr)
	if err != nil {
		hostPort = "camlistore.org:443"
	}
	var gceh http.Handler
	if e := os.Getenv("CAMLI_GCE_CLIENTID"); e != "" {
		gceh, err = gce.NewDeployHandler(hostPort, prefix)
	} else {
		config := filepath.Join(*root, "launcher-config.json")
		if _, err := os.Stat(config); err != nil {
			if os.IsNotExist(err) {
				return nil
			}
			log.Fatalf("Could not stat launcher-config.json: %v", err)
		}
		gceh, err = gce.NewDeployHandlerFromConfig(hostPort, prefix, config)
	}
	if err != nil {
		log.Fatalf("Error initializing gce deploy handler: %v", err)
	}
	pageBytes, err := ioutil.ReadFile(filepath.Join(*root, "tmpl", "page.html"))
	if err != nil {
		log.Fatalf("Error initializing gce deploy handler: %v", err)
	}
	if err := gceh.(*gce.DeployHandler).AddTemplateTheme(string(pageBytes)); err != nil {
		log.Fatalf("Error initializing gce deploy handler: %v", err)
	}
	log.Printf("Starting Camlistore launcher on https://%s%s", hostPort, prefix)
	return gceh
}
예제 #3
0
// certHostname figures out the name to use for the TLS certificates, using baseURL
// and falling back to the listen address if baseURL is empty or invalid.
func certHostname(listen, baseURL string) (string, error) {
	hostPort, err := netutil.HostPort(baseURL)
	if err != nil {
		hostPort = listen
	}
	hostname, _, err := net.SplitHostPort(hostPort)
	if err != nil {
		return "", fmt.Errorf("failed to find hostname for cert from address %q: %v", hostPort, err)
	}
	return hostname, nil
}
예제 #4
0
// Main sends on up when it's running, and shuts down when it receives from down.
func Main(up chan<- struct{}, down <-chan struct{}) {
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "camlistored version: %s\nGo version: %s (%s/%s)\n",
			buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH)
		return
	}
	if legalprint.MaybePrint(os.Stderr) {
		return
	}
	if env.OnGCE() {
		log.SetOutput(gce.LogWriter())
	}

	if *flagReindex {
		index.SetImpendingReindex()
	}

	log.Printf("Starting camlistored version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(),
		runtime.GOOS, runtime.GOARCH)

	shutdownc := make(chan io.Closer, 1) // receives io.Closer to cleanly shut down
	go handleSignals(shutdownc)

	// In case we're running in a Docker container with no
	// filesytem from which to load the root CAs, this
	// conditionally installs a static set if necessary. We do
	// this before we load the config file, which might come from
	// an https URL.
	httputil.InstallCerts()

	config, isNewConfig, err := loadConfig(*flagConfigFile)
	if err != nil {
		exitf("Error loading config file: %v", err)
	}

	ws := webserver.New()
	listen, baseURL := listenAndBaseURL(config)

	hostname, err := certHostname(listen, baseURL)
	if err != nil {
		exitf("Bad baseURL or listen address: %v", err)
	}
	setupTLS(ws, config, hostname)

	err = ws.Listen(listen)
	if err != nil {
		exitf("Listen: %v", err)
	}

	if baseURL == "" {
		baseURL = ws.ListenURL()
	}

	shutdownCloser, err := config.InstallHandlers(ws, baseURL, *flagReindex, nil)
	if err != nil {
		exitf("Error parsing config: %v", err)
	}
	shutdownc <- shutdownCloser

	urlToOpen := baseURL
	if !isNewConfig {
		// user may like to configure the server at the initial startup,
		// open UI if this is not the first run with a new config file.
		urlToOpen += config.UIPath
	}

	if *flagOpenBrowser {
		go osutil.OpenURL(urlToOpen)
	}

	go ws.Serve()
	if flagPollParent {
		osutil.DieOnParentDeath()
	}

	if err := config.StartApps(); err != nil {
		exitf("StartApps: %v", err)
	}

	for appName, appURL := range config.AppURL() {
		addr, err := netutil.HostPort(appURL)
		if err != nil {
			log.Printf("Could not get app %v address: %v", appName, err)
			continue
		}
		if err := netutil.AwaitReachable(addr, 5*time.Second); err != nil {
			log.Printf("Could not reach app %v: %v", appName, err)
		}
	}
	log.Printf("Available on %s", urlToOpen)

	if env.OnGCE() && strings.HasPrefix(baseURL, "https://") {
		go redirectFromHTTP(baseURL)
	}

	// Block forever, except during tests.
	up <- struct{}{}
	<-down
	osExit(0)
}