From 32895eb90f8e60eb925ea65d0748d08c8f391448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Wed, 31 Jul 2024 20:19:16 +0200 Subject: [PATCH] feat: act --- .github/workflows/go.yml | 10 +- .github/workflows/release.yaml | 4 +- Dockerfile | 4 +- cmd/beekeeper/cmd/check.go | 6 +- cmd/beekeeper/cmd/cluster.go | 27 +- cmd/beekeeper/cmd/cmd.go | 10 +- cmd/beekeeper/cmd/metrics.go | 2 +- cmd/beekeeper/cmd/node_funder.go | 8 +- cmd/beekeeper/cmd/simulate.go | 6 +- config/config.yaml | 57 +- config/helm-cluster.yaml | 3 - config/local.yaml | 55 +- config/mainnet.yaml | 3 - config/restricted.yaml | 15 - config/staging.yaml | 3 - config/testnet-giant.yaml | 6 - config/testnet.yaml | 6 - go.mod | 81 +-- go.sum | 338 ++++------ pkg/bee/api/act.go | 63 ++ pkg/bee/api/api.go | 82 +-- pkg/bee/api/auth.go | 175 ------ pkg/bee/api/auth_test.go | 27 - pkg/bee/{debugapi => api}/debugstore.go | 2 +- pkg/bee/{debugapi => api}/node.go | 6 +- pkg/bee/{debugapi => api}/pingpong.go | 2 +- pkg/bee/{debugapi => api}/postage.go | 2 +- pkg/bee/{debugapi => api}/stake.go | 8 +- pkg/bee/client.go | 197 +++--- pkg/bee/debugapi/debugapi.go | 244 -------- pkg/bee/debugapi/errors.go | 35 -- pkg/bee/debugapi/errors_test.go | 128 ---- pkg/bee/file.go | 19 +- pkg/check/act/act.go | 265 ++++++++ pkg/check/authenticated/authenticate.go | 120 ---- pkg/check/pss/pss.go | 13 +- pkg/check/smoke/load.go | 86 ++- pkg/check/smoke/smoke.go | 36 +- pkg/check/stake/stake.go | 13 +- pkg/config/bee.go | 5 - pkg/config/check.go | 73 ++- pkg/config/cluster.go | 63 +- pkg/config/nodegroup.go | 2 - pkg/k8s/customresource/ingressroute/client.go | 8 +- pkg/k8s/ingress/client.go | 8 +- pkg/operator/operator.go | 2 +- pkg/orchestration/cluster.go | 63 +- pkg/orchestration/k8s/cluster.go | 106 +--- pkg/orchestration/k8s/helpers.go | 25 +- pkg/orchestration/k8s/node.go | 584 +----------------- pkg/orchestration/k8s/node_orchestrator.go | 453 ++++++++++++++ pkg/orchestration/k8s/nodegroup.go | 138 ++--- pkg/orchestration/node.go | 36 +- pkg/orchestration/nodegroup.go | 29 +- pkg/orchestration/notset/bee.go | 12 + pkg/swap/geth.go | 5 +- pkg/test/auth.go | 11 - pkg/test/case.go | 4 - pkg/test/node.go | 4 - scripts/suite.sh | 28 +- version.go | 2 +- 61 files changed, 1653 insertions(+), 2175 deletions(-) delete mode 100644 config/restricted.yaml create mode 100644 pkg/bee/api/act.go delete mode 100644 pkg/bee/api/auth.go delete mode 100644 pkg/bee/api/auth_test.go rename pkg/bee/{debugapi => api}/debugstore.go (96%) rename pkg/bee/{debugapi => api}/node.go (98%) rename pkg/bee/{debugapi => api}/pingpong.go (96%) rename pkg/bee/{debugapi => api}/postage.go (99%) rename pkg/bee/{debugapi => api}/stake.go (84%) delete mode 100644 pkg/bee/debugapi/debugapi.go delete mode 100644 pkg/bee/debugapi/errors.go delete mode 100644 pkg/bee/debugapi/errors_test.go create mode 100644 pkg/check/act/act.go delete mode 100644 pkg/check/authenticated/authenticate.go create mode 100644 pkg/orchestration/k8s/node_orchestrator.go delete mode 100644 pkg/test/auth.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 007ac5b00..77fd43edb 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,18 +11,18 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Setup Go if: matrix.os == 'ubuntu-latest' - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: cache: false go-version-file: go.mod - name: Setup Go if: matrix.os == 'macos-latest' || matrix.os == 'windows-latest' - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: cache: true go-version-file: go.mod @@ -32,9 +32,9 @@ jobs: run: git config --global core.autocrlf false - name: Lint if: matrix.os == 'ubuntu-latest' - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v4 with: - version: v1.54.2 + version: v1.56.2 args: --timeout 10m skip-cache: false - name: Vet diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 929a91179..0da04c60b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Run GoReleaser diff --git a/Dockerfile b/Dockerfile index 1fbe5a46a..b5c2e0f21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21 AS build +FROM golang:1.22 AS build WORKDIR /src # enable modules caching in separate layer @@ -8,7 +8,7 @@ COPY . ./ RUN make binary -FROM debian:12.1-slim +FROM debian:12.5-slim ENV DEBIAN_FRONTEND noninteractive diff --git a/cmd/beekeeper/cmd/check.go b/cmd/beekeeper/cmd/check.go index 56855e9ce..eeda92ce1 100644 --- a/cmd/beekeeper/cmd/check.go +++ b/cmd/beekeeper/cmd/check.go @@ -41,7 +41,11 @@ func (c *command) initCheckCmd() (err error) { } // setup cluster - cluster, err := c.setupCluster(ctx, c.globalConfig.GetString(optionNameClusterName), c.config, c.globalConfig.GetBool(optionNameCreateCluster)) + cluster, err := c.setupCluster(ctx, + c.globalConfig.GetString(optionNameClusterName), + c.config, + c.globalConfig.GetBool(optionNameCreateCluster), + ) if err != nil { return fmt.Errorf("cluster setup: %w", err) } diff --git a/cmd/beekeeper/cmd/cluster.go b/cmd/beekeeper/cmd/cluster.go index 47e7b65c1..859049832 100644 --- a/cmd/beekeeper/cmd/cluster.go +++ b/cmd/beekeeper/cmd/cluster.go @@ -119,6 +119,9 @@ func (c *command) setupCluster(ctx context.Context, clusterName string, cfg *con var fundOpts orchestration.FundingOptions if startCluster { + if clusterConfig.IsUsingStaticEndpoints() { + return nil, errors.New("static endpoints are not supported for starting the cluster") + } if chainNodeEndpoint = c.globalConfig.GetString(optionNameChainNodeEndpoint); chainNodeEndpoint == "" { return nil, errors.New("chain node endpoint (geth-url) not provided") } @@ -182,13 +185,14 @@ func ensureFundingDefaults(fundOpts orchestration.FundingOptions, log logging.Lo func configureCluster(clusterConfig config.Cluster, c *command) orchestration.Cluster { clusterOpts := clusterConfig.Export() - clusterOpts.K8SClient = c.k8sClient clusterOpts.SwapClient = c.swapClient + clusterOpts.K8SClient = c.k8sClient return orchestrationK8S.NewCluster(clusterConfig.GetName(), clusterOpts, c.log) } func setupNodes(ctx context.Context, clusterConfig config.Cluster, cfg *config.Config, bootnode bool, cluster orchestration.Cluster, startCluster bool, bootnodesIn string, nodeResultCh chan nodeResult) (fundAddresses []string, bootnodesOut string, err error) { var nodeCount uint32 + for ngName, v := range clusterConfig.GetNodeGroups() { if (v.Mode != bootnodeMode && bootnode) || (v.Mode == bootnodeMode && !bootnode) { @@ -220,6 +224,17 @@ func setupNodes(ctx context.Context, clusterConfig config.Cluster, cfg *config.C return nil, "", fmt.Errorf("get node group: %w", err) } + if clusterConfig.IsUsingStaticEndpoints() { + for nodeName, endpoint := range v.GetEndpoints() { + beeOpt := orchestration.WithURL(endpoint.APIURL) + nodeCount++ + go setupOrAddNode(ctx, false, ng, nodeName, orchestration.NodeOptions{ + Config: &bConfig, + }, nodeResultCh, beeOpt) + } + continue + } + for i, node := range v.Nodes { // set node name nodeName := fmt.Sprintf("%s-%d", ngName, i) @@ -228,7 +243,6 @@ func setupNodes(ctx context.Context, clusterConfig config.Cluster, cfg *config.C } var nodeOpts orchestration.NodeOptions - if bootnode { // set bootnodes bConfig.Bootnodes = fmt.Sprintf(node.Bootnodes, clusterConfig.GetNamespace()) // TODO: improve bootnode management, support more than 2 bootnodes @@ -237,9 +251,8 @@ func setupNodes(ctx context.Context, clusterConfig config.Cluster, cfg *config.C } else { nodeOpts = setupNodeOptions(node, nil) } - nodeCount++ - go setupOrAddNode(ctx, startCluster, ng, nodeName, nodeOpts, nodeResultCh) + go setupOrAddNode(ctx, startCluster, ng, nodeName, nodeOpts, nodeResultCh, orchestration.WithNoOptions()) } if len(v.Nodes) == 0 && !bootnode { @@ -247,7 +260,7 @@ func setupNodes(ctx context.Context, clusterConfig config.Cluster, cfg *config.C // set node name nodeName := fmt.Sprintf("%s-%d", ngName, i) nodeCount++ - go setupOrAddNode(ctx, startCluster, ng, nodeName, orchestration.NodeOptions{}, nodeResultCh) + go setupOrAddNode(ctx, startCluster, ng, nodeName, orchestration.NodeOptions{}, nodeResultCh, orchestration.WithNoOptions()) } } } @@ -267,12 +280,12 @@ func setupNodes(ctx context.Context, clusterConfig config.Cluster, cfg *config.C return fundAddresses, bootnodesOut, nil } -func setupOrAddNode(ctx context.Context, startCluster bool, ng orchestration.NodeGroup, nName string, nodeOpts orchestration.NodeOptions, ch chan<- nodeResult) { +func setupOrAddNode(ctx context.Context, startCluster bool, ng orchestration.NodeGroup, nName string, nodeOpts orchestration.NodeOptions, ch chan<- nodeResult, beeOpt orchestration.BeeClientOption) { if startCluster { ethAddress, err := ng.SetupNode(ctx, nName, nodeOpts) ch <- nodeResult{ethAddress: ethAddress, err: err} } else { - err := ng.AddNode(ctx, nName, nodeOpts) + err := ng.AddNode(ctx, nName, nodeOpts, beeOpt) ch <- nodeResult{err: err} } } diff --git a/cmd/beekeeper/cmd/cmd.go b/cmd/beekeeper/cmd/cmd.go index 71b22bd0d..4e1ab0044 100644 --- a/cmd/beekeeper/cmd/cmd.go +++ b/cmd/beekeeper/cmd/cmd.go @@ -36,6 +36,9 @@ const ( optionNameTracingHost = "tracing-host" optionNameTracingPort = "tracing-port" optionNameTracingServiceName = "tracing-service-name" + optionNameEnableK8S = "enable-k8s" + optionNameInCluster = "in-cluster" + optionNameKubeconfig = "kubeconfig" ) func init() { @@ -309,10 +312,9 @@ func (c *command) preRunE(cmd *cobra.Command, args []string) (err error) { } func (c *command) setK8S() (err error) { - if c.globalConfig.GetBool("enable-k8s") { - - inCluster := c.globalConfig.GetBool("in-cluster") - kubeconfigPath := c.globalConfig.GetString("kubeconfig") + if c.globalConfig.GetBool(optionNameEnableK8S) { + inCluster := c.globalConfig.GetBool(optionNameInCluster) + kubeconfigPath := c.globalConfig.GetString(optionNameKubeconfig) options := []k8s.ClientOption{ k8s.WithLogger(c.log), diff --git a/cmd/beekeeper/cmd/metrics.go b/cmd/beekeeper/cmd/metrics.go index 9a99941b5..768da16de 100644 --- a/cmd/beekeeper/cmd/metrics.go +++ b/cmd/beekeeper/cmd/metrics.go @@ -12,7 +12,7 @@ import ( // newMetricsPusher returns a new metrics pusher and a cleanup function. func newMetricsPusher(pusherAddress, job string, logger logging.Logger) (*push.Pusher, func()) { metricsPusher := push.New(pusherAddress, job) - metricsPusher.Format(expfmt.FmtText) + metricsPusher.Format(expfmt.NewFormat(expfmt.TypeTextPlain)) killC := make(chan struct{}) var wg sync.WaitGroup diff --git a/cmd/beekeeper/cmd/node_funder.go b/cmd/beekeeper/cmd/node_funder.go index 37cabc873..ebdf83ab6 100644 --- a/cmd/beekeeper/cmd/node_funder.go +++ b/cmd/beekeeper/cmd/node_funder.go @@ -133,14 +133,14 @@ func (nf *nodeLister) List(ctx context.Context, namespace string) (nodes []funde return nil, fmt.Errorf("namespace not provided") } - ingressHosts, err := nf.k8sClient.Ingress.ListDebugNodesHosts(ctx, namespace) + ingressHosts, err := nf.k8sClient.Ingress.ListAPINodesHosts(ctx, namespace) if err != nil { - return nil, fmt.Errorf("list ingress debug nodes hosts: %s", err.Error()) + return nil, fmt.Errorf("list ingress api nodes hosts: %s", err.Error()) } - ingressRouteHosts, err := nf.k8sClient.IngressRoute.ListDebugNodesHosts(ctx, namespace) + ingressRouteHosts, err := nf.k8sClient.IngressRoute.ListAPINodesHosts(ctx, namespace) if err != nil { - return nil, fmt.Errorf("list ingress route debug nodes hosts: %s", err.Error()) + return nil, fmt.Errorf("list ingress route api nodes hosts: %s", err.Error()) } ingressHosts = append(ingressHosts, ingressRouteHosts...) diff --git a/cmd/beekeeper/cmd/simulate.go b/cmd/beekeeper/cmd/simulate.go index 331b02c43..96afba68d 100644 --- a/cmd/beekeeper/cmd/simulate.go +++ b/cmd/beekeeper/cmd/simulate.go @@ -41,7 +41,11 @@ func (c *command) initSimulateCmd() (err error) { } // setup cluster - cluster, err := c.setupCluster(ctx, c.globalConfig.GetString(optionNameClusterName), c.config, c.globalConfig.GetBool(optionNameCreateCluster)) + cluster, err := c.setupCluster(ctx, + c.globalConfig.GetString(optionNameClusterName), + c.config, + c.globalConfig.GetBool(optionNameCreateCluster), + ) if err != nil { return fmt.Errorf("cluster setup: %w", err) } diff --git a/config/config.yaml b/config/config.yaml index da46699ab..88d5f6622 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -6,12 +6,10 @@ clusters: name: bee namespace: beekeeper disable-namespace: false + use-static-endpoints: false api-domain: staging.internal api-insecure-tls: true api-scheme: https - debug-api-domain: staging.internal - debug-api-insecure-tls: true - debug-api-scheme: https admin-password: test funding: eth: 0.1 @@ -19,6 +17,10 @@ clusters: node-groups: bootnode: mode: bootnode + endpoints: + - name: bootnode-0 + api-url: https://bootnode-0.beekeeper.testnet.internal + debug-api-url: https://bootnode-0-debug.beekeeper.testnet.internal bee-config: bootnode config: default nodes: @@ -41,6 +43,16 @@ clusters: bee-config: default config: default count: 3 + endpoints: + - name: bee-0 + api-url: https://bee-0.beekeeper.testnet.internal + debug-api-url: https://bee-0-debug.beekeeper.testnet.internal + - name: bee-1 + api-url: https://bee-1.beekeeper.testnet.internal + debug-api-url: https://bee-1-debug.beekeeper.testnet.internal + - name: bee-2 + api-url: https://bee-2.beekeeper.testnet.internal + debug-api-url: https://bee-2-debug.beekeeper.testnet.internal # nodes: # - clef: # key: '{"address":"4558ab6d518bf60b813eeba3077eed986027c5da","crypto":{"cipher":"aes-128-ctr","ciphertext":"1bbeffa438a8b8fd592a46323fe0168d8d8e2625085ca8550023b5c0bd48a126","cipherparams":{"iv":"3f369a742a465aaf5e3025864639421a"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":64,"p":1,"r":8,"salt":"4c2c1fde6491213ea3c6021c82a70327bc0a056569a6e7c2a3fda9e486c0f090"},"mac":"f733b77f675acf0539e7d3d60735408c6efd43893dc0d5b0f94124b0197f89dd"},"id":"1e526dc4-60bd-4c4d-897d-f284806abf2b","version":3}' @@ -56,6 +68,16 @@ clusters: bee-config: light-node config: light-node count: 3 + endpoints: + - name: light-0 + api-url: https://light-0.beekeeper.testnet.internal + debug-api-url: https://light-0-debug.beekeeper.testnet.internal + - name: light-1 + api-url: https://light-1.beekeeper.testnet.internal + debug-api-url: https://light-1-debug.beekeeper.testnet.internal + - name: light-2 + api-url: https://light-2.beekeeper.testnet.internal + debug-api-url: https://light-2-debug.beekeeper.testnet.internal # node-groups defines node groups that can be registered in the cluster # node-groups may inherit it's configuration from already defined node-group and override specific fields from it @@ -78,7 +100,6 @@ node-groups: nginx.ingress.kubernetes.io/session-cookie-path: "default" nginx.ingress.kubernetes.io/ssl-redirect: "true" ingress-class: "nginx-internal" - ingress-debug-class: "nginx-internal" labels: app.kubernetes.io/component: "node" app.kubernetes.io/name: "bee" @@ -115,8 +136,6 @@ bee-configs: db-block-cache-capacity: 33554432 db-write-buffer-size: 33554432 db-disable-seeks-compaction: false - debug-api-addr: ":1635" - debug-api-enable: true full-node: true nat-addr: "" mainnet: false @@ -145,6 +164,7 @@ bee-configs: verbosity: 5 welcome-message: "Welcome to the Swarm, you are Bee-ing connected!" allow-private-cidrs: true + withdrawal-addresses-whitelist: "0xec44cb15b1b033e74d55ac5d0e24d861bde54532" bootnode: _inherit: "default" bootnode-mode: true @@ -215,6 +235,16 @@ checks: options: timeout: 5m type: pingpong + act: + options: + file-name: act + file-size: 1024 + postage-depth: 20 + postage-amount: 420000000 + postage-label: act-label + seed: 0 + timeout: 5m + type: act withdraw: options: target-address: 0xec44cb15b1b033e74d55ac5d0e24d861bde54532 @@ -315,9 +345,12 @@ checks: nodes-sync-wait: 1m duration: 12h downloader-count: 3 - upload-group: + uploader-count: 3 + max-storage-radius: 2 + storage-radius-check-wait: 5m + upload-groups: - gateway - download-group: + download-groups: - bee - light timeout: 12h @@ -337,13 +370,6 @@ checks: postage-depth: 17 postage-topup-amount: 100 postage-new-depth: 18 - authenticate: - type: authenticate - timeout: 5m - options: - role: consumer - admin-password: test - restricted-group-name: restricted stake: type: stake timeout: 5m @@ -369,7 +395,6 @@ checks: data-size: type: redundancy - # simulations defines simulations Beekeeper can execute against the cluster # type filed allows defining same simulation with different names and options simulations: diff --git a/config/helm-cluster.yaml b/config/helm-cluster.yaml index 84c936f49..ff12eb752 100644 --- a/config/helm-cluster.yaml +++ b/config/helm-cluster.yaml @@ -8,9 +8,6 @@ clusters: api-domain: staging.internal api-insecure-tls: true api-scheme: https - debug-api-domain: staging.internal - debug-api-insecure-tls: true - debug-api-scheme: https node-groups: bee: bee-config: default diff --git a/config/local.yaml b/config/local.yaml index a4b0c5c31..d2a1d924e 100644 --- a/config/local.yaml +++ b/config/local.yaml @@ -7,8 +7,6 @@ clusters: disable-namespace: true api-domain: localhost api-scheme: http - debug-api-domain: localhost - debug-api-scheme: http admin-password: test funding: eth: 0.1 @@ -45,18 +43,13 @@ clusters: bee: bee-config: bee-local-dns config: local-dns - count: 2 + count: 3 mode: node light: bee-config: bee-local-light config: local-light count: 2 mode: node - restricted: - mode: node - bee-config: bee-local-restricted - config: bee-local-restricted - count: 1 local-clef: _inherit: "local" node-groups: @@ -119,7 +112,6 @@ node-groups: nginx.ingress.kubernetes.io/session-cookie-path: "default" nginx.ingress.kubernetes.io/ssl-redirect: "true" ingress-class: "traefik" - ingress-debug-class: "traefik" labels: app.kubernetes.io/component: "node" app.kubernetes.io/name: "bee" @@ -143,8 +135,6 @@ node-groups: _inherit: "local" local-light: _inherit: "local" - bee-local-restricted: - _inherit: "local" # bee-configs defines Bee configuration that can be assigned to node-groups bee-configs: @@ -163,12 +153,10 @@ bee-configs: db-block-cache-capacity: 33554432 db-write-buffer-size: 33554432 db-disable-seeks-compaction: false - debug-api-addr: ":1635" - debug-api-enable: true full-node: true mainnet: false nat-addr: "" - network-id: 12345 + network-id: 0 p2p-addr: ":1634" p2p-ws-enable: false password: "beekeeper" @@ -177,24 +165,21 @@ bee-configs: payment-tolerance-percent: 25 storage-incentives-enable: true postage-stamp-start-block: 1 - postage-stamp-address: "0x538e6de1d876bbcd5667085257bc92f7c808a0f3" - price-oracle-address: "0xfc28330f1ece0ef2371b724e0d19c1ee60b728b2" - staking-address: "0xc0332d319b73cfeed89511fe1a83add141bd6f12" - redistribution-address: "0x56e442f99cafd7c890c404c1f8c16d38a569e41a" + postage-stamp-address: "0x657241f4494A2F15Ba75346E691d753A978C72Df" + price-oracle-address: "0x5aFE06fcC0855a76a15c3544b0886EDBE3294d62" + staking-address: "0xfc28330f1ecE0ef2371B724E0D19c1EE60B728b2" + redistribution-address: "0x09Ad42a7d020244920309FfA14EA376dd2D3b7d5" resolver-options: "" - restricted: false - token-encryption-key: "" - admin-password: "" chequebook-enable: true swap-enable: true swap-endpoint: "ws://geth-swap:8546" - swap-factory-address: "0x09ad42a7d020244920309ffa14ea376dd2d3b7d5" + swap-factory-address: "0xdD661f2500bA5831e3d1FEbAc379Ea1bF80773Ac" swap-initial-deposit: 500000000000000000 verbosity: 5 welcome-message: "Welcome to the Swarm, this is a local cluster!" warmup-time: 0s allow-private-cidrs: true - withdrawal-addresses-whitelist: 0xec44cb15b1b033e74d55ac5d0e24d861bde54532 + withdrawal-addresses-whitelist: "0xec44cb15b1b033e74d55ac5d0e24d861bde54532" bootnode-local: _inherit: "bee-local" @@ -214,12 +199,6 @@ bee-configs: _inherit: "bee-local" clef-signer-enable: true clef-signer-endpoint: "http://localhost:8550" - bee-local-restricted: - _inherit: "bee-local" - bootnode: /dnsaddr/localhost - restricted: true - token-encryption-key: testtest - admin-password: $2a$12$Ltg3M2W53Xv9wwJ2.iAv4e4gWELrrr8D2dYat7wNdY2xArdmOSL1i bootnode-local-clef: _inherit: "bee-local" clef-signer-enable: true @@ -235,6 +214,15 @@ bee-configs: # CI checks checks: + ci-act: + options: + file-size: 1024 + postage-depth: 20 + postage-amount: 420000000 + postage-label: act-label + seed: 0 + timeout: 5m + type: act ci-full-connectivity: timeout: 5m type: full-connectivity @@ -372,20 +360,13 @@ checks: postage-depth: 17 postage-topup-amount: 100 postage-new-depth: 18 - ci-authenticate: - type: authenticate - timeout: 5m - options: - role: consumer - admin-password: test - restricted-group-name: restricted ci-stake: type: stake timeout: 5m options: amount: 1000000000000000000 insufficient-amount: 102400 - contract-addr: "0xc0332d319b73cfeed89511fe1a83add141bd6f12" + contract-addr: "0xfc28330f1ecE0ef2371B724E0D19c1EE60B728b2" private-key: "4663c222787e30c1994b59044aa5045377a6e79193a8ead88293926b535c722d" geth-url: "http://geth-swap.localhost" geth-chain-id: 12345 diff --git a/config/mainnet.yaml b/config/mainnet.yaml index e2e868b74..e3b1c9cee 100644 --- a/config/mainnet.yaml +++ b/config/mainnet.yaml @@ -9,9 +9,6 @@ clusters: api-domain: gateway.ethswarm.org api-insecure-tls: true api-scheme: https - debug-api-domain: bee-gateway.mainnet.internal - debug-api-insecure-tls: true - debug-api-scheme: https funding: eth: 0.1 gbzz: 2.0 diff --git a/config/restricted.yaml b/config/restricted.yaml deleted file mode 100644 index ef0f995c9..000000000 --- a/config/restricted.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# bee config for restricted nodes -bee-configs: - restricted: - _inherit: default - restricted: true - token-encryption-key: testtest - admin-password: $2a$12$Ltg3M2W53Xv9wwJ2.iAv4e4gWELrrr8D2dYat7wNdY2xArdmOSL1i - -# node groups for restricted nodes -node-groups: - restricted: - _inherit: default - image: ethersphere/bee:latest - image-pull-policy: Always - persistence-enabled: true diff --git a/config/staging.yaml b/config/staging.yaml index 23e58ea9e..f0c9e18c6 100644 --- a/config/staging.yaml +++ b/config/staging.yaml @@ -9,9 +9,6 @@ clusters: api-domain: staging.ethswarm.org api-insecure-tls: true api-scheme: https - debug-api-domain: staging.internal - debug-api-insecure-tls: true - debug-api-scheme: https funding: eth: 0.1 gbzz: 2.0 diff --git a/config/testnet-giant.yaml b/config/testnet-giant.yaml index a44f94368..8f21f8c43 100644 --- a/config/testnet-giant.yaml +++ b/config/testnet-giant.yaml @@ -9,9 +9,6 @@ clusters: api-domain: staging.internal api-insecure-tls: true api-scheme: https - debug-api-domain: staging.internal - debug-api-insecure-tls: true - debug-api-scheme: https funding: eth: 0.1 gbzz: 2.0 @@ -51,7 +48,6 @@ node-groups: nginx.ingress.kubernetes.io/session-cookie-path: "default" nginx.ingress.kubernetes.io/ssl-redirect: "true" ingress-class: "nginx-internal" - ingress-debug-class: "nginx-internal" labels: app.kubernetes.io/component: "node" app.kubernetes.io/name: "bee" @@ -88,8 +84,6 @@ bee-configs: db-block-cache-capacity: 33554432 db-write-buffer-size: 33554432 db-disable-seeks-compaction: false - debug-api-addr: ":1635" - debug-api-enable: true full-node: true mainnet: false nat-addr: "" diff --git a/config/testnet.yaml b/config/testnet.yaml index d5b947475..b76bef31f 100644 --- a/config/testnet.yaml +++ b/config/testnet.yaml @@ -9,9 +9,6 @@ clusters: api-domain: staging.internal api-insecure-tls: true api-scheme: https - debug-api-domain: staging.internal - debug-api-insecure-tls: true - debug-api-scheme: https funding: eth: 0.1 gbzz: 2.0 @@ -48,7 +45,6 @@ node-groups: nginx.ingress.kubernetes.io/session-cookie-path: "default" nginx.ingress.kubernetes.io/ssl-redirect: "true" ingress-class: "nginx-internal" - ingress-debug-class: "nginx-internal" labels: app.kubernetes.io/component: "node" app.kubernetes.io/name: "bee" @@ -90,8 +86,6 @@ bee-configs: db-block-cache-capacity: 33554432 db-write-buffer-size: 33554432 db-disable-seeks-compaction: false - debug-api-addr: ":1635" - debug-api-enable: true full-node: true nat-addr: "" mainnet: false diff --git a/go.mod b/go.mod index a8cb54890..2583800be 100644 --- a/go.mod +++ b/go.mod @@ -1,28 +1,30 @@ module github.com/ethersphere/beekeeper -go 1.21 +go 1.22 + +toolchain go1.22.0 replace github.com/codahale/hdrhistogram => github.com/HdrHistogram/hdrhistogram-go v1.1.2 require ( - github.com/ethereum/go-ethereum v1.13.4 + github.com/ethereum/go-ethereum v1.14.3 github.com/ethersphere/bee v1.18.3-0.20240221015611-5de732c26957 github.com/ethersphere/bmt v0.1.4 github.com/ethersphere/ethproxy v0.0.5 github.com/ethersphere/node-funder v0.1.1 github.com/go-git/go-billy/v5 v5.5.0 github.com/go-git/go-git/v5 v5.11.0 - github.com/google/uuid v1.3.0 - github.com/gorilla/websocket v1.5.0 + github.com/google/uuid v1.6.0 + github.com/gorilla/websocket v1.5.1 github.com/opentracing/opentracing-go v1.2.0 - github.com/prometheus/client_golang v1.14.0 - github.com/prometheus/common v0.42.0 - github.com/sirupsen/logrus v1.9.0 - github.com/spf13/cobra v1.7.0 - github.com/spf13/viper v1.15.0 + github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/common v0.50.0 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.8.0 + github.com/spf13/viper v1.18.2 github.com/uber/jaeger-client-go v2.30.0+incompatible - golang.org/x/crypto v0.17.0 - golang.org/x/sync v0.3.0 + golang.org/x/crypto v0.22.0 + golang.org/x/sync v0.7.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.22.16 k8s.io/apimachinery v0.22.16 @@ -35,38 +37,37 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd v0.22.3 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudflare/circl v1.3.3 // indirect + github.com/cloudflare/circl v1.3.7 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect - github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect + github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/ethereum/c-kzg-4844 v0.3.1 // indirect + github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethersphere/go-sw3-abi v0.6.5 // indirect github.com/evanphx/json-patch v4.11.0+incompatible // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-chi/chi v1.5.4 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-logr/logr v1.2.3 // indirect - github.com/go-ole/go-ole v1.2.5 // indirect - github.com/go-stack/stack v1.8.1 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/googleapis/gnostic v0.5.5 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/holiman/uint256 v1.2.3 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect @@ -78,7 +79,6 @@ require ( github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-libp2p v0.30.0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.55 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -95,20 +95,22 @@ require ( github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.4.1 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/shirou/gopsutil v3.21.5+incompatible // indirect github.com/skeema/knownhosts v1.2.1 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/spf13/afero v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/subosito/gotenv v1.4.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.11 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect @@ -117,17 +119,18 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect go.uber.org/atomic v1.11.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.20.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index a4939b1a8..8561d7799 100644 --- a/go.sum +++ b/go.sum @@ -3,38 +3,23 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -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/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -72,8 +57,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 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/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd v0.22.3 h1:kYNaWFvOw6xvqP0vR20RP1Zq1DVMBxEO8QN5d1/EfNg= github.com/btcsuite/btcd v0.22.3/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= @@ -90,37 +75,36 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR 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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -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/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= -github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +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 v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= +github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +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/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A= -github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= @@ -134,16 +118,12 @@ github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/El github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg= -github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.13.4 h1:25HJnaWVg3q1O7Z62LaaI6S9wVq8QCw3K88g8wEzrcM= -github.com/ethereum/go-ethereum v1.13.4/go.mod h1:I0U5VewuuTzvBtVzKo7b3hJzDhXOUtn9mJW7SsIPB0Q= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.14.3 h1:5zvnAqLtnCZrU9uod1JCvHWJbPMURzYFHfc2eHz4PHA= +github.com/ethereum/go-ethereum v1.14.3/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= github.com/ethersphere/bee v1.18.3-0.20240221015611-5de732c26957 h1:VCgb+6EEHVhWU4v6zHonYaUf0HV61FYYZ6eZN9Ymm2g= github.com/ethersphere/bee v1.18.3-0.20240221015611-5de732c26957/go.mod h1:PIgkGa0N++OQRPp9j/f1Jr8k0M6Xzv4tgcBiwKXtk9s= github.com/ethersphere/bmt v0.1.4 h1:+rkWYNtMgDx6bkNqGdWu+U9DgGI1rRZplpSW3YhBr1Q= @@ -156,18 +136,22 @@ github.com/ethersphere/node-funder v0.1.1 h1:Y1gzbnmZV2jCecdZuUvAsFeXTWpEFofrIT4 github.com/ethersphere/node-funder v0.1.1/go.mod h1:pHYJyxpyhuAoI5c4ReaLn1CnuCG5RmcLeU7pGDzlfrI= github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= -github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= +github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= @@ -188,8 +172,9 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= @@ -197,8 +182,6 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9 github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -216,14 +199,11 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf 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= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -231,11 +211,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -245,47 +224,34 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -297,17 +263,16 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 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/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= -github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= -github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= 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/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= @@ -329,13 +294,12 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4 github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY= github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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= @@ -363,8 +327,6 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= @@ -433,25 +395,25 @@ github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ= +github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -461,31 +423,35 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc= github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= 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.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -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.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/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.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -502,11 +468,10 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -531,9 +496,7 @@ github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -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.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= gitlab.com/nolash/go-mockbytes v0.0.7 h1:9XVFpEfY67kGBVJve3uV19kzqORdlo7V+q09OE6Yo54= @@ -542,12 +505,12 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 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= @@ -557,14 +520,12 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -575,8 +536,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-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= 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= @@ -589,7 +550,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -598,12 +558,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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= @@ -616,7 +574,6 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -626,18 +583,8 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -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= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -645,34 +592,27 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -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.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -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/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -699,38 +639,26 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-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-20210303074136-134d130e1a04/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -738,14 +666,13 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -757,8 +684,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb 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.0.0-20210723032227-1f47c861a9ac/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/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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= @@ -789,30 +716,13 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -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-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= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -826,22 +736,12 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -861,42 +761,16 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -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/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= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 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= @@ -906,11 +780,10 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= @@ -948,7 +821,6 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.22.16 h1:JH5n0vS/IiHr6pe8erxpk3z3dRerMGP2HNHtLVJz38s= k8s.io/api v0.22.16/go.mod h1:EVa5pIbcAH9IJFyfQex8+afS++7kuDFzb89JCiu94mQ= k8s.io/apimachinery v0.22.16 h1:t6va6O07rpgP0FPOR8usGpgtrXUwnatpbTdtsxjwCXU= diff --git a/pkg/bee/api/act.go b/pkg/bee/api/act.go new file mode 100644 index 000000000..404f8591b --- /dev/null +++ b/pkg/bee/api/act.go @@ -0,0 +1,63 @@ +package api + +import ( + "context" + "io" + "net/http" + "net/url" + + "github.com/ethersphere/bee/pkg/swarm" +) + +type ActService service + +type ActUploadResponse struct { + Reference swarm.Address `json:"reference"` + HistoryAddress swarm.Address +} + +type ActGranteesResponse struct { + Reference swarm.Address `json:"ref"` + HistoryAddress swarm.Address `json:"historyref"` +} + +func (a *ActService) Download(ctx context.Context, addr swarm.Address, opts *DownloadOptions) (resp io.ReadCloser, err error) { + return a.client.requestData(ctx, http.MethodGet, "/"+apiVersion+"/bzz/"+addr.String()+"/", nil, opts) +} + +func (a *ActService) Upload(ctx context.Context, name string, data io.Reader, o UploadOptions) (ActUploadResponse, error) { + var resp ActUploadResponse + h := http.Header{} + h.Add(postageStampBatchHeader, o.BatchID) + h.Add("swarm-deferred-upload", "true") + h.Add("content-type", "application/octet-stream") + h.Add("Swarm-Act", "true") + h.Add(swarmPinHeader, "true") + historyParser := func(h http.Header) { + resp.HistoryAddress, _ = swarm.ParseHexAddress(h.Get("Swarm-Act-History-Address")) + } + err := a.client.requestWithHeader(ctx, http.MethodPost, "/"+apiVersion+"/bzz?"+url.QueryEscape("name="+name), h, data, &resp, historyParser) + return resp, err +} + +func (a *ActService) AddGrantees(ctx context.Context, data io.Reader, o UploadOptions) (ActGranteesResponse, error) { + var resp ActGranteesResponse + h := http.Header{} + h.Add(postageStampBatchHeader, o.BatchID) + h.Add(swarmActHistoryAddress, o.ActHistoryAddress.String()) + err := a.client.requestWithHeader(ctx, http.MethodPost, "/"+apiVersion+"/grantee", h, data, &resp) + return resp, err +} + +func (a *ActService) GetGrantees(ctx context.Context, addr swarm.Address) (resp io.ReadCloser, err error) { + return a.client.requestData(ctx, http.MethodGet, "/"+apiVersion+"/grantee/"+addr.String(), nil, nil) +} + +func (a *ActService) PatchGrantees(ctx context.Context, data io.Reader, addr swarm.Address, haddr swarm.Address, batchID string) (ActGranteesResponse, error) { + var resp ActGranteesResponse + h := http.Header{} + h.Add("swarm-postage-batch-id", batchID) + h.Add("swarm-act-history-address", haddr.String()) + err := a.client.requestWithHeader(ctx, http.MethodPatch, "/"+apiVersion+"/grantee/"+addr.String(), h, data, &resp) + return resp, err +} diff --git a/pkg/bee/api/api.go b/pkg/bee/api/api.go index 6e488dc12..4a86d5e5e 100644 --- a/pkg/bee/api/api.go +++ b/pkg/bee/api/api.go @@ -11,14 +11,19 @@ import ( "strconv" "strings" + "github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/beekeeper" ) const ( apiVersion = "v1" - contentType = "application/json; charset=utf-8" + contentType = "application/json, text/plain, */*; charset=utf-8" postageStampBatchHeader = "Swarm-Postage-Batch-Id" deferredUploadHeader = "Swarm-Deferred-Upload" + swarmAct = "Swarm-Act" + swarmActHistoryAddress = "Swarm-Act-History-Address" + swarmActPublisher = "Swarm-Act-Publisher" + swarmActTimestamp = "Swarm-Act-Timestamp" swarmPinHeader = "Swarm-Pin" swarmTagHeader = "Swarm-Tag" swarmCacheDownloadHeader = "Swarm-Cache" @@ -31,9 +36,9 @@ var userAgent = "beekeeper/" + beekeeper.Version type Client struct { httpClient *http.Client // HTTP client must handle authentication implicitly. service service // Reuse a single struct instead of allocating one for each service on the heap. - restricted bool // Services that API provides. + Act *ActService Bytes *BytesService Chunks *ChunksService Files *FilesService @@ -43,13 +48,15 @@ type Client struct { PSS *PSSService SOC *SOCService Stewardship *StewardshipService - Auth *AuthService + Node *NodeService + PingPong *PingPongService + Postage *PostageService + Stake *StakingService } // ClientOptions holds optional parameters for the Client. type ClientOptions struct { HTTPClient *http.Client - Restricted bool } // NewClient constructs a new Client. @@ -62,8 +69,6 @@ func NewClient(baseURL *url.URL, o *ClientOptions) (c *Client) { } c = newClient(httpClientWithTransport(baseURL, o.HTTPClient)) - c.restricted = o.Restricted - return } @@ -72,6 +77,7 @@ func NewClient(baseURL *url.URL, o *ClientOptions) (c *Client) { func newClient(httpClient *http.Client) (c *Client) { c = &Client{httpClient: httpClient} c.service.client = c + c.Act = (*ActService)(&c.service) c.Bytes = (*BytesService)(&c.service) c.Chunks = (*ChunksService)(&c.service) c.Files = (*FilesService)(&c.service) @@ -81,7 +87,10 @@ func newClient(httpClient *http.Client) (c *Client) { c.PSS = (*PSSService)(&c.service) c.SOC = (*SOCService)(&c.service) c.Stewardship = (*StewardshipService)(&c.service) - c.Auth = (*AuthService)(&c.service) + c.Node = (*NodeService)(&c.service) + c.PingPong = (*PingPongService)(&c.service) + c.Postage = (*PostageService)(&c.service) + c.Stake = (*StakingService)(&c.service) return c } @@ -140,14 +149,6 @@ func (c *Client) request(ctx context.Context, method, path string, body io.Reade } req.Header.Set("Accept", contentType) - if c.restricted && req.Header.Get("Authorization") == "" { - key, err := GetToken(path, method) - if err != nil { - return err - } - req.Header.Set("Authorization", "Bearer "+key) - } - r, err := c.httpClient.Do(req) if err != nil { return err @@ -185,13 +186,20 @@ func (c *Client) requestData(ctx context.Context, method, path string, body io.R req.Header.Set("Content-Type", contentType) } req.Header.Set("Accept", contentType) - - if c.restricted && req.Header.Get("Authorization") == "" { - key, err := GetToken(path, method) - if err != nil { - return nil, err + // ACT + if opts != nil { + if opts.Act != nil { + req.Header.Set(swarmAct, strconv.FormatBool(*opts.Act)) + } + if opts.ActHistoryAddress != nil { + req.Header.Set(swarmActHistoryAddress, (*opts.ActHistoryAddress).String()) + } + if opts.ActPublicKey != nil { + req.Header.Set(swarmActPublisher, (*opts.ActPublicKey).String()) + } + if opts.ActTimestamp != nil { + req.Header.Set(swarmActTimestamp, strconv.FormatUint(*opts.ActTimestamp, 10)) } - req.Header.Set("Authorization", "Bearer "+key) } if opts != nil && opts.Cache != nil { @@ -200,7 +208,6 @@ func (c *Client) requestData(ctx context.Context, method, path string, body io.R if opts != nil && opts.RedundancyFallbackMode != nil { req.Header.Set(swarmRedundancyFallbackMode, strconv.FormatBool(*opts.RedundancyFallbackMode)) } - r, err := c.httpClient.Do(req) if err != nil { return nil, err @@ -214,7 +221,7 @@ func (c *Client) requestData(ctx context.Context, method, path string, body io.R } // requestWithHeader handles the HTTP request response cycle. -func (c *Client) requestWithHeader(ctx context.Context, method, path string, header http.Header, body io.Reader, v interface{}) (err error) { +func (c *Client) requestWithHeader(ctx context.Context, method, path string, header http.Header, body io.Reader, v interface{}, headerParser ...func(http.Header)) (err error) { req, err := http.NewRequest(method, path, body) if err != nil { return err @@ -224,25 +231,16 @@ func (c *Client) requestWithHeader(ctx context.Context, method, path string, hea req.Header = header req.Header.Add("Accept", contentType) - if c.restricted && req.Header.Get("Authorization") == "" { - key, err := GetToken(path, method) - if err != nil { - return err - } - req.Header.Set("Authorization", "Bearer "+key) - } - r, err := c.httpClient.Do(req) if err != nil { return err } - if err = responseErrorHandler(r); err != nil { - return err - } - if v != nil && strings.Contains(r.Header.Get("Content-Type"), "application/json") { _ = json.NewDecoder(r.Body).Decode(&v) + for _, parser := range headerParser { + parser(r.Header) + } return err } @@ -314,13 +312,19 @@ func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { } type UploadOptions struct { - Pin bool - Tag uint64 - BatchID string - Direct bool + Act bool + Pin bool + Tag uint64 + BatchID string + Direct bool + ActHistoryAddress swarm.Address } type DownloadOptions struct { + Act *bool + ActHistoryAddress *swarm.Address + ActPublicKey *swarm.Address + ActTimestamp *uint64 Cache *bool RedundancyFallbackMode *bool } diff --git a/pkg/bee/api/auth.go b/pkg/bee/api/auth.go deleted file mode 100644 index 00357a41d..000000000 --- a/pkg/bee/api/auth.go +++ /dev/null @@ -1,175 +0,0 @@ -package api - -import ( - "bytes" - "context" - "encoding/base64" - "encoding/json" - "fmt" - "net/http" - "regexp" - "strings" -) - -// AuthService represents Bee's Auth service -type AuthService service - -// AuthResponse represents authentication response -type AuthResponse struct { - Key string `json:"key"` -} - -func (a *AuthService) Refresh(ctx context.Context, securityToken string) (string, error) { - header := make(http.Header) - header.Set("Content-Type", "application/json") - header.Set("Accept", "application/json") - header.Set("Authorization", "Bearer "+securityToken) - - data, err := json.Marshal(struct { - Expiry int `json:"expiry"` - }{Expiry: 30}) - if err != nil { - return "", err - } - - var resp AuthResponse - err = a.client.requestWithHeader(ctx, http.MethodPost, "/refresh", header, bytes.NewReader(data), &resp) - if err != nil { - return "", err - } - - return resp.Key, nil -} - -// Authenticate gets the bearer security token based on given credentials -func (a *AuthService) Authenticate(ctx context.Context, role, password string) (string, error) { - plain := fmt.Sprintf("test:%s", password) - encoded := base64.StdEncoding.EncodeToString([]byte(plain)) - - header := make(http.Header) - header.Set("Content-Type", "application/json") - header.Set("Accept", "application/json") - header.Set("Authorization", "Basic "+encoded) - - data, err := json.Marshal(struct { - Role string `json:"role"` - Expiry int `json:"expiry"` - }{Role: role, Expiry: 30}) - if err != nil { - return "", err - } - - var resp AuthResponse - err = a.client.requestWithHeader(ctx, http.MethodPost, "/auth", header, bytes.NewReader(data), &resp) - if err != nil { - return "", err - } - - return resp.Key, nil -} - -const ( - TokenConsumer = "CP5tR8Zqd2txobVbWn02+YXZ6YEXDBjl8lq1cYaRHDJLE7rldjGBft5r2imUTAnExkQoSoBWSywCG93feYF5jtDN3kHpxcwKrm0Mz/JJknYZFzcZml8=" - TokenCreator = "v2ACGxBiGJf3Jyos7MX/vq8nrp8zTVx/mT3wtGPXA/ayNBQdIZLIgd/gNlWoaS5r6AQ22zUAYa4hcbx93bKyUmIaKSJBuOGz/Sz0/dnUAZjkocF0pg==" - TokenMaintainer = "MZhpzQUMPyNMmbrQMKcTBLzHpLpz3JB1CKuFVuHH+yqzZI6kzdjWI4OOhGw1l5NonvwZMhxTOlCmsmW2Fq/dRLgvn8EiKyOKNDsYcK8es94IwkMwKLcebw==" - TokenAccountant = "3jpNFZwiVDAFeMEDi5tvSZ8czxgZjZr6AWaRSB0ApVueucGXpLbMVvU38HPxJtTIjEtW6BUtFb8EEkKfsw12coM+JngWNaRm9bWwJsCoG8b69oCklGK2sw==" -) - -var roles = map[string]string{ - "consumer": TokenConsumer, - "creator": TokenCreator, - "maintainer": TokenMaintainer, - "accountant": TokenAccountant, -} - -func GetToken(path, method string) (string, error) { - roleName := getRole(path, method) - - if roleName == "" { - return "", fmt.Errorf("role not found for path '%s' and method %s", path, method) - } - - return roles[roleName], nil -} - -func getRole(path, method string) string { - for _, v := range policies { - if v[2] != method { - if !strings.Contains(v[2], fmt.Sprintf("(%s)", method)) { - continue - } - } - re := regexp.MustCompile(v[1]) - if re.Match([]byte(path)) { - return v[0] - } - } - - return "" -} - -var policies = [][]string{ - {"consumer", "/bytes/*", "GET"}, - {"creator", "/bytes", "POST"}, - {"consumer", "/chunks/*", "GET"}, - {"creator", "/chunks", "POST"}, - {"consumer", "/bzz/*", "GET"}, - {"creator", "/bzz/*", "PATCH"}, - {"creator", "/bzz", "POST"}, - {"creator", "/bzz\\?*", "POST"}, - {"consumer", "/bzz/*/*", "GET"}, - {"creator", "/tags", "GET"}, - {"creator", "/tags\\?*", "GET"}, - {"creator", "/tags", "POST"}, - {"creator", "/tags/*", "(GET)|(DELETE)|(PATCH)"}, - {"creator", "/pins/*", "(GET)|(DELETE)|(POST)"}, - {"maintainer", "/pins", "GET"}, - {"creator", "/pss/send/*", "POST"}, - {"consumer", "/pss/subscribe/*", "GET"}, - {"creator", "/soc/*/*", "POST"}, - {"creator", "/feeds/*/*", "POST"}, - {"consumer", "/feeds/*/*", "GET"}, - {"maintainer", "/stamps", "GET"}, - {"maintainer", "/stamps/*", "GET"}, - {"maintainer", "/stamps/*/*", "POST"}, - {"maintainer", "/stamps/topup/*/*", "PATCH"}, - {"maintainer", "/stamps/dilute/*/*", "PATCH"}, - {"maintainer", "/addresses", "GET"}, - {"maintainer", "/blocklist", "GET"}, - {"maintainer", "/connect/*", "POST"}, - {"maintainer", "/peers", "GET"}, - {"maintainer", "/peers/*", "DELETE"}, - {"maintainer", "/pingpong/*", "POST"}, - {"maintainer", "/topology", "GET"}, - {"maintainer", "/welcome-message", "(GET)|(POST)"}, - {"maintainer", "/balances", "GET"}, - {"maintainer", "/balances/*", "GET"}, - {"maintainer", "/accounting", "GET"}, - {"maintainer", "/chequebook/cashout/*", "GET"}, - {"accountant", "/chequebook/cashout/*", "POST"}, - {"accountant", "/chequebook/withdraw", "POST"}, - {"accountant", "/chequebook/withdraw\\?*", "POST"}, - {"accountant", "/chequebook/deposit", "POST"}, - {"accountant", "/chequebook/deposit\\?*", "POST"}, - {"maintainer", "/chequebook/cheque/*", "GET"}, - {"maintainer", "/chequebook/cheque", "GET"}, - {"maintainer", "/chequebook/address", "GET"}, - {"maintainer", "/chequebook/balance", "GET"}, - {"maintainer", "/wallet", "GET"}, - {"maintainer", "/wallet/withdraw/*", "POST"}, - {"maintainer", "/chunks/*", "(GET)|(DELETE)"}, - {"maintainer", "/reservestate", "GET"}, - {"maintainer", "/chainstate", "GET"}, - {"maintainer", "/settlements/*", "GET"}, - {"maintainer", "/settlements", "GET"}, - {"maintainer", "/transactions", "GET"}, - {"consumer", "/transactions/*", "GET"}, - {"accountant", "/transactions/*", "(POST)|(DELETE)"}, - {"consumer", "/consumed", "GET"}, - {"consumer", "/consumed/*", "GET"}, - {"consumer", "/chunks/stream", "GET"}, - {"creator", "/stewardship/*", "GET"}, - {"consumer", "/stewardship/*", "PUT"}, - {"maintainer", "/stake/*", "POST"}, - {"maintainer", "/stake", "(GET)|(DELETE)"}, -} diff --git a/pkg/bee/api/auth_test.go b/pkg/bee/api/auth_test.go deleted file mode 100644 index 95f92a499..000000000 --- a/pkg/bee/api/auth_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package api - -import "testing" - -func TestGetRole(t *testing.T) { - tt := []struct { - desc string - path, method string - expectedRole string - }{ - {desc: "plain", expectedRole: "creator", path: "/bytes", method: "POST"}, - {desc: "query param", expectedRole: "creator", path: "/v1/bzz?name=settlements-2", method: "POST"}, - {desc: "multi method 1", expectedRole: "creator", path: "/tags", method: "POST"}, - {desc: "multi method 2", expectedRole: "creator", path: "/tags", method: "GET"}, - {desc: "one level", expectedRole: "consumer", path: "/bytes/123", method: "GET"}, - {desc: "two levels", expectedRole: "maintainer", path: "/stamps/1/17", method: "POST"}, - {desc: "topup", expectedRole: "maintainer", path: "/stamps/topup/d8e1c/100", method: "PATCH"}, - {desc: "dilute", expectedRole: "maintainer", path: "/stamps/dilute/d8e1c/100", method: "PATCH"}, - } - for _, tc := range tt { - t.Run(tc.desc, func(t *testing.T) { - if got := getRole(tc.path, tc.method); got != tc.expectedRole { - t.Errorf("expected %s, got %s", tc.expectedRole, got) - } - }) - } -} diff --git a/pkg/bee/debugapi/debugstore.go b/pkg/bee/api/debugstore.go similarity index 96% rename from pkg/bee/debugapi/debugstore.go rename to pkg/bee/api/debugstore.go index b8ded424a..66f6750cc 100644 --- a/pkg/bee/debugapi/debugstore.go +++ b/pkg/bee/api/debugstore.go @@ -1,4 +1,4 @@ -package debugapi +package api import ( "context" diff --git a/pkg/bee/debugapi/node.go b/pkg/bee/api/node.go similarity index 98% rename from pkg/bee/debugapi/node.go rename to pkg/bee/api/node.go index c1fef49f3..46c504b73 100644 --- a/pkg/bee/debugapi/node.go +++ b/pkg/bee/api/node.go @@ -1,4 +1,4 @@ -package debugapi +package api import ( "context" @@ -19,9 +19,9 @@ type NodeService service type Addresses struct { Ethereum string `json:"ethereum"` Overlay swarm.Address `json:"overlay"` - PublicKey string `json:"public_key"` + PublicKey string `json:"publicKey"` Underlay []string `json:"underlay"` - PSSPublicKey string `json:"pss_public_key"` + PSSPublicKey string `json:"pssPublicKey"` } // Addresses returns node's addresses diff --git a/pkg/bee/debugapi/pingpong.go b/pkg/bee/api/pingpong.go similarity index 96% rename from pkg/bee/debugapi/pingpong.go rename to pkg/bee/api/pingpong.go index 9be838771..bc9e050c8 100644 --- a/pkg/bee/debugapi/pingpong.go +++ b/pkg/bee/api/pingpong.go @@ -1,4 +1,4 @@ -package debugapi +package api import ( "context" diff --git a/pkg/bee/debugapi/postage.go b/pkg/bee/api/postage.go similarity index 99% rename from pkg/bee/debugapi/postage.go rename to pkg/bee/api/postage.go index 9c1b9f471..7b6dd65a4 100644 --- a/pkg/bee/debugapi/postage.go +++ b/pkg/bee/api/postage.go @@ -1,4 +1,4 @@ -package debugapi +package api import ( "context" diff --git a/pkg/bee/debugapi/stake.go b/pkg/bee/api/stake.go similarity index 84% rename from pkg/bee/debugapi/stake.go rename to pkg/bee/api/stake.go index 34e14cf5c..d02ab92a9 100644 --- a/pkg/bee/debugapi/stake.go +++ b/pkg/bee/api/stake.go @@ -1,4 +1,4 @@ -package debugapi +package api import ( "context" @@ -42,10 +42,10 @@ func (s *StakingService) GetStakedAmount(ctx context.Context) (stakedAmount *big return r.StakedAmount.Int, nil } -// WithdrawStake withdraws stake -func (s *StakingService) WithdrawStake(ctx context.Context) (txHash string, err error) { +// MigrateStake withdraws stake +func (s *StakingService) MigrateStake(ctx context.Context) (txHash string, err error) { r := new(stakeWithdrawResponse) - err = s.client.requestJSON(ctx, http.MethodDelete, "/stake", nil, r) + err = s.client.requestJSON(ctx, http.MethodPost, "/stake/migrate", nil, r) if err != nil { return "", err } diff --git a/pkg/bee/client.go b/pkg/bee/client.go index ed5bb6538..54d938699 100644 --- a/pkg/bee/client.go +++ b/pkg/bee/client.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/tls" + "encoding/json" "errors" "fmt" "io" @@ -16,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/beekeeper/pkg/bee/api" - "github.com/ethersphere/beekeeper/pkg/bee/debugapi" "github.com/ethersphere/beekeeper/pkg/logging" ) @@ -24,41 +24,32 @@ const retryCount int = 5 // Client manages communication with the Bee node type Client struct { - api *api.Client - debug *debugapi.Client - opts ClientOptions - logger logging.Logger + api *api.Client + opts ClientOptions + log logging.Logger // number of times to retry call retry int } // ClientOptions holds optional parameters for the Client. type ClientOptions struct { - APIURL *url.URL - APIInsecureTLS bool - DebugAPIURL *url.URL - DebugAPIInsecureTLS bool - Retry int - Restricted bool + APIURL *url.URL + APIInsecureTLS bool + Retry int } // NewClient returns Bee client -func NewClient(opts ClientOptions, logger logging.Logger) (c *Client) { +func NewClient(opts ClientOptions, log logging.Logger) (c *Client) { c = &Client{ - retry: retryCount, - opts: opts, - logger: logger, + retry: retryCount, + opts: opts, + log: log, } if opts.APIURL != nil { c.api = api.NewClient(opts.APIURL, &api.ClientOptions{HTTPClient: &http.Client{Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: opts.APIInsecureTLS}, - }}, Restricted: opts.Restricted}) - } - if opts.DebugAPIURL != nil { - c.debug = debugapi.NewClient(opts.DebugAPIURL, &debugapi.ClientOptions{HTTPClient: &http.Client{Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: opts.DebugAPIInsecureTLS}, - }}, Restricted: opts.Restricted}) + }}}) } if opts.Retry > 0 { c.retry = opts.Retry @@ -82,7 +73,7 @@ func (c *Client) Config() ClientOptions { // Addresses returns node's addresses func (c *Client) Addresses(ctx context.Context) (resp Addresses, err error) { - a, err := c.debug.Node.Addresses(ctx) + a, err := c.api.Node.Addresses(ctx) if err != nil { return Addresses{}, fmt.Errorf("get addresses: %w", err) } @@ -118,7 +109,7 @@ type Accounting struct { // Accounting returns node's accounts with all peers func (c *Client) Accounting(ctx context.Context) (resp Accounting, err error) { - r, err := c.debug.Node.Accounting(ctx) + r, err := c.api.Node.Accounting(ctx) if err != nil { return Accounting{}, fmt.Errorf("get accounting: %w", err) } @@ -150,7 +141,7 @@ type Balance struct { // Balance returns node's balance with a given peer func (c *Client) Balance(ctx context.Context, a swarm.Address) (resp Balance, err error) { - b, err := c.debug.Node.Balance(ctx, a) + b, err := c.api.Node.Balance(ctx, a) if err != nil { return Balance{}, fmt.Errorf("get balance with node %s: %w", a.String(), err) } @@ -168,7 +159,7 @@ type Balances struct { // Balances returns node's balances func (c *Client) Balances(ctx context.Context) (resp Balances, err error) { - r, err := c.debug.Node.Balances(ctx) + r, err := c.api.Node.Balances(ctx) if err != nil { return Balances{}, fmt.Errorf("get balances: %w", err) } @@ -233,15 +224,30 @@ func (c *Client) DownloadFile(ctx context.Context, a swarm.Address, opts *api.Do return size, h.Sum(nil), nil } +func (c *Client) DownloadActFile(ctx context.Context, a swarm.Address, opts *api.DownloadOptions) (size int64, hash []byte, err error) { + r, err := c.api.Act.Download(ctx, a, opts) + if err != nil { + return 0, nil, fmt.Errorf("download file %s: %w", a, err) + } + + h := fileHasher() + size, err = io.Copy(h, r) + if err != nil { + return 0, nil, fmt.Errorf("download file %s, hashing copy: %w", a, err) + } + + return size, h.Sum(nil), nil +} + // HasChunk returns true/false if node has a chunk func (c *Client) HasChunk(ctx context.Context, a swarm.Address) (bool, error) { - return c.debug.Node.HasChunk(ctx, a) + return c.api.Node.HasChunk(ctx, a) } func (c *Client) HasChunks(ctx context.Context, a []swarm.Address) (has []bool, count int, err error) { has = make([]bool, len(a)) for i, addr := range a { - v, err := c.debug.Node.HasChunk(ctx, addr) + v, err := c.api.Node.HasChunk(ctx, addr) if err != nil { return nil, 0, err } @@ -255,11 +261,11 @@ func (c *Client) HasChunks(ctx context.Context, a []swarm.Address) (has []bool, // Overlay returns node's overlay address func (c *Client) Overlay(ctx context.Context) (o swarm.Address, err error) { - var a debugapi.Addresses + var a api.Addresses for r := 0; r < c.retry; r++ { time.Sleep(2 * time.Duration(r) * time.Second) - a, err = c.debug.Node.Addresses(ctx) + a, err = c.api.Node.Addresses(ctx) if err != nil { continue } @@ -275,7 +281,7 @@ func (c *Client) Overlay(ctx context.Context) (o swarm.Address, err error) { // Peers returns addresses of node's peers func (c *Client) Peers(ctx context.Context) (peers []swarm.Address, err error) { - ps, err := c.debug.Node.Peers(ctx) + ps, err := c.api.Node.Peers(ctx) if err != nil { return nil, fmt.Errorf("get peers: %w", err) } @@ -310,7 +316,7 @@ func (c *Client) GetPins(ctx context.Context) ([]swarm.Address, error) { // Ping pings other node func (c *Client) Ping(ctx context.Context, node swarm.Address) (rtt string, err error) { - r, err := c.debug.PingPong.Ping(ctx, node) + r, err := c.api.PingPong.Ping(ctx, node) if err != nil { return "", fmt.Errorf("ping node %s: %w", node, err) } @@ -362,7 +368,7 @@ type Settlement struct { // Settlement returns node's settlement with a given peer func (c *Client) Settlement(ctx context.Context, a swarm.Address) (resp Settlement, err error) { - b, err := c.debug.Node.Settlement(ctx, a) + b, err := c.api.Node.Settlement(ctx, a) if err != nil { return Settlement{}, fmt.Errorf("get settlement with node %s: %w", a.String(), err) } @@ -384,9 +390,9 @@ func (c *Client) CreatePostageBatch(ctx context.Context, amount int64, depth uin if err != nil { return "", fmt.Errorf("print reserve state (before): %w", err) } - c.logger.Infof("reserve state (prior to buying the batch):%s", rs.String()) + c.log.Infof("reserve state (prior to buying the batch):%s", rs.String()) } - id, err := c.debug.Postage.CreatePostageBatch(ctx, amount, depth, label) + id, err := c.api.Postage.CreatePostageBatch(ctx, amount, depth, label) if err != nil { return "", fmt.Errorf("create postage stamp: %w", err) } @@ -396,7 +402,7 @@ func (c *Client) CreatePostageBatch(ctx context.Context, amount int64, depth uin // wait for the stamp to become usable for i := 0; i < 900; i++ { time.Sleep(1 * time.Second) - state, err := c.debug.Postage.PostageStamp(ctx, id) + state, err := c.api.Postage.PostageStamp(ctx, id) if err != nil { continue } @@ -420,8 +426,8 @@ func (c *Client) CreatePostageBatch(ctx context.Context, amount int64, depth uin if err != nil { return "", fmt.Errorf("print reserve state (after): %w", err) } - c.logger.Infof("reserve state (after buying the batch):\n%s", rs.String()) - c.logger.Infof("created batch id %s with depth %d and amount %d", id, depth, amount) + c.log.Infof("reserve state (after buying the batch): %s", rs.String()) + c.log.Infof("created batch id %s with depth %d and amount %d", id, depth, amount) } return id, nil } @@ -449,13 +455,13 @@ func (c *Client) GetOrCreateBatch(ctx context.Context, amount int64, depth uint6 } // PostageBatches returns the list of batches of node -func (c *Client) PostageBatches(ctx context.Context) ([]debugapi.PostageStampResponse, error) { - return c.debug.Postage.PostageBatches(ctx) +func (c *Client) PostageBatches(ctx context.Context) ([]api.PostageStampResponse, error) { + return c.api.Postage.PostageBatches(ctx) } // PostageStamp returns the batch by ID -func (c *Client) PostageStamp(ctx context.Context, batchID string) (debugapi.PostageStampResponse, error) { - return c.debug.Postage.PostageStamp(ctx, batchID) +func (c *Client) PostageStamp(ctx context.Context, batchID string) (api.PostageStampResponse, error) { + return c.api.Postage.PostageStamp(ctx, batchID) } // TopupPostageBatch tops up the given batch with the amount per chunk @@ -465,7 +471,7 @@ func (c *Client) TopUpPostageBatch(ctx context.Context, batchID string, amount i return fmt.Errorf("unable to retrieve batch details: %w", err) } - err = c.debug.Postage.TopUpPostageBatch(ctx, batchID, amount, gasPrice) + err = c.api.Postage.TopUpPostageBatch(ctx, batchID, amount, gasPrice) if err != nil { return err } @@ -489,12 +495,12 @@ func (c *Client) TopUpPostageBatch(ctx context.Context, batchID string, amount i // DilutePostageBatch dilutes the given batch by increasing the depth func (c *Client) DilutePostageBatch(ctx context.Context, batchID string, depth uint64, gasPrice string) error { - batch, err := c.debug.Postage.PostageStamp(ctx, batchID) + batch, err := c.api.Postage.PostageStamp(ctx, batchID) if err != nil { return fmt.Errorf("unable to retrieve batch details: %w", err) } - err = c.debug.Postage.DilutePostageBatch(ctx, batchID, depth, gasPrice) + err = c.api.Postage.DilutePostageBatch(ctx, batchID, depth, gasPrice) if err != nil { return err } @@ -502,7 +508,7 @@ func (c *Client) DilutePostageBatch(ctx context.Context, batchID string, depth u for i := 0; i < 60; i++ { time.Sleep(time.Second) - b, err := c.debug.Postage.PostageStamp(ctx, batchID) + b, err := c.api.Postage.PostageStamp(ctx, batchID) if err != nil { return err } @@ -517,8 +523,8 @@ func (c *Client) DilutePostageBatch(ctx context.Context, batchID string, depth u } // ReserveState returns reserve radius, available capacity, inner and outer radiuses -func (c *Client) ReserveState(ctx context.Context) (debugapi.ReserveState, error) { - return c.debug.Postage.ReserveState(ctx) +func (c *Client) ReserveState(ctx context.Context) (api.ReserveState, error) { + return c.api.Postage.ReserveState(ctx) } // SendPSSMessage triggers a PSS message with a topic and recipient address @@ -545,7 +551,7 @@ type Settlements struct { // Settlements returns node's settlements func (c *Client) Settlements(ctx context.Context) (resp Settlements, err error) { - r, err := c.debug.Node.Settlements(ctx) + r, err := c.api.Node.Settlements(ctx) if err != nil { return Settlements{}, fmt.Errorf("get settlements: %w", err) } @@ -584,7 +590,7 @@ type CashoutStatusResponse struct { } func (c *Client) CashoutStatus(ctx context.Context, a swarm.Address) (resp CashoutStatusResponse, err error) { - r, err := c.debug.Node.CashoutStatus(ctx, a) + r, err := c.api.Node.CashoutStatus(ctx, a) if err != nil { return CashoutStatusResponse{}, fmt.Errorf("cashout: %w", err) } @@ -612,7 +618,7 @@ func (c *Client) CashoutStatus(ctx context.Context, a swarm.Address) (resp Casho } func (c *Client) Cashout(ctx context.Context, a swarm.Address) (resp string, err error) { - r, err := c.debug.Node.Cashout(ctx, a) + r, err := c.api.Node.Cashout(ctx, a) if err != nil { return "", fmt.Errorf("cashout: %w", err) } @@ -626,7 +632,7 @@ type ChequebookBalanceResponse struct { } func (c *Client) ChequebookBalance(ctx context.Context) (resp ChequebookBalanceResponse, err error) { - r, err := c.debug.Node.ChequebookBalance(ctx) + r, err := c.api.Node.ChequebookBalance(ctx) if err != nil { return ChequebookBalanceResponse{}, fmt.Errorf("cashout: %w", err) } @@ -652,19 +658,19 @@ type Topology struct { // Bin represents Kademlia bin type Bin struct { - Population int `json:"population"` - Connected int `json:"connected"` - DisconnectedPeers []debugapi.PeerInfo `json:"disconnectedPeers"` - ConnectedPeers []debugapi.PeerInfo `json:"connectedPeers"` + Population int `json:"population"` + Connected int `json:"connected"` + DisconnectedPeers []api.PeerInfo `json:"disconnectedPeers"` + ConnectedPeers []api.PeerInfo `json:"connectedPeers"` } // Topology returns Kademlia topology func (c *Client) Topology(ctx context.Context) (topology Topology, err error) { - var t debugapi.Topology + var t api.Topology for r := 0; r < c.retry; r++ { time.Sleep(2 * time.Duration(r) * time.Second) - t, err = c.debug.Node.Topology(ctx) + t, err = c.api.Node.Topology(ctx) if err != nil { continue } @@ -708,7 +714,7 @@ func (c *Client) Topology(ctx context.Context) (topology Topology, err error) { // Underlay returns node's underlay addresses func (c *Client) Underlay(ctx context.Context) ([]string, error) { - a, err := c.debug.Node.Addresses(ctx) + a, err := c.api.Node.Addresses(ctx) if err != nil { return nil, fmt.Errorf("get underlay: %w", err) } @@ -760,6 +766,55 @@ func (c *Client) UploadFile(ctx context.Context, f *File, o api.UploadOptions) ( return } +func (c *Client) UploadActFile(ctx context.Context, f *File, o api.UploadOptions) (err error) { + h := fileHasher() + r, err := c.api.Act.Upload(ctx, f.Name(), io.TeeReader(f.DataReader(), h), o) + if err != nil { + return fmt.Errorf("upload ACT file: %w", err) + } + + f.SetAddress(r.Reference) + f.SetHistroryAddress(r.HistoryAddress) + f.SetHash(h.Sum(nil)) + + return nil +} + +func (c *Client) AddActGrantees(ctx context.Context, f *File, o api.UploadOptions) (err error) { + h := fileHasher() + r, err := c.api.Act.AddGrantees(ctx, io.TeeReader(f.DataReader(), h), o) + if err != nil { + return fmt.Errorf("add ACT grantees: %w", err) + } + + f.SetAddress(r.Reference) + f.SetHistroryAddress(r.HistoryAddress) + f.SetHash(h.Sum(nil)) + + return nil +} + +func (c *Client) GetActGrantees(ctx context.Context, a swarm.Address) (addresses []string, err error) { + r, e := c.api.Act.GetGrantees(ctx, a) + if e != nil { + return nil, fmt.Errorf("get grantees: %s: %w", a, e) + } + defer r.Close() + err = json.NewDecoder(r).Decode(&addresses) + return addresses, err +} + +func (c *Client) PatchActGrantees(ctx context.Context, pf *File, addr swarm.Address, haddr swarm.Address, batchID string) (err error) { + r, err := c.api.Act.PatchGrantees(ctx, pf.DataReader(), addr, haddr, batchID) + if err != nil { + return fmt.Errorf("add ACT grantees: %w", err) + } + + pf.SetAddress(r.Reference) + pf.SetHistroryAddress(r.HistoryAddress) + return nil +} + // UploadCollection uploads TAR collection bytes to the node func (c *Client) UploadCollection(ctx context.Context, f *File, o api.UploadOptions) (err error) { h := fileHasher() @@ -822,36 +877,24 @@ func (c *Client) Reupload(ctx context.Context, ref swarm.Address) error { return c.api.Stewardship.Reupload(ctx, ref) } -// Authenticate -func (c *Client) Authenticate(ctx context.Context, role, password string) (string, error) { - resp, err := c.api.Auth.Authenticate(ctx, role, password) - return resp, err -} - -// Refresh -func (c *Client) Refresh(ctx context.Context, securityToken string) (string, error) { - resp, err := c.api.Auth.Refresh(ctx, securityToken) - return resp, err -} - // DepositStake deposits stake func (c *Client) DepositStake(ctx context.Context, amount *big.Int) (string, error) { - return c.debug.Stake.DepositStake(ctx, amount) + return c.api.Stake.DepositStake(ctx, amount) } // GetStake returns stake amount func (c *Client) GetStake(ctx context.Context) (*big.Int, error) { - return c.debug.Stake.GetStakedAmount(ctx) + return c.api.Stake.GetStakedAmount(ctx) } -// WithdrawStake withdraws stake -func (c *Client) WithdrawStake(ctx context.Context) (string, error) { - return c.debug.Stake.WithdrawStake(ctx) +// MigrateStake withdraws stake +func (c *Client) MigrateStake(ctx context.Context) (string, error) { + return c.api.Stake.MigrateStake(ctx) } // WalletBalance fetches the balance for the given token func (c *Client) WalletBalance(ctx context.Context, token string) (*big.Int, error) { - resp, err := c.debug.Node.Wallet(ctx) + resp, err := c.api.Node.Wallet(ctx) if err != nil { return nil, err } @@ -865,7 +908,7 @@ func (c *Client) WalletBalance(ctx context.Context, token string) (*big.Int, err // Withdraw transfers token from eth address to the provided address func (c *Client) Withdraw(ctx context.Context, token, addr string, amount int64) error { - resp, err := c.debug.Node.Withdraw(ctx, token, addr, amount) + resp, err := c.api.Node.Withdraw(ctx, token, addr, amount) if err != nil { return err } diff --git a/pkg/bee/debugapi/debugapi.go b/pkg/bee/debugapi/debugapi.go deleted file mode 100644 index 5ee259897..000000000 --- a/pkg/bee/debugapi/debugapi.go +++ /dev/null @@ -1,244 +0,0 @@ -package debugapi - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strings" - - "github.com/ethersphere/beekeeper" - "github.com/ethersphere/beekeeper/pkg/bee/api" -) - -const contentType = "application/json; charset=utf-8" - -var userAgent = "beekeeper/" + beekeeper.Version - -// Client manages communication with the Bee Debug API. -type Client struct { - httpClient *http.Client // HTTP client must handle authentication implicitly. - service service // Reuse a single struct instead of allocating one for each service on the heap. - - // Services that API provides. - Node *NodeService - PingPong *PingPongService - Postage *PostageService - Stake *StakingService - restricted bool -} - -// ClientOptions holds optional parameters for the Client. -type ClientOptions struct { - HTTPClient *http.Client - Restricted bool -} - -// NewClient constructs a new Client. -func NewClient(baseURL *url.URL, o *ClientOptions) (c *Client) { - if o == nil { - o = new(ClientOptions) - } - if o.HTTPClient == nil { - o.HTTPClient = new(http.Client) - } - - c = newClient(httpClientWithTransport(baseURL, o.HTTPClient)) - c.restricted = o.Restricted - - return c -} - -// newClient constructs a new *Client with the provided http Client, which -// should handle authentication implicitly, and sets all API services. -func newClient(httpClient *http.Client) (c *Client) { - c = &Client{httpClient: httpClient} - c.service.client = c - c.Node = (*NodeService)(&c.service) - c.PingPong = (*PingPongService)(&c.service) - c.Postage = (*PostageService)(&c.service) - c.Stake = (*StakingService)(&c.service) - return c -} - -func httpClientWithTransport(baseURL *url.URL, c *http.Client) *http.Client { - if c == nil { - c = new(http.Client) - } - - transport := c.Transport - if transport == nil { - transport = http.DefaultTransport - } - - if !strings.HasSuffix(baseURL.Path, "/") { - baseURL.Path += "/" - } - - c.Transport = roundTripperFunc(func(r *http.Request) (resp *http.Response, err error) { - r.Header.Set("User-Agent", userAgent) - u, err := baseURL.Parse(r.URL.String()) - if err != nil { - return nil, err - } - r.URL = u - return transport.RoundTrip(r) - }) - return c -} - -// requestJSON handles the HTTP request response cycle. It JSON encodes the request -// body, creates an HTTP request with provided method on a path with required -// headers and decodes request body if the v argument is not nil and content type is -// application/json. -func (c *Client) requestJSON(ctx context.Context, method, path string, body, v interface{}) (err error) { - var bodyBuffer io.ReadWriter - if body != nil { - bodyBuffer = new(bytes.Buffer) - if err = encodeJSON(bodyBuffer, body); err != nil { - return err - } - } - - return c.request(ctx, method, path, bodyBuffer, v) -} - -// requestWithHeader handles the HTTP request response cycle. -func (c *Client) requestWithHeader(ctx context.Context, method, path string, header http.Header, body io.Reader, v interface{}) (err error) { - req, err := http.NewRequest(method, path, body) - if err != nil { - return err - } - req = req.WithContext(ctx) - - req.Header = header - req.Header.Add("Accept", contentType) - - r, err := c.httpClient.Do(req) - if err != nil { - return err - } - - if err = responseErrorHandler(r); err != nil { - return err - } - - if v != nil && strings.Contains(r.Header.Get("Content-Type"), "application/json") { - _ = json.NewDecoder(r.Body).Decode(&v) - return err - } - - return err -} - -// request handles the HTTP request response cycle. -func (c *Client) request(ctx context.Context, method, path string, body io.Reader, v interface{}) (err error) { - req, err := http.NewRequest(method, path, body) - if err != nil { - return err - } - req = req.WithContext(ctx) - - if body != nil { - req.Header.Set("Content-Type", contentType) - } - req.Header.Set("Accept", contentType) - - if c.restricted && req.Header.Get("Authorization") == "" { - key, err := api.GetToken(path, method) - if err != nil { - return err - } - req.Header.Set("Authorization", "Bearer "+key) - } - - r, err := c.httpClient.Do(req) - if err != nil { - return err - } - defer drain(r.Body) - - if err = responseErrorHandler(r); err != nil { - return err - } - - if v != nil && strings.Contains(r.Header.Get("Content-Type"), "application/json") { - return json.NewDecoder(r.Body).Decode(&v) - } - return nil -} - -// encodeJSON writes a JSON-encoded v object to the provided writer with -// SetEscapeHTML set to false. -func encodeJSON(w io.Writer, v interface{}) (err error) { - enc := json.NewEncoder(w) - enc.SetEscapeHTML(false) - return enc.Encode(v) -} - -// drain discards all of the remaining data from the reader and closes it, -// asynchronously. -func drain(r io.ReadCloser) { - go func() { - // Panicking here does not put data in - // an inconsistent state. - defer func() { - _ = recover() - }() - - _, _ = io.Copy(io.Discard, r) - r.Close() - }() -} - -type messageResponse struct { - Message string `json:"message"` -} - -// responseErrorHandler returns an error based on the HTTP status code or nil if -// the status code is from 200 to 299. -// The error will include the message from standardized JSON-encoded error response -// if it is not the same as the status text. -func responseErrorHandler(r *http.Response) (err error) { - if r.StatusCode/100 == 2 { - // no error if response in 2xx range - return nil - } - - var e messageResponse - if strings.Contains(r.Header.Get("Content-Type"), "application/json") { - if err = json.NewDecoder(r.Body).Decode(&e); err != nil && err != io.EOF { - return err - } - } - - err = NewHTTPStatusError(r.StatusCode) - // add message to the error if it is not already the same as the status text - if e.Message != "" && e.Message != http.StatusText(r.StatusCode) { - return fmt.Errorf("response message %q: status: %w", e.Message, err) - } - return err -} - -// service is the base type for all API service providing the Client instance -// for them to use. -type service struct { - client *Client -} - -// Bool is a helper routine that allocates a new bool value to store v and -// returns a pointer to it. -func Bool(v bool) (p *bool) { return &v } - -// roundTripperFunc type is an adapter to allow the use of ordinary functions as -// http.RoundTripper interfaces. If f is a function with the appropriate -// signature, roundTripperFunc(f) is a http.RoundTripper that calls f. -type roundTripperFunc func(*http.Request) (*http.Response, error) - -// RoundTrip calls f(r). -func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { - return f(r) -} diff --git a/pkg/bee/debugapi/errors.go b/pkg/bee/debugapi/errors.go deleted file mode 100644 index 8b42ba269..000000000 --- a/pkg/bee/debugapi/errors.go +++ /dev/null @@ -1,35 +0,0 @@ -package debugapi - -import ( - "errors" - "fmt" - "net/http" -) - -// HTTPStatusError represents the error derived from the HTTP response status -// code. -type HTTPStatusError struct { - Code int -} - -// NewHTTPStatusError creates a new instance of HTTPStatusError based on the -// provided code. -func NewHTTPStatusError(code int) *HTTPStatusError { - return &HTTPStatusError{ - Code: code, - } -} - -func (e *HTTPStatusError) Error() string { - return fmt.Sprintf("%d %s", e.Code, http.StatusText(e.Code)) -} - -// IsHTTPStatusErrorCode return whether the error is HTTPStatusError with a -// specific HTTP status code. -func IsHTTPStatusErrorCode(err error, code int) bool { - var e *HTTPStatusError - if errors.As(err, &e) { - return e.Code == code - } - return false -} diff --git a/pkg/bee/debugapi/errors_test.go b/pkg/bee/debugapi/errors_test.go deleted file mode 100644 index d07a65dca..000000000 --- a/pkg/bee/debugapi/errors_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package debugapi - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/http/httptest" - "testing" -) - -func TestIsHTTPStatusErrorCode(t *testing.T) { - if ok := IsHTTPStatusErrorCode(NewHTTPStatusError(http.StatusBadGateway), http.StatusBadGateway); !ok { - t.Fatal("got false") - } - if ok := IsHTTPStatusErrorCode(NewHTTPStatusError(http.StatusBadGateway), http.StatusInternalServerError); ok { - t.Fatal("got true") - } - if ok := IsHTTPStatusErrorCode(nil, http.StatusTeapot); ok { - t.Fatal("got true") - } - if ok := IsHTTPStatusErrorCode(io.EOF, http.StatusTeapot); ok { - t.Fatal("got true") - } -} - -func TestResponseErrorHandler(t *testing.T) { - for _, tc := range []struct { - name string - handler http.Handler - err error - }{ - { - name: "blank", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {}), - }, - { - name: "status ok", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), - }, - { - name: "status created", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusCreated) - }), - }, - { - name: "status only", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusBadRequest) - }), - err: NewHTTPStatusError(http.StatusBadRequest), - }, - { - name: "status only 2", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - }), - err: NewHTTPStatusError(http.StatusInternalServerError), - }, - { - name: "no data", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - w.Header().Set("Content-Type", contentType) - }), - err: NewHTTPStatusError(http.StatusInternalServerError), - }, - { - name: "no message", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - w.Header().Set("Content-Type", contentType) - _, _ = w.Write(encodeMessageResponse(t, "")) - }), - err: NewHTTPStatusError(http.StatusInternalServerError), - }, - { - name: "custom message", - handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", contentType) - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(encodeMessageResponse(t, "custom message")) - }), - err: fmt.Errorf("response message %q: status: %w", "custom message", NewHTTPStatusError(http.StatusInternalServerError)), - }, - } { - t.Run(tc.name, func(t *testing.T) { - recorder := httptest.NewRecorder() - tc.handler.ServeHTTP(recorder, nil) - - gotErr := responseErrorHandler(recorder.Result()) - - if tc.err == nil && gotErr == nil { - return // all fine - } - - var e *HTTPStatusError - if !errors.As(gotErr, &e) { - t.Fatalf("got error %v, want %v", gotErr, tc.err) - } else if e.Code != recorder.Code { - t.Fatalf("got error code %v, want %v", e.Code, recorder.Code) - } - - gotErrMessage := gotErr.Error() - wantErrMessage := tc.err.Error() - if gotErrMessage != wantErrMessage { - t.Fatalf("got error message %q, want %q", gotErrMessage, wantErrMessage) - } - }) - } -} - -func encodeMessageResponse(t *testing.T, message string) []byte { - t.Helper() - - data, err := json.Marshal(messageResponse{ - Message: message, - }) - if err != nil { - t.Fatal(err) - } - - return data -} diff --git a/pkg/bee/file.go b/pkg/bee/file.go index 9478e42f3..29c2207d6 100644 --- a/pkg/bee/file.go +++ b/pkg/bee/file.go @@ -13,11 +13,12 @@ import ( // File represents Bee file type File struct { - address swarm.Address - name string - hash []byte - dataReader io.Reader - size int64 + address swarm.Address + name string + hash []byte + dataReader io.Reader + size int64 + historyAddress swarm.Address } // NewRandomFile returns new pseudorandom file @@ -62,6 +63,10 @@ func (f *File) Address() swarm.Address { return f.address } +func (f *File) HistroryAddress() swarm.Address { + return f.historyAddress +} + // Name returns file's name func (f *File) Name() string { return f.name @@ -109,6 +114,10 @@ func (f *File) SetAddress(a swarm.Address) { f.address = a } +func (f *File) SetHistroryAddress(a swarm.Address) { + f.historyAddress = a +} + func (f *File) SetHash(h []byte) { f.hash = h } diff --git a/pkg/check/act/act.go b/pkg/check/act/act.go new file mode 100644 index 000000000..ac782cb82 --- /dev/null +++ b/pkg/check/act/act.go @@ -0,0 +1,265 @@ +package act + +import ( + "bytes" + "context" + "errors" + "fmt" + "time" + + "github.com/ethersphere/bee/pkg/swarm" + "github.com/ethersphere/beekeeper/pkg/bee" + "github.com/ethersphere/beekeeper/pkg/bee/api" + "github.com/ethersphere/beekeeper/pkg/beekeeper" + "github.com/ethersphere/beekeeper/pkg/logging" + "github.com/ethersphere/beekeeper/pkg/orchestration" + "github.com/ethersphere/beekeeper/pkg/random" +) + +// Options represents check options +type Options struct { + FileName string + FileSize int64 + PostageAmount int64 + PostageDepth uint64 + PostageLabel string + Seed int64 +} + +// NewDefaultOptions returns new default options +func NewDefaultOptions() Options { + return Options{ + FileName: "act", + FileSize: 1 * 1024, + PostageAmount: 420000000, + PostageDepth: 20, + PostageLabel: "act-label", + Seed: 0, + } +} + +// compile check whether Check implements interface +var _ beekeeper.Action = (*Check)(nil) + +// Check instance +type Check struct { + logger logging.Logger +} + +// NewCheck returns new check +func NewCheck(logger logging.Logger) beekeeper.Action { + return &Check{ + logger: logger, + } +} + +// Run executes act check +func (c *Check) Run(ctx context.Context, cluster orchestration.Cluster, opts interface{}) (err error) { + o, ok := opts.(Options) + if !ok { + return fmt.Errorf("invalid options type") + } + + clients, err := cluster.NodesClients(ctx) + if err != nil { + return err + } + + fullNodes := cluster.FullNodeNames() + lightNodes := cluster.LightNodeNames() + + upNodeName := lightNodes[0] + upClient := clients[upNodeName] + addr, _ := upClient.Addresses(ctx) + publisher, _ := swarm.ParseHexAddress(addr.PublicKey) + + nodeName1 := fullNodes[0] + client1 := clients[nodeName1] + addr1, _ := client1.Addresses(ctx) + pubk1, _ := swarm.ParseHexAddress(addr1.PublicKey) + + nodeName2 := fullNodes[1] + client2 := clients[nodeName2] + addr2, _ := client2.Addresses(ctx) + pubk2, _ := swarm.ParseHexAddress(addr2.PublicKey) + + nodeName3 := fullNodes[2] + client3 := clients[nodeName3] + addr3, _ := client3.Addresses(ctx) + pubk3, _ := swarm.ParseHexAddress(addr3.PublicKey) + + rnds := random.PseudoGenerators(o.Seed, 1) + + fileName := fmt.Sprintf("%s-%s-%d", o.FileName, upNodeName, rnds[0].Int()) + postagelabel := fmt.Sprintf("%s-%s-%d", o.PostageLabel, upNodeName, rnds[0].Int()) + + file := bee.NewRandomFile(rnds[0], fileName, o.FileSize) + + batchID, err := upClient.GetOrCreateBatch(ctx, o.PostageAmount, o.PostageDepth, postagelabel) + if err != nil { + return fmt.Errorf("created batched id %w", err) + } + + // upload act file + // ---------------------------------------------- + // Given batch is used for the upload + // When the file is uploaded to the node + // Then the file is uploaded successfully + uErr := upClient.UploadActFile(ctx, &file, api.UploadOptions{BatchID: batchID}) + if uErr != nil { + return fmt.Errorf("node %s: %w", upNodeName, uErr) + } + c.logger.Info("ACT file uploaded") + time.Sleep(1 * time.Second) + + // download act file + // ---------------------------------------------- + // Given the file is uploaded to the node + // When the file is downloaded from the node + // Then the file is downloaded successfully + act := true + fileAddress := file.Address() + history := file.HistroryAddress() + size, hash, err := upClient.DownloadActFile(ctx, fileAddress, &api.DownloadOptions{Act: &act, ActPublicKey: &publisher, ActHistoryAddress: &history}) + if err != nil { + return fmt.Errorf("node %s: %w", upNodeName, err) + } + if !bytes.Equal(file.Hash(), hash) { + c.logger.Infof("Node %s. ACT file hash not equal. Uploaded size: %d Downloaded size: %d File: %s", upNodeName, file.Size(), size, fileAddress.String()) + return errors.New("ACT file retrieval - hash error") + } + c.logger.Info("ACT file downloaded") + + // download act file with wrong public key + // ---------------------------------------------- + // Given the file is uploaded to the node + // When the file is downloaded from the node with wrong public key + // Then the file download is denied + notPublisher := pubk1 + _, _, notPErr := upClient.DownloadActFile(ctx, file.Address(), &api.DownloadOptions{Act: &act, ActPublicKey: ¬Publisher, ActHistoryAddress: &history}) + if notPErr == nil { + return fmt.Errorf("node %s: File downloaded with wrong public key successfully - this is an error", upNodeName) + } + c.logger.Info("ACT Access denied with incorrect public key") + + // add grantees list + // ---------------------------------------------- + // Given the file is uploaded to the node (fileHis) + // When the grantees are added to the file + // Then the grantees are added successfully + gFile := bee.NewBufferFile("grantees.json", bytes.NewBuffer([]byte(`{ "grantees": [ + "`+pubk2.String()+`", + "`+pubk3.String()+`" + ] + }`))) + fileHis := file.HistroryAddress() + err = upClient.AddActGrantees(ctx, &gFile, api.UploadOptions{BatchID: batchID, ActHistoryAddress: fileHis}) + if err != nil { + return fmt.Errorf("node %s: add grantees error: %w", upNodeName, err) + } + c.logger.Info("ACT grantees added") + time.Sleep(10 * time.Second) + + // list grantees + // ---------------------------------------------- + // Given the file is uploaded to the node (gFile) + // When the grantees are listed + // Then the grantees are listed successfully + addresses, gErr := upClient.GetActGrantees(ctx, gFile.Address()) + if gErr != nil { + return fmt.Errorf("node %s: GetActGrantees: %w", upNodeName, gErr) + } + if addresses == nil { + return fmt.Errorf("node %s: GetActGrantees: addresses is nil", upNodeName) + } + if len(addresses) != 2 { + return fmt.Errorf("node %s: GetActGrantees: addresses length is not 2", upNodeName) + } + c.logger.Info("ACT grantees listed") + time.Sleep(5 * time.Second) + + // download act file with the publisher after create grantees + // ---------------------------------------------- + // Given the grantee is added to the file + // When the file is downloaded from the node with the publisher + // Then the file is downloaded successfully + h := gFile.HistroryAddress() + size0, hash0, err0 := upClient.DownloadActFile(ctx, fileAddress, &api.DownloadOptions{Act: &act, ActPublicKey: &publisher, ActHistoryAddress: &h}) + if err0 != nil { + return fmt.Errorf("node %s: %w", upNodeName, err0) + } + if !bytes.Equal(file.Hash(), hash0) { + c.logger.Infof("Node %s. ACT file hash not equal. Uploaded size: %d Downloaded size: %d File: %s", upNodeName, file.Size(), size0, fileAddress.String()) + return errors.New("ACT file retrieval - hash error") + } + c.logger.Info("ACT file downloaded with the publisher") + + // download act file with the grantee + // ---------------------------------------------- + // Given the grantee is added to the file + // When the file is downloaded from the node with the grantee + // Then the file is downloaded successfully + his := gFile.HistroryAddress() + size1, hash1, err1 := client2.DownloadActFile(ctx, fileAddress, &api.DownloadOptions{Act: &act, ActPublicKey: &publisher, ActHistoryAddress: &his}) + if err1 != nil { + return fmt.Errorf("node %s: %w", nodeName2, err1) + } + if !bytes.Equal(file.Hash(), hash1) { + c.logger.Infof("Node %s. ACT file hash not equal. Uploaded size: %d Downloaded size: %d File: %s", nodeName2, file.Size(), size1, fileAddress.String()) + return errors.New("ACT file retrieval - hash error") + } + c.logger.Info("ACT file downloaded with the grantee") + + // patch grantees + // ---------------------------------------------- + // Given the grantee is added to the file (gFile) + // When the grantees are patched + // Then the grantees are patched successfully + pFile := bee.NewBufferFile("grantees-patch.json", bytes.NewBuffer([]byte(`{ + "add": [ + "`+pubk1.String()+`" + ], + "revoke": [ + "`+pubk2.String()+`", + "`+pubk3.String()+`" + ] + }`))) + + pErr := upClient.PatchActGrantees(ctx, &pFile, gFile.Address(), gFile.HistroryAddress(), batchID) + if pErr != nil { + return fmt.Errorf("node %s: PatchActGrantees: %w", upNodeName, pErr) + } + c.logger.Info("ACT grantees patched") + time.Sleep(5 * time.Second) + + // list grantees after patch + // ---------------------------------------------- + // Given the grantee is patched + // When the grantees are listed after patch + // Then the grantees are listed successfully + patchAddresses, patchErr := upClient.GetActGrantees(ctx, pFile.Address()) + if patchErr != nil { + return fmt.Errorf("node %s: GetActGrantees after patch: %w", upNodeName, patchErr) + } + if patchAddresses == nil { + return fmt.Errorf("node %s: GetActGrantees after patch: addresses is nil", upNodeName) + } + if len(patchAddresses) != 1 { + return fmt.Errorf("node %s: GetActGrantees after patch: addresses length is not 1", upNodeName) + } + c.logger.Info("ACT grantees listed after patch") + time.Sleep(5 * time.Second) + + // download act file with the not enabled grantee after patch + //---------------------------------------------- + // Given the grantee is patched + // When the file is downloaded from the node with the not enabled grantee + // Then the file download is denied + hG := pFile.HistroryAddress() + _, _, notGErr := client2.DownloadActFile(ctx, fileAddress, &api.DownloadOptions{Act: &act, ActPublicKey: &publisher, ActHistoryAddress: &hG}) + if notGErr == nil { + return fmt.Errorf("node %s: File downloaded with wrong public key successfully - this is an error", nodeName2) + } + c.logger.Info("ACT Access denied for not enabled grantee after patch") + return +} diff --git a/pkg/check/authenticated/authenticate.go b/pkg/check/authenticated/authenticate.go deleted file mode 100644 index c26aa9de9..000000000 --- a/pkg/check/authenticated/authenticate.go +++ /dev/null @@ -1,120 +0,0 @@ -package authenticated - -import ( - "context" - "errors" - "fmt" - - "github.com/ethersphere/beekeeper/pkg/beekeeper" - "github.com/ethersphere/beekeeper/pkg/logging" - "github.com/ethersphere/beekeeper/pkg/orchestration" - test "github.com/ethersphere/beekeeper/pkg/test" -) - -// Options represents check options -type Options struct { - DryRun bool - Role string - AdminPassword string - RestrictedGroupName string -} - -// NewDefaultOptions returns new default options -func NewDefaultOptions() (opts Options) { - return -} - -// compile check whether Check implements interface -var _ beekeeper.Action = (*Check)(nil) - -// Check instance -type Check struct { - logger logging.Logger -} - -// NewCheck returns new check -func NewCheck(logger logging.Logger) beekeeper.Action { - return &Check{ - logger: logger, - } -} - -func (c *Check) Run(ctx context.Context, cluster orchestration.Cluster, opts interface{}) (err error) { - o, ok := opts.(Options) - if !ok { - return fmt.Errorf("invalid options type") - } - - if o.DryRun { - c.logger.Info("running authenticated check (dry run mode)") - return dryRun(ctx, cluster, o) - } - - caseOpts := test.CaseOptions{ - AdminPassword: o.AdminPassword, - RestrictedGroupName: o.RestrictedGroupName, - Role: o.Role, - } - - checkCase, err := test.NewCheckCase(ctx, cluster, caseOpts, c.logger) - if err != nil { - return err - } - - // filter func - restricted := func(bee *test.BeeV2) bool { - return bee.Restricted() - } - - // testing closure - checkAuth := testAuth(ctx, o, c.logger) - - // execute test - if err := checkCase.Bees().Filter(restricted).ForEach(checkAuth); err != nil { - return err - } - - return -} - -func testAuth(ctx context.Context, o Options, logger logging.Logger) test.ConsumeFunc { - return func(bee *test.BeeV2) error { - logger.Info("testing authentication on %s", bee.Name()) - - // refresh with bad token - if _, err := bee.RefreshAuthToken(ctx, "bad-token"); err == nil { - return errors.New("expected error when making a call while unauthenticated") - } - - // auth with bad password - token, err := bee.Authenticate(ctx, "wrong-password") - if err == nil { - return fmt.Errorf("expected error when authenticating with bad credentials") - } - if token != "" { - return fmt.Errorf("want empty token got %s", token) - } - - // successful auth - token, err = bee.Authenticate(ctx, o.AdminPassword) - if err != nil { - return fmt.Errorf("authenticate: %w", err) - } - - // successful refresh - newToken, err := bee.RefreshAuthToken(ctx, token) - if err != nil { - return fmt.Errorf("refresh: %w", err) - } - if newToken == "" { - return fmt.Errorf("got empty token, want %s", token) - } - - return nil - } -} - -// dryRun does nothing -func dryRun(ctx context.Context, cluster orchestration.Cluster, opts interface{}) error { - return nil // success -} diff --git a/pkg/check/pss/pss.go b/pkg/check/pss/pss.go index d33bcd777..b6bce4626 100644 --- a/pkg/check/pss/pss.go +++ b/pkg/check/pss/pss.go @@ -9,7 +9,6 @@ import ( "time" "github.com/ethersphere/beekeeper/pkg/bee" - "github.com/ethersphere/beekeeper/pkg/bee/api" "github.com/ethersphere/beekeeper/pkg/beekeeper" "github.com/ethersphere/beekeeper/pkg/logging" "github.com/ethersphere/beekeeper/pkg/orchestration" @@ -130,7 +129,7 @@ func (c *Check) testPss(nodeAName, nodeBName string, clients map[string]*bee.Cli } c.logger.Infof("node %s: batched id %s", nodeAName, batchID) - ch, close, err := listenWebsocket(ctx, nodeB.Config().APIURL.Host, nodeB.Config().Restricted, testTopic, c.logger) + ch, close, err := listenWebsocket(ctx, nodeB.Config().APIURL.Host, testTopic, c.logger) if err != nil { cancel() return err @@ -168,19 +167,13 @@ func (c *Check) testPss(nodeAName, nodeBName string, clients map[string]*bee.Cli return nil } -func listenWebsocket(ctx context.Context, host string, setHeader bool, topic string, logger logging.Logger) (<-chan string, func(), error) { +func listenWebsocket(ctx context.Context, host string, topic string, logger logging.Logger) (<-chan string, func(), error) { dialer := &websocket.Dialer{ Proxy: http.ProxyFromEnvironment, HandshakeTimeout: 45 * time.Second, } - var header http.Header - if setHeader { - header = make(http.Header) - header.Add("Authorization", "Bearer "+api.TokenConsumer) - } - - ws, _, err := dialer.DialContext(ctx, fmt.Sprintf("ws://%s/pss/subscribe/%s", host, topic), header) + ws, _, err := dialer.DialContext(ctx, fmt.Sprintf("ws://%s/pss/subscribe/%s", host, topic), http.Header{}) if err != nil { return nil, nil, err } diff --git a/pkg/check/smoke/load.go b/pkg/check/smoke/load.go index 9c02600a1..43ee0ef5e 100644 --- a/pkg/check/smoke/load.go +++ b/pkg/check/smoke/load.go @@ -10,6 +10,7 @@ import ( "time" "github.com/ethersphere/bee/pkg/swarm" + "github.com/ethersphere/beekeeper/pkg/bee" "github.com/ethersphere/beekeeper/pkg/beekeeper" "github.com/ethersphere/beekeeper/pkg/logging" "github.com/ethersphere/beekeeper/pkg/orchestration" @@ -25,14 +26,14 @@ var _ beekeeper.Action = (*LoadCheck)(nil) // Check instance type LoadCheck struct { metrics metrics - logger logging.Logger + log logging.Logger } // NewCheck returns new check -func NewLoadCheck(logger logging.Logger) beekeeper.Action { +func NewLoadCheck(log logging.Logger) beekeeper.Action { return &LoadCheck{ metrics: newMetrics("check_load"), - logger: logger, + log: log, } } @@ -47,9 +48,15 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts return errors.New("no uploaders requested, quiting") } - c.logger.Info("random seed: ", o.RndSeed) - c.logger.Info("content size: ", o.ContentSize) - c.logger.Info("max batch lifespan: ", o.MaxUseBatch) + if o.MaxStorageRadius == 0 { + return errors.New("max storage radius is not set") + } + + c.log.Infof("random seed: %v", o.RndSeed) + c.log.Infof("content size: %v", o.ContentSize) + c.log.Infof("max batch lifespan: %v", o.MaxUseBatch) + c.log.Infof("max storage radius: %v", o.MaxStorageRadius) + c.log.Infof("storage radius check wait time: %v", o.StorageRadiusCheckWait) clients, err := cluster.NodesClients(ctx) if err != nil { @@ -59,7 +66,7 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts ctx, cancel := context.WithTimeout(ctx, o.Duration) defer cancel() - test := &test{clients: clients, logger: c.logger} + test := &test{clients: clients, logger: c.log} uploaders := selectNames(cluster, o.UploadGroups...) downloaders := selectNames(cluster, o.DownloadGroups...) @@ -69,10 +76,10 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts for i := 0; true; i++ { select { case <-ctx.Done(): - c.logger.Info("we are done") + c.log.Info("we are done") return nil default: - c.logger.Infof("starting iteration: #%d", i) + c.log.Infof("starting iteration: #%d", i) } var ( @@ -83,13 +90,13 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts txData = make([]byte, o.ContentSize) if _, err := crand.Read(txData); err != nil { - c.logger.Infof("unable to create random content: %v", err) + c.log.Infof("unable to create random content: %v", err) continue } txNames := pickRandom(o.UploaderCount, uploaders) - c.logger.Infof("uploader: %s", txNames) + c.log.Infof("uploader: %s", txNames) var ( upload sync.WaitGroup @@ -102,24 +109,30 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts txName := txName go func() { - defer once.Do(func() { upload.Done() }) // don't wait for all uploads + defer once.Do(func() { + upload.Done() + }) // don't wait for all uploads for retries := 10; txDuration == 0 && retries > 0; retries-- { select { case <-ctx.Done(): - c.logger.Info("we are done") + c.log.Info("we are done") return default: } + if !c.checkStorageRadius(ctx, test.clients[txName], o.MaxStorageRadius, o.StorageRadiusCheckWait) { + return + } + c.metrics.UploadAttempts.Inc() var duration time.Duration - c.logger.Infof("uploading to: %s", txName) + c.log.Infof("uploading to: %s", txName) batchID := batches.Get(txName) if batchID == "" { batchID, err = clients[txName].CreatePostageBatch(ctx, o.PostageAmount, o.PostageDepth, "load-test", true) if err != nil { - c.logger.Errorf("create new batch: %v", err) + c.log.Errorf("create new batch: %v", err) return } batches.Store(txName, batchID) @@ -128,8 +141,8 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts address, duration, err = test.upload(ctx, txName, txData, batchID) if err != nil { c.metrics.UploadErrors.Inc() - c.logger.Infof("upload failed: %v", err) - c.logger.Infof("retrying in: %v", o.TxOnErrWait) + c.log.Infof("upload failed: %v", err) + c.log.Infof("retrying in: %v", o.TxOnErrWait) time.Sleep(o.TxOnErrWait) return } @@ -144,12 +157,12 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts continue } - c.logger.Infof("sleeping for: %v seconds", o.NodesSyncWait.Seconds()) + c.log.Infof("sleeping for: %v seconds", o.NodesSyncWait.Seconds()) time.Sleep(o.NodesSyncWait) // Wait for nodes to sync. // pick a batch of downloaders rxNames := pickRandom(o.DownloaderCount, downloaders) - c.logger.Infof("downloaders: %s", rxNames) + c.log.Infof("downloaders: %s", rxNames) var wg sync.WaitGroup @@ -167,7 +180,7 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts for retries := 10; rxDuration == 0 && retries > 0; retries-- { select { case <-ctx.Done(): - c.logger.Infof("context done in retry: %v", retries) + c.log.Infof("context done in retry: %v", retries) return default: } @@ -177,8 +190,8 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts rxData, rxDuration, err = test.download(ctx, rxName, address) if err != nil { c.metrics.DownloadErrors.Inc() - c.logger.Infof("download failed: %v", err) - c.logger.Infof("retrying in: %v", o.RxOnErrWait) + c.log.Infof("download failed: %v", err) + c.log.Infof("retrying in: %v", o.RxOnErrWait) time.Sleep(o.RxOnErrWait) } } @@ -189,15 +202,15 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts } if !bytes.Equal(rxData, txData) { - c.logger.Info("uploaded data does not match downloaded data") + c.log.Info("uploaded data does not match downloaded data") c.metrics.DownloadMismatch.Inc() rxLen, txLen := len(rxData), len(txData) if rxLen != txLen { - c.logger.Infof("length mismatch: download length %d; upload length %d", rxLen, txLen) + c.log.Infof("length mismatch: download length %d; upload length %d", rxLen, txLen) if txLen < rxLen { - c.logger.Info("length mismatch: rx length is bigger then tx length") + c.log.Info("length mismatch: rx length is bigger then tx length") } return } @@ -208,7 +221,7 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts diff++ } } - c.logger.Infof("data mismatch: found %d different bytes, ~%.2f%%", diff, float64(diff)/float64(txLen)*100) + c.log.Infof("data mismatch: found %d different bytes, ~%.2f%%", diff, float64(diff)/float64(txLen)*100) return } @@ -225,6 +238,27 @@ func (c *LoadCheck) Run(ctx context.Context, cluster orchestration.Cluster, opts return nil } +func (c *LoadCheck) checkStorageRadius(ctx context.Context, client *bee.Client, maxRadius uint8, wait time.Duration) bool { + for { + rs, err := client.ReserveState(ctx) + if err != nil { + c.log.Infof("error getting state: %v", err) + return false + } + if rs.StorageRadius < maxRadius { + return true + } + c.log.Infof("waiting %v for StorageRadius to decrease. Current: %d, Max: %d", wait, rs.StorageRadius, maxRadius) + + select { + case <-ctx.Done(): + c.log.Infof("context done in StorageRadius check: %v", ctx.Err()) + return false + case <-time.After(wait): + } + } +} + func pickRandom(count int, peers []string) (names []string) { seq := randomIntSeq(count, len(peers)) for _, i := range seq { diff --git a/pkg/check/smoke/smoke.go b/pkg/check/smoke/smoke.go index 8d90b8efc..195dc1596 100644 --- a/pkg/check/smoke/smoke.go +++ b/pkg/check/smoke/smoke.go @@ -29,27 +29,31 @@ type Options struct { UploadTimeout time.Duration DownloadTimeout time.Duration // load test params - UploaderCount int - UploadGroups []string - DownloaderCount int - DownloadGroups []string - MaxUseBatch time.Duration + UploaderCount int + UploadGroups []string + DownloaderCount int + DownloadGroups []string + MaxUseBatch time.Duration + MaxStorageRadius uint8 + StorageRadiusCheckWait time.Duration } // NewDefaultOptions returns new default options func NewDefaultOptions() Options { return Options{ - ContentSize: 5000000, - RndSeed: time.Now().UnixNano(), - PostageAmount: 50_000_000, - PostageDepth: 24, - TxOnErrWait: 10 * time.Second, - RxOnErrWait: 10 * time.Second, - NodesSyncWait: time.Minute, - Duration: 12 * time.Hour, - UploadTimeout: 60 * time.Minute, - DownloadTimeout: 60 * time.Minute, - MaxUseBatch: 12 * time.Hour, + ContentSize: 5000000, + RndSeed: time.Now().UnixNano(), + PostageAmount: 50_000_000, + PostageDepth: 24, + TxOnErrWait: 10 * time.Second, + RxOnErrWait: 10 * time.Second, + NodesSyncWait: time.Minute, + Duration: 12 * time.Hour, + UploadTimeout: 60 * time.Minute, + DownloadTimeout: 60 * time.Minute, + MaxUseBatch: 12 * time.Hour, + MaxStorageRadius: 2, + StorageRadiusCheckWait: 5 * time.Minute, } } diff --git a/pkg/check/stake/stake.go b/pkg/check/stake/stake.go index 7b8232d7e..e7b2e770f 100644 --- a/pkg/check/stake/stake.go +++ b/pkg/check/stake/stake.go @@ -6,9 +6,10 @@ import ( "fmt" "math/big" + "github.com/ethersphere/beekeeper/pkg/bee/api" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethersphere/beekeeper/pkg/bee" - "github.com/ethersphere/beekeeper/pkg/bee/debugapi" "github.com/ethersphere/beekeeper/pkg/beekeeper" "github.com/ethersphere/beekeeper/pkg/logging" "github.com/ethersphere/beekeeper/pkg/orchestration" @@ -67,7 +68,7 @@ func (c *Check) Run(ctx context.Context, cluster orchestration.Cluster, opts int } if paused, err := stake.Paused(); err != nil { - return fmt.Errorf("chack if contract is paused: %w", err) + return fmt.Errorf("check if contract is paused: %w", err) } else if paused { c.logger.Info("contract is paused, skipping") return nil @@ -84,13 +85,13 @@ func (c *Check) Run(ctx context.Context, cluster orchestration.Cluster, opts int client := clients[node] if err := expectStakeAmountIs(ctx, client, zero); err != nil { - return errors.New("check initial staked amount") + return err } // depositing insufficient amount should fail _, err = client.DepositStake(ctx, o.InsufficientAmount) - if !debugapi.IsHTTPStatusErrorCode(err, 400) { + if !api.IsHTTPStatusErrorCode(err, 400) { return fmt.Errorf("deposit insufficient stake amount: expected code %v, got %v", 400, err) } @@ -121,7 +122,7 @@ func (c *Check) Run(ctx context.Context, cluster orchestration.Cluster, opts int } // should not allow withdrawing from a running contract - _, err = client.WithdrawStake(ctx) + _, err = client.MigrateStake(ctx) if err == nil { return errors.New("withdraw from running contract should fail") } @@ -147,7 +148,7 @@ func (c *Check) Run(ctx context.Context, cluster orchestration.Cluster, opts int }() // successful withdraw should set the staked amount to 0 - _, err = client.WithdrawStake(ctx) + _, err = client.MigrateStake(ctx) if err != nil { return fmt.Errorf("withdraw from paused contract: %w", err) } diff --git a/pkg/config/bee.go b/pkg/config/bee.go index 2d2536348..b83f1b6c6 100644 --- a/pkg/config/bee.go +++ b/pkg/config/bee.go @@ -26,8 +26,6 @@ type BeeConfig struct { DbBlockCacheCapacity *int `yaml:"db-block-cache-capacity"` DbWriteBufferSize *int `yaml:"db-write-buffer-size"` DbDisableSeeksCompaction *bool `yaml:"db-disable-seeks-compaction"` - DebugAPIAddr *string `yaml:"debug-api-addr"` - DebugAPIEnable *bool `yaml:"debug-api-enable"` FullNode *bool `yaml:"full-node"` NATAddr *string `yaml:"nat-addr"` Mainnet *bool `yaml:"mainnet"` @@ -45,9 +43,6 @@ type BeeConfig struct { StakingAddress *string `yaml:"staking-address"` StorageIncentivesEnable *string `yaml:"storage-incentives-enable"` ResolverOptions *string `yaml:"resolver-options"` - Restricted *bool `yaml:"restricted"` - TokenEncryptionKey *string `yaml:"token-encryption-key"` - AdminPassword *string `yaml:"admin-password"` ChequebookEnable *bool `yaml:"chequebook-enable"` SwapEnable *bool `yaml:"swap-enable"` SwapEndpoint *string `yaml:"swap-endpoint"` diff --git a/pkg/config/check.go b/pkg/config/check.go index a6ecc6269..4298defb7 100644 --- a/pkg/config/check.go +++ b/pkg/config/check.go @@ -6,11 +6,11 @@ import ( "reflect" "time" + "github.com/ethersphere/beekeeper/pkg/check/act" "github.com/ethersphere/beekeeper/pkg/check/networkavailability" "github.com/ethersphere/beekeeper/pkg/check/stake" "github.com/ethersphere/beekeeper/pkg/beekeeper" - "github.com/ethersphere/beekeeper/pkg/check/authenticated" "github.com/ethersphere/beekeeper/pkg/check/balances" "github.com/ethersphere/beekeeper/pkg/check/cashout" "github.com/ethersphere/beekeeper/pkg/check/datadurability" @@ -57,6 +57,28 @@ type CheckGlobalConfig struct { // Checks represents all available check types var Checks = map[string]CheckType{ + "act": { + NewAction: act.NewCheck, + NewOptions: func(checkGlobalConfig CheckGlobalConfig, check Check) (interface{}, error) { + checkOpts := new(struct { + FileName *string `yaml:"file-name"` + FileSize *int64 `yaml:"file-size"` + PostageAmount *int64 `yaml:"postage-amount"` + PostageDepth *int64 `yaml:"postage-depth"` + PostageLabel *string `yaml:"postage-label"` + Seed *int64 `yaml:"seed"` + }) + if err := check.Options.Decode(checkOpts); err != nil { + return nil, fmt.Errorf("decoding check %s options: %w", check.Type, err) + } + opts := act.NewDefaultOptions() + + if err := applyCheckConfig(checkGlobalConfig, checkOpts, &opts); err != nil { + return nil, fmt.Errorf("applying options: %w", err) + } + return opts, nil + }, + }, "balances": { NewAction: balances.NewCheck, NewOptions: func(checkGlobalConfig CheckGlobalConfig, check Check) (interface{}, error) { @@ -384,20 +406,22 @@ var Checks = map[string]CheckType{ NewAction: smoke.NewLoadCheck, NewOptions: func(checkGlobalConfig CheckGlobalConfig, check Check) (interface{}, error) { checkOpts := new(struct { - ContentSize *int64 `yaml:"content-size"` - RndSeed *int64 `yaml:"rnd-seed"` - PostageAmount *int64 `yaml:"postage-amount"` - PostageDepth *uint64 `yaml:"postage-depth"` - GasPrice *string `yaml:"gas-price"` - TxOnErrWait *time.Duration `yaml:"tx-on-err-wait"` - RxOnErrWait *time.Duration `yaml:"rx-on-err-wait"` - NodesSyncWait *time.Duration `yaml:"nodes-sync-wait"` - Duration *time.Duration `yaml:"duration"` - UploaderCount *int `yaml:"uploader-count"` - UploadGroups *[]string `yaml:"upload-groups"` - DownloaderCount *int `yaml:"downloader-count"` - DownloadGroups *[]string `yaml:"download-groups"` - MaxUseBatch *time.Duration `yaml:"max-use-batch"` + ContentSize *int64 `yaml:"content-size"` + RndSeed *int64 `yaml:"rnd-seed"` + PostageAmount *int64 `yaml:"postage-amount"` + PostageDepth *uint64 `yaml:"postage-depth"` + GasPrice *string `yaml:"gas-price"` + TxOnErrWait *time.Duration `yaml:"tx-on-err-wait"` + RxOnErrWait *time.Duration `yaml:"rx-on-err-wait"` + NodesSyncWait *time.Duration `yaml:"nodes-sync-wait"` + Duration *time.Duration `yaml:"duration"` + UploaderCount *int `yaml:"uploader-count"` + UploadGroups *[]string `yaml:"upload-groups"` + DownloaderCount *int `yaml:"downloader-count"` + DownloadGroups *[]string `yaml:"download-groups"` + MaxUseBatch *time.Duration `yaml:"max-use-batch"` + MaxStorageRadius *uint8 `yaml:"max-storage-radius"` + StorageRadiusCheckWait *time.Duration `yaml:"storage-radius-check-wait"` }) if err := check.Options.Decode(checkOpts); err != nil { return nil, fmt.Errorf("decoding check %s options: %w", check.Type, err) @@ -475,25 +499,6 @@ var Checks = map[string]CheckType{ return opts, nil }, }, - "authenticate": { - NewAction: authenticated.NewCheck, - NewOptions: func(checkGlobalConfig CheckGlobalConfig, check Check) (interface{}, error) { - checkOpts := new(struct { - DryRun *bool `yaml:"dry-run"` - Role *string `yaml:"role"` - AdminPassword *string `yaml:"admin-password"` - RestrictedGroupName *string `yaml:"restricted-group-name"` - }) - if err := check.Options.Decode(checkOpts); err != nil { - return nil, fmt.Errorf("decoding check %s options: %w", check.Type, err) - } - opts := authenticated.NewDefaultOptions() - if err := applyCheckConfig(checkGlobalConfig, checkOpts, &opts); err != nil { - return nil, fmt.Errorf("applying options: %w", err) - } - return opts, nil - }, - }, "longavailability": { NewAction: longavailability.NewCheck, NewOptions: func(checkGlobalConfig CheckGlobalConfig, check Check) (interface{}, error) { diff --git a/pkg/config/cluster.go b/pkg/config/cluster.go index abfb60ef8..4407ac4cd 100644 --- a/pkg/config/cluster.go +++ b/pkg/config/cluster.go @@ -11,27 +11,26 @@ type Cluster struct { // parent to inherit settings from *Inherit `yaml:",inline"` // Cluster configuration - Name *string `yaml:"name"` - Namespace *string `yaml:"namespace"` - DisableNamespace *bool `yaml:"disable-namespace"` - APIDomain *string `yaml:"api-domain"` - APIInsecureTLS *bool `yaml:"api-insecure-tls"` - APIScheme *string `yaml:"api-scheme"` - DebugAPIDomain *string `yaml:"debug-api-domain"` - DebugAPIInsecureTLS *bool `yaml:"debug-api-insecure-tls"` - DebugAPIScheme *string `yaml:"debug-api-scheme"` - Funding *Funding `yaml:"funding"` - NodeGroups *map[string]ClusterNodeGroup `yaml:"node-groups"` - AdminPassword *string `yaml:"admin-password"` + Name *string `yaml:"name"` + Namespace *string `yaml:"namespace"` + DisableNamespace *bool `yaml:"disable-namespace"` + UseStaticEndpoints *bool `yaml:"use-static-endpoints"` + APIDomain *string `yaml:"api-domain"` + APIInsecureTLS *bool `yaml:"api-insecure-tls"` + APIScheme *string `yaml:"api-scheme"` + Funding *Funding `yaml:"funding"` + NodeGroups *map[string]ClusterNodeGroup `yaml:"node-groups"` } // ClusterNodeGroup represents node group in the cluster type ClusterNodeGroup struct { - Mode string `yaml:"mode"` - BeeConfig string `yaml:"bee-config"` - Config string `yaml:"config"` - Count int `yaml:"count"` - Nodes []ClusterNode `yaml:"nodes"` + cluster *Cluster + Mode string `yaml:"mode"` + BeeConfig string `yaml:"bee-config"` + Config string `yaml:"config"` + Count int `yaml:"count"` + Nodes []ClusterNode `yaml:"nodes"` + NodeEndpoints []NodeEndpoint `yaml:"endpoints"` } // ClusterNode represents node in the cluster @@ -43,6 +42,11 @@ type ClusterNode struct { SwarmKey string `yaml:"swarm-key"` } +type NodeEndpoint struct { + Name string `yaml:"name"` + APIURL string `yaml:"api-url"` +} + type Clef struct { Key string `yaml:"key"` Password string `yaml:"password"` @@ -91,5 +95,28 @@ func (c *Cluster) GetNodeGroups() map[string]ClusterNodeGroup { if c.NodeGroups == nil { return nil } - return *c.NodeGroups + + nodeGroups := *c.NodeGroups + for key, group := range nodeGroups { + group.cluster = c // Set the reference to the parent cluster + nodeGroups[key] = group + } + + return nodeGroups +} + +// IsUsingStaticEndpoints +func (c *Cluster) IsUsingStaticEndpoints() bool { + if c.UseStaticEndpoints == nil { + return false + } + return *c.UseStaticEndpoints +} + +func (ng *ClusterNodeGroup) GetEndpoints() map[string]NodeEndpoint { + endpoints := make(map[string]NodeEndpoint) + for _, endpoint := range ng.NodeEndpoints { + endpoints[endpoint.Name] = endpoint + } + return endpoints } diff --git a/pkg/config/nodegroup.go b/pkg/config/nodegroup.go index c3d995dc5..4a6beeda2 100644 --- a/pkg/config/nodegroup.go +++ b/pkg/config/nodegroup.go @@ -19,8 +19,6 @@ type NodeGroup struct { ImagePullSecrets *[]string `yaml:"image-pull-secrets"` IngressAnnotations *map[string]string `yaml:"ingress-annotations"` IngressClass *string `yaml:"ingress-class"` - IngressDebugAnnotations *map[string]string `yaml:"ingress-debug-annotations"` - IngressDebugClass *string `yaml:"ingress-debug-class"` Labels *map[string]string `yaml:"labels"` NodeSelector *map[string]string `yaml:"node-selector"` PersistenceEnabled *bool `yaml:"persistence-enabled"` diff --git a/pkg/k8s/customresource/ingressroute/client.go b/pkg/k8s/customresource/ingressroute/client.go index 8cdd6478e..d18fec747 100644 --- a/pkg/k8s/customresource/ingressroute/client.go +++ b/pkg/k8s/customresource/ingressroute/client.go @@ -82,8 +82,8 @@ func (c *Client) Delete(ctx context.Context, name, namespace string) (err error) return } -// ListDebugNodesHosts list Ingresses that are nodes -func (c *Client) ListDebugNodesHosts(ctx context.Context, namespace string) (nodes []ingress.NodeInfo, err error) { +// ListAPINodesHosts list Ingresses that are nodes +func (c *Client) ListAPINodesHosts(ctx context.Context, namespace string) (nodes []ingress.NodeInfo, err error) { ingressRoutes, err := c.clientset.IngressRoutes(namespace).List(ctx, metav1.ListOptions{ LabelSelector: "app.kubernetes.io/name=bee", }) @@ -96,12 +96,12 @@ func (c *Client) ListDebugNodesHosts(ctx context.Context, namespace string) (nod if ingressRoutes != nil { for _, ingressRoute := range ingressRoutes.Items { - if strings.HasSuffix(ingressRoute.Name, "-debug") { + if strings.HasSuffix(ingressRoute.Name, "-api") { for _, route := range ingressRoute.Spec.Routes { host := route.GetHost() if host != "" { nodes = append(nodes, ingress.NodeInfo{ - Name: strings.TrimSuffix(ingressRoute.Name, "-debug"), + Name: strings.TrimSuffix(ingressRoute.Name, "-api"), Host: host, }) } diff --git a/pkg/k8s/ingress/client.go b/pkg/k8s/ingress/client.go index e756c8055..57a0d7f54 100644 --- a/pkg/k8s/ingress/client.go +++ b/pkg/k8s/ingress/client.go @@ -76,8 +76,8 @@ func (c *Client) Delete(ctx context.Context, name, namespace string) (err error) return } -// ListDebugNodesHosts list Ingresses that are nodes -func (c *Client) ListDebugNodesHosts(ctx context.Context, namespace string) (nodes []NodeInfo, err error) { +// ListAPINodesHosts list Ingresses that are nodes +func (c *Client) ListAPINodesHosts(ctx context.Context, namespace string) (nodes []NodeInfo, err error) { ingreses, err := c.clientset.NetworkingV1().Ingresses(namespace).List(ctx, metav1.ListOptions{ LabelSelector: "app.kubernetes.io/name=bee", }) @@ -89,11 +89,11 @@ func (c *Client) ListDebugNodesHosts(ctx context.Context, namespace string) (nod } for _, ingress := range ingreses.Items { - if strings.HasSuffix(ingress.Name, "-debug") { + if strings.HasSuffix(ingress.Name, "-api") { for _, rule := range ingress.Spec.Rules { if rule.Host != "" { nodes = append(nodes, NodeInfo{ - Name: strings.TrimSuffix(ingress.Name, "-debug"), + Name: strings.TrimSuffix(ingress.Name, "-api"), Host: rule.Host, }) } diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index 7b35dbaa2..50512b552 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -106,7 +106,7 @@ func (c *Client) processPodIP(ctx context.Context, podIp string) (bee.Addresses, // bee.Addresses is struct that represents response with field Ethereum string url := &url.URL{ Scheme: "http", - Host: podIp + ":1635", // it is possible to extract debug port from service + Host: podIp + ":1633", // it is possible to extract port from service Path: "/addresses", } diff --git a/pkg/orchestration/cluster.go b/pkg/orchestration/cluster.go index b67e9e180..5eab5a33c 100644 --- a/pkg/orchestration/cluster.go +++ b/pkg/orchestration/cluster.go @@ -2,7 +2,9 @@ package orchestration import ( "context" + "fmt" "math/rand" + "net/url" "github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/beekeeper/pkg/bee" @@ -11,49 +13,45 @@ import ( ) type Cluster interface { + Accounting(ctx context.Context) (accounting ClusterAccounting, err error) AddNodeGroup(name string, o NodeGroupOptions) Addresses(ctx context.Context) (addrs map[string]NodeGroupAddresses, err error) - Accounting(ctx context.Context) (accounting ClusterAccounting, err error) Balances(ctx context.Context) (balances ClusterBalances, err error) - FlattenBalances(ctx context.Context) (balances NodeGroupBalances, err error) FlattenAccounting(ctx context.Context) (accounting NodeGroupAccounting, err error) + FlattenBalances(ctx context.Context) (balances NodeGroupBalances, err error) + FlattenOverlays(ctx context.Context, exclude ...string) (map[string]swarm.Address, error) + FlattenSettlements(ctx context.Context) (settlements NodeGroupSettlements, err error) + FlattenTopologies(ctx context.Context) (topologies map[string]bee.Topology, err error) + FullNodeNames() (names []string) GlobalReplicationFactor(ctx context.Context, a swarm.Address) (grf int, err error) + LightNodeNames() (names []string) Name() string + NodeGroup(name string) (ng NodeGroup, err error) NodeGroups() (l map[string]NodeGroup) NodeGroupsSorted() (l []string) - NodeGroup(name string) (ng NodeGroup, err error) - Nodes() map[string]Node NodeNames() (names []string) - LightNodeNames() (names []string) - FullNodeNames() (names []string) + Nodes() map[string]Node NodesClients(ctx context.Context) (map[string]*bee.Client, error) NodesClientsAll(ctx context.Context) (map[string]*bee.Client, error) Overlays(ctx context.Context, exclude ...string) (overlays ClusterOverlays, err error) - FlattenOverlays(ctx context.Context, exclude ...string) (map[string]swarm.Address, error) Peers(ctx context.Context, exclude ...string) (peers ClusterPeers, err error) RandomNode(ctx context.Context, r *rand.Rand) (node Node, err error) Settlements(ctx context.Context) (settlements ClusterSettlements, err error) - FlattenSettlements(ctx context.Context) (settlements NodeGroupSettlements, err error) Size() (size int) Topologies(ctx context.Context) (topologies ClusterTopologies, err error) - FlattenTopologies(ctx context.Context) (topologies map[string]bee.Topology, err error) } // ClusterOptions represents Bee cluster options type ClusterOptions struct { - Annotations map[string]string - APIDomain string - APIInsecureTLS bool - APIScheme string - DebugAPIDomain string - DebugAPIInsecureTLS bool - DebugAPIScheme string - K8SClient *k8s.Client - SwapClient swap.Client - Labels map[string]string - Namespace string - DisableNamespace bool - AdminPassword string + Annotations map[string]string + APIDomain string + APIInsecureTLS bool + APIScheme string + K8SClient *k8s.Client + SwapClient swap.Client + Labels map[string]string + Namespace string + DisableNamespace bool } // ClusterAddresses represents addresses of all nodes in the cluster @@ -106,3 +104,24 @@ func (c ClusterOverlays) Random(r *rand.Rand) (nodeGroup string, nodeName string } return ng, name, o } + +// ApiURL generates URL for node's API +func (c ClusterOptions) ApiURL(name string) (u *url.URL, err error) { + if c.DisableNamespace { + u, err = url.Parse(fmt.Sprintf("%s://%s.%s", c.APIScheme, name, c.APIDomain)) + } else { + u, err = url.Parse(fmt.Sprintf("%s://%s.%s.%s", c.APIScheme, name, c.Namespace, c.APIDomain)) + } + if err != nil { + return nil, fmt.Errorf("bad API url for node %s: %w", name, err) + } + return +} + +// IngressHost generates host for node's API ingress +func (c ClusterOptions) IngressHost(name string) string { + if c.DisableNamespace { + return fmt.Sprintf("%s.%s", name, c.APIDomain) + } + return fmt.Sprintf("%s.%s.%s", name, c.Namespace, c.APIDomain) +} diff --git a/pkg/orchestration/k8s/cluster.go b/pkg/orchestration/k8s/cluster.go index b05622c7b..1be6ca1e1 100644 --- a/pkg/orchestration/k8s/cluster.go +++ b/pkg/orchestration/k8s/cluster.go @@ -4,15 +4,13 @@ import ( "context" "fmt" "math/rand" - "net/url" "sort" "github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/beekeeper/pkg/bee" - "github.com/ethersphere/beekeeper/pkg/k8s" "github.com/ethersphere/beekeeper/pkg/logging" "github.com/ethersphere/beekeeper/pkg/orchestration" - "github.com/ethersphere/beekeeper/pkg/swap" + "github.com/ethersphere/beekeeper/pkg/orchestration/notset" ) // compile check whether client implements interface @@ -20,53 +18,35 @@ var _ orchestration.Cluster = (*Cluster)(nil) // Cluster represents cluster of Bee nodes type Cluster struct { - name string - annotations map[string]string - apiDomain string - apiInsecureTLS bool - apiScheme string - debugAPIDomain string - debugAPIInsecureTLS bool - debugAPIScheme string - k8s *k8s.Client - swap swap.Client - labels map[string]string - namespace string - disableNamespace bool // do not use namespace for node hostnames - nodeGroups map[string]*NodeGroup // set when groups are added to the cluster - logger logging.Logger + nodeOrchestrator orchestration.NodeOrchestrator + name string + opts orchestration.ClusterOptions + nodeGroups map[string]orchestration.NodeGroup // set when groups are added to the cluster + log logging.Logger } // NewCluster returns new cluster -func NewCluster(name string, o orchestration.ClusterOptions, logger logging.Logger) *Cluster { +func NewCluster(name string, o orchestration.ClusterOptions, log logging.Logger) *Cluster { + var no orchestration.NodeOrchestrator + + if o.K8SClient == nil { + no = ¬set.BeeClient{} + } else { + no = newNodeOrchestrator(o.K8SClient, log) + } + return &Cluster{ - name: name, - annotations: o.Annotations, - apiDomain: o.APIDomain, - apiInsecureTLS: o.APIInsecureTLS, - apiScheme: o.APIScheme, - debugAPIDomain: o.DebugAPIDomain, - debugAPIInsecureTLS: o.DebugAPIInsecureTLS, - debugAPIScheme: o.DebugAPIScheme, - k8s: o.K8SClient, - swap: o.SwapClient, - labels: o.Labels, - namespace: o.Namespace, - disableNamespace: o.DisableNamespace, - nodeGroups: make(map[string]*NodeGroup), - logger: logger, + name: name, + nodeOrchestrator: no, + opts: o, + nodeGroups: make(map[string]orchestration.NodeGroup), + log: log, } } // AddNodeGroup adds new node group to the cluster func (c *Cluster) AddNodeGroup(name string, o orchestration.NodeGroupOptions) { - g := NewNodeGroup(name, o, c.logger) - g.cluster = c - g.k8s = c.k8s - g.opts.Annotations = mergeMaps(g.cluster.annotations, o.Annotations) - g.opts.Labels = mergeMaps(g.cluster.labels, o.Labels) - - c.nodeGroups[name] = g + c.nodeGroups[name] = NewNodeGroup(name, c.opts, c.nodeOrchestrator, o, c.log) } // Addresses returns ClusterAddresses @@ -355,7 +335,7 @@ func (c *Cluster) RandomNode(ctx context.Context, r *rand.Rand) (node orchestrat nodes := []orchestration.Node{} for _, ng := range c.NodeGroups() { stopped, err := ng.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -451,45 +431,3 @@ func (c *Cluster) FlattenTopologies(ctx context.Context) (topologies map[string] return } - -// apiURL generates URL for node's API -func (c *Cluster) apiURL(name string) (u *url.URL, err error) { - if c.disableNamespace { - u, err = url.Parse(fmt.Sprintf("%s://%s.%s", c.apiScheme, name, c.apiDomain)) - } else { - u, err = url.Parse(fmt.Sprintf("%s://%s.%s.%s", c.apiScheme, name, c.namespace, c.apiDomain)) - } - if err != nil { - return nil, fmt.Errorf("bad API url for node %s: %w", name, err) - } - return -} - -// ingressHost generates host for node's API ingress -func (c *Cluster) ingressHost(name string) string { - if c.disableNamespace { - return fmt.Sprintf("%s.%s", name, c.apiDomain) - } - return fmt.Sprintf("%s.%s.%s", name, c.namespace, c.apiDomain) -} - -// debugAPIURL generates URL for node's DebugAPI -func (c *Cluster) debugAPIURL(name string) (u *url.URL, err error) { - if c.disableNamespace { - u, err = url.Parse(fmt.Sprintf("%s://%s-debug.%s", c.debugAPIScheme, name, c.debugAPIDomain)) - } else { - u, err = url.Parse(fmt.Sprintf("%s://%s-debug.%s.%s", c.debugAPIScheme, name, c.namespace, c.debugAPIDomain)) - } - if err != nil { - return nil, fmt.Errorf("bad debug API url for node %s: %w", name, err) - } - return -} - -// ingressHost generates host for node's DebugAPI ingress -func (c *Cluster) ingressDebugHost(name string) string { - if c.disableNamespace { - return fmt.Sprintf("%s-debug.%s", name, c.debugAPIDomain) - } - return fmt.Sprintf("%s-debug.%s.%s", name, c.namespace, c.debugAPIDomain) -} diff --git a/pkg/orchestration/k8s/helpers.go b/pkg/orchestration/k8s/helpers.go index f2c27dc4f..671abb589 100644 --- a/pkg/orchestration/k8s/helpers.go +++ b/pkg/orchestration/k8s/helpers.go @@ -25,8 +25,6 @@ db-open-files-limit: {{.DbOpenFilesLimit}} db-block-cache-capacity: {{.DbBlockCacheCapacity}} db-write-buffer-size: {{.DbWriteBufferSize}} db-disable-seeks-compaction: {{.DbDisableSeeksCompaction}} -debug-api-addr: {{.DebugAPIAddr}} -debug-api-enable: {{.DebugAPIEnable}} full-node: {{.FullNode}} mainnet: {{.Mainnet}} nat-addr: {{.NATAddr}} @@ -44,9 +42,6 @@ redistribution-address: {{ .RedistributionAddress }} staking-address: {{ .StakingAddress }} storage-incentives-enable: {{ .StorageIncentivesEnable }} resolver-options: {{.ResolverOptions}} -restricted: {{.Restricted}} -token-encryption-key: {{.TokenEncryptionKey}} -admin-password: {{.AdminPassword}} chequebook-enable: {{.ChequebookEnable}} swap-enable: {{.SwapEnable}} swap-endpoint: {{.SwapEndpoint}} @@ -110,7 +105,6 @@ type setContainersOptions struct { Image string ImagePullPolicy string PortAPI int32 - PortDebug int32 PortP2P int32 PersistenceEnabled bool ResourcesLimitCPU string @@ -138,11 +132,6 @@ func setContainers(o setContainersOptions) (c containers.Containers) { ContainerPort: o.PortAPI, Protocol: "TCP", }, - { - Name: "debug", - ContainerPort: o.PortDebug, - Protocol: "TCP", - }, { Name: "p2p", ContainerPort: o.PortP2P, @@ -153,7 +142,7 @@ func setContainers(o setContainersOptions) (c containers.Containers) { InitialDelaySeconds: 5, Handler: containers.HTTPGetHandler{ Path: "/health", - Port: "debug", + Port: "api", }, }}, ReadinessProbe: containers.Probe{HTTPGet: &containers.HTTPGetProbe{ @@ -163,7 +152,7 @@ func setContainers(o setContainersOptions) (c containers.Containers) { // because Beekeeper does funding it needs node to be ready before it is funded // if Bee readiness is changed to be ready before funding, path can be set to "/readiness" Path: "/health", - Port: "debug", + Port: "api", }, }}, Resources: containers.Resources{ @@ -410,6 +399,11 @@ func setBeeNodePort(o setBeeNodePortOptions) (ports service.Ports) { }} } +func parsePort(port string) (int32, error) { + p, err := strconv.ParseInt(strings.Split(port, ":")[1], 10, 32) + return int32(p), err +} + func mergeMaps(a, b map[string]string) map[string]string { m := map[string]string{} for k, v := range a { @@ -421,8 +415,3 @@ func mergeMaps(a, b map[string]string) map[string]string { return m } - -func parsePort(port string) (int32, error) { - p, err := strconv.ParseInt(strings.Split(port, ":")[1], 10, 32) - return int32(p), err -} diff --git a/pkg/orchestration/k8s/node.go b/pkg/orchestration/k8s/node.go index 9634c2a8e..614de2c91 100644 --- a/pkg/orchestration/k8s/node.go +++ b/pkg/orchestration/k8s/node.go @@ -1,21 +1,9 @@ package k8s import ( - "bytes" "context" - "fmt" - "html/template" "github.com/ethersphere/beekeeper/pkg/bee" - "github.com/ethersphere/beekeeper/pkg/k8s" - "github.com/ethersphere/beekeeper/pkg/k8s/configmap" - "github.com/ethersphere/beekeeper/pkg/k8s/customresource/ingressroute" - "github.com/ethersphere/beekeeper/pkg/k8s/ingress" - "github.com/ethersphere/beekeeper/pkg/k8s/pod" - "github.com/ethersphere/beekeeper/pkg/k8s/secret" - "github.com/ethersphere/beekeeper/pkg/k8s/service" - "github.com/ethersphere/beekeeper/pkg/k8s/serviceaccount" - "github.com/ethersphere/beekeeper/pkg/k8s/statefulset" "github.com/ethersphere/beekeeper/pkg/logging" "github.com/ethersphere/beekeeper/pkg/orchestration" ) @@ -25,47 +13,20 @@ var _ orchestration.Node = (*Node)(nil) // Node represents Bee node type Node struct { - name string - clefKey string - clefPassword string - client *bee.Client - config *orchestration.Config - k8s *k8s.Client - libP2PKey string - swarmKey string - logger logging.Logger + orchestration.NodeOrchestrator + name string + opts orchestration.NodeOptions + log logging.Logger } // NewNode returns Bee node -func NewNode(name string, opts orchestration.NodeOptions, logger logging.Logger) (n *Node) { - n = &Node{ - name: name, - logger: logger, +func NewNode(name string, opts orchestration.NodeOptions, no orchestration.NodeOrchestrator, log logging.Logger) (n *Node) { + return &Node{ + NodeOrchestrator: no, + name: name, + opts: opts, + log: log, } - - if opts.Client != nil { - n.client = opts.Client - } - if opts.Config != nil { - n.config = opts.Config - } - if len(opts.ClefKey) > 0 { - n.clefKey = opts.ClefKey - } - if len(opts.ClefPassword) > 0 { - n.clefPassword = opts.ClefPassword - } - if len(opts.LibP2PKey) > 0 { - n.libP2PKey = opts.LibP2PKey - } - if len(opts.SwarmKey) > 0 { - n.swarmKey = opts.SwarmKey.ToString() - } - if opts.K8S != nil { - n.k8s = opts.K8S - } - - return } // Name returns node's name @@ -75,555 +36,78 @@ func (n Node) Name() string { // Client returns node's name func (n Node) Client() *bee.Client { - return n.client + return n.opts.Client } // Config returns node's config func (n Node) Config() *orchestration.Config { - return n.config + return n.opts.Config } // ClefKey returns node's clefKey func (n Node) ClefKey() string { - return n.clefKey + return n.opts.ClefKey } // ClefPassword returns node's clefPassword func (n Node) ClefPassword() string { - return n.clefPassword + return n.opts.ClefPassword } // LibP2PKey returns node's libP2PKey func (n Node) LibP2PKey() string { - return n.libP2PKey + return n.opts.LibP2PKey } // SwarmKey returns node's swarmKey func (n Node) SwarmKey() string { - return n.swarmKey + return n.opts.SwarmKey.String() } // SetSwarmKey sets node's Swarm key func (n Node) SetSwarmKey(key string) orchestration.Node { - n.swarmKey = key + n.opts.SwarmKey = orchestration.EncryptedKey(key) return n } // SetClefKey sets node's Clef key func (n Node) SetClefKey(key string) orchestration.Node { - n.clefKey = key + n.opts.ClefKey = key return n } // SetClefKey sets node's Clef key func (n Node) SetClefPassword(password string) orchestration.Node { - n.clefPassword = password + n.opts.ClefPassword = password return n } -// Create +// Create implements orchestration.Node. +// Subtle: this method shadows the method (NodeOrchestrator).Create of Node.NodeOrchestrator. func (n Node) Create(ctx context.Context, o orchestration.CreateOptions) (err error) { - // bee configuration - var config bytes.Buffer - if err := template.Must(template.New("").Parse(configTemplate)).Execute(&config, o.Config); err != nil { - return err - } - - configCM := o.Name - if _, err = n.k8s.ConfigMap.Set(ctx, configCM, o.Namespace, configmap.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - Data: map[string]string{ - ".bee.yaml": config.String(), - }, - }); err != nil { - return fmt.Errorf("set configmap in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("configmap %s is set in namespace %s", configCM, o.Namespace) - - // secret with keys - keysSecret := fmt.Sprintf("%s-keys", o.Name) - keysSecretData := map[string]string{} - if len(o.LibP2PKey) > 0 { - keysSecretData["libp2p"] = o.LibP2PKey - } - if len(o.SwarmKey) > 0 { - keysSecretData["swarm"] = o.SwarmKey - } - - if _, err := n.k8s.Secret.Set(ctx, keysSecret, o.Namespace, secret.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - StringData: keysSecretData, - }); err != nil { - return fmt.Errorf("set secret in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("secret %s is set in namespace %s", keysSecret, o.Namespace) - - // secret with clef key and pass - clefSecretEnabled := len(o.ClefKey) > 0 && len(o.ClefPassword) > 0 - clefSecret := fmt.Sprintf("%s-clef", o.Name) - if o.Config.ClefSignerEnable && clefSecretEnabled { - clefSecretData := map[string]string{ - "key": o.ClefKey, - "password": o.ClefPassword, - } - if _, err := n.k8s.Secret.Set(ctx, clefSecret, o.Namespace, secret.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - StringData: clefSecretData, - }); err != nil { - return fmt.Errorf("set secret in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("secret %s is set in namespace %s", clefSecret, o.Namespace) - } - - // service account - svcAccount := o.Name - if _, err := n.k8s.ServiceAccount.Set(ctx, svcAccount, o.Namespace, serviceaccount.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - ImagePullSecrets: o.ImagePullSecrets, - }); err != nil { - return fmt.Errorf("set serviceaccount in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("serviceaccount %s is set in namespace %s", svcAccount, o.Namespace) - - // api service - portAPI, err := parsePort(o.Config.APIAddr) - if err != nil { - return fmt.Errorf("parsing API port from config: %s", err) - } - - apiSvc := fmt.Sprintf("%s-api", o.Name) - if _, err := n.k8s.Service.Set(ctx, apiSvc, o.Namespace, service.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - ServiceSpec: service.Spec{ - Ports: service.Ports{ - { - AppProtocol: "TCP", - Name: "api", - Protocol: "TCP", - Port: portAPI, - TargetPort: "api", - }, - }, - Selector: o.Selector, - Type: "ClusterIP", - }, - }); err != nil { - return fmt.Errorf("set service in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("service %s is set in namespace %s", apiSvc, o.Namespace) - - if o.IngressClass == "traefik" { - // api service's ingressroute - apiIn := fmt.Sprintf("%s-api", o.Name) - if _, err := n.k8s.IngressRoute.Set(ctx, apiIn, o.Namespace, ingressroute.Options{ - Annotations: mergeMaps(o.Annotations, o.IngressAnnotations), - Labels: o.Labels, - Spec: ingressroute.IngressRouteSpec{ - Routes: []ingressroute.Route{ - { - Kind: "Rule", - Match: fmt.Sprintf("Host(\"%s.localhost\") && PathPrefix(\"/\")", o.Name), - Services: []ingressroute.Service{ - { - Kind: "Service", - Name: apiIn, - Namespace: "local", - Port: "api", - }, - }, - }, - }, - }, - }); err != nil { - return fmt.Errorf("set ingressroute in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("ingressroute %s is set in namespace %s", apiIn, o.Namespace) - } else { - // api service's ingress - apiIn := fmt.Sprintf("%s-api", o.Name) - if _, err := n.k8s.Ingress.Set(ctx, apiIn, o.Namespace, ingress.Options{ - Annotations: mergeMaps(o.Annotations, o.IngressAnnotations), - Labels: o.Labels, - Spec: ingress.Spec{ - Class: o.IngressClass, - Rules: ingress.Rules{{ - Host: o.IngressHost, - Paths: ingress.Paths{{ - Backend: ingress.Backend{ - ServiceName: apiSvc, - ServicePortName: "api", - }, - Path: "/", - PathType: "ImplementationSpecific", - }}, - }}, - }, - }); err != nil { - return fmt.Errorf("set ingress in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("ingress %s is set in namespace %s", apiIn, o.Namespace) - } - - // debug API - portDebug, err := parsePort(o.Config.DebugAPIAddr) - if err != nil { - return fmt.Errorf("parsing Debug port from config: %s", err) - } - - // debug service - debugSvc := fmt.Sprintf("%s-debug", o.Name) - if _, err := n.k8s.Service.Set(ctx, debugSvc, o.Namespace, service.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - ServiceSpec: service.Spec{ - Ports: service.Ports{{ - AppProtocol: "TCP", - Name: "debug", - Protocol: "TCP", - Port: portDebug, - TargetPort: "debug", - }}, - Selector: o.Selector, - Type: "ClusterIP", - }, - }); err != nil { - return fmt.Errorf("set service in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("service %s is set in namespace %s", debugSvc, o.Namespace) - - if o.IngressDebugClass == "traefik" { - // debug service's ingressroute - debugIn := fmt.Sprintf("%s-debug", o.Name) - if _, err := n.k8s.IngressRoute.Set(ctx, debugIn, o.Namespace, ingressroute.Options{ - Annotations: mergeMaps(o.Annotations, o.IngressAnnotations), - Labels: o.Labels, - Spec: ingressroute.IngressRouteSpec{ - Routes: []ingressroute.Route{ - { - Kind: "Rule", - Match: fmt.Sprintf("Host(\"%s.localhost\") && PathPrefix(\"/\")", debugIn), - Services: []ingressroute.Service{ - { - Kind: "Service", - Name: debugIn, - Namespace: "local", - Port: "debug", - }, - }, - }, - }, - }, - }); err != nil { - return fmt.Errorf("set ingressroute in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("ingressroute %s is set in namespace %s", debugIn, o.Namespace) - } else { - // debug service's ingress - debugIn := fmt.Sprintf("%s-debug", o.Name) - if _, err := n.k8s.Ingress.Set(ctx, debugIn, o.Namespace, ingress.Options{ - Annotations: mergeMaps(o.Annotations, o.IngressDebugAnnotations), - Labels: o.Labels, - Spec: ingress.Spec{ - Class: o.IngressDebugClass, - Rules: ingress.Rules{{ - Host: o.IngressDebugHost, - Paths: ingress.Paths{{ - Backend: ingress.Backend{ - ServiceName: debugSvc, - ServicePortName: "debug", - }, - Path: "/", - PathType: "ImplementationSpecific", - }}, - }}, - }, - }); err != nil { - return fmt.Errorf("set ingress in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("ingress %s is set in namespace %s", debugIn, o.Namespace) - } - - // p2p service - portP2P, err := parsePort(o.Config.P2PAddr) - if err != nil { - return fmt.Errorf("parsing P2P port from config: %s", err) - } - - var nodePortP2P int32 - if len(o.Config.NATAddr) > 0 { - nodePortP2P, err = parsePort(o.Config.NATAddr) - if err != nil { - return fmt.Errorf("parsing NAT address from config: %s", err) - } - } - - p2pSvc := fmt.Sprintf("%s-p2p", o.Name) - if _, err := n.k8s.Service.Set(ctx, p2pSvc, o.Namespace, service.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - ServiceSpec: service.Spec{ - ExternalTrafficPolicy: "Local", - Ports: setBeeNodePort(setBeeNodePortOptions{ - AppProtocol: "TCP", - Name: "p2p", - Protocol: "TCP", - TargetPort: "p2p", - Port: portP2P, - NodePort: nodePortP2P, - }), - Selector: o.Selector, - Type: "NodePort", - }, - }); err != nil { - return fmt.Errorf("set service in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("service %s is set in namespace %s", p2pSvc, o.Namespace) - - // headless service - headlessSvc := fmt.Sprintf("%s-headless", o.Name) - if _, err := n.k8s.Service.Set(ctx, headlessSvc, o.Namespace, service.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - ServiceSpec: service.Spec{ - Ports: service.Ports{ - { - AppProtocol: "TCP", - Name: "api", - Protocol: "TCP", - Port: portAPI, - TargetPort: "api", - }, - { - AppProtocol: "TCP", - Name: "debug", - Protocol: "TCP", - Port: portDebug, - TargetPort: "debug", - }, - { - AppProtocol: "TCP", - Name: "p2p", - Protocol: "TCP", - Port: portP2P, - TargetPort: "p2p", - }, - }, - Selector: o.Selector, - Type: "ClusterIP", - }, - }); err != nil { - return fmt.Errorf("set service in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("service %s is set in namespace %s", headlessSvc, o.Namespace) - - // statefulset - sSet := o.Name - clefEnabled := o.Config.ClefSignerEnable - libP2PEnabled := len(o.LibP2PKey) > 0 - swarmEnabled := len(o.SwarmKey) > 0 - - if _, err := n.k8s.StatefulSet.Set(ctx, sSet, o.Namespace, statefulset.Options{ - Annotations: o.Annotations, - Labels: o.Labels, - Spec: statefulset.StatefulSetSpec{ - PodManagementPolicy: o.PodManagementPolicy, - Replicas: 0, - Selector: o.Selector, - ServiceName: headlessSvc, - Template: pod.PodTemplateSpec{ - Name: sSet, - Namespace: o.Namespace, - Annotations: o.Annotations, - Labels: o.Labels, - Spec: pod.PodSpec{ - InitContainers: setInitContainers(setInitContainersOptions{ - ClefEnabled: clefEnabled, - ClefSecretEnabled: clefSecretEnabled, - ClefImage: o.ClefImage, - ClefImagePullPolicy: o.ClefImagePullPolicy, - ClefPassword: o.ClefPassword, - LibP2PEnabled: libP2PEnabled, - SwarmEnabled: swarmEnabled, - }), - Containers: setContainers(setContainersOptions{ - Name: sSet, - Image: o.Image, - ImagePullPolicy: o.ImagePullPolicy, - PortAPI: portAPI, - PortDebug: portDebug, - PortP2P: portP2P, - PersistenceEnabled: o.PersistenceEnabled, - ResourcesLimitCPU: o.ResourcesLimitCPU, - ResourcesLimitMemory: o.ResourcesLimitMemory, - ResourcesRequestCPU: o.ResourcesRequestCPU, - ResourcesRequestMemory: o.ResourcesRequestMemory, - ClefEnabled: clefEnabled, - ClefSecretEnabled: clefSecretEnabled, - ClefImage: o.ClefImage, - ClefImagePullPolicy: o.ClefImagePullPolicy, - ClefPassword: o.ClefPassword, - LibP2PEnabled: libP2PEnabled, - SwarmEnabled: swarmEnabled, - }), - NodeSelector: o.NodeSelector, - PodSecurityContext: pod.PodSecurityContext{ - FSGroup: 999, - }, - RestartPolicy: o.RestartPolicy, - ServiceAccountName: svcAccount, - Volumes: setVolumes(setVolumesOptions{ - ConfigCM: configCM, - KeysSecret: keysSecret, - PersistenceEnabled: o.PersistenceEnabled, - ClefEnabled: clefEnabled, - ClefSecretEnabled: clefSecretEnabled, - ClefSecret: clefSecret, - LibP2PEnabled: libP2PEnabled, - SwarmEnabled: swarmEnabled, - }), - }, - }, - UpdateStrategy: statefulset.UpdateStrategy{ - Type: o.UpdateStrategy, - }, - VolumeClaimTemplates: setPersistentVolumeClaims(setPersistentVolumeClaimsOptions{ - Enabled: o.PersistenceEnabled, - StorageClass: o.PersistenceStorageClass, - StorageRequest: o.PersistenceStorageRequest, - }), - }, - }); err != nil { - return fmt.Errorf("set statefulset in namespace %s: %w", o.Namespace, err) - } - n.logger.Infof("statefulset %s is set in namespace %s", sSet, o.Namespace) - - return + return n.NodeOrchestrator.Create(ctx, o) } +// Delete implements orchestration.Node. +// Subtle: this method shadows the method (NodeOrchestrator).Delete of Node.NodeOrchestrator. func (n Node) Delete(ctx context.Context, namespace string) (err error) { - // statefulset - if err := n.k8s.StatefulSet.Delete(ctx, n.name, namespace); err != nil { - return fmt.Errorf("deleting statefulset in namespace %s: %w", namespace, err) - } - n.logger.Infof("statefulset %s is deleted in namespace %s", n.name, namespace) - - // headless service - headlessSvc := fmt.Sprintf("%s-headless", n.name) - if err := n.k8s.Service.Delete(ctx, headlessSvc, namespace); err != nil { - return fmt.Errorf("deleting service in namespace %s: %w", namespace, err) - } - n.logger.Infof("service %s is deleted in namespace %s", headlessSvc, namespace) - - // p2p service - p2pSvc := fmt.Sprintf("%s-p2p", n.name) - if err := n.k8s.Service.Delete(ctx, p2pSvc, namespace); err != nil { - return fmt.Errorf("deleting service in namespace %s: %w", namespace, err) - } - n.logger.Infof("service %s is deleted in namespace %s", p2pSvc, namespace) - - // debug service's ingress - debugIn := fmt.Sprintf("%s-debug", n.name) - if err := n.k8s.Ingress.Delete(ctx, debugIn, namespace); err != nil { - return fmt.Errorf("deleting ingress in namespace %s: %w", namespace, err) - } - n.logger.Infof("ingress %s is deleted in namespace %s", debugIn, namespace) - - // debug service's ingress route - if err := n.k8s.IngressRoute.Delete(ctx, debugIn, namespace); err != nil { - return fmt.Errorf("deleting ingress route in namespace %s: %w", namespace, err) - } - n.logger.Infof("ingress route %s is deleted in namespace %s", debugIn, namespace) - - // debug service - debugSvc := fmt.Sprintf("%s-debug", n.name) - if err := n.k8s.Service.Delete(ctx, debugSvc, namespace); err != nil { - return fmt.Errorf("deleting service in namespace %s: %w", namespace, err) - } - n.logger.Infof("service %s is deleted in namespace %s", debugSvc, namespace) - - // api service's ingress - apiIn := fmt.Sprintf("%s-api", n.name) - if err := n.k8s.Ingress.Delete(ctx, apiIn, namespace); err != nil { - return fmt.Errorf("deleting ingress in namespace %s: %w", namespace, err) - } - n.logger.Infof("ingress %s is deleted in namespace %s", apiIn, namespace) - - // api service's ingress route - if err := n.k8s.IngressRoute.Delete(ctx, apiIn, namespace); err != nil { - return fmt.Errorf("deleting ingress route in namespace %s: %w", namespace, err) - } - n.logger.Infof("ingress route %s is deleted in namespace %s", apiIn, namespace) - - // api service - apiSvc := fmt.Sprintf("%s-api", n.name) - if err := n.k8s.Service.Delete(ctx, apiSvc, namespace); err != nil { - return fmt.Errorf("deleting service in namespace %s: %w", namespace, err) - } - n.logger.Infof("service %s is deleted in namespace %s", apiSvc, namespace) - - // service account - svcAccount := n.name - if err := n.k8s.ServiceAccount.Delete(ctx, svcAccount, namespace); err != nil { - return fmt.Errorf("deleting serviceaccount in namespace %s: %w", namespace, err) - } - n.logger.Infof("serviceaccount %s is deleted in namespace %s", svcAccount, namespace) - - // secret with clef key - clefSecret := fmt.Sprintf("%s-clef", n.name) - if err := n.k8s.Secret.Delete(ctx, clefSecret, namespace); err != nil { - return fmt.Errorf("deleting secret in namespace %s: %w", namespace, err) - } - n.logger.Infof("secret %s is deleted in namespace %s", clefSecret, namespace) - - // secret with keys - keysSecret := fmt.Sprintf("%s-keys", n.name) - if err = n.k8s.Secret.Delete(ctx, keysSecret, namespace); err != nil { - return fmt.Errorf("deleting secret %s in namespace %s: %w", keysSecret, namespace, err) - } - n.logger.Infof("secret %s is deleted in namespace %s", keysSecret, namespace) - - // bee configuration - configCM := n.name - if err = n.k8s.ConfigMap.Delete(ctx, configCM, namespace); err != nil { - return fmt.Errorf("deleting configmap %s in namespace %s: %w", configCM, namespace, err) - } - n.logger.Infof("configmap %s is deleted in namespace %s", configCM, namespace) - - n.logger.Infof("node %s is deleted in namespace %s", n.name, namespace) - return + return n.NodeOrchestrator.Delete(ctx, n.name, namespace) } +// Ready implements orchestration.Node. +// Subtle: this method shadows the method (NodeOrchestrator).Ready of Node.NodeOrchestrator. func (n Node) Ready(ctx context.Context, namespace string) (ready bool, err error) { - // r, err := n.k8s.StatefulSet.ReadyReplicas(ctx, n.name, namespace) - r, err := n.k8s.StatefulSet.ReadyReplicasWatch(ctx, n.name, namespace) - if err != nil { - return false, fmt.Errorf("statefulset %s in namespace %s ready replicas: %w", n.name, namespace, err) - } - - return r == 1, nil + return n.NodeOrchestrator.Ready(ctx, n.name, namespace) } +// Start implements orchestration.Node. +// Subtle: this method shadows the method (NodeOrchestrator).Start of Node.NodeOrchestrator. func (n Node) Start(ctx context.Context, namespace string) (err error) { - _, err = n.k8s.StatefulSet.Scale(ctx, n.name, namespace, 1) - if err != nil { - return fmt.Errorf("scale statefulset %s in namespace %s: %w", n.name, namespace, err) - } - - n.logger.Infof("node %s is started in namespace %s", n.name, namespace) - return + return n.NodeOrchestrator.Start(ctx, n.name, namespace) } +// Stop implements orchestration.Node. +// Subtle: this method shadows the method (NodeOrchestrator).Stop of Node.NodeOrchestrator. func (n Node) Stop(ctx context.Context, namespace string) (err error) { - _, err = n.k8s.StatefulSet.Scale(ctx, n.name, namespace, 0) - if err != nil { - return fmt.Errorf("scale statefulset %s in namespace %s: %w", n.name, namespace, err) - } - - n.logger.Infof("node %s is stopped in namespace %s", n.name, namespace) - return + return n.NodeOrchestrator.Stop(ctx, n.name, namespace) } diff --git a/pkg/orchestration/k8s/node_orchestrator.go b/pkg/orchestration/k8s/node_orchestrator.go new file mode 100644 index 000000000..d94c99047 --- /dev/null +++ b/pkg/orchestration/k8s/node_orchestrator.go @@ -0,0 +1,453 @@ +package k8s + +import ( + "bytes" + "context" + "fmt" + "html/template" + + "github.com/ethersphere/beekeeper/pkg/k8s" + "github.com/ethersphere/beekeeper/pkg/k8s/configmap" + "github.com/ethersphere/beekeeper/pkg/k8s/customresource/ingressroute" + "github.com/ethersphere/beekeeper/pkg/k8s/ingress" + "github.com/ethersphere/beekeeper/pkg/k8s/pod" + "github.com/ethersphere/beekeeper/pkg/k8s/secret" + "github.com/ethersphere/beekeeper/pkg/k8s/service" + "github.com/ethersphere/beekeeper/pkg/k8s/serviceaccount" + "github.com/ethersphere/beekeeper/pkg/k8s/statefulset" + "github.com/ethersphere/beekeeper/pkg/logging" + "github.com/ethersphere/beekeeper/pkg/orchestration" +) + +var _ orchestration.NodeOrchestrator = (*nodeOrchestrator)(nil) + +type nodeOrchestrator struct { + k8s *k8s.Client + log logging.Logger +} + +// newNodeOrchestrator returns a new Kubernetes Bee node orchestrator. +func newNodeOrchestrator(k8s *k8s.Client, log logging.Logger) orchestration.NodeOrchestrator { + return &nodeOrchestrator{ + k8s: k8s, + log: log, + } +} + +// RunningNodes implements orchestration.NodeOrchestrator. +func (n *nodeOrchestrator) RunningNodes(ctx context.Context, namespace string) (running []string, err error) { + running, err = n.k8s.StatefulSet.RunningStatefulSets(ctx, namespace) + if err != nil { + return nil, fmt.Errorf("running statefulsets in namespace %s: %w", namespace, err) + } + return +} + +// StoppedNodes implements orchestration.NodeOrchestrator. +func (n *nodeOrchestrator) StoppedNodes(ctx context.Context, namespace string) (stopped []string, err error) { + stopped, err = n.k8s.StatefulSet.StoppedStatefulSets(ctx, namespace) + if err != nil { + return nil, fmt.Errorf("stopped statefulsets in namespace %s: %w", namespace, err) + } + return +} + +// Create +func (n *nodeOrchestrator) Create(ctx context.Context, o orchestration.CreateOptions) (err error) { + // bee configuration + var config bytes.Buffer + if err := template.Must(template.New("").Parse(configTemplate)).Execute(&config, o.Config); err != nil { + return err + } + + configCM := o.Name + if _, err = n.k8s.ConfigMap.Set(ctx, configCM, o.Namespace, configmap.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + Data: map[string]string{ + ".bee.yaml": config.String(), + }, + }); err != nil { + return fmt.Errorf("set configmap in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("configmap %s is set in namespace %s", configCM, o.Namespace) + + // secret with keys + keysSecret := fmt.Sprintf("%s-keys", o.Name) + keysSecretData := map[string]string{} + if len(o.LibP2PKey) > 0 { + keysSecretData["libp2p"] = o.LibP2PKey + } + if len(o.SwarmKey) > 0 { + keysSecretData["swarm"] = o.SwarmKey + } + + if _, err := n.k8s.Secret.Set(ctx, keysSecret, o.Namespace, secret.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + StringData: keysSecretData, + }); err != nil { + return fmt.Errorf("set secret in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("secret %s is set in namespace %s", keysSecret, o.Namespace) + + // secret with clef key and pass + clefSecretEnabled := len(o.ClefKey) > 0 && len(o.ClefPassword) > 0 + clefSecret := fmt.Sprintf("%s-clef", o.Name) + if o.Config.ClefSignerEnable && clefSecretEnabled { + clefSecretData := map[string]string{ + "key": o.ClefKey, + "password": o.ClefPassword, + } + if _, err := n.k8s.Secret.Set(ctx, clefSecret, o.Namespace, secret.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + StringData: clefSecretData, + }); err != nil { + return fmt.Errorf("set secret in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("secret %s is set in namespace %s", clefSecret, o.Namespace) + } + + // service account + svcAccount := o.Name + if _, err := n.k8s.ServiceAccount.Set(ctx, svcAccount, o.Namespace, serviceaccount.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + ImagePullSecrets: o.ImagePullSecrets, + }); err != nil { + return fmt.Errorf("set serviceaccount in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("serviceaccount %s is set in namespace %s", svcAccount, o.Namespace) + + // api service + portAPI, err := parsePort(o.Config.APIAddr) + if err != nil { + return fmt.Errorf("parsing API port from config: %s", err) + } + + apiSvc := fmt.Sprintf("%s-api", o.Name) + if _, err := n.k8s.Service.Set(ctx, apiSvc, o.Namespace, service.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + ServiceSpec: service.Spec{ + Ports: service.Ports{ + { + AppProtocol: "TCP", + Name: "api", + Protocol: "TCP", + Port: portAPI, + TargetPort: "api", + }, + }, + Selector: o.Selector, + Type: "ClusterIP", + }, + }); err != nil { + return fmt.Errorf("set service in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("service %s is set in namespace %s", apiSvc, o.Namespace) + + if o.IngressClass == "traefik" { + // api service's ingressroute + apiIn := fmt.Sprintf("%s-api", o.Name) + if _, err := n.k8s.IngressRoute.Set(ctx, apiIn, o.Namespace, ingressroute.Options{ + Annotations: mergeMaps(o.Annotations, o.IngressAnnotations), + Labels: o.Labels, + Spec: ingressroute.IngressRouteSpec{ + Routes: []ingressroute.Route{ + { + Kind: "Rule", + Match: fmt.Sprintf("Host(\"%s.localhost\") && PathPrefix(\"/\")", o.Name), + Services: []ingressroute.Service{ + { + Kind: "Service", + Name: apiIn, + Namespace: "local", + Port: "api", + }, + }, + }, + }, + }, + }); err != nil { + return fmt.Errorf("set ingressroute in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("ingressroute %s is set in namespace %s", apiIn, o.Namespace) + } else { + // api service's ingress + apiIn := fmt.Sprintf("%s-api", o.Name) + if _, err := n.k8s.Ingress.Set(ctx, apiIn, o.Namespace, ingress.Options{ + Annotations: mergeMaps(o.Annotations, o.IngressAnnotations), + Labels: o.Labels, + Spec: ingress.Spec{ + Class: o.IngressClass, + Rules: ingress.Rules{{ + Host: o.IngressHost, + Paths: ingress.Paths{{ + Backend: ingress.Backend{ + ServiceName: apiSvc, + ServicePortName: "api", + }, + Path: "/", + PathType: "ImplementationSpecific", + }}, + }}, + }, + }); err != nil { + return fmt.Errorf("set ingress in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("ingress %s is set in namespace %s", apiIn, o.Namespace) + } + + // p2p service + portP2P, err := parsePort(o.Config.P2PAddr) + if err != nil { + return fmt.Errorf("parsing P2P port from config: %s", err) + } + + var nodePortP2P int32 + if len(o.Config.NATAddr) > 0 { + nodePortP2P, err = parsePort(o.Config.NATAddr) + if err != nil { + return fmt.Errorf("parsing NAT address from config: %s", err) + } + } + + p2pSvc := fmt.Sprintf("%s-p2p", o.Name) + if _, err := n.k8s.Service.Set(ctx, p2pSvc, o.Namespace, service.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + ServiceSpec: service.Spec{ + ExternalTrafficPolicy: "Local", + Ports: setBeeNodePort(setBeeNodePortOptions{ + AppProtocol: "TCP", + Name: "p2p", + Protocol: "TCP", + TargetPort: "p2p", + Port: portP2P, + NodePort: nodePortP2P, + }), + Selector: o.Selector, + Type: "NodePort", + }, + }); err != nil { + return fmt.Errorf("set service in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("service %s is set in namespace %s", p2pSvc, o.Namespace) + + // headless service + headlessSvc := fmt.Sprintf("%s-headless", o.Name) + if _, err := n.k8s.Service.Set(ctx, headlessSvc, o.Namespace, service.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + ServiceSpec: service.Spec{ + Ports: service.Ports{ + { + AppProtocol: "TCP", + Name: "api", + Protocol: "TCP", + Port: portAPI, + TargetPort: "api", + }, + { + AppProtocol: "TCP", + Name: "p2p", + Protocol: "TCP", + Port: portP2P, + TargetPort: "p2p", + }, + }, + Selector: o.Selector, + Type: "ClusterIP", + }, + }); err != nil { + return fmt.Errorf("set service in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("service %s is set in namespace %s", headlessSvc, o.Namespace) + + // statefulset + sSet := o.Name + clefEnabled := o.Config.ClefSignerEnable + libP2PEnabled := len(o.LibP2PKey) > 0 + swarmEnabled := len(o.SwarmKey) > 0 + + if _, err := n.k8s.StatefulSet.Set(ctx, sSet, o.Namespace, statefulset.Options{ + Annotations: o.Annotations, + Labels: o.Labels, + Spec: statefulset.StatefulSetSpec{ + PodManagementPolicy: o.PodManagementPolicy, + Replicas: 0, + Selector: o.Selector, + ServiceName: headlessSvc, + Template: pod.PodTemplateSpec{ + Name: sSet, + Namespace: o.Namespace, + Annotations: o.Annotations, + Labels: o.Labels, + Spec: pod.PodSpec{ + InitContainers: setInitContainers(setInitContainersOptions{ + ClefEnabled: clefEnabled, + ClefSecretEnabled: clefSecretEnabled, + ClefImage: o.ClefImage, + ClefImagePullPolicy: o.ClefImagePullPolicy, + ClefPassword: o.ClefPassword, + LibP2PEnabled: libP2PEnabled, + SwarmEnabled: swarmEnabled, + }), + Containers: setContainers(setContainersOptions{ + Name: sSet, + Image: o.Image, + ImagePullPolicy: o.ImagePullPolicy, + PortAPI: portAPI, + PortP2P: portP2P, + PersistenceEnabled: o.PersistenceEnabled, + ResourcesLimitCPU: o.ResourcesLimitCPU, + ResourcesLimitMemory: o.ResourcesLimitMemory, + ResourcesRequestCPU: o.ResourcesRequestCPU, + ResourcesRequestMemory: o.ResourcesRequestMemory, + ClefEnabled: clefEnabled, + ClefSecretEnabled: clefSecretEnabled, + ClefImage: o.ClefImage, + ClefImagePullPolicy: o.ClefImagePullPolicy, + ClefPassword: o.ClefPassword, + LibP2PEnabled: libP2PEnabled, + SwarmEnabled: swarmEnabled, + }), + NodeSelector: o.NodeSelector, + PodSecurityContext: pod.PodSecurityContext{ + FSGroup: 999, + }, + RestartPolicy: o.RestartPolicy, + ServiceAccountName: svcAccount, + Volumes: setVolumes(setVolumesOptions{ + ConfigCM: configCM, + KeysSecret: keysSecret, + PersistenceEnabled: o.PersistenceEnabled, + ClefEnabled: clefEnabled, + ClefSecretEnabled: clefSecretEnabled, + ClefSecret: clefSecret, + LibP2PEnabled: libP2PEnabled, + SwarmEnabled: swarmEnabled, + }), + }, + }, + UpdateStrategy: statefulset.UpdateStrategy{ + Type: o.UpdateStrategy, + }, + VolumeClaimTemplates: setPersistentVolumeClaims(setPersistentVolumeClaimsOptions{ + Enabled: o.PersistenceEnabled, + StorageClass: o.PersistenceStorageClass, + StorageRequest: o.PersistenceStorageRequest, + }), + }, + }); err != nil { + return fmt.Errorf("set statefulset in namespace %s: %w", o.Namespace, err) + } + n.log.Infof("statefulset %s is set in namespace %s", sSet, o.Namespace) + + return +} + +func (n *nodeOrchestrator) Delete(ctx context.Context, name string, namespace string) (err error) { + // statefulset + if err := n.k8s.StatefulSet.Delete(ctx, name, namespace); err != nil { + return fmt.Errorf("deleting statefulset in namespace %s: %w", namespace, err) + } + n.log.Infof("statefulset %s is deleted in namespace %s", name, namespace) + + // headless service + headlessSvc := fmt.Sprintf("%s-headless", name) + if err := n.k8s.Service.Delete(ctx, headlessSvc, namespace); err != nil { + return fmt.Errorf("deleting service in namespace %s: %w", namespace, err) + } + n.log.Infof("service %s is deleted in namespace %s", headlessSvc, namespace) + + // p2p service + p2pSvc := fmt.Sprintf("%s-p2p", name) + if err := n.k8s.Service.Delete(ctx, p2pSvc, namespace); err != nil { + return fmt.Errorf("deleting service in namespace %s: %w", namespace, err) + } + n.log.Infof("service %s is deleted in namespace %s", p2pSvc, namespace) + + // api service's ingress + apiIn := fmt.Sprintf("%s-api", name) + if err := n.k8s.Ingress.Delete(ctx, apiIn, namespace); err != nil { + return fmt.Errorf("deleting ingress in namespace %s: %w", namespace, err) + } + n.log.Infof("ingress %s is deleted in namespace %s", apiIn, namespace) + + // api service's ingress route + if err := n.k8s.IngressRoute.Delete(ctx, apiIn, namespace); err != nil { + return fmt.Errorf("deleting ingress route in namespace %s: %w", namespace, err) + } + n.log.Infof("ingress route %s is deleted in namespace %s", apiIn, namespace) + + // api service + apiSvc := fmt.Sprintf("%s-api", name) + if err := n.k8s.Service.Delete(ctx, apiSvc, namespace); err != nil { + return fmt.Errorf("deleting service in namespace %s: %w", namespace, err) + } + n.log.Infof("service %s is deleted in namespace %s", apiSvc, namespace) + + // service account + svcAccount := name + if err := n.k8s.ServiceAccount.Delete(ctx, svcAccount, namespace); err != nil { + return fmt.Errorf("deleting serviceaccount in namespace %s: %w", namespace, err) + } + n.log.Infof("serviceaccount %s is deleted in namespace %s", svcAccount, namespace) + + // secret with clef key + clefSecret := fmt.Sprintf("%s-clef", name) + if err := n.k8s.Secret.Delete(ctx, clefSecret, namespace); err != nil { + return fmt.Errorf("deleting secret in namespace %s: %w", namespace, err) + } + n.log.Infof("secret %s is deleted in namespace %s", clefSecret, namespace) + + // secret with keys + keysSecret := fmt.Sprintf("%s-keys", name) + if err = n.k8s.Secret.Delete(ctx, keysSecret, namespace); err != nil { + return fmt.Errorf("deleting secret %s in namespace %s: %w", keysSecret, namespace, err) + } + n.log.Infof("secret %s is deleted in namespace %s", keysSecret, namespace) + + // bee configuration + configCM := name + if err = n.k8s.ConfigMap.Delete(ctx, configCM, namespace); err != nil { + return fmt.Errorf("deleting configmap %s in namespace %s: %w", configCM, namespace, err) + } + n.log.Infof("configmap %s is deleted in namespace %s", configCM, namespace) + + n.log.Infof("node %s is deleted in namespace %s", name, namespace) + return +} + +func (n *nodeOrchestrator) Ready(ctx context.Context, name string, namespace string) (ready bool, err error) { + // r, err := n.k8s.StatefulSet.ReadyReplicas(ctx, name, namespace) + r, err := n.k8s.StatefulSet.ReadyReplicasWatch(ctx, name, namespace) + if err != nil { + return false, fmt.Errorf("statefulset %s in namespace %s ready replicas: %w", name, namespace, err) + } + + return r == 1, nil +} + +func (n *nodeOrchestrator) Start(ctx context.Context, name string, namespace string) (err error) { + _, err = n.k8s.StatefulSet.Scale(ctx, name, namespace, 1) + if err != nil { + return fmt.Errorf("scale statefulset %s in namespace %s: %w", name, namespace, err) + } + + n.log.Infof("node %s is started in namespace %s", name, namespace) + return +} + +func (n *nodeOrchestrator) Stop(ctx context.Context, name string, namespace string) (err error) { + _, err = n.k8s.StatefulSet.Scale(ctx, name, namespace, 0) + if err != nil { + return fmt.Errorf("scale statefulset %s in namespace %s: %w", name, namespace, err) + } + + n.log.Infof("node %s is stopped in namespace %s", name, namespace) + return +} diff --git a/pkg/orchestration/k8s/nodegroup.go b/pkg/orchestration/k8s/nodegroup.go index 7c1e1a1b7..647dd3953 100644 --- a/pkg/orchestration/k8s/nodegroup.go +++ b/pkg/orchestration/k8s/nodegroup.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "net/url" "sort" "sync" "time" @@ -11,7 +12,6 @@ import ( "github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/beekeeper/pkg/bee" - "github.com/ethersphere/beekeeper/pkg/k8s" "github.com/ethersphere/beekeeper/pkg/logging" "github.com/ethersphere/beekeeper/pkg/orchestration" "github.com/ethersphere/beekeeper/pkg/orchestration/utils" @@ -24,39 +24,37 @@ var _ orchestration.NodeGroup = (*NodeGroup)(nil) // NodeGroup represents group of Bee nodes type NodeGroup struct { - name string - nodes map[string]orchestration.Node - opts orchestration.NodeGroupOptions - - // set when added to the cluster - cluster *Cluster - k8s *k8s.Client - - logger logging.Logger - - lock sync.RWMutex + nodeOrchestrator orchestration.NodeOrchestrator + name string + nodes map[string]orchestration.Node + opts orchestration.NodeGroupOptions + clusterOpts orchestration.ClusterOptions + log logging.Logger + lock sync.RWMutex } // NewNodeGroup returns new node group -func NewNodeGroup(name string, o orchestration.NodeGroupOptions, logger logging.Logger) *NodeGroup { +func NewNodeGroup(name string, copts orchestration.ClusterOptions, no orchestration.NodeOrchestrator, ngopts orchestration.NodeGroupOptions, log logging.Logger) *NodeGroup { + ngopts.Annotations = mergeMaps(ngopts.Annotations, copts.Annotations) + ngopts.Labels = mergeMaps(ngopts.Labels, copts.Labels) + return &NodeGroup{ - name: name, - nodes: make(map[string]orchestration.Node), - opts: o, - logger: logger, + nodeOrchestrator: no, + name: name, + nodes: make(map[string]orchestration.Node), + opts: ngopts, + clusterOpts: copts, + log: log, } } // AddNode adss new node to the node group -func (g *NodeGroup) AddNode(ctx context.Context, name string, o orchestration.NodeOptions) (err error) { - aURL, err := g.cluster.apiURL(name) - if err != nil { - return fmt.Errorf("API URL %s: %w", name, err) - } +func (g *NodeGroup) AddNode(ctx context.Context, name string, o orchestration.NodeOptions, opts ...orchestration.BeeClientOption) (err error) { + var aURL *url.URL - dURL, err := g.cluster.debugAPIURL(name) + aURL, err = g.clusterOpts.ApiURL(name) if err != nil { - return fmt.Errorf("debug API URL %s: %w", name, err) + return fmt.Errorf("API URL %s: %w", name, err) } // TODO: make more granular, check every sub-option @@ -67,24 +65,29 @@ func (g *NodeGroup) AddNode(ctx context.Context, name string, o orchestration.No config = g.opts.BeeConfig } - client := bee.NewClient(bee.ClientOptions{ - APIURL: aURL, - APIInsecureTLS: g.cluster.apiInsecureTLS, - DebugAPIURL: dURL, - DebugAPIInsecureTLS: g.cluster.debugAPIInsecureTLS, - Retry: 5, - Restricted: config.Restricted, - }, g.logger) + beeClientOpts := bee.ClientOptions{ + APIURL: aURL, + APIInsecureTLS: g.clusterOpts.APIInsecureTLS, + Retry: 5, + } + + for _, opt := range opts { + err := opt(&beeClientOpts) + if err != nil { + return fmt.Errorf("bee client option: %w", err) + } + } + + client := bee.NewClient(beeClientOpts, g.log) n := NewNode(name, orchestration.NodeOptions{ ClefKey: o.ClefKey, ClefPassword: o.ClefPassword, Client: client, Config: config, - K8S: g.k8s, LibP2PKey: o.LibP2PKey, SwarmKey: o.SwarmKey, - }, g.logger) + }, g.nodeOrchestrator, g.log) g.addNode(n) @@ -124,7 +127,7 @@ type AddressesStreamMsg struct { // AddressesStream returns stream of addresses of all nodes in the node group func (g *NodeGroup) AddressesStream(ctx context.Context) (<-chan AddressesStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -199,7 +202,7 @@ type AccountingStreamMsg struct { // AccountingStream returns stream of accounting of all nodes in the node group func (g *NodeGroup) AccountingStream(ctx context.Context) (<-chan AccountingStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -274,7 +277,7 @@ type BalancesStreamMsg struct { // BalancesStream returns stream of balances of all nodes in the cluster func (g *NodeGroup) BalancesStream(ctx context.Context) (<-chan BalancesStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -322,7 +325,7 @@ func (g *NodeGroup) CreateNode(ctx context.Context, name string) (err error) { Config: *n.Config(), // Kubernetes configuration Name: name, - Namespace: g.cluster.namespace, + Namespace: g.clusterOpts.Namespace, Annotations: g.opts.Annotations, ClefImage: g.opts.ClefImage, ClefImagePullPolicy: g.opts.ClefImagePullPolicy, @@ -333,10 +336,7 @@ func (g *NodeGroup) CreateNode(ctx context.Context, name string) (err error) { ImagePullSecrets: g.opts.ImagePullSecrets, IngressAnnotations: g.opts.IngressAnnotations, IngressClass: g.opts.IngressClass, - IngressHost: g.cluster.ingressHost(name), - IngressDebugAnnotations: g.opts.IngressDebugAnnotations, - IngressDebugClass: g.opts.IngressDebugClass, - IngressDebugHost: g.cluster.ingressDebugHost(name), + IngressHost: g.clusterOpts.IngressHost(name), Labels: labels, LibP2PKey: n.LibP2PKey(), NodeSelector: g.opts.NodeSelector, @@ -361,8 +361,8 @@ func (g *NodeGroup) CreateNode(ctx context.Context, name string) (err error) { // DeleteNode deletes node from the k8s cluster and removes it from the node group func (g *NodeGroup) DeleteNode(ctx context.Context, name string) (err error) { - n := NewNode(name, orchestration.NodeOptions{K8S: g.k8s}, g.logger) - if err := n.Delete(ctx, g.cluster.namespace); err != nil { + n := NewNode(name, orchestration.NodeOptions{}, g.nodeOrchestrator, g.log) + if err := n.Delete(ctx, g.clusterOpts.Namespace); err != nil { return err } @@ -394,7 +394,7 @@ func (ng *NodeGroup) GetEthAddress(ctx context.Context, name string, o orchestra break } } - ng.logger.Infof("fund eth address: %s", a.Ethereum) + ng.log.Infof("fund eth address: %s", a.Ethereum) return a.Ethereum, nil } @@ -432,7 +432,7 @@ type HasChunkStreamMsg struct { // HasChunkStream returns stream of HasChunk requests for all nodes in the node group func (g *NodeGroup) HasChunkStream(ctx context.Context, a swarm.Address) (<-chan HasChunkStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -555,7 +555,7 @@ type OverlaysStreamMsg struct { // TODO: add semaphore func (g *NodeGroup) OverlaysStream(ctx context.Context) (<-chan OverlaysStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -620,7 +620,7 @@ type PeersStreamMsg struct { // PeersStream returns stream of peers of all nodes in the node group func (g *NodeGroup) PeersStream(ctx context.Context) (<-chan PeersStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -659,7 +659,7 @@ func (g *NodeGroup) NodeReady(ctx context.Context, name string) (ok bool, err er return false, err } - return n.Ready(ctx, g.cluster.namespace) + return n.Ready(ctx, g.clusterOpts.Namespace) } // PregenerateSwarmKey for a node if needed @@ -715,13 +715,13 @@ func (g *NodeGroup) PregenerateSwarmKey(ctx context.Context, name string) (err e return err } - txHash, err := g.cluster.swap.AttestOverlayEthAddress(ctx, key.Address) + txHash, err := g.clusterOpts.SwapClient.AttestOverlayEthAddress(ctx, key.Address) if err != nil { return fmt.Errorf("attest overlay Ethereum address for node %s: %w", name, err) } time.Sleep(10 * time.Second) - g.logger.Infof("overlay Ethereum address %s for node %s attested successfully: transaction: %s", key.Address, name, txHash) + g.log.Infof("overlay Ethereum address %s for node %s attested successfully: transaction: %s", key.Address, name, txHash) } return } @@ -729,23 +729,23 @@ func (g *NodeGroup) PregenerateSwarmKey(ctx context.Context, name string) (err e // RunningNodes returns list of running nodes // TODO: filter by labels func (g *NodeGroup) RunningNodes(ctx context.Context) (running []string, err error) { - running, err = g.k8s.StatefulSet.RunningStatefulSets(ctx, g.cluster.namespace) - if err != nil { - return nil, fmt.Errorf("running statefulsets in namespace %s: %w", g.cluster.namespace, err) + allRunning, err := g.nodeOrchestrator.RunningNodes(ctx, g.clusterOpts.Namespace) + if err != nil && err != orchestration.ErrNotSet { + return nil, fmt.Errorf("running nodes in namespace %s: %w", g.clusterOpts.Namespace, err) } - for _, v := range running { + for _, v := range allRunning { if contains(g.NodesSorted(), v) { running = append(running, v) } } - return + return running, nil } // SetupNode creates new node in the node group, starts it in the k8s cluster and funds it func (g *NodeGroup) SetupNode(ctx context.Context, name string, o orchestration.NodeOptions) (ethAddress string, err error) { - g.logger.Infof("starting setup node: %s", name) + g.log.Infof("starting setup node: %s", name) if err := g.AddNode(ctx, name, o); err != nil { return "", fmt.Errorf("add node %s: %w", name, err) @@ -817,7 +817,7 @@ type SettlementsStreamMsg struct { // SettlementsStream returns stream of settlements of all nodes in the cluster func (g *NodeGroup) SettlementsStream(ctx context.Context) (<-chan SettlementsStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } @@ -861,11 +861,11 @@ func (g *NodeGroup) StartNode(ctx context.Context, name string) (err error) { return err } - if err := n.Start(ctx, g.cluster.namespace); err != nil { + if err := n.Start(ctx, g.clusterOpts.Namespace); err != nil { return err } - g.logger.Infof("wait for %s to become ready", name) + g.log.Infof("wait for %s to become ready", name) for { ok, err := g.NodeReady(ctx, name) @@ -874,7 +874,7 @@ func (g *NodeGroup) StartNode(ctx context.Context, name string) (err error) { } if ok { - g.logger.Infof("%s is ready", name) + g.log.Infof("%s is ready", name) return nil } } @@ -887,11 +887,11 @@ func (g *NodeGroup) StopNode(ctx context.Context, name string) (err error) { return err } - if err := n.Stop(ctx, g.cluster.namespace); err != nil { + if err := n.Stop(ctx, g.clusterOpts.Namespace); err != nil { return err } - g.logger.Infof("wait for %s to stop", name) + g.log.Infof("wait for %s to stop", name) for { ok, err := g.NodeReady(ctx, name) @@ -900,7 +900,7 @@ func (g *NodeGroup) StopNode(ctx context.Context, name string) (err error) { } if !ok { - g.logger.Infof("%s is stopped", name) + g.log.Infof("%s is stopped", name) return nil } } @@ -909,9 +909,9 @@ func (g *NodeGroup) StopNode(ctx context.Context, name string) (err error) { // StoppedNodes returns list of stopped nodes // TODO: filter by labels func (g *NodeGroup) StoppedNodes(ctx context.Context) (stopped []string, err error) { - allStopped, err := g.k8s.StatefulSet.StoppedStatefulSets(ctx, g.cluster.namespace) - if err != nil { - return nil, fmt.Errorf("stopped statefulsets in namespace %s: %w", g.cluster.namespace, err) + allStopped, err := g.nodeOrchestrator.StoppedNodes(ctx, g.clusterOpts.Namespace) + if err != nil && err != orchestration.ErrNotSet { + return nil, fmt.Errorf("stopped nodes in namespace %s: %w", g.clusterOpts.Namespace, err) } for _, v := range allStopped { @@ -920,7 +920,7 @@ func (g *NodeGroup) StoppedNodes(ctx context.Context) (stopped []string, err err } } - return + return stopped, nil } // Topologies returns NodeGroupTopologies @@ -956,7 +956,7 @@ type TopologyStreamMsg struct { // TopologyStream returns stream of Kademlia topologies of all nodes in the node group func (g *NodeGroup) TopologyStream(ctx context.Context) (<-chan TopologyStreamMsg, error) { stopped, err := g.StoppedNodes(ctx) - if err != nil && err != orchestration.ErrNotSet { + if err != nil { return nil, fmt.Errorf("stopped nodes: %w", err) } diff --git a/pkg/orchestration/node.go b/pkg/orchestration/node.go index 0263f87f6..413abb0da 100644 --- a/pkg/orchestration/node.go +++ b/pkg/orchestration/node.go @@ -9,34 +9,43 @@ import ( "time" "github.com/ethersphere/beekeeper/pkg/bee" - "github.com/ethersphere/beekeeper/pkg/k8s" ) // ErrNotSet represents error when orchestration client is not set var ErrNotSet = errors.New("orchestration client not set") type Node interface { - Name() string - Client() *bee.Client ClefKey() string ClefPassword() string + Client() *bee.Client Config() *Config + LibP2PKey() string + Name() string + SetClefKey(key string) Node + SetClefPassword(key string) Node + SetSwarmKey(key string) Node + SwarmKey() string Create(ctx context.Context, o CreateOptions) (err error) Delete(ctx context.Context, namespace string) (err error) - LibP2PKey() string Ready(ctx context.Context, namespace string) (ready bool, err error) Start(ctx context.Context, namespace string) (err error) Stop(ctx context.Context, namespace string) (err error) - SwarmKey() string - SetSwarmKey(key string) Node - SetClefKey(key string) Node - SetClefPassword(key string) Node +} + +type NodeOrchestrator interface { + Create(ctx context.Context, o CreateOptions) (err error) + Delete(ctx context.Context, name string, namespace string) (err error) + Ready(ctx context.Context, name string, namespace string) (ready bool, err error) + Start(ctx context.Context, name string, namespace string) (err error) + Stop(ctx context.Context, name string, namespace string) (err error) + RunningNodes(ctx context.Context, namespace string) (running []string, err error) + StoppedNodes(ctx context.Context, namespace string) (stopped []string, err error) } // EncryptedKey is part of Ethereum JSON v3 key file format. type EncryptedKey string -func (ek EncryptedKey) ToString() string { +func (ek EncryptedKey) String() string { return string(ek) } @@ -68,7 +77,6 @@ type NodeOptions struct { ClefPassword string Client *bee.Client Config *Config - K8S *k8s.Client LibP2PKey string SwarmKey EncryptedKey } @@ -92,9 +100,6 @@ type CreateOptions struct { IngressAnnotations map[string]string IngressClass string IngressHost string - IngressDebugAnnotations map[string]string - IngressDebugClass string - IngressDebugHost string LibP2PKey string NodeSelector map[string]string PersistenceEnabled bool @@ -127,8 +132,6 @@ type Config struct { DbBlockCacheCapacity int // size of block cache of the database in bytes DbWriteBufferSize int // size of the database write buffer in bytes DbDisableSeeksCompaction bool // disables DB compactions triggered by seeks - DebugAPIAddr string // debug HTTP API listen address - DebugAPIEnable bool // enable debug HTTP API FullNode bool // cause the node to start in full mode Mainnet bool // enable mainnet NATAddr string // NAT exposed address @@ -143,9 +146,6 @@ type Config struct { PostageContractStartBlock uint64 // postage stamp address PriceOracleAddress string // price Oracle address ResolverOptions string // ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url - Restricted bool // start node in restricted mode - TokenEncryptionKey string // username for API authentication - AdminPassword string // password hash for API authentication ChequebookEnable bool // enable chequebook SwapEnable bool // enable swap SwapEndpoint string // swap ethereum blockchain endpoint diff --git a/pkg/orchestration/nodegroup.go b/pkg/orchestration/nodegroup.go index 4dd4f2e8b..369a7b465 100644 --- a/pkg/orchestration/nodegroup.go +++ b/pkg/orchestration/nodegroup.go @@ -2,6 +2,8 @@ package orchestration import ( "context" + "fmt" + "net/url" "github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/beekeeper/pkg/bee" @@ -9,7 +11,7 @@ import ( type NodeGroup interface { Accounting(ctx context.Context) (infos NodeGroupAccounting, err error) - AddNode(ctx context.Context, name string, o NodeOptions) (err error) + AddNode(ctx context.Context, name string, o NodeOptions, opts ...BeeClientOption) (err error) Addresses(ctx context.Context) (addrs NodeGroupAddresses, err error) Balances(ctx context.Context) (balances NodeGroupBalances, err error) CreateNode(ctx context.Context, name string) (err error) @@ -47,8 +49,6 @@ type NodeGroupOptions struct { ImagePullSecrets []string IngressAnnotations map[string]string IngressClass string - IngressDebugAnnotations map[string]string - IngressDebugClass string Labels map[string]string NodeSelector map[string]string PersistenceEnabled bool @@ -95,3 +95,26 @@ type SentReceived struct { // NodeGroupTopologies represents Kademlia topology of all nodes in the node group type NodeGroupTopologies map[string]bee.Topology + +// BeeClientOption represents bee client option +type BeeClientOption func(*bee.ClientOptions) error + +// WithURL returns BeeClientOption with given api url +func WithURL(apiURL string) BeeClientOption { + return func(o *bee.ClientOptions) error { + api, err := url.Parse(apiURL) + if err != nil { + return fmt.Errorf("invalid api url: %w", err) + } + + o.APIURL = api + return nil + } +} + +// WithNoOptions represents no BeeClientOption +func WithNoOptions() BeeClientOption { + return func(o *bee.ClientOptions) error { + return nil + } +} diff --git a/pkg/orchestration/notset/bee.go b/pkg/orchestration/notset/bee.go index 26f7a9ff2..d88d95a4f 100644 --- a/pkg/orchestration/notset/bee.go +++ b/pkg/orchestration/notset/bee.go @@ -6,6 +6,8 @@ import ( "github.com/ethersphere/beekeeper/pkg/orchestration" ) +var _ orchestration.NodeOrchestrator = (*BeeClient)(nil) + // BeeClient represents not implemented Kubernetes Bee client type BeeClient struct{} @@ -33,3 +35,13 @@ func (c *BeeClient) Start(ctx context.Context, name string, namespace string) (e func (c *BeeClient) Stop(ctx context.Context, name string, namespace string) (err error) { return orchestration.ErrNotSet } + +// RunningNodes implements orchestration.NodeOrchestrator. +func (c *BeeClient) RunningNodes(ctx context.Context, namespace string) (running []string, err error) { + return nil, orchestration.ErrNotSet +} + +// StoppedNodes implements orchestration.NodeOrchestrator. +func (c *BeeClient) StoppedNodes(ctx context.Context, namespace string) (stopped []string, err error) { + return nil, orchestration.ErrNotSet +} diff --git a/pkg/swap/geth.go b/pkg/swap/geth.go index dc13020a8..910b2c011 100644 --- a/pkg/swap/geth.go +++ b/pkg/swap/geth.go @@ -246,12 +246,11 @@ func (g *GethClient) ethAccounts(ctx context.Context) (a []string, err error) { // contains checks if list contains string func contains(list []string, find string) bool { - for _, v := range list { - if v == find { + for _, s := range list { + if strings.EqualFold(s, find) { return true } } - return false } diff --git a/pkg/test/auth.go b/pkg/test/auth.go deleted file mode 100644 index e896b6488..000000000 --- a/pkg/test/auth.go +++ /dev/null @@ -1,11 +0,0 @@ -package bee - -import "context" - -func (b *BeeV2) RefreshAuthToken(ctx context.Context, token string) (string, error) { - return b.client.Refresh(ctx, token) -} - -func (b *BeeV2) Authenticate(ctx context.Context, password string) (string, error) { - return b.client.Authenticate(ctx, b.opts.Role, password) -} diff --git a/pkg/test/case.go b/pkg/test/case.go index a4484b81f..716182792 100644 --- a/pkg/test/case.go +++ b/pkg/test/case.go @@ -32,10 +32,6 @@ type CaseOptions struct { PostageLabel string Seed int64 PostageDepth uint64 - - AdminPassword string - RestrictedGroupName string - Role string } func NewCheckCase(ctx context.Context, cluster orchestration.Cluster, caseOpts CaseOptions, logger logging.Logger) (*CheckCase, error) { diff --git a/pkg/test/node.go b/pkg/test/node.go index 64f2caf65..1503753d3 100644 --- a/pkg/test/node.go +++ b/pkg/test/node.go @@ -28,10 +28,6 @@ func (b *BeeV2) Name() string { return b.name } -func (b *BeeV2) Restricted() bool { - return b.client.Config().Restricted -} - func (b *BeeV2) DownloadChunk(ctx context.Context, ref swarm.Address) ([]byte, error) { return b.client.DownloadChunk(ctx, ref, "", nil) } diff --git a/scripts/suite.sh b/scripts/suite.sh index a89624a07..7982a97ff 100755 --- a/scripts/suite.sh +++ b/scripts/suite.sh @@ -28,60 +28,60 @@ declare -x BEEKEEPER_BIN="../dist/beekeeper" _fullconnectivity() { echo "*** FULLCONNECTIVITY ***" - "${BEEKEEPER_BIN}" check fullconnectivity --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" + "${BEEKEEPER_BIN}" check fullconnectivity --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" } _pingpong() { echo "*** PINGPONG ***" - "${BEEKEEPER_BIN}" check pingpong --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" + "${BEEKEEPER_BIN}" check pingpong --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" } _balances() { echo "*** BALANCES ***" - "${BEEKEEPER_BIN}" check balances --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" + "${BEEKEEPER_BIN}" check balances --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" } _settlements() { echo "*** SETTLEMENTS ***" - "${BEEKEEPER_BIN}" check settlements --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" -t 50000000000 --upload-node-count "${REPLICA}" --expect-settlements=false + "${BEEKEEPER_BIN}" check settlements --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" -t 50000000000 --upload-node-count "${REPLICA}" --expect-settlements=false } _cashout() { echo "*** CASHOUT ***" - "${BEEKEEPER_BIN}" check cashout --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" + "${BEEKEEPER_BIN}" check cashout --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" } _pushsync() { echo "*** PUSHSYNC ***" - "${BEEKEEPER_BIN}" check pushsync --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 - "${BEEKEEPER_BIN}" check pushsync --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 --upload-chunks + "${BEEKEEPER_BIN}" check pushsync --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 + "${BEEKEEPER_BIN}" check pushsync --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 --upload-chunks } _retrieval() { echo "*** RETRIEVAL ***" - "${BEEKEEPER_BIN}" check retrieval --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 + "${BEEKEEPER_BIN}" check retrieval --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 } _pullsync() { echo "*** PULLSYNC ***" - "${BEEKEEPER_BIN}" check pullsync --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 + "${BEEKEEPER_BIN}" check pullsync --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 } _manifest() { echo "*** MANIFEST ***" - "${BEEKEEPER_BIN}" check manifest --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" + "${BEEKEEPER_BIN}" check manifest --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" } _fileretrieval() { echo "*** FILERETRIEVAL ***" - "${BEEKEEPER_BIN}" check fileretrieval --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" + "${BEEKEEPER_BIN}" check fileretrieval --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" } _localpinning() { echo "*** LOCALPINNING ***" - "${BEEKEEPER_BIN}" check localpinning --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" - "${BEEKEEPER_BIN}" check localpinning --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" --large-file-disk-ratio 2 - "${BEEKEEPER_BIN}" check localpinning --api-scheme http --debug-api-scheme http ${NAMESPACE_OPTION} --debug-api-domain "${DOMAIN}" --api-domain "${DOMAIN}" --node-count "${REPLICA}" --large-file-disk-ratio 2 --large-file-count 10 + "${BEEKEEPER_BIN}" check localpinning --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" + "${BEEKEEPER_BIN}" check localpinning --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" --large-file-disk-ratio 2 + "${BEEKEEPER_BIN}" check localpinning --api-scheme http ${NAMESPACE_OPTION} --api-domain "${DOMAIN}" --node-count "${REPLICA}" --large-file-disk-ratio 2 --large-file-count 10 } diff --git a/version.go b/version.go index 34682250c..aafa6f24a 100644 --- a/version.go +++ b/version.go @@ -1,7 +1,7 @@ package beekeeper var ( - version = "0.15.2" // manually set semantic version number + version = "0.17.0" // manually set semantic version number commit string // automatically set git commit hash // Version TODO