From b305a73c34ce0277b9acb34ce23ed41f33a65647 Mon Sep 17 00:00:00 2001 From: Andrew Gouin Date: Tue, 24 Oct 2023 08:50:08 -0600 Subject: [PATCH] scheduled upgrades (#373) * first stab at scheduled upgrades * lint * add service account and cluster role/binding reconciliation * roles for manager * skip version check if versions are not populated in spec * matching labels * lint * switch to role * scheme * fix scheme, reconcile heights * use separate status map * change annotation so that pod is restarted * use new height map * height should be commit + 1 * restart pods with version mismatch immediately * harden rollout * version check on terminate in sidecar * ticker for height check * Make setting halt height configurable * remove unused func * Modify reconcile pods to prioritize upgrades * Add tests for rbac * wait until after first interval to lock db * harden pod control and test * dry up test --- Dockerfile | 1 + api/v1/cosmosfullnode_types.go | 29 ++ api/v1/zz_generated.deepcopy.go | 32 ++ healtcheck_cmd.go => cmd/healtcheck.go | 6 +- logger.go => cmd/logger.go | 4 +- cmd/versioncheck.go | 208 ++++++++++ .../cosmos.strange.love_cosmosfullnodes.yaml | 39 ++ config/manager/manager.yaml | 1 + config/rbac/role.yaml | 16 + controllers/cosmosfullnode_controller.go | 71 +++- go.mod | 82 ++-- go.sum | 299 +++++++++++---- internal/cosmos/cache_controller.go | 5 + internal/cosmos/status_collection.go | 44 +++ internal/fullnode/build_pods.go | 20 +- internal/fullnode/configmap_builder.go | 24 +- internal/fullnode/mock_test.go | 7 + internal/fullnode/pod_builder.go | 84 ++++- internal/fullnode/pod_builder_test.go | 15 +- internal/fullnode/pod_control.go | 85 ++++- internal/fullnode/pod_control_test.go | 355 +++++++++++++++++- internal/fullnode/rbac_builder.go | 120 ++++++ internal/fullnode/rbac_builder_test.go | 102 +++++ internal/fullnode/role_binding_control.go | 64 ++++ .../fullnode/role_binding_control_test.go | 70 ++++ internal/fullnode/role_control.go | 64 ++++ internal/fullnode/role_control_test.go | 70 ++++ internal/fullnode/service_account_control.go | 64 ++++ .../fullnode/service_account_control_test.go | 70 ++++ local.Dockerfile | 1 + main.go | 6 +- 31 files changed, 1885 insertions(+), 173 deletions(-) rename healtcheck_cmd.go => cmd/healtcheck.go (94%) rename logger.go => cmd/logger.go (89%) create mode 100644 cmd/versioncheck.go create mode 100644 internal/fullnode/rbac_builder.go create mode 100644 internal/fullnode/rbac_builder_test.go create mode 100644 internal/fullnode/role_binding_control.go create mode 100644 internal/fullnode/role_binding_control_test.go create mode 100644 internal/fullnode/role_control.go create mode 100644 internal/fullnode/role_control_test.go create mode 100644 internal/fullnode/service_account_control.go create mode 100644 internal/fullnode/service_account_control_test.go diff --git a/Dockerfile b/Dockerfile index f03e29bc..7ab9d030 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,7 @@ RUN go mod download # Copy the go source COPY *.go . COPY api/ api/ +COPY cmd/ cmd/ COPY controllers/ controllers/ COPY internal/ internal/ diff --git a/api/v1/cosmosfullnode_types.go b/api/v1/cosmosfullnode_types.go index 9c04a0ff..d536390a 100644 --- a/api/v1/cosmosfullnode_types.go +++ b/api/v1/cosmosfullnode_types.go @@ -139,6 +139,10 @@ type FullNodeStatus struct { // Current sync information. Collected every 60s. // +optional SyncInfo *SyncInfoStatus `json:"syncInfo,omitempty"` + + // Latest Height information. collected when node starts up and when RPC is successfully queried. + // +optional + Height map[string]uint64 `json:"height,omitempty"` } type SyncInfoStatus struct { @@ -524,6 +528,31 @@ type ChainSpec struct { // +kubebuilder:validation:Minimum:=0 // +optional PrivvalSleepSeconds *int32 `json:"privvalSleepSeconds"` + + // DatabaseBackend must match in order to detect the block height + // of the chain prior to starting in order to pick the correct image version. + // options: goleveldb, rocksdb, pebbledb + // Defaults to goleveldb. + // +optional + DatabaseBackend *string `json:"databaseBackend"` + + // Versions of the chain and which height they should be applied. + // When provided, the operator will automatically upgrade the chain as it reaches the specified heights. + // If not provided, the operator will not upgrade the chain, and will use the image specified in the pod spec. + // +optional + Versions []ChainVersion `json:"versions"` +} + +type ChainVersion struct { + // The block height when this version should be applied. + UpgradeHeight uint64 `json:"height"` + + // The docker image for this version in "repository:tag" format. E.g. busybox:latest. + Image string `json:"image"` + + // Determines if the node should forcefully halt at the upgrade height. + // +optional + SetHaltHeight bool `json:"setHaltHeight,omitempty"` } // CometConfig configures the config.toml. diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 4a0a7676..b528590a 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -99,6 +99,16 @@ func (in *ChainSpec) DeepCopyInto(out *ChainSpec) { *out = new(int32) **out = **in } + if in.DatabaseBackend != nil { + in, out := &in.DatabaseBackend, &out.DatabaseBackend + *out = new(string) + **out = **in + } + if in.Versions != nil { + in, out := &in.Versions, &out.Versions + *out = make([]ChainVersion, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChainSpec. @@ -111,6 +121,21 @@ func (in *ChainSpec) DeepCopy() *ChainSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChainVersion) DeepCopyInto(out *ChainVersion) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChainVersion. +func (in *ChainVersion) DeepCopy() *ChainVersion { + if in == nil { + return nil + } + out := new(ChainVersion) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CometConfig) DeepCopyInto(out *CometConfig) { *out = *in @@ -298,6 +323,13 @@ func (in *FullNodeStatus) DeepCopyInto(out *FullNodeStatus) { *out = new(SyncInfoStatus) (*in).DeepCopyInto(*out) } + if in.Height != nil { + in, out := &in.Height, &out.Height + *out = make(map[string]uint64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FullNodeStatus. diff --git a/healtcheck_cmd.go b/cmd/healtcheck.go similarity index 94% rename from healtcheck_cmd.go rename to cmd/healtcheck.go index 5306327f..d2f2b9aa 100644 --- a/healtcheck_cmd.go +++ b/cmd/healtcheck.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "context" @@ -14,7 +14,7 @@ import ( "golang.org/x/sync/errgroup" ) -func healthcheckCmd() *cobra.Command { +func HealthCheckCmd() *cobra.Command { hc := &cobra.Command{ Short: "Start health check probe", Use: "healthcheck", @@ -43,7 +43,7 @@ func startHealthCheckServer(cmd *cobra.Command, args []string) error { httpClient = &http.Client{Timeout: 30 * time.Second} cometClient = cosmos.NewCometClient(httpClient) - zlog = zapLogger("info", viper.GetString("log-format")) + zlog = ZapLogger("info", viper.GetString("log-format")) logger = zapr.NewLogger(zlog) ) defer func() { _ = zlog.Sync() }() diff --git a/logger.go b/cmd/logger.go similarity index 89% rename from logger.go rename to cmd/logger.go index 58134889..ed849e37 100644 --- a/logger.go +++ b/cmd/logger.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "os" @@ -8,7 +8,7 @@ import ( "go.uber.org/zap/zapcore" ) -func zapLogger(level, format string) *zap.Logger { +func ZapLogger(level, format string) *zap.Logger { config := zap.NewProductionEncoderConfig() config.EncodeTime = func(ts time.Time, encoder zapcore.PrimitiveArrayEncoder) { encoder.AppendString(ts.UTC().Format(time.RFC3339)) diff --git a/cmd/versioncheck.go b/cmd/versioncheck.go new file mode 100644 index 00000000..eba06f5a --- /dev/null +++ b/cmd/versioncheck.go @@ -0,0 +1,208 @@ +/* +Copyright © 2023 Strangelove Crypto, Inc. +*/ +package cmd + +import ( + "context" + "fmt" + "io" + "os" + "time" + + "cosmossdk.io/log" + "cosmossdk.io/store/rootmulti" + dbm "github.com/cosmos/cosmos-db" + "github.com/spf13/cobra" + cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + namespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" + + flagBackend = "backend" + flagDaemon = "daemon" + + tickTime = 30 * time.Second +) + +// VersionCheckCmd gets the height of this node and updates the status of the crd. +// It panics if the wrong image is specified for the pod for the height, +// restarting the pod so that the correct image is used from the patched height. +// this command is intended to be run as an init container. +func VersionCheckCmd(scheme *runtime.Scheme) *cobra.Command { + cmd := &cobra.Command{ + Use: "versioncheck", + Short: "Confirm correct image used for current node height", + Long: `Open the Cosmos SDK chain database, get the height, update the crd status with the height, then check the image for the height and panic if it is incorrect.`, + Run: func(cmd *cobra.Command, args []string) { + dataDir := os.Getenv("DATA_DIR") + backend, _ := cmd.Flags().GetString(flagBackend) + daemon, _ := cmd.Flags().GetBool(flagDaemon) + + nsbz, err := os.ReadFile(namespaceFile) + if err != nil { + panic(fmt.Errorf("failed to read namespace from service account: %w", err)) + } + ns := string(nsbz) + + config, err := rest.InClusterConfig() + if err != nil { + panic(fmt.Errorf("failed to get in cluster config: %w", err)) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + panic(fmt.Errorf("failed to create kube clientset: %w", err)) + } + + ctx := cmd.Context() + + thisPod, err := clientset.CoreV1().Pods(ns).Get(ctx, os.Getenv("HOSTNAME"), metav1.GetOptions{}) + if err != nil { + panic(fmt.Errorf("failed to get this pod: %w", err)) + } + + cosmosFullNodeName := thisPod.Labels["app.kubernetes.io/name"] + + kClient, err := client.New(config, client.Options{ + Scheme: scheme, + }) + if err != nil { + panic(fmt.Errorf("failed to create kube client: %w", err)) + } + + namespacedName := types.NamespacedName{ + Namespace: ns, + Name: cosmosFullNodeName, + } + + crd := new(cosmosv1.CosmosFullNode) + if err = kClient.Get(ctx, namespacedName, crd); err != nil { + panic(fmt.Errorf("failed to get crd: %w", err)) + } + + if len(crd.Spec.ChainSpec.Versions) == 0 { + fmt.Fprintln(cmd.OutOrStdout(), "No versions specified, skipping version check") + return + } + + s, err := os.Stat(dataDir) + if err != nil { + panic(fmt.Errorf("failed to stat %s: %w", dataDir, err)) + } + + if !s.IsDir() { + panic(fmt.Errorf("%s is not a directory", dataDir)) + } + + if daemon { + ticker := time.NewTicker(tickTime) + defer ticker.Stop() + for { + select { + case <-cmd.Context().Done(): + return + case <-ticker.C: + if err := checkVersion(cmd.Context(), nil, kClient, namespacedName, thisPod, dataDir, backend, cmd.OutOrStdout()); err != nil { + panic(err) + } + ticker.Reset(tickTime) + } + } + } + if err := checkVersion(cmd.Context(), crd, kClient, namespacedName, thisPod, dataDir, backend, cmd.OutOrStdout()); err != nil { + panic(err) + } + }, + } + + cmd.Flags().StringP(flagBackend, "b", "goleveldb", "Database backend") + cmd.Flags().BoolP(flagDaemon, "d", false, "Run as daemon") + + return cmd +} + +func checkVersion( + ctx context.Context, + crd *cosmosv1.CosmosFullNode, + kClient client.Client, + namespacedName types.NamespacedName, + thisPod *corev1.Pod, + dataDir string, + backend string, + writer io.Writer, +) error { + db, err := dbm.NewDB("application", getBackend(backend), dataDir) + if err != nil { + if crd == nil { + fmt.Fprintf(writer, "Failed to open db: %s. The node is likely running.\n", err) + // This is okay, we will read it later if the node shuts down. + return nil + } else { + return fmt.Errorf("failed to open db: %w", err) + } + } + store := rootmulti.NewStore(db, log.NewNopLogger(), nil) + + height := store.LatestVersion() + 1 + db.Close() + + if crd == nil { + crd = new(cosmosv1.CosmosFullNode) + if err := kClient.Get(ctx, namespacedName, crd); err != nil { + return fmt.Errorf("failed to get crd: %w", err) + } + } + + if crd.Status.Height == nil { + crd.Status.Height = make(map[string]uint64) + } + + crd.Status.Height[thisPod.Name] = uint64(height) + + if err := kClient.Status().Update( + ctx, crd, + ); err != nil { + return fmt.Errorf("failed to patch status: %w", err) + } + + var image string + for _, v := range crd.Spec.ChainSpec.Versions { + if uint64(height) < v.UpgradeHeight { + break + } + image = v.Image + } + + thisPodImage := thisPod.Spec.Containers[0].Image + if thisPodImage != image { + return fmt.Errorf("image mismatch for height %d: %s != %s", height, thisPodImage, image) + } + + fmt.Fprintf(writer, "Verified correct image for height %d: %s\n", height, image) + + return nil +} + +func getBackend(backend string) dbm.BackendType { + switch backend { + case "goleveldb": + return dbm.GoLevelDBBackend + case "memdb": + return dbm.MemDBBackend + case "rocksdb": + return dbm.RocksDBBackend + case "pebbledb": + return dbm.PebbleDBBackend + default: + panic(fmt.Errorf("unknown backend %s", backend)) + } +} diff --git a/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml b/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml index ce869fa6..1b340d34 100644 --- a/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml +++ b/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml @@ -220,6 +220,12 @@ spec: limits. type: string type: object + databaseBackend: + description: 'DatabaseBackend must match in order to detect the + block height of the chain prior to starting in order to pick + the correct image version. options: goleveldb, rocksdb, pebbledb + Defaults to goleveldb.' + type: string genesisScript: description: 'Specify shell (sh) script commands to properly download and save the genesis file. Prefer GenesisURL if the file is @@ -310,6 +316,32 @@ spec: if the snapshot archive is unconventional or requires special handling.' type: string + versions: + description: Versions of the chain and which height they should + be applied. When provided, the operator will automatically upgrade + the chain as it reaches the specified heights. If not provided, + the operator will not upgrade the chain, and will use the image + specified in the pod spec. + items: + properties: + height: + description: The block height when this version should be + applied. + format: int64 + type: integer + image: + description: The docker image for this version in "repository:tag" + format. E.g. busybox:latest. + type: string + setHaltHeight: + description: Determines if the node should forcefully halt + at the upgrade height. + type: boolean + required: + - height + - image + type: object + type: array required: - app - binary @@ -5909,6 +5941,13 @@ spec: status: description: FullNodeStatus defines the observed state of CosmosFullNode properties: + height: + additionalProperties: + format: int64 + type: integer + description: Latest Height information. collected when node starts + up and when RPC is successfully queried. + type: object observedGeneration: description: The most recent generation observed by the controller. format: int64 diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 1216d9a6..16811868 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -31,6 +31,7 @@ spec: containers: - command: - /manager + imagePullPolicy: Always args: - --leader-elect image: controller:latest diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 6254b8be..d114ff54 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -11,6 +11,7 @@ rules: - configmaps - persistentvolumeclaims - pods + - serviceaccounts - services verbs: - create @@ -144,6 +145,21 @@ rules: - get - patch - update +- apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + - roles + verbs: + - bind + - create + - delete + - escalate + - get + - list + - patch + - update + - watch - apiGroups: - snapshot.storage.k8s.io resources: diff --git a/controllers/cosmosfullnode_controller.go b/controllers/cosmosfullnode_controller.go index b80bb392..221cecfe 100644 --- a/controllers/cosmosfullnode_controller.go +++ b/controllers/cosmosfullnode_controller.go @@ -43,15 +43,18 @@ const controllerOwnerField = ".metadata.controller" type CosmosFullNodeReconciler struct { client.Client - cacheController *cosmos.CacheController - configMapControl fullnode.ConfigMapControl - nodeKeyControl fullnode.NodeKeyControl - peerCollector *fullnode.PeerCollector - podControl fullnode.PodControl - pvcControl fullnode.PVCControl - recorder record.EventRecorder - serviceControl fullnode.ServiceControl - statusClient *fullnode.StatusClient + cacheController *cosmos.CacheController + configMapControl fullnode.ConfigMapControl + nodeKeyControl fullnode.NodeKeyControl + peerCollector *fullnode.PeerCollector + podControl fullnode.PodControl + pvcControl fullnode.PVCControl + recorder record.EventRecorder + serviceControl fullnode.ServiceControl + statusClient *fullnode.StatusClient + serviceAccountControl fullnode.ServiceAccountControl + clusterRoleControl fullnode.RoleControl + clusterRoleBindingControl fullnode.RoleBindingControl } // NewFullNode returns a valid CosmosFullNode controller. @@ -64,15 +67,18 @@ func NewFullNode( return &CosmosFullNodeReconciler{ Client: client, - cacheController: cacheController, - configMapControl: fullnode.NewConfigMapControl(client), - nodeKeyControl: fullnode.NewNodeKeyControl(client), - peerCollector: fullnode.NewPeerCollector(client), - podControl: fullnode.NewPodControl(client, cacheController), - pvcControl: fullnode.NewPVCControl(client), - recorder: recorder, - serviceControl: fullnode.NewServiceControl(client), - statusClient: statusClient, + cacheController: cacheController, + configMapControl: fullnode.NewConfigMapControl(client), + nodeKeyControl: fullnode.NewNodeKeyControl(client), + peerCollector: fullnode.NewPeerCollector(client), + podControl: fullnode.NewPodControl(client, cacheController), + pvcControl: fullnode.NewPVCControl(client), + recorder: recorder, + serviceControl: fullnode.NewServiceControl(client), + statusClient: statusClient, + serviceAccountControl: fullnode.NewServiceAccountControl(client), + clusterRoleControl: fullnode.NewRoleControl(client), + clusterRoleBindingControl: fullnode.NewRoleBindingControl(client), } } @@ -85,7 +91,8 @@ var ( //+kubebuilder:rbac:groups=cosmos.strange.love,resources=cosmosfullnodes/status,verbs=get;update;patch //+kubebuilder:rbac:groups=cosmos.strange.love,resources=cosmosfullnodes/finalizers,verbs=update // Generate RBAC roles to watch and update resources. IMPORTANT!!!! All resource names must be lowercase or cluster role will not work. -//+kubebuilder:rbac:groups="",resources=pods;persistentvolumeclaims;services;configmaps,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",resources=pods;persistentvolumeclaims;services;serviceaccounts;configmaps,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=roles;rolebindings,verbs=get;list;watch;create;update;patch;delete;bind;escalate //+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch //+kubebuilder:rbac:groups="",resources=events,verbs=create;update;patch @@ -143,6 +150,24 @@ func (r *CosmosFullNodeReconciler) Reconcile(ctx context.Context, req ctrl.Reque errs.Append(err) } + // Reconcile service accounts. + err = r.serviceAccountControl.Reconcile(ctx, reporter, crd) + if err != nil { + errs.Append(err) + } + + // Reconcile cluster roles. + err = r.clusterRoleControl.Reconcile(ctx, reporter, crd) + if err != nil { + errs.Append(err) + } + + // Reconcile cluster role bindings. + err = r.clusterRoleBindingControl.Reconcile(ctx, reporter, crd) + if err != nil { + errs.Append(err) + } + // Reconcile pods. podRequeue, err := r.podControl.Reconcile(ctx, reporter, crd, configCksums) if err != nil { @@ -202,6 +227,14 @@ func (r *CosmosFullNodeReconciler) updateStatus(ctx context.Context, crd *cosmos status.StatusMessage = crd.Status.StatusMessage status.Peers = crd.Status.Peers status.SyncInfo = &consensus + for _, v := range consensus.Pods { + if v.Height != nil && *v.Height > 0 { + if status.Height == nil { + status.Height = make(map[string]uint64) + } + status.Height[v.Pod] = *v.Height + } + } }); err != nil { log.FromContext(ctx).Error(err, "Failed to patch status") } diff --git a/go.mod b/go.mod index 301051ba..0fdf743e 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,11 @@ module github.com/strangelove-ventures/cosmos-operator go 1.20 require ( + cosmossdk.io/log v1.2.1 + cosmossdk.io/store v1.0.0-rc.0 github.com/BurntSushi/toml v1.3.2 - github.com/cometbft/cometbft v0.37.2 + github.com/cometbft/cometbft v0.38.0-rc3 + github.com/cosmos/cosmos-db v1.0.0 github.com/go-logr/logr v1.2.4 github.com/go-logr/zapr v1.2.4 github.com/kubernetes-csi/external-snapshotter/client/v6 v6.1.0 @@ -17,8 +20,9 @@ require ( github.com/stretchr/testify v1.8.4 go.uber.org/goleak v1.2.1 go.uber.org/zap v1.26.0 - golang.org/x/exp v0.0.0-20220921164117-439092de6870 + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 golang.org/x/sync v0.3.0 + gopkg.in/inf.v0 v0.9.1 k8s.io/api v0.25.5 k8s.io/apimachinery v0.25.5 k8s.io/client-go v0.25.5 @@ -26,80 +30,116 @@ require ( ) require ( - cloud.google.com/go/compute v1.19.0 // indirect + cloud.google.com/go/compute v1.19.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect + cosmossdk.io/errors v1.0.0 // indirect + cosmossdk.io/math v1.1.2 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.27 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/DataDog/zstd v1.5.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cosmos/gogoproto v1.4.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cockroachdb/errors v1.10.0 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/cometbft/cometbft-db v0.7.0 // indirect + github.com/cosmos/gogoproto v1.4.11 // indirect + github.com/cosmos/iavl v1.0.0-rc.1 // indirect + github.com/cosmos/ics23/go v0.10.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/dgraph-io/badger/v2 v2.2007.4 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/emicklei/dot v1.4.2 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/getsentry/sentry-go v0.21.0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect + github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect + github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/gtank/merlin v0.1.1 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.1 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/linxGnu/grocksdb v1.7.16 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/petermattis/goid v0.0.0-20221215004737-a150e88a970d // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rs/zerolog v1.30.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + github.com/tidwall/btree v1.6.0 // indirect + go.etcd.io/bbolt v1.3.6 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.1.0 // indirect + golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect + google.golang.org/grpc v1.57.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index c4949028..31bcc471 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -39,6 +39,14 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl 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= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= +cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= +cosmossdk.io/log v1.2.1 h1:Xc1GgTCicniwmMiKwDxUjO4eLhPxoVdI9vtMW8Ti/uk= +cosmossdk.io/log v1.2.1/go.mod h1:GNSCc/6+DhFIj1aLn/j7Id7PaO8DzNylUZoOYBL9+I4= +cosmossdk.io/math v1.1.2 h1:ORZetZCTyWkI5GlZ6CZS28fMHi83ZYf+A2vVnHNzZBM= +cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= +cosmossdk.io/store v1.0.0-rc.0 h1:9DwOjuUYxDtYxn/REkTxGQAmxlIGfRroB35MQ8TrxF4= +cosmossdk.io/store v1.0.0-rc.0/go.mod h1:FtBDOJmwtOZfmKKF65bKZbTYgS3bDNjjo3nP76dAegk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -60,52 +68,92 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= 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/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= -github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= -github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cometbft/cometbft v0.37.2 h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc= -github.com/cometbft/cometbft v0.37.2/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= -github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= -github.com/cosmos/gogoproto v1.4.1 h1:WoyH+0/jbCTzpKNvyav5FL1ZTWsp1im1MxEpJEzKUB8= -github.com/cosmos/gogoproto v1.4.1/go.mod h1:Ac9lzL4vFpBMcptJROQ6dQ4M3pOEK5Z/l0Q9p+LoCr4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/errors v1.10.0 h1:lfxS8zZz1+OjtV4MtNWgboi/W5tyLEB6VQZBXN+0VUU= +github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b h1:LCs8gDhg6vt8A3dN7AEJxmCoETZ4qkySoVJVm3rcSJk= +github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cometbft/cometbft v0.38.0-rc3 h1:Ly3eVPWoFu0y68PmZwLljucPdEBtfigZtqm+OV1W6dE= +github.com/cometbft/cometbft v0.38.0-rc3/go.mod h1:5Jz0Z8YsHSf0ZaAqGvi/ifioSdVFPtEGrm8Y9T/993k= +github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= +github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0E= +github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= +github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= +github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= +github.com/cosmos/iavl v1.0.0-rc.1 h1:5+73BEWW1gZOIUJKlk/1fpD4lOqqeFBA8KuV+NpkCpU= +github.com/cosmos/iavl v1.0.0-rc.1/go.mod h1:CmTGqMnRnucjxbjduneZXT+0vPgNElYvdefjX2q9tYc= +github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= +github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emicklei/dot v1.4.2 h1:UbK6gX4yvrpHKlxuUQicwoAis4zl8Dzwit9SnbBAXWw= +github.com/emicklei/dot v1.4.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -119,14 +167,23 @@ github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMi github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/getsentry/sentry-go v0.21.0 h1:c9l5F1nPF30JIppulk4veau90PK6Smu3abgVtVQWon4= +github.com/getsentry/sentry-go v0.21.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= 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= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -134,15 +191,12 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= @@ -158,6 +212,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -165,6 +221,8 @@ github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -177,6 +235,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt 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/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 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= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -195,8 +254,13 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -227,8 +291,10 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -237,61 +303,83 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= -github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= -github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.1 h1:rfPwUqFU6uZXNvGl4hzjY8LEBsqFVU4si1H9/Hqck/U= +github.com/hashicorp/go-metrics v0.5.1/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/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/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= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= 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/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 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.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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= github.com/kubernetes-csi/external-snapshotter/client/v6 v6.1.0 h1:yeuon3bOuOADwiWl2CyYrU4vbmYbAzGLCTscE1yLNHk= github.com/kubernetes-csi/external-snapshotter/client/v6 v6.1.0/go.mod h1:eVY6gNtSrhsblGAqKFDG3CrkCLFAjsDvOpPpt+EaS6k= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= +github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -304,17 +392,35 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae h1:FatpGJD2jmJfhZiFDElaC0QhZUDQnxUeAwTGkfAHN3I= +github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= -github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/peterbourgon/mergemap v0.0.1 h1:5/brtSACv34REV0xoYjPQ8JXZnx3nurGt6WInLRwqX4= github.com/peterbourgon/mergemap v0.0.1/go.mod h1:jQyRpOpE/KbvPc0VKXjAqctYglwUO5W6zAcGcFfbvlo= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20221215004737-a150e88a970d h1:htwtWgtQo8YS6JFWWi2DNgY0RwSGJ1ruMoxY6CUUclk= +github.com/petermattis/goid v0.0.0-20221215004737-a150e88a970d/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -326,35 +432,35 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= @@ -362,19 +468,26 @@ github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71e github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -388,20 +501,32 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= +github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= 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= @@ -420,6 +545,7 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -441,8 +567,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220921164117-439092de6870 h1:j8b6j9gzSigH28O5SjSpQSSh9lFd6f5D/q0aHjNTulc= -golang.org/x/exp v0.0.0-20220921164117-439092de6870/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -469,6 +595,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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= @@ -491,6 +618,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/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-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -501,11 +629,11 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -517,10 +645,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= 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= @@ -536,7 +662,9 @@ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -545,11 +673,14 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -562,27 +693,31 @@ 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-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -603,8 +738,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -650,6 +785,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -659,6 +795,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -726,6 +863,8 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 h1:lv6/DhyiFFGsmzxbsUUTOkN29II+zeWHxvT8Lpdxsv0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -745,6 +884,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -758,19 +899,21 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 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/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= @@ -785,6 +928,8 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C 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= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/cosmos/cache_controller.go b/internal/cosmos/cache_controller.go index a4b71d92..f3577dd7 100644 --- a/internal/cosmos/cache_controller.go +++ b/internal/cosmos/cache_controller.go @@ -168,6 +168,11 @@ func (c *CacheController) SyncedPods(ctx context.Context, controller client.Obje return kube.AvailablePods(c.Collect(ctx, controller).SyncedPods(), 5*time.Second, time.Now()) } +// PodsWithStatus returns all pods with their status. +func (c *CacheController) PodsWithStatus(ctx context.Context, crd *cosmosv1.CosmosFullNode) []PodStatus { + return c.Collect(ctx, client.ObjectKeyFromObject(crd)).PodsWithStatus(crd) +} + func (c *CacheController) listPods(ctx context.Context, controller client.ObjectKey) ([]corev1.Pod, error) { var pods corev1.PodList if err := c.client.List(ctx, &pods, diff --git a/internal/cosmos/status_collection.go b/internal/cosmos/status_collection.go index aefa018f..672df04b 100644 --- a/internal/cosmos/status_collection.go +++ b/internal/cosmos/status_collection.go @@ -6,6 +6,7 @@ import ( "time" "github.com/samber/lo" + cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" "github.com/strangelove-ventures/cosmos-operator/internal/kube" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -113,3 +114,46 @@ func (coll StatusCollection) Synced() StatusCollection { func (coll StatusCollection) SyncedPods() []*corev1.Pod { return lo.Map(coll.Synced(), func(status StatusItem, _ int) *corev1.Pod { return status.GetPod() }) } + +// PodStatus is the status of a pod. +type PodStatus struct { + Pod *corev1.Pod + RPCReachable bool + Synced bool + AwaitingUpgrade bool +} + +// PodsWithStatus returns all pods with their status. +func (coll StatusCollection) PodsWithStatus(crd *cosmosv1.CosmosFullNode) []PodStatus { + out := make([]PodStatus, len(coll)) + for i, status := range coll { + ps := PodStatus{ + Pod: status.GetPod(), + } + if crd.Spec.ChainSpec.Versions != nil { + instanceHeight := uint64(0) + if height, ok := crd.Status.Height[status.Pod.Name]; ok { + instanceHeight = height + } + var image string + for _, version := range crd.Spec.ChainSpec.Versions { + if instanceHeight < version.UpgradeHeight { + break + } + image = version.Image + } + if image != "" && status.Pod.Spec.Containers[0].Image != image { + ps.AwaitingUpgrade = true + } + } + if status.Err == nil { + ps.RPCReachable = true + if !status.Status.Result.SyncInfo.CatchingUp { + ps.Synced = true + } + } + + out[i] = ps + } + return out +} diff --git a/internal/fullnode/build_pods.go b/internal/fullnode/build_pods.go index c46571bb..f5cc083d 100644 --- a/internal/fullnode/build_pods.go +++ b/internal/fullnode/build_pods.go @@ -7,7 +7,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -const configChecksumAnnotation = "cosmos.strange.love/config-checksum" +const ( + configChecksumAnnotation = "cosmos.strange.love/config-checksum" +) // BuildPods creates the final state of pods given the crd. func BuildPods(crd *cosmosv1.CosmosFullNode, cksums ConfigChecksums) ([]diff.Resource[*corev1.Pod], error) { @@ -25,6 +27,22 @@ func BuildPods(crd *cosmosv1.CosmosFullNode, cksums ConfigChecksums) ([]diff.Res if _, shouldSnapshot := candidates[pod.Name]; shouldSnapshot { continue } + if len(crd.Spec.ChainSpec.Versions) > 0 { + instanceHeight := uint64(0) + if height, ok := crd.Status.Height[pod.Name]; ok { + instanceHeight = height + } + var image string + for _, version := range crd.Spec.ChainSpec.Versions { + if instanceHeight < version.UpgradeHeight { + break + } + image = version.Image + } + if image != "" { + setMainContainerImage(pod, image) + } + } if o, ok := overrides[pod.Name]; ok { if o.DisableStrategy != nil { continue diff --git a/internal/fullnode/configmap_builder.go b/internal/fullnode/configmap_builder.go index 5039ffa6..eb0780a1 100644 --- a/internal/fullnode/configmap_builder.go +++ b/internal/fullnode/configmap_builder.go @@ -38,7 +38,29 @@ func BuildConfigMaps(crd *cosmosv1.CosmosFullNode, peers Peers) ([]diff.Resource return nil, err } buf.Reset() - if err := addAppToml(buf, data, crd.Spec.ChainSpec.App); err != nil { + appCfg := crd.Spec.ChainSpec.App + if len(crd.Spec.ChainSpec.Versions) > 0 { + instanceHeight := uint64(0) + if height, ok := crd.Status.Height[instance]; ok { + instanceHeight = height + } + haltHeight := uint64(0) + for i, v := range crd.Spec.ChainSpec.Versions { + if v.SetHaltHeight { + haltHeight = v.UpgradeHeight + } else { + haltHeight = 0 + } + if instanceHeight < v.UpgradeHeight { + break + } + if i == len(crd.Spec.ChainSpec.Versions)-1 { + haltHeight = 0 + } + } + appCfg.HaltHeight = ptr(haltHeight) + } + if err := addAppToml(buf, data, appCfg); err != nil { return nil, err } buf.Reset() diff --git a/internal/fullnode/mock_test.go b/internal/fullnode/mock_test.go index dbf5a247..278badcb 100644 --- a/internal/fullnode/mock_test.go +++ b/internal/fullnode/mock_test.go @@ -7,6 +7,7 @@ import ( cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -87,6 +88,12 @@ func (m *mockClient[T]) List(ctx context.Context, list client.ObjectList, opts . *ref = m.ObjectList.(corev1.ConfigMapList) case *corev1.SecretList: *ref = m.ObjectList.(corev1.SecretList) + case *corev1.ServiceAccountList: + *ref = m.ObjectList.(corev1.ServiceAccountList) + case *rbacv1.RoleList: + *ref = m.ObjectList.(rbacv1.RoleList) + case *rbacv1.RoleBindingList: + *ref = m.ObjectList.(rbacv1.RoleBindingList) default: panic(fmt.Errorf("unknown ObjectList type: %T", m.ObjectList)) } diff --git a/internal/fullnode/pod_builder.go b/internal/fullnode/pod_builder.go index fba3dfe3..8ad423e3 100644 --- a/internal/fullnode/pod_builder.go +++ b/internal/fullnode/pod_builder.go @@ -46,6 +46,11 @@ func NewPodBuilder(crd *cosmosv1.CosmosFullNode) PodBuilder { probes = podReadinessProbes(crd) ) + versionCheckCmd := []string{"/manager", "versioncheck", "-d"} + if crd.Spec.ChainSpec.DatabaseBackend != nil { + versionCheckCmd = append(versionCheckCmd, "-b", *crd.Spec.ChainSpec.DatabaseBackend) + } + pod := corev1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", @@ -57,6 +62,7 @@ func NewPodBuilder(crd *cosmosv1.CosmosFullNode) PodBuilder { Annotations: make(map[string]string), }, Spec: corev1.PodSpec{ + ServiceAccountName: serviceAccountName(crd), SecurityContext: &corev1.PodSecurityContext{ RunAsUser: ptr(int64(1025)), RunAsGroup: ptr(int64(1025)), @@ -83,28 +89,43 @@ func NewPodBuilder(crd *cosmosv1.CosmosFullNode) PodBuilder { ImagePullPolicy: tpl.ImagePullPolicy, WorkingDir: workDir, }, + // healthcheck sidecar + { + Name: "healthcheck", + // Available images: https://github.com/orgs/strangelove-ventures/packages?repo_name=cosmos-operator + // IMPORTANT: Must use v0.6.2 or later. + Image: "ghcr.io/strangelove-ventures/cosmos-operator:" + version.DockerTag(), + Command: []string{"/manager", "healthcheck"}, + Ports: []corev1.ContainerPort{{ContainerPort: healthCheckPort, Protocol: corev1.ProtocolTCP}}, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("5m"), + corev1.ResourceMemory: resource.MustParse("16Mi"), + }, + }, + ReadinessProbe: probes[1], + ImagePullPolicy: tpl.ImagePullPolicy, + }, + // version check sidecar, runs on terminate in case the instance is halting for upgrade. + { + Name: "version-check-term", + Image: "ghcr.io/strangelove-ventures/cosmos-operator:" + version.DockerTag(), + Command: versionCheckCmd, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("5m"), + corev1.ResourceMemory: resource.MustParse("16Mi"), + }, + }, + Env: envVars(crd), + ImagePullPolicy: tpl.ImagePullPolicy, + WorkingDir: workDir, + SecurityContext: &corev1.SecurityContext{}, + }, }, }, } - // Add healtcheck sidecar - pod.Spec.Containers = append(pod.Spec.Containers, corev1.Container{ - Name: "healthcheck", - // Available images: https://github.com/orgs/strangelove-ventures/packages?repo_name=cosmos-operator - // IMPORTANT: Must use v0.6.2 or later. - Image: "ghcr.io/strangelove-ventures/cosmos-operator:" + version.DockerTag(), - Command: []string{"/manager", "healthcheck"}, - Ports: []corev1.ContainerPort{{ContainerPort: healthCheckPort, Protocol: corev1.ProtocolTCP}}, - Resources: corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("5m"), - corev1.ResourceMemory: resource.MustParse("16Mi"), - }, - }, - ReadinessProbe: probes[1], - ImagePullPolicy: tpl.ImagePullPolicy, - }) - preserveMergeInto(pod.Labels, tpl.Metadata.Labels) preserveMergeInto(pod.Annotations, tpl.Metadata.Annotations) @@ -249,6 +270,7 @@ func (b PodBuilder) WithOrdinal(ordinal int32) PodBuilder { // The healthcheck sidecar needs access to the home directory so it can read disk usage. {Name: volChainHome, MountPath: ChainHomeDir(b.crd), ReadOnly: true}, } + pod.Spec.Containers[2].VolumeMounts = mounts b.pod = pod return b @@ -385,6 +407,32 @@ config-merge -f toml "$TMP_DIR/app.toml" "$OVERLAY_DIR/app-overlay.toml" > "$CON }) } + versionCheckCmd := []string{"/manager", "versioncheck"} + if crd.Spec.ChainSpec.DatabaseBackend != nil { + versionCheckCmd = append(versionCheckCmd, "-b", *crd.Spec.ChainSpec.DatabaseBackend) + } + + // Append version check after snapshot download, if applicable. + // That way the version check will be after the database is initialized. + // This initContainer will update the crd status with the current height for the pod, + // And then panic if the image version is not correct for the current height. + // After the status is patched, the pod will be restarted with the correct image. + required = append(required, corev1.Container{ + Name: "version-check", + Image: "ghcr.io/strangelove-ventures/cosmos-operator:" + version.DockerTag(), + Command: versionCheckCmd, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("5m"), + corev1.ResourceMemory: resource.MustParse("16Mi"), + }, + }, + Env: env, + ImagePullPolicy: tpl.ImagePullPolicy, + WorkingDir: workDir, + SecurityContext: &corev1.SecurityContext{}, + }) + return required } diff --git a/internal/fullnode/pod_builder_test.go b/internal/fullnode/pod_builder_test.go index 3ba1b8a3..830827ac 100644 --- a/internal/fullnode/pod_builder_test.go +++ b/internal/fullnode/pod_builder_test.go @@ -208,7 +208,7 @@ func TestPodBuilder(t *testing.T) { pod, err := builder.WithOrdinal(6).Build() require.NoError(t, err) - require.Len(t, pod.Spec.Containers, 2) + require.Len(t, pod.Spec.Containers, 3) startContainer := pod.Spec.Containers[0] require.Equal(t, "node", startContainer.Name) @@ -244,7 +244,7 @@ func TestPodBuilder(t *testing.T) { } require.Equal(t, healthPort, healthContainer.Ports[0]) - require.Len(t, lo.Map(pod.Spec.InitContainers, func(c corev1.Container, _ int) string { return c.Name }), 6) + require.Len(t, lo.Map(pod.Spec.InitContainers, func(c corev1.Container, _ int) string { return c.Name }), 7) wantInitImages := []string{ "ghcr.io/strangelove-ventures/infra-toolkit:v0.0.1", @@ -253,6 +253,7 @@ func TestPodBuilder(t *testing.T) { "ghcr.io/strangelove-ventures/infra-toolkit:v0.0.1", "ghcr.io/strangelove-ventures/infra-toolkit:v0.0.1", "ghcr.io/strangelove-ventures/infra-toolkit:v0.0.1", + "ghcr.io/strangelove-ventures/cosmos-operator:latest", } require.Equal(t, wantInitImages, lo.Map(pod.Spec.InitContainers, func(c corev1.Container, _ int) string { return c.Image @@ -287,7 +288,7 @@ func TestPodBuilder(t *testing.T) { pod, err := builder.WithOrdinal(6).Build() require.NoError(t, err) - require.Len(t, pod.Spec.Containers, 2) + require.Len(t, pod.Spec.Containers, 3) container := pod.Spec.Containers[0] require.Equal(t, "node", container.Name) @@ -346,7 +347,7 @@ func TestPodBuilder(t *testing.T) { require.Equal(t, "osmosis-node-key-5", vols[4].Secret.SecretName) require.Equal(t, []corev1.KeyToPath{{Key: "node_key.json", Path: "node_key.json"}}, vols[4].Secret.Items) - require.Equal(t, len(pod.Spec.Containers), 2) + require.Equal(t, len(pod.Spec.Containers), 3) c := pod.Spec.Containers[0] require.Equal(t, "node", c.Name) // Sanity check @@ -522,7 +523,7 @@ gaiad start --home /home/operator/cosmos` require.Nilf(t, cont.ReadinessProbe, "container %d", i) } - require.Equal(t, 2, len(pod.Spec.Containers)) + require.Equal(t, 3, len(pod.Spec.Containers)) require.Equal(t, "node", pod.Spec.Containers[0].Name) sidecar := pod.Spec.Containers[1] @@ -557,13 +558,13 @@ gaiad start --home /home/operator/cosmos` require.Equal(t, &corev1.EmptyDirVolumeSource{}, vols["foo-vol"].VolumeSource.EmptyDir) containers := lo.SliceToMap(pod.Spec.Containers, func(c corev1.Container) (string, corev1.Container) { return c.Name, c }) - require.ElementsMatch(t, []string{"node", "new-sidecar", "healthcheck"}, lo.Keys(containers)) + require.ElementsMatch(t, []string{"node", "new-sidecar", "healthcheck", "version-check-term"}, lo.Keys(containers)) extraVol := lo.Filter(containers["node"].VolumeMounts, func(vm corev1.VolumeMount, _ int) bool { return vm.Name == "foo-vol" }) require.Equal(t, "/foo", extraVol[0].MountPath) initConts := lo.SliceToMap(pod.Spec.InitContainers, func(c corev1.Container) (string, corev1.Container) { return c.Name, c }) - require.ElementsMatch(t, []string{"clean-init", "chain-init", "new-init", "genesis-init", "addrbook-init", "config-merge"}, lo.Keys(initConts)) + require.ElementsMatch(t, []string{"clean-init", "chain-init", "new-init", "genesis-init", "addrbook-init", "config-merge", "version-check"}, lo.Keys(initConts)) require.Equal(t, "foo:latest", initConts["chain-init"].Image) }) diff --git a/internal/fullnode/pod_control.go b/internal/fullnode/pod_control.go index db83c707..789b2208 100644 --- a/internal/fullnode/pod_control.go +++ b/internal/fullnode/pod_control.go @@ -4,8 +4,8 @@ import ( "context" "fmt" - "github.com/samber/lo" cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" + "github.com/strangelove-ventures/cosmos-operator/internal/cosmos" "github.com/strangelove-ventures/cosmos-operator/internal/diff" "github.com/strangelove-ventures/cosmos-operator/internal/kube" corev1 "k8s.io/api/core/v1" @@ -17,7 +17,7 @@ import ( ) type PodFilter interface { - SyncedPods(ctx context.Context, controller client.ObjectKey) []*corev1.Pod + PodsWithStatus(ctx context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus } // Client is a controller client. It is a subset of client.Client. @@ -83,23 +83,86 @@ func (pc PodControl) Reconcile(ctx context.Context, reporter kube.Reporter, crd return true, nil } - if len(diffed.Updates()) > 0 { + diffedUpdates := diffed.Updates() + if len(diffedUpdates) > 0 { var ( - // This may be a source of confusion by passing currentPods vs. pods from diff.Updates(). - // This is a leaky abstraction (which may be fixed in the future) because diff.Updates() pods are built - // from the operator and do not match what's returned by listing pods. - avail = pc.podFilter.SyncedPods(ctx, client.ObjectKeyFromObject(crd)) - numUpdates = pc.computeRollout(crd.Spec.RolloutStrategy.MaxUnavailable, int(crd.Spec.Replicas), len(avail)) + podsWithStatus = pc.podFilter.PodsWithStatus(ctx, crd) + upgradePods = make(map[string]bool) + otherUpdates = make(map[string]*corev1.Pod) + rpcReachablePods = make(map[string]bool) + inSyncPods = make(map[string]bool) + deletedPods = make(map[string]bool) ) - for _, pod := range lo.Slice(diffed.Updates(), 0, numUpdates) { - reporter.Info("Deleting pod for update", "podName", pod.Name) + for _, ps := range podsWithStatus { + if ps.Synced { + inSyncPods[ps.Pod.Name] = true + } + if ps.RPCReachable { + rpcReachablePods[ps.Pod.Name] = true + } + for _, update := range diffedUpdates { + if ps.Pod.Name == update.Name { + if ps.AwaitingUpgrade { + if !ps.RPCReachable { + upgradePods[ps.Pod.Name] = true + reporter.Info("Deleting pod for version upgrade", "podName", ps.Pod.Name) + // Because we should watch for deletes, we get a re-queued request, detect pod is missing, and re-create it. + if err := pc.client.Delete(ctx, ps.Pod, client.PropagationPolicy(metav1.DeletePropagationForeground)); client.IgnoreNotFound(err) != nil { + return true, kube.TransientError(fmt.Errorf("upgrade pod version %q: %w", ps.Pod.Name, err)) + } + deletedPods[ps.Pod.Name] = true + } else { + otherUpdates[ps.Pod.Name] = ps.Pod + } + } else { + otherUpdates[ps.Pod.Name] = ps.Pod + } + break + } + } + } + + // If we don't have any pods in sync, we are down anyways, so we can use the number of RPC reachable pods for computing the rollout, + // with the goal of recovering the pods as quickly as possible. + ready := len(inSyncPods) + if ready == 0 { + ready = len(rpcReachablePods) + } + + numUpdates := pc.computeRollout(crd.Spec.RolloutStrategy.MaxUnavailable, int(crd.Spec.Replicas), ready) + + updated := len(upgradePods) + + if updated == len(diffedUpdates) { + // All pods are updated. + return false, nil + } + + if updated >= numUpdates { + // Signal requeue. + return true, nil + } + + for podName, pod := range otherUpdates { + reporter.Info("Deleting pod for update", "podName", podName) // Because we should watch for deletes, we get a re-queued request, detect pod is missing, and re-create it. if err := pc.client.Delete(ctx, pod, client.PropagationPolicy(metav1.DeletePropagationForeground)); client.IgnoreNotFound(err) != nil { - return true, kube.TransientError(fmt.Errorf("update pod %q: %w", pod.Name, err)) + return true, kube.TransientError(fmt.Errorf("update pod %q: %w", podName, err)) + } + deletedPods[podName] = true + updated++ + if updated >= numUpdates { + // done for this round + break } } + if len(diffedUpdates) == updated { + // All pods are updated. + return false, nil + } + // Signal requeue. return true, nil } diff --git a/internal/fullnode/pod_control_test.go b/internal/fullnode/pod_control_test.go index a21cc003..41480a69 100644 --- a/internal/fullnode/pod_control_test.go +++ b/internal/fullnode/pod_control_test.go @@ -2,9 +2,14 @@ package fullnode import ( "context" + "fmt" "testing" + "github.com/samber/lo" + cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" + "github.com/strangelove-ventures/cosmos-operator/internal/cosmos" "github.com/strangelove-ventures/cosmos-operator/internal/diff" + "github.com/strangelove-ventures/cosmos-operator/internal/kube" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -12,16 +17,16 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -type mockPodFilter func(ctx context.Context, controller client.ObjectKey) []*corev1.Pod +type mockPodFilter func(ctx context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus -func (fn mockPodFilter) SyncedPods(ctx context.Context, controller client.ObjectKey) []*corev1.Pod { +func (fn mockPodFilter) PodsWithStatus(ctx context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { if ctx == nil { panic("nil context") } - return fn(ctx, controller) + return fn(ctx, crd) } -var panicPodFilter = mockPodFilter(func(context.Context, client.ObjectKey) []*corev1.Pod { +var panicPodFilter = mockPodFilter(func(context.Context, *cosmosv1.CosmosFullNode) []cosmos.PodStatus { panic("SyncedPods should not be called") }) @@ -96,6 +101,9 @@ func TestPodControl_Reconcile(t *testing.T) { crd.Name = "hub" crd.Namespace = namespace crd.Spec.Replicas = 5 + crd.Spec.RolloutStrategy = cosmosv1.RolloutStrategy{ + MaxUnavailable: ptr(intstr.FromInt(2)), + } pods, err := BuildPods(&crd, nil) require.NoError(t, err) @@ -107,11 +115,17 @@ func TestPodControl_Reconcile(t *testing.T) { } var didFilter bool - podFilter := mockPodFilter(func(_ context.Context, controller client.ObjectKey) []*corev1.Pod { - require.Equal(t, namespace, controller.Namespace) - require.Equal(t, "hub", controller.Name) + podFilter := mockPodFilter(func(_ context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { + require.Equal(t, namespace, crd.Namespace) + require.Equal(t, "hub", crd.Name) didFilter = true - return existing[:1] + return lo.Map(existing, func(pod *corev1.Pod, i int) cosmos.PodStatus { + return cosmos.PodStatus{ + Pod: pod, + RPCReachable: true, + Synced: true, + } + }) }) control := NewPodControl(&mClient, podFilter) @@ -119,8 +133,8 @@ func TestPodControl_Reconcile(t *testing.T) { control.computeRollout = func(maxUnavail *intstr.IntOrString, desired, ready int) int { require.EqualValues(t, crd.Spec.Replicas, desired) - require.Equal(t, 1, ready) // mockPodFilter only returns 1 candidate as ready - return stubRollout + require.Equal(t, stubRollout, ready) // mockPodFilter only returns 1 candidate as ready + return kube.ComputeRollout(maxUnavail, desired, ready) } // Trigger updates @@ -132,6 +146,325 @@ func TestPodControl_Reconcile(t *testing.T) { require.True(t, didFilter) require.Zero(t, mClient.CreateCount) - require.Equal(t, stubRollout, mClient.DeleteCount) + require.Equal(t, 2, mClient.DeleteCount) + + didFilter = false + podFilter = mockPodFilter(func(_ context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { + require.Equal(t, namespace, crd.Namespace) + require.Equal(t, "hub", crd.Name) + didFilter = true + return lo.Map(existing, func(pod *corev1.Pod, i int) cosmos.PodStatus { + ps := cosmos.PodStatus{ + Pod: pod, + RPCReachable: true, + Synced: true, + } + if i < 2 { + ps.RPCReachable = false + ps.Synced = false + } + return ps + }) + }) + + control = NewPodControl(&mClient, podFilter) + + requeue, err = control.Reconcile(ctx, nopReporter, &crd, nil) + require.NoError(t, err) + require.True(t, requeue) + + require.True(t, didFilter) + + require.Zero(t, mClient.CreateCount) + + // should not delete any more yet. + require.Equal(t, 2, mClient.DeleteCount) + }) + + t.Run("rollout version upgrade rolling", func(t *testing.T) { + crd := defaultCRD() + crd.Name = "hub" + crd.Namespace = namespace + crd.Spec.Replicas = 5 + crd.Spec.RolloutStrategy = cosmosv1.RolloutStrategy{ + MaxUnavailable: ptr(intstr.FromInt(2)), + } + crd.Spec.ChainSpec = cosmosv1.ChainSpec{ + Versions: []cosmosv1.ChainVersion{ + { + Image: "image", + }, + { + UpgradeHeight: 100, + Image: "new-image", + }, + }, + } + crd.Status.Height = make(map[string]uint64) + + pods, err := BuildPods(&crd, nil) + require.NoError(t, err) + existing := diff.New(nil, pods).Creates() + + var mClient mockPodClient + mClient.ObjectList = corev1.PodList{ + Items: valueSlice(existing), + } + + var didFilter bool + podFilter := mockPodFilter(func(_ context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { + require.Equal(t, namespace, crd.Namespace) + require.Equal(t, "hub", crd.Name) + didFilter = true + return lo.Map(existing, func(pod *corev1.Pod, i int) cosmos.PodStatus { + return cosmos.PodStatus{ + Pod: pod, + // pods are at or above upgrade height and not reachable + AwaitingUpgrade: true, + RPCReachable: true, + Synced: false, + } + }) + }) + + control := NewPodControl(&mClient, podFilter) + + control.computeRollout = func(maxUnavail *intstr.IntOrString, desired, ready int) int { + require.EqualValues(t, crd.Spec.Replicas, desired) + require.Equal(t, 5, ready) // all are reachable and reporting ready, so we will maintain liveliness. + return kube.ComputeRollout(maxUnavail, desired, ready) + } + + // Trigger updates + for _, pod := range existing { + crd.Status.Height[pod.Name] = 100 + } + + // Reconcile 1, should update 0 and 1 + + requeue, err := control.Reconcile(ctx, nopReporter, &crd, nil) + require.NoError(t, err) + + // only handled 2 updates, so should requeue. + require.True(t, requeue) + + require.True(t, didFilter) + + require.Zero(t, mClient.CreateCount) + require.Equal(t, 2, mClient.DeleteCount) + + existing[0].Spec.Containers[0].Image = "new-image" + existing[1].Spec.Containers[0].Image = "new-image" + + recalculatePodRevision(existing[0], 0) + recalculatePodRevision(existing[1], 1) + mClient.ObjectList = corev1.PodList{ + Items: valueSlice(existing), + } + + // 2 are now unavailable, working on upgrade + + didFilter = false + podFilter = mockPodFilter(func(_ context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { + require.Equal(t, namespace, crd.Namespace) + require.Equal(t, "hub", crd.Name) + didFilter = true + return lo.Map(existing, func(pod *corev1.Pod, i int) cosmos.PodStatus { + ps := cosmos.PodStatus{ + Pod: pod, + RPCReachable: true, + Synced: true, + } + if i < 2 { + ps.RPCReachable = false + ps.Synced = false + } else { + ps.AwaitingUpgrade = true + } + return ps + }) + }) + + control = NewPodControl(&mClient, podFilter) + + // Reconcile 2, should not update anything because 0 and 1 are still in progress. + + requeue, err = control.Reconcile(ctx, nopReporter, &crd, nil) + require.NoError(t, err) + + // no further updates yet, should requeue. + require.True(t, requeue) + + require.True(t, didFilter) + + require.Zero(t, mClient.CreateCount) + + // should not delete any more yet. + require.Equal(t, 2, mClient.DeleteCount) + + // mock out that one of the pods completed the upgrade. should begin upgrading one more + + didFilter = false + podFilter = mockPodFilter(func(_ context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { + require.Equal(t, namespace, crd.Namespace) + require.Equal(t, "hub", crd.Name) + didFilter = true + return lo.Map(existing, func(pod *corev1.Pod, i int) cosmos.PodStatus { + ps := cosmos.PodStatus{ + Pod: pod, + RPCReachable: true, + Synced: true, + } + if i == 1 { + ps.RPCReachable = false + ps.Synced = false + } + if i >= 2 { + ps.AwaitingUpgrade = true + } + return ps + }) + }) + + control = NewPodControl(&mClient, podFilter) + + // Reconcile 3, should update 2 (only one) because 1 is still in progress, but 0 is done. + + requeue, err = control.Reconcile(ctx, nopReporter, &crd, nil) + require.NoError(t, err) + + // only handled 1 updates, so should requeue. + require.True(t, requeue) + + require.True(t, didFilter) + + require.Zero(t, mClient.CreateCount) + + // should delete one more + require.Equal(t, 3, mClient.DeleteCount) + + existing[2].Spec.Containers[0].Image = "new-image" + recalculatePodRevision(existing[2], 2) + mClient.ObjectList = corev1.PodList{ + Items: valueSlice(existing), + } + + // mock out that both pods completed the upgrade. should begin upgrading the last 2 + + didFilter = false + podFilter = mockPodFilter(func(_ context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { + require.Equal(t, namespace, crd.Namespace) + require.Equal(t, "hub", crd.Name) + didFilter = true + return lo.Map(existing, func(pod *corev1.Pod, i int) cosmos.PodStatus { + ps := cosmos.PodStatus{ + Pod: pod, + RPCReachable: true, + Synced: true, + } + if i >= 3 { + ps.AwaitingUpgrade = true + } + return ps + }) + }) + + control = NewPodControl(&mClient, podFilter) + + // Reconcile 4, should update 3 and 4 because the rest are done. + + requeue, err = control.Reconcile(ctx, nopReporter, &crd, nil) + require.NoError(t, err) + + // all updates are now handled, no longer need requeue. + require.False(t, requeue) + + require.True(t, didFilter) + + require.Zero(t, mClient.CreateCount) + + // should delete the last 2 + require.Equal(t, 5, mClient.DeleteCount) }) + + t.Run("rollout version upgrade halt", func(t *testing.T) { + crd := defaultCRD() + crd.Name = "hub" + crd.Namespace = namespace + crd.Spec.Replicas = 5 + crd.Spec.RolloutStrategy = cosmosv1.RolloutStrategy{ + MaxUnavailable: ptr(intstr.FromInt(2)), + } + crd.Spec.ChainSpec = cosmosv1.ChainSpec{ + Versions: []cosmosv1.ChainVersion{ + { + Image: "image", + }, + { + UpgradeHeight: 100, + Image: "new-image", + SetHaltHeight: true, + }, + }, + } + crd.Status.Height = make(map[string]uint64) + + pods, err := BuildPods(&crd, nil) + require.NoError(t, err) + existing := diff.New(nil, pods).Creates() + + var mClient mockPodClient + mClient.ObjectList = corev1.PodList{ + Items: valueSlice(existing), + } + + var didFilter bool + podFilter := mockPodFilter(func(_ context.Context, crd *cosmosv1.CosmosFullNode) []cosmos.PodStatus { + require.Equal(t, namespace, crd.Namespace) + require.Equal(t, "hub", crd.Name) + didFilter = true + return lo.Map(existing, func(pod *corev1.Pod, i int) cosmos.PodStatus { + return cosmos.PodStatus{ + Pod: pod, + // pods are at or above upgrade height and not reachable + AwaitingUpgrade: true, + RPCReachable: false, + Synced: false, + } + }) + }) + + control := NewPodControl(&mClient, podFilter) + + control.computeRollout = func(maxUnavail *intstr.IntOrString, desired, ready int) int { + require.EqualValues(t, crd.Spec.Replicas, desired) + require.Equal(t, 0, ready) // mockPodFilter returns no pods as synced, but all are at the upgrade height. + return kube.ComputeRollout(maxUnavail, desired, ready) + } + + // Trigger updates + for _, pod := range existing { + crd.Status.Height[pod.Name] = 100 + } + + requeue, err := control.Reconcile(ctx, nopReporter, &crd, nil) + require.NoError(t, err) + + // all updates are handled, so should not requeue + require.False(t, requeue) + + require.True(t, didFilter) + + require.Zero(t, mClient.CreateCount) + require.Equal(t, 5, mClient.DeleteCount) + }) +} + +// revision hash must be taken without the revision label and the ordinal annotation. +func recalculatePodRevision(pod *corev1.Pod, ordinal int) { + delete(pod.Labels, "app.kubernetes.io/revision") + delete(pod.Annotations, "app.kubernetes.io/ordinal") + rev1 := diff.Adapt(pod, ordinal).Revision() + pod.Labels["app.kubernetes.io/revision"] = rev1 + pod.Annotations["app.kubernetes.io/ordinal"] = fmt.Sprintf("%d", ordinal) } diff --git a/internal/fullnode/rbac_builder.go b/internal/fullnode/rbac_builder.go new file mode 100644 index 00000000..219e313b --- /dev/null +++ b/internal/fullnode/rbac_builder.go @@ -0,0 +1,120 @@ +package fullnode + +import ( + cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" + "github.com/strangelove-ventures/cosmos-operator/internal/diff" + "github.com/strangelove-ventures/cosmos-operator/internal/kube" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func serviceAccountName(crd *cosmosv1.CosmosFullNode) string { + return crd.Name + "-vc-sa" +} + +func roleName(crd *cosmosv1.CosmosFullNode) string { + return crd.Name + "-vc-r" +} + +func roleBindingName(crd *cosmosv1.CosmosFullNode) string { + return crd.Name + "-vc-rb" +} + +// BuildServiceAccounts returns a list of service accounts given the crd. +// +// Creates a single service account for the version check. +func BuildServiceAccounts(crd *cosmosv1.CosmosFullNode) []diff.Resource[*corev1.ServiceAccount] { + diffSa := make([]diff.Resource[*corev1.ServiceAccount], 1) + sa := corev1.ServiceAccount{ + TypeMeta: v1.TypeMeta{ + Kind: "ServiceAccount", + APIVersion: "v1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: serviceAccountName(crd), + Namespace: crd.Namespace, + }, + } + + sa.Labels = defaultLabels(crd, kube.ComponentLabel, "vc") + + diffSa[0] = diff.Adapt(&sa, 0) + + return diffSa +} + +// BuildRoles returns a list of role bindings given the crd. +// +// Creates a single role binding for the version check. +func BuildRoles(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.Role] { + diffCr := make([]diff.Resource[*rbacv1.Role], 1) + cr := rbacv1.Role{ + TypeMeta: v1.TypeMeta{ + Kind: "Role", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: roleName(crd), + Namespace: crd.Namespace, + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, // core API group + Resources: []string{"namespaces", "pods"}, + Verbs: []string{"get", "list"}, + }, + { + APIGroups: []string{"cosmos.strange.love"}, + Resources: []string{"cosmosfullnodes"}, + Verbs: []string{"get"}, + }, + { + APIGroups: []string{"cosmos.strange.love"}, + Resources: []string{"cosmosfullnodes/status"}, + Verbs: []string{"update"}, + }, + }, + } + + cr.Labels = defaultLabels(crd, kube.ComponentLabel, "vc") + + diffCr[0] = diff.Adapt(&cr, 0) + + return diffCr +} + +// BuildRoles returns a list of role binding bindings given the crd. +// +// Creates a single role binding binding for the version check. +func BuildRoleBindings(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.RoleBinding] { + diffCrb := make([]diff.Resource[*rbacv1.RoleBinding], 1) + crb := rbacv1.RoleBinding{ + TypeMeta: v1.TypeMeta{ + Kind: "RoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: v1.ObjectMeta{ + Name: roleBindingName(crd), + Namespace: crd.Namespace, + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + Name: serviceAccountName(crd), + Namespace: crd.Namespace, + }, + }, + RoleRef: rbacv1.RoleRef{ + Kind: "Role", + Name: roleName(crd), + APIGroup: "rbac.authorization.k8s.io", + }, + } + + crb.Labels = defaultLabels(crd, kube.ComponentLabel, "vc") + + diffCrb[0] = diff.Adapt(&crb, 0) + + return diffCrb +} diff --git a/internal/fullnode/rbac_builder_test.go b/internal/fullnode/rbac_builder_test.go new file mode 100644 index 00000000..c7681b4c --- /dev/null +++ b/internal/fullnode/rbac_builder_test.go @@ -0,0 +1,102 @@ +package fullnode + +import ( + "testing" + + "github.com/stretchr/testify/require" + + rbacv1 "k8s.io/api/rbac/v1" +) + +func TestBuildRBAC(t *testing.T) { + t.Parallel() + + t.Run("build rbac", func(t *testing.T) { + crd := defaultCRD() + crd.Spec.Replicas = 3 + crd.Name = "hub" + crd.Namespace = "test" + crd.Spec.ChainSpec.Network = "testnet" + crd.Spec.PodTemplate.Image = "gaia:v6.0.0" + + sas := BuildServiceAccounts(&crd) + + require.Len(t, sas, 1) // 1 svc account in the namespace + + sa := sas[0].Object() + + require.Equal(t, "hub-vc-sa", sa.Name) + require.Equal(t, "test", sa.Namespace) + + wantLabels := map[string]string{ + "app.kubernetes.io/created-by": "cosmos-operator", + "app.kubernetes.io/name": "hub", + "app.kubernetes.io/component": "vc", + "app.kubernetes.io/version": "v6.0.0", + "cosmos.strange.love/network": "testnet", + "cosmos.strange.love/type": "FullNode", + } + require.Equal(t, wantLabels, sa.Labels) + + roles := BuildRoles(&crd) + + require.Len(t, roles, 1) // 1 role in the namespace + + role := roles[0].Object() + + require.Equal(t, "hub-vc-r", role.Name) + require.Equal(t, "test", role.Namespace) + + wantLabels = map[string]string{ + "app.kubernetes.io/created-by": "cosmos-operator", + "app.kubernetes.io/name": "hub", + "app.kubernetes.io/component": "vc", + "app.kubernetes.io/version": "v6.0.0", + "cosmos.strange.love/network": "testnet", + "cosmos.strange.love/type": "FullNode", + } + require.Equal(t, wantLabels, role.Labels) + + require.Equal(t, []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, // core API group + Resources: []string{"namespaces", "pods"}, + Verbs: []string{"get", "list"}, + }, + { + APIGroups: []string{"cosmos.strange.love"}, + Resources: []string{"cosmosfullnodes"}, + Verbs: []string{"get"}, + }, + { + APIGroups: []string{"cosmos.strange.love"}, + Resources: []string{"cosmosfullnodes/status"}, + Verbs: []string{"update"}, + }, + }, role.Rules) + + rbs := BuildRoleBindings(&crd) + + require.Len(t, rbs, 1) // 1 role in the namespace + + rb := rbs[0].Object() + + require.Equal(t, "hub-vc-rb", rb.Name) + require.Equal(t, "test", rb.Namespace) + + wantLabels = map[string]string{ + "app.kubernetes.io/created-by": "cosmos-operator", + "app.kubernetes.io/name": "hub", + "app.kubernetes.io/component": "vc", + "app.kubernetes.io/version": "v6.0.0", + "cosmos.strange.love/network": "testnet", + "cosmos.strange.love/type": "FullNode", + } + require.Equal(t, wantLabels, rb.Labels) + + require.Len(t, rb.Subjects, 1) + require.Equal(t, rb.Subjects[0].Name, "hub-vc-sa") + + require.Equal(t, rb.RoleRef.Name, "hub-vc-r") + }) +} diff --git a/internal/fullnode/role_binding_control.go b/internal/fullnode/role_binding_control.go new file mode 100644 index 00000000..12d90a8c --- /dev/null +++ b/internal/fullnode/role_binding_control.go @@ -0,0 +1,64 @@ +package fullnode + +import ( + "context" + "fmt" + + cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" + "github.com/strangelove-ventures/cosmos-operator/internal/diff" + "github.com/strangelove-ventures/cosmos-operator/internal/kube" + rbacv1 "k8s.io/api/rbac/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// RoleBindingControl creates or updates RoleBindings. +type RoleBindingControl struct { + client Client +} + +func NewRoleBindingControl(client Client) RoleBindingControl { + return RoleBindingControl{ + client: client, + } +} + +// Reconcile creates or updates role bindings. +func (sc RoleBindingControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError { + var crs rbacv1.RoleBindingList + if err := sc.client.List(ctx, &crs, + client.InNamespace(crd.Namespace), + client.MatchingLabels{ + kube.ControllerLabel: "cosmos-operator", + kube.ComponentLabel: "vc", + kube.NameLabel: appName(crd), + }, + ); err != nil { + return kube.TransientError(fmt.Errorf("list existing role bindings: %w", err)) + } + + current := ptrSlice(crs.Items) + want := BuildRoleBindings(crd) + diffed := diff.New(current, want) + + for _, cr := range diffed.Creates() { + log.Info("Creating role binding", "name", cr.Name) + if err := ctrl.SetControllerReference(crd, cr, sc.client.Scheme()); err != nil { + return kube.TransientError(fmt.Errorf("set controller reference on role binding %q: %w", cr.Name, err)) + } + // CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference. + // This ensures we update the service with the owner reference. + if err := kube.CreateOrUpdate(ctx, sc.client, cr); err != nil { + return kube.TransientError(fmt.Errorf("create role binding %q: %w", cr.Name, err)) + } + } + + for _, cr := range diffed.Updates() { + log.Info("Updating role binding", "name", cr.Name) + if err := sc.client.Update(ctx, cr); err != nil { + return kube.TransientError(fmt.Errorf("update role binding %q: %w", cr.Name, err)) + } + } + + return nil +} diff --git a/internal/fullnode/role_binding_control_test.go b/internal/fullnode/role_binding_control_test.go new file mode 100644 index 00000000..cefda597 --- /dev/null +++ b/internal/fullnode/role_binding_control_test.go @@ -0,0 +1,70 @@ +package fullnode + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestRoleBindingControl_Reconcile(t *testing.T) { + t.Parallel() + + type mockRbClient = mockClient[*rbacv1.RoleBinding] + + ctx := context.Background() + + t.Run("happy path", func(t *testing.T) { + crd := defaultCRD() + crd.Namespace = "test" + crd.Spec.Replicas = 3 + + var mClient mockRbClient + + control := NewRoleBindingControl(&mClient) + err := control.Reconcile(ctx, nopReporter, &crd) + require.NoError(t, err) + + require.Len(t, mClient.GotListOpts, 2) + var listOpt client.ListOptions + for _, opt := range mClient.GotListOpts { + opt.ApplyToList(&listOpt) + } + require.Equal(t, "test", listOpt.Namespace) + require.Zero(t, listOpt.Limit) + + require.Equal(t, 1, mClient.CreateCount) // Created 1 role binding. + require.Equal(t, "osmosis-vc-rb", mClient.LastCreateObject.Name) + require.NotEmpty(t, mClient.LastCreateObject.OwnerReferences) + require.Equal(t, crd.Name, mClient.LastCreateObject.OwnerReferences[0].Name) + require.Equal(t, "CosmosFullNode", mClient.LastCreateObject.OwnerReferences[0].Kind) + require.True(t, *mClient.LastCreateObject.OwnerReferences[0].Controller) + + mClient.ObjectList = rbacv1.RoleBindingList{Items: []rbacv1.RoleBinding{ + { + ObjectMeta: metav1.ObjectMeta{Name: "osmosis-vc-rb", Namespace: crd.Namespace}, + Subjects: nil, // different to force update + }, + }} + + mClient.GotListOpts = nil // reset for next reconcile + + err = control.Reconcile(ctx, nopReporter, &crd) + require.NoError(t, err) + + require.Len(t, mClient.GotListOpts, 2) + listOpt = client.ListOptions{} + for _, opt := range mClient.GotListOpts { + opt.ApplyToList(&listOpt) + } + require.Equal(t, "test", listOpt.Namespace) + require.Zero(t, listOpt.Limit) + + require.Equal(t, 1, mClient.UpdateCount) // Updated 1 role binding. + + require.Zero(t, mClient.DeleteCount) // Role bindings are never deleted. + }) +} diff --git a/internal/fullnode/role_control.go b/internal/fullnode/role_control.go new file mode 100644 index 00000000..ad5a7132 --- /dev/null +++ b/internal/fullnode/role_control.go @@ -0,0 +1,64 @@ +package fullnode + +import ( + "context" + "fmt" + + cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" + "github.com/strangelove-ventures/cosmos-operator/internal/diff" + "github.com/strangelove-ventures/cosmos-operator/internal/kube" + rbacv1 "k8s.io/api/rbac/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// RoleControl creates or updates Roles. +type RoleControl struct { + client Client +} + +func NewRoleControl(client Client) RoleControl { + return RoleControl{ + client: client, + } +} + +// Reconcile creates or updates roles. +func (sc RoleControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError { + var crs rbacv1.RoleList + if err := sc.client.List(ctx, &crs, + client.InNamespace(crd.Namespace), + client.MatchingLabels{ + kube.ControllerLabel: "cosmos-operator", + kube.ComponentLabel: "vc", + kube.NameLabel: appName(crd), + }, + ); err != nil { + return kube.TransientError(fmt.Errorf("list existing roles: %w", err)) + } + + current := ptrSlice(crs.Items) + want := BuildRoles(crd) + diffed := diff.New(current, want) + + for _, cr := range diffed.Creates() { + log.Info("Creating role", "name", cr.Name) + if err := ctrl.SetControllerReference(crd, cr, sc.client.Scheme()); err != nil { + return kube.TransientError(fmt.Errorf("set controller reference on role %q: %w", cr.Name, err)) + } + // CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference. + // This ensures we update the service with the owner reference. + if err := kube.CreateOrUpdate(ctx, sc.client, cr); err != nil { + return kube.TransientError(fmt.Errorf("create role %q: %w", cr.Name, err)) + } + } + + for _, cr := range diffed.Updates() { + log.Info("Updating role", "name", cr.Name) + if err := sc.client.Update(ctx, cr); err != nil { + return kube.TransientError(fmt.Errorf("update role %q: %w", cr.Name, err)) + } + } + + return nil +} diff --git a/internal/fullnode/role_control_test.go b/internal/fullnode/role_control_test.go new file mode 100644 index 00000000..e5f2141f --- /dev/null +++ b/internal/fullnode/role_control_test.go @@ -0,0 +1,70 @@ +package fullnode + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestRoleControl_Reconcile(t *testing.T) { + t.Parallel() + + type mockRoleClient = mockClient[*rbacv1.Role] + + ctx := context.Background() + + t.Run("happy path", func(t *testing.T) { + crd := defaultCRD() + crd.Namespace = "test" + crd.Spec.Replicas = 3 + + var mClient mockRoleClient + + control := NewRoleControl(&mClient) + err := control.Reconcile(ctx, nopReporter, &crd) + require.NoError(t, err) + + require.Len(t, mClient.GotListOpts, 2) + var listOpt client.ListOptions + for _, opt := range mClient.GotListOpts { + opt.ApplyToList(&listOpt) + } + require.Equal(t, "test", listOpt.Namespace) + require.Zero(t, listOpt.Limit) + + require.Equal(t, 1, mClient.CreateCount) // Created 1 role. + require.Equal(t, "osmosis-vc-r", mClient.LastCreateObject.Name) + require.NotEmpty(t, mClient.LastCreateObject.OwnerReferences) + require.Equal(t, crd.Name, mClient.LastCreateObject.OwnerReferences[0].Name) + require.Equal(t, "CosmosFullNode", mClient.LastCreateObject.OwnerReferences[0].Kind) + require.True(t, *mClient.LastCreateObject.OwnerReferences[0].Controller) + + mClient.ObjectList = rbacv1.RoleList{Items: []rbacv1.Role{ + { + ObjectMeta: metav1.ObjectMeta{Name: "osmosis-vc-r", Namespace: crd.Namespace}, + Rules: nil, // added to force update + }, + }} + + mClient.GotListOpts = nil // reset for next reconcile + + err = control.Reconcile(ctx, nopReporter, &crd) + require.NoError(t, err) + + require.Len(t, mClient.GotListOpts, 2) + listOpt = client.ListOptions{} + for _, opt := range mClient.GotListOpts { + opt.ApplyToList(&listOpt) + } + require.Equal(t, "test", listOpt.Namespace) + require.Zero(t, listOpt.Limit) + + require.Equal(t, 1, mClient.UpdateCount) // Updated 1 role. + + require.Zero(t, mClient.DeleteCount) // Roles are never deleted. + }) +} diff --git a/internal/fullnode/service_account_control.go b/internal/fullnode/service_account_control.go new file mode 100644 index 00000000..f2bc9119 --- /dev/null +++ b/internal/fullnode/service_account_control.go @@ -0,0 +1,64 @@ +package fullnode + +import ( + "context" + "fmt" + + cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" + "github.com/strangelove-ventures/cosmos-operator/internal/diff" + "github.com/strangelove-ventures/cosmos-operator/internal/kube" + corev1 "k8s.io/api/core/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ServiceControl creates or updates Services. +type ServiceAccountControl struct { + client Client +} + +func NewServiceAccountControl(client Client) ServiceAccountControl { + return ServiceAccountControl{ + client: client, + } +} + +// Reconcile creates or updates service accounts. +func (sc ServiceAccountControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError { + var sas corev1.ServiceAccountList + if err := sc.client.List(ctx, &sas, + client.InNamespace(crd.Namespace), + client.MatchingLabels{ + kube.ControllerLabel: "cosmos-operator", + kube.ComponentLabel: "vc", + kube.NameLabel: appName(crd), + }, + ); err != nil { + return kube.TransientError(fmt.Errorf("list existing service accounts: %w", err)) + } + + current := ptrSlice(sas.Items) + want := BuildServiceAccounts(crd) + diffed := diff.New(current, want) + + for _, sa := range diffed.Creates() { + log.Info("Creating service account", "name", sa.Name) + if err := ctrl.SetControllerReference(crd, sa, sc.client.Scheme()); err != nil { + return kube.TransientError(fmt.Errorf("set controller reference on service account %q: %w", sa.Name, err)) + } + // CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference. + // This ensures we update the service with the owner reference. + if err := kube.CreateOrUpdate(ctx, sc.client, sa); err != nil { + return kube.TransientError(fmt.Errorf("create service account %q: %w", sa.Name, err)) + } + } + + for _, sa := range diffed.Updates() { + log.Info("Updating service account", "name", sa.Name) + if err := sc.client.Update(ctx, sa); err != nil { + return kube.TransientError(fmt.Errorf("update service account %q: %w", sa.Name, err)) + } + } + + return nil +} diff --git a/internal/fullnode/service_account_control_test.go b/internal/fullnode/service_account_control_test.go new file mode 100644 index 00000000..4399fca3 --- /dev/null +++ b/internal/fullnode/service_account_control_test.go @@ -0,0 +1,70 @@ +package fullnode + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestServiceAccountControl_Reconcile(t *testing.T) { + t.Parallel() + + type mockSaClient = mockClient[*corev1.ServiceAccount] + + ctx := context.Background() + + t.Run("happy path", func(t *testing.T) { + crd := defaultCRD() + crd.Namespace = "test" + crd.Spec.Replicas = 3 + + var mClient mockSaClient + + control := NewServiceAccountControl(&mClient) + err := control.Reconcile(ctx, nopReporter, &crd) + require.NoError(t, err) + + require.Len(t, mClient.GotListOpts, 2) + var listOpt client.ListOptions + for _, opt := range mClient.GotListOpts { + opt.ApplyToList(&listOpt) + } + require.Equal(t, "test", listOpt.Namespace) + require.Zero(t, listOpt.Limit) + + require.Equal(t, 1, mClient.CreateCount) // Created 1 service account. + require.Equal(t, "osmosis-vc-sa", mClient.LastCreateObject.Name) + require.NotEmpty(t, mClient.LastCreateObject.OwnerReferences) + require.Equal(t, crd.Name, mClient.LastCreateObject.OwnerReferences[0].Name) + require.Equal(t, "CosmosFullNode", mClient.LastCreateObject.OwnerReferences[0].Kind) + require.True(t, *mClient.LastCreateObject.OwnerReferences[0].Controller) + + mClient.ObjectList = corev1.ServiceAccountList{Items: []corev1.ServiceAccount{ + { + ObjectMeta: metav1.ObjectMeta{Name: "osmosis-vc-sa", Namespace: crd.Namespace}, + AutomountServiceAccountToken: ptr(true), // added to force update + }, + }} + + mClient.GotListOpts = nil // reset for next reconcile + + err = control.Reconcile(ctx, nopReporter, &crd) + require.NoError(t, err) + + require.Len(t, mClient.GotListOpts, 2) + listOpt = client.ListOptions{} + for _, opt := range mClient.GotListOpts { + opt.ApplyToList(&listOpt) + } + require.Equal(t, "test", listOpt.Namespace) + require.Zero(t, listOpt.Limit) + + require.Equal(t, 1, mClient.UpdateCount) // Updated 1 service account. + + require.Zero(t, mClient.DeleteCount) // Service accounts are never deleted. + }) +} diff --git a/local.Dockerfile b/local.Dockerfile index 0ef37e31..45602348 100644 --- a/local.Dockerfile +++ b/local.Dockerfile @@ -13,6 +13,7 @@ RUN go mod download # Copy the go source COPY *.go . COPY api/ api/ +COPY cmd/ cmd/ COPY controllers/ controllers/ COPY internal/ internal/ diff --git a/main.go b/main.go index ae8d31d0..68f37e93 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ import ( "github.com/pkg/profile" "github.com/spf13/cobra" "github.com/spf13/viper" + opcmd "github.com/strangelove-ventures/cosmos-operator/cmd" "github.com/strangelove-ventures/cosmos-operator/controllers" "github.com/strangelove-ventures/cosmos-operator/internal/cosmos" "github.com/strangelove-ventures/cosmos-operator/internal/fullnode" @@ -106,7 +107,8 @@ func rootCmd() *cobra.Command { } // Add subcommands here - root.AddCommand(healthcheckCmd()) + root.AddCommand(opcmd.HealthCheckCmd()) + root.AddCommand(opcmd.VersionCheckCmd(scheme)) root.AddCommand(&cobra.Command{ Short: "Print the version", Use: "version", @@ -127,7 +129,7 @@ func startManager(cmd *cobra.Command, args []string) error { } }() - logger := zapLogger(logLevel, logFormat) + logger := opcmd.ZapLogger(logLevel, logFormat) defer func() { _ = logger.Sync() }() ctrl.SetLogger(zapr.NewLogger(logger))