// 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) }
// 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 }
// 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 }
// 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) }