diff --git a/cmd/backup/config.go b/cmd/backup/config.go index d6805f9..da7eecf 100644 --- a/cmd/backup/config.go +++ b/cmd/backup/config.go @@ -16,84 +16,74 @@ import ( // Config holds all configuration values that are expected to be set // by users. type Config struct { - AwsS3BucketName string `split_words:"true"` - AwsS3Path string `split_words:"true"` - AwsEndpoint string `split_words:"true" default:"s3.amazonaws.com"` - AwsEndpointProto string `split_words:"true" default:"https"` - AwsEndpointInsecure bool `split_words:"true"` - AwsEndpointCACert CertDecoder `envconfig:"AWS_ENDPOINT_CA_CERT"` - AwsStorageClass string `split_words:"true"` - AwsAccessKeyID string `envconfig:"AWS_ACCESS_KEY_ID"` - AwsAccessKeyIDFile string `envconfig:"AWS_ACCESS_KEY_ID_FILE"` - AwsSecretAccessKey string `split_words:"true"` - AwsSecretAccessKeyFile string `split_words:"true"` - AwsIamRoleEndpoint string `split_words:"true"` - AwsPartSize int64 `split_words:"true"` - BackupCompression CompressionType `split_words:"true" default:"gz"` - BackupSources string `split_words:"true" default:"/backup"` - BackupFilename string `split_words:"true" default:"backup-%Y-%m-%dT%H-%M-%S.{{ .Extension }}"` - BackupFilenameExpand bool `split_words:"true"` - BackupLatestSymlink string `split_words:"true"` - BackupArchive string `split_words:"true" default:"/archive"` - BackupRetentionDays int32 `split_words:"true" default:"-1"` - BackupPruningLeeway time.Duration `split_words:"true" default:"1m"` - BackupPruningPrefix string `split_words:"true"` - BackupStopContainerLabel string `split_words:"true" default:"true"` - BackupFromSnapshot bool `split_words:"true"` - BackupExcludeRegexp RegexpDecoder `split_words:"true"` - BackupSkipBackendsFromPrune []string `split_words:"true"` - GpgPassphrase string `split_words:"true"` - NotificationURLs []string `envconfig:"NOTIFICATION_URLS"` - NotificationLevel string `split_words:"true" default:"error"` - EmailNotificationRecipient string `split_words:"true"` - EmailNotificationSender string `split_words:"true" default:"noreply@nohost"` - EmailSMTPHost string `envconfig:"EMAIL_SMTP_HOST"` - EmailSMTPPort int `envconfig:"EMAIL_SMTP_PORT" default:"587"` - EmailSMTPUsername string `envconfig:"EMAIL_SMTP_USERNAME"` - EmailSMTPPassword string `envconfig:"EMAIL_SMTP_PASSWORD"` - WebdavUrl string `split_words:"true"` - WebdavUrlInsecure bool `split_words:"true"` - WebdavPath string `split_words:"true" default:"/"` - WebdavUsername string `split_words:"true"` - WebdavPassword string `split_words:"true"` - SSHHostName string `split_words:"true"` - SSHPort string `split_words:"true" default:"22"` - SSHUser string `split_words:"true"` - SSHPassword string `split_words:"true"` - SSHIdentityFile string `split_words:"true" default:"/root/.ssh/id_rsa"` - SSHIdentityPassphrase string `split_words:"true"` - SSHRemotePath string `split_words:"true"` - ExecLabel string `split_words:"true"` - ExecForwardOutput bool `split_words:"true"` - LockTimeout time.Duration `split_words:"true" default:"60m"` - AzureStorageAccountName string `split_words:"true"` - AzureStoragePrimaryAccountKey string `split_words:"true"` - AzureStorageContainerName string `split_words:"true"` - AzureStoragePath string `split_words:"true"` - AzureStorageEndpoint string `split_words:"true" default:"https://{{ .AccountName }}.blob.core.windows.net/"` - DropboxEndpoint string `split_words:"true" default:"https://api.dropbox.com/"` - DropboxOAuth2Endpoint string `envconfig:"DROPBOX_OAUTH2_ENDPOINT" default:"https://api.dropbox.com/"` - DropboxRefreshToken string `split_words:"true"` - DropboxAppKey string `split_words:"true"` - DropboxAppSecret string `split_words:"true"` - DropboxRemotePath string `split_words:"true"` - DropboxConcurrencyLevel NaturalNumber `split_words:"true" default:"6"` -} - -func (c *Config) resolveSecret(envVar string, secretPath string) (string, error) { - if secretPath == "" { - return envVar, nil - } - data, err := os.ReadFile(secretPath) - if err != nil { - return "", fmt.Errorf("resolveSecret: error reading secret path: %w", err) - } - return string(data), nil + AwsS3BucketName string `env:"AWS_S3_BUCKET_NAME"` + AwsS3Path string `env:"AWS_S3_PATH"` + AwsEndpoint string `envDefault:"s3.amazonaws.com"` + AwsEndpointProto string `envDefault:"https"` + AwsEndpointInsecure bool + AwsEndpointCACert CertDecoder `env:"AWS_ENDPOINT_CA_CERT"` + AwsStorageClass string + AwsAccessKeyID string `env:"AWS_ACCESS_KEY_ID"` + AwsAccessKeyIDFile string `env:"AWS_ACCESS_KEY_ID_FILE,file"` + AwsSecretAccessKey string + AwsSecretAccessKeyFile string `env:"AWS_SECRET_ACCESS_KEY_FILE,file"` + AwsIamRoleEndpoint string + AwsPartSize int64 + BackupCompression CompressionType `envDefault:"gz"` + BackupSources string `envDefault:"/backup"` + BackupFilename string `envDefault:"backup-%Y-%m-%dT%H-%M-%S.{{ .Extension }}"` + BackupFilenameExpand bool + BackupLatestSymlink string + BackupArchive string `envDefault:"/archive"` + BackupRetentionDays int32 `envDefault:"-1"` + BackupPruningLeeway time.Duration `envDefault:"1m"` + BackupPruningPrefix string + BackupStopContainerLabel string `envDefault:"true"` + BackupFromSnapshot bool + BackupExcludeRegexp RegexpDecoder + BackupSkipBackendsFromPrune []string + GpgPassphrase string + NotificationURLs []string `env:"NOTIFICATION_URLS"` + NotificationLevel string `envDefault:"error"` + EmailNotificationRecipient string + EmailNotificationSender string `envDefault:"noreply@nohost"` + EmailSMTPHost string `env:"EMAIL_SMTP_HOST"` + EmailSMTPPort int `env:"EMAIL_SMTP_PORT" envDefault:"587"` + EmailSMTPUsername string `env:"EMAIL_SMTP_USERNAME"` + EmailSMTPPassword string `env:"EMAIL_SMTP_PASSWORD"` + WebdavUrl string + WebdavUrlInsecure bool + WebdavPath string `envDefault:"/"` + WebdavUsername string + WebdavPassword string + SSHHostName string `env:"SSH_HOST_NAME"` + SSHPort string `env:"SSH_PORT" envDefault:"22"` + SSHUser string `env:"SSH_USER"` + SSHPassword string `env:"SSH_PASSWORD"` + SSHIdentityFile string `env:"SSH_IDENTITY_FILE" envDefault:"/root/.ssh/id_rsa"` + SSHIdentityPassphrase string `env:"SSH_IDENTITY_PASSPHRASE"` + SSHRemotePath string `env:"SSH_REMOTE_PATH"` + ExecLabel string + ExecForwardOutput bool + LockTimeout time.Duration `envDefault:"60m"` + AzureStorageAccountName string + AzureStoragePrimaryAccountKey string + AzureStorageContainerName string + AzureStoragePath string + AzureStorageEndpoint string `envDefault:"https://{{ .AccountName }}.blob.core.windows.net/"` + DropboxEndpoint string `envDefault:"https://api.dropbox.com/"` + DropboxOAuth2Endpoint string `env:"DROPBOX_OAUTH2_ENDPOINT" envDefault:"https://api.dropbox.com/"` + DropboxRefreshToken string + DropboxAppKey string + DropboxAppSecret string + DropboxRemotePath string + DropboxConcurrencyLevel NaturalNumber `envDefault:"6"` } type CompressionType string -func (c *CompressionType) Decode(v string) error { +func (c *CompressionType) UnmarshalText(text []byte) error { + v := string(text) switch v { case "gz", "zst": *c = CompressionType(v) @@ -111,7 +101,8 @@ type CertDecoder struct { Cert *x509.Certificate } -func (c *CertDecoder) Decode(v string) error { +func (c *CertDecoder) UnmarshalText(text []byte) error { + v := string(text) if v == "" { return nil } @@ -132,7 +123,8 @@ type RegexpDecoder struct { Re *regexp.Regexp } -func (r *RegexpDecoder) Decode(v string) error { +func (r *RegexpDecoder) UnmarshalText(text []byte) error { + v := string(text) if v == "" { return nil } @@ -146,7 +138,8 @@ func (r *RegexpDecoder) Decode(v string) error { type NaturalNumber int -func (n *NaturalNumber) Decode(v string) error { +func (n *NaturalNumber) UnmarshalText(text []byte) error { + v := string(text) asInt, err := strconv.Atoi(v) if err != nil { return fmt.Errorf("config: error converting %s to int", v) diff --git a/cmd/backup/script.go b/cmd/backup/script.go index 83f135a..ef31ce9 100644 --- a/cmd/backup/script.go +++ b/cmd/backup/script.go @@ -140,14 +140,21 @@ func newScript() (*script, error) { } if s.c.AwsS3BucketName != "" { - accessKeyID, err := s.c.resolveSecret(s.c.AwsAccessKeyID, s.c.AwsAccessKeyIDFile) - if err != nil { - return nil, fmt.Errorf("newScript: error resolving AwsAccessKeyID: %w", err) + var accessKeyID string + var secretAccessKey string + + if s.c.AwsAccessKeyIDFile != "" { + accessKeyID = s.c.AwsAccessKeyIDFile + } else { + accessKeyID = s.c.AwsAccessKeyID } - secretAccessKey, err := s.c.resolveSecret(s.c.AwsSecretAccessKey, s.c.AwsSecretAccessKeyFile) - if err != nil { - return nil, fmt.Errorf("newScript: error resolving AwsSecretAccessKey: %w", err) + + if s.c.AwsSecretAccessKeyFile != "" { + secretAccessKey = s.c.AwsSecretAccessKeyFile + } else { + secretAccessKey = s.c.AwsSecretAccessKey } + s3Config := s3.Config{ Endpoint: s.c.AwsEndpoint, AccessKeyID: accessKeyID,