mirror of https://github.com/kubernetes/kops.git
Merge pull request #14843 from justinsb/vfs_openstack_swift_context
VFS: Add context to internals of Openstack Swift client
This commit is contained in:
commit
61fd1289cd
|
|
@ -438,6 +438,23 @@ func (c *VFSContext) getGCSClient(ctx context.Context) (*storage.Service, error)
|
||||||
return gcsClient, nil
|
return gcsClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getSwiftClient returns the openstack switch client, caching it for future calls
|
||||||
|
func (c *VFSContext) getSwiftClient(ctx context.Context) (*gophercloud.ServiceClient, error) {
|
||||||
|
c.mutex.Lock()
|
||||||
|
defer c.mutex.Unlock()
|
||||||
|
|
||||||
|
if c.swiftClient != nil {
|
||||||
|
return c.swiftClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
swiftClient, err := NewSwiftClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.swiftClient = swiftClient
|
||||||
|
return swiftClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *VFSContext) buildOpenstackSwiftPath(p string) (*SwiftPath, error) {
|
func (c *VFSContext) buildOpenstackSwiftPath(p string) (*SwiftPath, error) {
|
||||||
u, err := url.Parse(p)
|
u, err := url.Parse(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -453,15 +470,7 @@ func (c *VFSContext) buildOpenstackSwiftPath(p string) (*SwiftPath, error) {
|
||||||
return nil, fmt.Errorf("invalid swift path: %q", p)
|
return nil, fmt.Errorf("invalid swift path: %q", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.swiftClient == nil {
|
return NewSwiftPath(c, bucket, u.Path)
|
||||||
swiftClient, err := NewSwiftClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.swiftClient = swiftClient
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewSwiftPath(c.swiftClient, bucket, u.Path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *VFSContext) buildAzureBlobPath(p string) (*AzureBlobPath, error) {
|
func (c *VFSContext) buildAzureBlobPath(p string) (*AzureBlobPath, error) {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -42,7 +43,7 @@ import (
|
||||||
"k8s.io/kops/util/pkg/hashing"
|
"k8s.io/kops/util/pkg/hashing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewSwiftClient() (*gophercloud.ServiceClient, error) {
|
func NewSwiftClient(ctx context.Context) (*gophercloud.ServiceClient, error) {
|
||||||
config := OpenstackConfig{}
|
config := OpenstackConfig{}
|
||||||
|
|
||||||
// Check if env credentials are valid first
|
// Check if env credentials are valid first
|
||||||
|
|
@ -226,10 +227,10 @@ func (oc OpenstackConfig) GetServiceConfig(name string) (gophercloud.EndpointOpt
|
||||||
|
|
||||||
// SwiftPath is a vfs path for Openstack Cloud Storage.
|
// SwiftPath is a vfs path for Openstack Cloud Storage.
|
||||||
type SwiftPath struct {
|
type SwiftPath struct {
|
||||||
client *gophercloud.ServiceClient
|
vfsContext *VFSContext
|
||||||
bucket string
|
bucket string
|
||||||
key string
|
key string
|
||||||
hash string
|
hash string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -253,14 +254,14 @@ var swiftWriteBackoff = wait.Backoff{
|
||||||
Steps: 5,
|
Steps: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSwiftPath(client *gophercloud.ServiceClient, bucket string, key string) (*SwiftPath, error) {
|
func NewSwiftPath(vfsContext *VFSContext, bucket string, key string) (*SwiftPath, error) {
|
||||||
bucket = strings.TrimSuffix(bucket, "/")
|
bucket = strings.TrimSuffix(bucket, "/")
|
||||||
key = strings.TrimPrefix(key, "/")
|
key = strings.TrimPrefix(key, "/")
|
||||||
|
|
||||||
return &SwiftPath{
|
return &SwiftPath{
|
||||||
client: client,
|
vfsContext: vfsContext,
|
||||||
bucket: bucket,
|
bucket: bucket,
|
||||||
key: key,
|
key: key,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,11 +277,20 @@ func (p *SwiftPath) String() string {
|
||||||
return p.Path()
|
return p.Path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *SwiftPath) getClient(ctx context.Context) (*gophercloud.ServiceClient, error) {
|
||||||
|
return p.vfsContext.getSwiftClient(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *SwiftPath) Remove() error {
|
func (p *SwiftPath) Remove() error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
done, err := RetryWithBackoff(swiftWriteBackoff, func() (bool, error) {
|
done, err := RetryWithBackoff(swiftWriteBackoff, func() (bool, error) {
|
||||||
opt := swiftobject.DeleteOpts{}
|
client, err := p.getClient(ctx)
|
||||||
_, err := swiftobject.Delete(p.client, p.bucket, p.key, opt).Extract()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
opt := swiftobject.DeleteOpts{}
|
||||||
|
if _, err := swiftobject.Delete(client, p.bucket, p.key, opt).Extract(); err != nil {
|
||||||
if isSwiftNotFound(err) {
|
if isSwiftNotFound(err) {
|
||||||
return true, os.ErrNotExist
|
return true, os.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
@ -307,22 +317,28 @@ func (p *SwiftPath) Join(relativePath ...string) Path {
|
||||||
args = append(args, relativePath...)
|
args = append(args, relativePath...)
|
||||||
joined := path.Join(args...)
|
joined := path.Join(args...)
|
||||||
return &SwiftPath{
|
return &SwiftPath{
|
||||||
client: p.client,
|
vfsContext: p.vfsContext,
|
||||||
bucket: p.bucket,
|
bucket: p.bucket,
|
||||||
key: joined,
|
key: joined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SwiftPath) WriteFile(data io.ReadSeeker, acl ACL) error {
|
func (p *SwiftPath) WriteFile(data io.ReadSeeker, acl ACL) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
done, err := RetryWithBackoff(swiftWriteBackoff, func() (bool, error) {
|
done, err := RetryWithBackoff(swiftWriteBackoff, func() (bool, error) {
|
||||||
|
client, err := p.getClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
klog.V(4).Infof("Writing file %q", p)
|
klog.V(4).Infof("Writing file %q", p)
|
||||||
if _, err := data.Seek(0, 0); err != nil {
|
if _, err := data.Seek(0, 0); err != nil {
|
||||||
return false, fmt.Errorf("error seeking to start of data stream for %s: %v", p, err)
|
return false, fmt.Errorf("error seeking to start of data stream for %s: %v", p, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
createOpts := swiftobject.CreateOpts{Content: data}
|
createOpts := swiftobject.CreateOpts{Content: data}
|
||||||
_, err := swiftobject.Create(p.client, p.bucket, p.key, createOpts).Extract()
|
if _, err := swiftobject.Create(client, p.bucket, p.key, createOpts).Extract(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("error writing %s: %v", p, err)
|
return false, fmt.Errorf("error writing %s: %v", p, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,14 +361,21 @@ func (p *SwiftPath) WriteFile(data io.ReadSeeker, acl ACL) error {
|
||||||
var createFileLockSwift sync.Mutex
|
var createFileLockSwift sync.Mutex
|
||||||
|
|
||||||
func (p *SwiftPath) CreateFile(data io.ReadSeeker, acl ACL) error {
|
func (p *SwiftPath) CreateFile(data io.ReadSeeker, acl ACL) error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
client, err := p.getClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
createFileLockSwift.Lock()
|
createFileLockSwift.Lock()
|
||||||
defer createFileLockSwift.Unlock()
|
defer createFileLockSwift.Unlock()
|
||||||
|
|
||||||
// Check if exists.
|
// Check if exists.
|
||||||
_, err := RetryWithBackoff(swiftReadBackoff, func() (bool, error) {
|
if _, err := RetryWithBackoff(swiftReadBackoff, func() (bool, error) {
|
||||||
klog.V(4).Infof("Getting file %q", p)
|
klog.V(4).Infof("Getting file %q", p)
|
||||||
|
|
||||||
_, err := swiftobject.Get(p.client, p.bucket, p.key, swiftobject.GetOpts{}).Extract()
|
_, err := swiftobject.Get(client, p.bucket, p.key, swiftobject.GetOpts{}).Extract()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return true, nil
|
return true, nil
|
||||||
} else if isSwiftNotFound(err) {
|
} else if isSwiftNotFound(err) {
|
||||||
|
|
@ -360,8 +383,7 @@ func (p *SwiftPath) CreateFile(data io.ReadSeeker, acl ACL) error {
|
||||||
} else {
|
} else {
|
||||||
return false, fmt.Errorf("error getting %s: %v", p, err)
|
return false, fmt.Errorf("error getting %s: %v", p, err)
|
||||||
}
|
}
|
||||||
})
|
}); err == nil {
|
||||||
if err == nil {
|
|
||||||
return os.ErrExist
|
return os.ErrExist
|
||||||
} else if !os.IsNotExist(err) {
|
} else if !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
|
|
@ -376,14 +398,20 @@ func (p *SwiftPath) CreateFile(data io.ReadSeeker, acl ACL) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SwiftPath) createBucket() error {
|
func (p *SwiftPath) createBucket() error {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
done, err := RetryWithBackoff(swiftWriteBackoff, func() (bool, error) {
|
done, err := RetryWithBackoff(swiftWriteBackoff, func() (bool, error) {
|
||||||
_, err := swiftcontainer.Get(p.client, p.bucket, swiftcontainer.GetOpts{}).Extract()
|
client, err := p.getClient(ctx)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := swiftcontainer.Get(client, p.bucket, swiftcontainer.GetOpts{}).Extract(); err == nil {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
if isSwiftNotFound(err) {
|
if isSwiftNotFound(err) {
|
||||||
createOpts := swiftcontainer.CreateOpts{}
|
createOpts := swiftcontainer.CreateOpts{}
|
||||||
_, err = swiftcontainer.Create(p.client, p.bucket, createOpts).Extract()
|
_, err = swiftcontainer.Create(client, p.bucket, createOpts).Extract()
|
||||||
return err == nil, err
|
return err == nil, err
|
||||||
}
|
}
|
||||||
return false, err
|
return false, err
|
||||||
|
|
@ -426,10 +454,17 @@ func (p *SwiftPath) ReadFile() ([]byte, error) {
|
||||||
|
|
||||||
// WriteTo implements io.WriterTo
|
// WriteTo implements io.WriterTo
|
||||||
func (p *SwiftPath) WriteTo(out io.Writer) (int64, error) {
|
func (p *SwiftPath) WriteTo(out io.Writer) (int64, error) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
klog.V(4).Infof("Reading file %q", p)
|
klog.V(4).Infof("Reading file %q", p)
|
||||||
|
|
||||||
|
client, err := p.getClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
opt := swiftobject.DownloadOpts{}
|
opt := swiftobject.DownloadOpts{}
|
||||||
result := swiftobject.Download(p.client, p.bucket, p.key, opt)
|
result := swiftobject.Download(client, p.bucket, p.key, opt)
|
||||||
if result.Err != nil {
|
if result.Err != nil {
|
||||||
if isSwiftNotFound(result.Err) {
|
if isSwiftNotFound(result.Err) {
|
||||||
return 0, os.ErrNotExist
|
return 0, os.ErrNotExist
|
||||||
|
|
@ -442,28 +477,34 @@ func (p *SwiftPath) WriteTo(out io.Writer) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SwiftPath) readPath(opt swiftobject.ListOpts) ([]Path, error) {
|
func (p *SwiftPath) readPath(opt swiftobject.ListOpts) ([]Path, error) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
var ret []Path
|
var ret []Path
|
||||||
done, err := RetryWithBackoff(swiftReadBackoff, func() (bool, error) {
|
done, err := RetryWithBackoff(swiftReadBackoff, func() (bool, error) {
|
||||||
|
client, err := p.getClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
var paths []Path
|
var paths []Path
|
||||||
pager := swiftobject.List(p.client, p.bucket, opt)
|
pager := swiftobject.List(client, p.bucket, opt)
|
||||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
if err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||||
objects, err1 := swiftobject.ExtractInfo(page)
|
objects, err1 := swiftobject.ExtractInfo(page)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return false, err1
|
return false, err1
|
||||||
}
|
}
|
||||||
for _, o := range objects {
|
for _, o := range objects {
|
||||||
child := &SwiftPath{
|
child := &SwiftPath{
|
||||||
client: p.client,
|
vfsContext: p.vfsContext,
|
||||||
bucket: p.bucket,
|
bucket: p.bucket,
|
||||||
key: o.Name,
|
key: o.Name,
|
||||||
hash: o.Hash,
|
hash: o.Hash,
|
||||||
}
|
}
|
||||||
paths = append(paths, child)
|
paths = append(paths, child)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
})
|
}); err != nil {
|
||||||
if err != nil {
|
|
||||||
if isSwiftNotFound(err) {
|
if isSwiftNotFound(err) {
|
||||||
return true, os.ErrNotExist
|
return true, os.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue