Skip to content

Commit

Permalink
Merge branch 'main' of github.com:hashicorp/consul into asheshvidyut/…
Browse files Browse the repository at this point in the history
…NET-3865
  • Loading branch information
absolutelightning committed Jun 15, 2023
2 parents ee1deb0 + a633347 commit 71f05d6
Show file tree
Hide file tree
Showing 16 changed files with 2,723 additions and 15 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/jira-issues.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ jobs:

- name: Close ticket
if: ( github.event.action == 'closed' || github.event.action == 'deleted' ) && steps.search.outputs.issue
uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3
uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3
with:
issue: ${{ steps.search.outputs.issue }}
transition: "Closed"

- name: Reopen ticket
if: github.event.action == 'reopened' && steps.search.outputs.issue
uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3
uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3
with:
issue: ${{ steps.search.outputs.issue }}
transition: "To Do"
4 changes: 2 additions & 2 deletions .github/workflows/jira-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ jobs:

- name: Close ticket
if: ( github.event.action == 'closed' || github.event.action == 'deleted' ) && steps.search.outputs.issue
uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3
uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3
with:
issue: ${{ steps.search.outputs.issue }}
transition: "Closed"

- name: Reopen ticket
if: github.event.action == 'reopened' && steps.search.outputs.issue
uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3
uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3
with:
issue: ${{ steps.search.outputs.issue }}
transition: "To Do"
16 changes: 15 additions & 1 deletion agent/hcp/client/metrics_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const (
// defaultRetryMax is set to 0 to turn off retry functionality, until dynamic configuration is possible.
// This is to circumvent any spikes in load that may cause or exacerbate server-side issues for now.
defaultRetryMax = 0

// defaultErrRespBodyLength refers to the max character length of the body on a failure to export metrics.
// anything beyond we will truncate.
defaultErrRespBodyLength = 100
)

// MetricsClient exports Consul metrics in OTLP format to the HCP Telemetry Gateway.
Expand Down Expand Up @@ -150,8 +154,18 @@ func (o *otlpClient) ExportMetrics(ctx context.Context, protoMetrics *metricpb.R
}

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to export metrics: code %d: %s", resp.StatusCode, string(body))
truncatedBody := truncate(respData.String(), defaultErrRespBodyLength)
return fmt.Errorf("failed to export metrics: code %d: %s", resp.StatusCode, truncatedBody)
}

return nil
}

func truncate(text string, width uint) string {
if len(text) <= int(width) {
return text
}
r := []rune(text)
trunc := r[:width]
return string(trunc) + "..."
}
67 changes: 64 additions & 3 deletions agent/hcp/client/metrics_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package client
import (
"context"
"fmt"
"math/rand"
"net/http"
"net/http/httptest"
"testing"
Expand Down Expand Up @@ -64,10 +65,21 @@ func TestNewMetricsClient(t *testing.T) {
}
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZäöüÄÖÜ世界")

func randStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}

func TestExportMetrics(t *testing.T) {
for name, test := range map[string]struct {
wantErr string
status int
wantErr string
status int
largeBodyError bool
}{
"success": {
status: http.StatusOK,
Expand All @@ -76,8 +88,14 @@ func TestExportMetrics(t *testing.T) {
status: http.StatusBadRequest,
wantErr: "failed to export metrics: code 400",
},
"failsWithNonRetryableErrorWithLongError": {
status: http.StatusBadRequest,
wantErr: "failed to export metrics: code 400",
largeBodyError: true,
},
} {
t.Run(name, func(t *testing.T) {
randomBody := randStringRunes(1000)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, r.Header.Get("content-type"), "application/x-protobuf")
require.Equal(t, r.Header.Get("x-hcp-resource-id"), testResourceID)
Expand All @@ -91,7 +109,12 @@ func TestExportMetrics(t *testing.T) {

w.Header().Set("Content-Type", "application/x-protobuf")
w.WriteHeader(test.status)
w.Write(bytes)
if test.largeBodyError {
w.Write([]byte(randomBody))
} else {
w.Write(bytes)
}

}))
defer srv.Close()

Expand All @@ -105,10 +128,48 @@ func TestExportMetrics(t *testing.T) {
if test.wantErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), test.wantErr)
if test.largeBodyError {
truncatedBody := truncate(randomBody, defaultErrRespBodyLength)
require.Contains(t, err.Error(), truncatedBody)
}
return
}

require.NoError(t, err)
})
}
}

func TestTruncate(t *testing.T) {
for name, tc := range map[string]struct {
body string
expectedSize int
}{
"ZeroSize": {
body: "",
expectedSize: 0,
},
"LessThanSize": {
body: "foobar",
expectedSize: 6,
},
"defaultSize": {
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vel tincidunt nunc, sed tristique risu",
expectedSize: 100,
},
"greaterThanSize": {
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vel tincidunt nunc, sed tristique risus",
expectedSize: 103,
},
"greaterThanSizeWithUnicode": {
body: randStringRunes(1000),
expectedSize: 103,
},
} {
t.Run(name, func(t *testing.T) {
truncatedBody := truncate(tc.body, defaultErrRespBodyLength)
truncatedRunes := []rune(truncatedBody)
require.Equal(t, len(truncatedRunes), tc.expectedSize)
})
}
}
12 changes: 9 additions & 3 deletions agent/xds/delta.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ func applyEnvoyExtension(logger hclog.Logger, cfgSnap *proxycfg.ConfigSnapshot,
extender, err := envoyextensions.ConstructExtension(ext)
metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate_arguments"}, now, getMetricLabels(err))
if err != nil {
errorParams = append(errorParams, "error", err)
logFn("failed to construct extension", errorParams...)

if ext.Required {
Expand All @@ -507,6 +508,7 @@ func applyEnvoyExtension(logger hclog.Logger, cfgSnap *proxycfg.ConfigSnapshot,
if err != nil {
errorParams = append(errorParams, "error", err)
logFn("failed to validate extension arguments", errorParams...)

if ext.Required {
return status.Errorf(codes.InvalidArgument, "failed to validate arguments for extension %q for service %q", ext.Name, svc.Name)
}
Expand All @@ -517,9 +519,13 @@ func applyEnvoyExtension(logger hclog.Logger, cfgSnap *proxycfg.ConfigSnapshot,
now = time.Now()
_, err = extender.Extend(resources, &runtimeConfig)
metrics.MeasureSinceWithLabels([]string{"envoy_extension", "extend"}, now, getMetricLabels(err))
logFn("failed to apply envoy extension", errorParams...)
if err != nil && ext.Required {
return status.Errorf(codes.InvalidArgument, "failed to patch xDS resources in the %q extension: %v", ext.Name, err)
if err != nil {
errorParams = append(errorParams, "error", err)
logFn("failed to apply envoy extension", errorParams...)

if ext.Required {
return status.Errorf(codes.InvalidArgument, "failed to patch xDS resources in the %q extension: %v", ext.Name, err)
}
}

return nil
Expand Down
8 changes: 5 additions & 3 deletions website/content/docs/connect/failover/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ The following table compares these strategies in deployments with multiple datac
| Failover Strategy | Supports WAN Federation | Supports Cluster Peering | Multi-Datacenter Failover Strength | Multi-Datacenter Usage Scenario |
| :---------------: | :---------------------: | :----------------------: | :--------------------------------- | :------------------------------ |
| `Failover` stanza | &#9989; | &#9989; | Enables more granular logic for failover targeting | Configuring failover for a single service or service subset, especially for testing or debugging purposes |
| Prepared query | &#9989; | &#9989; | Central policies that can automatically target the nearest datacenter | WAN-federated deployments where a primary datacenter is configured. Prepared queries are not replicated over peer connections. |
| Prepared query | &#9989; | &#10060; | Central policies that can automatically target the nearest datacenter | WAN-federated deployments where a primary datacenter is configured. |
| Sameness groups | &#10060; | &#9989; | Group size changes without edits to existing member configurations | Cluster peering deployments with consistently named services and namespaces |

Although cluster peering connections support the [`Failover` field of the prepared query request schema](/consul/api-docs/query#failover) when using Consul's service discovery features to [perform dynamic DNS queries](/consul/docs/services/discovery/dns-dynamic-lookups), they do not support prepared queries for service mesh failover scenarios.

### Failover configurations for a service mesh with a single datacenter

You can implement a service resolver configuration entry and specify a pool of failover service instances that other services can exchange messages with when the primary service becomes unhealthy or unreachable. We recommend adopting this strategy as a minimum baseline when implementing Consul service mesh and layering additional failover strategies to build resilience into your application network.
Expand All @@ -32,9 +34,9 @@ Refer to the [`Failover` configuration ](/consul/docs/connect/config-entries/ser

### Failover configuration for WAN-federated datacenters

If your network has multiple Consul datacenters that are WAN-federated, you can configure your applications to look for failover services with prepared queries. [Prepared queries](/consul/api-docs/) are configurations that enable you to define complex service discovery lookups. This strategy hinges on the secondary datacenter containing service instances that have the same name and residing in the same namespace as their counterparts in the primary datacenter.
If your network has multiple Consul datacenters that are WAN-federated, you can configure your applications to look for failover services with prepared queries. [Prepared queries](/consul/api-docs/) are configurations that enable you to define complex service discovery lookups. This strategy hinges on the secondary datacenter containing service instances that have the same name and residing in the same namespace as their counterparts in the primary datacenter.

Refer to the [Automate geo-failover with prepared queries tutorial](/consul/tutorials/developer-discovery/automate-geo-failover) for additional information.
Refer to the [Automate geo-failover with prepared queries tutorial](/consul/tutorials/developer-discovery/automate-geo-failover) for additional information.

### Failover configuration for peered clusters and partitions

Expand Down
Loading

0 comments on commit 71f05d6

Please sign in to comment.