[ARVADOS] created: 1.3.0-2944-g7556d0ea3

Git user git at public.arvados.org
Thu Aug 20 20:24:56 UTC 2020


        at  7556d0ea3265a898d0170bf32bab82e8d9920dde (commit)


commit 7556d0ea3265a898d0170bf32bab82e8d9920dde
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Thu Aug 20 16:24:19 2020 -0400

    16535: Add S3 DeleteObject API.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/services/keep-web/s3.go b/services/keep-web/s3.go
index 12e294d93..01bc8b704 100644
--- a/services/keep-web/s3.go
+++ b/services/keep-web/s3.go
@@ -205,6 +205,54 @@ func (h *handler) serveS3(w http.ResponseWriter, r *http.Request) bool {
 		}
 		w.WriteHeader(http.StatusOK)
 		return true
+	case r.Method == http.MethodDelete:
+		if !objectNameGiven || r.URL.Path == "/" {
+			http.Error(w, "missing object name in DELETE request", http.StatusBadRequest)
+			return true
+		}
+		fspath := "by_id" + r.URL.Path
+		if strings.HasSuffix(fspath, "/") {
+			fspath = strings.TrimSuffix(fspath, "/")
+			fi, err := fs.Stat(fspath)
+			if os.IsNotExist(err) {
+				w.WriteHeader(http.StatusNoContent)
+				return true
+			} else if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return true
+			} else if !fi.IsDir() {
+				// if "foo" exists and is a file, then
+				// "foo/" doesn't exist, so we say
+				// delete was successful.
+				w.WriteHeader(http.StatusNoContent)
+				return true
+			}
+		} else if fi, err := fs.Stat(fspath); err == nil && fi.IsDir() {
+			// if "foo" is a dir, it is visible via S3
+			// only as "foo/", not "foo" -- so we leave
+			// the dir alone and return 204 to indicate
+			// that "foo" does not exist.
+			w.WriteHeader(http.StatusNoContent)
+			return true
+		}
+		err = fs.Remove(fspath)
+		if os.IsNotExist(err) {
+			w.WriteHeader(http.StatusNoContent)
+			return true
+		}
+		if err != nil {
+			err = fmt.Errorf("rm failed: %w", err)
+			http.Error(w, err.Error(), http.StatusBadRequest)
+			return true
+		}
+		err = fs.Sync()
+		if err != nil {
+			err = fmt.Errorf("sync failed: %w", err)
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return true
+		}
+		w.WriteHeader(http.StatusNoContent)
+		return true
 	default:
 		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
 		return true
diff --git a/services/keep-web/s3_test.go b/services/keep-web/s3_test.go
index 73553ff4d..85921f84d 100644
--- a/services/keep-web/s3_test.go
+++ b/services/keep-web/s3_test.go
@@ -260,6 +260,43 @@ func (s *IntegrationSuite) TestS3ProjectPutObjectNotSupported(c *check.C) {
 	}
 }
 
+func (s *IntegrationSuite) TestS3CollectionDeleteObject(c *check.C) {
+	stage := s.s3setup(c)
+	defer stage.teardown(c)
+	s.testS3DeleteObject(c, stage.collbucket, "")
+}
+func (s *IntegrationSuite) TestS3ProjectDeleteObject(c *check.C) {
+	stage := s.s3setup(c)
+	defer stage.teardown(c)
+	s.testS3DeleteObject(c, stage.projbucket, stage.coll.Name+"/")
+}
+func (s *IntegrationSuite) testS3DeleteObject(c *check.C, bucket *s3.Bucket, prefix string) {
+	s.testServer.Config.cluster.Collections.S3FolderObjects = true
+	for _, trial := range []struct {
+		path string
+	}{
+		{"/"},
+		{"nonexistentfile"},
+		{"emptyfile"},
+		{"sailboat.txt"},
+		{"sailboat.txt/"},
+		{"emptydir"},
+		{"emptydir/"},
+	} {
+		objname := prefix + trial.path
+		comment := check.Commentf("objname %q", objname)
+
+		err := bucket.Del(objname)
+		if trial.path == "/" {
+			c.Check(err, check.NotNil)
+			continue
+		}
+		c.Check(err, check.IsNil, comment)
+		_, err = bucket.GetReader(objname)
+		c.Check(err, check.NotNil, comment)
+	}
+}
+
 func (s *IntegrationSuite) TestS3CollectionPutObjectFailure(c *check.C) {
 	stage := s.s3setup(c)
 	defer stage.teardown(c)

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list