202 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
| 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
 | |
| }
 |