示例#1
0
func main() {
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "publisher version: %s\nGo version: %s (%s/%s)\n",
			buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH)
		return
	}

	logf("Starting publisher version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(),
		runtime.GOOS, runtime.GOARCH)

	listenAddr, err := app.ListenAddress()
	if err != nil {
		logger.Fatalf("Listen address: %v", err)
	}
	conf := appConfig()
	ph := newPublishHandler(conf)
	if err := ph.initRootNode(); err != nil {
		logf("%v", err)
	}
	ws := webserver.New()
	ws.Logger = logger
	ws.Handle("/", ph)
	if conf.HTTPSCert != "" && conf.HTTPSKey != "" {
		ws.SetTLS(conf.HTTPSCert, conf.HTTPSKey)
	}
	if err := ws.Listen(listenAddr); err != nil {
		logger.Fatalf("Listen: %v", err)
	}
	ws.Serve()
}
示例#2
0
func main() {
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "hello version: %s\nGo version: %s (%s/%s)\n",
			buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH)
		return
	}

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

	listenAddr, err := app.ListenAddress()
	if err != nil {
		log.Fatalf("Listen address: %v", err)
	}
	conf := appConfig()
	ws := webserver.New()
	ws.Handle("/", &helloHandler{who: conf.Word})
	// TODO(mpl): handle status requests too. Camlistore will send an auth
	// token in the extra config that should be used as the "password" for
	// subsequent status requests.
	if err := ws.Listen(listenAddr); err != nil {
		log.Fatalf("Listen: %v", err)
	}

	ws.Serve()
}
示例#3
0
func (sh *StatusHandler) currentStatus() *status {
	res := &status{
		Version: buildinfo.Version(),
		Storage: make(map[string]storageStatus),
	}
	_, hi, err := sh.handlerFinder.FindHandlerByType("root")
	if err != nil {
		res.Error = fmt.Sprintf("Error finding root handler: %v", err)
		return res
	}
	rh := hi.(*RootHandler)
	res.rootPrefix = rh.Prefix
	for _, sh := range rh.sync {
		res.SyncStatus = append(res.SyncStatus, sh.currentStatus())
	}

	types, handlers := sh.handlerFinder.AllHandlers()

	// Storage
	for pfx, typ := range types {
		if !strings.HasPrefix(typ, "storage-") {
			continue
		}
		h := handlers[pfx]
		_, isIndex := h.(*index.Index)
		res.Storage[pfx] = storageStatus{
			Type:    strings.TrimPrefix(typ, "storage-"),
			Primary: pfx == rh.BlobRoot,
			IsIndex: isIndex,
		}
	}

	return res
}
示例#4
0
func (rh *RootHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if wantsDiscovery(req) {
		if auth.Allowed(req, auth.OpDiscovery) {
			rh.serveDiscovery(rw, req)
			return
		}
		if !rh.Stealth {
			http.Error(rw, "Unauthorized", http.StatusUnauthorized)
		}
		return
	}

	if rh.Stealth {
		return
	}
	if req.URL.Path == "/favicon.ico" {
		serveStaticFile(rw, req, Files, "favicon.ico")
		return
	}
	f := func(p string, a ...interface{}) {
		fmt.Fprintf(rw, p, a...)
	}
	f("<html><body><p>This is camlistored (%s), a "+
		"<a href='http://camlistore.org'>Camlistore</a> server.</p>", buildinfo.Version())
	if auth.IsLocalhost(req) && !isDevServer() {
		f("<p>If you're coming from localhost, configure your Camlistore server at <a href='/setup'>/setup</a>.</p>")
	}
	if rh.ui != nil {
		f("<p>To manage your content, access the <a href='%s'>%s</a>.</p>", rh.ui.prefix, rh.ui.prefix)
	}
	if rh.statusRoot != "" {
		f("<p>To view status, see <a href='%s'>%s</a>", rh.statusRoot, rh.statusRoot)
	}
	fmt.Fprintf(rw, "</body></html>")
}
示例#5
0
// camputMain is separated from main for testing from camput
func camputMain(args ...string) {
	if *flagVersion {
		fmt.Fprintf(stderr, "camget version: %s\n", buildinfo.Version())
		return
	}
	if *flagHelp {
		usage("")
	}
	if len(args) == 0 {
		usage("No mode given.")
	}

	mode := args[0]
	cmd, ok := modeCommand[mode]
	if !ok {
		usage(fmt.Sprintf("Unknown mode %q", mode))
	}

	var up *Uploader
	if mode != "init" {
		up = newUploader()
	}

	cmdFlags := modeFlags[mode]
	err := cmdFlags.Parse(args[1:])
	if err != nil {
		err = ErrUsage
	} else {
		err = cmd.RunCommand(up, cmdFlags.Args())
	}
	if ue, isUsage := err.(UsageError); isUsage {
		if isUsage {
			errf("%s\n", ue)
		}
		cmd.Usage()
		errf("\nGlobal options:\n")
		flag.PrintDefaults()

		if hasFlags(cmdFlags) {
			errf("\nMode-specific options for mode %q:\n", mode)
			cmdFlags.PrintDefaults()
		}
		exit(1)
	}
	if *flagVerbose {
		stats := up.Stats()
		log.Printf("Client stats: %s", stats.String())
		log.Printf("  #HTTP reqs: %d", up.transport.Requests())
	}
	previousErrors := wereErrors
	if err != nil {
		wereErrors = true
		if !previousErrors {
			log.Printf("Error: %v", err)
		}
	}
	if wereErrors {
		exit(2)
	}
}
示例#6
0
func (sh *StatusHandler) serveStatus(rw http.ResponseWriter, req *http.Request) {
	res := &statusResponse{
		Version: buildinfo.Version(),
	}

	httputil.ReturnJSON(rw, res)
}
示例#7
0
// Main is meant to be the core of a command that has
// subcommands (modes), such as camput or camtool.
func Main() {
	registerFlagOnce.Do(ExtraFlagRegistration)
	if setCommandLineOutput != nil {
		setCommandLineOutput(Stderr)
	}
	flag.Parse()

	args := flag.Args()
	if *FlagVersion {
		fmt.Fprintf(Stderr, "%s version: %s\n", os.Args[0], buildinfo.Version())
		return
	}
	if *FlagHelp {
		usage("")
	}
	if len(args) == 0 {
		usage("No mode given.")
	}

	mode := args[0]
	cmd, ok := modeCommand[mode]
	if !ok {
		usage(fmt.Sprintf("Unknown mode %q", mode))
	}

	cmdFlags := modeFlags[mode]
	cmdFlags.SetOutput(Stderr)
	err := cmdFlags.Parse(args[1:])
	if err != nil {
		err = ErrUsage
	} else {
		if *wantHelp[mode] {
			help(mode)
			return
		}
		err = cmd.RunCommand(cmdFlags.Args())
	}
	if ue, isUsage := err.(UsageError); isUsage {
		if isUsage {
			Errorf("%s\n", ue)
		}
		cmd.Usage()
		Errorf("\nGlobal options:\n")
		flag.PrintDefaults()

		if hasFlags(cmdFlags) {
			Errorf("\nMode-specific options for mode %q:\n", mode)
			cmdFlags.PrintDefaults()
		}
		Exit(1)
	}
	PreExit()
	if err != nil {
		if !ExitWithFailure {
			// because it was already logged if ExitWithFailure
			log.Printf("Error: %v", err)
		}
		Exit(2)
	}
}
示例#8
0
// Main is meant to be the core of a command that has
// subcommands (modes), such as camput or camtool.
func Main() {
	ExtraFlagRegistration()
	flag.Parse()
	args := flag.Args()
	if *FlagVersion {
		fmt.Fprintf(Stderr, "%s version: %s\n", os.Args[0], buildinfo.Version())
		return
	}
	if *FlagHelp {
		usage("")
	}
	if len(args) == 0 {
		usage("No mode given.")
	}

	mode := args[0]
	cmd, ok := modeCommand[mode]
	if !ok {
		usage(fmt.Sprintf("Unknown mode %q", mode))
	}

	cmdFlags := modeFlags[mode]
	var cmdHelp bool
	cmdFlags.BoolVar(&cmdHelp, "help", false, "Help for this mode.")
	err := cmdFlags.Parse(args[1:])
	if err != nil {
		err = ErrUsage
	} else {
		if cmdHelp {
			help(mode)
			return
		}
		err = cmd.RunCommand(cmdFlags.Args())
	}
	if ue, isUsage := err.(UsageError); isUsage {
		if isUsage {
			Errorf("%s\n", ue)
		}
		cmd.Usage()
		Errorf("\nGlobal options:\n")
		flag.PrintDefaults()

		if hasFlags(cmdFlags) {
			Errorf("\nMode-specific options for mode %q:\n", mode)
			cmdFlags.PrintDefaults()
		}
		Exit(1)
	}
	if *FlagVerbose {
		PreExit()
	}
	if err != nil {
		if !ExitWithFailure {
			// because it was already logged if ExitWithFailure
			log.Printf("Error: %v", err)
		}
		Exit(2)
	}
}
示例#9
0
func main() {
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "camlistored version: %s\n", buildinfo.Version())
		return
	}

	fileName, err := findConfigFile(*flagConfigFile)
	if err != nil {
		exitf("Error finding config file %q: %v", fileName, err)
	}
	log.Printf("Using config file %s", fileName)
	config, err := serverconfig.Load(fileName)
	if err != nil {
		exitf("Could not load server config: %v", err)
	}

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

	setupTLS(ws, config, listen)
	err = config.InstallHandlers(ws, baseURL, nil)
	if err != nil {
		exitf("Error parsing config: %v", err)
	}

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

	urlOpened := false
	if config.UIPath != "" {
		uiURL := ws.ListenURL() + config.UIPath
		if baseURL != "" {
			uiURL = baseURL + config.UIPath
		}
		log.Printf("UI available at %s", uiURL)
		if runtime.GOOS == "windows" {
			// Might be double-clicking an icon with no shell window?
			// Just open the URL for them.
			urlOpened = true
			go osutil.OpenURL(uiURL)
		}
	}
	if *flagConfigFile == "" && !urlOpened {
		go osutil.OpenURL(ws.ListenURL())
	}

	go ws.Serve()
	go handleSignals()
	if flagPollParent {
		osutil.DieOnParentDeath()
	}
	select {}
}
示例#10
0
func main() {
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "camlistored version: %s\n", buildinfo.Version())
		return
	}

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

	fileName, isNewConfig, err := findConfigFile(*flagConfigFile)
	if err != nil {
		exitf("Error finding config file %q: %v", fileName, err)
	}
	log.Printf("Using config file %s", fileName)
	config, err := serverconfig.Load(fileName)
	if err != nil {
		exitf("Could not load server config: %v", err)
	}

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

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

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

	urlToOpen := ws.ListenURL()
	if baseURL != "" {
		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
	}

	log.Printf("Available on %s", urlToOpen)
	if *flagOpenBrowser {
		go osutil.OpenURL(urlToOpen)
	}

	go ws.Serve()
	if flagPollParent {
		osutil.DieOnParentDeath()
	}
	select {}
}
示例#11
0
func main() {
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "publisher version: %s\nGo version: %s (%s/%s)\n",
			buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH)
		return
	}

	logf("Starting publisher version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(),
		runtime.GOOS, runtime.GOARCH)

	listenAddr, err := app.ListenAddress()
	if err != nil {
		logger.Fatalf("Listen address: %v", err)
	}
	conf, err := appConfig()
	if err != nil {
		logger.Fatalf("no app config: %v", err)
	}
	ph := newPublishHandler(conf)
	masterQueryURL := os.Getenv("CAMLI_APP_MASTERQUERY_URL")
	if masterQueryURL == "" {
		logger.Fatalf("Publisher application needs a CAMLI_APP_MASTERQUERY_URL env var")
	}
	ph.masterQueryURL = masterQueryURL
	if err := ph.initRootNode(); err != nil {
		logf("%v", err)
	} else {
		if err := ph.setMasterQuery(ph.rootNode); err != nil {
			logf("%v", err)
		}
	}
	ws := webserver.New()
	ws.Logger = logger
	if err := setupTLS(ws, conf); err != nil {
		logger.Fatal("could not setup TLS: %v", err)
	}
	ws.Handle("/", ph)
	if err := ws.Listen(listenAddr); err != nil {
		logger.Fatalf("Listen: %v", err)
	}
	ws.Serve()
}
示例#12
0
func (sh *StatusHandler) currentStatus() *status {
	res := &status{
		Version: buildinfo.Version(),
		Storage: make(map[string]storageStatus),
		Sync:    make(map[string]syncStatus),
	}
	if v := os.Getenv("CAMLI_FAKE_STATUS_ERROR"); v != "" {
		res.addError(v, "/status/#fakeerror")
	}
	_, hi, err := sh.handlerFinder.FindHandlerByType("root")
	if err != nil {
		res.addError(fmt.Sprintf("Error finding root handler: %v", err), "")
		return res
	}
	rh := hi.(*RootHandler)
	res.rootPrefix = rh.Prefix

	if pfx, h, err := sh.handlerFinder.FindHandlerByType("importer"); err == nil {
		res.importerRoot = pfx
		as := h.(interface {
			AccountsStatus() (interface{}, []camtypes.StatusError)
		})
		var errs []camtypes.StatusError
		res.ImporterAccounts, errs = as.AccountsStatus()
		res.Errors = append(res.Errors, errs...)
	}

	types, handlers := sh.handlerFinder.AllHandlers()

	// Sync
	for pfx, h := range handlers {
		sh, ok := h.(*SyncHandler)
		if !ok {
			continue
		}
		res.Sync[pfx] = sh.currentStatus()
	}

	// Storage
	for pfx, typ := range types {
		if !strings.HasPrefix(typ, "storage-") {
			continue
		}
		h := handlers[pfx]
		_, isIndex := h.(*index.Index)
		res.Storage[pfx] = storageStatus{
			Type:    strings.TrimPrefix(typ, "storage-"),
			Primary: pfx == rh.BlobRoot,
			IsIndex: isIndex,
		}
	}

	return res
}
示例#13
0
func (sh *StatusHandler) serveStatusHTML(rw http.ResponseWriter, req *http.Request) {
	st := sh.currentStatus()
	f := func(p string, a ...interface{}) {
		if len(a) == 0 {
			io.WriteString(rw, p)
		} else {
			fmt.Fprintf(rw, p, a...)
		}
	}
	f("<html><head><title>camlistored status</title></head>")
	f("<body>")

	f("<h1>camlistored status</h1>")

	f("<h2>Versions</h2><ul>")
	var envStr string
	if env.OnGCE() {
		envStr = " (on GCE)"
	}
	f("<li><b>Camlistore</b>: %s%s</li>", html.EscapeString(buildinfo.Version()), envStr)
	f("<li><b>Go</b>: %s/%s %s, cgo=%v</li>", runtime.GOOS, runtime.GOARCH, runtime.Version(), cgoEnabled)
	f("<li><b>djpeg</b>: %s", html.EscapeString(buildinfo.DjpegStatus()))
	f("</ul>")

	f("<h2>Logs</h2><ul>")
	f("  <li><a href='/debug/config'>/debug/config</a> - server config</li>\n")
	if env.OnGCE() {
		f("  <li><a href='/debug/logs/camlistored'>camlistored logs on Google Cloud Logging</a></li>\n")
		f("  <li><a href='/debug/logs/system'>system logs from Google Compute Engine</a></li>\n")
	}
	f("</ul>")

	f("<h2>Admin</h2>")
	f("<form method='post' action='restart' onsubmit='return confirm(\"Really restart now?\")'><button>restart server</button></form>")

	f("<h2>Handlers</h2>")
	f("<p>As JSON: <a href='status.json'>status.json</a>; and the <a href='%s?camli.mode=config'>discovery JSON</a>.</p>", st.rootPrefix)
	f("<p>Not yet pretty HTML UI:</p>")
	js, err := json.MarshalIndent(st, "", "  ")
	if err != nil {
		log.Printf("JSON marshal error: %v", err)
	}
	jsh := html.EscapeString(string(js))
	jsh = quotedPrefix.ReplaceAllStringFunc(jsh, func(in string) string {
		pfx := in[1 : len(in)-1]
		if st.isHandler(pfx) {
			return fmt.Sprintf("%s<a href='%s'>%s</a>%s", in[:1], pfx, pfx, in[len(in)-1:])
		}
		return in
	})
	f("<pre>%s</pre>", jsh)
}
示例#14
0
// Main is meant to be the core of a command that has
// subcommands (modes), such as camput or camtool.
func Main() error {
	ExtraFlagRegistration()
	flag.Parse()
	args := flag.Args()
	if *FlagVersion {
		fmt.Fprintf(Stderr, "camput version: %s\n", buildinfo.Version())
		return nil
	}
	if *FlagHelp {
		usage("")
	}
	if len(args) == 0 {
		usage("No mode given.")
	}

	mode := args[0]
	cmd, ok := modeCommand[mode]
	if !ok {
		usage(fmt.Sprintf("Unknown mode %q", mode))
	}

	cmdFlags := modeFlags[mode]
	err := cmdFlags.Parse(args[1:])
	if err != nil {
		err = ErrUsage
	} else {
		err = cmd.RunCommand(cmdFlags.Args())
	}
	if ue, isUsage := err.(UsageError); isUsage {
		if isUsage {
			Errf("%s\n", ue)
		}
		cmd.Usage()
		Errf("\nGlobal options:\n")
		flag.PrintDefaults()

		if hasFlags(cmdFlags) {
			Errf("\nMode-specific options for mode %q:\n", mode)
			cmdFlags.PrintDefaults()
		}
		Exit(1)
	}
	if *FlagVerbose {
		PreExit()
	}
	return err
}
示例#15
0
func (rh *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if wantsDiscovery(r) {
		if auth.Allowed(r, auth.OpDiscovery) {
			rh.serveDiscovery(w, r)
			return
		}
		if !rh.Stealth {
			auth.SendUnauthorized(w, r)
		}
		return
	}

	if rh.Stealth {
		return
	}
	if r.RequestURI == "/" && rh.ui != nil {
		http.Redirect(w, r, "/ui/", http.StatusMovedPermanently)
		return
	}
	if r.URL.Path == "/favicon.ico" {
		ServeStaticFile(w, r, Files, "favicon.ico")
		return
	}
	f := func(p string, a ...interface{}) {
		fmt.Fprintf(w, p, a...)
	}
	f("<html><body><p>This is camlistored (%s), a "+
		"<a href='http://camlistore.org'>Camlistore</a> server.</p>", buildinfo.Version())
	if rh.ui != nil {
		f("<p>To manage your content, access the <a href='%s'>%s</a>.</p>", rh.ui.prefix, rh.ui.prefix)
	}
	if rh.statusRoot != "" {
		f("<p>To view status, see <a href='%s'>%s</a>.</p>", rh.statusRoot, rh.statusRoot)
	}
	if rh.helpRoot != "" {
		f("<p>To view more information on accessing the server, see <a href='%s'>%s</a>.</p>", rh.helpRoot, rh.helpRoot)
	}
	fmt.Fprintf(w, "</body></html>")
}
示例#16
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)
}
示例#17
0
func (sh *StatusHandler) serveStatusHTML(rw http.ResponseWriter, req *http.Request) {
	st := sh.currentStatus()
	f := func(p string, a ...interface{}) {
		if len(a) == 0 {
			io.WriteString(rw, p)
		} else {
			fmt.Fprintf(rw, p, a...)
		}
	}
	f("<html><head><title>camlistored status</title></head>")
	f("<body>")

	f("<h1>camlistored status</h1>")

	f("<h2>Versions</h2><ul>")
	var envStr string
	if env.OnGCE() {
		envStr = " (on GCE)"
	}
	f("<li><b>Camlistore</b>: %s%s</li>", html.EscapeString(buildinfo.Version()), envStr)
	f("<li><b>Go</b>: %s/%s %s, cgo=%v</li>", runtime.GOOS, runtime.GOARCH, runtime.Version(), cgoEnabled)
	f("<li><b>djpeg</b>: %s", html.EscapeString(buildinfo.DjpegStatus()))
	f("</ul>")

	f("<h2>Logs</h2><ul>")
	f("  <li><a href='/debug/config'>/debug/config</a> - server config</li>\n")
	if env.OnGCE() {
		f("  <li><a href='/debug/logs/camlistored'>camlistored logs on Google Cloud Logging</a></li>\n")
		f("  <li><a href='/debug/logs/system'>system logs from Google Compute Engine</a></li>\n")
	}
	f("</ul>")

	f("<h2>Admin</h2>")
	f("<ul>")
	f("  <li><form method='post' action='restart' onsubmit='return confirm(\"Really restart now?\")'><button>restart server</button>")
	f("<input type='checkbox' name='reindex'> reindex</form></li>")
	if env.OnGCE() {
		console, err := sh.googleCloudConsole()
		if err != nil {
			log.Printf("error getting Google Cloud Console URL: %v", err)
		} else {
			f("   <li><b>Updating:</b> When a new image for Camlistore on GCE is available, you can update by hitting \"Reset\" (or \"Stop\", then \"Start\") for your instance on your <a href='%s'>Google Cloud Console</a>.<br>Alternatively, you can ssh to your instance and restart the Camlistore service with: <b>sudo systemctl restart camlistored</b>.</li>", console)
		}
	}
	f("</ul>")

	f("<h2>Handlers</h2>")
	f("<p>As JSON: <a href='status.json'>status.json</a>; and the <a href='%s?camli.mode=config'>discovery JSON</a>.</p>", st.rootPrefix)
	f("<p>Not yet pretty HTML UI:</p>")
	js, err := json.MarshalIndent(st, "", "  ")
	if err != nil {
		log.Printf("JSON marshal error: %v", err)
	}
	jsh := html.EscapeString(string(js))
	jsh = quotedPrefix.ReplaceAllStringFunc(jsh, func(in string) string {
		pfx := in[1 : len(in)-1]
		if st.isHandler(pfx) {
			return fmt.Sprintf("%s<a href='%s'>%s</a>%s", in[:1], pfx, pfx, in[len(in)-1:])
		}
		return in
	})
	f("<pre>%s</pre>", jsh)
}
示例#18
0
func main() {
	client.AddFlags()
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "camget version: %s\n", buildinfo.Version())
		return
	}

	if *flagGraph && flag.NArg() != 1 {
		log.Fatalf("The --graph option requires exactly one parameter.")
	}

	var cl *client.Client
	var items []*blobref.BlobRef

	if *flagShared != "" {
		if client.ExplicitServer() != "" {
			log.Fatal("Can't use --shared with an explicit blobserver; blobserver is implicit from the --shared URL.")
		}
		if flag.NArg() != 0 {
			log.Fatal("No arguments permitted when using --shared")
		}
		cl1, target, err := client.NewFromShareRoot(*flagShared,
			client.OptionInsecure(*flagInsecureTLS))
		if err != nil {
			log.Fatal(err)
		}
		cl = cl1
		items = append(items, target)
	} else {
		cl = client.NewOrFail()
		for n := 0; n < flag.NArg(); n++ {
			arg := flag.Arg(n)
			br := blobref.Parse(arg)
			if br == nil {
				log.Fatalf("Failed to parse argument %q as a blobref.", arg)
			}
			items = append(items, br)
		}
	}

	cl.InsecureTLS = *flagInsecureTLS
	tr := cl.TransportForConfig(&client.TransportConfig{
		Verbose: *flagHTTP,
	})
	httpStats, _ := tr.(*httputil.StatsTransport)
	cl.SetHTTPClient(&http.Client{Transport: tr})

	diskCacheFetcher, err := cacher.NewDiskCache(cl)
	if err != nil {
		log.Fatalf("Error setting up local disk cache: %v", err)
	}
	defer diskCacheFetcher.Clean()
	if *flagVerbose {
		log.Printf("Using temp blob cache directory %s", diskCacheFetcher.Root)
	}

	for _, br := range items {
		if *flagGraph {
			printGraph(diskCacheFetcher, br)
			return
		}
		if *flagCheck {
			// TODO: do HEAD requests checking if the blobs exists.
			log.Fatal("not implemented")
			return
		}
		if *flagOutput == "-" {
			var rc io.ReadCloser
			var err error
			if *flagContents {
				rc, err = schema.NewFileReader(diskCacheFetcher, br)
				if err == nil {
					rc.(*schema.FileReader).LoadAllChunks()
				}
			} else {
				rc, err = fetch(diskCacheFetcher, br)
			}
			if err != nil {
				log.Fatal(err)
			}
			defer rc.Close()
			if _, err := io.Copy(os.Stdout, rc); err != nil {
				log.Fatalf("Failed reading %q: %v", br, err)
			}
		} else {
			if err := smartFetch(diskCacheFetcher, *flagOutput, br); err != nil {
				log.Fatal(err)
			}
		}
	}

	if *flagVerbose {
		log.Printf("HTTP requests: %d\n", httpStats.Requests())
	}
}
示例#19
0
func main() {
	client.AddFlags()
	flag.Parse()

	if *cmdmain.FlagHelp {
		flag.PrintDefaults()
	}

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "camget version: %s\n", buildinfo.Version())
		return
	}

	if *cmdmain.FlagLegal {
		cmdmain.PrintLicenses()
		return
	}

	if *flagGraph && flag.NArg() != 1 {
		log.Fatalf("The --graph option requires exactly one parameter.")
	}

	var cl *client.Client
	var items []blob.Ref

	optTransportConfig := client.OptionTransportConfig(&client.TransportConfig{
		Verbose: *flagHTTP,
	})

	if *flagShared != "" {
		if client.ExplicitServer() != "" {
			log.Fatal("Can't use --shared with an explicit blobserver; blobserver is implicit from the --shared URL.")
		}
		if flag.NArg() != 0 {
			log.Fatal("No arguments permitted when using --shared")
		}
		cl1, target, err := client.NewFromShareRoot(*flagShared,
			client.OptionInsecure(*flagInsecureTLS),
			client.OptionTrustedCert(*flagTrustedCert),
			optTransportConfig,
		)
		if err != nil {
			log.Fatal(err)
		}
		cl = cl1
		items = append(items, target)
	} else {
		if *flagTrustedCert != "" {
			log.Fatal("Can't use --cert without --shared.")
		}
		cl = client.NewOrFail(client.OptionInsecure(*flagInsecureTLS), optTransportConfig)
		for n := 0; n < flag.NArg(); n++ {
			arg := flag.Arg(n)
			br, ok := blob.Parse(arg)
			if !ok {
				log.Fatalf("Failed to parse argument %q as a blobref.", arg)
			}
			items = append(items, br)
		}
	}

	httpStats := cl.HTTPStats()

	diskCacheFetcher, err := cacher.NewDiskCache(cl)
	if err != nil {
		log.Fatalf("Error setting up local disk cache: %v", err)
	}
	defer diskCacheFetcher.Clean()
	if *flagVerbose {
		log.Printf("Using temp blob cache directory %s", diskCacheFetcher.Root)
	}
	if *flagShared != "" {
		diskCacheFetcher.SetCacheHitHook(func(br blob.Ref, rc io.ReadCloser) (io.ReadCloser, error) {
			var buf bytes.Buffer
			if err := cl.UpdateShareChain(br, io.TeeReader(rc, &buf)); err != nil {
				rc.Close()
				return nil, err
			}
			return struct {
				io.Reader
				io.Closer
			}{io.MultiReader(&buf, rc), rc}, nil
		})
	}

	for _, br := range items {
		if *flagGraph {
			printGraph(diskCacheFetcher, br)
			return
		}
		if *flagCheck {
			// TODO: do HEAD requests checking if the blobs exists.
			log.Fatal("not implemented")
			return
		}
		if *flagOutput == "-" {
			var rc io.ReadCloser
			var err error
			if *flagContents {
				rc, err = schema.NewFileReader(diskCacheFetcher, br)
				if err == nil {
					rc.(*schema.FileReader).LoadAllChunks()
				}
			} else {
				rc, err = fetch(diskCacheFetcher, br)
			}
			if err != nil {
				log.Fatal(err)
			}
			defer rc.Close()
			if _, err := io.Copy(os.Stdout, rc); err != nil {
				log.Fatalf("Failed reading %q: %v", br, err)
			}
		} else {
			if err := smartFetch(diskCacheFetcher, *flagOutput, br); err != nil {
				log.Fatal(err)
			}
		}
	}

	if *flagVerbose {
		log.Printf("HTTP requests: %d\n", httpStats.Requests())
		h1, h2 := httpStats.ProtoVersions()
		log.Printf("    responses: %d (h1), %d (h2)\n", h1, h2)
	}
}
示例#20
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 *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)

	fileName, isNewConfig, err := findConfigFile(*flagConfigFile)
	if err != nil {
		exitf("Error finding config file %q: %v", fileName, err)
	}
	log.Printf("Using config file %s", fileName)
	config, err := serverinit.Load(fileName)
	if err != nil {
		exitf("Could not load server config: %v", err)
	}

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

	setupTLS(ws, config, listen)

	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
	}

	log.Printf("Available on %s", urlToOpen)
	if *flagOpenBrowser {
		go osutil.OpenURL(urlToOpen)
	}

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

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