123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- package storage
- // Copyright 2017 Microsoft Corporation
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- import (
- "errors"
- "net/http"
- "net/url"
- "strconv"
- "time"
- )
- // lease constants.
- const (
- leaseHeaderPrefix = "x-ms-lease-"
- headerLeaseID = "x-ms-lease-id"
- leaseAction = "x-ms-lease-action"
- leaseBreakPeriod = "x-ms-lease-break-period"
- leaseDuration = "x-ms-lease-duration"
- leaseProposedID = "x-ms-proposed-lease-id"
- leaseTime = "x-ms-lease-time"
- acquireLease = "acquire"
- renewLease = "renew"
- changeLease = "change"
- releaseLease = "release"
- breakLease = "break"
- )
- // leasePut is common PUT code for the various acquire/release/break etc functions.
- func (b *Blob) leaseCommonPut(headers map[string]string, expectedStatus int, options *LeaseOptions) (http.Header, error) {
- params := url.Values{"comp": {"lease"}}
- if options != nil {
- params = addTimeout(params, options.Timeout)
- headers = mergeHeaders(headers, headersFromStruct(*options))
- }
- uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
- resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, nil, b.Container.bsc.auth)
- if err != nil {
- return nil, err
- }
- defer drainRespBody(resp)
- if err := checkRespCode(resp, []int{expectedStatus}); err != nil {
- return nil, err
- }
- return resp.Header, nil
- }
- // LeaseOptions includes options for all operations regarding leasing blobs
- type LeaseOptions struct {
- Timeout uint
- Origin string `header:"Origin"`
- IfMatch string `header:"If-Match"`
- IfNoneMatch string `header:"If-None-Match"`
- IfModifiedSince *time.Time `header:"If-Modified-Since"`
- IfUnmodifiedSince *time.Time `header:"If-Unmodified-Since"`
- RequestID string `header:"x-ms-client-request-id"`
- }
- // AcquireLease creates a lease for a blob
- // returns leaseID acquired
- // In API Versions starting on 2012-02-12, the minimum leaseTimeInSeconds is 15, the maximum
- // non-infinite leaseTimeInSeconds is 60. To specify an infinite lease, provide the value -1.
- // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Lease-Blob
- func (b *Blob) AcquireLease(leaseTimeInSeconds int, proposedLeaseID string, options *LeaseOptions) (returnedLeaseID string, err error) {
- headers := b.Container.bsc.client.getStandardHeaders()
- headers[leaseAction] = acquireLease
- if leaseTimeInSeconds == -1 {
- // Do nothing, but don't trigger the following clauses.
- } else if leaseTimeInSeconds > 60 || b.Container.bsc.client.apiVersion < "2012-02-12" {
- leaseTimeInSeconds = 60
- } else if leaseTimeInSeconds < 15 {
- leaseTimeInSeconds = 15
- }
- headers[leaseDuration] = strconv.Itoa(leaseTimeInSeconds)
- if proposedLeaseID != "" {
- headers[leaseProposedID] = proposedLeaseID
- }
- respHeaders, err := b.leaseCommonPut(headers, http.StatusCreated, options)
- if err != nil {
- return "", err
- }
- returnedLeaseID = respHeaders.Get(http.CanonicalHeaderKey(headerLeaseID))
- if returnedLeaseID != "" {
- return returnedLeaseID, nil
- }
- return "", errors.New("LeaseID not returned")
- }
- // BreakLease breaks the lease for a blob
- // Returns the timeout remaining in the lease in seconds
- // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Lease-Blob
- func (b *Blob) BreakLease(options *LeaseOptions) (breakTimeout int, err error) {
- headers := b.Container.bsc.client.getStandardHeaders()
- headers[leaseAction] = breakLease
- return b.breakLeaseCommon(headers, options)
- }
- // BreakLeaseWithBreakPeriod breaks the lease for a blob
- // breakPeriodInSeconds is used to determine how long until new lease can be created.
- // Returns the timeout remaining in the lease in seconds
- // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Lease-Blob
- func (b *Blob) BreakLeaseWithBreakPeriod(breakPeriodInSeconds int, options *LeaseOptions) (breakTimeout int, err error) {
- headers := b.Container.bsc.client.getStandardHeaders()
- headers[leaseAction] = breakLease
- headers[leaseBreakPeriod] = strconv.Itoa(breakPeriodInSeconds)
- return b.breakLeaseCommon(headers, options)
- }
- // breakLeaseCommon is common code for both version of BreakLease (with and without break period)
- func (b *Blob) breakLeaseCommon(headers map[string]string, options *LeaseOptions) (breakTimeout int, err error) {
- respHeaders, err := b.leaseCommonPut(headers, http.StatusAccepted, options)
- if err != nil {
- return 0, err
- }
- breakTimeoutStr := respHeaders.Get(http.CanonicalHeaderKey(leaseTime))
- if breakTimeoutStr != "" {
- breakTimeout, err = strconv.Atoi(breakTimeoutStr)
- if err != nil {
- return 0, err
- }
- }
- return breakTimeout, nil
- }
- // ChangeLease changes a lease ID for a blob
- // Returns the new LeaseID acquired
- // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Lease-Blob
- func (b *Blob) ChangeLease(currentLeaseID string, proposedLeaseID string, options *LeaseOptions) (newLeaseID string, err error) {
- headers := b.Container.bsc.client.getStandardHeaders()
- headers[leaseAction] = changeLease
- headers[headerLeaseID] = currentLeaseID
- headers[leaseProposedID] = proposedLeaseID
- respHeaders, err := b.leaseCommonPut(headers, http.StatusOK, options)
- if err != nil {
- return "", err
- }
- newLeaseID = respHeaders.Get(http.CanonicalHeaderKey(headerLeaseID))
- if newLeaseID != "" {
- return newLeaseID, nil
- }
- return "", errors.New("LeaseID not returned")
- }
- // ReleaseLease releases the lease for a blob
- // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Lease-Blob
- func (b *Blob) ReleaseLease(currentLeaseID string, options *LeaseOptions) error {
- headers := b.Container.bsc.client.getStandardHeaders()
- headers[leaseAction] = releaseLease
- headers[headerLeaseID] = currentLeaseID
- _, err := b.leaseCommonPut(headers, http.StatusOK, options)
- if err != nil {
- return err
- }
- return nil
- }
- // RenewLease renews the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
- func (b *Blob) RenewLease(currentLeaseID string, options *LeaseOptions) error {
- headers := b.Container.bsc.client.getStandardHeaders()
- headers[leaseAction] = renewLease
- headers[headerLeaseID] = currentLeaseID
- _, err := b.leaseCommonPut(headers, http.StatusOK, options)
- if err != nil {
- return err
- }
- return nil
- }
|