Support auth method with snapshot agent [ENT] (#15020)

Port of hashicorp/consul-enterprise#3303
This commit is contained in:
Iryna Shustava 2022-10-17 15:57:48 -06:00 committed by GitHub
parent 9f41cc4a25
commit 22b6c39092
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 160 additions and 4 deletions

View File

@ -35,3 +35,15 @@ func (h *FlagMapValue) Set(value string) error {
return nil return nil
} }
// Merge will overlay this value if it has been set.
func (h *FlagMapValue) Merge(onto map[string]string) {
if h == nil || onto == nil {
return
}
for k, v := range *h {
if _, ok := onto[k]; !ok {
onto[k] = v
}
}
}

View File

@ -3,6 +3,8 @@ package flags
import ( import (
"fmt" "fmt"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestFlagMapValueSet(t *testing.T) { func TestFlagMapValueSet(t *testing.T) {
@ -78,3 +80,75 @@ func TestFlagMapValueSet(t *testing.T) {
} }
}) })
} }
func TestFlagMapValueMerge(t *testing.T) {
cases := map[string]struct {
src FlagMapValue
dst map[string]string
exp map[string]string
}{
"empty source and destination": {},
"empty source": {
dst: map[string]string{
"key": "val",
},
exp: map[string]string{
"key": "val",
},
},
"empty destination": {
src: map[string]string{
"key": "val",
},
dst: make(map[string]string),
exp: map[string]string{
"key": "val",
},
},
"non-overlapping keys": {
src: map[string]string{
"key1": "val1",
},
dst: map[string]string{
"key2": "val2",
},
exp: map[string]string{
"key1": "val1",
"key2": "val2",
},
},
"overlapping keys": {
src: map[string]string{
"key1": "val1",
},
dst: map[string]string{
"key1": "val2",
},
exp: map[string]string{
"key1": "val2",
},
},
"multiple keys": {
src: map[string]string{
"key1": "val1",
"key2": "val2",
},
dst: map[string]string{
"key1": "val2",
"key3": "val3",
},
exp: map[string]string{
"key1": "val2",
"key2": "val2",
"key3": "val3",
},
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
c.src.Merge(c.dst)
require.Equal(t, c.exp, c.dst)
})
}
}

View File

@ -2,6 +2,7 @@ package retry
import ( import (
"context" "context"
"fmt"
"math/rand" "math/rand"
"time" "time"
) )
@ -30,7 +31,7 @@ func NewJitter(percent int64) Jitter {
} }
// Waiter records the number of failures and performs exponential backoff when // Waiter records the number of failures and performs exponential backoff when
// when there are consecutive failures. // there are consecutive failures.
type Waiter struct { type Waiter struct {
// MinFailures before exponential backoff starts. Any failures before // MinFailures before exponential backoff starts. Any failures before
// MinFailures is reached will wait MinWait time. // MinFailures is reached will wait MinWait time.
@ -117,3 +118,23 @@ func (w *Waiter) Wait(ctx context.Context) error {
func (w *Waiter) NextWait() time.Duration { func (w *Waiter) NextWait() time.Duration {
return w.delay() return w.delay()
} }
// RetryLoop retries an operation until either operation completes without error
// or Waiter's context is canceled.
func (w *Waiter) RetryLoop(ctx context.Context, operation func() error) error {
var lastError error
for {
if err := w.Wait(ctx); err != nil {
// The error will only be non-nil if the context is canceled.
return fmt.Errorf("could not retry operation: %w", lastError)
}
if err := operation(); err == nil {
// Reset the failure count seen by the waiter if there was no error.
w.Reset()
return nil
} else {
lastError = err
}
}
}

View File

@ -2,6 +2,7 @@ package retry
import ( import (
"context" "context"
"fmt"
"math" "math"
"testing" "testing"
"time" "time"
@ -157,6 +158,38 @@ func TestWaiter_Wait(t *testing.T) {
}) })
} }
func TestWaiter_RetryLoop(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
// Change the default factor so that we retry faster.
w := &Waiter{Factor: 1 * time.Millisecond}
t.Run("exits if operation is successful after a few reties", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
t.Cleanup(cancel)
numRetries := 0
err := w.RetryLoop(ctx, func() error {
if numRetries < 2 {
numRetries++
return fmt.Errorf("operation not successful")
}
return nil
})
require.NoError(t, err)
})
t.Run("errors if operation is never successful", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
t.Cleanup(cancel)
err := w.RetryLoop(ctx, func() error {
return fmt.Errorf("operation not successful")
})
require.NotNil(t, err)
require.EqualError(t, err, "could not retry operation: operation not successful")
})
}
func runWait(ctx context.Context, w *Waiter) (time.Duration, error) { func runWait(ctx context.Context, w *Waiter) (time.Duration, error) {
before := time.Now() before := time.Now()
err := w.Wait(ctx) err := w.Wait(ctx)

View File

@ -143,6 +143,12 @@ Usage: `consul snapshot agent [options]`
"key_file": "", "key_file": "",
"license_path": "", "license_path": "",
"tls_server_name": "", "tls_server_name": "",
"login": {
"auth_method": "",
"bearer_token": "",
"bearer_token_file": "",
"meta": {},
},
"log": { "log": {
"level": "INFO", "level": "INFO",
"enable_syslog": false, "enable_syslog": false,
@ -238,6 +244,16 @@ if desired.
- `-syslog-facility` - Sets the facility to use for forwarding logs to syslog. - `-syslog-facility` - Sets the facility to use for forwarding logs to syslog.
Defaults to "LOCAL0". Defaults to "LOCAL0".
- `login-auth-method` - Auth method name to use to log into Consul. If provided, the token obtained with this auth method
will be used instead of a static token if it is provided. Currently, only `kubernetes` auth method type is supported.
- `login-bearer-token` - Bearer token to use to log into Consul. Used only if `-login-auth-method` is set.
- `login-bearer-token-file` - A file container bearer token to use for logging into Consul.
`-login-bearer-token` is ignored if this flag is provided.
- `login-meta` - Metadata to set on the token, formatted as key=value. This flag may be provided multiple times.
#### Local Storage Options #### Local Storage Options
- `-local-path` - Location to store snapshots locally. The default behavior - `-local-path` - Location to store snapshots locally. The default behavior
@ -277,7 +293,7 @@ Note that despite the AWS references, any S3-compatible endpoint can be specifie
Use this if you want to rely on [S3's versioning capabilities](http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html) instead of the agent handling it for you. Use this if you want to rely on [S3's versioning capabilities](http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html) instead of the agent handling it for you.
- `-aws-s3-force-path-style` - Enables the use of legacy path-based addressing instead of virtual addressing. This flag is required by minio - `-aws-s3-force-path-style` - Enables the use of legacy path-based addressing instead of virtual addressing. This flag is required by minio
and other 3rd party S3 compatible object storage platforms where DNS or TLS requirements for virtual addressing are prohibitive. and other 3rd party S3 compatible object storage platforms where DNS or TLS requirements for virtual addressing are prohibitive.
For more information, refer to the AWS documentation on [Methods for accessing a bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html) For more information, refer to the AWS documentation on [Methods for accessing a bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html)
- `-aws-s3-enable-kms` - Enables using [Amazon KMS](https://aws.amazon.com/kms/) for encrypting snapshots. - `-aws-s3-enable-kms` - Enables using [Amazon KMS](https://aws.amazon.com/kms/) for encrypting snapshots.
@ -394,6 +410,6 @@ then the order of precedence is as follows:
2. `CONSUL_LICENSE_PATH` variable 2. `CONSUL_LICENSE_PATH` variable
3. `license_path` configuration. 3. `license_path` configuration.
The ability to load licenses from the configuration or environment was added in v1.10.0, The ability to load licenses from the configuration or environment was added in v1.10.0,
v1.9.7 and v1.8.13. See the [licensing documentation](/docs/enterprise/license/overview) for v1.9.7 and v1.8.13. See the [licensing documentation](/docs/enterprise/license/overview) for
more information about Consul Enterprise license management. more information about Consul Enterprise license management.