mirror of https://github.com/kubernetes/kops.git
150 lines
3.4 KiB
Go
150 lines
3.4 KiB
Go
package fi
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
"github.com/aws/aws-sdk-go/service/s3"
|
|
"github.com/golang/glog"
|
|
"k8s.io/kube-deploy/upup/pkg/fi/utils"
|
|
"k8s.io/kube-deploy/upup/pkg/fi/vfs"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type StateStore interface {
|
|
// VFSPath returns the path where the StateStore is stored
|
|
VFSPath() vfs.Path
|
|
|
|
CA() CAStore
|
|
Secrets() SecretStore
|
|
|
|
ReadConfig(config interface{}) error
|
|
WriteConfig(config interface{}) error
|
|
}
|
|
|
|
type VFSStateStore struct {
|
|
location vfs.Path
|
|
ca CAStore
|
|
secrets SecretStore
|
|
}
|
|
|
|
var _ StateStore = &VFSStateStore{}
|
|
|
|
func NewVFSStateStore(location vfs.Path, dryrun bool) (*VFSStateStore, error) {
|
|
s := &VFSStateStore{
|
|
location: location,
|
|
}
|
|
var err error
|
|
s.ca, err = NewVFSCAStore(location.Join("pki"), dryrun)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error building CA store: %v", err)
|
|
}
|
|
s.secrets, err = NewVFSSecretStore(location.Join("secrets"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error building secret store: %v", err)
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func (s *VFSStateStore) CA() CAStore {
|
|
return s.ca
|
|
}
|
|
|
|
func (s *VFSStateStore) VFSPath() vfs.Path {
|
|
return s.location
|
|
}
|
|
|
|
func (s *VFSStateStore) Secrets() SecretStore {
|
|
return s.secrets
|
|
}
|
|
|
|
func (s *VFSStateStore) ReadConfig(config interface{}) error {
|
|
configPath := s.location.Join("config")
|
|
data, err := configPath.ReadFile()
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("error reading configuration file %s: %v", configPath, err)
|
|
}
|
|
|
|
// Yaml can't parse empty strings
|
|
configString := string(data)
|
|
configString = strings.TrimSpace(configString)
|
|
|
|
if configString != "" {
|
|
err = utils.YamlUnmarshal([]byte(configString), config)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing configuration: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *VFSStateStore) WriteConfig(config interface{}) error {
|
|
configPath := s.location.Join("config")
|
|
|
|
data, err := utils.YamlMarshal(config)
|
|
if err != nil {
|
|
return fmt.Errorf("error marshalling configuration: %v", err)
|
|
}
|
|
|
|
err = configPath.WriteFile(data)
|
|
if err != nil {
|
|
return fmt.Errorf("error writing configuration file %s: %v", configPath, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func BuildVfsPath(p string) (vfs.Path, error) {
|
|
if strings.HasPrefix(p, "s3://") {
|
|
u, err := url.Parse(p)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid s3 path: %q", err)
|
|
}
|
|
|
|
var region string
|
|
{
|
|
config := aws.NewConfig().WithRegion("us-east-1")
|
|
session := session.New()
|
|
s3Client := s3.New(session, config)
|
|
|
|
bucket := strings.TrimSuffix(u.Host, "/")
|
|
request := &s3.GetBucketLocationInput{}
|
|
request.Bucket = aws.String(bucket)
|
|
|
|
response, err := s3Client.GetBucketLocation(request)
|
|
if err != nil {
|
|
// TODO: Auto-create bucket?
|
|
return nil, fmt.Errorf("error getting location for S3 bucket %q: %v", bucket, err)
|
|
}
|
|
if response.LocationConstraint == nil {
|
|
// US Classic does not return a region
|
|
region = "us-east-1"
|
|
} else {
|
|
region = *response.LocationConstraint
|
|
// Another special case: "EU" can mean eu-west-1
|
|
if region == "EU" {
|
|
region = "eu-west-1"
|
|
}
|
|
}
|
|
glog.V(2).Infof("Found bucket %q in region %q", bucket, region)
|
|
}
|
|
|
|
{
|
|
config := aws.NewConfig().WithRegion(region)
|
|
session := session.New()
|
|
s3Client := s3.New(session, config)
|
|
|
|
s3path := vfs.NewS3Path(s3Client, u.Host, u.Path)
|
|
return s3path, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("unknown / unhandled path type: %q", p)
|
|
}
|