| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | package swift | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 	"github.com/restic/restic/internal/backend" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/debug" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/errors" | 
					
						
							| 
									
										
										
										
											2017-07-24 17:42:25 +02:00
										 |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	"github.com/ncw/swift" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const connLimit = 10 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // beSwift is a backend which stores the data on a swift endpoint. | 
					
						
							|  |  |  | type beSwift struct { | 
					
						
							|  |  |  | 	conn      *swift.Connection | 
					
						
							| 
									
										
										
										
											2017-06-06 00:33:25 +02:00
										 |  |  | 	sem       *backend.Semaphore | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	container string // Container name | 
					
						
							|  |  |  | 	prefix    string // Prefix of object names in the container | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	backend.Layout | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | // ensure statically that *beSwift implements restic.Backend. | 
					
						
							|  |  |  | var _ restic.Backend = &beSwift{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | // Open opens the swift backend at a container in region. The container is | 
					
						
							|  |  |  | // created if it does not exist yet. | 
					
						
							|  |  |  | func Open(cfg Config) (restic.Backend, error) { | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	debug.Log("config %#v", cfg) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 00:33:25 +02:00
										 |  |  | 	sem, err := backend.NewSemaphore(cfg.Connections) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	be := &beSwift{ | 
					
						
							|  |  |  | 		conn: &swift.Connection{ | 
					
						
							|  |  |  | 			UserName:       cfg.UserName, | 
					
						
							|  |  |  | 			Domain:         cfg.Domain, | 
					
						
							|  |  |  | 			ApiKey:         cfg.APIKey, | 
					
						
							|  |  |  | 			AuthUrl:        cfg.AuthURL, | 
					
						
							|  |  |  | 			Region:         cfg.Region, | 
					
						
							|  |  |  | 			Tenant:         cfg.Tenant, | 
					
						
							|  |  |  | 			TenantId:       cfg.TenantID, | 
					
						
							|  |  |  | 			TenantDomain:   cfg.TenantDomain, | 
					
						
							|  |  |  | 			TrustId:        cfg.TrustID, | 
					
						
							|  |  |  | 			StorageUrl:     cfg.StorageURL, | 
					
						
							|  |  |  | 			AuthToken:      cfg.AuthToken, | 
					
						
							|  |  |  | 			ConnectTimeout: time.Minute, | 
					
						
							|  |  |  | 			Timeout:        time.Minute, | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			Transport: backend.Transport(), | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-06-06 00:33:25 +02:00
										 |  |  | 		sem:       sem, | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 		container: cfg.Container, | 
					
						
							|  |  |  | 		prefix:    cfg.Prefix, | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 		Layout: &backend.DefaultLayout{ | 
					
						
							|  |  |  | 			Path: cfg.Prefix, | 
					
						
							|  |  |  | 			Join: path.Join, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Authenticate if needed | 
					
						
							|  |  |  | 	if !be.conn.Authenticated() { | 
					
						
							|  |  |  | 		if err := be.conn.Authenticate(); err != nil { | 
					
						
							|  |  |  | 			return nil, errors.Wrap(err, "conn.Authenticate") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ensure container exists | 
					
						
							|  |  |  | 	switch _, _, err := be.conn.Container(be.container); err { | 
					
						
							|  |  |  | 	case nil: | 
					
						
							|  |  |  | 		// Container exists | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case swift.ContainerNotFound: | 
					
						
							|  |  |  | 		err = be.createContainer(cfg.DefaultContainerPolicy) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, errors.Wrap(err, "beSwift.createContainer") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return nil, errors.Wrap(err, "conn.Container") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	return be, nil | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (be *beSwift) createContainer(policy string) error { | 
					
						
							|  |  |  | 	var h swift.Headers | 
					
						
							|  |  |  | 	if policy != "" { | 
					
						
							|  |  |  | 		h = swift.Headers{ | 
					
						
							|  |  |  | 			"X-Storage-Policy": policy, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return be.conn.ContainerCreate(be.container, h) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Location returns this backend's location (the container name). | 
					
						
							|  |  |  | func (be *beSwift) Location() string { | 
					
						
							|  |  |  | 	return be.container | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Load returns a reader that yields the contents of the file at h at the | 
					
						
							|  |  |  | // given offset. If length is nonzero, only a portion of the file is | 
					
						
							|  |  |  | // returned. rd must be closed after use. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) Load(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) { | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	debug.Log("Load %v, length %v, offset %v", h, length, offset) | 
					
						
							|  |  |  | 	if err := h.Valid(); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if offset < 0 { | 
					
						
							|  |  |  | 		return nil, errors.New("offset is negative") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if length < 0 { | 
					
						
							|  |  |  | 		return nil, errors.Errorf("invalid length %d", length) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	objName := be.Filename(h) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 00:33:25 +02:00
										 |  |  | 	be.sem.GetToken() | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	defer func() { | 
					
						
							| 
									
										
										
										
											2017-06-06 00:33:25 +02:00
										 |  |  | 		be.sem.ReleaseToken() | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	headers := swift.Headers{} | 
					
						
							|  |  |  | 	if offset > 0 { | 
					
						
							|  |  |  | 		headers["Range"] = fmt.Sprintf("bytes=%d-", offset) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	if length > 0 { | 
					
						
							|  |  |  | 		headers["Range"] = fmt.Sprintf("bytes=%d-%d", offset, offset+int64(length)-1) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	if _, ok := headers["Range"]; ok { | 
					
						
							|  |  |  | 		debug.Log("Load(%v) send range %v", h, headers["Range"]) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	obj, _, err := be.conn.ObjectOpen(be.container, objName, false, headers) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 		debug.Log("  err %v", err) | 
					
						
							|  |  |  | 		return nil, errors.Wrap(err, "conn.ObjectOpen") | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	return obj, nil | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Save stores data in the backend at the handle. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) Save(ctx context.Context, h restic.Handle, rd io.Reader) (err error) { | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	if err = h.Valid(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	objName := be.Filename(h) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	debug.Log("Save %v at %v", h, objName) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check key does not already exist | 
					
						
							|  |  |  | 	switch _, _, err = be.conn.Object(be.container, objName); err { | 
					
						
							|  |  |  | 	case nil: | 
					
						
							|  |  |  | 		debug.Log("%v already exists", h) | 
					
						
							|  |  |  | 		return errors.New("key already exists") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case swift.ObjectNotFound: | 
					
						
							|  |  |  | 		// Ok, that's what we want | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return errors.Wrap(err, "conn.Object") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 00:33:25 +02:00
										 |  |  | 	be.sem.GetToken() | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	defer func() { | 
					
						
							| 
									
										
										
										
											2017-06-06 00:33:25 +02:00
										 |  |  | 		be.sem.ReleaseToken() | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encoding := "binary/octet-stream" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	debug.Log("PutObject(%v, %v, %v)", be.container, objName, encoding) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	_, err = be.conn.ObjectPut(be.container, objName, rd, true, "", encoding, nil) | 
					
						
							|  |  |  | 	debug.Log("%v, err %#v", objName, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return errors.Wrap(err, "client.PutObject") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stat returns information about a blob. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) Stat(ctx context.Context, h restic.Handle) (bi restic.FileInfo, err error) { | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	debug.Log("%v", h) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	objName := be.Filename(h) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	obj, _, err := be.conn.Object(be.container, objName) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		debug.Log("Object() err %v", err) | 
					
						
							|  |  |  | 		return restic.FileInfo{}, errors.Wrap(err, "conn.Object") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return restic.FileInfo{Size: obj.Bytes}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Test returns true if a blob of the given type and name exists in the backend. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) Test(ctx context.Context, h restic.Handle) (bool, error) { | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	objName := be.Filename(h) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	switch _, _, err := be.conn.Object(be.container, objName); err { | 
					
						
							|  |  |  | 	case nil: | 
					
						
							|  |  |  | 		return true, nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case swift.ObjectNotFound: | 
					
						
							|  |  |  | 		return false, nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return false, errors.Wrap(err, "conn.Object") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Remove removes the blob with the given name and type. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) Remove(ctx context.Context, h restic.Handle) error { | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	objName := be.Filename(h) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	err := be.conn.ObjectDelete(be.container, objName) | 
					
						
							|  |  |  | 	debug.Log("Remove(%v) -> err %v", h, err) | 
					
						
							|  |  |  | 	return errors.Wrap(err, "conn.ObjectDelete") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // List returns a channel that yields all names of blobs of type t. A | 
					
						
							|  |  |  | // goroutine is started for this. If the channel done is closed, sending | 
					
						
							|  |  |  | // stops. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) List(ctx context.Context, t restic.FileType) <-chan string { | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	debug.Log("listing %v", t) | 
					
						
							|  |  |  | 	ch := make(chan string) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	prefix := be.Filename(restic.Handle{Type: t}) + "/" | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer close(ch) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 		err := be.conn.ObjectsWalk(be.container, &swift.ObjectsOpts{Prefix: prefix}, | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 			func(opts *swift.ObjectsOpts) (interface{}, error) { | 
					
						
							|  |  |  | 				newObjects, err := be.conn.ObjectNames(be.container, opts) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return nil, errors.Wrap(err, "conn.ObjectNames") | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for _, obj := range newObjects { | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 					m := filepath.Base(strings.TrimPrefix(obj, prefix)) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 					if m == "" { | 
					
						
							|  |  |  | 						continue | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					select { | 
					
						
							|  |  |  | 					case ch <- m: | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | 					case <-ctx.Done(): | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 						return nil, io.EOF | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return newObjects, nil | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			debug.Log("ObjectsWalk returned error: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ch | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Remove keys for a specified backend type. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) removeKeys(ctx context.Context, t restic.FileType) error { | 
					
						
							|  |  |  | 	for key := range be.List(ctx, t) { | 
					
						
							|  |  |  | 		err := be.Remove(ctx, restic.Handle{Type: t, Name: key}) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | // IsNotExist returns true if the error is caused by a not existing file. | 
					
						
							|  |  |  | func (be *beSwift) IsNotExist(err error) bool { | 
					
						
							|  |  |  | 	if e, ok := errors.Cause(err).(*swift.Error); ok { | 
					
						
							|  |  |  | 		return e.StatusCode == http.StatusNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | // Delete removes all restic objects in the container. | 
					
						
							|  |  |  | // It will not remove the container itself. | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | func (be *beSwift) Delete(ctx context.Context) error { | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 	alltypes := []restic.FileType{ | 
					
						
							|  |  |  | 		restic.DataFile, | 
					
						
							|  |  |  | 		restic.KeyFile, | 
					
						
							|  |  |  | 		restic.LockFile, | 
					
						
							|  |  |  | 		restic.SnapshotFile, | 
					
						
							|  |  |  | 		restic.IndexFile} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, t := range alltypes { | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | 		err := be.removeKeys(ctx, t) | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-03 17:39:57 +02:00
										 |  |  | 	err := be.Remove(ctx, restic.Handle{Type: restic.ConfigFile}) | 
					
						
							| 
									
										
										
										
											2017-05-01 10:13:03 +02:00
										 |  |  | 	if err != nil && !be.IsNotExist(err) { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2017-03-29 23:58:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Close does nothing | 
					
						
							|  |  |  | func (be *beSwift) Close() error { return nil } |