Example #1
0
// InitRESTRouter initializes a mux.Router with REST API
// routes.
func InitRESTRouter(r *mux.Router, versionMain string,
	mgr *cbgt.Manager, staticDir, staticETag string,
	mr *cbgt.MsgRing,
	assetDir func(name string) ([]string, error),
	asset func(name string) ([]byte, error)) (
	*mux.Router, map[string]RESTMeta, error) {
	PIndexTypesInitRouter(r, "manager.before")

	meta := map[string]RESTMeta{}
	handle := func(path string, method string, h http.Handler,
		opts map[string]string) {
		if a, ok := h.(RESTOpts); ok {
			a.RESTOpts(opts)
		}
		meta[path+" "+RESTMethodOrds[method]+method] =
			RESTMeta{path, method, opts}
		r.Handle(path, h).Methods(method)
	}
	handleFunc := func(path string, method string, h http.HandlerFunc,
		opts map[string]string) {
		meta[path+" "+RESTMethodOrds[method]+method] =
			RESTMeta{path, method, opts}
		r.HandleFunc(path, h).Methods(method)
	}

	handle("/api/index", "GET", NewListIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Returns all index definitions as JSON.`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}", "PUT", NewCreateIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Creates/updates an index definition.`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}", "DELETE", NewDeleteIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Deletes an index definition.`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}", "GET", NewGetIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Returns the definition of an index as JSON.`,
			"version introduced": "0.0.1",
		})

	if mgr == nil || mgr.TagsMap() == nil || mgr.TagsMap()["queryer"] {
		handle("/api/index/{indexName}/count", "GET",
			NewCountHandler(mgr),
			map[string]string{
				"_category":          "Indexing|Index querying",
				"_about":             `Returns the count of indexed documents.`,
				"version introduced": "0.0.1",
			})
		handle("/api/index/{indexName}/query", "POST",
			NewQueryHandler(mgr),
			map[string]string{
				"_category":          "Indexing|Index querying",
				"_about":             `Queries an index.`,
				"version introduced": "0.2.0",
			})
	}

	handle("/api/index/{indexName}/planFreezeControl/{op}", "POST",
		NewIndexControlHandler(mgr, "planFreeze", map[string]bool{
			"freeze":   true,
			"unfreeze": true,
		}),
		map[string]string{
			"_category": "Indexing|Index management",
			"_about":    `Freeze the assignment of index partitions to nodes.`,
			"param: op": "required, string, URL path parameter\n\n" +
				`Allowed values for op are "freeze" or "unfreeze".`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}/ingestControl/{op}", "POST",
		NewIndexControlHandler(mgr, "write", map[string]bool{
			"pause":  true,
			"resume": true,
		}),
		map[string]string{
			"_category": "Indexing|Index management",
			"_about": `Pause index updates and maintenance (no more
                          ingesting document mutations).`,
			"param: op": "required, string, URL path parameter\n\n" +
				`Allowed values for op are "pause" or "resume".`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}/queryControl/{op}", "POST",
		NewIndexControlHandler(mgr, "read", map[string]bool{
			"allow":    true,
			"disallow": true,
		}),
		map[string]string{
			"_category": "Indexing|Index management",
			"_about":    `Disallow queries on an index.`,
			"param: op": "required, string, URL path parameter\n\n" +
				`Allowed values for op are "allow" or "disallow".`,
			"version introduced": "0.0.1",
		})

	if mgr == nil || mgr.TagsMap() == nil || mgr.TagsMap()["pindex"] {
		handle("/api/pindex", "GET",
			NewListPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition definition",
				"version introduced": "0.0.1",
			})
		handle("/api/pindex/{pindexName}", "GET",
			NewGetPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition definition",
				"version introduced": "0.0.1",
			})
		handle("/api/pindex/{pindexName}/count", "GET",
			NewCountPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition querying",
				"version introduced": "0.0.1",
			})
		handle("/api/pindex/{pindexName}/query", "POST",
			NewQueryPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition querying",
				"version introduced": "0.2.0",
			})
	}

	handle("/api/cfg", "GET", NewCfgGetHandler(mgr),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Returns the node's current view
                       of the cluster's configuration as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/cfgRefresh", "POST", NewCfgRefreshHandler(mgr),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Requests the node to refresh its configuration
                       from the configuration provider.`,
			"version introduced": "0.0.1",
		})

	handle("/api/log", "GET", NewLogGetHandler(mgr, mr),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns recent log messages
                       and key events for the node as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/managerKick", "POST", NewManagerKickHandler(mgr),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Forces the node to replan resource assignments
                       (by running the planner, if enabled) and to update
                       its runtime state to reflect the latest plan
                       (by running the janitor, if enabled).`,
			"version introduced": "0.0.1",
		})

	handle("/api/managerMeta", "GET", NewManagerMetaHandler(mgr, meta),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Returns information on the node's capabilities,
                       including available indexing and storage options as JSON,
                       and is intended to help management tools and web UI's
                       to be more dynamically metadata driven.`,
			"version introduced": "0.0.1",
		})

	handle("/api/runtime", "GET",
		NewRuntimeGetHandler(versionMain, mgr),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns information on the node's software,
                       such as version strings and slow-changing
                       runtime settings as JSON.`,
			"version introduced": "0.0.1",
		})

	handleFunc("/api/runtime/args", "GET",
		RESTGetRuntimeArgs, map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns information on the node's command-line,
                       parameters, environment variables and
                       O/S process values as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/diag", "GET",
		NewDiagGetHandler(versionMain, mgr, mr, assetDir, asset),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns full set of diagnostic information
                        from the node in one shot as JSON.  That is, the
                        /api/diag response will be the union of the responses
                        from the other REST API diagnostic and monitoring
                        endpoints from the node, and is intended to make
                        production support easier.`,
			"version introduced": "0.0.1",
		})

	handleFunc("/api/runtime/gc", "POST",
		RESTPostRuntimeGC, map[string]string{
			"_category":          "Node|Node management",
			"_about":             `Requests the node to perform a GC.`,
			"version introduced": "0.0.1",
		})

	handleFunc("/api/runtime/profile/cpu", "POST",
		RESTProfileCPU, map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Requests the node to capture local
                       cpu usage profiling information.`,
			"version introduced": "0.0.1",
		})

	handleFunc("/api/runtime/profile/memory", "POST",
		RESTProfileMemory, map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Requests the node to capture lcoal
                       memory usage profiling information.`,
			"version introduced": "0.0.1",
		})

	handleFunc("/api/runtime/stats", "GET",
		RESTGetRuntimeStats, map[string]string{
			"_category": "Node|Node monitoring",
			"_about": `Returns information on the node's
                       low-level runtime stats as JSON.`,
			"version introduced": "0.0.1",
		})

	handleFunc("/api/runtime/statsMem", "GET",
		RESTGetRuntimeStatsMem, map[string]string{
			"_category": "Node|Node monitoring",
			"_about": `Returns information on the node's
                       low-level GC and memory related runtime stats as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/stats", "GET", NewStatsHandler(mgr),
		map[string]string{
			"_category": "Indexing|Index monitoring",
			"_about": `Returns indexing and data related metrics,
                       timings and counters from the node as JSON.`,
			"version introduced": "0.0.1",
		})

	// TODO: If we ever implement cluster-wide index stats, we should
	// have it under /api/index/{indexName}/stats GET endpoint.
	//
	handle("/api/stats/index/{indexName}", "GET", NewStatsHandler(mgr),
		map[string]string{
			"_category": "Indexing|Index monitoring",
			"_about": `Returns metrics, timings and counters
                       for a single index from the node as JSON.`,
			"version introduced": "0.0.1",
		})

	PIndexTypesInitRouter(r, "manager.after")

	return r, meta, nil
}
Example #2
0
// InitRESTRouter initializes a mux.Router with REST API routes with
// extra option.
func InitRESTRouterEx(r *mux.Router, versionMain string,
	mgr *cbgt.Manager, staticDir, staticETag string,
	mr *cbgt.MsgRing,
	assetDir func(name string) ([]string, error),
	asset func(name string) ([]byte, error),
	options map[string]interface{}) (
	*mux.Router, map[string]RESTMeta, error) {
	var authHandler func(http.Handler) http.Handler

	mapRESTPathStats := map[string]*RESTPathStats{} // Keyed by path spec.

	if options != nil {
		if v, ok := options["auth"]; ok {
			authHandler, ok = v.(func(http.Handler) http.Handler)
			if !ok {
				return nil, nil, fmt.Errorf("rest: auth function invalid")
			}
		}

		if v, ok := options["mapRESTPathStats"]; ok {
			mapRESTPathStats, ok = v.(map[string]*RESTPathStats)
			if !ok {
				return nil, nil, fmt.Errorf("rest: mapRESTPathStats invalid")
			}
		}
	}

	prefix := mgr.Options()["urlPrefix"]

	PIndexTypesInitRouter(r, "manager.before", mgr)

	meta := map[string]RESTMeta{}

	handle := func(path string, method string, h http.Handler,
		opts map[string]string) {
		opts["_path"] = path
		if a, ok := h.(RESTOpts); ok {
			a.RESTOpts(opts)
		}
		prefixPath := prefix + path
		restMeta := RESTMeta{prefixPath, method, opts}
		meta[prefixPath+" "+RESTMethodOrds[method]+method] = restMeta
		h = &HandlerWithRESTMeta{
			h:         h,
			RESTMeta:  &restMeta,
			pathStats: mapRESTPathStats[path],
			focusName: PathFocusName(path),
		}
		if authHandler != nil {
			h = authHandler(h)
		}
		r.Handle(prefixPath, h).Methods(method).Name(prefixPath)
	}

	handle("/api/index", "GET", NewListIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Returns all index definitions as JSON.`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}", "PUT", NewCreateIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Creates/updates an index definition.`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}", "DELETE", NewDeleteIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Deletes an index definition.`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}", "GET", NewGetIndexHandler(mgr),
		map[string]string{
			"_category":          "Indexing|Index definition",
			"_about":             `Returns the definition of an index as JSON.`,
			"version introduced": "0.0.1",
		})

	if mgr == nil || mgr.TagsMap() == nil || mgr.TagsMap()["queryer"] {
		handle("/api/index/{indexName}/count", "GET",
			NewCountHandler(mgr),
			map[string]string{
				"_category":          "Indexing|Index querying",
				"_about":             `Returns the count of indexed documents.`,
				"version introduced": "0.0.1",
			})
		handle("/api/index/{indexName}/query", "POST",
			NewQueryHandler(mgr,
				mapRESTPathStats["/api/index/{indexName}/query"]),
			map[string]string{
				"_category":          "Indexing|Index querying",
				"_about":             `Queries an index.`,
				"version introduced": "0.2.0",
			})
	}

	handle("/api/index/{indexName}/planFreezeControl/{op}", "POST",
		NewIndexControlHandler(mgr, "planFreeze", map[string]bool{
			"freeze":   true,
			"unfreeze": true,
		}),
		map[string]string{
			"_category": "Indexing|Index management",
			"_about":    `Freeze the assignment of index partitions to nodes.`,
			"param: op": "required, string, URL path parameter\n\n" +
				`Allowed values for op are "freeze" or "unfreeze".`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}/ingestControl/{op}", "POST",
		NewIndexControlHandler(mgr, "write", map[string]bool{
			"pause":  true,
			"resume": true,
		}),
		map[string]string{
			"_category": "Indexing|Index management",
			"_about": `Pause index updates and maintenance (no more
                          ingesting document mutations).`,
			"param: op": "required, string, URL path parameter\n\n" +
				`Allowed values for op are "pause" or "resume".`,
			"version introduced": "0.0.1",
		})
	handle("/api/index/{indexName}/queryControl/{op}", "POST",
		NewIndexControlHandler(mgr, "read", map[string]bool{
			"allow":    true,
			"disallow": true,
		}),
		map[string]string{
			"_category": "Indexing|Index management",
			"_about":    `Disallow queries on an index.`,
			"param: op": "required, string, URL path parameter\n\n" +
				`Allowed values for op are "allow" or "disallow".`,
			"version introduced": "0.0.1",
		})

	if mgr == nil || mgr.TagsMap() == nil || mgr.TagsMap()["pindex"] {
		handle("/api/pindex", "GET",
			NewListPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition definition",
				"version introduced": "0.0.1",
			})
		handle("/api/pindex/{pindexName}", "GET",
			NewGetPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition definition",
				"version introduced": "0.0.1",
			})
		handle("/api/pindex/{pindexName}/count", "GET",
			NewCountPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition querying",
				"version introduced": "0.0.1",
			})
		handle("/api/pindex/{pindexName}/query", "POST",
			NewQueryPIndexHandler(mgr),
			map[string]string{
				"_category":          "x/Advanced|x/Index partition querying",
				"version introduced": "0.2.0",
			})
	}

	handle("/api/managerOptions", "PUT", NewManagerOptions(mgr),
		map[string]string{
			"_category":          "Node|Node configuration",
			"_about":             "Set the options for the manager",
			"version introduced": "4.2.0",
		})

	handle("/api/cfg", "GET", NewCfgGetHandler(mgr),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Returns the node's current view
                       of the cluster's configuration as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/cfgRefresh", "POST", NewCfgRefreshHandler(mgr),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Requests the node to refresh its configuration
                       from the configuration provider.`,
			"version introduced": "0.0.1",
		})

	handle("/api/log", "GET", NewLogGetHandler(mgr, mr),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns recent log messages
                       and key events for the node as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/manager", "GET", NewManagerHandler(mgr),
		map[string]string{
			"_category":          "Node|Node configuration",
			"_about":             `Returns runtime config information about this node.`,
			"version introduced": "0.4.0",
		})

	handle("/api/managerKick", "POST", NewManagerKickHandler(mgr),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Forces the node to replan resource assignments
                       (by running the planner, if enabled) and to update
                       its runtime state to reflect the latest plan
                       (by running the janitor, if enabled).`,
			"version introduced": "0.0.1",
		})

	handle("/api/managerMeta", "GET", NewManagerMetaHandler(mgr, meta),
		map[string]string{
			"_category": "Node|Node configuration",
			"_about": `Returns information on the node's capabilities,
                       including available indexing and storage options as JSON,
                       and is intended to help management tools and web UI's
                       to be more dynamically metadata driven.`,
			"version introduced": "0.0.1",
		})

	handle("/api/runtime", "GET",
		NewRuntimeGetHandler(versionMain, mgr),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns information on the node's software,
                       such as version strings and slow-changing
                       runtime settings as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/runtime/args", "GET",
		http.HandlerFunc(RESTGetRuntimeArgs),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns information on the node's command-line,
                       parameters, environment variables and
                       O/S process values as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/diag", "GET",
		NewDiagGetHandler(versionMain, mgr, mr, assetDir, asset),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Returns full set of diagnostic information
                        from the node in one shot as JSON.  That is, the
                        /api/diag response will be the union of the responses
                        from the other REST API diagnostic and monitoring
                        endpoints from the node, and is intended to make
                        production support easier.`,
			"version introduced": "0.0.1",
		})

	handle("/api/ping", "GET", &NoopHandler{},
		map[string]string{
			"_category":          "Node|Node diagnostics",
			"_about":             `Returns an empty body as a quick aliveness check.`,
			"version introduced": "5.0.0",
		})

	handle("/api/runtime/gc", "POST",
		http.HandlerFunc(RESTPostRuntimeGC),
		map[string]string{
			"_category":          "Node|Node management",
			"_about":             `Requests the node to perform a GC.`,
			"version introduced": "0.0.1",
		})

	handle("/api/runtime/profile/cpu", "POST",
		http.HandlerFunc(RESTProfileCPU),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Requests the node to capture local
                       cpu usage profiling information.`,
			"version introduced": "0.0.1",
		})

	handle("/api/runtime/profile/memory", "POST",
		http.HandlerFunc(RESTProfileMemory),
		map[string]string{
			"_category": "Node|Node diagnostics",
			"_about": `Requests the node to capture lcoal
                       memory usage profiling information.`,
			"version introduced": "0.0.1",
		})

	handle("/api/runtime/stats", "GET",
		http.HandlerFunc(RESTGetRuntimeStats),
		map[string]string{
			"_category": "Node|Node monitoring",
			"_about": `Returns information on the node's
                       low-level runtime stats as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/runtime/statsMem", "GET",
		http.HandlerFunc(RESTGetRuntimeStatsMem),
		map[string]string{
			"_category": "Node|Node monitoring",
			"_about": `Returns information on the node's
                       low-level GC and memory related runtime stats as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/stats", "GET", NewStatsHandler(mgr),
		map[string]string{
			"_category": "Indexing|Index monitoring",
			"_about": `Returns indexing and data related metrics,
                       timings and counters from the node as JSON.`,
			"version introduced": "0.0.1",
		})

	// TODO: If we ever implement cluster-wide index stats, we should
	// have it under /api/index/{indexName}/stats GET endpoint.
	//
	handle("/api/stats/index/{indexName}", "GET", NewStatsHandler(mgr),
		map[string]string{
			"_category": "Indexing|Index monitoring",
			"_about": `Returns metrics, timings and counters
                       for a single index from the node as JSON.`,
			"version introduced": "0.0.1",
		})

	handle("/api/stats/sourceStats/{indexName}", "GET",
		NewSourceStatsHandler(mgr),
		map[string]string{
			"_category": "Indexing|Index monitoring",
			"_about": `Returns data source specific stats
                       for an index as JSON.`,
			"version introduced": "4.2.0",
		})

	handle("/api/stats/sourcePartitionSeqs/{indexName}", "GET",
		NewSourcePartitionSeqsHandler(mgr),
		map[string]string{
			"_category": "Indexing|Index monitoring",
			"_about": `Returns data source partiton seqs
                       for an index as JSON.`,
			"version introduced": "4.2.0",
		})

	PIndexTypesInitRouter(r, "manager.after", mgr)

	return r, meta, nil
}