Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a CLI for uploading and downloading blocks #760

Merged
merged 11 commits into from
Nov 12, 2024

Conversation

kushalShukla-web
Copy link
Contributor

@kushalShukla-web kushalShukla-web commented Sep 24, 2024

This PR introduces a powerful CLI tool for seamless block uploading and downloading. The initial implementation leverages an object storage as the storage backend, with the potential for other storage backends in the future.

  • Added a dedicated upload function for uploading data to the object store, with error handling and status logs using log/slog.
  • A separate download function was created to fetch data from the object store.
    Structured logging is a key feature of this PR, made possible by the utilization of the log/slog package. This enables easier traceability and debugging during storage operations.
  • Insured clear separation of concerns by modularizing upload and download logic into distinct functions.
  • Integrated the Thanos object storage package to facilitate efficient data storage and retrieval handling.

Test plan

  • Manual testing locally against a Minio service.

Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see 'upload'; will you be downloading data at some point?

tools/load-generator/main.go Outdated Show resolved Hide resolved
@kushalShukla-web
Copy link
Contributor Author

I see 'upload'; will you be downloading data at some point?

yes @bboreham I have to implement both upload and download functionality.

Copy link
Member

@kakkoyun kakkoyun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good start. Let's keep up the good work.

infra/infra.go Outdated Show resolved Hide resolved
pkg/provider/store/object_store.go Outdated Show resolved Hide resolved
@kakkoyun
Copy link
Member

@kushalShukla-web Also, we should work on the PR title and the description.

Please also sign your commits https://github.com/prometheus/test-infra/pull/760/checks?check_run_id=30633470860

Copy link
Member

@kakkoyun kakkoyun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's going in a good direction. Thanks a lot. I have commented. We need to clean up the architecture.

We should also work on the naming and documentation. We miss the README as well.

Check this out https://go.dev/blog/package-names

tools/object-storage/Dockerfile Outdated Show resolved Hide resolved
tools/object-storage/obj.go Outdated Show resolved Hide resolved
tools/object-storage/obj.go Outdated Show resolved Hide resolved
config := c.ObjectConfig
configBytes, err := os.ReadFile(config)
if err != nil {
panic(fmt.Errorf("failed to read config file: %v", err))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function returns an error. Why do we panic? Let's just return the error.

tools/object-storage/upload_download.go Outdated Show resolved Hide resolved
app := kingpin.New(filepath.Base(os.Args[0]), "Tool for storing TSDB data to object storage")
app.HelpFlag.Short('h')

s := newstore()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructor should get the flag variable. Why do we have a store in an inconsistent state?

}
fmt.Println(exists)

err = objstore.UploadDir(context.Background(), log.NewNopLogger(), bucket, c.TsdbPath, commitDir)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should give a proper logger to the buckets.

}
commitDir := c.ObjectKey

bucket, err := client.NewBucket(log.NewNopLogger(), configBytes, "example")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bucket, err := client.NewBucket(log.NewNopLogger(), configBytes, "example")
bucket, err := client.NewBucket(log.NewNopLogger(), configBytes, "block-sync")

We could use a proper component name.

if err != nil {
panic(err)
}
exists, err := bucket.Exists(context.Background(), "example")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

example is wrong here, no? This should be a parent directory we get as a command line argument.

panic(fmt.Errorf("failed to read config file: %v", err))
}
commitDir := c.ObjectKey
bucket, err := client.NewBucket(log.NewNopLogger(), configBytes, "example")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again we should use a proper component name.

@kushalShukla-web kushalShukla-web changed the title Used Module Object storage Bucket Implement Thanos Object Storage Support with Command-Line Data Upload and Download Sep 27, 2024
tools/blockSyncer/Dockerfile Outdated Show resolved Hide resolved
tools/blockSyncer/Readme.md Outdated Show resolved Hide resolved
app.HelpFlag.Short('h')

var tsdbPath, objectConfig, objectKey string
var s *Store
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can omit this.

objstore.Flag("tsdb-path", "Path for The TSDB data in prometheus").Required().StringVar(&tsdbPath)
objstore.Flag("objstore.config-file", "Path for The Config file").Required().StringVar(&objectConfig)
objstore.Flag("key", "Path for the Key where to store block data").Required().StringVar(&objectKey)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
s = newstore(tsdbPath, objectConfig, objectKey)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
s, err := newStore(...)
if err != nil {
logger.Log(..)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ctx, cancel := context.WithCancel(context.Backgroud())
defer cancel()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ctx, stop := signal.NotifyContext(ctx, os.Interrupt)
defer stop()

objstore.Flag("tsdb-path", "Path for The TSDB data in prometheus").Required().StringVar(&tsdbPath)
objstore.Flag("objstore.config-file", "Path for The Config file").Required().StringVar(&objectConfig)
objstore.Flag("key", "Path for the Key where to store block data").Required().StringVar(&objectKey)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
kingpin.MustParse(app.Parse(os.Args[1:]))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we move this to line 34, it will not be able to recognize the download and upload functions because these lines are declared below.

tools/blockSyncer/upload_download.go Outdated Show resolved Hide resolved
tools/blockSyncer/upload_download.go Outdated Show resolved Hide resolved
tools/blockSyncer/upload_download.go Outdated Show resolved Hide resolved
tools/blockSyncer/upload_download.go Outdated Show resolved Hide resolved
tools/blockSyncer/upload_download.go Outdated Show resolved Hide resolved
@kushalShukla-web kushalShukla-web changed the title Implement Thanos Object Storage Support with Command-Line Data Upload and Download Create Thanos Object Storage Support with Command-Line Data Upload and Download Oct 4, 2024
@kakkoyun kakkoyun changed the title Create Thanos Object Storage Support with Command-Line Data Upload and Download Create a CLI for uploading and downloading blocks Oct 8, 2024
@bwplotka
Copy link
Member

bwplotka commented Oct 14, 2024

Is this something that would be useful in promtool? 🤔 https://github.com/prometheus/prometheus/tree/main/cmd/promtool

@bwplotka
Copy link
Member

Ah this is for old data in prombench, cool.

Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments

tools/block-sync/README.md Outdated Show resolved Hide resolved
cd /repo1 && \
git fetch origin pull/{{ .PR_NUMBER }}/head:pr-branch && \
git checkout pr-branch && \
cp objectconfig.yml /mnt/repo/objectconfig.yml && \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where you would be combining password etc from some Secret?

Comment on lines 225 to 227
- name: config
hostPath:
path: /object-config
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do this; just use the instance-ssd volume.

Comment on lines 107 to 109
- name: config
hostPath:
path: /config-file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do this; just use the instance-ssd volume.

tools/prometheus-builder/build.sh Outdated Show resolved Hide resolved
tools/prometheus-builder/build.sh Outdated Show resolved Hide resolved
The configuration file is essential for connecting to your object storage solution. Below are basic templates for different object storage systems.

```yaml
type: s3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are other types available? E.g. GCS?

tools/load-generator/main.go Outdated Show resolved Hide resolved
defer resp.Body.Close()

duration := time.Since(start)
duration := time.Since(*baseTime)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No

2. changed upload-download function to extract key
3. updated bash.sh file

Signed-off-by: Kushal Shukla <[email protected]>
Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've discussed this PR on video-call and on Slack; I'm repeating a couple of points here:

  • Make this PR just the CLI program; pull out the yamls and scripting to another PR.
  • Get the images updated in one PR, then change the yamls that use them. We can't merge a change to use your privately-built image.

@@ -44,10 +44,35 @@ spec:
- name: GITHUB_ORG
value: "{{ .GITHUB_ORG }}"
- name: GITHUB_REPO
value: "{{ .GITHUB_REPO }}"
value: "{{ .GITHUB_REPO }}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spurious change

@@ -34,7 +34,7 @@ spec:
runAsUser: 0
initContainers:
- name: prometheus-builder
image: docker.io/prominfra/prometheus-builder:master
image: kushalshukla/builder
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guessing this one is built from the change in this PR.

@@ -5,8 +5,7 @@ DIR="/go/src/github.com/prometheus/prometheus"
if [[ -z $PR_NUMBER || -z $VOLUME_DIR || -z $GITHUB_ORG || -z $GITHUB_REPO ]]; then
echo "ERROR:: environment variables not set correctly"
exit 1;
fi

fi
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spurious change - removal of blank line.

Comment on lines 26 to 27
MKDIR="/config"
cp "$DIR/key.yml" "$MKDIR/key.yml"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a comment at least.

Comment on lines 184 to 190
apk add --no-cache bash && \
git clone --depth 1 https://github.com/{{ .GITHUB_ORG }}/{{ .GITHUB_REPO }}.git /repo1 && \
cd /repo1 && \
git fetch origin pull/{{ .PR_NUMBER }}/head:pr-branch && \
git checkout pr-branch && \
cp key.yml /config/key.yml && \
rm -rf /repo1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This multi-line command is getting unwieldly. Pull it out to a .sh file.

type: Opaque
stringData:
object-config.yml: |
type: S3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be configured differently for each installation - s3 is good for local installs using Minio, but when run at Google Cloud it needs to say gcs.
I suggest you take this Secret out of the PR and instead put instructions in the docs, e.g. here, for the person who installs Prombench to set it up.

kind: Secret
metadata:
name: s3-secret
namespace: prombench-{{ .PR_NUMBER }} # Replace with your actual namespace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you put the Secret in the namespace for the PR, but I see the same bucket being used across many runs.

Key changes
1. removed multiline command and put it in script on prometheus-builder image.
2. configure this in prometheus deployment.
3. added download.sh script which will download the data if key present , else
skip the downloading process and move to next container.
@bboreham
Copy link
Member

bboreham commented Nov 7, 2024

One thing that could be added (not vital right now) is to be able to upload several blocks.

Example:

# du -h
4.6G    ./01JC3JCA8Y39ZV72Y0F0FEEQND/chunks
5.8G    ./01JC3JCA8Y39ZV72Y0F0FEEQND
1.5G    ./01JC3J7CCY83F1EZGCBMEPG2RY/chunks
1.9G    ./01JC3J7CCY83F1EZGCBMEPG2RY
4.6G    ./01JC2XS9SGSE6YTKJZSAJP3YR8/chunks
5.8G    ./01JC2XS9SGSE6YTKJZSAJP3YR8
[...]
958.2M  ./chunks_head
85.4M   ./wal/checkpoint.00002015
4.2G    ./wal

I can specify one block, e.g. 01JC3J7CCY83F1EZGCBMEPG2RY, but I can't specify two.
If I upload the entire Prometheus data direectory I will get wal and chunks_head, which we don't want to download for a subsequent Prombench run.

…t.yaml.

2. Added a section for secretes in kind.md file
Signed-off-by: Kushal Shukla <[email protected]>
Signed-off-by: Kushal Shukla <[email protected]>
Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, let's merge this and see how well it works.

@bboreham bboreham merged commit d9fd1a1 into prometheus:master Nov 12, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants