├── .dockerignore ├── .github └── workflows │ └── docker.yml ├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── analyze.go ├── dump.go ├── go.mod ├── go.sum ├── import.go ├── inspect.go ├── inspect_test.go ├── ls.go ├── main.go ├── main_test.go └── unwrap.go /.dockerignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | /.idea/ 3 | /.vscode/ 4 | /data/ 5 | /S3/ 6 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [master] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | 13 | # tests takes too long inside docker arm buildx 14 | - uses: actions/setup-go@v4 15 | with: 16 | go-version-file: go.mod 17 | - run: make test 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | - name: Set up Docker Buildx 22 | uses: docker/setup-buildx-action@v3 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v3 25 | with: 26 | username: sepa 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: Docker meta 30 | id: meta 31 | uses: docker/metadata-action@v5 32 | with: 33 | images: sepa/thanos-kit 34 | tags: | 35 | type=raw,value={{date 'YYMMDD'}} 36 | type=raw,value={{branch}}-{{sha}} 37 | flavor: | 38 | latest=true 39 | 40 | - name: Build and push 41 | id: docker_build 42 | uses: docker/build-push-action@v5 43 | with: 44 | platforms: linux/amd64,linux/arm64 45 | push: true 46 | tags: ${{ steps.meta.outputs.tags }} 47 | labels: ${{ steps.meta.outputs.labels }} 48 | build-args: VER=${{ steps.meta.outputs.version }} 49 | cache-from: type=gha 50 | cache-to: type=gha,mode=max -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /.vscode/ 3 | /thanos-kit 4 | /data/ 5 | /S3/ 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.21 as builder 2 | WORKDIR /build 3 | # try to cache deps 4 | COPY go.mod go.sum ./ 5 | RUN go mod download -x 6 | # resets caches 7 | COPY . . 8 | ARG VER 9 | RUN make build 10 | 11 | FROM quay.io/prometheus/busybox:latest 12 | COPY --from=builder /build/thanos-kit /bin/thanos-kit 13 | ENTRYPOINT ["/bin/thanos-kit"] 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VER ?= `git show -s --format=%cd-%h --date=format:%y%m%d` 2 | 3 | help: ## Displays help 4 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} /^[a-z0-9A-Z_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) 5 | 6 | test: ## Run unit tests 7 | @go test ./... 8 | 9 | build: ## Build binaries with version set 10 | @CGO_ENABLED=0 go build -ldflags "-w -s \ 11 | -X github.com/prometheus/common/version.Version=${VER} \ 12 | -X github.com/prometheus/common/version.Revision=`git rev-parse HEAD` \ 13 | -X github.com/prometheus/common/version.Branch=`git rev-parse --abbrev-ref HEAD` \ 14 | -X github.com/prometheus/common/version.BuildUser=${USER}@`hostname` \ 15 | -X github.com/prometheus/common/version.BuildDate=`date +%Y%m%d-%H:%M:%S`" 16 | 17 | docker: ## Builds 'thanos-kit' docker with no tag 18 | @docker build -t "thanos-kit" . 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # thanos-kit 2 | Tooling to work with Thanos blocks in object storage. 3 | 4 | - **ls** - List all blocks ULIDs in the bucket, also show ULID as time (same as `thanos tools bucket ls` but with mimir support) 5 | - **inspect** - Inspect all blocks in the bucket in detailed, table-like way (same as `thanos tools bucket inspect` but with mimir support) 6 | - **analyze** - Analyze churn, label pair cardinality for specific block. (same as `promtool tsdb analyze` but also show Labels suitable for block split) 7 | - **dump** - Dump samples from a TSDB to text format (same as `promtool tsdb dump` but to promtext format) 8 | - **import** - Import samples to TSDB blocks (same as `promtool tsdb create-blocks-from openmetrics` but from promtext format). Read more about [backfill](#backfill) below 9 | - **unwrap** - Split one TSDB block to multiple based on Label values. Read more [below](#unwrap) 10 | 11 | Cli arguments are mostly the same as for `thanos`, help is available for each sub-command: 12 | ``` 13 | $ docker run sepa/thanos-kit -h 14 | usage: thanos-kit [] [ ...] 15 | 16 | Tooling for Thanos blocks in object storage 17 | 18 | Flags: 19 | -h, --help Show context-sensitive help (also try --help-long and --help-man). 20 | --version Show application version. 21 | --log.level=info Log filtering level (info, debug) 22 | --objstore.config-file= 23 | Path to YAML file that contains object store configuration. See format details: https://thanos.io/tip/thanos/storage.md/ 24 | --objstore.config= 25 | Alternative to 'objstore.config-file' flag (mutually exclusive). Content of YAML file that contains object store configuration. See format details: https://thanos.io/tip/thanos/storage.md/ 26 | 27 | Commands: 28 | help [...] 29 | Show help. 30 | 31 | ls [] 32 | List all blocks in the bucket. 33 | 34 | inspect [] 35 | Inspect all blocks in the bucket in detailed, table-like way 36 | 37 | analyze [] 38 | Analyze churn, label pair cardinality and find labels to split on 39 | 40 | dump [] ... 41 | Dump samples from a TSDB to text 42 | 43 | import --input-file=INPUT-FILE --label=="" [] 44 | Import samples from text to TSDB blocks 45 | 46 | unwrap [] 47 | Split TSDB block to multiple blocks by Label 48 | ``` 49 | 50 | ### Get it 51 | Docker images are available on [Docker Hub](https://hub.docker.com/repository/docker/sepa/thanos-kit/tags) 52 | 53 | ### Backfill 54 | ([Original PR](https://github.com/prometheus/prometheus/pull/7586)) 55 | Supported input format is Prometheus text format. 56 | You are free to export/convert your existing data to this format, into one **time-sorted** text file. 57 | 58 | `metric{[labels]} value timestamp_ms` 59 | 60 | For example: 61 | ```ini 62 | k8s_ns_hourly_cost{namespace="kube-system"} 5.7 1599771600000 63 | k8s_ns_hourly_cost{namespace="kube-system"} 5.0 1599771630000 64 | ... 65 | ``` 66 | 67 | Note, `value` can be mixed as normal or scientific number as per your preference. 68 | 69 | This format is simple to produce, but not optimized or compressed, so it's normal if your data file is huge. 70 | Example of a 19G OpenMetrics file, with ~20k timeseries and 200M data points (samples) on 2y period. Globally resolution is very low in this example. 71 | Import will take around 2h and uncompacted new TSDB blocks will be around 2.1G for 7600 blocks. When thanos-compact scan them, it starts automatically compacting them in the background. Once compaction is completed (~30min), TSDB blocks will be around 970M for 80 blocks. 72 | The size, and number of blocks depends on timeseries numbers and metrics resolution, but it gives you an order of sizes. 73 | 74 | Apart from labels set for each metric in text file, you would also need to set Thanos Metadata Labels for the whole batch of blocks you are importing (consider this as prometheus `external_labels` which scraped the metrics from the text file) 75 | 76 | Example of command for importing data from `data.prom` (above) to GCS bucket `bucketname`: 77 | ```bash 78 | docker run -it --rm \ 79 | -v `pwd`:/work -w /work \ 80 | -e GOOGLE_APPLICATION_CREDENTIALS=/work/svc.json \ 81 | sepa/thanos-kit import \ 82 | --objstore.config='{type: GCS, config: {bucket: bucketname}}' \ 83 | --input-file data.prom \ 84 | --label=replica=\"prom-a\" \ 85 | --label=location=\"us-east1\" 86 | ``` 87 | Please note that compactor has default `--consistency-delay=30m` which is based on file upload time (not ULID), so it could take some time before compactor would start processing these blocks. 88 | 89 | ### Cache dir 90 | By default, `thanos-kit` will cache blocks from object storage to `./data` directory, and the dir is not cleaned up on exit. This is to speed up subsequent runs, and to avoid deleting user data when `--data-dir=/tmp` is used for example. 91 | 92 | Important note that `dump` command downloads specified blocks to cache dir, but then dump TSDB as a whole (including blocks already present there) 93 | 94 | ### Unwrap 95 | 96 | This could be useful for incorporating Mimir to Thanos world by replacing thanos-receive component. Currently Mimir could accept remote-write, and do instant queries via [sidecar](https://grafana.com/docs/mimir/latest/set-up/migrate/migrate-from-thanos-to-mimir-with-thanos-sidecar/) scheme or via [thanos-promql-connector](https://github.com/thanos-community/thanos-promql-connector). But long-term queries via thanos-store would not work with Mimir blocks, as they have no Thanos metadata set. 97 | 98 | Consider this example, we have 2 prometheuses in different locations configured like so: 99 | ```yml 100 | # first 101 | global: 102 | external_labels: 103 | prometheus: A 104 | location: dc1 105 | 106 | # second 107 | global: 108 | external_labels: 109 | prometheus: B 110 | location: dc2 111 | ``` 112 | 113 | And they do remote-write to Mimir, let's take a look at produced block: 114 | ```bash 115 | # thanos-kit analyze 116 | Block ID: 01GXGKXC3PA1DE6QNAH2BM2P0R 117 | Thanos Labels: 118 | Label names appearing in all Series: [instance, job, prometheus, location] 119 | ``` 120 | 121 | The block has no Thanos labels set, and each metric inside has labels `[prometheus, location]` coming from external_labels. We can split this block to 2 separate blocks for each original prometheus like this: 122 | ```bash 123 | # thanos-kit unwrap --relabel-config='[{target_label: __meta_ext_labels, replacement: prometheus}]' 124 | uploaded block ulid=001 125 | uploaded block ulid=002 126 | 127 | # thanos-kit analyze 001 128 | Block ID: 001 129 | Thanos Labels: prometheus=A 130 | Label names appearing in all Series: [instance, job, location] 131 | 132 | # thanos-kit analyze 002 133 | Block ID: 002 134 | Thanos Labels: prometheus=B 135 | Label names appearing in all Series: [instance, job, location] 136 | ``` 137 | Unwrap command takes usual [relabel_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config) and can modify block data. But additionally special label `__meta_ext_labels` is parsed if assigned, and all label names in it are extracted to unique blocks. You can specify multiple values separated by `;`, in example above to split original Mimir block by both prometheus+location sets: 138 | ```yaml 139 | - | 140 | --relabel-config= 141 | - target_label: __meta_ext_labels 142 | replacement: prometheus;location 143 | ``` 144 | And resulting blocks are the same, as would be shipped by `thanos-sidecar`. So they would be compacted without duplicates and wasted space on S3 by compactor afterward. 145 | 146 | This could also be used for blocks produced by thanos-receive too, existing Thanos labels would be merged with extracted ones. Smaller blocks ease thanos-compactor/store sharding, and helps to have different retentions. 147 | 148 | ### Alternatives 149 | - [thanos tools bucket](https://thanos.io/tip/components/tools.md/#bucket) 150 | - [promtool tsdb](https://prometheus.io/docs/prometheus/latest/command-line/promtool/#promtool-tsdb) 151 | - [mimirtool](https://grafana.com/docs/mimir/latest/manage/tools/mimirtool/#backfill) 152 | -------------------------------------------------------------------------------- /analyze.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/go-kit/log" 7 | "github.com/prometheus/prometheus/model/labels" 8 | "github.com/prometheus/prometheus/promql/parser" 9 | "github.com/prometheus/prometheus/storage" 10 | "github.com/prometheus/prometheus/tsdb" 11 | "github.com/prometheus/prometheus/tsdb/chunks" 12 | tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" 13 | "github.com/prometheus/prometheus/tsdb/index" 14 | "github.com/thanos-io/objstore" 15 | "github.com/thanos-io/thanos/pkg/block/metadata" 16 | "golang.org/x/exp/slices" 17 | "path/filepath" 18 | "strings" 19 | "time" 20 | ) 21 | 22 | func analyze(bkt objstore.Bucket, id, dir *string, analyzeLimit *int, analyzeMatchers *string, logger log.Logger) error { 23 | ctx := context.Background() 24 | if err := downloadBlock(ctx, *dir, *id, bkt, logger); err != nil { 25 | return err 26 | } 27 | return analyzeBlock(*dir, *id, *analyzeLimit, *analyzeMatchers) 28 | } 29 | 30 | // https://github.com/prometheus/prometheus/blob/main/cmd/promtool/tsdb.go#L415 31 | func analyzeBlock(path, blockID string, limit int, matchers string) error { 32 | var ( 33 | selectors []*labels.Matcher 34 | err error 35 | ) 36 | if len(matchers) > 0 { 37 | selectors, err = parser.ParseMetricSelector(matchers) 38 | if err != nil { 39 | return err 40 | } 41 | } 42 | db, block, err := openBlock(path, blockID) 43 | if err != nil { 44 | return err 45 | } 46 | defer func() { 47 | err = tsdb_errors.NewMulti(err, db.Close()).Err() 48 | }() 49 | 50 | meta := block.Meta() 51 | fmt.Printf("Block ID: %s\n", meta.ULID) 52 | m, err := metadata.ReadFromDir(filepath.Join(path, blockID)) 53 | if err != nil { 54 | return fmt.Errorf("fail to read meta.json for %s: %w", blockID, err) 55 | } 56 | fmt.Printf("Thanos Labels: %s\n", labelsToString(m.Thanos.Labels)) 57 | 58 | // Presume 1ms resolution that Prometheus uses. 59 | fmt.Printf("Duration: %s\n", (time.Duration(meta.MaxTime-meta.MinTime) * 1e6).String()) 60 | fmt.Printf("Total Series: %d\n", meta.Stats.NumSeries) 61 | if len(matchers) > 0 { 62 | fmt.Printf("Matcher: %s\n", matchers) 63 | } 64 | ir, err := block.Index() 65 | if err != nil { 66 | return err 67 | } 68 | defer ir.Close() 69 | 70 | allLabelNames, err := ir.LabelNames(selectors...) 71 | if err != nil { 72 | return err 73 | } 74 | fmt.Printf("Label names: %d\n", len(allLabelNames)) 75 | 76 | type postingInfo struct { 77 | key string 78 | metric uint64 79 | } 80 | postingInfos := []postingInfo{} 81 | 82 | printInfo := func(postingInfos []postingInfo) { 83 | slices.SortFunc(postingInfos, func(a, b postingInfo) bool { return a.metric > b.metric }) 84 | 85 | for i, pc := range postingInfos { 86 | if i >= limit { 87 | break 88 | } 89 | fmt.Printf("%d %s\n", pc.metric, pc.key) 90 | } 91 | } 92 | 93 | labelsUncovered := map[string]uint64{} 94 | labelpairsUncovered := map[string]uint64{} 95 | labelpairsCount := map[string]uint64{} 96 | entries := 0 97 | var ( 98 | p index.Postings 99 | refs []storage.SeriesRef 100 | ) 101 | if len(matchers) > 0 { 102 | p, err = tsdb.PostingsForMatchers(ir, selectors...) 103 | if err != nil { 104 | return err 105 | } 106 | // Expand refs first and cache in memory. 107 | // So later we don't have to expand again. 108 | refs, err = index.ExpandPostings(p) 109 | if err != nil { 110 | return err 111 | } 112 | fmt.Printf("Matched series: %d\n", len(refs)) 113 | p = index.NewListPostings(refs) 114 | } else { 115 | p, err = ir.Postings("", "") // The special all key. 116 | if err != nil { 117 | return err 118 | } 119 | } 120 | 121 | chks := []chunks.Meta{} 122 | builder := labels.ScratchBuilder{} 123 | first := true 124 | splitLabels := make(map[string]bool) // labels appearing in all series 125 | for p.Next() { 126 | if err = ir.Series(p.At(), &builder, &chks); err != nil { 127 | return err 128 | } 129 | // Amount of the block time range not covered by this series. 130 | uncovered := uint64(meta.MaxTime-meta.MinTime) - uint64(chks[len(chks)-1].MaxTime-chks[0].MinTime) 131 | builder.Labels().Range(func(lbl labels.Label) { 132 | key := lbl.Name + "=" + lbl.Value 133 | labelsUncovered[lbl.Name] += uncovered 134 | labelpairsUncovered[key] += uncovered 135 | labelpairsCount[key]++ 136 | entries++ 137 | }) 138 | if first { 139 | for _, l := range builder.Labels() { 140 | if l.Name != "__name__" { 141 | splitLabels[l.Name] = true 142 | } 143 | } 144 | first = false 145 | } 146 | for l, _ := range splitLabels { 147 | if !builder.Labels().Has(l) { 148 | delete(splitLabels, l) 149 | } 150 | } 151 | } 152 | if p.Err() != nil { 153 | return p.Err() 154 | } 155 | fmt.Printf("Postings (unique label pairs): %d\n", len(labelpairsUncovered)) 156 | fmt.Printf("Postings entries (total label pairs): %d\n", entries) 157 | tmp := []string{} 158 | for k, _ := range splitLabels { 159 | tmp = append(tmp, k) 160 | } 161 | fmt.Printf("Label names appearing in all Series: [%s]\n", strings.Join(tmp, ", ")) 162 | 163 | postingInfos = postingInfos[:0] 164 | for k, m := range labelpairsUncovered { 165 | postingInfos = append(postingInfos, postingInfo{k, uint64(float64(m) / float64(meta.MaxTime-meta.MinTime))}) 166 | } 167 | 168 | fmt.Printf("\nLabel pairs most involved in churning:\n") 169 | printInfo(postingInfos) 170 | 171 | postingInfos = postingInfos[:0] 172 | for k, m := range labelsUncovered { 173 | postingInfos = append(postingInfos, postingInfo{k, uint64(float64(m) / float64(meta.MaxTime-meta.MinTime))}) 174 | } 175 | 176 | fmt.Printf("\nLabel names most involved in churning:\n") 177 | printInfo(postingInfos) 178 | 179 | postingInfos = postingInfos[:0] 180 | for k, m := range labelpairsCount { 181 | postingInfos = append(postingInfos, postingInfo{k, m}) 182 | } 183 | 184 | fmt.Printf("\nMost common label pairs:\n") 185 | printInfo(postingInfos) 186 | 187 | postingInfos = postingInfos[:0] 188 | for _, n := range allLabelNames { 189 | values, err := ir.SortedLabelValues(n, selectors...) 190 | if err != nil { 191 | return err 192 | } 193 | var cumulativeLength uint64 194 | for _, str := range values { 195 | cumulativeLength += uint64(len(str)) 196 | } 197 | postingInfos = append(postingInfos, postingInfo{n, cumulativeLength}) 198 | } 199 | 200 | fmt.Printf("\nLabel names with highest cumulative label value length:\n") 201 | printInfo(postingInfos) 202 | 203 | postingInfos = postingInfos[:0] 204 | for _, n := range allLabelNames { 205 | lv, err := ir.SortedLabelValues(n, selectors...) 206 | if err != nil { 207 | return err 208 | } 209 | postingInfos = append(postingInfos, postingInfo{n, uint64(len(lv))}) 210 | } 211 | fmt.Printf("\nHighest cardinality labels:\n") 212 | printInfo(postingInfos) 213 | 214 | postingInfos = postingInfos[:0] 215 | lv, err := ir.SortedLabelValues("__name__", selectors...) 216 | if err != nil { 217 | return err 218 | } 219 | for _, n := range lv { 220 | postings, err := ir.Postings("__name__", n) 221 | if err != nil { 222 | return err 223 | } 224 | postings = index.Intersect(postings, index.NewListPostings(refs)) 225 | count := 0 226 | for postings.Next() { 227 | count++ 228 | } 229 | if postings.Err() != nil { 230 | return postings.Err() 231 | } 232 | postingInfos = append(postingInfos, postingInfo{n, uint64(count)}) 233 | } 234 | fmt.Printf("\nHighest cardinality metric names:\n") 235 | printInfo(postingInfos) 236 | 237 | return nil 238 | } 239 | 240 | func openBlock(path, blockID string) (*tsdb.DBReadOnly, tsdb.BlockReader, error) { 241 | db, err := tsdb.OpenDBReadOnly(path, nil) 242 | if err != nil { 243 | return nil, nil, err 244 | } 245 | 246 | if blockID == "" { 247 | blockID, err = db.LastBlockID() 248 | if err != nil { 249 | return nil, nil, err 250 | } 251 | } 252 | 253 | b, err := db.Block(blockID) 254 | if err != nil { 255 | return nil, nil, err 256 | } 257 | 258 | return db, b, nil 259 | } 260 | -------------------------------------------------------------------------------- /dump.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/go-kit/log" 7 | "github.com/go-kit/log/level" 8 | "github.com/oklog/ulid" 9 | "github.com/pkg/errors" 10 | "github.com/prometheus/prometheus/promql/parser" 11 | "github.com/prometheus/prometheus/tsdb" 12 | "github.com/prometheus/prometheus/tsdb/chunkenc" 13 | tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" 14 | "github.com/thanos-io/objstore" 15 | "github.com/thanos-io/thanos/pkg/block" 16 | "io" 17 | "os" 18 | "path/filepath" 19 | "time" 20 | ) 21 | 22 | func dump(bkt objstore.Bucket, out io.Writer, ids *[]string, dir *string, mint, maxt *int64, match *string, logger log.Logger) error { 23 | ctx := context.Background() 24 | for _, id := range *ids { 25 | if _, err := ulid.Parse(id); err != nil { 26 | return errors.Wrapf(err, `invalid ULID "%s"`, id) 27 | } 28 | if err := downloadBlock(ctx, *dir, id, bkt, logger); err != nil { 29 | return err 30 | } 31 | } 32 | os.Mkdir(filepath.Join(*dir, "wal"), 0777) 33 | return dumpSamples(out, *dir, *mint, *maxt, *match) 34 | } 35 | 36 | // https://github.com/prometheus/prometheus/blob/main/cmd/promtool/tsdb.go#L703 37 | func dumpSamples(out io.Writer, path string, mint, maxt int64, match string) (err error) { 38 | db, err := tsdb.OpenDBReadOnly(path, nil) 39 | if err != nil { 40 | return err 41 | } 42 | defer func() { 43 | err = tsdb_errors.NewMulti(err, db.Close()).Err() 44 | }() 45 | q, err := db.Querier(context.Background(), mint, maxt) 46 | if err != nil { 47 | return err 48 | } 49 | defer q.Close() 50 | 51 | matchers, err := parser.ParseMetricSelector(match) 52 | if err != nil { 53 | return err 54 | } 55 | ss := q.Select(false, nil, matchers...) 56 | 57 | for ss.Next() { 58 | series := ss.At() 59 | name := series.Labels().Get("__name__") 60 | lbs := series.Labels().MatchLabels(false, "__name__") 61 | // todo: add thanos labels? 62 | it := series.Iterator(nil) 63 | for it.Next() == chunkenc.ValFloat { 64 | ts, val := it.At() 65 | fmt.Fprintf(out, "%s%s %g %d\n", name, lbs, val, ts) 66 | } 67 | for it.Next() == chunkenc.ValFloatHistogram { 68 | ts, fh := it.AtFloatHistogram() 69 | fmt.Fprintf(out, "%s%s %s %d\n", name, lbs, fh.String(), ts) 70 | } 71 | for it.Next() == chunkenc.ValHistogram { 72 | ts, h := it.AtHistogram() 73 | fmt.Fprintf(out, "%s%s %s %d\n", name, lbs, h.String(), ts) 74 | } 75 | if it.Err() != nil { 76 | return ss.Err() 77 | } 78 | } 79 | 80 | if ws := ss.Warnings(); len(ws) > 0 { 81 | return tsdb_errors.NewMulti(ws...).Err() 82 | } 83 | 84 | if ss.Err() != nil { 85 | return ss.Err() 86 | } 87 | return nil 88 | } 89 | 90 | // download block id to dir 91 | func downloadBlock(ctx context.Context, dir, id string, bkt objstore.Bucket, logger log.Logger) error { 92 | dest := filepath.Join(dir, id) 93 | begin := time.Now() 94 | err := block.Download(ctx, logger, bkt, ulid.MustParse(id), dest) 95 | if err != nil { 96 | return errors.Wrapf(err, "download block %s", id) 97 | } 98 | return level.Info(logger).Log("msg", "downloaded block", "id", id, "duration", time.Since(begin)) 99 | } 100 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sepich/thanos-kit 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 7 | github.com/efficientgo/tools/extkingpin v0.0.0-20220817170617-6c25e3b627dd 8 | github.com/go-kit/log v0.2.1 9 | github.com/oklog/ulid v1.3.1 10 | github.com/olekukonko/tablewriter v0.0.5 11 | github.com/pkg/errors v0.9.1 12 | github.com/prometheus/common v0.44.0 13 | github.com/prometheus/prometheus v0.46.1-0.20230818184859-4d8e380269da 14 | github.com/thanos-io/objstore v0.0.0-20231112185854-37752ee64d98 15 | github.com/thanos-io/thanos v0.32.5 16 | golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 17 | golang.org/x/sync v0.4.0 18 | golang.org/x/text v0.13.0 19 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 20 | gopkg.in/yaml.v2 v2.4.0 21 | ) 22 | 23 | require ( 24 | cloud.google.com/go v0.110.8 // indirect 25 | cloud.google.com/go/compute v1.23.0 // indirect 26 | cloud.google.com/go/compute/metadata v0.2.3 // indirect 27 | cloud.google.com/go/iam v1.1.2 // indirect 28 | cloud.google.com/go/storage v1.30.1 // indirect 29 | github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect 30 | github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect 31 | github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect 32 | github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 // indirect 33 | github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect 34 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect 35 | github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible // indirect 36 | github.com/aws/aws-sdk-go v1.45.25 // indirect 37 | github.com/aws/aws-sdk-go-v2 v1.16.0 // indirect 38 | github.com/aws/aws-sdk-go-v2/config v1.15.1 // indirect 39 | github.com/aws/aws-sdk-go-v2/credentials v1.11.0 // indirect 40 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.1 // indirect 41 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.7 // indirect 42 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.1 // indirect 43 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.8 // indirect 44 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.1 // indirect 45 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.1 // indirect 46 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.1 // indirect 47 | github.com/aws/smithy-go v1.11.1 // indirect 48 | github.com/baidubce/bce-sdk-go v0.9.111 // indirect 49 | github.com/beorn7/perks v1.0.1 // indirect 50 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 51 | github.com/clbanning/mxj v1.8.4 // indirect 52 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 53 | github.com/dennwc/varint v1.0.0 // indirect 54 | github.com/dustin/go-humanize v1.0.1 // indirect 55 | github.com/efficientgo/core v1.0.0-rc.2 // indirect 56 | github.com/go-logfmt/logfmt v0.6.0 // indirect 57 | github.com/gofrs/flock v0.8.1 // indirect 58 | github.com/gogo/protobuf v1.3.2 // indirect 59 | github.com/golang-jwt/jwt/v5 v5.0.0 // indirect 60 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 61 | github.com/golang/protobuf v1.5.3 // indirect 62 | github.com/golang/snappy v0.0.4 // indirect 63 | github.com/google/go-cmp v0.6.0 // indirect 64 | github.com/google/go-querystring v1.1.0 // indirect 65 | github.com/google/s2a-go v0.1.7 // indirect 66 | github.com/google/uuid v1.3.1 // indirect 67 | github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect 68 | github.com/googleapis/gax-go/v2 v2.12.0 // indirect 69 | github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect 70 | github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible // indirect 71 | github.com/jmespath/go-jmespath v0.4.0 // indirect 72 | github.com/jpillora/backoff v1.0.0 // indirect 73 | github.com/json-iterator/go v1.1.12 // indirect 74 | github.com/klauspost/compress v1.17.1 // indirect 75 | github.com/klauspost/cpuid/v2 v2.2.5 // indirect 76 | github.com/kylelemons/godebug v1.1.0 // indirect 77 | github.com/mattn/go-runewidth v0.0.13 // indirect 78 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect 79 | github.com/minio/md5-simd v1.1.2 // indirect 80 | github.com/minio/minio-go/v7 v7.0.61 // indirect 81 | github.com/minio/sha256-simd v1.0.1 // indirect 82 | github.com/mitchellh/mapstructure v1.5.0 // indirect 83 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 84 | github.com/modern-go/reflect2 v1.0.2 // indirect 85 | github.com/mozillazg/go-httpheader v0.2.1 // indirect 86 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect 87 | github.com/ncw/swift v1.0.53 // indirect 88 | github.com/oracle/oci-go-sdk/v65 v65.41.1 // indirect 89 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect 90 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 91 | github.com/prometheus/client_golang v1.16.0 // indirect 92 | github.com/prometheus/client_model v0.4.0 // indirect 93 | github.com/prometheus/common/sigv4 v0.1.0 // indirect 94 | github.com/prometheus/procfs v0.11.1 // indirect 95 | github.com/rivo/uniseg v0.2.0 // indirect 96 | github.com/rs/xid v1.5.0 // indirect 97 | github.com/sirupsen/logrus v1.9.3 // indirect 98 | github.com/sony/gobreaker v0.5.0 // indirect 99 | github.com/stretchr/testify v1.8.4 // indirect 100 | github.com/tencentyun/cos-go-sdk-v5 v0.7.40 // indirect 101 | go.opencensus.io v0.24.0 // indirect 102 | go.uber.org/atomic v1.11.0 // indirect 103 | go.uber.org/goleak v1.2.1 // indirect 104 | golang.org/x/crypto v0.14.0 // indirect 105 | golang.org/x/net v0.17.0 // indirect 106 | golang.org/x/oauth2 v0.13.0 // indirect 107 | golang.org/x/sys v0.13.0 // indirect 108 | golang.org/x/time v0.3.0 // indirect 109 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 110 | google.golang.org/api v0.147.0 // indirect 111 | google.golang.org/appengine v1.6.7 // indirect 112 | google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect 113 | google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a // indirect 114 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect 115 | google.golang.org/grpc v1.58.3 // indirect 116 | google.golang.org/protobuf v1.31.0 // indirect 117 | gopkg.in/ini.v1 v1.67.0 // indirect 118 | gopkg.in/yaml.v3 v3.0.1 // indirect 119 | ) 120 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= 17 | cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= 18 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 19 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 20 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 21 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 22 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 23 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 24 | cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= 25 | cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= 26 | cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= 27 | cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= 28 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 29 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 30 | cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4= 31 | cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= 32 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 33 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 34 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 35 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 36 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 37 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 38 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 39 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 40 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 41 | cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= 42 | cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= 43 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 44 | github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= 45 | github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= 46 | github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= 47 | github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= 48 | github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= 49 | github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= 50 | github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= 51 | github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 h1:BMTdr+ib5ljLa9MxTJK8x/Ds0MbBb4MfuW5BL0zMJnI= 52 | github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU= 53 | github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= 54 | github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= 55 | github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= 56 | github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= 57 | github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= 58 | github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= 59 | github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= 60 | github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= 61 | github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= 62 | github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= 63 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 64 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 65 | github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= 66 | github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= 67 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 68 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 69 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 70 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 71 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 72 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 73 | github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= 74 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= 75 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= 76 | github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM= 77 | github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= 78 | github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= 79 | github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= 80 | github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= 81 | github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 82 | github.com/aws/aws-sdk-go-v2 v1.16.0 h1:cBAYjiiexRAg9v2z9vb6IdxAa7ef4KCtjW7w7e3GxGo= 83 | github.com/aws/aws-sdk-go-v2 v1.16.0/go.mod h1:lJYcuZZEHWNIb6ugJjbQY1fykdoobWbOS7kJYb4APoI= 84 | github.com/aws/aws-sdk-go-v2/config v1.15.1 h1:hTIZFepYESYyowQUBo47lu69WSxsYqGUILY9Nu8+7pY= 85 | github.com/aws/aws-sdk-go-v2/config v1.15.1/go.mod h1:MZHGbuW2WnqIOQQBKu2ZkhTjuutZSTnn56TDq4QyydE= 86 | github.com/aws/aws-sdk-go-v2/credentials v1.11.0 h1:gc4Uhs80s60nmLon5Z4JXWinX2BkAGT0YROoUT8h8U4= 87 | github.com/aws/aws-sdk-go-v2/credentials v1.11.0/go.mod h1:EdV1ZFgtZ4XM5RDHWcRWK8H+xW5duNVBqWj2oLu7tRo= 88 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.1 h1:F9Je1nq5YXfMOv6451NHvMf6U0iTWeMnsG0MMIQoUmk= 89 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.1/go.mod h1:Yph0XsTbQ5GGZ2+mO1a03P/SO9fdX3t1nejIp2tq79g= 90 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.7 h1:KUErSJgdqmqAPBWAp6Zx9CjL0YXfytXJeXcsWnuCM1c= 91 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.7/go.mod h1:oB9nZcxH1cGq7NPGurVJwxrO2vmJ9mmEBayCwcAlmT8= 92 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.1 h1:feVfa9eJonhJiss7g51ikjNB2DrUzbNZNvPL8pw/54k= 93 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.1/go.mod h1:K4vz7lRYCyLYpYAMCLObODahFgARdD3YVa0MvQte9Co= 94 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.8 h1:adr3PfiggFtqgFofAMUFCtdvwzpf3QxPES4ezK4M3iI= 95 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.8/go.mod h1:wLbQYt36AJqaRZUQiCNXzbtkNigyPfKHrotHuIDiCy8= 96 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.1 h1:B/SPX7J+Y0Yrcjv60Nhbh1gC2uBN47SfN8JYre6Mp4M= 97 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.1/go.mod h1:2Hhr9Eh1gJzDatwACX/ozAZ/ljq5vzvPRu5cdu25tzc= 98 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.1 h1:DyHctRsJIAWIvom1Itb4T84D2jwpIu+KIi3d0SFaswg= 99 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.1/go.mod h1:CvFTucADIx7U/M44vjLs/ZttpQHdpxwK+62+dUGhDeY= 100 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.1 h1:xsOtPAvHqhvQvBza5ohaUcfq1LceH2lZKMUGZJKiZiM= 101 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.1/go.mod h1:Aq2/Qggh2oemSfyHH+EO4UBbgWG6zFCXLHYI4ILTY7w= 102 | github.com/aws/smithy-go v1.11.1 h1:IQ+lPZVkSM3FRtyaDox41R8YS6iwPMYIreejOgPW49g= 103 | github.com/aws/smithy-go v1.11.1/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= 104 | github.com/baidubce/bce-sdk-go v0.9.111 h1:yGgtPpZYUZW4uoVorQ4xnuEgVeddACydlcJKW87MDV4= 105 | github.com/baidubce/bce-sdk-go v0.9.111/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= 106 | github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= 107 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 108 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 109 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 110 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 111 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 112 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 113 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= 114 | github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 115 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 116 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 117 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 118 | github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= 119 | github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= 120 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 121 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 122 | github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= 123 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 124 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 125 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 126 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 127 | github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= 128 | github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= 129 | github.com/digitalocean/godo v1.99.0 h1:gUHO7n9bDaZFWvbzOum4bXE0/09ZuYA9yA8idQHX57E= 130 | github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= 131 | github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= 132 | github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= 133 | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= 134 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= 135 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 136 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 137 | github.com/efficientgo/core v1.0.0-rc.2 h1:7j62qHLnrZqO3V3UA0AqOGd5d5aXV3AX6m/NZBHp78I= 138 | github.com/efficientgo/core v1.0.0-rc.2/go.mod h1:FfGdkzWarkuzOlY04VY+bGfb1lWrjaL6x/GLcQ4vJps= 139 | github.com/efficientgo/e2e v0.14.1-0.20230710114240-c316eb95ae5b h1:8VX23BNufsa4KCqnnEonvI3yrou2Pjp8JLcbdVn0Fs8= 140 | github.com/efficientgo/tools/extkingpin v0.0.0-20220817170617-6c25e3b627dd h1:VaYzzXeUbC5fVheskcKVNOyJMEYD+HgrJNzIAg/mRIM= 141 | github.com/efficientgo/tools/extkingpin v0.0.0-20220817170617-6c25e3b627dd/go.mod h1:ZV0utlglOczUWv3ih2AbqPSoLoFzdplUYxwV62eZi6Q= 142 | github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= 143 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 144 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 145 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 146 | github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= 147 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 148 | github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= 149 | github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= 150 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 151 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 152 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 153 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 154 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 155 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 156 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 157 | github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= 158 | github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 159 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 160 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 161 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 162 | github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= 163 | github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 164 | github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= 165 | github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= 166 | github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= 167 | github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= 168 | github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= 169 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 170 | github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= 171 | github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= 172 | github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= 173 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 174 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 175 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 176 | github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= 177 | github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= 178 | github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= 179 | github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 180 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 181 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 182 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 183 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 184 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 185 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 186 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 187 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 188 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 189 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 190 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 191 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 192 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 193 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 194 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 195 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 196 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 197 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 198 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 199 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 200 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 201 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 202 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 203 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 204 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 205 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 206 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 207 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 208 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 209 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 210 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 211 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 212 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 213 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 214 | github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= 215 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 216 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 217 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 218 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 219 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 220 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 221 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 222 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 223 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 224 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 225 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 226 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 227 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 228 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 229 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 230 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 231 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 232 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 233 | github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= 234 | github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= 235 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 236 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 237 | github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= 238 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 239 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 240 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 241 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 242 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 243 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 244 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 245 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 246 | github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= 247 | github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= 248 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 249 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 250 | github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= 251 | github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 252 | github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= 253 | github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= 254 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 255 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 256 | github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= 257 | github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= 258 | github.com/gophercloud/gophercloud v1.5.0 h1:cDN6XFCLKiiqvYpjQLq9AiM7RDRbIC9450WpPH+yvXo= 259 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 260 | github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= 261 | github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= 262 | github.com/hashicorp/consul/api v1.22.0 h1:ydEvDooB/A0c/xpsBd8GSt7P2/zYPBui4KrNip0xGjE= 263 | github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= 264 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= 265 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 266 | github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= 267 | github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= 268 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 269 | github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= 270 | github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= 271 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 272 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 273 | github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= 274 | github.com/hashicorp/nomad/api v0.0.0-20230718173136-3a687930bd3e h1:sr4lujmn9heD030xx/Pd4B/JSmvRhFzuotNXaaV0WLs= 275 | github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= 276 | github.com/hetznercloud/hcloud-go/v2 v2.0.0 h1:Sg1DJ+MAKvbYAqaBaq9tPbwXBS2ckPIaMtVdUjKu+4g= 277 | github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible h1:tKTaPHNVwikS3I1rdyf1INNvgJXWSf/+TzqsiGbrgnQ= 278 | github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s= 279 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 280 | github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= 281 | github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= 282 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 283 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 284 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 285 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 286 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 287 | github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= 288 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 289 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 290 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 291 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 292 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 293 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 294 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 295 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 296 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 297 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 298 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 299 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 300 | github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= 301 | github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 302 | github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 303 | github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= 304 | github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 305 | github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= 306 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 307 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 308 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 309 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 310 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 311 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 312 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 313 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 314 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 315 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 316 | github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw= 317 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 318 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 319 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 320 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 321 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 322 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 323 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 324 | github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= 325 | github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 326 | github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= 327 | github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= 328 | github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= 329 | github.com/minio/minio-go/v7 v7.0.61 h1:87c+x8J3jxQ5VUGimV9oHdpjsAvy3fhneEBKuoKEVUI= 330 | github.com/minio/minio-go/v7 v7.0.61/go.mod h1:BTu8FcrEw+HidY0zd/0eny43QnVNkXRPXrLXFuQBHXg= 331 | github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= 332 | github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 333 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 334 | github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 335 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 336 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 337 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 338 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 339 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 340 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 341 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 342 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 343 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 344 | github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= 345 | github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= 346 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 347 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 348 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= 349 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 350 | github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= 351 | github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= 352 | github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= 353 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 354 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 355 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 356 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 357 | github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= 358 | github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= 359 | github.com/oracle/oci-go-sdk/v65 v65.41.1 h1:+lbosOyNiib3TGJDvLq1HwEAuFqkOjPJDIkyxM15WdQ= 360 | github.com/oracle/oci-go-sdk/v65 v65.41.1/go.mod h1:MXMLMzHnnd9wlpgadPkdlkZ9YrwQmCOmbX5kjVEJodw= 361 | github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM= 362 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= 363 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= 364 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 365 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 366 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 367 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 368 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 369 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 370 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 371 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 372 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 373 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 374 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 375 | github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= 376 | github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= 377 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 378 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 379 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 380 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 381 | github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= 382 | github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= 383 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 384 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 385 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 386 | github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= 387 | github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= 388 | github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= 389 | github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= 390 | github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= 391 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 392 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 393 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 394 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 395 | github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= 396 | github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= 397 | github.com/prometheus/prometheus v0.46.1-0.20230818184859-4d8e380269da h1:D5uk+FEdNjQs9ly/wkb/pXkoWc60GcV9RVsMUpg/BIE= 398 | github.com/prometheus/prometheus v0.46.1-0.20230818184859-4d8e380269da/go.mod h1:uvQsz/zwlfb8TRuWjK7L7ofV5ycAYq8dorvNf2iOBN4= 399 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 400 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 401 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 402 | github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 403 | github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= 404 | github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 405 | github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM= 406 | github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20 h1:a9hSJdJcd16e0HoMsnFvaHvxB3pxSD+SC7+CISp7xY0= 407 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 408 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 409 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 410 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 411 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 412 | github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= 413 | github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= 414 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 415 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 416 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 417 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 418 | github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= 419 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 420 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 421 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 422 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 423 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 424 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 425 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 426 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 427 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 428 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 429 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 430 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= 431 | github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4= 432 | github.com/tencentyun/cos-go-sdk-v5 v0.7.40 h1:W6vDGKCHe4wBACI1d2UgE6+50sJFhRWU4O8IB2ozzxM= 433 | github.com/tencentyun/cos-go-sdk-v5 v0.7.40/go.mod h1:4dCEtLHGh8QPxHEkgq+nFaky7yZxQuYwgSJM87icDaw= 434 | github.com/thanos-io/objstore v0.0.0-20231112185854-37752ee64d98 h1:gx2MTto1UQRumGoJzY3aFPQ31Ov3nOV7NaD7j6q288k= 435 | github.com/thanos-io/objstore v0.0.0-20231112185854-37752ee64d98/go.mod h1:JauBAcJ61tRSv9widgISVmA6akQXDeUMXBrVmWW4xog= 436 | github.com/thanos-io/thanos v0.32.5 h1:khHvuEAbUKox9DQI9cSmLes4F9G3MqWPxcdrf2tYY0w= 437 | github.com/thanos-io/thanos v0.32.5/go.mod h1:POOrd2N/0wRQKkg1MJTvU29X+IVs7iMjSoN08q8V1Mo= 438 | github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= 439 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 440 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 441 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 442 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 443 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 444 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 445 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 446 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 447 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 448 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 449 | go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= 450 | go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 451 | go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= 452 | go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= 453 | go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= 454 | go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 455 | go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= 456 | go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= 457 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 458 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 459 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 460 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 461 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 462 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 463 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 464 | golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= 465 | golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 466 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 467 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 468 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 469 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 470 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 471 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 472 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 473 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 474 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 475 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 476 | golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= 477 | golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= 478 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 479 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 480 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 481 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 482 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 483 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 484 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 485 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 486 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 487 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 488 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 489 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 490 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 491 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 492 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 493 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 494 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 495 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 496 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 497 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 498 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 499 | golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= 500 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 501 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 502 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 503 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 504 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 505 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 506 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 507 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 508 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 509 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 510 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 511 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 512 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 513 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 514 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 515 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 516 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 517 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 518 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 519 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 520 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 521 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 522 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 523 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 524 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 525 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 526 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 527 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 528 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 529 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 530 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 531 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 532 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 533 | golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= 534 | golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= 535 | golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 536 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 537 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 538 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 539 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 540 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 541 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 542 | golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= 543 | golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= 544 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 545 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 546 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 547 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 548 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 549 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 550 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 551 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 552 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 553 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 554 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 555 | golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= 556 | golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 557 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 558 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 559 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 560 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 561 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 562 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 563 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 564 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 565 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 566 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 567 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 568 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 569 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 570 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 571 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 572 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 573 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 574 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 575 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 576 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 577 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 578 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 579 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 580 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 581 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 582 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 583 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 584 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 585 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 586 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 587 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 588 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 589 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 590 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 591 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 592 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 593 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 594 | golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 595 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 596 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 597 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 598 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 599 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 600 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 601 | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= 602 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 603 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 604 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 605 | golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 606 | golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= 607 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 608 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 609 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 610 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 611 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 612 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 613 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 614 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 615 | golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= 616 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 617 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 618 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 619 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 620 | golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= 621 | golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 622 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 623 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 624 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 625 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 626 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 627 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 628 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 629 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 630 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 631 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 632 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 633 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 634 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 635 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 636 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 637 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 638 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 639 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 640 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 641 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 642 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 643 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 644 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 645 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 646 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 647 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 648 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 649 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 650 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 651 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 652 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 653 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 654 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 655 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 656 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 657 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 658 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 659 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 660 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 661 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 662 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 663 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 664 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 665 | golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= 666 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 667 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 668 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 669 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 670 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= 671 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 672 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 673 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 674 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 675 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 676 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 677 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 678 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 679 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 680 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 681 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 682 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 683 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 684 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 685 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 686 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 687 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 688 | google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= 689 | google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= 690 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 691 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 692 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 693 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 694 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 695 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 696 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 697 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 698 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 699 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 700 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 701 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 702 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 703 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 704 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 705 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 706 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 707 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 708 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 709 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 710 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 711 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 712 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 713 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 714 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 715 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 716 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 717 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 718 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 719 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 720 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 721 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 722 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 723 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 724 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 725 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 726 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 727 | google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= 728 | google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= 729 | google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a h1:myvhA4is3vrit1a6NZCWBIwN0kNEnX21DJOJX/NvIfI= 730 | google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= 731 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= 732 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= 733 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 734 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 735 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 736 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 737 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 738 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 739 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 740 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 741 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 742 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 743 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 744 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 745 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 746 | google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= 747 | google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 748 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 749 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 750 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 751 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 752 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 753 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 754 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 755 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 756 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 757 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 758 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 759 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 760 | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= 761 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 762 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 763 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 764 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 765 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 766 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 767 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 768 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 769 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 770 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 771 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 772 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 773 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 774 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 775 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 776 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 777 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 778 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 779 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 780 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 781 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 782 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 783 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 784 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 785 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 786 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 787 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 788 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 789 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 790 | k8s.io/api v0.27.3 h1:yR6oQXXnUEBWEWcvPWS0jQL575KoAboQPfJAuKNrw5Y= 791 | k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= 792 | k8s.io/client-go v0.27.3 h1:7dnEGHZEJld3lYwxvLl7WoehK6lAq7GvgjxpA3nv1E8= 793 | k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= 794 | k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= 795 | k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 h1:OmK1d0WrkD3IPfkskvroRykOulHVHf0s0ZIFRjyt+UI= 796 | k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= 797 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 798 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 799 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 800 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= 801 | sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= 802 | sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= 803 | -------------------------------------------------------------------------------- /import.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/alecthomas/units" 7 | "github.com/go-kit/log" 8 | "github.com/go-kit/log/level" 9 | "github.com/oklog/ulid" 10 | "github.com/pkg/errors" 11 | "github.com/prometheus/prometheus/model/labels" 12 | "github.com/prometheus/prometheus/model/textparse" 13 | "github.com/prometheus/prometheus/tsdb" 14 | tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" 15 | "github.com/prometheus/prometheus/tsdb/fileutil" 16 | "github.com/thanos-io/objstore" 17 | "github.com/thanos-io/thanos/pkg/block" 18 | "github.com/thanos-io/thanos/pkg/block/metadata" 19 | "io" 20 | "math" 21 | "os" 22 | "path/filepath" 23 | "strconv" 24 | "text/tabwriter" 25 | "time" 26 | ) 27 | 28 | func importMetrics(bkt objstore.Bucket, file *string, importBlockSize *time.Duration, dir *string, importLabels *[]string, upload bool, logger log.Logger) error { 29 | inputFile, err := fileutil.OpenMmapFile(*file) 30 | if err != nil { 31 | return err 32 | } 33 | defer inputFile.Close() 34 | 35 | if err := os.MkdirAll(*dir, 0o777); err != nil { 36 | return fmt.Errorf("create output dir: %w", err) 37 | } 38 | 39 | labels, err := parseFlagLabels(*importLabels) 40 | if err != nil { 41 | return errors.Wrap(err, "parse thanos labels") 42 | } 43 | 44 | p := textparse.NewPromParser(inputFile.Bytes()) 45 | maxt, mint, err := getMinAndMaxTimestamps(p) 46 | if err != nil { 47 | return fmt.Errorf("getting min and max timestamp: %w", err) 48 | } 49 | ids, err := createBlocks(inputFile.Bytes(), mint, maxt, int64(*importBlockSize/time.Millisecond), 5000, *dir, true, labels, logger) 50 | if err != nil { 51 | return fmt.Errorf("block creation: %w", err) 52 | } 53 | 54 | if upload { 55 | for _, id := range ids { 56 | begin := time.Now() 57 | err = block.Upload(context.Background(), logger, bkt, filepath.Join(*dir, id.String()), metadata.SHA256Func) 58 | if err != nil { 59 | return errors.Wrapf(err, "upload block %s", id.String()) 60 | } 61 | level.Info(logger).Log("msg", "uploaded block", "id", id.String(), "duration", time.Since(begin)) 62 | } 63 | } 64 | return nil 65 | } 66 | 67 | func getMinAndMaxTimestamps(p textparse.Parser) (int64, int64, error) { 68 | var maxt, mint int64 = math.MinInt64, math.MaxInt64 69 | 70 | for { 71 | entry, err := p.Next() 72 | if errors.Is(err, io.EOF) { 73 | break 74 | } 75 | if err != nil { 76 | return 0, 0, fmt.Errorf("next: %w", err) 77 | } 78 | 79 | if entry != textparse.EntrySeries { 80 | continue 81 | } 82 | 83 | _, ts, _ := p.Series() 84 | if ts == nil { 85 | return 0, 0, fmt.Errorf("expected timestamp for series got none") 86 | } 87 | 88 | if *ts > maxt { 89 | maxt = *ts 90 | } 91 | if *ts < mint { 92 | mint = *ts 93 | } 94 | } 95 | 96 | if maxt == math.MinInt64 { 97 | maxt = 0 98 | } 99 | if mint == math.MaxInt64 { 100 | mint = 0 101 | } 102 | 103 | return maxt, mint, nil 104 | } 105 | 106 | func getCompatibleBlockDuration(maxBlockDuration int64) int64 { 107 | blockDuration := tsdb.DefaultBlockDuration 108 | if maxBlockDuration > tsdb.DefaultBlockDuration { 109 | ranges := tsdb.ExponentialBlockRanges(tsdb.DefaultBlockDuration, 10, 3) 110 | idx := len(ranges) - 1 // Use largest range if user asked for something enormous. 111 | for i, v := range ranges { 112 | if v > maxBlockDuration { 113 | idx = i - 1 114 | break 115 | } 116 | } 117 | blockDuration = ranges[idx] 118 | } 119 | return blockDuration 120 | } 121 | 122 | // https://github.com/prometheus/prometheus/blob/main/cmd/promtool/backfill.go#L87 123 | func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesInAppender int, outputDir string, humanReadable bool, lbls labels.Labels, logger log.Logger) (ids []ulid.ULID, returnErr error) { 124 | blockDuration := getCompatibleBlockDuration(maxBlockDuration) 125 | mint = blockDuration * (mint / blockDuration) 126 | 127 | db, err := tsdb.OpenDBReadOnly(outputDir, nil) 128 | if err != nil { 129 | return nil, err 130 | } 131 | defer func() { 132 | returnErr = tsdb_errors.NewMulti(returnErr, db.Close()).Err() 133 | }() 134 | 135 | var ( 136 | wroteHeader bool 137 | nextSampleTs int64 = math.MaxInt64 138 | ) 139 | 140 | for t := mint; t <= maxt; t += blockDuration { 141 | tsUpper := t + blockDuration 142 | if nextSampleTs != math.MaxInt64 && nextSampleTs >= tsUpper { 143 | // The next sample is not in this timerange, we can avoid parsing 144 | // the file for this timerange. 145 | continue 146 | } 147 | nextSampleTs = math.MaxInt64 148 | 149 | err := func() error { 150 | // To prevent races with compaction, a block writer only allows appending samples 151 | // that are at most half a block size older than the most recent sample appended so far. 152 | // However, in the way we use the block writer here, compaction doesn't happen, while we 153 | // also need to append samples throughout the whole block range. To allow that, we 154 | // pretend that the block is twice as large here, but only really add sample in the 155 | // original interval later. 156 | w, err := tsdb.NewBlockWriter(logger, outputDir, 2*blockDuration) 157 | if err != nil { 158 | return fmt.Errorf("block writer: %w", err) 159 | } 160 | defer func() { 161 | err = tsdb_errors.NewMulti(err, w.Close()).Err() 162 | }() 163 | 164 | ctx := context.Background() 165 | app := w.Appender(ctx) 166 | p := textparse.NewPromParser(input) 167 | samplesCount := 0 168 | for { 169 | e, err := p.Next() 170 | if errors.Is(err, io.EOF) { 171 | break 172 | } 173 | if err != nil { 174 | return fmt.Errorf("parse: %w", err) 175 | } 176 | if e != textparse.EntrySeries { 177 | continue 178 | } 179 | 180 | _, ts, v := p.Series() 181 | if ts == nil { 182 | l := labels.Labels{} 183 | p.Metric(&l) 184 | return fmt.Errorf("expected timestamp for series %v, got none", l) 185 | } 186 | if *ts < t { 187 | continue 188 | } 189 | if *ts >= tsUpper { 190 | if *ts < nextSampleTs { 191 | nextSampleTs = *ts 192 | } 193 | continue 194 | } 195 | 196 | l := labels.Labels{} 197 | p.Metric(&l) 198 | 199 | if _, err := app.Append(0, l, *ts, v); err != nil { 200 | return fmt.Errorf("add sample: %w", err) 201 | } 202 | 203 | samplesCount++ 204 | if samplesCount < maxSamplesInAppender { 205 | continue 206 | } 207 | 208 | // If we arrive here, the samples count is greater than the maxSamplesInAppender. 209 | // Therefore the old appender is committed and a new one is created. 210 | // This prevents keeping too many samples lined up in an appender and thus in RAM. 211 | if err := app.Commit(); err != nil { 212 | return fmt.Errorf("commit: %w", err) 213 | } 214 | 215 | app = w.Appender(ctx) 216 | samplesCount = 0 217 | } 218 | 219 | if err := app.Commit(); err != nil { 220 | return fmt.Errorf("commit: %w", err) 221 | } 222 | 223 | blk, err := w.Flush(ctx) 224 | switch { 225 | case err == nil: 226 | ids = append(ids, blk) 227 | blocks, err := db.Blocks() 228 | if err != nil { 229 | return fmt.Errorf("get blocks: %w", err) 230 | } 231 | for _, b := range blocks { 232 | if b.Meta().ULID == blk { 233 | if err = writeThanosMeta(b.Meta(), lbls.Map(), 0, outputDir, logger); err != nil { 234 | return fmt.Errorf("write metadata: %w", err) 235 | } 236 | printBlocks([]tsdb.BlockReader{b}, !wroteHeader, humanReadable) 237 | wroteHeader = true 238 | break 239 | } 240 | } 241 | case errors.Is(err, tsdb.ErrNoSeriesAppended): 242 | default: 243 | return fmt.Errorf("flush: %w", err) 244 | } 245 | 246 | return nil 247 | }() 248 | if err != nil { 249 | return nil, fmt.Errorf("process blocks: %w", err) 250 | } 251 | } 252 | return ids, nil 253 | } 254 | 255 | func printBlocks(blocks []tsdb.BlockReader, writeHeader, humanReadable bool) { 256 | tw := tabwriter.NewWriter(os.Stdout, 13, 0, 2, ' ', 0) 257 | defer tw.Flush() 258 | 259 | if writeHeader { 260 | fmt.Fprintln(tw, "BLOCK ULID\tMIN TIME\tMAX TIME\tDURATION\tNUM SAMPLES\tNUM CHUNKS\tNUM SERIES\tSIZE") 261 | } 262 | 263 | for _, b := range blocks { 264 | meta := b.Meta() 265 | 266 | fmt.Fprintf(tw, 267 | "%v\t%v\t%v\t%v\t%v\t%v\t%v\t%v\n", 268 | meta.ULID, 269 | getFormatedTime(meta.MinTime, humanReadable), 270 | getFormatedTime(meta.MaxTime, humanReadable), 271 | time.Duration(meta.MaxTime-meta.MinTime)*time.Millisecond, 272 | meta.Stats.NumSamples, 273 | meta.Stats.NumChunks, 274 | meta.Stats.NumSeries, 275 | getFormatedBytes(b.Size(), humanReadable), 276 | ) 277 | } 278 | } 279 | 280 | func getFormatedTime(timestamp int64, humanReadable bool) string { 281 | if humanReadable { 282 | return time.Unix(timestamp/1000, 0).UTC().String() 283 | } 284 | return strconv.FormatInt(timestamp, 10) 285 | } 286 | 287 | func getFormatedBytes(bytes int64, humanReadable bool) string { 288 | if humanReadable { 289 | return units.Base2Bytes(bytes).String() 290 | } 291 | return strconv.FormatInt(bytes, 10) 292 | } 293 | 294 | func writeThanosMeta(meta tsdb.BlockMeta, lbls map[string]string, res int64, dir string, logger log.Logger) error { 295 | m := metadata.Meta{ 296 | BlockMeta: meta, 297 | Thanos: metadata.Thanos{ 298 | Version: metadata.ThanosVersion1, 299 | Labels: lbls, 300 | Downsample: metadata.ThanosDownsample{Resolution: res}, 301 | Source: "thanos-kit", 302 | }, 303 | } 304 | return m.WriteToDir(logger, dir+"/"+meta.ULID.String()) 305 | } 306 | -------------------------------------------------------------------------------- /inspect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/go-kit/log" 8 | "github.com/oklog/ulid" 9 | "github.com/olekukonko/tablewriter" 10 | "github.com/pkg/errors" 11 | "github.com/prometheus/common/model" 12 | "github.com/prometheus/prometheus/model/labels" 13 | "github.com/thanos-io/objstore" 14 | "github.com/thanos-io/thanos/pkg/block/metadata" 15 | mtd "github.com/thanos-io/thanos/pkg/model" 16 | "github.com/thanos-io/thanos/pkg/runutil" 17 | "golang.org/x/sync/errgroup" 18 | "golang.org/x/text/language" 19 | "golang.org/x/text/message" 20 | "io" 21 | "os" 22 | "sort" 23 | "strconv" 24 | "strings" 25 | "sync" 26 | "time" 27 | ) 28 | 29 | const concurrency = 32 30 | 31 | var ( 32 | inspectColumns = []string{"DIR", "ULID", "FROM", "RANGE", "LVL", "RES", "#SAMPLES", "#CHUNKS", "LABELS", "SRC"} 33 | ) 34 | 35 | type Meta struct { 36 | metadata.Meta 37 | Prefix string 38 | } 39 | 40 | func inspect(bkt objstore.Bucket, recursive *bool, selector *[]string, sortBy *[]string, maxTime *mtd.TimeOrDurationValue, logger log.Logger) error { 41 | selectorLabels, err := parseFlagLabels(*selector) 42 | if err != nil { 43 | return errors.Wrap(err, "error parsing selector flag") 44 | } 45 | 46 | ctx := context.Background() // Ctrl-C instead of 5min limit 47 | metas, err := getAllMetas(ctx, bkt, *recursive, maxTime, logger) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | return printTable(metas, selectorLabels, *sortBy, *recursive) 53 | } 54 | 55 | func parseFlagLabels(s []string) (labels.Labels, error) { 56 | var lset labels.Labels 57 | for _, l := range s { 58 | parts := strings.SplitN(l, "=", 2) 59 | if len(parts) != 2 { 60 | return nil, errors.Errorf("unrecognized label %q", l) 61 | } 62 | if !model.LabelName.IsValid(model.LabelName(parts[0])) { 63 | return nil, errors.Errorf("unsupported format for label %s", l) 64 | } 65 | val := parts[1] 66 | if strings.Index(val, `"`) != -1 { 67 | var err error 68 | val, err = strconv.Unquote(parts[1]) 69 | if err != nil { 70 | return nil, errors.Wrap(err, "unquote label value") 71 | } 72 | } 73 | lset = append(lset, labels.Label{Name: parts[0], Value: val}) 74 | } 75 | sort.Sort(lset) 76 | return lset, nil 77 | } 78 | 79 | // read mata.json from all blocks in bucket 80 | func getAllMetas(ctx context.Context, bkt objstore.Bucket, recursive bool, maxTime *mtd.TimeOrDurationValue, logger log.Logger) (map[ulid.ULID]*Meta, error) { 81 | blocks, err := getBlocks(ctx, bkt, recursive, maxTime) 82 | if err != nil { 83 | return nil, err 84 | } 85 | res := make(map[ulid.ULID]*Meta, len(blocks)) 86 | mu := sync.RWMutex{} 87 | eg := errgroup.Group{} 88 | ch := make(chan Block, concurrency) 89 | // workers 90 | for i := 0; i < concurrency; i++ { 91 | eg.Go(func() error { 92 | for b := range ch { 93 | m, err := getMeta(ctx, b, bkt, logger) 94 | if bkt.IsObjNotFoundErr(err) { 95 | continue // Meta.json was deleted between bkt.Exists and here. 96 | } 97 | if err != nil { 98 | return err 99 | } 100 | mu.Lock() 101 | res[b.Id] = &Meta{Meta: *m, Prefix: b.Prefix} 102 | mu.Unlock() 103 | } 104 | return nil 105 | }) 106 | } 107 | 108 | // distribute work 109 | eg.Go(func() error { 110 | defer close(ch) 111 | for _, b := range blocks { 112 | select { 113 | case <-ctx.Done(): 114 | return ctx.Err() 115 | case ch <- b: 116 | } 117 | } 118 | return nil 119 | }) 120 | 121 | if err := eg.Wait(); err != nil { 122 | return nil, err 123 | } 124 | return res, nil 125 | } 126 | 127 | func printTable(blockMetas map[ulid.ULID]*Meta, selectorLabels labels.Labels, sortBy []string, recursive bool) error { 128 | var lines [][]string 129 | p := message.NewPrinter(language.English) 130 | 131 | for _, blockMeta := range blockMetas { 132 | if !matchesSelector(blockMeta, selectorLabels) { 133 | continue 134 | } 135 | 136 | timeRange := time.Duration((blockMeta.MaxTime - blockMeta.MinTime) * int64(time.Millisecond)) 137 | 138 | var line []string 139 | if recursive { 140 | line = append(line, blockMeta.Prefix) 141 | } 142 | line = append(line, blockMeta.ULID.String()) 143 | line = append(line, time.Unix(blockMeta.MinTime/1000, 0).Format("2006-01-02 15:04:05")) 144 | line = append(line, humanizeDuration(timeRange)) 145 | line = append(line, p.Sprintf("%d", blockMeta.Compaction.Level)) 146 | line = append(line, humanizeDuration(time.Duration(blockMeta.Thanos.Downsample.Resolution*int64(time.Millisecond)))) 147 | line = append(line, p.Sprintf("%d", blockMeta.Stats.NumSamples)) 148 | line = append(line, p.Sprintf("%d", blockMeta.Stats.NumChunks)) 149 | line = append(line, labelsToString(blockMeta.Thanos.Labels)) 150 | line = append(line, string(blockMeta.Thanos.Source)) 151 | lines = append(lines, line) 152 | } 153 | 154 | if !recursive { 155 | inspectColumns = inspectColumns[1:] 156 | } 157 | var sortByColNum []int 158 | for _, col := range sortBy { 159 | index := getStrIndex(inspectColumns, col) 160 | if index == -1 { 161 | return errors.Errorf("column %s not found", col) 162 | } 163 | sortByColNum = append(sortByColNum, index) 164 | } 165 | 166 | t := Table{Header: inspectColumns, Lines: lines, SortIndices: sortByColNum} 167 | sort.Sort(t) 168 | 169 | table := tablewriter.NewWriter(os.Stdout) 170 | table.SetHeader(inspectColumns) 171 | table.SetBorders(tablewriter.Border{Left: false, Top: false, Right: false, Bottom: false}) 172 | table.SetCenterSeparator("|") 173 | table.SetAutoWrapText(false) 174 | table.SetReflowDuringAutoWrap(false) 175 | table.SetAlignment(tablewriter.ALIGN_LEFT) 176 | table.AppendBulk(lines) 177 | table.Render() 178 | 179 | return nil 180 | } 181 | 182 | // matchesSelector checks if blockMeta contains every label from 183 | // the selector with the correct value. 184 | func matchesSelector(blockMeta *Meta, selectorLabels labels.Labels) bool { 185 | for _, l := range selectorLabels { 186 | if v, ok := blockMeta.Thanos.Labels[l.Name]; !ok || (l.Value != "*" && v != l.Value) { 187 | return false 188 | } 189 | } 190 | return true 191 | } 192 | 193 | // getKeysAlphabetically return sorted keys of a given map 194 | func getKeysAlphabetically(labels map[string]string) []string { 195 | var keys []string 196 | for k := range labels { 197 | keys = append(keys, k) 198 | } 199 | sort.Strings(keys) 200 | return keys 201 | } 202 | 203 | // labelsToString returns labels as comma separated k=v pairs 204 | func labelsToString(lables map[string]string) string { 205 | pairs := []string{} 206 | for _, k := range getKeysAlphabetically(lables) { 207 | pairs = append(pairs, fmt.Sprintf("%s=%s", k, lables[k])) 208 | } 209 | return strings.Join(pairs, ", ") 210 | } 211 | 212 | // humanizeDuration returns more humane string for duration 213 | func humanizeDuration(d time.Duration) string { 214 | d = d.Truncate(time.Second) 215 | if d.Seconds() > 58 { 216 | d = d.Round(time.Minute) 217 | } 218 | if d%(24*time.Hour) == 0 { 219 | return fmt.Sprintf("%dd", d/(24*time.Hour)) 220 | } 221 | s := d.String() 222 | if strings.HasSuffix(s, "m0s") { 223 | s = s[:len(s)-2] 224 | } 225 | if strings.HasSuffix(s, "h0m") { 226 | s = s[:len(s)-2] 227 | } 228 | return s 229 | } 230 | 231 | // getStrIndex calculates the index of s in strings. 232 | func getStrIndex(strings []string, s string) int { 233 | for i, col := range strings { 234 | if col == s { 235 | return i 236 | } 237 | } 238 | return -1 239 | } 240 | 241 | // Table implements sort.Interface 242 | type Table struct { 243 | Header []string 244 | Lines [][]string 245 | SortIndices []int 246 | } 247 | 248 | func (t Table) Len() int { return len(t.Lines) } 249 | 250 | func (t Table) Swap(i, j int) { t.Lines[i], t.Lines[j] = t.Lines[j], t.Lines[i] } 251 | 252 | func (t Table) Less(i, j int) bool { 253 | for _, index := range t.SortIndices { 254 | if t.Lines[i][index] == t.Lines[j][index] { 255 | continue 256 | } 257 | return compare(t.Lines[i][index], t.Lines[j][index]) 258 | } 259 | return compare(t.Lines[i][0], t.Lines[j][0]) 260 | } 261 | 262 | // compare values can be either Time, Duration, comma-delimited integers or strings. 263 | func compare(s1, s2 string) bool { 264 | s1Time, s1Err := time.Parse("2006-01-02 15:04:05", s1) 265 | s2Time, s2Err := time.Parse("2006-01-02 15:04:05", s2) 266 | if s1Err != nil || s2Err != nil { 267 | s1Duration, s1Err := time.ParseDuration(s1) 268 | s2Duration, s2Err := time.ParseDuration(s2) 269 | if s1Err != nil || s2Err != nil { 270 | s1Int, s1Err := strconv.ParseUint(strings.Replace(s1, ",", "", -1), 10, 64) 271 | s2Int, s2Err := strconv.ParseUint(strings.Replace(s2, ",", "", -1), 10, 64) 272 | if s1Err != nil || s2Err != nil { 273 | return s1 < s2 274 | } 275 | return s1Int < s2Int 276 | } 277 | return s1Duration < s2Duration 278 | } 279 | return s1Time.Before(s2Time) 280 | } 281 | 282 | // get block Metadata from bucket 283 | func getMeta(ctx context.Context, b Block, bkt objstore.Bucket, logger log.Logger) (*metadata.Meta, error) { 284 | metaFile := b.Prefix + b.Id.String() + "/" + metadata.MetaFilename 285 | r, err := bkt.Get(ctx, metaFile) 286 | if bkt.IsObjNotFoundErr(err) { 287 | return nil, err // continue 288 | } 289 | if err != nil { 290 | return nil, errors.Wrapf(err, "get meta file: %v", metaFile) 291 | } 292 | 293 | defer runutil.CloseWithLogOnErr(logger, r, "close bkt meta get") 294 | 295 | metaContent, err := io.ReadAll(r) 296 | if err != nil { 297 | return nil, errors.Wrapf(err, "read meta file: %v", metaFile) 298 | } 299 | 300 | m := &metadata.Meta{} 301 | if err := json.Unmarshal(metaContent, m); err != nil { 302 | return nil, errors.Wrapf(err, "%s unmarshal", metaFile) 303 | } 304 | if m.Version != metadata.ThanosVersion1 { 305 | return nil, errors.Errorf("unexpected meta file: %s version: %d", metaFile, m.Version) 306 | } 307 | return m, nil 308 | } 309 | -------------------------------------------------------------------------------- /inspect_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/prometheus/prometheus/model/labels" 7 | ) 8 | 9 | func Test_parseFlagLabels(t *testing.T) { 10 | cases := []struct { 11 | s []string 12 | expectErr bool 13 | }{ 14 | { 15 | s: []string{`labelName="LabelVal"`, `_label_Name="LabelVal"`, `label_name="LabelVal"`, `LAb_el_Name="LabelValue"`, `lab3l_Nam3=LabelValue `}, 16 | expectErr: false, 17 | }, 18 | { 19 | s: []string{`label-Name="LabelVal"`}, // Unsupported labelname. 20 | expectErr: true, 21 | }, 22 | { 23 | s: []string{`label:Name="LabelVal"`}, // Unsupported labelname. 24 | expectErr: true, 25 | }, 26 | { 27 | s: []string{`1abelName="LabelVal"`}, // Unsupported labelname. 28 | expectErr: true, 29 | }, 30 | { 31 | s: []string{`label_Name"LabelVal"`}, // Missing "=" seprator. 32 | expectErr: true, 33 | }, 34 | { 35 | s: []string{`label_Name= "LabelVal"`}, // Whitespace invalid syntax. 36 | expectErr: true, 37 | }, 38 | } 39 | for _, td := range cases { 40 | _, err := parseFlagLabels(td.s) 41 | if (err != nil) != td.expectErr { 42 | t.Errorf("parseFlagLabels(%q) err=%v, wants %v", td.s, err != nil, td.expectErr) 43 | } 44 | } 45 | } 46 | 47 | func Test_matchesSelector(t *testing.T) { 48 | cases := []struct { 49 | thanosLabels map[string]string 50 | selectorLabels labels.Labels 51 | res bool 52 | }{ 53 | { 54 | thanosLabels: map[string]string{"label": "value"}, 55 | selectorLabels: labels.Labels{ 56 | {"label", "value"}, 57 | }, 58 | res: true, 59 | }, 60 | { 61 | thanosLabels: map[string]string{ 62 | "label": "value", 63 | "label2": "value2", 64 | "label3 ": "value3 ", 65 | }, 66 | selectorLabels: labels.Labels{ 67 | {"label", "*"}, 68 | {"label3 ", "value3 "}, 69 | }, 70 | res: true, 71 | }, 72 | { 73 | thanosLabels: map[string]string{ 74 | "label": "value", 75 | "label2": "value2", 76 | }, 77 | selectorLabels: labels.Labels{ 78 | {"label", "value"}, 79 | {"label3 ", "value3 "}, 80 | }, 81 | res: false, 82 | }, 83 | } 84 | for _, td := range cases { 85 | blockMeta := Meta{} 86 | blockMeta.Thanos.Labels = td.thanosLabels 87 | res := matchesSelector(&blockMeta, td.selectorLabels) 88 | if res != td.res { 89 | t.Errorf("matchesSelector(%q, %q)=%v, wants %v", td.thanosLabels, td.selectorLabels, res, td.res) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /ls.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/oklog/ulid" 7 | "github.com/thanos-io/objstore" 8 | "github.com/thanos-io/thanos/pkg/block" 9 | "github.com/thanos-io/thanos/pkg/model" 10 | "strings" 11 | ) 12 | 13 | func ls(bkt objstore.Bucket, recursive *bool, maxTime *model.TimeOrDurationValue) error { 14 | blocks, err := getBlocks(context.Background(), bkt, *recursive, maxTime) 15 | if err == nil { 16 | for _, b := range blocks { 17 | fmt.Println(b.Prefix+b.Id.String(), ulid.Time(b.Id.Time()).UTC().Format("06-01-02T15:04:05Z")) 18 | } 19 | } 20 | return err 21 | } 22 | 23 | type Block struct { 24 | Prefix string 25 | Id ulid.ULID 26 | } 27 | 28 | func getBlocks(ctx context.Context, bkt objstore.Bucket, recursive bool, maxTime *model.TimeOrDurationValue) (found []Block, err error) { 29 | if recursive { 30 | err = bkt.Iter(ctx, "", func(name string) error { 31 | parts := strings.Split(name, "/") 32 | if len(parts) < 2 { 33 | return nil 34 | } 35 | dir, file := parts[len(parts)-2], parts[len(parts)-1] 36 | if !block.IsBlockMetaFile(file) { 37 | return nil 38 | } 39 | if id, ok := block.IsBlockDir(dir); ok { 40 | prefix := "" 41 | if len(parts) > 2 { 42 | prefix = strings.Join(parts[0:len(parts)-2], "/") + "/" 43 | } 44 | if id.Time() < uint64(maxTime.PrometheusTimestamp()) { 45 | found = append(found, Block{Prefix: prefix, Id: id}) 46 | } 47 | } 48 | return nil 49 | }, objstore.WithRecursiveIter) 50 | } else { 51 | err = bkt.Iter(ctx, "", func(name string) error { 52 | if id, ok := block.IsBlockDir(name); ok && id.Time() < uint64(maxTime.PrometheusTimestamp()) { 53 | found = append(found, Block{Prefix: "", Id: id}) 54 | } 55 | return nil 56 | }) 57 | } 58 | return found, err 59 | } 60 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/efficientgo/tools/extkingpin" 6 | "github.com/go-kit/log" 7 | "github.com/go-kit/log/level" 8 | "github.com/prometheus/common/version" 9 | "github.com/thanos-io/objstore/client" 10 | "github.com/thanos-io/thanos/pkg/model" 11 | "gopkg.in/alecthomas/kingpin.v2" 12 | "math" 13 | "os" 14 | "path/filepath" 15 | "strconv" 16 | ) 17 | 18 | func main() { 19 | app := kingpin.New(filepath.Base(os.Args[0]), "Tooling for Thanos blocks in object storage").Version(version.Print("thanos-split")) 20 | app.HelpFlag.Short('h') 21 | logLevel := app.Flag("log.level", "Log filtering level (info, debug)").Default("info").Enum("error", "warn", "info", "debug") 22 | objStoreConfig := extkingpin.RegisterPathOrContent(app, "objstore.config", "YAML file that contains object store configuration. See format details: https://thanos.io/tip/thanos/storage.md/ ", extkingpin.WithEnvSubstitution(), extkingpin.WithRequired()) 23 | 24 | lsCmd := app.Command("ls", "List all blocks in the bucket.") 25 | lsRecursive := lsCmd.Flag("recursive", "Recurive search for blocks in the bucket (Mimir has blocks nested to tenants folders)").Short('r').Default("false").Bool() 26 | lsMaxTime := model.TimeOrDuration(lsCmd.Flag("max-time", "End of time range limit to get blocks. List only those, which happened earlier than this value. Option can be a constant time in RFC3339 format or time duration relative to current time, such as -1d or 2h45m. Valid duration units are ms, s, m, h, d, w, y."). 27 | Default("9999-12-31T23:59:59Z")) 28 | 29 | inspectCmd := app.Command("inspect", "Inspect all blocks in the bucket in detailed, table-like way") 30 | inspectRecursive := inspectCmd.Flag("recursive", "Recursive search for blocks in the bucket (Mimir has blocks nested to tenants folders)").Short('r').Default("false").Bool() 31 | inspectSelector := inspectCmd.Flag("label", `Filter by Thanos block label, e.g. '-l key1="value1" -l key2="value2"'. All key value pairs must match. To select all blocks for some key use "*" as value.`).Short('l').PlaceHolder(`=""`).Strings() 32 | inspectSortBy := inspectCmd.Flag("sort-by", "Sort by columns. It's also possible to sort by multiple columns, e.g. '--sort-by FROM --sort-by LABELS'. I.e., if the 'FROM' value is equal the rows are then further sorted by the 'LABELS' value"). 33 | Default("FROM", "LABELS").Enums(inspectColumns...) 34 | inspectMaxTime := model.TimeOrDuration(inspectCmd.Flag("max-time", "End of time range limit to get blocks. Inspect only those, which happened earlier than this value. Option can be a constant time in RFC3339 format or time duration relative to current time, such as -1d or 2h45m. Valid duration units are ms, s, m, h, d, w, y."). 35 | Default("9999-12-31T23:59:59Z")) 36 | 37 | analyzeCmd := app.Command("analyze", "Analyze churn, label pair cardinality and find labels to split on") 38 | analyzeULID := analyzeCmd.Arg("ULID", "Block id to analyze (ULID)").Required().String() 39 | analyzeLimit := analyzeCmd.Flag("limit", "How many items to show in each list").Default("20").Int() 40 | analyzeDir := analyzeCmd.Flag("data-dir", "Data directory in which to cache blocks"). 41 | Default("./data").String() 42 | analyzeMatchers := analyzeCmd.Flag("match", "Series selector to analyze. Only 1 set of matchers is supported now.").String() 43 | 44 | dumpCmd := app.Command("dump", "Dump samples from a TSDB to text") 45 | dumpULIDs := dumpCmd.Arg("ULID", "Blocks id (ULID) to dump (repeated)").Required().Strings() 46 | dumpDir := dumpCmd.Flag("data-dir", "Data directory in which to cache blocks").Default("./data").String() 47 | dumpMinTime := dumpCmd.Flag("min-time", "Minimum timestamp to dump").Default("0").Int64() 48 | dumpMaxTime := dumpCmd.Flag("max-time", "Maximum timestamp to dump").Default(strconv.FormatInt(math.MaxInt64, 10)).Int64() 49 | dumpMatch := dumpCmd.Flag("match", "Series selector.").Default("{__name__=~'(?s:.*)'}").String() 50 | 51 | importCmd := app.Command("import", "Import samples from text to TSDB blocks") 52 | importFromFile := importCmd.Flag("input-file", "Promtext file to read samples from.").Short('f').Required().String() 53 | importBlockSize := importCmd.Flag("block-size", "The maximum block size. The actual block timestamps will be aligned with Prometheus time ranges").Default("2h").Duration() 54 | importDir := importCmd.Flag("data-dir", "Data directory in which to cache blocks"). 55 | Default("./data").String() 56 | importLabels := importCmd.Flag("label", "Labels to add as Thanos block metadata (repeated)").Short('l').PlaceHolder(`=""`).Required().Strings() 57 | importUpload := importCmd.Flag("upload", "Upload imported blocks to object storage").Default("false").Bool() 58 | 59 | unwrapCmd := app.Command("unwrap", "Split TSDB block to multiple blocks by Label") 60 | unwrapRelabel := extkingpin.RegisterPathOrContent(unwrapCmd, "relabel-config", fmt.Sprintf("YAML file that contains relabeling configuration. Set %s=name1;name2;... to split separate blocks for each uniq label combination.", metaExtLabels), extkingpin.WithEnvSubstitution(), extkingpin.WithRequired()) 61 | unwrapMetaRelabel := extkingpin.RegisterPathOrContent(unwrapCmd, "meta-relabel", "YAML file that contains relabeling configuration for block labels (meta.json)", extkingpin.WithEnvSubstitution()) 62 | unwrapRecursive := unwrapCmd.Flag("recursive", "Recursive search for blocks in the bucket (Mimir has blocks nested to tenants folders)").Short('r').Default("false").Bool() 63 | unwrapDir := unwrapCmd.Flag("data-dir", "Data directory in which to cache blocks and process tsdb.").Default("./data").String() 64 | unwrapWait := unwrapCmd.Flag("wait-interval", "Wait interval between consecutive runs and bucket refreshes. Run once if 0.").Default("5m").Short('w').Duration() 65 | unwrapDry := unwrapCmd.Flag("dry-run", "Don't do any changes to bucket. Only print what would be done.").Default("false").Bool() 66 | unwrapDst := extkingpin.RegisterPathOrContent(unwrapCmd, "dst.config", "YAML file that contains destination object store configuration for generated blocks.", extkingpin.WithEnvSubstitution(), extkingpin.WithRequired()) 67 | unwrapMaxTime := model.TimeOrDuration(unwrapCmd.Flag("max-time", "End of time range limit to get blocks. Unwrap only those, which happened earlier than this value. Option can be a constant time in RFC3339 format or time duration relative to current time, such as -1d or 2h45m. Valid duration units are ms, s, m, h, d, w, y."). 68 | Default("9999-12-31T23:59:59Z")) 69 | unwrapSrc := unwrapCmd.Flag("source", "Only process blocks produced by this source (e.g `compactor`). Empty means process all blocks").Default("").String() 70 | 71 | cmd := kingpin.MustParse(app.Parse(os.Args[1:])) 72 | var logger log.Logger 73 | { 74 | lvl := level.AllowInfo() 75 | if *logLevel == "debug" { 76 | lvl = level.AllowDebug() 77 | } 78 | logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) 79 | logger = level.NewFilter(logger, lvl) 80 | logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) 81 | } 82 | 83 | objStoreYaml, err := objStoreConfig.Content() 84 | if err != nil { 85 | exitCode(err) 86 | } 87 | bkt, err := client.NewBucket(logger, objStoreYaml, "thanos-kit") 88 | if err != nil { 89 | exitCode(err) 90 | } 91 | 92 | switch cmd { 93 | case lsCmd.FullCommand(): 94 | exitCode(ls(bkt, lsRecursive, lsMaxTime)) 95 | case inspectCmd.FullCommand(): 96 | exitCode(inspect(bkt, inspectRecursive, inspectSelector, inspectSortBy, inspectMaxTime, logger)) 97 | case analyzeCmd.FullCommand(): 98 | exitCode(analyze(bkt, analyzeULID, analyzeDir, analyzeLimit, analyzeMatchers, logger)) 99 | case dumpCmd.FullCommand(): 100 | exitCode(dump(bkt, os.Stdout, dumpULIDs, dumpDir, dumpMinTime, dumpMaxTime, dumpMatch, logger)) 101 | case importCmd.FullCommand(): 102 | exitCode(importMetrics(bkt, importFromFile, importBlockSize, importDir, importLabels, *importUpload, logger)) 103 | case unwrapCmd.FullCommand(): 104 | exitCode(unwrap(bkt, *unwrapRelabel, *unwrapMetaRelabel, *unwrapRecursive, unwrapDir, unwrapWait, *unwrapDry, unwrapDst, unwrapMaxTime, unwrapSrc, logger)) 105 | } 106 | } 107 | 108 | func exitCode(err error) { 109 | if err != nil { 110 | fmt.Fprintln(os.Stderr, err) 111 | os.Exit(1) 112 | } 113 | return 114 | } 115 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/thanos-io/objstore/client" 6 | "math" 7 | "math/rand" 8 | "os" 9 | "os/exec" 10 | "path/filepath" 11 | "testing" 12 | "time" 13 | 14 | "github.com/go-kit/log" 15 | "github.com/thanos-io/thanos/pkg/block/metadata" 16 | ) 17 | 18 | func Test_e2e(t *testing.T) { 19 | tmpDir := "./tmp" 20 | bktDir := tmpDir + "/bucket" 21 | if err := os.MkdirAll(bktDir, 0750); err != nil { 22 | t.Fatalf("Unable to create %s directory for testing", bktDir) 23 | } 24 | cacheDir := tmpDir + "/cache" 25 | if err := os.MkdirAll(cacheDir, 0750); err != nil { 26 | t.Fatalf("Unable to create %s directory for testing", cacheDir) 27 | } 28 | 29 | // prepare test data 30 | inputFile := tmpDir + "/import.prom" 31 | f, _ := os.Create(inputFile) 32 | end := time.Now().Unix() 33 | for i := end - 3600; i <= end; i += 15 { 34 | fmt.Fprintf(f, "test_metric_one{label=\"test1\"} %g %d000\n", float64(rand.Int()), i) 35 | fmt.Fprintf(f, "test_metric_two{label=\"test2\", new=\"another label\"} %g %d500\n", rand.Float64(), i) 36 | } 37 | f.Close() 38 | 39 | // import metrics to local objStore 40 | logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) 41 | bkt, err := client.NewBucket(logger, []byte("{type: FILESYSTEM, config: {directory: "+bktDir+"}}"), "thanos-kit") 42 | if err != nil { 43 | t.Fatalf("Open bucket: %v", err) 44 | } 45 | blockSize := 2 * time.Hour 46 | importLabels := []string{ 47 | `prometheus="prometheus-a"`, 48 | "datacenter=us", 49 | } 50 | if err := importMetrics(bkt, &inputFile, &blockSize, &cacheDir, &importLabels, true, logger); err != nil { 51 | t.Fatalf("Import of %s failed: %v", inputFile, err) 52 | } 53 | os.RemoveAll(cacheDir) 54 | 55 | // check thanos labels 56 | dirs, _ := os.ReadDir(bktDir) 57 | ids := []string{} 58 | for _, d := range dirs { 59 | ids = append(ids, d.Name()) 60 | meta, err := metadata.ReadFromDir(filepath.Join(bktDir, d.Name())) 61 | if err != nil { 62 | t.Fatalf("fail to read meta.json for %s: %v", d.Name(), err) 63 | } 64 | if len(meta.Thanos.Labels) != 2 || 65 | meta.Thanos.Labels["prometheus"] != "prometheus-a" || 66 | meta.Thanos.Labels["datacenter"] != "us" { 67 | t.Fatalf("Wrong Thanos Labels in object storage block %s: %v", d.Name(), meta.Thanos.Labels) 68 | } 69 | } 70 | 71 | // export data from object storage 72 | outFile := tmpDir + "/export.prom" 73 | f, _ = os.Create(outFile) 74 | minT := int64(0) 75 | maxT := int64(math.MaxInt64) 76 | match := "{__name__=~'(?s:.*)'}" 77 | if err := dump(bkt, f, &ids, &cacheDir, &minT, &maxT, &match, logger); err != nil { 78 | t.Fatalf("Export of %s failed: %v", ids, err) 79 | } 80 | f.Close() 81 | 82 | // compare results 83 | cmd := exec.Command("bash", "-c", fmt.Sprintf("diff <(sort %s) <(sort %s)", inputFile, outFile)) 84 | cmd.Stderr = os.Stderr 85 | if err := cmd.Run(); err != nil { 86 | t.Fatalf("Compare files %s and %s result: %v", inputFile, outFile, err) 87 | } 88 | 89 | // Cleanup 90 | os.RemoveAll(tmpDir) 91 | } 92 | -------------------------------------------------------------------------------- /unwrap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/efficientgo/tools/extkingpin" 7 | "github.com/go-kit/log" 8 | "github.com/go-kit/log/level" 9 | "github.com/oklog/ulid" 10 | "github.com/prometheus/prometheus/model/labels" 11 | "github.com/prometheus/prometheus/model/relabel" 12 | "github.com/prometheus/prometheus/storage" 13 | "github.com/prometheus/prometheus/tsdb" 14 | "github.com/prometheus/prometheus/tsdb/chunkenc" 15 | tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" 16 | "github.com/thanos-io/objstore" 17 | "github.com/thanos-io/objstore/client" 18 | "github.com/thanos-io/thanos/pkg/block" 19 | "github.com/thanos-io/thanos/pkg/block/metadata" 20 | "github.com/thanos-io/thanos/pkg/model" 21 | "github.com/thanos-io/thanos/pkg/runutil" 22 | "gopkg.in/yaml.v2" 23 | "math" 24 | "os" 25 | "path" 26 | "path/filepath" 27 | "slices" 28 | "strings" 29 | "sync" 30 | "time" 31 | ) 32 | 33 | const metaExtLabels = "__meta_ext_labels" 34 | 35 | func unwrap(bkt objstore.Bucket, unwrapRelabel extkingpin.PathOrContent, unwrapMetaRelabel extkingpin.PathOrContent, recursive bool, dir *string, wait *time.Duration, unwrapDry bool, outConfig *extkingpin.PathOrContent, maxTime *model.TimeOrDurationValue, unwrapSrc *string, logger log.Logger) (err error) { 36 | relabelContentYaml, err := unwrapRelabel.Content() 37 | if err != nil { 38 | return fmt.Errorf("get content of relabel configuration: %w", err) 39 | } 40 | var relabelConfig []*relabel.Config 41 | if err := yaml.Unmarshal(relabelContentYaml, &relabelConfig); err != nil { 42 | return fmt.Errorf("parse relabel configuration: %w", err) 43 | } 44 | metaRelabelContentYaml, err := unwrapMetaRelabel.Content() 45 | if err != nil { 46 | return fmt.Errorf("get content of meta-relabel configuration: %w", err) 47 | } 48 | var metaRelabel []*relabel.Config 49 | if err := yaml.Unmarshal(metaRelabelContentYaml, &metaRelabel); err != nil { 50 | return fmt.Errorf("parse relabel configuration: %w", err) 51 | } 52 | 53 | objStoreYaml, err := outConfig.Content() 54 | if err != nil { 55 | return err 56 | } 57 | dst, err := client.NewBucket(logger, objStoreYaml, "thanos-kit") 58 | if err != nil { 59 | return err 60 | } 61 | 62 | processBucket := func() error { 63 | begin := time.Now() 64 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) 65 | defer cancel() 66 | blocks, err := getBlocks(ctx, bkt, recursive, maxTime) 67 | if err != nil { 68 | return err 69 | } 70 | for _, b := range blocks { 71 | if *unwrapSrc != "" { 72 | m, err := getMeta(ctx, b, bkt, logger) 73 | if bkt.IsObjNotFoundErr(err) { 74 | continue // Meta.json was deleted between bkt.Exists and here. 75 | } 76 | if err != nil { 77 | return err 78 | } 79 | if string(m.Thanos.Source) != *unwrapSrc { 80 | continue 81 | } 82 | } 83 | if err := unwrapBlock(bkt, b, relabelConfig, metaRelabel, *dir, unwrapDry, dst, logger); err != nil { 84 | return err 85 | } 86 | } 87 | level.Info(logger).Log("msg", "bucket iteration done", "blocks", len(blocks), "duration", time.Since(begin), "sleeping", wait) 88 | return nil 89 | } 90 | 91 | if *wait == 0 { 92 | return processBucket() 93 | } 94 | ctx, cancel := context.WithCancel(context.Background()) 95 | defer cancel() 96 | return runutil.Repeat(*wait, ctx.Done(), func() error { 97 | return processBucket() 98 | }) 99 | } 100 | 101 | func unwrapBlock(bkt objstore.Bucket, b Block, relabelConfig []*relabel.Config, metaRelabel []*relabel.Config, dir string, unwrapDry bool, dst objstore.Bucket, logger log.Logger) error { 102 | if err := runutil.DeleteAll(dir); err != nil { 103 | return fmt.Errorf("unable to cleanup cache folder %s: %w", dir, err) 104 | } 105 | inDir := path.Join(dir, "in") 106 | outDir := path.Join(dir, "out") 107 | matchAll := &labels.Matcher{ 108 | Name: "__name__", 109 | Type: labels.MatchNotEqual, 110 | Value: "", 111 | } 112 | 113 | // prepare input 114 | ctxd, canceld := context.WithTimeout(context.Background(), 10*time.Minute) 115 | defer canceld() 116 | pb := objstore.NewPrefixedBucket(bkt, b.Prefix) 117 | if err := downloadBlock(ctxd, inDir, b.Id.String(), pb, logger); err != nil { 118 | return err 119 | } 120 | os.Mkdir(path.Join(inDir, "wal"), 0777) 121 | origMeta, err := metadata.ReadFromDir(path.Join(inDir, b.Id.String())) 122 | if err != nil { 123 | return fmt.Errorf("fail to read meta.json for %s: %w", b.Id.String(), err) 124 | } 125 | lbls, keep := relabel.Process(labels.FromMap(origMeta.Thanos.Labels), metaRelabel...) 126 | if !keep { 127 | return nil 128 | } 129 | origMeta.Thanos.Labels = lbls.Map() 130 | db, err := tsdb.OpenDBReadOnly(inDir, logger) 131 | if err != nil { 132 | return err 133 | } 134 | defer func() { 135 | err = tsdb_errors.NewMulti(err, db.Close()).Err() 136 | }() 137 | q, err := db.Querier(context.Background(), 0, math.MaxInt64) 138 | if err != nil { 139 | return err 140 | } 141 | defer q.Close() 142 | 143 | // prepare output 144 | os.Mkdir(outDir, 0777) 145 | duration := getCompatibleBlockDuration(math.MaxInt64) //todo 146 | mw, err := newMultiBlockWriter(outDir, logger, duration, *origMeta) 147 | if err != nil { 148 | return err 149 | } 150 | 151 | // unwrap 152 | ss := q.Select(false, nil, matchAll) 153 | for ss.Next() { 154 | series := ss.At() 155 | rl, keep := relabel.Process(series.Labels(), relabelConfig...) 156 | if !keep { 157 | continue 158 | } 159 | 160 | lbs, extl := extractLabels(rl, strings.Split(rl.Get(metaExtLabels), ";")) 161 | tdb, err := mw.getTenant(context.Background(), extl) 162 | if err != nil { 163 | return err 164 | } 165 | it := series.Iterator(nil) 166 | for it.Next() == chunkenc.ValFloat { 167 | ts, val := it.At() 168 | if _, err := tdb.appender.Append(0, lbs, ts, val); err != nil { 169 | return err 170 | } 171 | tdb.samples++ 172 | } 173 | for it.Next() == chunkenc.ValFloatHistogram { 174 | ts, fh := it.AtFloatHistogram() 175 | if _, err := tdb.appender.AppendHistogram(0, lbs, ts, nil, fh); err != nil { 176 | return err 177 | } 178 | tdb.samples++ 179 | } 180 | for it.Next() == chunkenc.ValHistogram { 181 | ts, h := it.AtHistogram() 182 | if _, err := tdb.appender.AppendHistogram(0, lbs, ts, h, nil); err != nil { 183 | return err 184 | } 185 | tdb.samples++ 186 | } 187 | if it.Err() != nil { 188 | return ss.Err() 189 | } 190 | } 191 | 192 | if ss.Err() != nil { 193 | return ss.Err() 194 | } 195 | if ws := ss.Warnings(); len(ws) > 0 { 196 | return tsdb_errors.NewMulti(ws...).Err() 197 | } 198 | 199 | blocks, err := mw.flush(context.Background()) 200 | if unwrapDry { 201 | level.Info(logger).Log("msg", "dry-run: skipping upload of created blocks and delete of original block", "ulids", fmt.Sprint(blocks), "orig", b.Id) 202 | } else { 203 | for _, id := range blocks { 204 | begin := time.Now() 205 | ctxu, cancelu := context.WithTimeout(context.Background(), 10*time.Minute) 206 | defer cancelu() 207 | err = block.Upload(ctxu, logger, dst, filepath.Join(outDir, id.String()), metadata.SHA256Func) 208 | if err != nil { 209 | return fmt.Errorf("upload block %s: %v", id, err) 210 | } 211 | level.Info(logger).Log("msg", "uploaded block", "ulid", id, "duration", time.Since(begin)) 212 | } 213 | level.Info(logger).Log("msg", "deleting original block", "ulid", b.Id) 214 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) 215 | defer cancel() 216 | if err := block.Delete(ctx, logger, pb, b.Id); err != nil { 217 | return fmt.Errorf("delete block %s%s: %v", b.Prefix, b.Id, err) 218 | } 219 | } 220 | 221 | return nil 222 | } 223 | 224 | // extractLabels splits given labels to two sets: for given `names` and the rest without metaExtLabels preserving sort order 225 | func extractLabels(ls labels.Labels, names []string) (res labels.Labels, el labels.Labels) { 226 | slices.Sort(names) 227 | i, j := 0, 0 228 | for i < len(ls) && j < len(names) { 229 | switch { 230 | // https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config 231 | // Labels starting with __ will be removed from the label set after target relabeling is completed. 232 | case strings.HasPrefix(ls[i].Name, "__") && ls[i].Name != "__name__": 233 | i++ 234 | case names[j] < ls[i].Name: 235 | j++ 236 | case ls[i].Name < names[j]: 237 | res = append(res, ls[i]) 238 | i++ 239 | default: 240 | el = append(el, ls[i]) 241 | i++ 242 | j++ 243 | } 244 | } 245 | res = append(res, ls[i:]...) 246 | return res, el 247 | } 248 | 249 | type MultiBlockWriter struct { 250 | db *tsdb.DBReadOnly 251 | origMeta metadata.Meta 252 | blockSize int64 // in ms 253 | tenants map[uint64]*tenant 254 | logger log.Logger 255 | dir string 256 | mu sync.Mutex 257 | } 258 | 259 | type tenant struct { 260 | appender storage.Appender 261 | writer *tsdb.BlockWriter 262 | samples int 263 | extLables labels.Labels 264 | } 265 | 266 | // newMultiBlockWriter creates a new multi-tenant tsdb BlockWriter 267 | func newMultiBlockWriter(dir string, logger log.Logger, blockSize int64, meta metadata.Meta) (*MultiBlockWriter, error) { 268 | return &MultiBlockWriter{ 269 | blockSize: blockSize, 270 | origMeta: meta, 271 | tenants: make(map[uint64]*tenant), 272 | logger: logger, 273 | dir: dir, 274 | }, nil 275 | } 276 | 277 | func (m *MultiBlockWriter) getTenant(ctx context.Context, lbls labels.Labels) (*tenant, error) { 278 | id := lbls.Hash() 279 | if _, ok := m.tenants[id]; !ok { 280 | w, err := tsdb.NewBlockWriter(m.logger, m.dir, m.blockSize) 281 | if err != nil { 282 | return nil, err 283 | } 284 | m.mu.Lock() 285 | m.tenants[id] = &tenant{ 286 | writer: w, 287 | appender: w.Appender(ctx), 288 | samples: 0, 289 | extLables: lbls, 290 | } 291 | m.mu.Unlock() 292 | } 293 | // reduce Mem usage, commit appender 294 | if m.tenants[id].samples > 5000 { 295 | if err := m.commit(ctx, id); err != nil { 296 | return nil, err 297 | } 298 | } 299 | 300 | return m.tenants[id], nil 301 | } 302 | 303 | func (m *MultiBlockWriter) commit(ctx context.Context, id uint64) error { 304 | err := m.tenants[id].appender.Commit() 305 | m.mu.Lock() 306 | defer m.mu.Unlock() 307 | m.tenants[id].appender = m.tenants[id].writer.Appender(ctx) 308 | m.tenants[id].samples = 0 309 | return err 310 | } 311 | 312 | // flush writes all blocks and reset MultiBlockWriter tenants 313 | func (m *MultiBlockWriter) flush(ctx context.Context) (ids []ulid.ULID, err error) { 314 | m.mu.Lock() 315 | defer m.mu.Unlock() 316 | for _, t := range m.tenants { 317 | if err := t.appender.Commit(); err != nil { 318 | return nil, err 319 | } 320 | id, err := t.writer.Flush(ctx) 321 | if err != nil { 322 | return nil, err 323 | } 324 | ids = append(ids, id) 325 | if err := t.writer.Close(); err != nil { 326 | return nil, err 327 | } 328 | 329 | meta, err := metadata.ReadFromDir(path.Join(m.dir, id.String())) 330 | if err != nil { 331 | return nil, fmt.Errorf("read %s metadata: %w", id, err) 332 | } 333 | l := m.origMeta.Thanos.Labels 334 | for _, e := range t.extLables { 335 | l[e.Name] = e.Value 336 | } 337 | if err = writeThanosMeta(meta.BlockMeta, l, m.origMeta.Thanos.Downsample.Resolution, m.dir, m.logger); err != nil { 338 | return nil, fmt.Errorf("write %s metadata: %w", id, err) 339 | } 340 | } 341 | m.tenants = make(map[uint64]*tenant) 342 | return ids, nil 343 | } 344 | --------------------------------------------------------------------------------