diff --git a/agent/txn_endpoint.go b/agent/txn_endpoint.go index 4e898bfce8..f528bbda4d 100644 --- a/agent/txn_endpoint.go +++ b/agent/txn_endpoint.go @@ -185,6 +185,7 @@ func (s *HTTPHandlers) convertOps(resp http.ResponseWriter, req *http.Request) ( Address: node.Address, Datacenter: node.Datacenter, TaggedAddresses: node.TaggedAddresses, + PeerName: node.PeerName, Meta: node.Meta, RaftIndex: structs.RaftIndex{ ModifyIndex: node.ModifyIndex, @@ -207,6 +208,7 @@ func (s *HTTPHandlers) convertOps(resp http.ResponseWriter, req *http.Request) ( Service: structs.NodeService{ ID: svc.ID, Service: svc.Service, + Kind: structs.ServiceKind(svc.Kind), Tags: svc.Tags, Address: svc.Address, Meta: svc.Meta, @@ -226,6 +228,39 @@ func (s *HTTPHandlers) convertOps(resp http.ResponseWriter, req *http.Request) ( }, }, } + + if svc.Proxy != nil { + out.Service.Service.Proxy = structs.ConnectProxyConfig{} + t := &out.Service.Service.Proxy + if svc.Proxy.DestinationServiceName != "" { + t.DestinationServiceName = svc.Proxy.DestinationServiceName + } + if svc.Proxy.DestinationServiceID != "" { + t.DestinationServiceID = svc.Proxy.DestinationServiceID + } + if svc.Proxy.LocalServiceAddress != "" { + t.LocalServiceAddress = svc.Proxy.LocalServiceAddress + } + if svc.Proxy.LocalServicePort != 0 { + t.LocalServicePort = svc.Proxy.LocalServicePort + } + if svc.Proxy.LocalServiceSocketPath != "" { + t.LocalServiceSocketPath = svc.Proxy.LocalServiceSocketPath + } + if svc.Proxy.MeshGateway.Mode != "" { + t.MeshGateway.Mode = structs.MeshGatewayMode(svc.Proxy.MeshGateway.Mode) + } + + if svc.Proxy.TransparentProxy != nil { + if svc.Proxy.TransparentProxy.DialedDirectly { + t.TransparentProxy.DialedDirectly = svc.Proxy.TransparentProxy.DialedDirectly + } + + if svc.Proxy.TransparentProxy.OutboundListenerPort != 0 { + t.TransparentProxy.OutboundListenerPort = svc.Proxy.TransparentProxy.OutboundListenerPort + } + } + } opsRPC = append(opsRPC, out) case in.Check != nil: @@ -265,6 +300,8 @@ func (s *HTTPHandlers) convertOps(resp http.ResponseWriter, req *http.Request) ( ServiceID: check.ServiceID, ServiceName: check.ServiceName, ServiceTags: check.ServiceTags, + PeerName: check.PeerName, + ExposedPort: check.ExposedPort, Definition: structs.HealthCheckDefinition{ HTTP: check.Definition.HTTP, TLSServerName: check.Definition.TLSServerName, diff --git a/agent/txn_endpoint_test.go b/agent/txn_endpoint_test.go index 4b529d5dee..f6f47b8fab 100644 --- a/agent/txn_endpoint_test.go +++ b/agent/txn_endpoint_test.go @@ -585,6 +585,7 @@ func TestTxnEndpoint_UpdateCheck(t *testing.T) { "Output": "success", "ServiceID": "", "ServiceName": "", + "ExposedPort": 5678, "Definition": { "IntervalDuration": "15s", "TimeoutDuration": "15s", @@ -600,12 +601,8 @@ func TestTxnEndpoint_UpdateCheck(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/txn", buf) resp := httptest.NewRecorder() obj, err := a.srv.Txn(resp, req) - if err != nil { - t.Fatalf("err: %v", err) - } - if resp.Code != 200 { - t.Fatalf("expected 200, got %d", resp.Code) - } + require.NoError(t, err) + require.Equal(t, 200, resp.Code, resp.Body) txnResp, ok := obj.(structs.TxnResponse) if !ok { @@ -662,12 +659,13 @@ func TestTxnEndpoint_UpdateCheck(t *testing.T) { }, &structs.TxnResult{ Check: &structs.HealthCheck{ - Node: a.config.NodeName, - CheckID: "nodecheck", - Name: "Node http check", - Status: api.HealthPassing, - Notes: "Http based health check", - Output: "success", + Node: a.config.NodeName, + CheckID: "nodecheck", + Name: "Node http check", + Status: api.HealthPassing, + Notes: "Http based health check", + Output: "success", + ExposedPort: 5678, Definition: structs.HealthCheckDefinition{ Interval: 15 * time.Second, Timeout: 15 * time.Second, @@ -686,3 +684,117 @@ func TestTxnEndpoint_UpdateCheck(t *testing.T) { } assert.Equal(t, expected, txnResp) } + +func TestTxnEndpoint_NodeService(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + a := NewTestAgent(t, "") + defer a.Shutdown() + testrpc.WaitForTestAgent(t, a.RPC, "dc1") + + // Make sure the fields of a check are handled correctly when both creating and + // updating, and test both sets of duration fields to ensure backwards compatibility. + buf := bytes.NewBuffer([]byte(fmt.Sprintf(` +[ + { + "Service": { + "Verb": "set", + "Node": "%s", + "Service": { + "Service": "test", + "Port": 4444 + } + } + }, + { + "Service": { + "Verb": "set", + "Node": "%s", + "Service": { + "Service": "test-sidecar-proxy", + "Port": 20000, + "Kind": "connect-proxy", + "Proxy": { + "DestinationServiceName": "test", + "DestinationServiceID": "test", + "LocalServiceAddress": "127.0.0.1", + "LocalServicePort": 4444, + "upstreams": [ + { + "DestinationName": "fake-backend", + "LocalBindPort": 25001 + } + ] + } + } + } + } +] +`, a.config.NodeName, a.config.NodeName))) + req, _ := http.NewRequest("PUT", "/v1/txn", buf) + resp := httptest.NewRecorder() + obj, err := a.srv.Txn(resp, req) + require.NoError(t, err) + require.Equal(t, 200, resp.Code) + + txnResp, ok := obj.(structs.TxnResponse) + if !ok { + t.Fatalf("bad type: %T", obj) + } + require.Equal(t, 2, len(txnResp.Results)) + + index := txnResp.Results[0].Service.ModifyIndex + expected := structs.TxnResponse{ + Results: structs.TxnResults{ + &structs.TxnResult{ + Service: &structs.NodeService{ + Service: "test", + ID: "test", + Port: 4444, + Weights: &structs.Weights{ + Passing: 1, + Warning: 1, + }, + RaftIndex: structs.RaftIndex{ + CreateIndex: index, + ModifyIndex: index, + }, + EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), + }, + }, + &structs.TxnResult{ + Service: &structs.NodeService{ + Service: "test-sidecar-proxy", + ID: "test-sidecar-proxy", + Port: 20000, + Kind: "connect-proxy", + Weights: &structs.Weights{ + Passing: 1, + Warning: 1, + }, + Proxy: structs.ConnectProxyConfig{ + DestinationServiceName: "test", + DestinationServiceID: "test", + LocalServiceAddress: "127.0.0.1", + LocalServicePort: 4444, + }, + TaggedAddresses: map[string]structs.ServiceAddress{ + "consul-virtual": { + Address: "240.0.0.1", + Port: 20000, + }, + }, + RaftIndex: structs.RaftIndex{ + CreateIndex: index, + ModifyIndex: index, + }, + EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), + }, + }, + }, + } + assert.Equal(t, expected, txnResp) +} diff --git a/api/catalog.go b/api/catalog.go index 80ae325eac..84a2bdbc65 100644 --- a/api/catalog.go +++ b/api/catalog.go @@ -20,6 +20,7 @@ type Node struct { CreateIndex uint64 ModifyIndex uint64 Partition string `json:",omitempty"` + PeerName string `json:",omitempty"` } type ServiceAddress struct { diff --git a/api/health.go b/api/health.go index 2bcb3cb52e..0886bb12ac 100644 --- a/api/health.go +++ b/api/health.go @@ -45,6 +45,8 @@ type HealthCheck struct { Type string Namespace string `json:",omitempty"` Partition string `json:",omitempty"` + ExposedPort int + PeerName string `json:",omitempty"` Definition HealthCheckDefinition @@ -176,8 +178,7 @@ type HealthChecks []*HealthCheck // attached, this function determines the best representative of the status as // as single string using the following heuristic: // -// maintenance > critical > warning > passing -// +// maintenance > critical > warning > passing func (c HealthChecks) AggregatedStatus() string { var passing, warning, critical, maintenance bool for _, check := range c {