mirror of
				https://github.com/restic/restic.git
				synced 2025-11-03 23:00:59 +00:00 
			
		
		
		
	backend: add standardized Config.ApplyEnvironment
This removes the backend specific special cases while parsing the configuration in `global.go`.
This commit is contained in:
		
							parent
							
								
									f903db492c
								
							
						
					
					
						commit
						32a6b66267
					
				
					 8 changed files with 68 additions and 144 deletions
				
			
		| 
						 | 
				
			
			@ -535,112 +535,21 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func parseConfig(loc location.Location, opts options.Options) (interface{}, error) {
 | 
			
		||||
	cfg := loc.Config
 | 
			
		||||
	if cfg, ok := cfg.(restic.ApplyEnvironmenter); ok {
 | 
			
		||||
		if err := cfg.ApplyEnvironment(""); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// only apply options for a particular backend here
 | 
			
		||||
	opts = opts.Extract(loc.Scheme)
 | 
			
		||||
 | 
			
		||||
	switch loc.Scheme {
 | 
			
		||||
	case "local":
 | 
			
		||||
		cfg := loc.Config.(*local.Config)
 | 
			
		||||
	if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening local repository at %#v", cfg)
 | 
			
		||||
	debug.Log("opening %v repository at %#v", loc.Scheme, cfg)
 | 
			
		||||
	return cfg, nil
 | 
			
		||||
 | 
			
		||||
	case "sftp":
 | 
			
		||||
		cfg := loc.Config.(*sftp.Config)
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening sftp repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
 | 
			
		||||
	case "s3":
 | 
			
		||||
		cfg := loc.Config.(*s3.Config)
 | 
			
		||||
 | 
			
		||||
		if err := s3.ApplyEnvironment(cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening s3 repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
 | 
			
		||||
	case "gs":
 | 
			
		||||
		cfg := loc.Config.(*gs.Config)
 | 
			
		||||
 | 
			
		||||
		if err := gs.ApplyEnvironment(cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening gs repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
 | 
			
		||||
	case "azure":
 | 
			
		||||
		cfg := loc.Config.(*azure.Config)
 | 
			
		||||
 | 
			
		||||
		if err := azure.ApplyEnvironment(cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening gs repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
 | 
			
		||||
	case "swift":
 | 
			
		||||
		cfg := loc.Config.(*swift.Config)
 | 
			
		||||
 | 
			
		||||
		if err := swift.ApplyEnvironment("", cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening swift repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
 | 
			
		||||
	case "b2":
 | 
			
		||||
		cfg := loc.Config.(*b2.Config)
 | 
			
		||||
 | 
			
		||||
		if err := b2.ApplyEnvironment(cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening b2 repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
	case "rest":
 | 
			
		||||
		cfg := loc.Config.(*rest.Config)
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening rest repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
	case "rclone":
 | 
			
		||||
		cfg := loc.Config.(*rclone.Config)
 | 
			
		||||
		if err := opts.Apply(loc.Scheme, cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug.Log("opening rest repository at %#v", cfg)
 | 
			
		||||
		return cfg, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.Fatalf("invalid backend: %q", loc.Scheme)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Open the backend specified by a location config.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import (
 | 
			
		|||
 | 
			
		||||
	"github.com/restic/restic/internal/errors"
 | 
			
		||||
	"github.com/restic/restic/internal/options"
 | 
			
		||||
	"github.com/restic/restic/internal/restic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config contains all configuration necessary to connect to an azure compatible
 | 
			
		||||
| 
						 | 
				
			
			@ -55,19 +56,20 @@ func ParseConfig(s string) (*Config, error) {
 | 
			
		|||
	return &cfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ restic.ApplyEnvironmenter = &Config{}
 | 
			
		||||
 | 
			
		||||
// ApplyEnvironment saves values from the environment to the config.
 | 
			
		||||
func ApplyEnvironment(cfgRaw interface{}) error {
 | 
			
		||||
	cfg := cfgRaw.(*Config)
 | 
			
		||||
func (cfg *Config) ApplyEnvironment(prefix string) error {
 | 
			
		||||
	if cfg.AccountName == "" {
 | 
			
		||||
		cfg.AccountName = os.Getenv("AZURE_ACCOUNT_NAME")
 | 
			
		||||
		cfg.AccountName = os.Getenv(prefix + "AZURE_ACCOUNT_NAME")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.AccountKey.String() == "" {
 | 
			
		||||
		cfg.AccountKey = options.NewSecretString(os.Getenv("AZURE_ACCOUNT_KEY"))
 | 
			
		||||
		cfg.AccountKey = options.NewSecretString(os.Getenv(prefix + "AZURE_ACCOUNT_KEY"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.AccountSAS.String() == "" {
 | 
			
		||||
		cfg.AccountSAS = options.NewSecretString(os.Getenv("AZURE_ACCOUNT_SAS"))
 | 
			
		||||
		cfg.AccountSAS = options.NewSecretString(os.Getenv(prefix + "AZURE_ACCOUNT_SAS"))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import (
 | 
			
		|||
 | 
			
		||||
	"github.com/restic/restic/internal/errors"
 | 
			
		||||
	"github.com/restic/restic/internal/options"
 | 
			
		||||
	"github.com/restic/restic/internal/restic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config contains all configuration necessary to connect to an b2 compatible
 | 
			
		||||
| 
						 | 
				
			
			@ -81,11 +82,12 @@ func ParseConfig(s string) (*Config, error) {
 | 
			
		|||
	return &cfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ restic.ApplyEnvironmenter = &Config{}
 | 
			
		||||
 | 
			
		||||
// ApplyEnvironment saves values from the environment to the config.
 | 
			
		||||
func ApplyEnvironment(cfgRaw interface{}) error {
 | 
			
		||||
	cfg := cfgRaw.(*Config)
 | 
			
		||||
func (cfg *Config) ApplyEnvironment(prefix string) error {
 | 
			
		||||
	if cfg.AccountID == "" {
 | 
			
		||||
		cfg.AccountID = os.Getenv("B2_ACCOUNT_ID")
 | 
			
		||||
		cfg.AccountID = os.Getenv(prefix + "B2_ACCOUNT_ID")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.AccountID == "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +95,7 @@ func ApplyEnvironment(cfgRaw interface{}) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.Key.String() == "" {
 | 
			
		||||
		cfg.Key = options.NewSecretString(os.Getenv("B2_ACCOUNT_KEY"))
 | 
			
		||||
		cfg.Key = options.NewSecretString(os.Getenv(prefix + "B2_ACCOUNT_KEY"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.Key.String() == "" {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import (
 | 
			
		|||
 | 
			
		||||
	"github.com/restic/restic/internal/errors"
 | 
			
		||||
	"github.com/restic/restic/internal/options"
 | 
			
		||||
	"github.com/restic/restic/internal/restic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config contains all configuration necessary to connect to a Google Cloud Storage
 | 
			
		||||
| 
						 | 
				
			
			@ -58,11 +59,12 @@ func ParseConfig(s string) (*Config, error) {
 | 
			
		|||
	return &cfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ restic.ApplyEnvironmenter = &Config{}
 | 
			
		||||
 | 
			
		||||
// ApplyEnvironment saves values from the environment to the config.
 | 
			
		||||
func ApplyEnvironment(cfgRaw interface{}) error {
 | 
			
		||||
	cfg := cfgRaw.(*Config)
 | 
			
		||||
func (cfg *Config) ApplyEnvironment(prefix string) error {
 | 
			
		||||
	if cfg.ProjectID == "" {
 | 
			
		||||
		cfg.ProjectID = os.Getenv("GOOGLE_PROJECT_ID")
 | 
			
		||||
		cfg.ProjectID = os.Getenv(prefix + "GOOGLE_PROJECT_ID")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import (
 | 
			
		|||
 | 
			
		||||
	"github.com/restic/restic/internal/errors"
 | 
			
		||||
	"github.com/restic/restic/internal/options"
 | 
			
		||||
	"github.com/restic/restic/internal/restic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config contains all configuration necessary to connect to an s3 compatible
 | 
			
		||||
| 
						 | 
				
			
			@ -93,15 +94,16 @@ func createConfig(endpoint, bucket, prefix string, useHTTP bool) (*Config, error
 | 
			
		|||
	return &cfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ restic.ApplyEnvironmenter = &Config{}
 | 
			
		||||
 | 
			
		||||
// ApplyEnvironment saves values from the environment to the config.
 | 
			
		||||
func ApplyEnvironment(cfgRaw interface{}) error {
 | 
			
		||||
	cfg := cfgRaw.(*Config)
 | 
			
		||||
func (cfg *Config) ApplyEnvironment(prefix string) error {
 | 
			
		||||
	if cfg.KeyID == "" {
 | 
			
		||||
		cfg.KeyID = os.Getenv("AWS_ACCESS_KEY_ID")
 | 
			
		||||
		cfg.KeyID = os.Getenv(prefix + "AWS_ACCESS_KEY_ID")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.Secret.String() == "" {
 | 
			
		||||
		cfg.Secret = options.NewSecretString(os.Getenv("AWS_SECRET_ACCESS_KEY"))
 | 
			
		||||
		cfg.Secret = options.NewSecretString(os.Getenv(prefix + "AWS_SECRET_ACCESS_KEY"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.KeyID == "" && cfg.Secret.String() != "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +113,7 @@ func ApplyEnvironment(cfgRaw interface{}) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.Region == "" {
 | 
			
		||||
		cfg.Region = os.Getenv("AWS_DEFAULT_REGION")
 | 
			
		||||
		cfg.Region = os.Getenv(prefix + "AWS_DEFAULT_REGION")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import (
 | 
			
		|||
 | 
			
		||||
	"github.com/restic/restic/internal/errors"
 | 
			
		||||
	"github.com/restic/restic/internal/options"
 | 
			
		||||
	"github.com/restic/restic/internal/restic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config contains basic configuration needed to specify swift location for a swift server
 | 
			
		||||
| 
						 | 
				
			
			@ -73,45 +74,46 @@ func ParseConfig(s string) (*Config, error) {
 | 
			
		|||
	return &cfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ restic.ApplyEnvironmenter = &Config{}
 | 
			
		||||
 | 
			
		||||
// ApplyEnvironment saves values from the environment to the config.
 | 
			
		||||
func ApplyEnvironment(prefix string, cfg interface{}) error {
 | 
			
		||||
	c := cfg.(*Config)
 | 
			
		||||
func (cfg *Config) ApplyEnvironment(prefix string) error {
 | 
			
		||||
	for _, val := range []struct {
 | 
			
		||||
		s   *string
 | 
			
		||||
		env string
 | 
			
		||||
	}{
 | 
			
		||||
		// v2/v3 specific
 | 
			
		||||
		{&c.UserName, prefix + "OS_USERNAME"},
 | 
			
		||||
		{&c.APIKey, prefix + "OS_PASSWORD"},
 | 
			
		||||
		{&c.Region, prefix + "OS_REGION_NAME"},
 | 
			
		||||
		{&c.AuthURL, prefix + "OS_AUTH_URL"},
 | 
			
		||||
		{&cfg.UserName, prefix + "OS_USERNAME"},
 | 
			
		||||
		{&cfg.APIKey, prefix + "OS_PASSWORD"},
 | 
			
		||||
		{&cfg.Region, prefix + "OS_REGION_NAME"},
 | 
			
		||||
		{&cfg.AuthURL, prefix + "OS_AUTH_URL"},
 | 
			
		||||
 | 
			
		||||
		// v3 specific
 | 
			
		||||
		{&c.UserID, prefix + "OS_USER_ID"},
 | 
			
		||||
		{&c.Domain, prefix + "OS_USER_DOMAIN_NAME"},
 | 
			
		||||
		{&c.DomainID, prefix + "OS_USER_DOMAIN_ID"},
 | 
			
		||||
		{&c.Tenant, prefix + "OS_PROJECT_NAME"},
 | 
			
		||||
		{&c.TenantDomain, prefix + "OS_PROJECT_DOMAIN_NAME"},
 | 
			
		||||
		{&c.TenantDomainID, prefix + "OS_PROJECT_DOMAIN_ID"},
 | 
			
		||||
		{&c.TrustID, prefix + "OS_TRUST_ID"},
 | 
			
		||||
		{&cfg.UserID, prefix + "OS_USER_ID"},
 | 
			
		||||
		{&cfg.Domain, prefix + "OS_USER_DOMAIN_NAME"},
 | 
			
		||||
		{&cfg.DomainID, prefix + "OS_USER_DOMAIN_ID"},
 | 
			
		||||
		{&cfg.Tenant, prefix + "OS_PROJECT_NAME"},
 | 
			
		||||
		{&cfg.TenantDomain, prefix + "OS_PROJECT_DOMAIN_NAME"},
 | 
			
		||||
		{&cfg.TenantDomainID, prefix + "OS_PROJECT_DOMAIN_ID"},
 | 
			
		||||
		{&cfg.TrustID, prefix + "OS_TRUST_ID"},
 | 
			
		||||
 | 
			
		||||
		// v2 specific
 | 
			
		||||
		{&c.TenantID, prefix + "OS_TENANT_ID"},
 | 
			
		||||
		{&c.Tenant, prefix + "OS_TENANT_NAME"},
 | 
			
		||||
		{&cfg.TenantID, prefix + "OS_TENANT_ID"},
 | 
			
		||||
		{&cfg.Tenant, prefix + "OS_TENANT_NAME"},
 | 
			
		||||
 | 
			
		||||
		// v1 specific
 | 
			
		||||
		{&c.AuthURL, prefix + "ST_AUTH"},
 | 
			
		||||
		{&c.UserName, prefix + "ST_USER"},
 | 
			
		||||
		{&c.APIKey, prefix + "ST_KEY"},
 | 
			
		||||
		{&cfg.AuthURL, prefix + "ST_AUTH"},
 | 
			
		||||
		{&cfg.UserName, prefix + "ST_USER"},
 | 
			
		||||
		{&cfg.APIKey, prefix + "ST_KEY"},
 | 
			
		||||
 | 
			
		||||
		// Application Credential auth
 | 
			
		||||
		{&c.ApplicationCredentialID, prefix + "OS_APPLICATION_CREDENTIAL_ID"},
 | 
			
		||||
		{&c.ApplicationCredentialName, prefix + "OS_APPLICATION_CREDENTIAL_NAME"},
 | 
			
		||||
		{&cfg.ApplicationCredentialID, prefix + "OS_APPLICATION_CREDENTIAL_ID"},
 | 
			
		||||
		{&cfg.ApplicationCredentialName, prefix + "OS_APPLICATION_CREDENTIAL_NAME"},
 | 
			
		||||
 | 
			
		||||
		// Manual authentication
 | 
			
		||||
		{&c.StorageURL, prefix + "OS_STORAGE_URL"},
 | 
			
		||||
		{&cfg.StorageURL, prefix + "OS_STORAGE_URL"},
 | 
			
		||||
 | 
			
		||||
		{&c.DefaultContainerPolicy, prefix + "SWIFT_DEFAULT_CONTAINER_POLICY"},
 | 
			
		||||
		{&cfg.DefaultContainerPolicy, prefix + "SWIFT_DEFAULT_CONTAINER_POLICY"},
 | 
			
		||||
	} {
 | 
			
		||||
		if *val.s == "" {
 | 
			
		||||
			*val.s = os.Getenv(val.env)
 | 
			
		||||
| 
						 | 
				
			
			@ -121,8 +123,8 @@ func ApplyEnvironment(prefix string, cfg interface{}) error {
 | 
			
		|||
		s   *options.SecretString
 | 
			
		||||
		env string
 | 
			
		||||
	}{
 | 
			
		||||
		{&c.ApplicationCredentialSecret, prefix + "OS_APPLICATION_CREDENTIAL_SECRET"},
 | 
			
		||||
		{&c.AuthToken, prefix + "OS_AUTH_TOKEN"},
 | 
			
		||||
		{&cfg.ApplicationCredentialSecret, prefix + "OS_APPLICATION_CREDENTIAL_SECRET"},
 | 
			
		||||
		{&cfg.AuthToken, prefix + "OS_AUTH_TOKEN"},
 | 
			
		||||
	} {
 | 
			
		||||
		if val.s.String() == "" {
 | 
			
		||||
			*val.s = options.NewSecretString(os.Getenv(val.env))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ func newSwiftTestSuite(t testing.TB) *test.Suite[swift.Config] {
 | 
			
		|||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err = swift.ApplyEnvironment("RESTIC_TEST_", &cfg); err != nil {
 | 
			
		||||
			if err = cfg.ApplyEnvironment("RESTIC_TEST_"); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			cfg.Prefix += fmt.Sprintf("/test-%d", time.Now().UnixNano())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,3 +80,8 @@ type FileInfo struct {
 | 
			
		|||
	Size int64
 | 
			
		||||
	Name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplyEnvironmenter fills in a backend configuration from the environment
 | 
			
		||||
type ApplyEnvironmenter interface {
 | 
			
		||||
	ApplyEnvironment(prefix string) error
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue