Beispiel #1
0
func Start(dir string, port int, tlsCrt, tlsKey, jwtPubKey, jwtPrivateKey string) {
	var err error
	HttpDB, err = db.OpenDB(dir)
	if err != nil {
		panic(err)
	}

	// These endpoints are always available and do not require JWT auth
	http.HandleFunc("/", Welcome)
	http.HandleFunc("/version", Version)
	http.HandleFunc("/memstats", MemStats)

	if jwtPrivateKey != "" {
		// JWT support
		ServeJWTEnabledEndpoints(jwtPubKey, jwtPrivateKey)
	} else {
		// No JWT
		ServeEndpoints()
	}

	if tlsCrt != "" {
		tdlog.Noticef("Will listen on all interfaces (HTTPS), port %d.", port)
		if err := http.ListenAndServeTLS(fmt.Sprintf(":%d", port), tlsCrt, tlsKey, nil); err != nil {
			tdlog.Panicf("Failed to start HTTPS service - %s", err)
		}
	} else {
		tdlog.Noticef("Will listen on all interfaces (HTTP), port %d.", port)
		http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
	}
}
Beispiel #2
0
func ServeJWTEnabledEndpoints(jwtPubKey, jwtPrivateKey string) {
	var e error
	if publicKey, e = ioutil.ReadFile(jwtPubKey); e != nil {
		tdlog.Panicf("JWT: Failed to read public key file - %s", e)
	} else if privateKey, e = ioutil.ReadFile(jwtPrivateKey); e != nil {
		tdlog.Panicf("JWT: Failed to read private key file - %s", e)
	}

	jwtInitSetup()

	// collection management (stop-the-world)
	http.HandleFunc("/create", jwtWrap(Create))
	http.HandleFunc("/rename", jwtWrap(Rename))
	http.HandleFunc("/drop", jwtWrap(Drop))
	http.HandleFunc("/all", jwtWrap(All))
	http.HandleFunc("/scrub", jwtWrap(Scrub))
	http.HandleFunc("/sync", jwtWrap(Sync))
	// query
	http.HandleFunc("/query", jwtWrap(Query))
	http.HandleFunc("/count", jwtWrap(Count))
	// document management
	http.HandleFunc("/insert", jwtWrap(Insert))
	http.HandleFunc("/get", jwtWrap(Get))
	http.HandleFunc("/getpage", jwtWrap(GetPage))
	http.HandleFunc("/update", jwtWrap(Update))
	http.HandleFunc("/delete", jwtWrap(Delete))
	http.HandleFunc("/approxdoccount", jwtWrap(ApproxDocCount))
	// index management (stop-the-world)
	http.HandleFunc("/index", jwtWrap(Index))
	http.HandleFunc("/indexes", jwtWrap(Indexes))
	http.HandleFunc("/unindex", jwtWrap(Unindex))
	// misc
	http.HandleFunc("/shutdown", jwtWrap(Shutdown))
	http.HandleFunc("/dump", jwtWrap(Dump))
	// does not require JWT auth
	http.HandleFunc("/getjwt", getJWT)
	http.HandleFunc("/checkjwt", checkJWT)

	tdlog.Noticef("JWT is enabled. API endpoints require JWT authorization.")
}
Beispiel #3
0
// If necessary, create the JWT identity collection, indexes, and the default/special user identity "admin".
func jwtInitSetup() {
	// Create collection
	if HttpDB.Use(JWT_COL_NAME) == nil {
		if err := HttpDB.Create(JWT_COL_NAME); err != nil {
			tdlog.Panicf("JWT: failed to create JWT identity collection - %v", err)
		}
	}
	jwtCol := HttpDB.Use(JWT_COL_NAME)
	// Create indexes on ID attribute
	indexPaths := make(map[string]struct{})
	for _, oneIndex := range jwtCol.AllIndexes() {
		indexPaths[strings.Join(oneIndex, db.INDEX_PATH_SEP)] = struct{}{}
	}
	if _, exists := indexPaths[JWT_USER_ATTR]; !exists {
		if err := jwtCol.Index([]string{JWT_USER_ATTR}); err != nil {
			tdlog.Panicf("JWT: failed to create collection index - %v", err)
		}
	}
	// Create default user "admin"
	adminQuery := map[string]interface{}{
		"eq": JWT_USER_ADMIN,
		"in": []interface{}{JWT_USER_ATTR}}
	adminQueryResult := make(map[int]struct{})
	if err := db.EvalQuery(adminQuery, jwtCol, &adminQueryResult); err != nil {
		tdlog.Panicf("JWT: failed to query admin user ID - %v", err)
	}
	if len(adminQueryResult) == 0 {
		if _, err := jwtCol.Insert(map[string]interface{}{
			JWT_USER_ATTR:        JWT_USER_ADMIN,
			JWT_PASS_ATTR:        "",
			JWT_COLLECTIONS_ATTR: []interface{}{},
			JWT_ENDPOINTS_ATTR:   []interface{}{}}); err != nil {
			tdlog.Panicf("JWT: failed to create default admin user - %v", err)
		}
		tdlog.Notice("JWT: successfully initialized DB for JWT features. The default user 'admin' has been created.")
	}
}
Beispiel #4
0
func main() {
	var err error
	var defaultMaxprocs int
	if defaultMaxprocs, err = strconv.Atoi(os.Getenv("GOMAXPROCS")); err != nil {
		defaultMaxprocs = runtime.NumCPU()
	}

	// Parse CLI parameters
	var mode, dir string
	var port, maxprocs int
	var profile bool
	flag.StringVar(&mode, "mode", "", "[httpd|bench|bench2|example]")
	flag.StringVar(&dir, "dir", "", "(HTTP API) database directory")
	flag.IntVar(&port, "port", 8080, "(HTTP API) port number")
	flag.StringVar(&webcp.WebCp, "webcp", "admin", "(HTTP API) web control panel route (without leading slash)")
	flag.IntVar(&maxprocs, "gomaxprocs", defaultMaxprocs, "GOMAXPROCS")
	flag.IntVar(&benchSize, "benchsize", 400000, "Benchmark sample size")
	flag.BoolVar(&profile, "profile", false, "Write profiler results to prof.out")
	flag.BoolVar(&tdlog.VerboseLog, "verbose", false, "Turn verbose logging on/off")
	flag.BoolVar(&benchCleanup, "benchcleanup", true, "Whether to clean up (delete benchmark DB) after benchmark")
	flag.Parse()

	// User must specify a mode to run
	if mode == "" {
		flag.PrintDefaults()
		return
	}

	// Set appropriate GOMAXPROCS
	runtime.GOMAXPROCS(maxprocs)
	tdlog.Noticef("GOMAXPROCS is set to %d", maxprocs)
	if maxprocs < runtime.NumCPU() {
		tdlog.Noticef("GOMAXPROCS (%d) is less than number of CPUs (%d), this may reduce performance. You can change it via environment variable GOMAXPROCS or by passing CLI parameter -gomaxprocs", maxprocs, runtime.NumCPU())
	}

	// Start profiler if enabled
	if profile {
		resultFile, err := os.Create("perf.out")
		if err != nil {
			log.Panicf("Cannot create profiler result file %s", resultFile)
		}
		pprof.StartCPUProfile(resultFile)
		defer pprof.StopCPUProfile()
	}

	switch mode {
	case "httpd": // Run HTTP API server
		if dir == "" {
			tdlog.Panicf("Please specify database directory, for example -dir=/tmp/db")
		}
		if port == 0 {
			tdlog.Panicf("Please specify port number, for example -port=8080")
		}
		db, err := db.OpenDB(dir)
		if err != nil {
			panic(err)
		}
		httpapi.Start(db, port)
	case "example": // Run embedded usage examples
		embeddedExample()
	case "bench": // Benchmark scenarios
		benchmark()
	case "bench2":
		benchmark2()
	default:
		flag.PrintDefaults()
		return
	}
}
Beispiel #5
0
// Start HTTP server and block until the server shuts down. Panic on error.
func Start(dir string, port int, tlsCrt, tlsKey, jwtPubKey, jwtPrivateKey, bind, authToken string) {
	var err error
	HttpDB, err = db.OpenDB(dir)
	if err != nil {
		panic(err)
	}

	// These endpoints are always available and do not require authentication
	http.HandleFunc("/", Welcome)
	http.HandleFunc("/version", Version)
	http.HandleFunc("/memstats", MemStats)

	// Install API endpoint handlers that may require authorization
	var authWrap func(http.HandlerFunc) http.HandlerFunc
	if authToken != "" {
		tdlog.Noticef("API endpoints now require the pre-shared token in Authorization header.")
		authWrap = func(originalHandler http.HandlerFunc) http.HandlerFunc {
			return func(w http.ResponseWriter, r *http.Request) {
				if "token "+authToken != r.Header.Get("Authorization") {
					http.Error(w, "", http.StatusUnauthorized)
					return
				}
				originalHandler(w, r)
			}
		}
	} else if jwtPubKey != "" && jwtPrivateKey != "" {
		tdlog.Noticef("API endpoints now require JWT in Authorization header.")
		var publicKeyContent, privateKeyContent []byte
		if publicKeyContent, err = ioutil.ReadFile(jwtPubKey); err != nil {
			panic(err)
		} else if publicKey, err = jwt.ParseRSAPublicKeyFromPEM(publicKeyContent); err != nil {
			panic(err)
		} else if privateKeyContent, err = ioutil.ReadFile(jwtPrivateKey); err != nil {
			panic(err)
		} else if privateKey, err = jwt.ParseRSAPrivateKeyFromPEM(privateKeyContent); err != nil {
			panic(err)
		}
		jwtInitSetup()
		authWrap = jwtWrap
		// does not require JWT auth
		http.HandleFunc("/getjwt", getJWT)
		http.HandleFunc("/checkjwt", checkJWT)
	} else {
		tdlog.Noticef("API endpoints do not require Authorization header.")
		authWrap = func(originalHandler http.HandlerFunc) http.HandlerFunc {
			return originalHandler
		}
	}
	// collection management (stop-the-world)
	http.HandleFunc("/create", authWrap(Create))
	http.HandleFunc("/rename", authWrap(Rename))
	http.HandleFunc("/drop", authWrap(Drop))
	http.HandleFunc("/all", authWrap(All))
	http.HandleFunc("/scrub", authWrap(Scrub))
	http.HandleFunc("/sync", authWrap(Sync))
	// query
	http.HandleFunc("/query", authWrap(Query))
	http.HandleFunc("/count", authWrap(Count))
	// document management
	http.HandleFunc("/insert", authWrap(Insert))
	http.HandleFunc("/get", authWrap(Get))
	http.HandleFunc("/getpage", authWrap(GetPage))
	http.HandleFunc("/update", authWrap(Update))
	http.HandleFunc("/delete", authWrap(Delete))
	http.HandleFunc("/approxdoccount", authWrap(ApproxDocCount))
	// index management (stop-the-world)
	http.HandleFunc("/index", authWrap(Index))
	http.HandleFunc("/indexes", authWrap(Indexes))
	http.HandleFunc("/unindex", authWrap(Unindex))
	// misc (stop-the-world)
	http.HandleFunc("/shutdown", authWrap(Shutdown))
	http.HandleFunc("/dump", authWrap(Dump))

	iface := "all interfaces"
	if bind != "" {
		iface = bind
	}

	if tlsCrt != "" {
		tdlog.Noticef("Will listen on %s (HTTPS), port %d.", iface, port)
		if err := http.ListenAndServeTLS(fmt.Sprintf("%s:%d", bind, port), tlsCrt, tlsKey, nil); err != nil {
			tdlog.Panicf("Failed to start HTTPS service - %s", err)
		}
	} else {
		tdlog.Noticef("Will listen on %s (HTTP), port %d.", iface, port)
		http.ListenAndServe(fmt.Sprintf("%s:%d", bind, port), nil)
	}
}
Beispiel #6
0
func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	var err error
	var defaultMaxprocs int
	if defaultMaxprocs, err = strconv.Atoi(os.Getenv("GOMAXPROCS")); err != nil {
		defaultMaxprocs = runtime.NumCPU() * 2
	}

	// Parse CLI parameters
	var mode, dir string
	var port, maxprocs, benchSize int
	var profile bool
	flag.StringVar(&mode, "mode", "", "http|bench|bench2|bench3|example]")
	flag.StringVar(&dir, "dir", "", "database directory")
	flag.IntVar(&port, "port", 0, "listening port number")
	flag.IntVar(&maxprocs, "gomaxprocs", defaultMaxprocs, "GOMAXPROCS")
	flag.IntVar(&benchSize, "benchsize", 400000, "Benchmark sample size")
	flag.BoolVar(&profile, "profile", false, "write profiler results to prof.out")
	flag.BoolVar(&tdlog.VerboseLog, "verbose", true, "verbose logging true/false (default is true)")
	flag.Parse()

	// User must specify a mode to run
	if mode == "" {
		flag.PrintDefaults()
		return
	}

	// Setup appropriate GOMAXPROCS parameter
	runtime.GOMAXPROCS(maxprocs)
	tdlog.Printf("GOMAXPROCS is set to %d", maxprocs)
	if maxprocs < runtime.NumCPU() {
		tdlog.Printf("GOMAXPROCS (%d) is less than number of CPUs (%d), this may affect performance. You can change it via environment variable GOMAXPROCS or by passing CLI parameter -gomaxprocs", maxprocs, runtime.NumCPU())
	}

	// Start profiler if enabled
	if profile {
		resultFile, err := os.Create("perf.out")
		if err != nil {
			tdlog.Panicf("Cannot create profiler result file %s", resultFile)
		}
		pprof.StartCPUProfile(resultFile)
		defer pprof.StopCPUProfile()
	}

	switch mode {
	case "http": // Run HTTP service (API V3)
		if dir == "" {
			tdlog.Fatal("Please specify database directory, for example -dir=/tmp/db")
		}
		if port == 0 {
			tdlog.Fatal("Please specify port number, for example -port=8080")
		}
		db, err := db.OpenDB(dir)
		if err != nil {
			tdlog.Fatal(err)
		}
		v3.Start(db, port)

	case "bench": // Benchmark scenarios
		benchmark(benchSize)
	case "bench2":
		benchmark2(benchSize)
	case "bench3":
		benchmark3(benchSize)

	case "example": // Embedded usage example
		embeddedExample()
	default:
		flag.PrintDefaults()
		return
	}
}