mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-02-09 15:27:11 +00:00
![Roman Khavronenko](/assets/img/avatar_default.png)
The new flag type is supposed to be used for specifying URL values which
could contain sensitive information such as auth tokens in GET params or
HTTP basic authentication.
The URL flag also allows loading its value from files if `file://`
prefix is specified. As example, the new flag type was used in
app/vmbackup as it requires specifying `authKey` param for making the
snapshot.
See related issue
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5973
Thanks to @wasim-nihal for initial implementation
https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6060
---------
Signed-off-by: hagen1778 <roman@victoriametrics.com>
(cherry picked from commit 029060af60
)
115 lines
3.5 KiB
Go
115 lines
3.5 KiB
Go
package snapshot
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
|
)
|
|
|
|
var (
|
|
tlsInsecureSkipVerify = flag.Bool("snapshot.tlsInsecureSkipVerify", false, "Whether to skip tls verification when connecting to -snapshotCreateURL")
|
|
tlsCertFile = flag.String("snapshot.tlsCertFile", "", "Optional path to client-side TLS certificate file to use when connecting to -snapshotCreateURL")
|
|
tlsKeyFile = flag.String("snapshot.tlsKeyFile", "", "Optional path to client-side TLS certificate key to use when connecting to -snapshotCreateURL")
|
|
tlsCAFile = flag.String("snapshot.tlsCAFile", "", `Optional path to TLS CA file to use for verifying connections to -snapshotCreateURL. By default, system CA is used`)
|
|
tlsServerName = flag.String("snapshot.tlsServerName", "", `Optional TLS server name to use for connections to -snapshotCreateURL. By default, the server name from -snapshotCreateURL is used`)
|
|
)
|
|
|
|
type snapshot struct {
|
|
Status string `json:"status"`
|
|
Snapshot string `json:"snapshot"`
|
|
Msg string `json:"msg"`
|
|
}
|
|
|
|
// Create creates a snapshot via the provided api endpoint and returns the snapshot name
|
|
func Create(createSnapshotURL string) (string, error) {
|
|
logger.Infof("Creating snapshot")
|
|
u, err := url.Parse(createSnapshotURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// create Transport
|
|
tr, err := httputils.Transport(createSnapshotURL, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
hc := &http.Client{Transport: tr}
|
|
|
|
resp, err := hc.Get(u.String())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", fmt.Errorf("unexpected status code: %d; expecting %d; response body: %q", resp.StatusCode, http.StatusOK, body)
|
|
}
|
|
|
|
snap := snapshot{}
|
|
err = json.Unmarshal(body, &snap)
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot parse JSON response: %w; response body: %q", err, body)
|
|
}
|
|
|
|
if snap.Status == "ok" {
|
|
logger.Infof("Snapshot %s created", snap.Snapshot)
|
|
return snap.Snapshot, nil
|
|
}
|
|
if snap.Status == "error" {
|
|
return "", errors.New(snap.Msg)
|
|
}
|
|
return "", fmt.Errorf("unknown status: %v", snap.Status)
|
|
}
|
|
|
|
// Delete deletes a snapshot via the provided api endpoint
|
|
func Delete(deleteSnapshotURL string, snapshotName string) error {
|
|
logger.Infof("Deleting snapshot %s", snapshotName)
|
|
formData := url.Values{
|
|
"snapshot": {snapshotName},
|
|
}
|
|
u, err := url.Parse(deleteSnapshotURL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// create Transport
|
|
tr, err := httputils.Transport(deleteSnapshotURL, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
hc := &http.Client{Transport: tr}
|
|
resp, err := hc.PostForm(u.String(), formData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("unexpected status code: %d; expecting %d; response body: %q", resp.StatusCode, http.StatusOK, body)
|
|
}
|
|
|
|
snap := snapshot{}
|
|
err = json.Unmarshal(body, &snap)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse JSON response: %w; response body: %q", err, body)
|
|
}
|
|
|
|
if snap.Status == "ok" {
|
|
logger.Infof("Snapshot %s deleted", snapshotName)
|
|
return nil
|
|
}
|
|
if snap.Status == "error" {
|
|
return errors.New(snap.Msg)
|
|
}
|
|
return fmt.Errorf("unknown status: %v", snap.Status)
|
|
}
|