diff --git a/command/agent/config.go b/command/agent/config.go index 9fe653a33..791f5ede9 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -392,9 +392,20 @@ func DecodeConfig(r io.Reader) (*Config, error) { // Check the result type if obj, ok := raw.(map[string]interface{}); ok { - // Check for a "service" or "check" key, meaning + // Check for a "services", "service" or "check" key, meaning // this is actually a definition entry - if sub, ok := obj["service"]; ok { + if sub, ok := obj["services"]; ok { + if list, ok := sub.([]interface{}); ok { + for _, srv := range list { + service, err := DecodeServiceDefinition(srv) + if err != nil { + return nil, err + } + result.Services = append(result.Services, service) + } + return &result, nil + } + } else if sub, ok := obj["service"]; ok { service, err := DecodeServiceDefinition(sub) result.Services = append(result.Services, service) return &result, err diff --git a/command/agent/config_test.go b/command/agent/config_test.go index f1c109b0f..e4a8b779e 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -516,6 +516,86 @@ func TestDecodeConfig(t *testing.T) { } } +func TestDecodeConfig_Services(t *testing.T) { + input := `{ + "services": [ + { + "id": "red0", + "name": "redis", + "tags": [ + "master" + ], + "port": 6000, + "check": { + "script": "/bin/check_redis -p 6000", + "interval": "5s", + "ttl": "20s" + } + }, + { + "id": "red1", + "name": "redis", + "tags": [ + "delayed", + "slave" + ], + "port": 7000, + "check": { + "script": "/bin/check_redis -p 7000", + "interval": "30s", + "ttl": "60s" + } + } + ] + }` + + config, err := DecodeConfig(bytes.NewReader([]byte(input))) + if err != nil { + t.Fatalf("err: %s", err) + } + + if len(config.Services) != 2 { + t.Fatalf("missing services") + } + + expected := &ServiceDefinition{ + Check: CheckType{ + Interval: 5 * time.Second, + Script: "/bin/check_redis -p 6000", + TTL: 20 * time.Second, + }, + ID: "red0", + Name: "redis", + Tags: []string{ + "master", + }, + Port: 6000, + } + + if !reflect.DeepEqual(config.Services[0], expected) { + t.Fatalf("services do not match:\n%+v\n%+v", config.Services[0], expected) + } + + expected = &ServiceDefinition{ + Check: CheckType{ + Interval: 30 * time.Second, + Script: "/bin/check_redis -p 7000", + TTL: 60 * time.Second, + }, + ID: "red1", + Name: "redis", + Tags: []string{ + "delayed", + "slave", + }, + Port: 7000, + } + + if !reflect.DeepEqual(config.Services[1], expected) { + t.Fatalf("services do not match:\n%+v\n%+v", config.Services[1], expected) + } +} + func TestDecodeConfig_Service(t *testing.T) { // Basics input := `{"service": {"id": "red1", "name": "redis", "tags": ["master"], "port":8000, "check": {"script": "/bin/check_redis", "interval": "10s", "ttl": "15s" }}}` diff --git a/website/source/docs/agent/services.html.markdown b/website/source/docs/agent/services.html.markdown index 3e99fb855..6dc8e30ee 100644 --- a/website/source/docs/agent/services.html.markdown +++ b/website/source/docs/agent/services.html.markdown @@ -62,3 +62,41 @@ end in the ".json" extension to be loaded by Consul. Check definitions can also be updated by sending a `SIGHUP` to the agent. Alternatively, the service can be registered dynamically using the [HTTP API](/docs/agent/http.html). +## Multiple Service Definitions + +Multiple services definitions can be provided at once. Single and mutiple service definitions can't be provided together in one configuration file. + +```javascript +{ + "services": [ + { + "id": "red0", + "name": "redis", + "tags": [ + "master" + ], + "port": 6000, + "check": { + "script": "/bin/check_redis -p 6000", + "interval": "5s", + "ttl": "20s" + } + }, + { + "id": "red1", + "name": "redis", + "tags": [ + "delayed", + "slave" + ], + "port": 7000, + "check": { + "script": "/bin/check_redis -p 7000", + "interval": "30s", + "ttl": "60s" + } + }, + ... + ] +} +```