diff --git a/api/services.go b/api/services.go index 9a48ea06c47..823634ac09a 100644 --- a/api/services.go +++ b/api/services.go @@ -182,7 +182,7 @@ type ConsulUpstream struct { } type ConsulExposeConfig struct { - Paths []*ConsulExposePath `mapstructure:"paths"` + Path []*ConsulExposePath `mapstructure:"path"` // todo(shoenig): add magic for 'checks' option } diff --git a/command/agent/job_endpoint.go b/command/agent/job_endpoint.go index 333255940bf..e260e7e8b6f 100644 --- a/command/agent/job_endpoint.go +++ b/command/agent/job_endpoint.go @@ -1235,7 +1235,7 @@ func apiConsulExposeConfigToStructs(in *api.ConsulExposeConfig) *structs.ConsulE return nil } return &structs.ConsulExposeConfig{ - Paths: apiConsulExposePathsToStructs(in.Paths), + Paths: apiConsulExposePathsToStructs(in.Path), } } diff --git a/command/agent/job_endpoint_test.go b/command/agent/job_endpoint_test.go index f53db52c506..7c7c38e56d0 100644 --- a/command/agent/job_endpoint_test.go +++ b/command/agent/job_endpoint_test.go @@ -2631,7 +2631,7 @@ func TestConversion_apiConsulExposeConfigToStructs(t *testing.T) { require.Equal(t, &structs.ConsulExposeConfig{ Paths: []structs.ConsulExposePath{{Path: "/health"}}, }, apiConsulExposeConfigToStructs(&api.ConsulExposeConfig{ - Paths: []*api.ConsulExposePath{{Path: "/health"}}, + Path: []*api.ConsulExposePath{{Path: "/health"}}, })) } @@ -2670,7 +2670,7 @@ func TestConversion_apiConnectSidecarServiceProxyToStructs(t *testing.T) { DestinationName: "upstream", }}, ExposeConfig: &api.ConsulExposeConfig{ - Paths: []*api.ConsulExposePath{{ + Path: []*api.ConsulExposePath{{ Path: "/health", }}, }, diff --git a/jobspec/parse_service.go b/jobspec/parse_service.go index ff591160b18..f89b7d0ab5e 100644 --- a/jobspec/parse_service.go +++ b/jobspec/parse_service.go @@ -403,6 +403,17 @@ func parseProxy(o *ast.ObjectItem) (*api.ConsulProxy, error) { } func parseExpose(eo *ast.ObjectItem) (*api.ConsulExposeConfig, error) { + valid := []string{ + "path", // an array of path blocks + // todo(shoenig) checks boolean + } + + if err := helper.CheckHCLKeys(eo.Val, valid); err != nil { + return nil, multierror.Prefix(err, "expose ->") + } + + var expose api.ConsulExposeConfig + var listVal *ast.ObjectList if eoType, ok := eo.Val.(*ast.ObjectType); ok { listVal = eoType.List @@ -410,32 +421,53 @@ func parseExpose(eo *ast.ObjectItem) (*api.ConsulExposeConfig, error) { return nil, fmt.Errorf("expose: should be an object") } + // Parse the expose block + + po := listVal.Filter("path") // array + if len(po.Items) > 0 { + expose.Path = make([]*api.ConsulExposePath, len(po.Items)) + for i := range po.Items { + p, err := parseExposePath(po.Items[i]) + if err != nil { + return nil, err + } + expose.Path[i] = p + } + } + + return &expose, nil +} + +func parseExposePath(epo *ast.ObjectItem) (*api.ConsulExposePath, error) { valid := []string{ - "paths", + "path", + "protocol", + "local_path_port", + "listener_port", } - if err := helper.CheckHCLKeys(listVal, valid); err != nil { - return nil, multierror.Prefix(err, "expose ->") + if err := helper.CheckHCLKeys(epo.Val, valid); err != nil { + return nil, multierror.Prefix(err, "path ->") } + var path api.ConsulExposePath var m map[string]interface{} - if err := hcl.DecodeObject(&m, eo.Val); err != nil { + if err := hcl.DecodeObject(&m, epo.Val); err != nil { return nil, err } - // Build the expose block - var expose api.ConsulExposeConfig dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ - Result: &expose, + Result: &path, }) if err != nil { return nil, err } + if err := dec.Decode(m); err != nil { return nil, err } - return &expose, nil + return &path, nil } func parseUpstream(uo *ast.ObjectItem) (*api.ConsulUpstream, error) { diff --git a/jobspec/parse_test.go b/jobspec/parse_test.go index ddc6d54db82..78d13125dfd 100644 --- a/jobspec/parse_test.go +++ b/jobspec/parse_test.go @@ -1130,11 +1130,16 @@ func TestParse(t *testing.T) { SidecarService: &api.ConsulSidecarService{ Proxy: &api.ConsulProxy{ ExposeConfig: &api.ConsulExposeConfig{ - Paths: []*api.ConsulExposePath{{ + Path: []*api.ConsulExposePath{{ Path: "/health", Protocol: "http", LocalPathPort: 2222, ListenerPort: "healthcheck", + }, { + Path: "/metrics", + Protocol: "grpc", + LocalPathPort: 3000, + ListenerPort: "metrics", }}, }, }, diff --git a/jobspec/test-fixtures/tg-service-proxy-expose.hcl b/jobspec/test-fixtures/tg-service-proxy-expose.hcl index 2195a716f7c..b5032f9d46a 100644 --- a/jobspec/test-fixtures/tg-service-proxy-expose.hcl +++ b/jobspec/test-fixtures/tg-service-proxy-expose.hcl @@ -6,12 +6,19 @@ job "group_service_proxy_expose" { sidecar_service { proxy { expose { - paths = [{ + path = { path = "/health" protocol = "http" local_path_port = 2222 listener_port = "healthcheck" - }] + } + + path = { + path = "/metrics" + protocol = "grpc" + local_path_port = 3000 + listener_port = "metrics" + } } } }