share.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package storage
  2. // Copyright 2017 Microsoft Corporation
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. import (
  16. "fmt"
  17. "net/http"
  18. "net/url"
  19. "strconv"
  20. )
  21. // Share represents an Azure file share.
  22. type Share struct {
  23. fsc *FileServiceClient
  24. Name string `xml:"Name"`
  25. Properties ShareProperties `xml:"Properties"`
  26. Metadata map[string]string
  27. }
  28. // ShareProperties contains various properties of a share.
  29. type ShareProperties struct {
  30. LastModified string `xml:"Last-Modified"`
  31. Etag string `xml:"Etag"`
  32. Quota int `xml:"Quota"`
  33. }
  34. // builds the complete path for this share object.
  35. func (s *Share) buildPath() string {
  36. return fmt.Sprintf("/%s", s.Name)
  37. }
  38. // Create this share under the associated account.
  39. // If a share with the same name already exists, the operation fails.
  40. //
  41. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Create-Share
  42. func (s *Share) Create(options *FileRequestOptions) error {
  43. extraheaders := map[string]string{}
  44. if s.Properties.Quota > 0 {
  45. extraheaders["x-ms-share-quota"] = strconv.Itoa(s.Properties.Quota)
  46. }
  47. params := prepareOptions(options)
  48. headers, err := s.fsc.createResource(s.buildPath(), resourceShare, params, mergeMDIntoExtraHeaders(s.Metadata, extraheaders), []int{http.StatusCreated})
  49. if err != nil {
  50. return err
  51. }
  52. s.updateEtagAndLastModified(headers)
  53. return nil
  54. }
  55. // CreateIfNotExists creates this share under the associated account if
  56. // it does not exist. Returns true if the share is newly created or false if
  57. // the share already exists.
  58. //
  59. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Create-Share
  60. func (s *Share) CreateIfNotExists(options *FileRequestOptions) (bool, error) {
  61. extraheaders := map[string]string{}
  62. if s.Properties.Quota > 0 {
  63. extraheaders["x-ms-share-quota"] = strconv.Itoa(s.Properties.Quota)
  64. }
  65. params := prepareOptions(options)
  66. resp, err := s.fsc.createResourceNoClose(s.buildPath(), resourceShare, params, extraheaders)
  67. if resp != nil {
  68. defer drainRespBody(resp)
  69. if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict {
  70. if resp.StatusCode == http.StatusCreated {
  71. s.updateEtagAndLastModified(resp.Header)
  72. return true, nil
  73. }
  74. return false, s.FetchAttributes(nil)
  75. }
  76. }
  77. return false, err
  78. }
  79. // Delete marks this share for deletion. The share along with any files
  80. // and directories contained within it are later deleted during garbage
  81. // collection. If the share does not exist the operation fails
  82. //
  83. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Delete-Share
  84. func (s *Share) Delete(options *FileRequestOptions) error {
  85. return s.fsc.deleteResource(s.buildPath(), resourceShare, options)
  86. }
  87. // DeleteIfExists operation marks this share for deletion if it exists.
  88. //
  89. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Delete-Share
  90. func (s *Share) DeleteIfExists(options *FileRequestOptions) (bool, error) {
  91. resp, err := s.fsc.deleteResourceNoClose(s.buildPath(), resourceShare, options)
  92. if resp != nil {
  93. defer drainRespBody(resp)
  94. if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound {
  95. return resp.StatusCode == http.StatusAccepted, nil
  96. }
  97. }
  98. return false, err
  99. }
  100. // Exists returns true if this share already exists
  101. // on the storage account, otherwise returns false.
  102. func (s *Share) Exists() (bool, error) {
  103. exists, headers, err := s.fsc.resourceExists(s.buildPath(), resourceShare)
  104. if exists {
  105. s.updateEtagAndLastModified(headers)
  106. s.updateQuota(headers)
  107. }
  108. return exists, err
  109. }
  110. // FetchAttributes retrieves metadata and properties for this share.
  111. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-share-properties
  112. func (s *Share) FetchAttributes(options *FileRequestOptions) error {
  113. params := prepareOptions(options)
  114. headers, err := s.fsc.getResourceHeaders(s.buildPath(), compNone, resourceShare, params, http.MethodHead)
  115. if err != nil {
  116. return err
  117. }
  118. s.updateEtagAndLastModified(headers)
  119. s.updateQuota(headers)
  120. s.Metadata = getMetadataFromHeaders(headers)
  121. return nil
  122. }
  123. // GetRootDirectoryReference returns a Directory object at the root of this share.
  124. func (s *Share) GetRootDirectoryReference() *Directory {
  125. return &Directory{
  126. fsc: s.fsc,
  127. share: s,
  128. }
  129. }
  130. // ServiceClient returns the FileServiceClient associated with this share.
  131. func (s *Share) ServiceClient() *FileServiceClient {
  132. return s.fsc
  133. }
  134. // SetMetadata replaces the metadata for this share.
  135. //
  136. // Some keys may be converted to Camel-Case before sending. All keys
  137. // are returned in lower case by GetShareMetadata. HTTP header names
  138. // are case-insensitive so case munging should not matter to other
  139. // applications either.
  140. //
  141. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-share-metadata
  142. func (s *Share) SetMetadata(options *FileRequestOptions) error {
  143. headers, err := s.fsc.setResourceHeaders(s.buildPath(), compMetadata, resourceShare, mergeMDIntoExtraHeaders(s.Metadata, nil), options)
  144. if err != nil {
  145. return err
  146. }
  147. s.updateEtagAndLastModified(headers)
  148. return nil
  149. }
  150. // SetProperties sets system properties for this share.
  151. //
  152. // Some keys may be converted to Camel-Case before sending. All keys
  153. // are returned in lower case by SetShareProperties. HTTP header names
  154. // are case-insensitive so case munging should not matter to other
  155. // applications either.
  156. //
  157. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Set-Share-Properties
  158. func (s *Share) SetProperties(options *FileRequestOptions) error {
  159. extraheaders := map[string]string{}
  160. if s.Properties.Quota > 0 {
  161. if s.Properties.Quota > 5120 {
  162. return fmt.Errorf("invalid value %v for quota, valid values are [1, 5120]", s.Properties.Quota)
  163. }
  164. extraheaders["x-ms-share-quota"] = strconv.Itoa(s.Properties.Quota)
  165. }
  166. headers, err := s.fsc.setResourceHeaders(s.buildPath(), compProperties, resourceShare, extraheaders, options)
  167. if err != nil {
  168. return err
  169. }
  170. s.updateEtagAndLastModified(headers)
  171. return nil
  172. }
  173. // updates Etag and last modified date
  174. func (s *Share) updateEtagAndLastModified(headers http.Header) {
  175. s.Properties.Etag = headers.Get("Etag")
  176. s.Properties.LastModified = headers.Get("Last-Modified")
  177. }
  178. // updates quota value
  179. func (s *Share) updateQuota(headers http.Header) {
  180. quota, err := strconv.Atoi(headers.Get("x-ms-share-quota"))
  181. if err == nil {
  182. s.Properties.Quota = quota
  183. }
  184. }
  185. // URL gets the canonical URL to this share. This method does not create a publicly accessible
  186. // URL if the share is private and this method does not check if the share exists.
  187. func (s *Share) URL() string {
  188. return s.fsc.client.getEndpoint(fileServiceName, s.buildPath(), url.Values{})
  189. }