-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split config and storage files to clarify structure
- Loading branch information
1 parent
61c37ab
commit 2c9b27e
Showing
15 changed files
with
276 additions
and
251 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package storage | ||
|
||
// Config is an interface of factory method for Storage | ||
type Config interface { | ||
// NewStorage returns a new instance of Storage. | ||
NewStorage() (Storage, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package local | ||
|
||
import "github.com/minamijoyo/tfmigrate/storage" | ||
|
||
// Config is a config for local storage. | ||
type Config struct { | ||
// Path to a migration history file. Relative to the current working directory. | ||
Path string `hcl:"path"` | ||
} | ||
|
||
// Config implements a storage.Config. | ||
var _ storage.Config = (*Config)(nil) | ||
|
||
// NewStorage returns a new instance of storage.Storage. | ||
func (c *Config) NewStorage() (storage.Storage, error) { | ||
s := NewStorage(c.Path) | ||
return s, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package local | ||
|
||
import "testing" | ||
|
||
func TestConfigNewStorage(t *testing.T) { | ||
cases := []struct { | ||
desc string | ||
config *Config | ||
ok bool | ||
}{ | ||
{ | ||
desc: "valid", | ||
config: &Config{ | ||
Path: "tmp/history.json", | ||
}, | ||
ok: true, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.desc, func(t *testing.T) { | ||
got, err := tc.config.NewStorage() | ||
if tc.ok && err != nil { | ||
t.Fatalf("unexpected err: %s", err) | ||
} | ||
if !tc.ok && err == nil { | ||
t.Fatalf("expected to return an error, but no error, got: %#v", got) | ||
} | ||
if tc.ok { | ||
_ = got.(*Storage) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package mock | ||
|
||
import "github.com/minamijoyo/tfmigrate/storage" | ||
|
||
// Config is a config for mock storage. | ||
type Config struct { | ||
// Data stores a serialized data for history. | ||
Data string `hcl:"data"` | ||
// WriteError is a flag to return an error on Write(). | ||
WriteError bool `hcl:"write_error"` | ||
// ReadError is a flag to return an error on Read(). | ||
ReadError bool `hcl:"read_error"` | ||
|
||
// A reference to an instance of mock storage for testing. | ||
s *Storage | ||
} | ||
|
||
// Config implements a storage.Config. | ||
var _ storage.Config = (*Config)(nil) | ||
|
||
// NewStorage returns a new instance of storage.Storage. | ||
func (c *Config) NewStorage() (storage.Storage, error) { | ||
s := NewStorage(c.Data, c.WriteError, c.ReadError) | ||
|
||
// store a reference for test assertion. | ||
c.s = s | ||
return s, nil | ||
} | ||
|
||
// StorageData returns a raw data in mock storage for testing. | ||
func (c *Config) StorageData() string { | ||
return c.s.data | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package mock | ||
|
||
import "testing" | ||
|
||
func TestConfigNewStorage(t *testing.T) { | ||
cases := []struct { | ||
desc string | ||
config *Config | ||
ok bool | ||
}{ | ||
{ | ||
desc: "valid", | ||
config: &Config{ | ||
Data: "foo", | ||
WriteError: true, | ||
ReadError: false, | ||
}, | ||
ok: true, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.desc, func(t *testing.T) { | ||
got, err := tc.config.NewStorage() | ||
if tc.ok && err != nil { | ||
t.Fatalf("unexpected err: %s", err) | ||
} | ||
if !tc.ok && err == nil { | ||
t.Fatalf("expected to return an error, but no error, got: %#v", got) | ||
} | ||
if tc.ok { | ||
_ = got.(*Storage) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package s3 | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/request" | ||
"github.com/aws/aws-sdk-go/service/s3" | ||
"github.com/aws/aws-sdk-go/service/s3/s3iface" | ||
awsbase "github.com/hashicorp/aws-sdk-go-base" | ||
) | ||
|
||
// Client is an abstraction layer for AWS S3 API. | ||
// It is intended to be replaced with a mock for testing. | ||
type Client interface { | ||
// PutObjectWithContext puts a file to S3. | ||
PutObjectWithContext(ctx aws.Context, input *s3.PutObjectInput, opts ...request.Option) (*s3.PutObjectOutput, error) | ||
// GetObjectWithContext gets a file from S3. | ||
GetObjectWithContext(ctx aws.Context, input *s3.GetObjectInput, opts ...request.Option) (*s3.GetObjectOutput, error) | ||
} | ||
|
||
// client is a real implementation of the Client. | ||
type client struct { | ||
s3api s3iface.S3API | ||
} | ||
|
||
// newClient returns a new instance of Client. | ||
func newClient(config *Config) (Client, error) { | ||
cfg := &awsbase.Config{ | ||
AccessKey: config.AccessKey, | ||
AssumeRoleARN: config.RoleARN, | ||
Profile: config.Profile, | ||
Region: config.Region, | ||
SecretKey: config.SecretKey, | ||
SkipCredsValidation: config.SkipCredentialsValidation, | ||
SkipMetadataApiCheck: config.SkipMetadataAPICheck, | ||
} | ||
|
||
sess, err := awsbase.GetSession(cfg) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to new s3 client: %s", err) | ||
} | ||
|
||
client := s3.New(sess.Copy(&aws.Config{ | ||
Endpoint: aws.String(config.Endpoint), | ||
S3ForcePathStyle: aws.Bool(config.ForcePathStyle), | ||
})) | ||
|
||
return client, nil | ||
} | ||
|
||
// PutObjectWithContext puts a file to S3. | ||
func (c *client) PutObjectWithContext(ctx aws.Context, input *s3.PutObjectInput, opts ...request.Option) (*s3.PutObjectOutput, error) { | ||
return c.s3api.PutObjectWithContext(ctx, input, opts...) | ||
} | ||
|
||
// GetObjectWithContext gets a file from S3. | ||
func (c *client) GetObjectWithContext(ctx aws.Context, input *s3.GetObjectInput, opts ...request.Option) (*s3.GetObjectOutput, error) { | ||
return c.s3api.GetObjectWithContext(ctx, input, opts...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package s3 | ||
|
||
import "github.com/minamijoyo/tfmigrate/storage" | ||
|
||
// Config is a config for s3 storage. | ||
// This is expected to have almost the same options as Terraform s3 backend. | ||
// https://www.terraform.io/docs/backends/types/s3.html | ||
// However, it has many minor options and it's a pain to test all options from | ||
// first, so we added only options we need for now. | ||
type Config struct { | ||
// Name of the bucket. | ||
Bucket string `hcl:"bucket"` | ||
// Path to the migration history file. | ||
Key string `hcl:"key"` | ||
|
||
// AWS region. | ||
Region string `hcl:"region,optional"` | ||
// Custom endpoint for the AWS S3 API. | ||
Endpoint string `hcl:"endpoint,optional"` | ||
// AWS access key. | ||
AccessKey string `hcl:"access_key,optional"` | ||
// AWS secret key. | ||
SecretKey string `hcl:"secret_key,optional"` | ||
// Name of AWS profile in AWS shared credentials file. | ||
Profile string `hcl:"profile,optional"` | ||
// Amazon Resource Name (ARN) of the IAM Role to assume. | ||
RoleARN string `hcl:"role_arn,optional"` | ||
// Skip credentials validation via the STS API. | ||
SkipCredentialsValidation bool `hcl:"skip_credentials_validation,optional"` | ||
// Skip usage of EC2 Metadata API. | ||
SkipMetadataAPICheck bool `hcl:"skip_metadata_api_check,optional"` | ||
// Enable path-style S3 URLs (https://<HOST>/<BUCKET> | ||
// instead of https://<BUCKET>.<HOST>). | ||
ForcePathStyle bool `hcl:"force_path_style,optional"` | ||
// SSE KMS Key Id for optional server-side encryption enablement | ||
KmsKeyID string `hcl:"kms_key_id,optional"` | ||
} | ||
|
||
// Config implements a storage.Config. | ||
var _ storage.Config = (*Config)(nil) | ||
|
||
// NewStorage returns a new instance of storage.Storage. | ||
func (c *Config) NewStorage() (storage.Storage, error) { | ||
return NewStorage(c, nil) | ||
} |
Oops, something went wrong.