From 000dec3c6f6e92ec20cb86d1375ec82d2f6062b3 Mon Sep 17 00:00:00 2001
From: Sylvain Baubeau <sbaubeau@redhat.com>
Date: Fri, 3 Jul 2015 12:29:54 +0200
Subject: [PATCH] Inline Swift errors handling

Signed-off-by: Sylvain Baubeau <sbaubeau@redhat.com>
---
 docs/storage/driver/swift/swift.go | 161 ++++++++++++++++++-----------
 1 file changed, 102 insertions(+), 59 deletions(-)

diff --git a/docs/storage/driver/swift/swift.go b/docs/storage/driver/swift/swift.go
index 4daf7ccc..e3c73982 100644
--- a/docs/storage/driver/swift/swift.go
+++ b/docs/storage/driver/swift/swift.go
@@ -192,17 +192,19 @@ func (d *driver) Name() string {
 // GetContent retrieves the content stored at "path" as a []byte.
 func (d *driver) GetContent(ctx context.Context, path string) ([]byte, error) {
 	content, err := d.Conn.ObjectGetBytes(d.Container, d.swiftPath(path))
-	if err != nil {
-		return nil, parseError(path, err)
+	if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+		return nil, storagedriver.PathNotFoundError{Path: path}
 	}
 	return content, nil
 }
 
 // PutContent stores the []byte content at a location designated by "path".
 func (d *driver) PutContent(ctx context.Context, path string, contents []byte) error {
-	err := d.Conn.ObjectPutBytes(d.Container, d.swiftPath(path),
-		contents, d.getContentType())
-	return parseError(path, err)
+	err := d.Conn.ObjectPutBytes(d.Container, d.swiftPath(path), contents, d.getContentType())
+	if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+		return storagedriver.PathNotFoundError{Path: path}
+	}
+	return err
 }
 
 // ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
@@ -212,16 +214,13 @@ func (d *driver) ReadStream(ctx context.Context, path string, offset int64) (io.
 	headers["Range"] = "bytes=" + strconv.FormatInt(offset, 10) + "-"
 
 	file, _, err := d.Conn.ObjectOpen(d.Container, d.swiftPath(path), false, headers)
-
-	if err != nil {
-		if swiftErr, ok := err.(*swift.Error); ok && swiftErr.StatusCode == http.StatusRequestedRangeNotSatisfiable {
-			return ioutil.NopCloser(bytes.NewReader(nil)), nil
-		}
-
-		return nil, parseError(path, err)
+	if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+		return nil, storagedriver.PathNotFoundError{Path: path}
 	}
-
-	return file, nil
+	if swiftErr, ok := err.(*swift.Error); ok && swiftErr.StatusCode == http.StatusRequestedRangeNotSatisfiable {
+		return ioutil.NopCloser(bytes.NewReader(nil)), nil
+	}
+	return file, err
 }
 
 // WriteStream stores the contents of the provided io.Reader at a
@@ -257,22 +256,23 @@ func (d *driver) WriteStream(ctx context.Context, path string, offset int64, rea
 
 	info, _, err := d.Conn.Object(d.Container, d.swiftPath(path))
 	if err != nil {
-		if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+		if err == swift.ObjectNotFound {
 			// Create a object manifest
 			manifest, err := d.createManifest(path)
 			if err != nil {
-				return 0, parseError(path, err)
+				return 0, err
 			}
 			manifest.Close()
+		} else if err == swift.ContainerNotFound {
+			return 0, storagedriver.PathNotFoundError{Path: path}
 		} else {
-			return 0, parseError(path, err)
+			return 0, err
 		}
 	} else {
 		// The manifest already exists. Get all the segments
 		currentLength = info.Bytes
-		segments, err = d.getAllSegments(path)
-		if err != nil {
-			return 0, parseError(path, err)
+		if segments, err = d.getAllSegments(path); err != nil {
+			return 0, err
 		}
 	}
 
@@ -290,9 +290,13 @@ func (d *driver) WriteStream(ctx context.Context, path string, offset int64, rea
 	if offset >= currentLength {
 		for offset-currentLength >= chunkSize {
 			// Insert a block a zero
-			d.Conn.ObjectPut(d.Container, getSegment(),
-				bytes.NewReader(zeroBuf), false, "",
-				d.getContentType(), nil)
+			_, err := d.Conn.ObjectPut(d.Container, getSegment(), bytes.NewReader(zeroBuf), false, "", d.getContentType(), nil)
+			if err != nil {
+				if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+					return 0, storagedriver.PathNotFoundError{Path: getSegment()}
+				}
+				return 0, err
+			}
 			currentLength += chunkSize
 			partNumber++
 		}
@@ -304,9 +308,11 @@ func (d *driver) WriteStream(ctx context.Context, path string, offset int64, rea
 		// data from the beginning of the segment to offset
 		file, _, err := d.Conn.ObjectOpen(d.Container, getSegment(), false, nil)
 		if err != nil {
-			return 0, parseError(getSegment(), err)
+			if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+				return 0, storagedriver.PathNotFoundError{Path: getSegment()}
+			}
+			return 0, err
 		}
-
 		defer file.Close()
 		paddingReader = file
 	}
@@ -321,12 +327,15 @@ func (d *driver) WriteStream(ctx context.Context, path string, offset int64, rea
 	writeSegment := func(segment string) (finished bool, bytesRead int64, err error) {
 		currentSegment, err := d.Conn.ObjectCreate(d.Container, segment, false, "", d.getContentType(), nil)
 		if err != nil {
-			return false, bytesRead, parseError(path, err)
+			if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+				return false, bytesRead, storagedriver.PathNotFoundError{Path: segment}
+			}
+			return false, bytesRead, err
 		}
 
 		n, err := io.Copy(currentSegment, multi)
 		if err != nil {
-			return false, bytesRead, parseError(path, err)
+			return false, bytesRead, err
 		}
 
 		if n > 0 {
@@ -342,17 +351,23 @@ func (d *driver) WriteStream(ctx context.Context, path string, offset int64, rea
 				headers["Range"] = "bytes=" + strconv.FormatInt(cursor+n, 10) + "-" + strconv.FormatInt(cursor+chunkSize, 10)
 				file, _, err := d.Conn.ObjectOpen(d.Container, d.swiftPath(path), false, headers)
 				if err != nil {
-					return false, bytesRead, parseError(path, err)
+					if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+						return false, bytesRead, storagedriver.PathNotFoundError{Path: path}
+					}
+					return false, bytesRead, err
 				}
 
 				_, copyErr := io.Copy(currentSegment, file)
 
 				if err := file.Close(); err != nil {
-					return false, bytesRead, parseError(path, err)
+					if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+						return false, bytesRead, storagedriver.PathNotFoundError{Path: path}
+					}
+					return false, bytesRead, err
 				}
 
 				if copyErr != nil {
-					return false, bytesRead, parseError(path, copyErr)
+					return false, bytesRead, copyErr
 				}
 			}
 
@@ -391,6 +406,9 @@ func (d *driver) Stat(ctx context.Context, path string) (storagedriver.FileInfo,
 
 	objects, err := d.Conn.ObjectsAll(d.Container, opts)
 	if err != nil {
+		if err == swift.ContainerNotFound {
+			return nil, storagedriver.PathNotFoundError{Path: path}
+		}
 		return nil, err
 	}
 
@@ -407,7 +425,10 @@ func (d *driver) Stat(ctx context.Context, path string) (storagedriver.FileInfo,
 			// so we need to do a second HEAD request
 			info, _, err := d.Conn.Object(d.Container, swiftPath)
 			if err != nil {
-				return nil, parseError(path, err)
+				if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+					return nil, storagedriver.PathNotFoundError{Path: path}
+				}
+				return nil, err
 			}
 			fi.IsDir = false
 			fi.Size = info.Bytes
@@ -438,19 +459,20 @@ func (d *driver) List(ctx context.Context, path string) ([]string, error) {
 		files = append(files, strings.TrimPrefix(strings.TrimSuffix(obj.Name, "/"), d.swiftPath("/")))
 	}
 
-	return files, parseError(path, err)
+	if err == swift.ContainerNotFound {
+		return files, storagedriver.PathNotFoundError{Path: path}
+	}
+	return files, err
 }
 
 // Move moves an object stored at sourcePath to destPath, removing the original
 // object.
 func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
-	err := d.Conn.ObjectMove(d.Container, d.swiftPath(sourcePath),
-		d.Container, d.swiftPath(destPath))
-	if err != nil {
-		return parseError(sourcePath, err)
+	err := d.Conn.ObjectMove(d.Container, d.swiftPath(sourcePath), d.Container, d.swiftPath(destPath))
+	if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+		return storagedriver.PathNotFoundError{Path: sourcePath}
 	}
-
-	return nil
+	return err
 }
 
 // Delete recursively deletes all objects stored at "path" and its subpaths.
@@ -461,7 +483,10 @@ func (d *driver) Delete(ctx context.Context, path string) error {
 
 	objects, err := d.Conn.ObjectsAll(d.Container, &opts)
 	if err != nil {
-		return parseError(path, err)
+		if err == swift.ContainerNotFound {
+			return storagedriver.PathNotFoundError{Path: path}
+		}
+		return err
 	}
 
 	if d.BulkDeleteSupport {
@@ -470,7 +495,10 @@ func (d *driver) Delete(ctx context.Context, path string) error {
 			filenames[i] = obj.Name
 		}
 		if _, err := d.Conn.BulkDelete(d.Container, filenames); err != swift.Forbidden {
-			return parseError(path, err)
+			if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+				return storagedriver.PathNotFoundError{Path: path}
+			}
+			return err
 		}
 	}
 
@@ -485,30 +513,46 @@ func (d *driver) Delete(ctx context.Context, path string) error {
 				segContainer := components[0]
 				segments, err := d.getAllSegments(components[1])
 				if err != nil {
-					return parseError(obj.Name, err)
+					return err
 				}
 
 				for _, s := range segments {
 					if err := d.Conn.ObjectDelete(segContainer, s.Name); err != nil {
-						return parseError(s.Name, err)
+						if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+							return storagedriver.PathNotFoundError{Path: s.Name}
+						}
+						return err
 					}
 				}
 			}
 		} else {
-			return parseError(obj.Name, err)
+			if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+				return storagedriver.PathNotFoundError{Path: obj.Name}
+			}
+			return err
 		}
 
 		if err := d.Conn.ObjectDelete(d.Container, obj.Name); err != nil {
-			return parseError(obj.Name, err)
+			if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+				return storagedriver.PathNotFoundError{Path: obj.Name}
+			}
+			return err
 		}
 	}
 
-	if _, err := d.Stat(ctx, path); err == nil {
-		return parseError(path, d.Conn.ObjectDelete(d.Container, d.swiftPath(path)))
-	} else if len(objects) == 0 {
+	_, _, err = d.Conn.Object(d.Container, d.swiftPath(path))
+	if err == nil {
+		if err := d.Conn.ObjectDelete(d.Container, d.swiftPath(path)); err != nil {
+			if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
+				return storagedriver.PathNotFoundError{Path: path}
+			}
+			return err
+		}
+	} else if err == swift.ObjectNotFound && len(objects) == 0 {
+		return storagedriver.PathNotFoundError{Path: path}
+	} else if err == swift.ContainerNotFound {
 		return storagedriver.PathNotFoundError{Path: path}
 	}
-
 	return nil
 }
 
@@ -531,14 +575,21 @@ func (d *driver) getContentType() string {
 }
 
 func (d *driver) getAllSegments(path string) ([]swift.Object, error) {
-	return d.Conn.ObjectsAll(d.Container, &swift.ObjectsOpts{Prefix: d.swiftSegmentPath(path)})
+	segments, err := d.Conn.ObjectsAll(d.Container, &swift.ObjectsOpts{Prefix: d.swiftSegmentPath(path)})
+	if err == swift.ContainerNotFound {
+		return nil, storagedriver.PathNotFoundError{Path: path}
+	}
+	return segments, err
 }
 
 func (d *driver) createManifest(path string) (*swift.ObjectCreateFile, error) {
 	headers := make(swift.Headers)
 	headers["X-Object-Manifest"] = d.Container + "/" + d.swiftSegmentPath(path)
-	return d.Conn.ObjectCreate(d.Container, d.swiftPath(path), false, "",
-		d.getContentType(), headers)
+	file, err := d.Conn.ObjectCreate(d.Container, d.swiftPath(path), false, "", d.getContentType(), headers)
+	if err == swift.ContainerNotFound {
+		return nil, storagedriver.PathNotFoundError{Path: path}
+	}
+	return file, err
 }
 
 func detectBulkDelete(authURL string) (bulkDelete bool) {
@@ -553,11 +604,3 @@ func detectBulkDelete(authURL string) (bulkDelete bool) {
 	}
 	return
 }
-
-func parseError(path string, err error) error {
-	if err == swift.ContainerNotFound || err == swift.ObjectNotFound {
-		return storagedriver.PathNotFoundError{Path: path}
-	}
-
-	return err
-}