api-put-bucket.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * Minio Go Library for Amazon S3 Compatible Cloud Storage
  3. * Copyright 2015-2017 Minio, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package minio
  18. import (
  19. "bytes"
  20. "context"
  21. "encoding/xml"
  22. "io/ioutil"
  23. "net/http"
  24. "net/url"
  25. "strings"
  26. "github.com/minio/minio-go/pkg/s3utils"
  27. )
  28. /// Bucket operations
  29. // MakeBucket creates a new bucket with bucketName.
  30. //
  31. // Location is an optional argument, by default all buckets are
  32. // created in US Standard Region.
  33. //
  34. // For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html
  35. // For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations
  36. func (c Client) MakeBucket(bucketName string, location string) (err error) {
  37. defer func() {
  38. // Save the location into cache on a successful makeBucket response.
  39. if err == nil {
  40. c.bucketLocCache.Set(bucketName, location)
  41. }
  42. }()
  43. // Validate the input arguments.
  44. if err := s3utils.CheckValidBucketNameStrict(bucketName); err != nil {
  45. return err
  46. }
  47. // If location is empty, treat is a default region 'us-east-1'.
  48. if location == "" {
  49. location = "us-east-1"
  50. // For custom region clients, default
  51. // to custom region instead not 'us-east-1'.
  52. if c.region != "" {
  53. location = c.region
  54. }
  55. }
  56. // PUT bucket request metadata.
  57. reqMetadata := requestMetadata{
  58. bucketName: bucketName,
  59. bucketLocation: location,
  60. }
  61. // If location is not 'us-east-1' create bucket location config.
  62. if location != "us-east-1" && location != "" {
  63. createBucketConfig := createBucketConfiguration{}
  64. createBucketConfig.Location = location
  65. var createBucketConfigBytes []byte
  66. createBucketConfigBytes, err = xml.Marshal(createBucketConfig)
  67. if err != nil {
  68. return err
  69. }
  70. reqMetadata.contentMD5Base64 = sumMD5Base64(createBucketConfigBytes)
  71. reqMetadata.contentSHA256Hex = sum256Hex(createBucketConfigBytes)
  72. reqMetadata.contentBody = bytes.NewReader(createBucketConfigBytes)
  73. reqMetadata.contentLength = int64(len(createBucketConfigBytes))
  74. }
  75. // Execute PUT to create a new bucket.
  76. resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
  77. defer closeResponse(resp)
  78. if err != nil {
  79. return err
  80. }
  81. if resp != nil {
  82. if resp.StatusCode != http.StatusOK {
  83. return httpRespToErrorResponse(resp, bucketName, "")
  84. }
  85. }
  86. // Success.
  87. return nil
  88. }
  89. // SetBucketPolicy set the access permissions on an existing bucket.
  90. func (c Client) SetBucketPolicy(bucketName, policy string) error {
  91. // Input validation.
  92. if err := s3utils.CheckValidBucketName(bucketName); err != nil {
  93. return err
  94. }
  95. // If policy is empty then delete the bucket policy.
  96. if policy == "" {
  97. return c.removeBucketPolicy(bucketName)
  98. }
  99. // Save the updated policies.
  100. return c.putBucketPolicy(bucketName, policy)
  101. }
  102. // Saves a new bucket policy.
  103. func (c Client) putBucketPolicy(bucketName, policy string) error {
  104. // Input validation.
  105. if err := s3utils.CheckValidBucketName(bucketName); err != nil {
  106. return err
  107. }
  108. // Get resources properly escaped and lined up before
  109. // using them in http request.
  110. urlValues := make(url.Values)
  111. urlValues.Set("policy", "")
  112. // Content-length is mandatory for put policy request
  113. policyReader := strings.NewReader(policy)
  114. b, err := ioutil.ReadAll(policyReader)
  115. if err != nil {
  116. return err
  117. }
  118. reqMetadata := requestMetadata{
  119. bucketName: bucketName,
  120. queryValues: urlValues,
  121. contentBody: policyReader,
  122. contentLength: int64(len(b)),
  123. }
  124. // Execute PUT to upload a new bucket policy.
  125. resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
  126. defer closeResponse(resp)
  127. if err != nil {
  128. return err
  129. }
  130. if resp != nil {
  131. if resp.StatusCode != http.StatusNoContent {
  132. return httpRespToErrorResponse(resp, bucketName, "")
  133. }
  134. }
  135. return nil
  136. }
  137. // Removes all policies on a bucket.
  138. func (c Client) removeBucketPolicy(bucketName string) error {
  139. // Input validation.
  140. if err := s3utils.CheckValidBucketName(bucketName); err != nil {
  141. return err
  142. }
  143. // Get resources properly escaped and lined up before
  144. // using them in http request.
  145. urlValues := make(url.Values)
  146. urlValues.Set("policy", "")
  147. // Execute DELETE on objectName.
  148. resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{
  149. bucketName: bucketName,
  150. queryValues: urlValues,
  151. contentSHA256Hex: emptySHA256Hex,
  152. })
  153. defer closeResponse(resp)
  154. if err != nil {
  155. return err
  156. }
  157. return nil
  158. }
  159. // SetBucketLifecycle set the lifecycle on an existing bucket.
  160. func (c Client) SetBucketLifecycle(bucketName, lifecycle string) error {
  161. // Input validation.
  162. if err := s3utils.CheckValidBucketName(bucketName); err != nil {
  163. return err
  164. }
  165. // If lifecycle is empty then delete it.
  166. if lifecycle == "" {
  167. return c.removeBucketLifecycle(bucketName)
  168. }
  169. // Save the updated lifecycle.
  170. return c.putBucketLifecycle(bucketName, lifecycle)
  171. }
  172. // Saves a new bucket lifecycle.
  173. func (c Client) putBucketLifecycle(bucketName, lifecycle string) error {
  174. // Input validation.
  175. if err := s3utils.CheckValidBucketName(bucketName); err != nil {
  176. return err
  177. }
  178. // Get resources properly escaped and lined up before
  179. // using them in http request.
  180. urlValues := make(url.Values)
  181. urlValues.Set("lifecycle", "")
  182. // Content-length is mandatory for put lifecycle request
  183. lifecycleReader := strings.NewReader(lifecycle)
  184. b, err := ioutil.ReadAll(lifecycleReader)
  185. if err != nil {
  186. return err
  187. }
  188. reqMetadata := requestMetadata{
  189. bucketName: bucketName,
  190. queryValues: urlValues,
  191. contentBody: lifecycleReader,
  192. contentLength: int64(len(b)),
  193. contentMD5Base64: sumMD5Base64(b),
  194. }
  195. // Execute PUT to upload a new bucket lifecycle.
  196. resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
  197. defer closeResponse(resp)
  198. if err != nil {
  199. return err
  200. }
  201. if resp != nil {
  202. if resp.StatusCode != http.StatusOK {
  203. return httpRespToErrorResponse(resp, bucketName, "")
  204. }
  205. }
  206. return nil
  207. }
  208. // Remove lifecycle from a bucket.
  209. func (c Client) removeBucketLifecycle(bucketName string) error {
  210. // Input validation.
  211. if err := s3utils.CheckValidBucketName(bucketName); err != nil {
  212. return err
  213. }
  214. // Get resources properly escaped and lined up before
  215. // using them in http request.
  216. urlValues := make(url.Values)
  217. urlValues.Set("lifecycle", "")
  218. // Execute DELETE on objectName.
  219. resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{
  220. bucketName: bucketName,
  221. queryValues: urlValues,
  222. contentSHA256Hex: emptySHA256Hex,
  223. })
  224. defer closeResponse(resp)
  225. if err != nil {
  226. return err
  227. }
  228. return nil
  229. }
  230. // SetBucketNotification saves a new bucket notification.
  231. func (c Client) SetBucketNotification(bucketName string, bucketNotification BucketNotification) error {
  232. // Input validation.
  233. if err := s3utils.CheckValidBucketName(bucketName); err != nil {
  234. return err
  235. }
  236. // Get resources properly escaped and lined up before
  237. // using them in http request.
  238. urlValues := make(url.Values)
  239. urlValues.Set("notification", "")
  240. notifBytes, err := xml.Marshal(bucketNotification)
  241. if err != nil {
  242. return err
  243. }
  244. notifBuffer := bytes.NewReader(notifBytes)
  245. reqMetadata := requestMetadata{
  246. bucketName: bucketName,
  247. queryValues: urlValues,
  248. contentBody: notifBuffer,
  249. contentLength: int64(len(notifBytes)),
  250. contentMD5Base64: sumMD5Base64(notifBytes),
  251. contentSHA256Hex: sum256Hex(notifBytes),
  252. }
  253. // Execute PUT to upload a new bucket notification.
  254. resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
  255. defer closeResponse(resp)
  256. if err != nil {
  257. return err
  258. }
  259. if resp != nil {
  260. if resp.StatusCode != http.StatusOK {
  261. return httpRespToErrorResponse(resp, bucketName, "")
  262. }
  263. }
  264. return nil
  265. }
  266. // RemoveAllBucketNotification - Remove bucket notification clears all previously specified config
  267. func (c Client) RemoveAllBucketNotification(bucketName string) error {
  268. return c.SetBucketNotification(bucketName, BucketNotification{})
  269. }