* Add boundary ferry command (#4462) * Add boundary ferry status (#4463) * Add sending auth token automatically to ferry daemon (#4465) * Hide ferry cmds, background error msgs, and dont retry background add-token requests (#4571)
76 lines
2.3 KiB
Go
76 lines
2.3 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package ferry
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/api"
|
|
"github.com/hashicorp/go-retryablehttp"
|
|
)
|
|
|
|
// userTokenToAdd is the request body to this handler.
|
|
type UpsertTokenRequest struct {
|
|
// BoundaryAddr is a required field for all requests
|
|
BoundaryAddr string `json:"boundary_addr,omitempty"`
|
|
// The raw auth token for this user.
|
|
Token string `json:"token,omitempty"`
|
|
}
|
|
|
|
// addToken builds the UpsertTokenRequest using the client's address and token.
|
|
// It then sends the request to the ferry daemon.
|
|
// The passed in cli.Ui is used to print out any errors when looking up the
|
|
// auth token from the keyring. This allows background operations calling this
|
|
// method to pass in a silent UI to suppress any output.
|
|
func addToken(ctx context.Context, apiClient *api.Client, port uint) (*api.Response, *api.Error, error) {
|
|
pa := UpsertTokenRequest{
|
|
BoundaryAddr: apiClient.Addr(),
|
|
}
|
|
token := apiClient.Token()
|
|
if token == "" {
|
|
return nil, nil, errors.New("The client auth token is empty.")
|
|
}
|
|
if parts := strings.Split(token, "_"); len(parts) != 3 {
|
|
return nil, nil, errors.New("The client provided auth token is not in the proper format.")
|
|
}
|
|
pa.Token = token
|
|
|
|
client := retryablehttp.NewClient()
|
|
client.Logger = nil
|
|
client.RetryWaitMin = 100 * time.Millisecond
|
|
client.RetryWaitMax = 1500 * time.Millisecond
|
|
|
|
// TODO (ICU-13140): Until we release ferry feature, do not retry attempts
|
|
// to connect to the ferry daemon since it adds a noticeably long delay to
|
|
// the command.
|
|
client.RetryMax = 0
|
|
|
|
req, err := retryablehttp.NewRequestWithContext(ctx, "POST", ferryUrl(port, "v1/tokens"),
|
|
retryablehttp.ReaderFunc(func() (io.Reader, error) {
|
|
b, err := json.Marshal(&pa)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error marshaling body: %w", err)
|
|
}
|
|
return bytes.NewReader(b), nil
|
|
}))
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
req.Header.Set("content-type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("Error when sending request to the ferry daemon: %w.", err)
|
|
}
|
|
apiResp := api.NewResponse(resp)
|
|
apiErr, err := apiResp.Decode(nil)
|
|
return apiResp, apiErr, err
|
|
}
|