add HCP integration component (#14723)
* add HCP integration * lint: use non-deprecated logging interface
This commit is contained in:
parent
d9e42b0f1c
commit
5e4b3ef5d4
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
agent/hcp: add initial HashiCorp Cloud Platform integration
|
||||
```
|
|
@ -24,9 +24,11 @@ import (
|
|||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/hcp-scada-provider/capability"
|
||||
"github.com/hashicorp/raft"
|
||||
"github.com/hashicorp/serf/serf"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
|
@ -40,6 +42,8 @@ import (
|
|||
"github.com/hashicorp/consul/agent/consul/servercert"
|
||||
"github.com/hashicorp/consul/agent/dns"
|
||||
external "github.com/hashicorp/consul/agent/grpc-external"
|
||||
"github.com/hashicorp/consul/agent/hcp/scada"
|
||||
libscada "github.com/hashicorp/consul/agent/hcp/scada"
|
||||
"github.com/hashicorp/consul/agent/local"
|
||||
"github.com/hashicorp/consul/agent/proxycfg"
|
||||
proxycfgglue "github.com/hashicorp/consul/agent/proxycfg-glue"
|
||||
|
@ -382,6 +386,10 @@ type Agent struct {
|
|||
// xdsServer serves the XDS protocol for configuring Envoy proxies.
|
||||
xdsServer *xds.Server
|
||||
|
||||
// scadaProvider is set when HashiCorp Cloud Platform integration is configured and exposes the agent's API over
|
||||
// an encrypted session to HCP
|
||||
scadaProvider scada.Provider
|
||||
|
||||
// enterpriseAgent embeds fields that we only access in consul-enterprise builds
|
||||
enterpriseAgent
|
||||
}
|
||||
|
@ -428,6 +436,7 @@ func New(bd BaseDeps) (*Agent, error) {
|
|||
config: bd.RuntimeConfig,
|
||||
cache: bd.Cache,
|
||||
routineManager: routine.NewManager(bd.Logger),
|
||||
scadaProvider: bd.HCP.Provider,
|
||||
}
|
||||
|
||||
// TODO: create rpcClientHealth in BaseDeps once NetRPC is available without Agent
|
||||
|
@ -769,6 +778,17 @@ func (a *Agent) Start(ctx context.Context) error {
|
|||
}()
|
||||
}
|
||||
|
||||
if a.scadaProvider != nil {
|
||||
a.scadaProvider.UpdateMeta(map[string]string{
|
||||
"consul_server_id": string(a.config.NodeID),
|
||||
})
|
||||
|
||||
if err = a.scadaProvider.Start(); err != nil {
|
||||
a.baseDeps.Logger.Error("scada provider failed to start, some HashiCorp Cloud Platform functionality has been disabled",
|
||||
"error", err, "resource_id", a.config.Cloud.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -954,6 +974,12 @@ func (a *Agent) startListeners(addrs []net.Addr) ([]net.Listener, error) {
|
|||
}
|
||||
l = &tcpKeepAliveListener{l.(*net.TCPListener)}
|
||||
|
||||
case *capability.Addr:
|
||||
l, err = a.scadaProvider.Listen(x.Capability())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
closeAll()
|
||||
return nil, fmt.Errorf("unsupported address type %T", addr)
|
||||
|
@ -1011,6 +1037,11 @@ func (a *Agent) listenHTTP() ([]apiServer, error) {
|
|||
MaxHeaderBytes: a.config.HTTPMaxHeaderBytes,
|
||||
}
|
||||
|
||||
if libscada.IsCapability(l.Addr()) {
|
||||
// wrap in http2 server handler
|
||||
httpServer.Handler = h2c.NewHandler(srv.handler(a.config.EnableDebug), &http2.Server{})
|
||||
}
|
||||
|
||||
// Load the connlimit helper into the server
|
||||
connLimitFn := a.httpConnLimiter.HTTPConnStateFuncWithDefault429Handler(10 * time.Millisecond)
|
||||
|
||||
|
@ -1027,7 +1058,12 @@ func (a *Agent) listenHTTP() ([]apiServer, error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
if err := start("http", a.config.HTTPAddrs); err != nil {
|
||||
httpAddrs := a.config.HTTPAddrs
|
||||
if a.config.IsCloudEnabled() {
|
||||
httpAddrs = append(httpAddrs, scada.CAPCoreAPI)
|
||||
}
|
||||
|
||||
if err := start("http", httpAddrs); err != nil {
|
||||
closeListeners(ln)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1582,6 +1618,11 @@ func (a *Agent) ShutdownAgent() error {
|
|||
|
||||
a.rpcClientHealth.Close()
|
||||
|
||||
// Shutdown SCADA provider
|
||||
if a.scadaProvider != nil {
|
||||
a.scadaProvider.Stop()
|
||||
}
|
||||
|
||||
var err error
|
||||
if a.delegate != nil {
|
||||
err = a.delegate.Shutdown()
|
||||
|
|
|
@ -28,10 +28,14 @@ import (
|
|||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/google/tcpproxy"
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/consul/agent/hcp/scada"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/hcp-scada-provider/capability"
|
||||
"github.com/hashicorp/serf/coordinate"
|
||||
"github.com/hashicorp/serf/serf"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
|
@ -6049,6 +6053,67 @@ peering {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAgent_startListeners_scada(t *testing.T) {
|
||||
t.Parallel()
|
||||
pvd := scada.NewMockProvider(t)
|
||||
c := capability.NewAddr("testcap")
|
||||
pvd.EXPECT().Listen(c.Capability()).Return(nil, nil).Once()
|
||||
bd := BaseDeps{
|
||||
Deps: consul.Deps{
|
||||
Logger: hclog.NewInterceptLogger(nil),
|
||||
Tokens: new(token.Store),
|
||||
GRPCConnPool: &fakeGRPCConnPool{},
|
||||
HCP: hcp.Deps{
|
||||
Provider: pvd,
|
||||
},
|
||||
},
|
||||
RuntimeConfig: &config.RuntimeConfig{},
|
||||
Cache: cache.New(cache.Options{}),
|
||||
}
|
||||
|
||||
bd, err := initEnterpriseBaseDeps(bd, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
agent, err := New(bd)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = agent.startListeners([]net.Addr{c})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAgent_scadaProvider(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pvd := scada.NewMockProvider(t)
|
||||
|
||||
// this listener is used when mocking out the scada provider
|
||||
l, err := net.Listen("tcp4", fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t)))
|
||||
require.NoError(t, err)
|
||||
defer require.NoError(t, l.Close())
|
||||
|
||||
pvd.EXPECT().UpdateMeta(mock.Anything).Once()
|
||||
pvd.EXPECT().Start().Return(nil).Once()
|
||||
pvd.EXPECT().Listen(scada.CAPCoreAPI.Capability()).Return(l, nil).Once()
|
||||
pvd.EXPECT().Stop().Return(nil).Once()
|
||||
pvd.EXPECT().SessionStatus().Return("test").Once()
|
||||
a := TestAgent{
|
||||
OverrideDeps: func(deps *BaseDeps) {
|
||||
deps.HCP.Provider = pvd
|
||||
},
|
||||
Overrides: `
|
||||
cloud {
|
||||
resource_id = "organization/0b9de9a3-8403-4ca6-aba8-fca752f42100/project/0b9de9a3-8403-4ca6-aba8-fca752f42100/consul.cluster/0b9de9a3-8403-4ca6-aba8-fca752f42100"
|
||||
client_id = "test"
|
||||
client_secret = "test"
|
||||
}`,
|
||||
}
|
||||
defer a.Shutdown()
|
||||
require.NoError(t, a.Start(t))
|
||||
|
||||
_, err = api.NewClient(&api.Config{Address: l.Addr().String()})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func getExpectedCaPoolByFile(t *testing.T) *x509.CertPool {
|
||||
pool := x509.NewCertPool()
|
||||
data, err := ioutil.ReadFile("../test/ca/root.cer")
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/armon/go-metrics/prometheus"
|
||||
hcpconfig "github.com/hashicorp/consul/agent/hcp/config"
|
||||
"github.com/hashicorp/go-bexpr"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
@ -959,6 +960,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) {
|
|||
AutoEncryptIPSAN: autoEncryptIPSAN,
|
||||
AutoEncryptAllowTLS: autoEncryptAllowTLS,
|
||||
AutoConfig: autoConfig,
|
||||
Cloud: b.cloudConfigVal(c.Cloud),
|
||||
ConnectEnabled: connectEnabled,
|
||||
ConnectCAProvider: connectCAProvider,
|
||||
ConnectCAConfig: connectCAConfig,
|
||||
|
@ -2446,6 +2448,20 @@ func validateAutoConfigAuthorizer(rt RuntimeConfig) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *builder) cloudConfigVal(v *CloudConfigRaw) (val hcpconfig.CloudConfig) {
|
||||
if v == nil {
|
||||
return val
|
||||
}
|
||||
|
||||
val.ResourceID = stringVal(v.ResourceID)
|
||||
val.ClientID = stringVal(v.ClientID)
|
||||
val.ClientSecret = stringVal(v.ClientSecret)
|
||||
val.AuthURL = stringVal(v.AuthURL)
|
||||
val.Hostname = stringVal(v.Hostname)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// decodeBytes returns the encryption key decoded.
|
||||
func decodeBytes(key string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(key)
|
||||
|
|
|
@ -153,6 +153,7 @@ type Config struct {
|
|||
CheckUpdateInterval *string `mapstructure:"check_update_interval"`
|
||||
Checks []CheckDefinition `mapstructure:"checks"`
|
||||
ClientAddr *string `mapstructure:"client_addr"`
|
||||
Cloud *CloudConfigRaw `mapstructure:"cloud"`
|
||||
ConfigEntries ConfigEntries `mapstructure:"config_entries"`
|
||||
AutoEncrypt AutoEncrypt `mapstructure:"auto_encrypt"`
|
||||
Connect Connect `mapstructure:"connect"`
|
||||
|
@ -859,6 +860,14 @@ type RPC struct {
|
|||
EnableStreaming *bool `mapstructure:"enable_streaming"`
|
||||
}
|
||||
|
||||
type CloudConfigRaw struct {
|
||||
ResourceID *string `mapstructure:"resource_id"`
|
||||
ClientID *string `mapstructure:"client_id"`
|
||||
ClientSecret *string `mapstructure:"client_secret"`
|
||||
Hostname *string `mapstructure:"hostname"`
|
||||
AuthURL *string `mapstructure:"auth_url"`
|
||||
}
|
||||
|
||||
type TLSProtocolConfig struct {
|
||||
CAFile *string `mapstructure:"ca_file"`
|
||||
CAPath *string `mapstructure:"ca_path"`
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/hashicorp/consul/agent/cache"
|
||||
"github.com/hashicorp/consul/agent/consul"
|
||||
"github.com/hashicorp/consul/agent/dns"
|
||||
hcpconfig "github.com/hashicorp/consul/agent/hcp/config"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/agent/token"
|
||||
"github.com/hashicorp/consul/api"
|
||||
|
@ -157,6 +158,11 @@ type RuntimeConfig struct {
|
|||
// hcl: autopilot { upgrade_version_tag = string }
|
||||
AutopilotUpgradeVersionTag string
|
||||
|
||||
// Cloud contains configuration for agents to connect to HCP.
|
||||
//
|
||||
// hcl: cloud { ... }
|
||||
Cloud hcpconfig.CloudConfig
|
||||
|
||||
// DNSAllowStale is used to enable lookups with stale
|
||||
// data. This gives horizontal read scalability since
|
||||
// any Consul server can service the query instead of
|
||||
|
@ -1679,6 +1685,11 @@ func (c *RuntimeConfig) Sanitized() map[string]interface{} {
|
|||
return sanitize("rt", reflect.ValueOf(c)).Interface().(map[string]interface{})
|
||||
}
|
||||
|
||||
// IsCloudEnabled returns true if a cloud.resource_id is set and the server mode is enabled
|
||||
func (c *RuntimeConfig) IsCloudEnabled() bool {
|
||||
return c.ServerMode && c.Cloud.ResourceID != ""
|
||||
}
|
||||
|
||||
// isSecret determines whether a field name represents a field which
|
||||
// may contain a secret.
|
||||
func isSecret(name string) bool {
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
|
||||
"github.com/armon/go-metrics/prometheus"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
hcpconfig "github.com/hashicorp/consul/agent/hcp/config"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
|
@ -5989,6 +5990,13 @@ func TestLoad_FullConfig(t *testing.T) {
|
|||
},
|
||||
ConnectMeshGatewayWANFederationEnabled: false,
|
||||
ConnectServerlessPluginEnabled: true,
|
||||
Cloud: hcpconfig.CloudConfig{
|
||||
ResourceID: "N43DsscE",
|
||||
ClientID: "6WvsDZCP",
|
||||
ClientSecret: "lCSMHOpB",
|
||||
Hostname: "DH4bh7aC",
|
||||
AuthURL: "332nCdR2",
|
||||
},
|
||||
DNSAddrs: []net.Addr{tcpAddr("93.95.95.81:7001"), udpAddr("93.95.95.81:7001")},
|
||||
DNSARecordLimit: 29907,
|
||||
DNSAllowStale: true,
|
||||
|
@ -6771,6 +6779,11 @@ func TestRuntimeConfig_Sanitize(t *testing.T) {
|
|||
EntryFetchMaxBurst: 42,
|
||||
EntryFetchRate: 0.334,
|
||||
},
|
||||
Cloud: hcpconfig.CloudConfig{
|
||||
ResourceID: "cluster1",
|
||||
ClientID: "id",
|
||||
ClientSecret: "secret",
|
||||
},
|
||||
ConsulCoordinateUpdatePeriod: 15 * time.Second,
|
||||
RaftProtocol: 3,
|
||||
RetryJoinLAN: []string{
|
||||
|
|
|
@ -124,6 +124,13 @@
|
|||
}
|
||||
],
|
||||
"ClientAddrs": [],
|
||||
"Cloud": {
|
||||
"AuthURL": "",
|
||||
"ClientID": "id",
|
||||
"ClientSecret": "hidden",
|
||||
"Hostname": "",
|
||||
"ResourceID": "cluster1"
|
||||
},
|
||||
"ConfigEntryBootstrap": [],
|
||||
"ConnectCAConfig": {},
|
||||
"ConnectCAProvider": "",
|
||||
|
|
|
@ -201,6 +201,13 @@ auto_encrypt = {
|
|||
ip_san = ["192.168.4.139", "192.168.4.140"]
|
||||
allow_tls = true
|
||||
}
|
||||
cloud {
|
||||
resource_id = "N43DsscE"
|
||||
client_id = "6WvsDZCP"
|
||||
client_secret = "lCSMHOpB"
|
||||
hostname = "DH4bh7aC"
|
||||
auth_url = "332nCdR2"
|
||||
}
|
||||
connect {
|
||||
ca_provider = "consul"
|
||||
ca_config {
|
||||
|
|
|
@ -203,6 +203,13 @@
|
|||
"ip_san": ["192.168.4.139", "192.168.4.140"],
|
||||
"allow_tls": true
|
||||
},
|
||||
"cloud": {
|
||||
"resource_id": "N43DsscE",
|
||||
"client_id": "6WvsDZCP",
|
||||
"client_secret": "lCSMHOpB",
|
||||
"hostname": "DH4bh7aC",
|
||||
"auth_url": "332nCdR2"
|
||||
},
|
||||
"connect": {
|
||||
"ca_provider": "consul",
|
||||
"ca_config": {
|
||||
|
|
|
@ -37,11 +37,11 @@ func (c *Client) setupSerf(conf *serf.Config, ch chan serf.Event, path string) (
|
|||
serfLogger := c.logger.
|
||||
NamedIntercept(logging.Serf).
|
||||
NamedIntercept(logging.LAN).
|
||||
StandardLoggerIntercept(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
StandardLogger(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
memberlistLogger := c.logger.
|
||||
NamedIntercept(logging.Memberlist).
|
||||
NamedIntercept(logging.LAN).
|
||||
StandardLoggerIntercept(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
StandardLogger(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
|
||||
conf.MemberlistConfig.Logger = memberlistLogger
|
||||
conf.Logger = serfLogger
|
||||
|
|
|
@ -2,6 +2,7 @@ package consul
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -1457,7 +1458,7 @@ func TestLeader_ConfigEntryBootstrap_Fail(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expectMessage: `Failed to apply configuration entry "service-splitter" / "web": discovery chain "web" uses a protocol "tcp" that does not permit advanced routing or splitting behavior"`,
|
||||
expectMessage: `Failed to apply configuration entry "service-splitter" / "web": discovery chain "web" uses a protocol "tcp" that does not permit advanced routing or splitting behavior`,
|
||||
},
|
||||
{
|
||||
name: "service-intentions without migration",
|
||||
|
@ -1497,7 +1498,7 @@ func TestLeader_ConfigEntryBootstrap_Fail(t *testing.T) {
|
|||
serverCB: func(c *Config) {
|
||||
c.ConnectEnabled = false
|
||||
},
|
||||
expectMessage: `Refusing to apply configuration entry "service-intentions" / "web" because Connect must be enabled to bootstrap intentions"`,
|
||||
expectMessage: `Refusing to apply configuration entry "service-intentions" / "web" because Connect must be enabled to bootstrap intentions`,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1516,9 +1517,11 @@ func TestLeader_ConfigEntryBootstrap_Fail(t *testing.T) {
|
|||
scan := bufio.NewScanner(pr)
|
||||
for scan.Scan() {
|
||||
line := scan.Text()
|
||||
lineJson := map[string]interface{}{}
|
||||
json.Unmarshal([]byte(line), &lineJson)
|
||||
|
||||
if strings.Contains(line, "failed to establish leadership") {
|
||||
applyErrorLine = line
|
||||
applyErrorLine = lineJson["error"].(string)
|
||||
ch <- ""
|
||||
return
|
||||
}
|
||||
|
@ -1546,6 +1549,7 @@ func TestLeader_ConfigEntryBootstrap_Fail(t *testing.T) {
|
|||
Name: config.NodeName,
|
||||
Level: testutil.TestLogLevel,
|
||||
Output: io.MultiWriter(pw, testutil.NewLogBuffer(t)),
|
||||
JSONFormat: true,
|
||||
})
|
||||
|
||||
deps := newDefaultDeps(t, config)
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package consul
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/hashicorp/consul-net-rpc/net/rpc"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
|
||||
"github.com/hashicorp/consul/agent/consul/stream"
|
||||
"github.com/hashicorp/consul/agent/grpc-external/limiter"
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/consul/agent/pool"
|
||||
"github.com/hashicorp/consul/agent/router"
|
||||
"github.com/hashicorp/consul/agent/rpc/middleware"
|
||||
|
@ -31,6 +32,10 @@ type Deps struct {
|
|||
GetNetRPCInterceptorFunc func(recorder *middleware.RequestRecorder) rpc.ServerServiceCallInterceptor
|
||||
// NewRequestRecorderFunc provides a middleware.RequestRecorder for the server to use; it cannot be nil
|
||||
NewRequestRecorderFunc func(logger hclog.Logger, isLeader func() bool, localDC string) *middleware.RequestRecorder
|
||||
|
||||
// HCP contains the dependencies required when integrating with the HashiCorp Cloud Platform
|
||||
HCP hcp.Deps
|
||||
|
||||
EnterpriseDeps
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package consul
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -17,6 +18,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
connlimit "github.com/hashicorp/go-connlimit"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
|
@ -60,6 +62,7 @@ import (
|
|||
"github.com/hashicorp/consul/proto/pbsubscribe"
|
||||
"github.com/hashicorp/consul/tlsutil"
|
||||
"github.com/hashicorp/consul/types"
|
||||
cslversion "github.com/hashicorp/consul/version"
|
||||
)
|
||||
|
||||
// NOTE The "consul.client.rpc" and "consul.client.rpc.exceeded" counters are defined in consul/client.go
|
||||
|
@ -379,6 +382,9 @@ type Server struct {
|
|||
// server is able to handle.
|
||||
xdsCapacityController *xdscapacity.Controller
|
||||
|
||||
// hcpManager handles pushing server status updates to the HashiCorp Cloud Platform when enabled
|
||||
hcpManager *hcp.Manager
|
||||
|
||||
// embedded struct to hold all the enterprise specific data
|
||||
EnterpriseServer
|
||||
}
|
||||
|
@ -448,6 +454,12 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server) (*Ser
|
|||
publisher: flat.EventPublisher,
|
||||
}
|
||||
|
||||
s.hcpManager = hcp.NewManager(hcp.ManagerConfig{
|
||||
Client: flat.HCP.Client,
|
||||
StatusFn: s.hcpServerStatus(flat),
|
||||
Logger: logger.Named("hcp_manager"),
|
||||
})
|
||||
|
||||
var recorder *middleware.RequestRecorder
|
||||
if flat.NewRequestRecorderFunc != nil {
|
||||
recorder = flat.NewRequestRecorderFunc(serverLogger, s.IsLeader, s.config.Datacenter)
|
||||
|
@ -789,6 +801,9 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server) (*Ser
|
|||
// Start the metrics handlers.
|
||||
go s.updateMetrics()
|
||||
|
||||
// Now we are setup, configure the HCP manager
|
||||
go s.hcpManager.Run(&lib.StopChannelContext{StopCh: shutdownCh})
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
|
@ -1712,6 +1727,9 @@ func (s *Server) trackLeaderChanges() {
|
|||
|
||||
s.grpcLeaderForwarder.UpdateLeaderAddr(s.config.Datacenter, string(leaderObs.LeaderAddr))
|
||||
s.peeringBackend.SetLeaderAddress(string(leaderObs.LeaderAddr))
|
||||
|
||||
// Trigger sending an update to HCP status
|
||||
s.hcpManager.SendUpdate()
|
||||
case <-s.shutdownCh:
|
||||
s.raft.DeregisterObserver(observer)
|
||||
return
|
||||
|
@ -1719,6 +1737,61 @@ func (s *Server) trackLeaderChanges() {
|
|||
}
|
||||
}
|
||||
|
||||
// hcpServerStatus is the callback used by the HCP manager to emit status updates to the HashiCorp Cloud Platform when
|
||||
// enabled.
|
||||
func (s *Server) hcpServerStatus(deps Deps) hcp.StatusCallback {
|
||||
return func(ctx context.Context) (status hcp.ServerStatus, err error) {
|
||||
status.Name = s.config.NodeName
|
||||
status.ID = string(s.config.NodeID)
|
||||
status.Version = cslversion.GetHumanVersion()
|
||||
status.LanAddress = s.config.RPCAdvertise.IP.String()
|
||||
status.GossipPort = s.config.SerfLANConfig.MemberlistConfig.AdvertisePort
|
||||
status.RPCPort = s.config.RPCAddr.Port
|
||||
|
||||
tlsCert := s.tlsConfigurator.Cert()
|
||||
if tlsCert != nil {
|
||||
status.TLS.Enabled = true
|
||||
leaf := tlsCert.Leaf
|
||||
if leaf == nil {
|
||||
// Parse the leaf cert
|
||||
leaf, err = x509.ParseCertificate(tlsCert.Certificate[0])
|
||||
if err != nil {
|
||||
// Shouldn't be possible
|
||||
return
|
||||
}
|
||||
}
|
||||
status.TLS.CertName = leaf.Subject.CommonName
|
||||
status.TLS.CertSerial = leaf.SerialNumber.String()
|
||||
status.TLS.CertExpiry = leaf.NotAfter
|
||||
status.TLS.VerifyIncoming = s.tlsConfigurator.VerifyIncomingRPC()
|
||||
status.TLS.VerifyOutgoing = s.tlsConfigurator.Base().InternalRPC.VerifyOutgoing
|
||||
status.TLS.VerifyServerHostname = s.tlsConfigurator.VerifyServerHostname()
|
||||
}
|
||||
|
||||
status.Raft.IsLeader = s.raft.State() == raft.Leader
|
||||
_, leaderID := s.raft.LeaderWithID()
|
||||
status.Raft.KnownLeader = leaderID != ""
|
||||
status.Raft.AppliedIndex = s.raft.AppliedIndex()
|
||||
if !status.Raft.IsLeader {
|
||||
status.Raft.TimeSinceLastContact = time.Since(s.raft.LastContact())
|
||||
}
|
||||
|
||||
apState := s.autopilot.GetState()
|
||||
status.Autopilot.Healthy = apState.Healthy
|
||||
status.Autopilot.FailureTolerance = apState.FailureTolerance
|
||||
status.Autopilot.NumServers = len(apState.Servers)
|
||||
status.Autopilot.NumVoters = len(apState.Voters)
|
||||
status.Autopilot.MinQuorum = int(s.getAutopilotConfigOrDefault().MinQuorum)
|
||||
|
||||
status.ScadaStatus = "unknown"
|
||||
if deps.HCP.Provider != nil {
|
||||
status.ScadaStatus = deps.HCP.Provider.SessionStatus()
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
}
|
||||
|
||||
// peersInfoContent is used to help operators understand what happened to the
|
||||
// peers.json file. This is written to a file called peers.info in the same
|
||||
// location.
|
||||
|
|
|
@ -153,11 +153,11 @@ func (s *Server) setupSerfConfig(opts setupSerfOptions) (*serf.Config, error) {
|
|||
serfLogger := s.logger.
|
||||
NamedIntercept(logging.Serf).
|
||||
NamedIntercept(subLoggerName).
|
||||
StandardLoggerIntercept(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
StandardLogger(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
memberlistLogger := s.logger.
|
||||
NamedIntercept(logging.Memberlist).
|
||||
NamedIntercept(subLoggerName).
|
||||
StandardLoggerIntercept(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
StandardLogger(&hclog.StandardLoggerOptions{InferLevels: true})
|
||||
|
||||
conf.MemberlistConfig.Logger = memberlistLogger
|
||||
conf.Logger = serfLogger
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package consul
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
@ -15,10 +16,12 @@ import (
|
|||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/google/tcpproxy"
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/memberlist"
|
||||
"github.com/hashicorp/raft"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/time/rate"
|
||||
"google.golang.org/grpc"
|
||||
|
@ -2012,3 +2015,27 @@ func TestServer_Peering_LeadershipCheck(t *testing.T) {
|
|||
// test corollary by transitivity to future-proof against any setup bugs
|
||||
require.NotEqual(t, s2.config.RPCAddr.String(), peeringLeaderAddr)
|
||||
}
|
||||
|
||||
func TestServer_hcpManager(t *testing.T) {
|
||||
_, conf1 := testServerConfig(t)
|
||||
conf1.BootstrapExpect = 1
|
||||
conf1.RPCAdvertise = &net.TCPAddr{IP: []byte{127, 0, 0, 2}, Port: conf1.RPCAddr.Port}
|
||||
hcp1 := hcp.NewMockClient(t)
|
||||
hcp1.EXPECT().PushServerStatus(mock.Anything, mock.MatchedBy(func(status *hcp.ServerStatus) bool {
|
||||
return status.ID == string(conf1.NodeID)
|
||||
})).Run(func(ctx context.Context, status *hcp.ServerStatus) {
|
||||
require.Equal(t, status.LanAddress, "127.0.0.2")
|
||||
}).Call.Return(nil)
|
||||
|
||||
deps1 := newDefaultDeps(t, conf1)
|
||||
deps1.HCP.Client = hcp1
|
||||
s1, err := newServerWithDeps(t, conf1, deps1)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
defer s1.Shutdown()
|
||||
require.NotNil(t, s1.hcpManager)
|
||||
waitForLeaderEstablishment(t, s1)
|
||||
hcp1.AssertExpectations(t)
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
// Package bootstrap handles bootstrapping an agent's config from HCP. It must be a
|
||||
// separate package from other HCP components because it has a dependency on
|
||||
// agent/config while other components need to be imported and run within the
|
||||
// server process in agent/consul and that would create a dependency cycle.
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/agent/config"
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/consul/lib/retry"
|
||||
)
|
||||
|
||||
const (
|
||||
caFileName = "server-tls-cas.pem"
|
||||
certFileName = "server-tls-cert.pem"
|
||||
keyFileName = "server-tls-key.pem"
|
||||
configFileName = "server-config.json"
|
||||
subDir = "hcp-config"
|
||||
)
|
||||
|
||||
type ConfigLoader func(source config.Source) (config.LoadResult, error)
|
||||
|
||||
// UI is a shim to allow the agent command to pass in it's mitchelh/cli.UI so we
|
||||
// can output useful messages to the user during bootstrapping. For example if
|
||||
// we have to retry several times to bootstrap we don't want the agent to just
|
||||
// stall with no output which is the case if we just returned all intermediate
|
||||
// warnings or errors.
|
||||
type UI interface {
|
||||
Output(string)
|
||||
Warn(string)
|
||||
Info(string)
|
||||
Error(string)
|
||||
}
|
||||
|
||||
// MaybeBootstrap will use the passed ConfigLoader to read the existing
|
||||
// configuration, and if required attempt to bootstrap from HCP. It will retry
|
||||
// until successful or a terminal error condition is found (e.g. permission
|
||||
// denied). It must be passed a (CLI) UI implementation so it can deliver progress
|
||||
// updates to the user, for example if it is waiting to retry for a long period.
|
||||
func MaybeBootstrap(ctx context.Context, loader ConfigLoader, ui UI) (bool, ConfigLoader, error) {
|
||||
loader = wrapConfigLoader(loader)
|
||||
res, err := loader(nil)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
// Check to see if this is a server and HCP is configured
|
||||
|
||||
if !res.RuntimeConfig.IsCloudEnabled() {
|
||||
// Not a server, let agent continue unmodified
|
||||
return false, loader, nil
|
||||
}
|
||||
|
||||
ui.Output("Bootstrapping configuration from HCP")
|
||||
|
||||
// See if we have existing config on disk
|
||||
cfgJSON, ok := loadPersistedBootstrapConfig(res.RuntimeConfig, ui)
|
||||
|
||||
if !ok {
|
||||
// Fetch from HCP
|
||||
ui.Info("Fetching configuration from HCP")
|
||||
cfgJSON, err = doHCPBootstrap(ctx, res.RuntimeConfig, ui)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("failed to bootstrap from HCP: %w", err)
|
||||
}
|
||||
ui.Info("Configuration fetched from HCP and saved on local disk")
|
||||
} else {
|
||||
ui.Info("Loaded configuration from local disk")
|
||||
}
|
||||
|
||||
// Create a new loader func to return
|
||||
newLoader := func(source config.Source) (config.LoadResult, error) {
|
||||
// Don't allow any further attempts to provide a DefaultSource. This should
|
||||
// only ever be needed later in client agent AutoConfig code but that should
|
||||
// be mutually exclusive from this bootstrapping mechanism since this is
|
||||
// only for servers. If we ever try to change that, this clear failure
|
||||
// should alert future developers that the assumptions are changing rather
|
||||
// than quietly not applying the config they expect!
|
||||
if source != nil {
|
||||
return config.LoadResult{},
|
||||
fmt.Errorf("non-nil config source provided to a loader after HCP bootstrap already provided a DefaultSource")
|
||||
}
|
||||
// Otherwise, just call to the loader we were passed with our own additional
|
||||
// JSON as the source.
|
||||
s := config.FileSource{
|
||||
Name: "HCP Bootstrap",
|
||||
Format: "json",
|
||||
Data: cfgJSON,
|
||||
}
|
||||
return loader(s)
|
||||
}
|
||||
|
||||
return true, newLoader, nil
|
||||
}
|
||||
|
||||
func wrapConfigLoader(loader ConfigLoader) ConfigLoader {
|
||||
return func(source config.Source) (config.LoadResult, error) {
|
||||
res, err := loader(source)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if res.RuntimeConfig.Cloud.ResourceID == "" {
|
||||
res.RuntimeConfig.Cloud.ResourceID = os.Getenv("HCP_RESOURCE_ID")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func doHCPBootstrap(ctx context.Context, rc *config.RuntimeConfig, ui UI) (string, error) {
|
||||
w := retry.Waiter{
|
||||
MinWait: 1 * time.Second,
|
||||
MaxWait: 5 * time.Minute,
|
||||
Jitter: retry.NewJitter(50),
|
||||
}
|
||||
|
||||
var bsCfg *hcp.BootstrapConfig
|
||||
|
||||
client, err := hcp.NewClient(rc.Cloud)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
// Note we don't want to shadow `ctx` here since we need that for the Wait
|
||||
// below.
|
||||
reqCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
resp, err := client.FetchBootstrap(reqCtx)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("failed to fetch bootstrap config from HCP, will retry in %s: %s",
|
||||
w.NextWait().Round(time.Second), err))
|
||||
if err := w.Wait(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Finished waiting, restart loop
|
||||
continue
|
||||
}
|
||||
bsCfg = resp
|
||||
break
|
||||
}
|
||||
|
||||
dataDir := rc.DataDir
|
||||
shouldPersist := true
|
||||
if dataDir == "" {
|
||||
// Agent in dev mode, we still need somewhere to persist the certs
|
||||
// temporarily though to be able to start up at all since we don't support
|
||||
// inline certs right now. Use temp dir
|
||||
tmp, err := os.MkdirTemp(os.TempDir(), "consul-dev-")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temp dir for certificates: %w", err)
|
||||
}
|
||||
dataDir = tmp
|
||||
shouldPersist = false
|
||||
}
|
||||
|
||||
// Persist the TLS cert files from the response since we need to refer to them
|
||||
// as disk files either way.
|
||||
if err := persistTLSCerts(dataDir, bsCfg); err != nil {
|
||||
return "", fmt.Errorf("failed to persist TLS certificates to dir %q: %w", dataDir, err)
|
||||
}
|
||||
// Update the config JSON to include those TLS cert files
|
||||
cfgJSON, err := injectTLSCerts(dataDir, bsCfg.ConsulConfig)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to inject TLS Certs into bootstrap config: %w", err)
|
||||
}
|
||||
|
||||
// Persist the final config we need to add for restarts. Assuming this wasn't
|
||||
// a tmp dir to start with.
|
||||
if shouldPersist {
|
||||
if err := persistBootstrapConfig(dataDir, cfgJSON); err != nil {
|
||||
return "", fmt.Errorf("failed to persist bootstrap config to dir %q: %w", dataDir, err)
|
||||
}
|
||||
}
|
||||
|
||||
return cfgJSON, nil
|
||||
}
|
||||
|
||||
func persistTLSCerts(dataDir string, bsCfg *hcp.BootstrapConfig) error {
|
||||
dir := filepath.Join(dataDir, subDir)
|
||||
|
||||
if bsCfg.TLSCert == "" || bsCfg.TLSCertKey == "" {
|
||||
return fmt.Errorf("unexpected bootstrap response from HCP: missing TLS information")
|
||||
}
|
||||
|
||||
// Create a subdir if it's not already there
|
||||
if err := lib.EnsurePath(dir, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write out CA cert(s). We write them all to one file because Go's x509
|
||||
// machinery will read as many certs as it finds from each PEM file provided
|
||||
// and add them separaetly to the CertPool for validation
|
||||
f, err := os.OpenFile(filepath.Join(dir, caFileName), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bf := bufio.NewWriter(f)
|
||||
for _, caPEM := range bsCfg.TLSCAs {
|
||||
bf.WriteString(caPEM + "\n")
|
||||
}
|
||||
if err := bf.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, certFileName), []byte(bsCfg.TLSCert), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, keyFileName), []byte(bsCfg.TLSCertKey), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func injectTLSCerts(dataDir string, bootstrapJSON string) (string, error) {
|
||||
// Parse just to a map for now as we only have to inject to a specific place
|
||||
// and parsing whole Config struct is complicated...
|
||||
var cfg map[string]interface{}
|
||||
|
||||
if err := json.Unmarshal([]byte(bootstrapJSON), &cfg); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Inject TLS cert files
|
||||
cfg["ca_file"] = filepath.Join(dataDir, subDir, caFileName)
|
||||
cfg["cert_file"] = filepath.Join(dataDir, subDir, certFileName)
|
||||
cfg["key_file"] = filepath.Join(dataDir, subDir, keyFileName)
|
||||
|
||||
jsonBs, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(jsonBs), nil
|
||||
}
|
||||
|
||||
func persistBootstrapConfig(dataDir, cfgJSON string) error {
|
||||
// Persist the important bits we got from bootstrapping. The TLS certs are
|
||||
// already persisted, just need to persist the config we are going to add.
|
||||
name := filepath.Join(dataDir, subDir, configFileName)
|
||||
return ioutil.WriteFile(name, []byte(cfgJSON), 0600)
|
||||
}
|
||||
|
||||
func loadPersistedBootstrapConfig(rc *config.RuntimeConfig, ui UI) (string, bool) {
|
||||
// Check if the files all exist
|
||||
files := []string{
|
||||
filepath.Join(rc.DataDir, subDir, configFileName),
|
||||
filepath.Join(rc.DataDir, subDir, caFileName),
|
||||
filepath.Join(rc.DataDir, subDir, certFileName),
|
||||
filepath.Join(rc.DataDir, subDir, keyFileName),
|
||||
}
|
||||
hasSome := false
|
||||
for _, name := range files {
|
||||
if _, err := os.Stat(name); errors.Is(err, os.ErrNotExist) {
|
||||
// At least one required file doesn't exist, failed loading. This is not
|
||||
// an error though
|
||||
if hasSome {
|
||||
ui.Warn("ignoring incomplete local bootstrap config files")
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
hasSome = true
|
||||
}
|
||||
|
||||
name := filepath.Join(rc.DataDir, subDir, configFileName)
|
||||
jsonBs, err := ioutil.ReadFile(name)
|
||||
if err != nil {
|
||||
ui.Warn(fmt.Sprintf("failed to read local bootstrap config file, ignoring local files: %s", err))
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Check this looks non-empty at least
|
||||
jsonStr := strings.TrimSpace(string(jsonBs))
|
||||
// 50 is arbitrary but config containing the right secrets would always be
|
||||
// bigger than this in JSON format so it is a reasonable test that this wasn't
|
||||
// empty or just an empty JSON object or something.
|
||||
if len(jsonStr) < 50 {
|
||||
ui.Warn("ignoring incomplete local bootstrap config files")
|
||||
return "", false
|
||||
}
|
||||
|
||||
// TODO we could parse the certificates and check they are still valid here
|
||||
// and force a reload if not. We could also attempt to parse config and check
|
||||
// it's all valid just in case the local config was really old and has
|
||||
// deprecated fields or something?
|
||||
return jsonStr, true
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models"
|
||||
"github.com/hashicorp/hcp-sdk-go/resource"
|
||||
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/consul/tlsutil"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
)
|
||||
|
||||
// TestEndpoint returns an hcp.TestEndpoint to be used in an hcp.MockHCPServer.
|
||||
func TestEndpoint() hcp.TestEndpoint {
|
||||
// Memoize data so it's consistent for the life of the test server
|
||||
data := make(map[string]gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse)
|
||||
|
||||
return hcp.TestEndpoint{
|
||||
Methods: []string{"GET"},
|
||||
PathSuffix: "agent/bootstrap_config",
|
||||
Handler: func(r *http.Request, cluster resource.Resource) (interface{}, error) {
|
||||
return handleBootstrap(data, cluster)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func handleBootstrap(data map[string]gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse, cluster resource.Resource) (interface{}, error) {
|
||||
resp, ok := data[cluster.ID]
|
||||
if !ok {
|
||||
// Create new response
|
||||
r, err := generateClusterData(cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data[cluster.ID] = r
|
||||
resp = r
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func generateClusterData(cluster resource.Resource) (gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse, error) {
|
||||
resp := gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse{
|
||||
Cluster: &gnmmod.HashicorpCloudGlobalNetworkManager20220215Cluster{},
|
||||
Bootstrap: &gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterBootstrap{
|
||||
ServerTLS: &gnmmod.HashicorpCloudGlobalNetworkManager20220215ServerTLS{},
|
||||
},
|
||||
}
|
||||
|
||||
CACert, CAKey, err := tlsutil.GenerateCA(tlsutil.CAOpts{})
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
resp.Bootstrap.ServerTLS.CertificateAuthorities = append(resp.Bootstrap.ServerTLS.CertificateAuthorities, CACert)
|
||||
signer, err := tlsutil.ParseSigner(CAKey)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
cert, priv, err := tlsutil.GenerateCert(tlsutil.CertOpts{
|
||||
Signer: signer,
|
||||
CA: CACert,
|
||||
Name: "server.dc1.consul",
|
||||
Days: 30,
|
||||
DNSNames: []string{"server.dc1.consul", "localhost"},
|
||||
IPAddresses: append([]net.IP{}, net.ParseIP("127.0.0.1")),
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
})
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.Bootstrap.ServerTLS.Cert = cert
|
||||
resp.Bootstrap.ServerTLS.PrivateKey = priv
|
||||
|
||||
// Generate Config. We don't use the read config.Config struct because it
|
||||
// doesn't have `omitempty` which makes the output gross. We only want a tiny
|
||||
// subset, so we use a map that ends up with the same structure for now.
|
||||
|
||||
// Gossip key
|
||||
gossipKeyBs := make([]byte, 32)
|
||||
_, err = rand.Reader.Read(gossipKeyBs)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
retryJoinArgs := map[string]string{
|
||||
"provider": "hcp",
|
||||
"resource_id": cluster.String(),
|
||||
"client_id": "test_id",
|
||||
"client_secret": "test_secret",
|
||||
}
|
||||
|
||||
cfg := map[string]interface{}{
|
||||
"encrypt": base64.StdEncoding.EncodeToString(gossipKeyBs),
|
||||
"encrypt_verify_incoming": true,
|
||||
"encrypt_verify_outgoing": true,
|
||||
|
||||
// TLS settings (certs will be added by client since we can't put them inline)
|
||||
"verify_incoming": true,
|
||||
"verify_outgoing": true,
|
||||
"verify_server_hostname": true,
|
||||
"auto_encrypt": map[string]interface{}{
|
||||
"allow_tls": true,
|
||||
},
|
||||
|
||||
// Enable HTTPS port, disable HTTP
|
||||
"ports": map[string]interface{}{
|
||||
"https": 8501,
|
||||
"http": -1,
|
||||
},
|
||||
|
||||
// RAFT Peers
|
||||
"bootstrap_expect": 1,
|
||||
"retry_join": []string{
|
||||
mapArgsString(retryJoinArgs),
|
||||
},
|
||||
}
|
||||
|
||||
// ACLs
|
||||
management, err := uuid.GenerateUUID()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
cfg["acl"] = map[string]interface{}{
|
||||
"tokens": map[string]interface{}{
|
||||
"initial_management": management,
|
||||
// Also setup the server's own agent token to be the same so it has
|
||||
// permission to register itself.
|
||||
"agent": management,
|
||||
},
|
||||
"default_policy": "deny",
|
||||
"enabled": true,
|
||||
"enable_token_persistence": true,
|
||||
}
|
||||
|
||||
// Encode and return a JSON string in the response
|
||||
jsonBs, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.Bootstrap.ConsulConfig = string(jsonBs)
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func mapArgsString(m map[string]string) string {
|
||||
args := make([]string, len(m))
|
||||
for k, v := range m {
|
||||
args = append(args, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
return strings.Join(args, " ")
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
package hcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
hcpgnm "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/client/global_network_manager_service"
|
||||
gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models"
|
||||
"github.com/hashicorp/hcp-sdk-go/httpclient"
|
||||
"github.com/hashicorp/hcp-sdk-go/resource"
|
||||
|
||||
"github.com/hashicorp/consul/agent/hcp/config"
|
||||
"github.com/hashicorp/consul/version"
|
||||
)
|
||||
|
||||
// Client interface exposes HCP operations that can be invoked by Consul
|
||||
//go:generate mockery --name Client --with-expecter --inpackage
|
||||
type Client interface {
|
||||
FetchBootstrap(ctx context.Context) (*BootstrapConfig, error)
|
||||
PushServerStatus(ctx context.Context, status *ServerStatus) error
|
||||
DiscoverServers(ctx context.Context) ([]string, error)
|
||||
}
|
||||
|
||||
type BootstrapConfig struct {
|
||||
Name string
|
||||
BootstrapExpect int
|
||||
GossipKey string
|
||||
TLSCert string
|
||||
TLSCertKey string
|
||||
TLSCAs []string
|
||||
ConsulConfig string
|
||||
}
|
||||
|
||||
type hcpClient struct {
|
||||
hc *httptransport.Runtime
|
||||
cfg config.CloudConfig
|
||||
gnm hcpgnm.ClientService
|
||||
resource resource.Resource
|
||||
}
|
||||
|
||||
func NewClient(cfg config.CloudConfig) (Client, error) {
|
||||
client := &hcpClient{
|
||||
cfg: cfg,
|
||||
}
|
||||
|
||||
var err error
|
||||
client.resource, err = resource.FromString(cfg.ResourceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.hc, err = httpClient(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.gnm = hcpgnm.New(client.hc, nil)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func httpClient(c config.CloudConfig) (*httptransport.Runtime, error) {
|
||||
cfg, err := c.HCPConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return httpclient.New(httpclient.Config{
|
||||
HCPConfig: cfg,
|
||||
SourceChannel: "consul " + version.GetHumanVersion(),
|
||||
})
|
||||
}
|
||||
|
||||
func (c *hcpClient) FetchBootstrap(ctx context.Context) (*BootstrapConfig, error) {
|
||||
params := hcpgnm.NewAgentBootstrapConfigParamsWithContext(ctx).
|
||||
WithID(c.resource.ID).
|
||||
WithLocationOrganizationID(c.resource.Organization).
|
||||
WithLocationProjectID(c.resource.Project)
|
||||
|
||||
resp, err := c.gnm.AgentBootstrapConfig(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bootstrapConfigFromHCP(resp.Payload), nil
|
||||
}
|
||||
|
||||
func bootstrapConfigFromHCP(res *gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse) *BootstrapConfig {
|
||||
var serverTLS gnmmod.HashicorpCloudGlobalNetworkManager20220215ServerTLS
|
||||
if res.Bootstrap.ServerTLS != nil {
|
||||
serverTLS = *res.Bootstrap.ServerTLS
|
||||
}
|
||||
|
||||
return &BootstrapConfig{
|
||||
Name: res.Bootstrap.ID,
|
||||
BootstrapExpect: int(res.Bootstrap.BootstrapExpect),
|
||||
GossipKey: res.Bootstrap.GossipKey,
|
||||
TLSCert: serverTLS.Cert,
|
||||
TLSCertKey: serverTLS.PrivateKey,
|
||||
TLSCAs: serverTLS.CertificateAuthorities,
|
||||
ConsulConfig: res.Bootstrap.ConsulConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *hcpClient) PushServerStatus(ctx context.Context, s *ServerStatus) error {
|
||||
params := hcpgnm.NewAgentPushServerStateParamsWithContext(ctx).
|
||||
WithID(c.resource.ID).
|
||||
WithLocationOrganizationID(c.resource.Organization).
|
||||
WithLocationProjectID(c.resource.Project)
|
||||
|
||||
params.SetBody(&gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentPushServerStateRequest{
|
||||
ServerState: serverStatusToHCP(s),
|
||||
})
|
||||
|
||||
_, err := c.gnm.AgentPushServerState(params, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
type ServerStatus struct {
|
||||
ID string
|
||||
Name string
|
||||
Version string
|
||||
LanAddress string
|
||||
GossipPort int
|
||||
RPCPort int
|
||||
|
||||
Autopilot ServerAutopilot
|
||||
Raft ServerRaft
|
||||
TLS ServerTLSInfo
|
||||
|
||||
ScadaStatus string
|
||||
}
|
||||
|
||||
type ServerAutopilot struct {
|
||||
FailureTolerance int
|
||||
Healthy bool
|
||||
MinQuorum int
|
||||
NumServers int
|
||||
NumVoters int
|
||||
}
|
||||
|
||||
type ServerRaft struct {
|
||||
IsLeader bool
|
||||
KnownLeader bool
|
||||
AppliedIndex uint64
|
||||
TimeSinceLastContact time.Duration
|
||||
}
|
||||
|
||||
type ServerTLSInfo struct {
|
||||
Enabled bool
|
||||
CertExpiry time.Time
|
||||
CertName string
|
||||
CertSerial string
|
||||
VerifyIncoming bool
|
||||
VerifyOutgoing bool
|
||||
VerifyServerHostname bool
|
||||
}
|
||||
|
||||
func serverStatusToHCP(s *ServerStatus) *gnmmod.HashicorpCloudGlobalNetworkManager20220215ServerState {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
return &gnmmod.HashicorpCloudGlobalNetworkManager20220215ServerState{
|
||||
Autopilot: &gnmmod.HashicorpCloudGlobalNetworkManager20220215AutoPilotInfo{
|
||||
FailureTolerance: int32(s.Autopilot.FailureTolerance),
|
||||
Healthy: s.Autopilot.Healthy,
|
||||
MinQuorum: int32(s.Autopilot.MinQuorum),
|
||||
NumServers: int32(s.Autopilot.NumServers),
|
||||
NumVoters: int32(s.Autopilot.NumVoters),
|
||||
},
|
||||
GossipPort: int32(s.GossipPort),
|
||||
ID: s.ID,
|
||||
LanAddress: s.LanAddress,
|
||||
Name: s.Name,
|
||||
Raft: &gnmmod.HashicorpCloudGlobalNetworkManager20220215RaftInfo{
|
||||
AppliedIndex: strconv.FormatUint(s.Raft.AppliedIndex, 10),
|
||||
IsLeader: s.Raft.IsLeader,
|
||||
KnownLeader: s.Raft.KnownLeader,
|
||||
TimeSinceLastContact: s.Raft.TimeSinceLastContact.String(),
|
||||
},
|
||||
RPCPort: int32(s.RPCPort),
|
||||
TLS: &gnmmod.HashicorpCloudGlobalNetworkManager20220215TLSInfo{
|
||||
CertExpiry: strfmt.DateTime(s.TLS.CertExpiry),
|
||||
CertName: s.TLS.CertName,
|
||||
CertSerial: s.TLS.CertSerial,
|
||||
Enabled: s.TLS.Enabled,
|
||||
VerifyIncoming: s.TLS.VerifyIncoming,
|
||||
VerifyOutgoing: s.TLS.VerifyOutgoing,
|
||||
VerifyServerHostname: s.TLS.VerifyServerHostname,
|
||||
},
|
||||
Version: s.Version,
|
||||
ScadaStatus: s.ScadaStatus,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *hcpClient) DiscoverServers(ctx context.Context) ([]string, error) {
|
||||
params := hcpgnm.NewAgentDiscoverParamsWithContext(ctx).
|
||||
WithID(c.resource.ID).
|
||||
WithLocationOrganizationID(c.resource.Organization).
|
||||
WithLocationProjectID(c.resource.Project)
|
||||
|
||||
resp, err := c.gnm.AgentDiscover(params, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var servers []string
|
||||
for _, srv := range resp.Payload.Servers {
|
||||
if srv != nil {
|
||||
servers = append(servers, fmt.Sprintf("%s:%d", srv.LanAddress, srv.GossipPort))
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
||||
hcpcfg "github.com/hashicorp/hcp-sdk-go/config"
|
||||
)
|
||||
|
||||
// CloudConfig defines configuration for connecting to HCP services
|
||||
type CloudConfig struct {
|
||||
ResourceID string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
Hostname string
|
||||
AuthURL string
|
||||
}
|
||||
|
||||
func (c *CloudConfig) HCPConfig(opts ...hcpcfg.HCPConfigOption) (hcpcfg.HCPConfig, error) {
|
||||
if c.ClientID != "" && c.ClientSecret != "" {
|
||||
opts = append(opts, hcpcfg.WithClientCredentials(c.ClientID, c.ClientSecret))
|
||||
}
|
||||
if c.AuthURL != "" {
|
||||
opts = append(opts, hcpcfg.WithAuth(c.AuthURL, &tls.Config{}))
|
||||
}
|
||||
if c.Hostname != "" {
|
||||
opts = append(opts, hcpcfg.WithAPI(c.Hostname, &tls.Config{}))
|
||||
}
|
||||
opts = append(opts, hcpcfg.FromEnv())
|
||||
return hcpcfg.NewHCPConfig(opts...)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package hcp
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/consul/agent/hcp/config"
|
||||
"github.com/hashicorp/consul/agent/hcp/scada"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
// Deps contains the interfaces that the rest of Consul core depends on for HCP integration.
|
||||
type Deps struct {
|
||||
Client Client
|
||||
Provider scada.Provider
|
||||
}
|
||||
|
||||
func NewDeps(cfg config.CloudConfig, logger hclog.Logger) (d Deps, err error) {
|
||||
d.Client, err = NewClient(cfg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
d.Provider, err = scada.New(cfg, logger.Named("hcp.scada"))
|
||||
return
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package discover
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/consul/agent/hcp/config"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
}
|
||||
|
||||
var (
|
||||
defaultTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
type providerConfig struct {
|
||||
config.CloudConfig
|
||||
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func (p *Provider) Addrs(args map[string]string, l *log.Logger) ([]string, error) {
|
||||
cfg, err := parseArgs(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := hcp.NewClient(cfg.CloudConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), cfg.timeout)
|
||||
defer cancel()
|
||||
servers, err := client.DiscoverServers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func (p *Provider) Help() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func parseArgs(args map[string]string) (cfg providerConfig, err error) {
|
||||
cfg.timeout = defaultTimeout
|
||||
|
||||
if id, ok := args["resource_id"]; ok {
|
||||
cfg.ResourceID = id
|
||||
} else {
|
||||
err = fmt.Errorf("'resource_id' was not found and is required")
|
||||
}
|
||||
|
||||
if cid, ok := args["client_id"]; ok {
|
||||
cfg.ClientID = cid
|
||||
}
|
||||
|
||||
if csec, ok := args["client_secret"]; ok {
|
||||
cfg.ClientSecret = csec
|
||||
}
|
||||
|
||||
if timeoutRaw, ok := args["timeout"]; ok {
|
||||
timeout, err := time.ParseDuration(timeoutRaw)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
cfg.timeout = timeout
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
package hcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultManagerMinInterval = 45 * time.Minute
|
||||
defaultManagerMaxInterval = 75 * time.Minute
|
||||
)
|
||||
|
||||
type ManagerConfig struct {
|
||||
Client Client
|
||||
|
||||
StatusFn StatusCallback
|
||||
MinInterval time.Duration
|
||||
MaxInterval time.Duration
|
||||
|
||||
Logger hclog.Logger
|
||||
}
|
||||
|
||||
func (cfg *ManagerConfig) enabled() bool {
|
||||
return cfg.Client != nil && cfg.StatusFn != nil
|
||||
}
|
||||
|
||||
func (cfg *ManagerConfig) nextHeartbeat() time.Duration {
|
||||
min := cfg.MinInterval
|
||||
if min == 0 {
|
||||
min = defaultManagerMinInterval
|
||||
}
|
||||
|
||||
max := cfg.MaxInterval
|
||||
if max == 0 {
|
||||
max = defaultManagerMaxInterval
|
||||
}
|
||||
if max < min {
|
||||
max = min
|
||||
}
|
||||
return min + lib.RandomStagger(max-min)
|
||||
}
|
||||
|
||||
type StatusCallback func(context.Context) (ServerStatus, error)
|
||||
|
||||
type Manager struct {
|
||||
logger hclog.Logger
|
||||
|
||||
cfg ManagerConfig
|
||||
cfgMu sync.RWMutex
|
||||
|
||||
updateCh chan struct{}
|
||||
|
||||
// testUpdateSent is set by unit tests to signal when the manager's status update has triggered
|
||||
testUpdateSent chan struct{}
|
||||
}
|
||||
|
||||
// NewManager returns an initialized Manager with a zero configuration. It won't
|
||||
// do anything until UpdateConfig is called with a config that provides
|
||||
// credentials to contact HCP.
|
||||
func NewManager(cfg ManagerConfig) *Manager {
|
||||
return &Manager{
|
||||
logger: cfg.Logger,
|
||||
cfg: cfg,
|
||||
|
||||
updateCh: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// Run executes the Manager it's designed to be run in its own goroutine for
|
||||
// the life of a server agent. It should be run even if HCP is not configured
|
||||
// yet for servers since a config update might configure it later and
|
||||
// UpdateConfig called. It will effectively do nothing if there are no HCP
|
||||
// credentials set other than wait for some to be added.
|
||||
func (m *Manager) Run(ctx context.Context) {
|
||||
var err error
|
||||
m.logger.Debug("HCP manager starting")
|
||||
|
||||
// immediately send initial update
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-m.updateCh: // empty the update chan if there is a queued update to prevent repeated update in main loop
|
||||
err = m.sendUpdate()
|
||||
default:
|
||||
err = m.sendUpdate()
|
||||
}
|
||||
|
||||
// main loop
|
||||
for {
|
||||
m.cfgMu.RLock()
|
||||
cfg := m.cfg
|
||||
m.cfgMu.RUnlock()
|
||||
nextUpdate := cfg.nextHeartbeat()
|
||||
if err != nil {
|
||||
m.logger.Error("failed to send server status to HCP", "err", err, "next_heartbeat", nextUpdate.String())
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case <-m.updateCh:
|
||||
err = m.sendUpdate()
|
||||
|
||||
case <-time.After(nextUpdate):
|
||||
err = m.sendUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) UpdateConfig(cfg ManagerConfig) {
|
||||
m.cfgMu.Lock()
|
||||
defer m.cfgMu.Unlock()
|
||||
old := m.cfg
|
||||
m.cfg = cfg
|
||||
if old.enabled() || cfg.enabled() {
|
||||
// Only log about this if cloud is actually configured or it would be
|
||||
// confusing. We check both old and new in case we are disabling cloud or
|
||||
// enabling it or just updating it.
|
||||
m.logger.Info("updated HCP configuration")
|
||||
}
|
||||
|
||||
// Send a new status update since we might have just gotten connection details
|
||||
// for the first time.
|
||||
m.SendUpdate()
|
||||
}
|
||||
|
||||
func (m *Manager) SendUpdate() {
|
||||
m.logger.Debug("HCP triggering status update")
|
||||
select {
|
||||
case m.updateCh <- struct{}{}:
|
||||
// trigger update
|
||||
default:
|
||||
// if chan is full then there is already an update triggered that will soon
|
||||
// be acted on so don't bother blocking.
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: we should have retried on failures here with backoff but take into
|
||||
// account that if a new update is triggered while we are still retrying we
|
||||
// should not start another retry loop. Something like have a "dirty" flag which
|
||||
// we mark on first PushUpdate and then a retry timer as well as the interval
|
||||
// and a "isRetrying" state or something so that we attempt to send update, but
|
||||
// then fetch fresh info on each attempt to send so if we are already in a retry
|
||||
// backoff a new push is a no-op.
|
||||
func (m *Manager) sendUpdate() error {
|
||||
m.cfgMu.RLock()
|
||||
cfg := m.cfg
|
||||
m.cfgMu.RUnlock()
|
||||
|
||||
if !cfg.enabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.testUpdateSent != nil {
|
||||
defer func() {
|
||||
select {
|
||||
case m.testUpdateSent <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
s, err := cfg.StatusFn(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.cfg.Client.PushServerStatus(ctx, &s)
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package hcp
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestManager_Run(t *testing.T) {
|
||||
client := NewMockClient(t)
|
||||
statusF := func(ctx context.Context) (ServerStatus, error) {
|
||||
return ServerStatus{ID: t.Name()}, nil
|
||||
}
|
||||
updateCh := make(chan struct{}, 1)
|
||||
client.EXPECT().PushServerStatus(mock.Anything, &ServerStatus{ID: t.Name()}).Return(nil).Once()
|
||||
mgr := NewManager(ManagerConfig{
|
||||
Client: client,
|
||||
Logger: hclog.New(&hclog.LoggerOptions{Output: ioutil.Discard}),
|
||||
StatusFn: statusF,
|
||||
})
|
||||
mgr.testUpdateSent = updateCh
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
go mgr.Run(ctx)
|
||||
select {
|
||||
case <-updateCh:
|
||||
case <-time.After(time.Second):
|
||||
require.Fail(t, "manager did not send update in expected time")
|
||||
}
|
||||
|
||||
// Make sure after manager has stopped no more statuses are pushed.
|
||||
cancel()
|
||||
mgr.SendUpdate()
|
||||
client.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestManager_SendUpdate(t *testing.T) {
|
||||
client := NewMockClient(t)
|
||||
statusF := func(ctx context.Context) (ServerStatus, error) {
|
||||
return ServerStatus{ID: t.Name()}, nil
|
||||
}
|
||||
updateCh := make(chan struct{}, 1)
|
||||
|
||||
// Expect two calls, once during run startup and again when SendUpdate is called
|
||||
client.EXPECT().PushServerStatus(mock.Anything, &ServerStatus{ID: t.Name()}).Return(nil).Twice()
|
||||
mgr := NewManager(ManagerConfig{
|
||||
Client: client,
|
||||
Logger: hclog.New(&hclog.LoggerOptions{Output: ioutil.Discard}),
|
||||
StatusFn: statusF,
|
||||
})
|
||||
mgr.testUpdateSent = updateCh
|
||||
go mgr.Run(context.Background())
|
||||
select {
|
||||
case <-updateCh:
|
||||
case <-time.After(time.Second):
|
||||
require.Fail(t, "manager did not send update in expected time")
|
||||
}
|
||||
mgr.SendUpdate()
|
||||
select {
|
||||
case <-updateCh:
|
||||
case <-time.After(time.Second):
|
||||
require.Fail(t, "manager did not send update in expected time")
|
||||
}
|
||||
client.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestManager_SendUpdate_Periodic(t *testing.T) {
|
||||
client := NewMockClient(t)
|
||||
statusF := func(ctx context.Context) (ServerStatus, error) {
|
||||
return ServerStatus{ID: t.Name()}, nil
|
||||
}
|
||||
updateCh := make(chan struct{}, 1)
|
||||
|
||||
// Expect two calls, once during run startup and again when SendUpdate is called
|
||||
client.EXPECT().PushServerStatus(mock.Anything, &ServerStatus{ID: t.Name()}).Return(nil).Twice()
|
||||
mgr := NewManager(ManagerConfig{
|
||||
Client: client,
|
||||
Logger: hclog.New(&hclog.LoggerOptions{Output: ioutil.Discard}),
|
||||
StatusFn: statusF,
|
||||
MaxInterval: time.Second,
|
||||
MinInterval: 100 * time.Millisecond,
|
||||
})
|
||||
mgr.testUpdateSent = updateCh
|
||||
go mgr.Run(context.Background())
|
||||
select {
|
||||
case <-updateCh:
|
||||
case <-time.After(time.Second):
|
||||
require.Fail(t, "manager did not send update in expected time")
|
||||
}
|
||||
select {
|
||||
case <-updateCh:
|
||||
case <-time.After(time.Second):
|
||||
require.Fail(t, "manager did not send update in expected time")
|
||||
}
|
||||
client.AssertExpectations(t)
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
// Code generated by mockery v2.13.1. DO NOT EDIT.
|
||||
|
||||
package hcp
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockClient is an autogenerated mock type for the Client type
|
||||
type MockClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockClient_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockClient) EXPECT() *MockClient_Expecter {
|
||||
return &MockClient_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// DiscoverServers provides a mock function with given fields: ctx
|
||||
func (_m *MockClient) DiscoverServers(ctx context.Context) ([]string, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 []string
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []string); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockClient_DiscoverServers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DiscoverServers'
|
||||
type MockClient_DiscoverServers_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// DiscoverServers is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *MockClient_Expecter) DiscoverServers(ctx interface{}) *MockClient_DiscoverServers_Call {
|
||||
return &MockClient_DiscoverServers_Call{Call: _e.mock.On("DiscoverServers", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockClient_DiscoverServers_Call) Run(run func(ctx context.Context)) *MockClient_DiscoverServers_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockClient_DiscoverServers_Call) Return(_a0 []string, _a1 error) *MockClient_DiscoverServers_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
// FetchBootstrap provides a mock function with given fields: ctx
|
||||
func (_m *MockClient) FetchBootstrap(ctx context.Context) (*BootstrapConfig, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 *BootstrapConfig
|
||||
if rf, ok := ret.Get(0).(func(context.Context) *BootstrapConfig); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*BootstrapConfig)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockClient_FetchBootstrap_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FetchBootstrap'
|
||||
type MockClient_FetchBootstrap_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// FetchBootstrap is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *MockClient_Expecter) FetchBootstrap(ctx interface{}) *MockClient_FetchBootstrap_Call {
|
||||
return &MockClient_FetchBootstrap_Call{Call: _e.mock.On("FetchBootstrap", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockClient_FetchBootstrap_Call) Run(run func(ctx context.Context)) *MockClient_FetchBootstrap_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockClient_FetchBootstrap_Call) Return(_a0 *BootstrapConfig, _a1 error) *MockClient_FetchBootstrap_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
// PushServerStatus provides a mock function with given fields: ctx, status
|
||||
func (_m *MockClient) PushServerStatus(ctx context.Context, status *ServerStatus) error {
|
||||
ret := _m.Called(ctx, status)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *ServerStatus) error); ok {
|
||||
r0 = rf(ctx, status)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockClient_PushServerStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PushServerStatus'
|
||||
type MockClient_PushServerStatus_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// PushServerStatus is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - status *ServerStatus
|
||||
func (_e *MockClient_Expecter) PushServerStatus(ctx interface{}, status interface{}) *MockClient_PushServerStatus_Call {
|
||||
return &MockClient_PushServerStatus_Call{Call: _e.mock.On("PushServerStatus", ctx, status)}
|
||||
}
|
||||
|
||||
func (_c *MockClient_PushServerStatus_Call) Run(run func(ctx context.Context, status *ServerStatus)) *MockClient_PushServerStatus_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*ServerStatus))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockClient_PushServerStatus_Call) Return(_a0 error) *MockClient_PushServerStatus_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewMockClient interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewMockClient creates a new instance of MockClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewMockClient(t mockConstructorTestingTNewMockClient) *MockClient {
|
||||
mock := &MockClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package scada
|
||||
|
||||
import "github.com/hashicorp/hcp-scada-provider/capability"
|
||||
|
||||
// CAPCoreAPI is the capability used to securely expose the Consul HTTP API to HCP
|
||||
var CAPCoreAPI = capability.NewAddr("core_api")
|
|
@ -0,0 +1,302 @@
|
|||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
|
||||
package scada
|
||||
|
||||
import (
|
||||
net "net"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
time "time"
|
||||
)
|
||||
|
||||
// MockProvider is an autogenerated mock type for the Provider type
|
||||
type MockProvider struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockProvider_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockProvider) EXPECT() *MockProvider_Expecter {
|
||||
return &MockProvider_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// GetMeta provides a mock function with given fields:
|
||||
func (_m *MockProvider) GetMeta() map[string]string {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 map[string]string
|
||||
if rf, ok := ret.Get(0).(func() map[string]string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]string)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockProvider_GetMeta_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMeta'
|
||||
type MockProvider_GetMeta_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetMeta is a helper method to define mock.On call
|
||||
func (_e *MockProvider_Expecter) GetMeta() *MockProvider_GetMeta_Call {
|
||||
return &MockProvider_GetMeta_Call{Call: _e.mock.On("GetMeta")}
|
||||
}
|
||||
|
||||
func (_c *MockProvider_GetMeta_Call) Run(run func()) *MockProvider_GetMeta_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProvider_GetMeta_Call) Return(_a0 map[string]string) *MockProvider_GetMeta_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
// LastError provides a mock function with given fields:
|
||||
func (_m *MockProvider) LastError() (time.Time, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 time.Time
|
||||
if rf, ok := ret.Get(0).(func() time.Time); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(time.Time)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockProvider_LastError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LastError'
|
||||
type MockProvider_LastError_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// LastError is a helper method to define mock.On call
|
||||
func (_e *MockProvider_Expecter) LastError() *MockProvider_LastError_Call {
|
||||
return &MockProvider_LastError_Call{Call: _e.mock.On("LastError")}
|
||||
}
|
||||
|
||||
func (_c *MockProvider_LastError_Call) Run(run func()) *MockProvider_LastError_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProvider_LastError_Call) Return(_a0 time.Time, _a1 error) *MockProvider_LastError_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Listen provides a mock function with given fields: capability
|
||||
func (_m *MockProvider) Listen(capability string) (net.Listener, error) {
|
||||
ret := _m.Called(capability)
|
||||
|
||||
var r0 net.Listener
|
||||
if rf, ok := ret.Get(0).(func(string) net.Listener); ok {
|
||||
r0 = rf(capability)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(net.Listener)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(capability)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockProvider_Listen_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Listen'
|
||||
type MockProvider_Listen_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Listen is a helper method to define mock.On call
|
||||
// - capability string
|
||||
func (_e *MockProvider_Expecter) Listen(capability interface{}) *MockProvider_Listen_Call {
|
||||
return &MockProvider_Listen_Call{Call: _e.mock.On("Listen", capability)}
|
||||
}
|
||||
|
||||
func (_c *MockProvider_Listen_Call) Run(run func(capability string)) *MockProvider_Listen_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProvider_Listen_Call) Return(_a0 net.Listener, _a1 error) *MockProvider_Listen_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SessionStatus provides a mock function with given fields:
|
||||
func (_m *MockProvider) SessionStatus() string {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockProvider_SessionStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SessionStatus'
|
||||
type MockProvider_SessionStatus_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SessionStatus is a helper method to define mock.On call
|
||||
func (_e *MockProvider_Expecter) SessionStatus() *MockProvider_SessionStatus_Call {
|
||||
return &MockProvider_SessionStatus_Call{Call: _e.mock.On("SessionStatus")}
|
||||
}
|
||||
|
||||
func (_c *MockProvider_SessionStatus_Call) Run(run func()) *MockProvider_SessionStatus_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProvider_SessionStatus_Call) Return(_a0 string) *MockProvider_SessionStatus_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Start provides a mock function with given fields:
|
||||
func (_m *MockProvider) Start() error {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func() error); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockProvider_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
|
||||
type MockProvider_Start_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Start is a helper method to define mock.On call
|
||||
func (_e *MockProvider_Expecter) Start() *MockProvider_Start_Call {
|
||||
return &MockProvider_Start_Call{Call: _e.mock.On("Start")}
|
||||
}
|
||||
|
||||
func (_c *MockProvider_Start_Call) Run(run func()) *MockProvider_Start_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProvider_Start_Call) Return(_a0 error) *MockProvider_Start_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Stop provides a mock function with given fields:
|
||||
func (_m *MockProvider) Stop() error {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func() error); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockProvider_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop'
|
||||
type MockProvider_Stop_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Stop is a helper method to define mock.On call
|
||||
func (_e *MockProvider_Expecter) Stop() *MockProvider_Stop_Call {
|
||||
return &MockProvider_Stop_Call{Call: _e.mock.On("Stop")}
|
||||
}
|
||||
|
||||
func (_c *MockProvider_Stop_Call) Run(run func()) *MockProvider_Stop_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProvider_Stop_Call) Return(_a0 error) *MockProvider_Stop_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
// UpdateMeta provides a mock function with given fields: _a0
|
||||
func (_m *MockProvider) UpdateMeta(_a0 map[string]string) {
|
||||
_m.Called(_a0)
|
||||
}
|
||||
|
||||
// MockProvider_UpdateMeta_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateMeta'
|
||||
type MockProvider_UpdateMeta_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// UpdateMeta is a helper method to define mock.On call
|
||||
// - _a0 map[string]string
|
||||
func (_e *MockProvider_Expecter) UpdateMeta(_a0 interface{}) *MockProvider_UpdateMeta_Call {
|
||||
return &MockProvider_UpdateMeta_Call{Call: _e.mock.On("UpdateMeta", _a0)}
|
||||
}
|
||||
|
||||
func (_c *MockProvider_UpdateMeta_Call) Run(run func(_a0 map[string]string)) *MockProvider_UpdateMeta_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(map[string]string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProvider_UpdateMeta_Call) Return() *MockProvider_UpdateMeta_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewMockProvider interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewMockProvider creates a new instance of MockProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewMockProvider(t mockConstructorTestingTNewMockProvider) *MockProvider {
|
||||
mock := &MockProvider{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package scada
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/hashicorp/consul/agent/hcp/config"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
libscada "github.com/hashicorp/hcp-scada-provider"
|
||||
"github.com/hashicorp/hcp-scada-provider/capability"
|
||||
"github.com/hashicorp/hcp-sdk-go/resource"
|
||||
)
|
||||
|
||||
// Provider is the interface used in the rest of Consul core when using SCADA, it is aliased here to the same interface
|
||||
// provided by the hcp-scada-provider library. If the interfaces needs to be extended in the future it can be done so
|
||||
// with minimal impact on the rest of the codebase.
|
||||
//
|
||||
//go:generate mockery --name Provider --with-expecter --inpackage
|
||||
type Provider interface {
|
||||
libscada.SCADAProvider
|
||||
}
|
||||
|
||||
const (
|
||||
scadaConsulServiceKey = "consul"
|
||||
)
|
||||
|
||||
func New(cfg config.CloudConfig, logger hclog.Logger) (Provider, error) {
|
||||
resource, err := resource.FromString(cfg.ResourceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse cloud resource_id: %w", err)
|
||||
}
|
||||
|
||||
hcpConfig, err := cfg.HCPConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build HCPConfig: %w", err)
|
||||
}
|
||||
|
||||
pvd, err := libscada.New(&libscada.Config{
|
||||
Service: scadaConsulServiceKey,
|
||||
HCPConfig: hcpConfig,
|
||||
Resource: *resource.Link(),
|
||||
Logger: logger,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pvd, nil
|
||||
}
|
||||
|
||||
// IsCapability takes a net.Addr and returns true if it is a SCADA capability.Addr
|
||||
func IsCapability(a net.Addr) bool {
|
||||
_, ok := a.(*capability.Addr)
|
||||
return ok
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
package hcp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models"
|
||||
"github.com/hashicorp/hcp-sdk-go/resource"
|
||||
)
|
||||
|
||||
type TestEndpoint struct {
|
||||
Methods []string
|
||||
PathSuffix string
|
||||
Handler func(r *http.Request, cluster resource.Resource) (interface{}, error)
|
||||
}
|
||||
|
||||
type MockHCPServer struct {
|
||||
mu sync.Mutex
|
||||
handlers map[string]TestEndpoint
|
||||
|
||||
servers map[string]*gnmmod.HashicorpCloudGlobalNetworkManager20220215Server
|
||||
}
|
||||
|
||||
var basePathRe = regexp.MustCompile("/global-network-manager/[^/]+/organizations/([^/]+)/projects/([^/]+)/clusters/([^/]+)/([^/]+.*)")
|
||||
|
||||
func NewMockHCPServer() *MockHCPServer {
|
||||
s := &MockHCPServer{
|
||||
handlers: make(map[string]TestEndpoint),
|
||||
servers: make(map[string]*gnmmod.HashicorpCloudGlobalNetworkManager20220215Server),
|
||||
}
|
||||
// Define endpoints in this package
|
||||
s.AddEndpoint(TestEndpoint{
|
||||
Methods: []string{"POST"},
|
||||
PathSuffix: "agent/server-state",
|
||||
Handler: s.handleStatus,
|
||||
})
|
||||
s.AddEndpoint(TestEndpoint{
|
||||
Methods: []string{"POST"},
|
||||
PathSuffix: "agent/discover",
|
||||
Handler: s.handleDiscover,
|
||||
})
|
||||
return s
|
||||
}
|
||||
|
||||
// AddEndpoint allows adding additional endpoints from other packages e.g.
|
||||
// bootstrap (which can't be merged into one package due to dependency cycles).
|
||||
// It's not safe to call this concurrently with any other call to AddEndpoint or
|
||||
// ServeHTTP.
|
||||
func (s *MockHCPServer) AddEndpoint(e TestEndpoint) {
|
||||
s.handlers[e.PathSuffix] = e
|
||||
}
|
||||
|
||||
func (s *MockHCPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if r.URL.Path == "/oauth/token" {
|
||||
mockTokenResponse(w)
|
||||
return
|
||||
}
|
||||
|
||||
matches := basePathRe.FindStringSubmatch(r.URL.Path)
|
||||
if matches == nil || len(matches) < 5 {
|
||||
w.WriteHeader(404)
|
||||
log.Printf("ERROR 404: %s %s\n", r.Method, r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
cluster := resource.Resource{
|
||||
ID: matches[3],
|
||||
Type: "cluster",
|
||||
Organization: matches[1],
|
||||
Project: matches[2],
|
||||
}
|
||||
found := false
|
||||
var resp interface{}
|
||||
var err error
|
||||
for _, e := range s.handlers {
|
||||
if e.PathSuffix == matches[4] {
|
||||
found = true
|
||||
if !enforceMethod(w, r, e.Methods) {
|
||||
return
|
||||
}
|
||||
resp, err = e.Handler(r, cluster)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
w.WriteHeader(404)
|
||||
log.Printf("ERROR 404: %s %s\n", r.Method, r.URL.Path)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
errResponse(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
// no response body
|
||||
log.Printf("OK 204: %s %s\n", r.Method, r.URL.Path)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
bs, err := json.MarshalIndent(resp, "", " ")
|
||||
if err != nil {
|
||||
errResponse(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("OK 200: %s %s\n", r.Method, r.URL.Path)
|
||||
w.Header().Set("content-type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(bs)
|
||||
}
|
||||
|
||||
func enforceMethod(w http.ResponseWriter, r *http.Request, methods []string) bool {
|
||||
for _, m := range methods {
|
||||
if strings.EqualFold(r.Method, m) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// No match, sent 4xx
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
log.Printf("ERROR 405: bad method (not in %v): %s %s\n", methods, r.Method, r.URL.Path)
|
||||
return false
|
||||
}
|
||||
|
||||
func mockTokenResponse(w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{access_token: "token", token_type: "Bearer"}`))
|
||||
}
|
||||
|
||||
func (s *MockHCPServer) handleStatus(r *http.Request, cluster resource.Resource) (interface{}, error) {
|
||||
var req gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentPushServerStateRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
status := req.ServerState
|
||||
log.Printf("STATUS UPDATE: server=%s version=%s leader=%v hasLeader=%v healthy=%v tlsCertExpiryDays=%1.0f",
|
||||
status.Name,
|
||||
status.Version,
|
||||
status.Raft.IsLeader,
|
||||
status.Raft.KnownLeader,
|
||||
status.Autopilot.Healthy,
|
||||
time.Until(time.Time(status.TLS.CertExpiry)).Hours()/24,
|
||||
)
|
||||
s.servers[status.Name] = &gnmmod.HashicorpCloudGlobalNetworkManager20220215Server{
|
||||
GossipPort: status.GossipPort,
|
||||
ID: status.ID,
|
||||
LanAddress: status.LanAddress,
|
||||
Name: status.Name,
|
||||
RPCPort: status.RPCPort,
|
||||
}
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
func (s *MockHCPServer) handleDiscover(r *http.Request, cluster resource.Resource) (interface{}, error) {
|
||||
servers := make([]*gnmmod.HashicorpCloudGlobalNetworkManager20220215Server, len(s.servers))
|
||||
for _, server := range s.servers {
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
return gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentDiscoverResponse{Servers: servers}, nil
|
||||
}
|
||||
|
||||
func errResponse(w http.ResponseWriter, err error) {
|
||||
log.Printf("ERROR 500: %s\n", err)
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(fmt.Sprintf(`{"error": %q}`, err.Error())))
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/consul/agent/hcp/bootstrap"
|
||||
)
|
||||
|
||||
var port int
|
||||
|
||||
func main() {
|
||||
flag.IntVar(&port, "port", 9999, "port to listen on")
|
||||
flag.Parse()
|
||||
|
||||
s := hcp.NewMockHCPServer()
|
||||
s.AddEndpoint(bootstrap.TestEndpoint())
|
||||
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
addr := fmt.Sprintf("127.0.0.1:%d", port)
|
||||
srv := http.Server{
|
||||
Addr: addr,
|
||||
Handler: s,
|
||||
}
|
||||
|
||||
log.Printf("Listening on %s\n", addr)
|
||||
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("listen: %s\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-sigs
|
||||
log.Println("Shutting down HTTP server")
|
||||
srv.Close()
|
||||
}
|
|
@ -201,7 +201,7 @@ func makeUpstream(g *structs.GatewayService) structs.Upstream {
|
|||
}
|
||||
|
||||
func (s *handlerIngressGateway) watchIngressLeafCert(ctx context.Context, snap *ConfigSnapshot) error {
|
||||
// Note that we DON'T test for TLS.Enabled because we need a leaf cert for the
|
||||
// Note that we DON'T test for TLS.enabled because we need a leaf cert for the
|
||||
// gateway even without TLS to use as a client cert.
|
||||
if !snap.IngressGateway.GatewayConfigLoaded || !snap.IngressGateway.HostsSet {
|
||||
return nil
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
discoverhcp "github.com/hashicorp/consul/agent/hcp/discover"
|
||||
discover "github.com/hashicorp/go-discover"
|
||||
discoverk8s "github.com/hashicorp/go-discover/provider/k8s"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
|
@ -114,6 +115,7 @@ func newDiscover() (*discover.Discover, error) {
|
|||
providers[k] = v
|
||||
}
|
||||
providers["k8s"] = &discoverk8s.Provider{}
|
||||
providers["hcp"] = &discoverhcp.Provider{}
|
||||
|
||||
return discover.New(
|
||||
discover.WithUserAgent(lib.UserAgent()),
|
||||
|
|
|
@ -12,7 +12,7 @@ func TestAgentRetryNewDiscover(t *testing.T) {
|
|||
d, err := newDiscover()
|
||||
require.NoError(t, err)
|
||||
expected := []string{
|
||||
"aliyun", "aws", "azure", "digitalocean", "gce", "k8s", "linode",
|
||||
"aliyun", "aws", "azure", "digitalocean", "gce", "hcp", "k8s", "linode",
|
||||
"mdns", "os", "packet", "scaleway", "softlayer", "tencentcloud",
|
||||
"triton", "vsphere",
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/armon/go-metrics/prometheus"
|
||||
"github.com/hashicorp/consul/agent/hcp"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
|
@ -153,6 +154,12 @@ func NewBaseDeps(configLoader ConfigLoader, logOut io.Writer) (BaseDeps, error)
|
|||
d.EventPublisher = stream.NewEventPublisher(10 * time.Second)
|
||||
|
||||
d.XDSStreamLimiter = limiter.NewSessionLimiter()
|
||||
if cfg.IsCloudEnabled() {
|
||||
d.HCP, err = hcp.NewDeps(cfg.Cloud, d.Logger)
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
|
|
@ -85,6 +85,9 @@ type TestAgent struct {
|
|||
// non-user settable configurations
|
||||
Overrides string
|
||||
|
||||
// allows the BaseDeps to be modified before starting the embedded agent
|
||||
OverrideDeps func(deps *BaseDeps)
|
||||
|
||||
// Agent is the embedded consul agent.
|
||||
// It is valid after Start().
|
||||
*Agent
|
||||
|
@ -234,6 +237,10 @@ func (a *TestAgent) Start(t *testing.T) error {
|
|||
}
|
||||
a.Config = bd.RuntimeConfig
|
||||
|
||||
if a.OverrideDeps != nil {
|
||||
a.OverrideDeps(&bd)
|
||||
}
|
||||
|
||||
agent, err := New(bd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating agent: %s", err)
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/consul/agent"
|
||||
"github.com/hashicorp/consul/agent/config"
|
||||
hcpbootstrap "github.com/hashicorp/consul/agent/hcp/bootstrap"
|
||||
"github.com/hashicorp/consul/command/cli"
|
||||
"github.com/hashicorp/consul/command/flags"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
|
@ -152,7 +153,7 @@ func (c *cmd) startupJoinWan(agent *agent.Agent, cfg *config.RuntimeConfig) erro
|
|||
func (c *cmd) run(args []string) int {
|
||||
ui := &mcli.PrefixedUi{
|
||||
OutputPrefix: "==> ",
|
||||
InfoPrefix: " ",
|
||||
InfoPrefix: " ", // Note that startupLogger also uses this prefix
|
||||
ErrorPrefix: "==> ",
|
||||
Ui: c.ui,
|
||||
}
|
||||
|
@ -175,6 +176,29 @@ func (c *cmd) run(args []string) int {
|
|||
c.configLoadOpts.DefaultConfig = source
|
||||
return config.Load(c.configLoadOpts)
|
||||
}
|
||||
|
||||
// wait for signal
|
||||
signalCh := make(chan os.Signal, 10)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// startup logger is a shim since we need to be about to log both before and
|
||||
// after logging is setup properly but before agent has started fully. This
|
||||
// takes care of that!
|
||||
suLogger := newStartupLogger()
|
||||
go handleStartupSignals(ctx, cancel, signalCh, suLogger)
|
||||
|
||||
// See if we need to bootstrap config from HCP before we go any further with
|
||||
// agent startup. We override loader with the one returned as it may be
|
||||
// modified to include HCP-provided config.
|
||||
var err error
|
||||
_, loader, err = hcpbootstrap.MaybeBootstrap(ctx, loader, ui)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
bd, err := agent.NewBaseDeps(loader, logGate)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
|
@ -187,6 +211,9 @@ func (c *cmd) run(args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
// Upgrade our startupLogger to use the real logger now we have it
|
||||
suLogger.SetLogger(c.logger)
|
||||
|
||||
config := bd.RuntimeConfig
|
||||
if config.Logging.LogJSON {
|
||||
// Hide all non-error output when JSON logging is enabled.
|
||||
|
@ -229,38 +256,6 @@ func (c *cmd) run(args []string) int {
|
|||
ui.Output("Log data will now stream in as it occurs:\n")
|
||||
logGate.Flush()
|
||||
|
||||
// wait for signal
|
||||
signalCh := make(chan os.Signal, 10)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
for {
|
||||
var sig os.Signal
|
||||
select {
|
||||
case s := <-signalCh:
|
||||
sig = s
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
switch sig {
|
||||
case syscall.SIGPIPE:
|
||||
continue
|
||||
|
||||
case syscall.SIGHUP:
|
||||
err := fmt.Errorf("cannot reload before agent started")
|
||||
c.logger.Error("Caught", "signal", sig, "error", err)
|
||||
|
||||
default:
|
||||
c.logger.Info("Caught", "signal", sig)
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = agent.Start(ctx)
|
||||
signal.Stop(signalCh)
|
||||
cancel()
|
||||
|
@ -362,6 +357,32 @@ func (c *cmd) run(args []string) int {
|
|||
}
|
||||
}
|
||||
|
||||
func handleStartupSignals(ctx context.Context, cancel func(), signalCh chan os.Signal, logger *startupLogger) {
|
||||
for {
|
||||
var sig os.Signal
|
||||
select {
|
||||
case s := <-signalCh:
|
||||
sig = s
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
switch sig {
|
||||
case syscall.SIGPIPE:
|
||||
continue
|
||||
|
||||
case syscall.SIGHUP:
|
||||
err := fmt.Errorf("cannot reload before agent started")
|
||||
logger.Error("Caught", "signal", sig, "error", err)
|
||||
|
||||
default:
|
||||
logger.Info("Caught", "signal", sig)
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cmd) Synopsis() string {
|
||||
return synopsis
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package agent
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
// startupLogger is a shim that allows signal handling (and anything else) to
|
||||
// log to an appropriate output throughout several startup phases. Initially
|
||||
// when bootstrapping from HCP we need to log caught signals direct to the UI
|
||||
// output since logging is not setup yet and won't be if we are interrupted
|
||||
// before we try to start the agent itself. Later, during agent.Start we could
|
||||
// block retrieving auto TLS or auto-config from servers so need to handle
|
||||
// signals, but in this case logging has already started so we should log the
|
||||
// signal event to the logger.
|
||||
type startupLogger struct {
|
||||
mu sync.Mutex
|
||||
logger hclog.Logger
|
||||
}
|
||||
|
||||
func newStartupLogger() *startupLogger {
|
||||
return &startupLogger{
|
||||
// Start off just using defaults for hclog since this is too early to have
|
||||
// parsed logging config even and we just want to get _something_ out to the
|
||||
// user.
|
||||
logger: hclog.New(&hclog.LoggerOptions{
|
||||
Name: "agent.startup",
|
||||
// Nothing else output in UI has a time prefix until logging is properly
|
||||
// setup so use the same prefix as other "Info" lines to make it look less
|
||||
// strange. Note one less space than in PrefixedUI since hclog puts a
|
||||
// space between the time prefix and log line already.
|
||||
TimeFormat: " ",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *startupLogger) SetLogger(logger hclog.Logger) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
l.logger = logger
|
||||
}
|
||||
|
||||
func (l *startupLogger) Info(msg string, args ...interface{}) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
l.logger.Info(msg, args...)
|
||||
}
|
||||
|
||||
func (l *startupLogger) Warn(msg string, args ...interface{}) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
l.logger.Warn(msg, args...)
|
||||
}
|
||||
|
||||
func (l *startupLogger) Error(msg string, args ...interface{}) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
l.logger.Error(msg, args...)
|
||||
}
|
47
go.mod
47
go.mod
|
@ -21,6 +21,8 @@ require (
|
|||
github.com/docker/go-connections v0.3.0
|
||||
github.com/envoyproxy/go-control-plane v0.10.1
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/go-openapi/runtime v0.19.24
|
||||
github.com/go-openapi/strfmt v0.20.0
|
||||
github.com/golang/protobuf v1.5.0
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/google/gofuzz v1.2.0
|
||||
|
@ -37,7 +39,7 @@ require (
|
|||
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||
github.com/hashicorp/go-connlimit v0.3.0
|
||||
github.com/hashicorp/go-discover v0.0.0-20220411141802-20db45f7f0f9
|
||||
github.com/hashicorp/go-hclog v0.14.1
|
||||
github.com/hashicorp/go-hclog v1.2.1
|
||||
github.com/hashicorp/go-memdb v1.3.2
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-raftchunking v0.6.2
|
||||
|
@ -47,6 +49,8 @@ require (
|
|||
github.com/hashicorp/go-version v1.2.1
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/hashicorp/hcp-scada-provider v0.1.0
|
||||
github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc
|
||||
github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038
|
||||
github.com/hashicorp/memberlist v0.4.0
|
||||
github.com/hashicorp/raft v1.3.9
|
||||
|
@ -55,7 +59,7 @@ require (
|
|||
github.com/hashicorp/serf v0.10.0
|
||||
github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086
|
||||
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267
|
||||
github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493
|
||||
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87
|
||||
github.com/imdario/mergo v0.3.13
|
||||
github.com/kr/text v0.2.0
|
||||
github.com/miekg/dns v1.1.41
|
||||
|
@ -78,11 +82,11 @@ require (
|
|||
go.uber.org/goleak v1.1.10
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
||||
google.golang.org/genproto v0.0.0-20200623002339-fbb79eadd5eb
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987
|
||||
google.golang.org/grpc v1.37.1
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/square/go-jose.v2 v2.5.1
|
||||
|
@ -93,7 +97,7 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.59.0 // indirect
|
||||
cloud.google.com/go v0.65.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v44.0.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
|
||||
|
@ -107,6 +111,9 @@ require (
|
|||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
|
||||
github.com/Microsoft/go-winio v0.4.3 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/boltdb/bolt v1.3.1 // indirect
|
||||
|
@ -120,10 +127,20 @@ require (
|
|||
github.com/digitalocean/godo v1.10.0 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
|
||||
github.com/frankban/quicktest v1.11.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/analysis v0.20.0 // indirect
|
||||
github.com/go-openapi/errors v0.20.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/loads v0.20.2 // indirect
|
||||
github.com/go-openapi/spec v0.20.3 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-openapi/validate v0.20.2 // indirect
|
||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
|
@ -134,21 +151,25 @@ require (
|
|||
github.com/gophercloud/gophercloud v0.1.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.5 // indirect
|
||||
github.com/hashicorp/go-msgpack v1.1.5 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.6.7 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/mdns v1.0.4 // indirect
|
||||
github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 // indirect
|
||||
github.com/hashicorp/raft-boltdb v0.0.0-20211202195631-7d34b9fb3f42 // indirect
|
||||
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect
|
||||
github.com/json-iterator/go v1.1.9 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/linode/linodego v0.7.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
|
@ -166,6 +187,7 @@ require (
|
|||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.4.0 // indirect
|
||||
|
@ -175,17 +197,18 @@ require (
|
|||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect
|
||||
github.com/vmware/govmomi v0.18.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.opencensus.io v0.22.3 // indirect
|
||||
go.mongodb.org/mongo-driver v1.4.6 // indirect
|
||||
go.opencensus.io v0.22.4 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/tools v0.1.0 // indirect
|
||||
google.golang.org/api v0.28.0 // indirect
|
||||
google.golang.org/api v0.30.0 // indirect
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/resty.v1 v1.12.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog v1.0.0 // indirect
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 // indirect
|
||||
|
|
292
go.sum
292
go.sum
|
@ -11,8 +11,9 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6
|
|||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.59.0 h1:BM3svUDU3itpc2m5cu5wCyThIYNDlFlts9GASw31GW8=
|
||||
cloud.google.com/go v0.59.0/go.mod h1:qJxNOVCRTxHfwLhvDxxSI9vQc1zI59b9pEglp1Iv60E=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
|
@ -29,6 +30,7 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy
|
|||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-sdk-for-go v44.0.0+incompatible h1:e82Yv2HNpS0kuyeCrV29OPKvEiqfs2/uJHic3/3iKdg=
|
||||
github.com/Azure/azure-sdk-for-go v44.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
|
@ -77,13 +79,20 @@ github.com/NYTimes/gziphandler v1.0.1 h1:iLrQrdwjDd52kHDA5op2UBJFjmOb9g+7scBan4R
|
|||
github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=
|
||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
|
@ -97,8 +106,15 @@ github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb
|
|||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
||||
github.com/aws/aws-sdk-go v1.42.34 h1:fqGAiKmCSRY1rEa4G9VqgkKKbNmLKYq5dKmLtQkvYi8=
|
||||
github.com/aws/aws-sdk-go v1.42.34/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
|
@ -155,6 +171,8 @@ github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
|
|||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/go-connections v0.3.0 h1:3lOnM9cSzgGwx8VfK/NGOW5fLQ0GjIlCkaktF+n1M6o=
|
||||
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
|
@ -170,8 +188,9 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrp
|
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
|
@ -182,6 +201,8 @@ github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWp
|
|||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
|
@ -194,14 +215,132 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
|||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
||||
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
||||
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
|
||||
github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ=
|
||||
github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk=
|
||||
github.com/go-openapi/analysis v0.20.0 h1:UN09o0kNhleunxW7LR+KnltD0YrJ8FF03pSqvAN3Vro=
|
||||
github.com/go-openapi/analysis v0.20.0/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxlOmQr9FBZk+Og=
|
||||
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.20.1 h1:j23mMDtRxMwIobkpId7sWh7Ddcx4ivaoqUbfXx5P+a8=
|
||||
github.com/go-openapi/errors v0.20.1/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
|
||||
github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=
|
||||
github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY=
|
||||
github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc=
|
||||
github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc=
|
||||
github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4=
|
||||
github.com/go-openapi/loads v0.20.2 h1:z5p5Xf5wujMxS1y8aP+vxwW5qYT2zdJBbXKmQUG3lcc=
|
||||
github.com/go-openapi/loads v0.20.2/go.mod h1:hTVUotJ+UonAMMZsvakEgmWKgtulweO9vYP2bQYKA/o=
|
||||
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
|
||||
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
|
||||
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
|
||||
github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo=
|
||||
github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98=
|
||||
github.com/go-openapi/runtime v0.19.24 h1:TqagMVlRAOTwllE/7hNKx6rQ10O6T8ZzeJdMjSTKaD4=
|
||||
github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
|
||||
github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
|
||||
github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/spec v0.20.1/go.mod h1:93x7oh+d+FQsmsieroS4cmR3u0p/ywH649a3qwC9OsQ=
|
||||
github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
|
||||
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
|
||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
||||
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||
github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||
github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||
github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc=
|
||||
github.com/go-openapi/strfmt v0.20.0 h1:l2omNtmNbMc39IGptl9BuXBEKcZfS8zjrTsPKTiJiDM=
|
||||
github.com/go-openapi/strfmt v0.20.0/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
|
||||
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
|
||||
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
|
||||
github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=
|
||||
github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8=
|
||||
github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4=
|
||||
github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI=
|
||||
github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0=
|
||||
github.com/go-openapi/validate v0.20.2 h1:AhqDegYV3J3iQkMPJSXkvzymHKMTw0BST3RK3hTT4ts=
|
||||
github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZIVCbJBpTUoY0=
|
||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE=
|
||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
|
||||
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
||||
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
|
||||
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
|
||||
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
||||
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
||||
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
|
||||
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
|
||||
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
|
||||
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
|
||||
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
|
||||
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
|
||||
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
|
||||
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
|
||||
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
|
||||
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
||||
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
||||
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
||||
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
||||
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
|
||||
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
|
||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
|
@ -220,6 +359,7 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
|
|||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -248,6 +388,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
|
@ -262,19 +403,22 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
|||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22 h1:ub2sxhs2A0HRa2dWHavvmWxiVGXNfE9wI+gcTMwED8A=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 h1:AtvtonGEH/fZK0XPNNBdB6swgy7Iudfx88wzyIpwqJ8=
|
||||
github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2/go.mod h1:DavVbd41y+b7ukKDmlnPR4nGYmkWXR6vHUkjQNiHPBs=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
|
@ -313,8 +457,9 @@ github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9
|
|||
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
|
||||
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw=
|
||||
github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
|
@ -322,8 +467,9 @@ github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jU
|
|||
github.com/hashicorp/go-memdb v1.3.2 h1:RBKHOsnSszpU6vxq80LzC2BaQjuuvoyaQbkLTf7V7g8=
|
||||
github.com/hashicorp/go-memdb v1.3.2/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs=
|
||||
github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
|
@ -355,6 +501,10 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l
|
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/hcp-scada-provider v0.1.0 h1:FSjTw7EBl6GJFv5533harm1vw15OaEYodNGHde908MI=
|
||||
github.com/hashicorp/hcp-scada-provider v0.1.0/go.mod h1:8Pp3pBLzZ9DL56OHSbf55qhh+TpvmXBuR5cJx9jcdcA=
|
||||
github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc h1:on26TCKYnX7JzZCtwkR/LWHSqMu40PoZ6h/0e6Pq8ug=
|
||||
github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc/go.mod h1:/9UoDY2FYYA8lFaKBb2HmM/jKYZGANmf65q9QRc/cVw=
|
||||
github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 h1:n9J0rwVWXDpNd5iZnwY7w4WZyq53/rROeI7OVvLW8Ok=
|
||||
github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
|
@ -365,6 +515,8 @@ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
|
|||
github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/memberlist v0.4.0 h1:k3uda5gZcltmafuFF+UFqNEl5PrH+yPZ4zkjp1f/H/8=
|
||||
github.com/hashicorp/memberlist v0.4.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
|
||||
github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 h1:lc3c72qGlIMDqQpQH82Y4vaglRMMFdJbziYWriR4UcE=
|
||||
github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q=
|
||||
github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM=
|
||||
github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
|
||||
github.com/hashicorp/raft v1.2.0/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
|
||||
|
@ -388,8 +540,8 @@ github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267/go.mod h1:W
|
|||
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 h1:O/pT5C1Q3mVXMyuqg7yuAWUg/jMZR1/0QTzTRdNR6Uw=
|
||||
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 h1:brI5vBRUlAlM34VFmnLPwjnCL/FxAJp9XvOdX6Zt+XE=
|
||||
github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I=
|
||||
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
@ -407,7 +559,10 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
|
|||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA=
|
||||
github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f h1:ENpDacvnr8faw5ugQmEF1QYk+f/Y9lXFvuYmRxykago=
|
||||
github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk=
|
||||
|
@ -418,10 +573,13 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
|
||||
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
@ -431,6 +589,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
|||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
|
@ -441,16 +600,28 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
|
|||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
|
@ -461,6 +632,8 @@ github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJys
|
|||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
|
@ -477,6 +650,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/z
|
|||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
|
||||
|
@ -490,11 +665,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s=
|
||||
github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
|
@ -510,7 +688,10 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw
|
|||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
|
||||
|
@ -558,6 +739,8 @@ github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOe
|
|||
github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
|
@ -572,13 +755,18 @@ github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627/go.mod h1:7zjs06q
|
|||
github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5/go.mod h1:BeybITEsBEg6qbIiqJ6/Bqeq25bCLbL7YFmpaFfJDuM=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d h1:bVQRCxQvfjNUeRqaY/uT0tFuvuFY0ulgnczuR684Xic=
|
||||
github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
@ -587,6 +775,7 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
|
|||
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
|
@ -597,6 +786,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
|
|||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
|
@ -606,10 +796,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v1.0.162 h1:8fDzz4GuVg4skjY2B0nMN7h6uN61EDVkuLyI2+qGHhI=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v1.0.162/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||
|
@ -619,23 +812,36 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z
|
|||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo=
|
||||
github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
|
||||
go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
|
||||
go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.mongodb.org/mongo-driver v1.4.6 h1:rh7GdYmDrb8AQSkF8yteAus8qYOgOASWDOv1BWqBXkU=
|
||||
go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
|
@ -648,10 +854,14 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -694,6 +904,7 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -701,6 +912,7 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -708,7 +920,9 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
|
|||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
@ -723,8 +937,14 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||
|
@ -733,15 +953,18 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
|
|||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 h1:Mj83v+wSRNEar42a/MQgxk9X42TdEmrOl9i+y8WbxLo=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -759,14 +982,18 @@ golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -791,6 +1018,7 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -799,8 +1027,10 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -812,6 +1042,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -825,14 +1057,22 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
|
@ -862,8 +1102,11 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc
|
|||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
|
@ -884,8 +1127,10 @@ google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
|
|||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0 h1:jMF5hhVfMkTZwHW1SDpKq5CkgWLXOb31Foaca9Zr3oM=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -919,8 +1164,11 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG
|
|||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200623002339-fbb79eadd5eb h1:PUcq6RTy8Gp9xukBme8m2+2Z8pQCmJ7TbPpQd6xNDvk=
|
||||
google.golang.org/genproto v0.0.0-20200623002339-fbb79eadd5eb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
|
@ -934,6 +1182,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
|||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.1 h1:ARnQJNWxGyYJpdf/JXscNlQr/uv607ZPU9Z7ogHi+iI=
|
||||
|
@ -955,8 +1205,9 @@ gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4
|
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
|
@ -973,9 +1224,14 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -108,3 +108,10 @@ func (w *Waiter) Wait(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NextWait returns the period the next call to Wait with block for assuming
|
||||
// it's context is not cancelled. It's useful for informing a user how long
|
||||
// it will be before the next attempt is made.
|
||||
func (w *Waiter) NextWait() time.Duration {
|
||||
return w.delay()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue