diff --git a/contributing/checklist-jobspec.md b/contributing/checklist-jobspec.md index 83db385f850..5d6215124b4 100644 --- a/contributing/checklist-jobspec.md +++ b/contributing/checklist-jobspec.md @@ -15,6 +15,7 @@ * [ ] Add structs/fields to `nomad/structs` package * Validation happens in this package and must be implemented * Implement other methods and tests from `api/` package + * Note that analogous struct field names should match with `api/` package * [ ] Add conversion between `api/` and `nomad/structs` in `command/agent/job_endpoint.go` * [ ] Add check for job diff in `nomad/structs/diff.go` * Note that fields must be listed in alphabetical order in `FieldDiff` slices in `nomad/structs/diff_test.go` diff --git a/jobspec/parse_service.go b/jobspec/parse_service.go index 24c35176df7..fa53f087661 100644 --- a/jobspec/parse_service.go +++ b/jobspec/parse_service.go @@ -320,6 +320,24 @@ func parseProxy(o *ast.ObjectItem) (*api.ConsulProxy, error) { } var proxy api.ConsulProxy + var m map[string]interface{} + if err := hcl.DecodeObject(&m, o.Val); err != nil { + return nil, err + } + + delete(m, "upstreams") + delete(m, "expose") + delete(m, "config") + + dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + Result: &proxy, + }) + if err != nil { + return nil, err + } + if err := dec.Decode(m); err != nil { + return nil, fmt.Errorf("proxy: %v", err) + } var listVal *ast.ObjectList if ot, ok := o.Val.(*ast.ObjectType); ok { diff --git a/jobspec/parse_test.go b/jobspec/parse_test.go index c171f9acf47..8cd61d7ed24 100644 --- a/jobspec/parse_test.go +++ b/jobspec/parse_test.go @@ -894,28 +894,6 @@ func TestParse(t *testing.T) { }, false, }, - { - "service-connect-sidecar_task-name.hcl", - &api.Job{ - ID: helper.StringToPtr("sidecar_task_name"), - Name: helper.StringToPtr("sidecar_task_name"), - Type: helper.StringToPtr("service"), - TaskGroups: []*api.TaskGroup{{ - Name: helper.StringToPtr("group"), - Services: []*api.Service{{ - Name: "example", - Connect: &api.ConsulConnect{ - Native: false, - SidecarService: &api.ConsulSidecarService{}, - SidecarTask: &api.SidecarTask{ - Name: "my-sidecar", - }, - }, - }}, - }}, - }, - false, - }, { "reschedule-job.hcl", &api.Job{ @@ -1051,6 +1029,7 @@ func TestParse(t *testing.T) { SidecarService: &api.ConsulSidecarService{ Tags: []string{"side1", "side2"}, Proxy: &api.ConsulProxy{ + LocalServicePort: 8080, Upstreams: []*api.ConsulUpstream{ { DestinationName: "other-service", @@ -1172,6 +1151,99 @@ func TestParse(t *testing.T) { }, false, }, + { + "tg-service-connect-sidecar_task-name.hcl", + &api.Job{ + ID: helper.StringToPtr("sidecar_task_name"), + Name: helper.StringToPtr("sidecar_task_name"), + Type: helper.StringToPtr("service"), + TaskGroups: []*api.TaskGroup{{ + Name: helper.StringToPtr("group"), + Services: []*api.Service{{ + Name: "example", + Connect: &api.ConsulConnect{ + Native: false, + SidecarService: &api.ConsulSidecarService{}, + SidecarTask: &api.SidecarTask{ + Name: "my-sidecar", + }, + }, + }}, + }}, + }, + false, + }, + { + "tg-service-connect-proxy.hcl", + &api.Job{ + ID: helper.StringToPtr("service-connect-proxy"), + Name: helper.StringToPtr("service-connect-proxy"), + Type: helper.StringToPtr("service"), + TaskGroups: []*api.TaskGroup{{ + Name: helper.StringToPtr("group"), + Services: []*api.Service{{ + Name: "example", + Connect: &api.ConsulConnect{ + Native: false, + SidecarService: &api.ConsulSidecarService{ + Proxy: &api.ConsulProxy{ + LocalServiceAddress: "10.0.1.2", + LocalServicePort: 8080, + ExposeConfig: &api.ConsulExposeConfig{ + Path: []*api.ConsulExposePath{{ + Path: "/metrics", + Protocol: "http", + LocalPathPort: 9001, + ListenerPort: "metrics", + }, { + Path: "/health", + Protocol: "http", + LocalPathPort: 9002, + ListenerPort: "health", + }}, + }, + Upstreams: []*api.ConsulUpstream{{ + DestinationName: "upstream1", + LocalBindPort: 2001, + }, { + DestinationName: "upstream2", + LocalBindPort: 2002, + }}, + Config: map[string]interface{}{ + "foo": "bar", + }, + }, + }, + }, + }}, + }}, + }, + false, + }, + { + "tg-service-connect-local-service.hcl", + &api.Job{ + ID: helper.StringToPtr("connect-proxy-local-service"), + Name: helper.StringToPtr("connect-proxy-local-service"), + Type: helper.StringToPtr("service"), + TaskGroups: []*api.TaskGroup{{ + Name: helper.StringToPtr("group"), + Services: []*api.Service{{ + Name: "example", + Connect: &api.ConsulConnect{ + Native: false, + SidecarService: &api.ConsulSidecarService{ + Proxy: &api.ConsulProxy{ + LocalServiceAddress: "10.0.1.2", + LocalServicePort: 9876, + }, + }, + }, + }}, + }}, + }, + false, + }, { "tg-service-check-expose.hcl", &api.Job{ diff --git a/jobspec/test-fixtures/tg-service-connect-local-service.hcl b/jobspec/test-fixtures/tg-service-connect-local-service.hcl new file mode 100644 index 00000000000..dc97689b86e --- /dev/null +++ b/jobspec/test-fixtures/tg-service-connect-local-service.hcl @@ -0,0 +1,17 @@ +job "connect-proxy-local-service" { + type = "service" + + group "group" { + service { + name = "example" + connect { + sidecar_service { + proxy { + local_service_port = 9876 + local_service_address = "10.0.1.2" + } + } + } + } + } +} \ No newline at end of file diff --git a/jobspec/test-fixtures/tg-service-connect-proxy.hcl b/jobspec/test-fixtures/tg-service-connect-proxy.hcl new file mode 100644 index 00000000000..841742c920a --- /dev/null +++ b/jobspec/test-fixtures/tg-service-connect-proxy.hcl @@ -0,0 +1,42 @@ +job "service-connect-proxy" { + type = "service" + + group "group" { + service { + name = "example" + connect { + sidecar_service { + proxy { + local_service_port = 8080 + local_service_address = "10.0.1.2" + upstreams { + destination_name = "upstream1" + local_bind_port = 2001 + } + upstreams { + destination_name = "upstream2" + local_bind_port = 2002 + } + expose { + path { + path = "/metrics" + protocol = "http" + local_path_port = 9001 + listener_port = "metrics" + } + path { + path = "/health" + protocol = "http" + local_path_port = 9002 + listener_port = "health" + } + } + config { + foo = "bar" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/jobspec/test-fixtures/service-connect-sidecar_task-name.hcl b/jobspec/test-fixtures/tg-service-connect-sidecar_task-name.hcl similarity index 100% rename from jobspec/test-fixtures/service-connect-sidecar_task-name.hcl rename to jobspec/test-fixtures/tg-service-connect-sidecar_task-name.hcl diff --git a/nomad/structs/services.go b/nomad/structs/services.go index d12bb697f98..578b1dd22e3 100644 --- a/nomad/structs/services.go +++ b/nomad/structs/services.go @@ -889,7 +889,9 @@ type ConsulProxy struct { // Expose configures the consul proxy.expose stanza to "open up" endpoints // used by task-group level service checks using HTTP or gRPC protocols. - Expose *ConsulExposeConfig + // + // Use json tag to match with field name in api/ + Expose *ConsulExposeConfig `json:"ExposeConfig"` // Config is a proxy configuration. It is opaque to Nomad and passed // directly to Consul. @@ -905,7 +907,7 @@ func (p *ConsulProxy) Copy() *ConsulProxy { newP := &ConsulProxy{ LocalServiceAddress: p.LocalServiceAddress, LocalServicePort: p.LocalServicePort, - Expose: p.Expose, + Expose: p.Expose.Copy(), } if n := len(p.Upstreams); n > 0 { @@ -1009,7 +1011,8 @@ func (u *ConsulUpstream) Equals(o *ConsulUpstream) bool { // ExposeConfig represents a Consul Connect expose jobspec stanza. type ConsulExposeConfig struct { - Paths []ConsulExposePath + // Use json tag to match with field name in api/ + Paths []ConsulExposePath `json:"Path"` } type ConsulExposePath struct {