Skip to content

Commit

Permalink
disable api endpoints on-demand
Browse files Browse the repository at this point in the history
  • Loading branch information
runabol committed Sep 8, 2023
1 parent be671ae commit bcddcb0
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 11 deletions.
1 change: 1 addition & 0 deletions bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ func createCoordinator(broker mq.Broker, ds datastore.Datastore) (*coordinator.C
Address: conf.String("coordinator.address"),
Middlewares: middlewares,
Endpoints: endpoints,
Enabled: conf.BoolMap("coordinator.api.endpoints"),
})
if err != nil {
return nil, errors.Wrap(err, "error creating the coordinator")
Expand Down
16 changes: 16 additions & 0 deletions conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func IntMap(key string) map[string]int {
return konf.IntMap(key)
}

func BoolMap(key string) map[string]bool {
return konf.BoolMap(key)
}

func String(key string) string {
return konf.String(key)
}
Expand All @@ -75,3 +79,15 @@ func StringDefault(key, dv string) string {
}
return dv
}

func Bool(key string) bool {
return konf.Bool(key)
}

func BoolDefault(key string, dv bool) bool {
v := konf.String(key)
if v != "" {
return Bool(key)
}
return dv
}
65 changes: 65 additions & 0 deletions conf/conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,68 @@ func TestLoadConfigEnv(t *testing.T) {

assert.Equal(t, "world", conf.String("hello"))
}

func TestBoolTrue(t *testing.T) {
konf := `
[main]
enabled = true
`
err := os.WriteFile("config.toml", []byte(konf), os.ModePerm)
assert.NoError(t, err)
defer func() {
assert.NoError(t, os.Remove("config.toml"))
}()
err = conf.LoadConfig()
assert.NoError(t, err)
assert.True(t, conf.Bool("main.enabled"))
}

func TestBoolFalse(t *testing.T) {
konf := `
[main]
enabled = false
`
err := os.WriteFile("config.toml", []byte(konf), os.ModePerm)
assert.NoError(t, err)
defer func() {
assert.NoError(t, os.Remove("config.toml"))
}()
err = conf.LoadConfig()
assert.NoError(t, err)
assert.False(t, conf.Bool("main.enabled"))
}

func TestBoolDefault(t *testing.T) {
konf := `
[main]
enabled = false
`
err := os.WriteFile("config.toml", []byte(konf), os.ModePerm)
assert.NoError(t, err)
defer func() {
assert.NoError(t, os.Remove("config.toml"))
}()
err = conf.LoadConfig()

assert.NoError(t, err)
assert.False(t, conf.BoolDefault("main.enabled", true))
assert.False(t, conf.BoolDefault("main.enabled", false))
assert.True(t, conf.BoolDefault("main.other", true))
}

func TestBoolMap(t *testing.T) {
os.Setenv("TORK_BOOLMAP_KEY1", "false")
os.Setenv("TORK_BOOLMAP_KEY2", "true")
defer func() {
os.Unsetenv("TORK_BOOLMAP_KEY1")
os.Unsetenv("TORK_BOOLMAP_KEY2")
}()

err := conf.LoadConfig()
assert.NoError(t, err)

m := conf.BoolMap("boolmap")

assert.False(t, m["key1"])
assert.True(t, m["key2"])
}
8 changes: 8 additions & 0 deletions configs/sample.config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ dsn = "host=localhost user=tork password=tork dbname=tork port=5432 sslmode=disa
[coordinator]
address = "localhost:8000"

[coordinator.api]
endpoints.health = true # turn on|off the /health endpoint
endpoints.jobs = true # turn on|off the /jobs endpoints
endpoints.tasks = true # turn on|off the /tasks endpoints
endpoints.nodes = true # turn on|off the /nodes endpoint
endpoints.queues = true # turn on|off the /queues endpoint
endpoints.stats = true # turn on|off the /stats endpoint

[coordinator.queues]
completed = 1 # completed queue consumers (default: 1)
error = 1 # error queue consumers (default: 1)
Expand Down
33 changes: 23 additions & 10 deletions internal/coordinator/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Config struct {
Address string
Middlewares []middleware.MiddlewareFunc
Endpoints map[string]middleware.HandlerFunc
Enabled map[string]bool
}

func NewAPI(cfg Config) (*API, error) {
Expand All @@ -64,16 +65,28 @@ func NewAPI(cfg Config) (*API, error) {
}

// built-in endpoints
r.GET("/health", s.health)
r.GET("/tasks/:id", s.getTask)
r.GET("/queues", s.listQueues)
r.GET("/nodes", s.listActiveNodes)
r.POST("/jobs", s.createJob)
r.GET("/jobs/:id", s.getJob)
r.GET("/jobs", s.listJobs)
r.PUT("/jobs/:id/cancel", s.cancelJob)
r.PUT("/jobs/:id/restart", s.restartJob)
r.GET("/stats", s.getStats)
if v, ok := cfg.Enabled["health"]; !ok || v {
r.GET("/health", s.health)
}
if v, ok := cfg.Enabled["tasks"]; !ok || v {
r.GET("/tasks/:id", s.getTask)
}
if v, ok := cfg.Enabled["queues"]; !ok || v {
r.GET("/queues", s.listQueues)
}
if v, ok := cfg.Enabled["nodes"]; !ok || v {
r.GET("/nodes", s.listActiveNodes)
}
if v, ok := cfg.Enabled["jobs"]; !ok || v {
r.POST("/jobs", s.createJob)
r.GET("/jobs/:id", s.getJob)
r.GET("/jobs", s.listJobs)
r.PUT("/jobs/:id/cancel", s.cancelJob)
r.PUT("/jobs/:id/restart", s.restartJob)
}
if v, ok := cfg.Enabled["stats"]; !ok || v {
r.GET("/stats", s.getStats)
}

// register additional custom endpoints
for spec, h := range cfg.Endpoints {
Expand Down
20 changes: 19 additions & 1 deletion internal/coordinator/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func Test_getActiveNodes(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Code)
}

func Test_getStatus(t *testing.T) {
func Test_health(t *testing.T) {
api, err := NewAPI(Config{
DataStore: datastore.NewInMemoryDatastore(),
Broker: mq.NewInMemoryBroker(),
Expand Down Expand Up @@ -718,3 +718,21 @@ func Test_customEndpointBind(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "Me", string(body))
}

func Test_disableEndpoint(t *testing.T) {
api, err := NewAPI(Config{
DataStore: datastore.NewInMemoryDatastore(),
Broker: mq.NewInMemoryBroker(),
Enabled: map[string]bool{"health": false},
})
assert.NoError(t, err)
assert.NotNil(t, api)
req, err := http.NewRequest("GET", "/health", nil)
assert.NoError(t, err)
w := httptest.NewRecorder()
api.server.Handler.ServeHTTP(w, req)
_, err = io.ReadAll(w.Body)

assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, w.Code)
}
4 changes: 4 additions & 0 deletions internal/coordinator/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Config struct {
Queues map[string]int
Middlewares []middleware.MiddlewareFunc
Endpoints map[string]middleware.HandlerFunc
Enabled map[string]bool
}

func NewCoordinator(cfg Config) (*Coordinator, error) {
Expand All @@ -55,6 +56,9 @@ func NewCoordinator(cfg Config) (*Coordinator, error) {
if cfg.Endpoints == nil {
cfg.Endpoints = make(map[string]middleware.HandlerFunc)
}
if cfg.Enabled == nil {
cfg.Enabled = make(map[string]bool)
}
if cfg.Queues[mq.QUEUE_COMPLETED] < 1 {
cfg.Queues[mq.QUEUE_COMPLETED] = 1
}
Expand Down

0 comments on commit bcddcb0

Please sign in to comment.