github.com/pachyderm/pachyderm@v1.13.4/src/server/pfs/s3/object.go (about) 1 package s3 2 3 import ( 4 "fmt" 5 "io" 6 "net/http" 7 "strings" 8 9 "github.com/gogo/protobuf/types" 10 pfsServer "github.com/pachyderm/pachyderm/src/server/pfs" 11 "github.com/pachyderm/pachyderm/src/server/pkg/errutil" 12 "github.com/pachyderm/s2" 13 ) 14 15 func (c *controller) GetObject(r *http.Request, bucketName, file, version string) (*s2.GetObjectResult, error) { 16 c.logger.Debugf("GetObject: bucketName=%+v, file=%+v, version=%+v", bucketName, file, version) 17 18 pc, err := c.requestClient(r) 19 if err != nil { 20 return nil, err 21 } 22 23 if strings.HasSuffix(file, "/") { 24 return nil, invalidFilePathError(r) 25 } 26 27 bucket, err := c.driver.bucket(pc, r, bucketName) 28 if err != nil { 29 return nil, err 30 } 31 bucketCaps, err := c.driver.bucketCapabilities(pc, r, bucket) 32 if err != nil { 33 return nil, err 34 } 35 if !bucketCaps.readable { 36 return nil, s2.NoSuchKeyError(r) 37 } 38 39 if bucketCaps.historicVersions && version != "" { 40 commitInfo, err := pc.InspectCommit(bucket.Repo, version) 41 if err != nil { 42 return nil, maybeNotFoundError(r, err) 43 } 44 if commitInfo.Branch.Name != bucket.Commit { 45 return nil, s2.NoSuchVersionError(r) 46 } 47 bucket.Commit = commitInfo.Commit.ID 48 } 49 50 fileInfo, err := pc.InspectFile(bucket.Repo, bucket.Commit, file) 51 if err != nil { 52 return nil, maybeNotFoundError(r, err) 53 } 54 55 modTime, err := types.TimestampFromProto(fileInfo.Committed) 56 if err != nil { 57 return nil, err 58 } 59 60 content, err := pc.GetFileReadSeeker(bucket.Repo, bucket.Commit, file) 61 if err != nil { 62 return nil, err 63 } 64 65 result := s2.GetObjectResult{ 66 ModTime: modTime, 67 Content: content, 68 ETag: fmt.Sprintf("%x", fileInfo.Hash), 69 Version: bucket.Commit, 70 DeleteMarker: false, 71 } 72 73 return &result, nil 74 } 75 76 func (c *controller) CopyObject(r *http.Request, srcBucketName, srcFile string, srcObj *s2.GetObjectResult, destBucketName, destFile string) (string, error) { 77 c.logger.Tracef("CopyObject: srcBucketName=%+v, srcFile=%+v, srcObj=%+v, destBucketName=%+v, destFile=%+v", srcBucketName, srcFile, srcObj, destBucketName, destFile) 78 79 pc, err := c.requestClient(r) 80 if err != nil { 81 return "", err 82 } 83 84 if strings.HasSuffix(destFile, "/") { 85 return "", invalidFilePathError(r) 86 } 87 88 srcBucket, err := c.driver.bucket(pc, r, srcBucketName) 89 if err != nil { 90 return "", err 91 } 92 // srcBucket capabilities were already verified, since s2 will call 93 // `GetObject` under the hood before calling `CopyObject` 94 95 destBucket, err := c.driver.bucket(pc, r, destBucketName) 96 if err != nil { 97 return "", err 98 } 99 destBucketCaps, err := c.driver.bucketCapabilities(pc, r, destBucket) 100 if err != nil { 101 return "", err 102 } 103 if !destBucketCaps.writable { 104 return "", s2.NotImplementedError(r) 105 } 106 107 if err = pc.CopyFile(srcBucket.Repo, srcBucket.Commit, srcFile, destBucket.Repo, destBucket.Commit, destFile, true); err != nil { 108 if errutil.IsWriteToOutputBranchError(err) { 109 return "", writeToOutputBranchError(r) 110 } else if errutil.IsNotADirectoryError(err) { 111 return "", invalidFileParentError(r) 112 } else if errutil.IsInvalidPathError(err) { 113 return "", invalidFilePathError(r) 114 } 115 return "", err 116 } 117 118 fileInfo, err := pc.InspectFile(destBucket.Repo, destBucket.Commit, destFile) 119 if err != nil && !pfsServer.IsOutputCommitNotFinishedErr(err) { 120 return "", err 121 } 122 var version string 123 if fileInfo != nil { 124 version = fileInfo.File.Commit.ID 125 } 126 127 return version, nil 128 } 129 130 func (c *controller) PutObject(r *http.Request, bucketName, file string, reader io.Reader) (*s2.PutObjectResult, error) { 131 c.logger.Debugf("PutObject: bucketName=%+v, file=%+v", bucketName, file) 132 133 pc, err := c.requestClient(r) 134 if err != nil { 135 return nil, err 136 } 137 138 if strings.HasSuffix(file, "/") { 139 return nil, invalidFilePathError(r) 140 } 141 142 bucket, err := c.driver.bucket(pc, r, bucketName) 143 if err != nil { 144 return nil, err 145 } 146 bucketCaps, err := c.driver.bucketCapabilities(pc, r, bucket) 147 if err != nil { 148 return nil, err 149 } 150 if !bucketCaps.writable { 151 return nil, s2.NotImplementedError(r) 152 } 153 154 _, err = pc.PutFileOverwrite(bucket.Repo, bucket.Commit, file, reader, 0) 155 if err != nil { 156 if errutil.IsWriteToOutputBranchError(err) { 157 return nil, writeToOutputBranchError(r) 158 } else if errutil.IsNotADirectoryError(err) { 159 return nil, invalidFileParentError(r) 160 } else if errutil.IsInvalidPathError(err) { 161 return nil, invalidFilePathError(r) 162 } 163 return nil, err 164 } 165 166 fileInfo, err := pc.InspectFile(bucket.Repo, bucket.Commit, file) 167 if err != nil && !pfsServer.IsOutputCommitNotFinishedErr(err) { 168 return nil, err 169 } 170 171 result := s2.PutObjectResult{} 172 if fileInfo != nil { 173 result.ETag = fmt.Sprintf("%x", fileInfo.Hash) 174 result.Version = fileInfo.File.Commit.ID 175 } 176 177 return &result, nil 178 } 179 180 func (c *controller) DeleteObject(r *http.Request, bucketName, file, version string) (*s2.DeleteObjectResult, error) { 181 c.logger.Debugf("DeleteObject: bucketName=%+v, file=%+v, version=%+v", bucketName, file, version) 182 183 pc, err := c.requestClient(r) 184 if err != nil { 185 return nil, err 186 } 187 188 if strings.HasSuffix(file, "/") { 189 return nil, invalidFilePathError(r) 190 } 191 if version != "" { 192 return nil, s2.NotImplementedError(r) 193 } 194 195 bucket, err := c.driver.bucket(pc, r, bucketName) 196 if err != nil { 197 return nil, err 198 } 199 bucketCaps, err := c.driver.bucketCapabilities(pc, r, bucket) 200 if err != nil { 201 return nil, err 202 } 203 if !bucketCaps.writable { 204 return nil, s2.NotImplementedError(r) 205 } 206 207 if err = pc.DeleteFile(bucket.Repo, bucket.Commit, file); err != nil { 208 if errutil.IsWriteToOutputBranchError(err) { 209 return nil, writeToOutputBranchError(r) 210 } 211 return nil, maybeNotFoundError(r, err) 212 } 213 214 result := s2.DeleteObjectResult{ 215 Version: "", 216 DeleteMarker: false, 217 } 218 219 return &result, nil 220 }