aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2016-11-03 00:22:53 +0800
committerPéter Szilágyi <peterke@gmail.com>2016-11-03 16:32:57 +0800
commitbad0de0dcbae82d96f68d1eec1701042d5dfa985 (patch)
tree7b6e585f47a0c4bb9f6e3a17d549ca1d0ddbd642 /vendor/github.com
parent3b62c145f8d699767e13770d1bb21d07c2ba9b46 (diff)
downloadgo-tangerine-bad0de0dcbae82d96f68d1eec1701042d5dfa985.tar.gz
go-tangerine-bad0de0dcbae82d96f68d1eec1701042d5dfa985.tar.zst
go-tangerine-bad0de0dcbae82d96f68d1eec1701042d5dfa985.zip
vendor: pull in azure sdk and openpgp signer
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/.gitignore32
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/.travis.yml33
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md280
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/LICENSE202
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/README.md102
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/glide.lock53
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/glide.yaml12
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/README.md5
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go1278
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/client.go551
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/file.go352
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go306
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/table.go129
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/table_entities.go355
-rw-r--r--vendor/github.com/Azure/azure-sdk-for-go/storage/util.go85
-rw-r--r--vendor/github.com/davecgh/go-spew/LICENSE2
-rw-r--r--vendor/github.com/davecgh/go-spew/README.md21
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/bypass.go2
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/bypasssafe.go2
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/common.go2
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/config.go11
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/doc.go11
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/dump.go8
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/format.go2
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/spew.go2
-rw-r--r--vendor/github.com/huin/goupnp/ssdp/registry.go2
-rw-r--r--vendor/github.com/mattn/go-colorable/colorable_windows.go8
27 files changed, 3829 insertions, 19 deletions
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/.gitignore b/vendor/github.com/Azure/azure-sdk-for-go/.gitignore
new file mode 100644
index 000000000..2da4dc358
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/.gitignore
@@ -0,0 +1,32 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+# Editor swap files
+*.swp
+*~
+.DS_Store
+
+# ignore vendor/
+vendor/
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml b/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml
new file mode 100644
index 000000000..6a134afeb
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml
@@ -0,0 +1,33 @@
+sudo: false
+
+language: go
+
+go: 1.7
+
+install:
+ - go get -u github.com/golang/lint/golint
+ - go get -u github.com/Masterminds/glide
+ - go get -u golang.org/x/net/context
+ - go get -u github.com/HewlettPackard/gas
+ - go get -u gopkg.in/godo.v2/cmd/godo
+ - export GO15VENDOREXPERIMENT=1
+ - glide install
+
+script:
+ - gas -skip=management/examples/*.go -skip=*vendor* -skip=Gododir/* ./... | tee gas-scan.txt
+ - test -z "$(grep 'Severity:\s*HIGH' gas-scan.txt)"
+ - test -z "$(gofmt -s -l $(find ./arm/* -type d -print) | tee /dev/stderr)"
+ - test -z "$(gofmt -s -l -w management | tee /dev/stderr)"
+ - test -z "$(gofmt -s -l -w storage | tee /dev/stderr)"
+ - test -z "$(gofmt -s -l -w Gododir | tee /dev/stderr)"
+ - test -z "$(go build $(find ./* -type d -print | grep -v '^./vendor$') | tee /dev/stderr)"
+ - test -z "$(go vet $(find ./arm/* -type d -print) | tee /dev/stderr)"
+ - test -z "$(golint ./arm/... | tee /dev/stderr)"
+ - go test -v ./storage/... -check.v
+ - test -z "$(golint ./storage/... | tee /dev/stderr)"
+ - go vet ./storage/...
+ - go test -v ./management/...
+ - test -z "$(golint ./management/... | grep -v 'should have comment' | grep -v 'stutters' | tee /dev/stderr)"
+ - go vet ./management/...
+ - test -z "$(golint ./Gododir/... | tee /dev/stderr)"
+ - go vet ./Gododir/...
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md
new file mode 100644
index 000000000..13a0ca4b3
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md
@@ -0,0 +1,280 @@
+# CHANGELOG
+
+-----
+
+## `v6.0.0-beta`
+
+| api | version | note |
+|:-------------------------------|:-------------------|:-----------------------------------|
+| arm/authorization | no change | code refactoring |
+| arm/batch | no change | code refactoring |
+| arm/compute | no change | code refactoring |
+| arm/containerservice | 2016-03-30 | return |
+| arm/datalake-analytics/account | 2015-10-01-preview | new |
+| arm/datalake-store/filesystem | no change | moved to datalake-store/filesystem |
+| arm/eventhub | no change | code refactoring |
+| arm/intune | no change | code refactoring |
+| arm/iothub | no change | code refactoring |
+| arm/keyvault | no change | code refactoring |
+| arm/mediaservices | no change | code refactoring |
+| arm/network | no change | code refactoring |
+| arm/notificationhubs | no change | code refactoring |
+| arm/redis | no change | code refactoring |
+| arm/resources/resources | no change | code refactoring |
+| arm/resources/links | 2016-09-01 | new |
+| arm/resources/locks | 2016-09-01 | updated |
+| arm/resources/policy | no change | code refactoring |
+| arm/resources/resources | 2016-09-01 | updated |
+| arm/servermanagement | 2016-07-01-preview | updated |
+| arm/web | no change | code refactoring |
+
+- storage: Added blob lease functionality and tests
+
+## `v5.0.0-beta`
+
+| api | version | note |
+|:------------------------------|:--------------------|:-----------------|
+| arm/network | 2016-09-01 | updated |
+| arm/servermanagement | 2015-07-01-preview | new |
+| arm/eventhub | 2015-08-01 | new |
+| arm/containerservice | -- | removed |
+| arm/resources/subscriptions | no change | code refactoring |
+| arm/resources/features | no change | code refactoring |
+| arm/resources/resources | no change | code refactoring |
+| arm/datalake-store/accounts | no change | code refactoring |
+| arm/datalake-store/filesystem | no change | code refactoring |
+| arm/notificationhubs | no change | code refactoring |
+| arm/redis | no change | code refactoring |
+
+- storage: Add more file storage share operations.
+- azure-rest-api-specs/commit/b8cdc2c50a0872fc0039f20c2b6b33aa0c2af4bf
+- Uses go-autorest v7.2.1
+
+## `v4.0.0-beta`
+
+- arm/logic: breaking change in package logic.
+- arm: parameter validation code added in all arm packages.
+- Uses go-autorest v7.2.0.
+
+
+## `v3.2.0-beta`
+
+| api | version | note |
+|:----------------------------|:--------------------|:----------|
+| arm/mediaservices | 2015-10-01 | new |
+| arm/keyvault | 2015-06-01 | new |
+| arm/iothub | 2016-02-03 | new |
+| arm/datalake-store | 2015-12-01 | new |
+| arm/network | 2016-06-01 | updated |
+| arm/resources/resources | 2016-07-01 | updated |
+| arm/resources/policy | 2016-04-01 | updated |
+| arm/servicebus | 2015-08-01 | updated |
+
+- arm: uses go-autorest version v7.1.0.
+- storage: fix for operating on blobs names containing special characters.
+- storage: add SetBlobProperties(), update BlobProperties response fields.
+- storage: make storage client work correctly with read-only secondary account.
+- storage: add Azure Storage Emulator support.
+
+
+## `v3.1.0-beta`
+
+- Added a new arm/compute/containerservice (2016-03-30) package
+- Reintroduced NewxxClientWithBaseURI method.
+- Uses go-autorest version - v7.0.7.
+
+
+## `v3.0.0-beta`
+
+This release brings the Go SDK ARM packages up-to-date with Azure ARM Swagger files for most
+services. Since the underlying [Swagger files](https://github.com/Azure/azure-rest-api-specs)
+continue to change substantially, the ARM packages are still in *beta* status.
+
+The ARM packages now align with the following API versions (*highlighted* packages are new or
+updated in this release):
+
+| api | version | note |
+|:----------------------------|:--------------------|:----------|
+| arm/authorization | 2015-07-01 | no change |
+| arm/intune | 2015-01-14-preview | no change |
+| arm/notificationhubs | 2014-09-01 | no change |
+| arm/resources/features | 2015-12-01 | no change |
+| arm/resources/subscriptions | 2015-11-01 | no change |
+| arm/web | 2015-08-01 | no change |
+| arm/cdn | 2016-04-02 | updated |
+| arm/compute | 2016-03-30 | updated |
+| arm/dns | 2016-04-01 | updated |
+| arm/logic | 2015-08-01-preview | updated |
+| arm/network | 2016-03-30 | updated |
+| arm/redis | 2016-04-01 | updated |
+| arm/resources/resources | 2016-02-01 | updated |
+| arm/resources/policy | 2015-10-01-preview | updated |
+| arm/resources/locks | 2015-01-01 | updated (resources/authorization earlier)|
+| arm/scheduler | 2016-03-01 | updated |
+| arm/storage | 2016-01-01 | updated |
+| arm/search | 2015-02-28 | updated |
+| arm/batch | 2015-12-01 | new |
+| arm/cognitiveservices | 2016-02-01-preview | new |
+| arm/devtestlabs | 2016-05-15 | new |
+| arm/machinelearning | 2016-05-01-preview | new |
+| arm/powerbiembedded | 2016-01-29 | new |
+| arm/mobileengagement | 2014-12-01 | new |
+| arm/servicebus | 2014-09-01 | new |
+| arm/sql | 2015-05-01 | new |
+| arm/trafficmanager | 2015-11-01 | new |
+
+
+Below are some design changes.
+- Removed Api version from method arguments.
+- Removed New...ClientWithBaseURI() method in all clients. BaseURI value is set in client.go.
+- Uses go-autorest version v7.0.6.
+
+
+## `v2.2.0-beta`
+
+- Uses go-autorest version v7.0.5.
+- Update version of pacakges "jwt-go" and "crypto" in glide.lock.
+
+
+## `v2.1.1-beta`
+
+- arm: Better error messages for long running operation failures (Uses go-autorest version v7.0.4).
+
+
+## `v2.1.0-beta`
+
+- arm: Uses go-autorest v7.0.3 (polling related updates).
+- arm: Cancel channel argument added in long-running calls.
+- storage: Allow caller to provide headers for DeleteBlob methods.
+- storage: Enables connection sharing with http keepalive.
+- storage: Add BlobPrefixes and Delimiter to BlobListResponse
+
+
+## `v2.0.0-beta`
+
+- Uses go-autorest v6.0.0 (Polling and Asynchronous requests related changes).
+
+
+## `v0.5.0-beta`
+
+Updated following packages to new API versions:
+- arm/resources/features 2015-12-01
+- arm/resources/resources 2015-11-01
+- arm/resources/subscriptions 2015-11-01
+
+
+### Changes
+
+ - SDK now uses go-autorest v3.0.0.
+
+
+
+## `v0.4.0-beta`
+
+This release brings the Go SDK ARM packages up-to-date with Azure ARM Swagger files for most
+services. Since the underlying [Swagger files](https://github.com/Azure/azure-rest-api-specs)
+continue to change substantially, the ARM packages are still in *beta* status.
+
+The ARM packages now align with the following API versions (*highlighted* packages are new or
+updated in this release):
+
+- *arm/authorization 2015-07-01*
+- *arm/cdn 2015-06-01*
+- arm/compute 2015-06-15
+- arm/dns 2015-05-04-preview
+- *arm/intune 2015-01-14-preview*
+- arm/logic 2015-02-01-preview
+- *arm/network 2015-06-15*
+- *arm/notificationhubs 2014-09-01*
+- arm/redis 2015-08-01
+- *arm/resources/authorization 2015-01-01*
+- *arm/resources/features 2014-08-01-preview*
+- *arm/resources/resources 2014-04-01-preview*
+- *arm/resources/subscriptions 2014-04-01-preview*
+- *arm/scheduler 2016-01-01*
+- arm/storage 2015-06-15
+- arm/web 2015-08-01
+
+### Changes
+
+- Moved the arm/authorization, arm/features, arm/resources, and arm/subscriptions packages under a new, resources, package (to reflect the corresponding Swagger structure)
+- Added a new arm/authoriation (2015-07-01) package
+- Added a new arm/cdn (2015-06-01) package
+- Added a new arm/intune (2015-01-14-preview) package
+- Udated arm/network (2015-06-01)
+- Added a new arm/notificationhubs (2014-09-01) package
+- Updated arm/scheduler (2016-01-01) package
+
+
+-----
+
+## `v0.3.0-beta`
+
+- Corrected unintentional struct field renaming and client renaming in v0.2.0-beta
+
+-----
+
+## `v0.2.0-beta`
+
+- Added support for DNS, Redis, and Web site services
+- Updated Storage service to API version 2015-06-15
+- Updated Network to include routing table support
+- Address https://github.com/Azure/azure-sdk-for-go/issues/232
+- Address https://github.com/Azure/azure-sdk-for-go/issues/231
+- Address https://github.com/Azure/azure-sdk-for-go/issues/230
+- Address https://github.com/Azure/azure-sdk-for-go/issues/224
+- Address https://github.com/Azure/azure-sdk-for-go/issues/184
+- Address https://github.com/Azure/azure-sdk-for-go/issues/183
+
+------
+
+## `v0.1.1-beta`
+
+- Improves the UserAgent string to disambiguate arm packages from others in the SDK
+- Improves setting the http.Response into generated results (reduces likelihood of a nil reference)
+- Adds gofmt, golint, and govet to Travis CI for the arm packages
+
+##### Fixed Issues
+
+- https://github.com/Azure/azure-sdk-for-go/issues/196
+- https://github.com/Azure/azure-sdk-for-go/issues/213
+
+------
+
+## v0.1.0-beta
+
+This release addresses the issues raised against the alpha release and adds more features. Most
+notably, to address the challenges of encoding JSON
+(see the [comments](https://github.com/Azure/go-autorest#handling-empty-values) in the
+[go-autorest](https://github.com/Azure/go-autorest) package) by using pointers for *all* structure
+fields (with the exception of enumerations). The
+[go-autorest/autorest/to](https://github.com/Azure/go-autorest/tree/master/autorest/to) package
+provides helpers to convert to / from pointers. The examples demonstrate their usage.
+
+Additionally, the packages now align with Go coding standards and pass both `golint` and `govet`.
+Accomplishing this required renaming various fields and parameters (such as changing Url to URL).
+
+##### Changes
+
+- Changed request / response structures to use pointer fields.
+- Changed methods to return `error` instead of `autorest.Error`.
+- Re-divided methods to ease asynchronous requests.
+- Added paged results support.
+- Added a UserAgent string.
+- Added changes necessary to pass golint and govet.
+- Updated README.md with details on asynchronous requests and paging.
+- Saved package dependencies through Godep (for the entire SDK).
+
+##### Fixed Issues:
+
+- https://github.com/Azure/azure-sdk-for-go/issues/205
+- https://github.com/Azure/azure-sdk-for-go/issues/206
+- https://github.com/Azure/azure-sdk-for-go/issues/211
+- https://github.com/Azure/azure-sdk-for-go/issues/212
+
+-----
+
+## v0.1.0-alpha
+
+This release introduces the Azure Resource Manager packages generated from the corresponding
+[Swagger API](http://swagger.io) [definitions](https://github.com/Azure/azure-rest-api-specs). \ No newline at end of file
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/LICENSE b/vendor/github.com/Azure/azure-sdk-for-go/LICENSE
new file mode 100644
index 000000000..af39a91e7
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2016 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.
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/README.md b/vendor/github.com/Azure/azure-sdk-for-go/README.md
new file mode 100644
index 000000000..6a1aaf4ac
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/README.md
@@ -0,0 +1,102 @@
+# Microsoft Azure SDK for Go
+
+This project provides various Go packages to perform operations
+on Microsoft Azure REST APIs.
+
+[![GoDoc](https://godoc.org/github.com/Azure/azure-sdk-for-go?status.svg)](https://godoc.org/github.com/Azure/azure-sdk-for-go) [![Build Status](https://travis-ci.org/Azure/azure-sdk-for-go.svg?branch=master)](https://travis-ci.org/Azure/azure-sdk-for-go)
+
+> **NOTE:** This repository is under heavy ongoing development and
+is likely to break over time. We currently do not have any releases
+yet. If you are planning to use the repository, please consider vendoring
+the packages in your project and update them when a stable tag is out.
+
+# Packages
+
+## Azure Resource Manager (ARM)
+
+[About ARM](/arm/README.md)
+
+- [authorization](/arm/authorization)
+- [batch](/arm/batch)
+- [cdn](/arm/cdn)
+- [cognitiveservices](/arm/cognitiveservices)
+- [compute](/arm/compute)
+- [containerservice](/arm/containerservice)
+- [datalake-store](/arm/datalake-store)
+- [devtestlabs](/arm/devtestlabs)
+- [dns](/arm/dns)
+- [intune](/arm/intune)
+- [iothub](/arm/iothub)
+- [keyvault](/arm/keyvault)
+- [logic](/arm/logic)
+- [machinelearning](/arm/machinelearning)
+- [mediaservices](/arm/mediaservices)
+- [mobileengagement](/arm/mobileengagement)
+- [network](/arm/network)
+- [notificationhubs](/arm/notificationhubs)
+- [powerbiembedded](/arm/powerbiembedded)
+- [redis](/arm/redis)
+- [resources](/arm/resources)
+- [scheduler](/arm/scheduler)
+- [search](/arm/search)
+- [servicebus](/arm/servicebus)
+- [sql](/arm/sql)
+- [storage](/arm/storage)
+- [trafficmanager](/arm/trafficmanager)
+- [web](/arm/web)
+
+## Azure Service Management (ASM), aka classic deployment
+
+[About ASM](/management/README.md)
+
+- [affinitygroup](/management/affinitygroup)
+- [hostedservice](/management/hostedservice)
+- [location](/management/location)
+- [networksecuritygroup](/management/networksecuritygroup)
+- [osimage](/management/osimage)
+- [sql](/management/sql)
+- [storageservice](/management/storageservice)
+- [virtualmachine](/management/virtualmachine)
+- [virtualmachinedisk](/management/virtualmachinedisk)
+- [virtualmachineimage](/management/virtualmachineimage)
+- [virtualnetwork](/management/virtualnetwork)
+- [vmutils](/management/vmutils)
+
+## Azure Storage SDK for Go
+
+[About Storage](/storage/README.md)
+
+- [storage](/storage)
+
+# Installation
+
+- [Install Go 1.7](https://golang.org/dl/).
+
+- Go get the SDK:
+
+```
+$ go get -d github.com/Azure/azure-sdk-for-go
+```
+
+> **IMPORTANT:** We highly suggest vendoring Azure SDK for Go as a dependency. For vendoring dependencies, Azure SDK for Go uses [glide](https://github.com/Masterminds/glide). If you haven't already, install glide. Navigate to your project directory and install the dependencies.
+
+```
+$ cd your/project
+$ glide create
+$ glide install
+```
+
+# Documentation
+
+Read the Godoc of the repository at [Godoc.org](http://godoc.org/github.com/Azure/azure-sdk-for-go/).
+
+# Contribute
+
+If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.io/guidelines/).
+
+# License
+
+This project is published under [Apache 2.0 License](LICENSE).
+
+-----
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/glide.lock b/vendor/github.com/Azure/azure-sdk-for-go/glide.lock
new file mode 100644
index 000000000..31f3207ee
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/glide.lock
@@ -0,0 +1,53 @@
+hash: 7407050cee9bb9ce89e23ef26bce4051cce63d558338a4937f027a18b789e3a1
+updated: 2016-10-25T11:34:48.4987356-07:00
+imports:
+- name: github.com/Azure/go-autorest
+ version: 0781901f19f1e7db3034d97ec57af753db0bf808
+ subpackages:
+ - autorest
+ - autorest/azure
+ - autorest/date
+ - autorest/to
+ - autorest/validation
+- name: github.com/dgrijalva/jwt-go
+ version: 24c63f56522a87ec5339cc3567883f1039378fdb
+- name: github.com/howeyc/gopass
+ version: f5387c492211eb133053880d23dfae62aa14123d
+- name: github.com/mattn/go-colorable
+ version: 6c903ff4aa50920ca86087a280590b36b3152b9c
+- name: github.com/mattn/go-isatty
+ version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8
+- name: github.com/mgutz/ansi
+ version: c286dcecd19ff979eeb73ea444e479b903f2cfcb
+- name: github.com/mgutz/minimist
+ version: 39eb8cf573ca29344bd7d7e6ba4d7febdebd37a9
+- name: github.com/mgutz/str
+ version: 968bf66e3da857419e4f6e71b2d5c9ae95682dc4
+- name: github.com/mgutz/to
+ version: 2a0bcba0661696e339461f5efb2273f4459dd1b9
+- name: github.com/MichaelTJones/walk
+ version: 3af09438b0ab0e8f296410bfa646a7e635ea1fc0
+- name: github.com/nozzle/throttler
+ version: d9b45f19996c645d38c9266d1f5cf1990e930119
+- name: github.com/satori/uuid
+ version: b061729afc07e77a8aa4fad0a2fd840958f1942a
+- name: golang.org/x/crypto
+ version: 84e98f45760e87786b7f24603b8166a6fa09811d
+ subpackages:
+ - pkcs12
+ - pkcs12/internal/rc2
+ - ssh/terminal
+- name: golang.org/x/sys
+ version: c200b10b5d5e122be351b67af224adc6128af5bf
+ subpackages:
+ - unix
+- name: gopkg.in/check.v1
+ version: 4f90aeace3a26ad7021961c297b22c42160c7b25
+- name: gopkg.in/godo.v2
+ version: b5fd2f0bef1ebe832e628cfad18ab1cc707f65a1
+ subpackages:
+ - glob
+ - util
+ - watcher
+ - watcher/fswatch
+testImports: []
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/glide.yaml b/vendor/github.com/Azure/azure-sdk-for-go/glide.yaml
new file mode 100644
index 000000000..90f54fd10
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/glide.yaml
@@ -0,0 +1,12 @@
+package: github.com/Azure/azure-sdk-for-go
+import:
+- package: github.com/Azure/go-autorest
+ subpackages:
+ - /autorest
+ - autorest/azure
+ - autorest/date
+ - autorest/to
+- package: golang.org/x/crypto
+ subpackages:
+ - /pkcs12
+- package: gopkg.in/check.v1 \ No newline at end of file
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/README.md b/vendor/github.com/Azure/azure-sdk-for-go/storage/README.md
new file mode 100644
index 000000000..0ab099848
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/README.md
@@ -0,0 +1,5 @@
+# Azure Storage SDK for Go
+
+The `github.com/Azure/azure-sdk-for-go/storage` package is used to perform operations in Azure Storage Service. To manage your storage accounts (Azure Resource Manager / ARM), use the [github.com/Azure/azure-sdk-for-go/arm/storage](../arm/storage) package. For your classic storage accounts (Azure Service Management / ASM), use [github.com/Azure/azure-sdk-for-go/management/storageservice](../management/storageservice) package.
+
+This package includes support for [Azure Storage Emulator](https://azure.microsoft.com/documentation/articles/storage-use-emulator/) \ No newline at end of file
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go
new file mode 100644
index 000000000..317620363
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go
@@ -0,0 +1,1278 @@
+package storage
+
+import (
+ "bytes"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// BlobStorageClient contains operations for Microsoft Azure Blob Storage
+// Service.
+type BlobStorageClient struct {
+ client Client
+}
+
+// A Container is an entry in ContainerListResponse.
+type Container struct {
+ Name string `xml:"Name"`
+ Properties ContainerProperties `xml:"Properties"`
+ // TODO (ahmetalpbalkan) Metadata
+}
+
+// ContainerProperties contains various properties of a container returned from
+// various endpoints like ListContainers.
+type ContainerProperties struct {
+ LastModified string `xml:"Last-Modified"`
+ Etag string `xml:"Etag"`
+ LeaseStatus string `xml:"LeaseStatus"`
+ LeaseState string `xml:"LeaseState"`
+ LeaseDuration string `xml:"LeaseDuration"`
+ // TODO (ahmetalpbalkan) remaining fields
+}
+
+// ContainerListResponse contains the response fields from
+// ListContainers call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
+type ContainerListResponse struct {
+ XMLName xml.Name `xml:"EnumerationResults"`
+ Xmlns string `xml:"xmlns,attr"`
+ Prefix string `xml:"Prefix"`
+ Marker string `xml:"Marker"`
+ NextMarker string `xml:"NextMarker"`
+ MaxResults int64 `xml:"MaxResults"`
+ Containers []Container `xml:"Containers>Container"`
+}
+
+// A Blob is an entry in BlobListResponse.
+type Blob struct {
+ Name string `xml:"Name"`
+ Properties BlobProperties `xml:"Properties"`
+ Metadata BlobMetadata `xml:"Metadata"`
+}
+
+// BlobMetadata is a set of custom name/value pairs.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179404.aspx
+type BlobMetadata map[string]string
+
+type blobMetadataEntries struct {
+ Entries []blobMetadataEntry `xml:",any"`
+}
+type blobMetadataEntry struct {
+ XMLName xml.Name
+ Value string `xml:",chardata"`
+}
+
+// UnmarshalXML converts the xml:Metadata into Metadata map
+func (bm *BlobMetadata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+ var entries blobMetadataEntries
+ if err := d.DecodeElement(&entries, &start); err != nil {
+ return err
+ }
+ for _, entry := range entries.Entries {
+ if *bm == nil {
+ *bm = make(BlobMetadata)
+ }
+ (*bm)[strings.ToLower(entry.XMLName.Local)] = entry.Value
+ }
+ return nil
+}
+
+// MarshalXML implements the xml.Marshaler interface. It encodes
+// metadata name/value pairs as they would appear in an Azure
+// ListBlobs response.
+func (bm BlobMetadata) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
+ entries := make([]blobMetadataEntry, 0, len(bm))
+ for k, v := range bm {
+ entries = append(entries, blobMetadataEntry{
+ XMLName: xml.Name{Local: http.CanonicalHeaderKey(k)},
+ Value: v,
+ })
+ }
+ return enc.EncodeElement(blobMetadataEntries{
+ Entries: entries,
+ }, start)
+}
+
+// BlobProperties contains various properties of a blob
+// returned in various endpoints like ListBlobs or GetBlobProperties.
+type BlobProperties struct {
+ LastModified string `xml:"Last-Modified"`
+ Etag string `xml:"Etag"`
+ ContentMD5 string `xml:"Content-MD5"`
+ ContentLength int64 `xml:"Content-Length"`
+ ContentType string `xml:"Content-Type"`
+ ContentEncoding string `xml:"Content-Encoding"`
+ CacheControl string `xml:"Cache-Control"`
+ ContentLanguage string `xml:"Cache-Language"`
+ BlobType BlobType `xml:"x-ms-blob-blob-type"`
+ SequenceNumber int64 `xml:"x-ms-blob-sequence-number"`
+ CopyID string `xml:"CopyId"`
+ CopyStatus string `xml:"CopyStatus"`
+ CopySource string `xml:"CopySource"`
+ CopyProgress string `xml:"CopyProgress"`
+ CopyCompletionTime string `xml:"CopyCompletionTime"`
+ CopyStatusDescription string `xml:"CopyStatusDescription"`
+ LeaseStatus string `xml:"LeaseStatus"`
+}
+
+// BlobHeaders contains various properties of a blob and is an entry
+// in SetBlobProperties
+type BlobHeaders struct {
+ ContentMD5 string `header:"x-ms-blob-content-md5"`
+ ContentLanguage string `header:"x-ms-blob-content-language"`
+ ContentEncoding string `header:"x-ms-blob-content-encoding"`
+ ContentType string `header:"x-ms-blob-content-type"`
+ CacheControl string `header:"x-ms-blob-cache-control"`
+}
+
+// BlobListResponse contains the response fields from ListBlobs call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd135734.aspx
+type BlobListResponse struct {
+ XMLName xml.Name `xml:"EnumerationResults"`
+ Xmlns string `xml:"xmlns,attr"`
+ Prefix string `xml:"Prefix"`
+ Marker string `xml:"Marker"`
+ NextMarker string `xml:"NextMarker"`
+ MaxResults int64 `xml:"MaxResults"`
+ Blobs []Blob `xml:"Blobs>Blob"`
+
+ // BlobPrefix is used to traverse blobs as if it were a file system.
+ // It is returned if ListBlobsParameters.Delimiter is specified.
+ // The list here can be thought of as "folders" that may contain
+ // other folders or blobs.
+ BlobPrefixes []string `xml:"Blobs>BlobPrefix>Name"`
+
+ // Delimiter is used to traverse blobs as if it were a file system.
+ // It is returned if ListBlobsParameters.Delimiter is specified.
+ Delimiter string `xml:"Delimiter"`
+}
+
+// ListContainersParameters defines the set of customizable parameters to make a
+// List Containers call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
+type ListContainersParameters struct {
+ Prefix string
+ Marker string
+ Include string
+ MaxResults uint
+ Timeout uint
+}
+
+func (p ListContainersParameters) getParameters() url.Values {
+ out := url.Values{}
+
+ if p.Prefix != "" {
+ out.Set("prefix", p.Prefix)
+ }
+ if p.Marker != "" {
+ out.Set("marker", p.Marker)
+ }
+ if p.Include != "" {
+ out.Set("include", p.Include)
+ }
+ if p.MaxResults != 0 {
+ out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults))
+ }
+ if p.Timeout != 0 {
+ out.Set("timeout", fmt.Sprintf("%v", p.Timeout))
+ }
+
+ return out
+}
+
+// ListBlobsParameters defines the set of customizable
+// parameters to make a List Blobs call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd135734.aspx
+type ListBlobsParameters struct {
+ Prefix string
+ Delimiter string
+ Marker string
+ Include string
+ MaxResults uint
+ Timeout uint
+}
+
+func (p ListBlobsParameters) getParameters() url.Values {
+ out := url.Values{}
+
+ if p.Prefix != "" {
+ out.Set("prefix", p.Prefix)
+ }
+ if p.Delimiter != "" {
+ out.Set("delimiter", p.Delimiter)
+ }
+ if p.Marker != "" {
+ out.Set("marker", p.Marker)
+ }
+ if p.Include != "" {
+ out.Set("include", p.Include)
+ }
+ if p.MaxResults != 0 {
+ out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults))
+ }
+ if p.Timeout != 0 {
+ out.Set("timeout", fmt.Sprintf("%v", p.Timeout))
+ }
+
+ return out
+}
+
+// BlobType defines the type of the Azure Blob.
+type BlobType string
+
+// Types of page blobs
+const (
+ BlobTypeBlock BlobType = "BlockBlob"
+ BlobTypePage BlobType = "PageBlob"
+ BlobTypeAppend BlobType = "AppendBlob"
+)
+
+// PageWriteType defines the type updates that are going to be
+// done on the page blob.
+type PageWriteType string
+
+// Types of operations on page blobs
+const (
+ PageWriteTypeUpdate PageWriteType = "update"
+ PageWriteTypeClear PageWriteType = "clear"
+)
+
+const (
+ blobCopyStatusPending = "pending"
+ blobCopyStatusSuccess = "success"
+ blobCopyStatusAborted = "aborted"
+ blobCopyStatusFailed = "failed"
+)
+
+// lease constants.
+const (
+ leaseHeaderPrefix = "x-ms-lease-"
+ leaseID = "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"
+)
+
+// BlockListType is used to filter out types of blocks in a Get Blocks List call
+// for a block blob.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx for all
+// block types.
+type BlockListType string
+
+// Filters for listing blocks in block blobs
+const (
+ BlockListTypeAll BlockListType = "all"
+ BlockListTypeCommitted BlockListType = "committed"
+ BlockListTypeUncommitted BlockListType = "uncommitted"
+)
+
+// ContainerAccessType defines the access level to the container from a public
+// request.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179468.aspx and "x-ms-
+// blob-public-access" header.
+type ContainerAccessType string
+
+// Access options for containers
+const (
+ ContainerAccessTypePrivate ContainerAccessType = ""
+ ContainerAccessTypeBlob ContainerAccessType = "blob"
+ ContainerAccessTypeContainer ContainerAccessType = "container"
+)
+
+// Maximum sizes (per REST API) for various concepts
+const (
+ MaxBlobBlockSize = 4 * 1024 * 1024
+ MaxBlobPageSize = 4 * 1024 * 1024
+)
+
+// BlockStatus defines states a block for a block blob can
+// be in.
+type BlockStatus string
+
+// List of statuses that can be used to refer to a block in a block list
+const (
+ BlockStatusUncommitted BlockStatus = "Uncommitted"
+ BlockStatusCommitted BlockStatus = "Committed"
+ BlockStatusLatest BlockStatus = "Latest"
+)
+
+// Block is used to create Block entities for Put Block List
+// call.
+type Block struct {
+ ID string
+ Status BlockStatus
+}
+
+// BlockListResponse contains the response fields from Get Block List call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx
+type BlockListResponse struct {
+ XMLName xml.Name `xml:"BlockList"`
+ CommittedBlocks []BlockResponse `xml:"CommittedBlocks>Block"`
+ UncommittedBlocks []BlockResponse `xml:"UncommittedBlocks>Block"`
+}
+
+// BlockResponse contains the block information returned
+// in the GetBlockListCall.
+type BlockResponse struct {
+ Name string `xml:"Name"`
+ Size int64 `xml:"Size"`
+}
+
+// GetPageRangesResponse contains the reponse fields from
+// Get Page Ranges call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx
+type GetPageRangesResponse struct {
+ XMLName xml.Name `xml:"PageList"`
+ PageList []PageRange `xml:"PageRange"`
+}
+
+// PageRange contains information about a page of a page blob from
+// Get Pages Range call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx
+type PageRange struct {
+ Start int64 `xml:"Start"`
+ End int64 `xml:"End"`
+}
+
+var (
+ errBlobCopyAborted = errors.New("storage: blob copy is aborted")
+ errBlobCopyIDMismatch = errors.New("storage: blob copy id is a mismatch")
+)
+
+// ListContainers returns the list of containers in a storage account along with
+// pagination token and other response details.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
+func (b BlobStorageClient) ListContainers(params ListContainersParameters) (ContainerListResponse, error) {
+ q := mergeParams(params.getParameters(), url.Values{"comp": {"list"}})
+ uri := b.client.getEndpoint(blobServiceName, "", q)
+ headers := b.client.getStandardHeaders()
+
+ var out ContainerListResponse
+ resp, err := b.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return out, err
+ }
+ defer resp.body.Close()
+
+ err = xmlUnmarshal(resp.body, &out)
+ return out, err
+}
+
+// CreateContainer creates a blob container within the storage account
+// with given name and access level. Returns error if container already exists.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179468.aspx
+func (b BlobStorageClient) CreateContainer(name string, access ContainerAccessType) error {
+ resp, err := b.createContainer(name, access)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// CreateContainerIfNotExists creates a blob container if it does not exist. Returns
+// true if container is newly created or false if container already exists.
+func (b BlobStorageClient) CreateContainerIfNotExists(name string, access ContainerAccessType) (bool, error) {
+ resp, err := b.createContainer(name, access)
+ if resp != nil {
+ defer resp.body.Close()
+ if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict {
+ return resp.statusCode == http.StatusCreated, nil
+ }
+ }
+ return false, err
+}
+
+func (b BlobStorageClient) createContainer(name string, access ContainerAccessType) (*storageResponse, error) {
+ verb := "PUT"
+ uri := b.client.getEndpoint(blobServiceName, pathForContainer(name), url.Values{"restype": {"container"}})
+
+ headers := b.client.getStandardHeaders()
+ if access != "" {
+ headers["x-ms-blob-public-access"] = string(access)
+ }
+ return b.client.exec(verb, uri, headers, nil)
+}
+
+// ContainerExists returns true if a container with given name exists
+// on the storage account, otherwise returns false.
+func (b BlobStorageClient) ContainerExists(name string) (bool, error) {
+ verb := "HEAD"
+ uri := b.client.getEndpoint(blobServiceName, pathForContainer(name), url.Values{"restype": {"container"}})
+ headers := b.client.getStandardHeaders()
+
+ resp, err := b.client.exec(verb, uri, headers, nil)
+ if resp != nil {
+ defer resp.body.Close()
+ if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound {
+ return resp.statusCode == http.StatusOK, nil
+ }
+ }
+ return false, err
+}
+
+// DeleteContainer deletes the container with given name on the storage
+// account. If the container does not exist returns error.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179408.aspx
+func (b BlobStorageClient) DeleteContainer(name string) error {
+ resp, err := b.deleteContainer(name)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusAccepted})
+}
+
+// DeleteContainerIfExists deletes the container with given name on the storage
+// account if it exists. Returns true if container is deleted with this call, or
+// false if the container did not exist at the time of the Delete Container
+// operation.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179408.aspx
+func (b BlobStorageClient) DeleteContainerIfExists(name string) (bool, error) {
+ resp, err := b.deleteContainer(name)
+ if resp != nil {
+ defer resp.body.Close()
+ if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
+ return resp.statusCode == http.StatusAccepted, nil
+ }
+ }
+ return false, err
+}
+
+func (b BlobStorageClient) deleteContainer(name string) (*storageResponse, error) {
+ verb := "DELETE"
+ uri := b.client.getEndpoint(blobServiceName, pathForContainer(name), url.Values{"restype": {"container"}})
+
+ headers := b.client.getStandardHeaders()
+ return b.client.exec(verb, uri, headers, nil)
+}
+
+// ListBlobs returns an object that contains list of blobs in the container,
+// pagination token and other information in the response of List Blobs call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd135734.aspx
+func (b BlobStorageClient) ListBlobs(container string, params ListBlobsParameters) (BlobListResponse, error) {
+ q := mergeParams(params.getParameters(), url.Values{
+ "restype": {"container"},
+ "comp": {"list"}})
+ uri := b.client.getEndpoint(blobServiceName, pathForContainer(container), q)
+ headers := b.client.getStandardHeaders()
+
+ var out BlobListResponse
+ resp, err := b.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return out, err
+ }
+ defer resp.body.Close()
+
+ err = xmlUnmarshal(resp.body, &out)
+ return out, err
+}
+
+// BlobExists returns true if a blob with given name exists on the specified
+// container of the storage account.
+func (b BlobStorageClient) BlobExists(container, name string) (bool, error) {
+ verb := "HEAD"
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{})
+ headers := b.client.getStandardHeaders()
+ resp, err := b.client.exec(verb, uri, headers, nil)
+ if resp != nil {
+ defer resp.body.Close()
+ if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound {
+ return resp.statusCode == http.StatusOK, nil
+ }
+ }
+ return false, err
+}
+
+// GetBlobURL gets the canonical URL to the blob with the specified name in the
+// specified container. This method does not create a publicly accessible URL if
+// the blob or container is private and this method does not check if the blob
+// exists.
+func (b BlobStorageClient) GetBlobURL(container, name string) string {
+ if container == "" {
+ container = "$root"
+ }
+ return b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{})
+}
+
+// GetBlob returns a stream to read the blob. Caller must call Close() the
+// reader to close on the underlying connection.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179440.aspx
+func (b BlobStorageClient) GetBlob(container, name string) (io.ReadCloser, error) {
+ resp, err := b.getBlobRange(container, name, "", nil)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return nil, err
+ }
+ return resp.body, nil
+}
+
+// GetBlobRange reads the specified range of a blob to a stream. The bytesRange
+// string must be in a format like "0-", "10-100" as defined in HTTP 1.1 spec.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179440.aspx
+func (b BlobStorageClient) GetBlobRange(container, name, bytesRange string, extraHeaders map[string]string) (io.ReadCloser, error) {
+ resp, err := b.getBlobRange(container, name, bytesRange, extraHeaders)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusPartialContent}); err != nil {
+ return nil, err
+ }
+ return resp.body, nil
+}
+
+func (b BlobStorageClient) getBlobRange(container, name, bytesRange string, extraHeaders map[string]string) (*storageResponse, error) {
+ verb := "GET"
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{})
+
+ headers := b.client.getStandardHeaders()
+ if bytesRange != "" {
+ headers["Range"] = fmt.Sprintf("bytes=%s", bytesRange)
+ }
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec(verb, uri, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ return resp, err
+}
+
+// leasePut is common PUT code for the various aquire/release/break etc functions.
+func (b BlobStorageClient) leaseCommonPut(container string, name string, headers map[string]string, expectedStatus int) (http.Header, error) {
+ params := url.Values{"comp": {"lease"}}
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params)
+
+ resp, err := b.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{expectedStatus}); err != nil {
+ return nil, err
+ }
+
+ return resp.headers, nil
+}
+
+// AcquireLease creates a lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
+// returns leaseID acquired
+func (b BlobStorageClient) AcquireLease(container string, name string, leaseTimeInSeconds int, proposedLeaseID string) (returnedLeaseID string, err error) {
+ headers := b.client.getStandardHeaders()
+ headers[leaseAction] = acquireLease
+ headers[leaseProposedID] = proposedLeaseID
+ headers[leaseDuration] = strconv.Itoa(leaseTimeInSeconds)
+
+ respHeaders, err := b.leaseCommonPut(container, name, headers, http.StatusCreated)
+ if err != nil {
+ return "", err
+ }
+
+ returnedLeaseID = respHeaders.Get(http.CanonicalHeaderKey(leaseID))
+
+ if returnedLeaseID != "" {
+ return returnedLeaseID, nil
+ }
+
+ // what should we return in case of HTTP 201 but no lease ID?
+ // or it just cant happen? (brave words)
+ return "", errors.New("LeaseID not returned")
+}
+
+// BreakLease breaks the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
+// Returns the timeout remaining in the lease in seconds
+func (b BlobStorageClient) BreakLease(container string, name string) (breakTimeout int, err error) {
+ headers := b.client.getStandardHeaders()
+ headers[leaseAction] = breakLease
+ return b.breakLeaseCommon(container, name, headers)
+}
+
+// BreakLeaseWithBreakPeriod breaks the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
+// breakPeriodInSeconds is used to determine how long until new lease can be created.
+// Returns the timeout remaining in the lease in seconds
+func (b BlobStorageClient) BreakLeaseWithBreakPeriod(container string, name string, breakPeriodInSeconds int) (breakTimeout int, err error) {
+ headers := b.client.getStandardHeaders()
+ headers[leaseAction] = breakLease
+ headers[leaseBreakPeriod] = strconv.Itoa(breakPeriodInSeconds)
+ return b.breakLeaseCommon(container, name, headers)
+}
+
+// breakLeaseCommon is common code for both version of BreakLease (with and without break period)
+func (b BlobStorageClient) breakLeaseCommon(container string, name string, headers map[string]string) (breakTimeout int, err error) {
+
+ respHeaders, err := b.leaseCommonPut(container, name, headers, http.StatusAccepted)
+ 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 as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
+// Returns the new LeaseID acquired
+func (b BlobStorageClient) ChangeLease(container string, name string, currentLeaseID string, proposedLeaseID string) (newLeaseID string, err error) {
+ headers := b.client.getStandardHeaders()
+ headers[leaseAction] = changeLease
+ headers[leaseID] = currentLeaseID
+ headers[leaseProposedID] = proposedLeaseID
+
+ respHeaders, err := b.leaseCommonPut(container, name, headers, http.StatusOK)
+ if err != nil {
+ return "", err
+ }
+
+ newLeaseID = respHeaders.Get(http.CanonicalHeaderKey(leaseID))
+ if newLeaseID != "" {
+ return newLeaseID, nil
+ }
+
+ return "", errors.New("LeaseID not returned")
+}
+
+// ReleaseLease releases the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
+func (b BlobStorageClient) ReleaseLease(container string, name string, currentLeaseID string) error {
+ headers := b.client.getStandardHeaders()
+ headers[leaseAction] = releaseLease
+ headers[leaseID] = currentLeaseID
+
+ _, err := b.leaseCommonPut(container, name, headers, http.StatusOK)
+ 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 BlobStorageClient) RenewLease(container string, name string, currentLeaseID string) error {
+ headers := b.client.getStandardHeaders()
+ headers[leaseAction] = renewLease
+ headers[leaseID] = currentLeaseID
+
+ _, err := b.leaseCommonPut(container, name, headers, http.StatusOK)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// GetBlobProperties provides various information about the specified
+// blob. See https://msdn.microsoft.com/en-us/library/azure/dd179394.aspx
+func (b BlobStorageClient) GetBlobProperties(container, name string) (*BlobProperties, error) {
+ verb := "HEAD"
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{})
+
+ headers := b.client.getStandardHeaders()
+ resp, err := b.client.exec(verb, uri, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return nil, err
+ }
+
+ var contentLength int64
+ contentLengthStr := resp.headers.Get("Content-Length")
+ if contentLengthStr != "" {
+ contentLength, err = strconv.ParseInt(contentLengthStr, 0, 64)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ var sequenceNum int64
+ sequenceNumStr := resp.headers.Get("x-ms-blob-sequence-number")
+ if sequenceNumStr != "" {
+ sequenceNum, err = strconv.ParseInt(sequenceNumStr, 0, 64)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return &BlobProperties{
+ LastModified: resp.headers.Get("Last-Modified"),
+ Etag: resp.headers.Get("Etag"),
+ ContentMD5: resp.headers.Get("Content-MD5"),
+ ContentLength: contentLength,
+ ContentEncoding: resp.headers.Get("Content-Encoding"),
+ ContentType: resp.headers.Get("Content-Type"),
+ CacheControl: resp.headers.Get("Cache-Control"),
+ ContentLanguage: resp.headers.Get("Content-Language"),
+ SequenceNumber: sequenceNum,
+ CopyCompletionTime: resp.headers.Get("x-ms-copy-completion-time"),
+ CopyStatusDescription: resp.headers.Get("x-ms-copy-status-description"),
+ CopyID: resp.headers.Get("x-ms-copy-id"),
+ CopyProgress: resp.headers.Get("x-ms-copy-progress"),
+ CopySource: resp.headers.Get("x-ms-copy-source"),
+ CopyStatus: resp.headers.Get("x-ms-copy-status"),
+ BlobType: BlobType(resp.headers.Get("x-ms-blob-type")),
+ LeaseStatus: resp.headers.Get("x-ms-lease-status"),
+ }, nil
+}
+
+// SetBlobProperties replaces the BlobHeaders for the specified blob.
+//
+// Some keys may be converted to Camel-Case before sending. All keys
+// are returned in lower case by GetBlobProperties. HTTP header names
+// are case-insensitive so case munging should not matter to other
+// applications either.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/ee691966.aspx
+func (b BlobStorageClient) SetBlobProperties(container, name string, blobHeaders BlobHeaders) error {
+ params := url.Values{"comp": {"properties"}}
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params)
+ headers := b.client.getStandardHeaders()
+
+ extraHeaders := headersFromStruct(blobHeaders)
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusOK})
+}
+
+// SetBlobMetadata replaces the metadata for the specified blob.
+//
+// Some keys may be converted to Camel-Case before sending. All keys
+// are returned in lower case by GetBlobMetadata. HTTP header names
+// are case-insensitive so case munging should not matter to other
+// applications either.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
+func (b BlobStorageClient) SetBlobMetadata(container, name string, metadata map[string]string, extraHeaders map[string]string) error {
+ params := url.Values{"comp": {"metadata"}}
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params)
+ headers := b.client.getStandardHeaders()
+ for k, v := range metadata {
+ headers[userDefinedMetadataHeaderPrefix+k] = v
+ }
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusOK})
+}
+
+// GetBlobMetadata returns all user-defined metadata for the specified blob.
+//
+// All metadata keys will be returned in lower case. (HTTP header
+// names are case-insensitive.)
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
+func (b BlobStorageClient) GetBlobMetadata(container, name string) (map[string]string, error) {
+ params := url.Values{"comp": {"metadata"}}
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params)
+ headers := b.client.getStandardHeaders()
+
+ resp, err := b.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return nil, err
+ }
+
+ metadata := make(map[string]string)
+ for k, v := range resp.headers {
+ // Can't trust CanonicalHeaderKey() to munge case
+ // reliably. "_" is allowed in identifiers:
+ // https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
+ // https://msdn.microsoft.com/library/aa664670(VS.71).aspx
+ // http://tools.ietf.org/html/rfc7230#section-3.2
+ // ...but "_" is considered invalid by
+ // CanonicalMIMEHeaderKey in
+ // https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542
+ // so k can be "X-Ms-Meta-Foo" or "x-ms-meta-foo_bar".
+ k = strings.ToLower(k)
+ if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) {
+ continue
+ }
+ // metadata["foo"] = content of the last X-Ms-Meta-Foo header
+ k = k[len(userDefinedMetadataHeaderPrefix):]
+ metadata[k] = v[len(v)-1]
+ }
+ return metadata, nil
+}
+
+// CreateBlockBlob initializes an empty block blob with no blocks.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx
+func (b BlobStorageClient) CreateBlockBlob(container, name string) error {
+ return b.CreateBlockBlobFromReader(container, name, 0, nil, nil)
+}
+
+// CreateBlockBlobFromReader initializes a block blob using data from
+// reader. Size must be the number of bytes read from reader. To
+// create an empty blob, use size==0 and reader==nil.
+//
+// The API rejects requests with size > 64 MiB (but this limit is not
+// checked by the SDK). To write a larger blob, use CreateBlockBlob,
+// PutBlock, and PutBlockList.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx
+func (b BlobStorageClient) CreateBlockBlobFromReader(container, name string, size uint64, blob io.Reader, extraHeaders map[string]string) error {
+ path := fmt.Sprintf("%s/%s", container, name)
+ uri := b.client.getEndpoint(blobServiceName, path, url.Values{})
+ headers := b.client.getStandardHeaders()
+ headers["x-ms-blob-type"] = string(BlobTypeBlock)
+ headers["Content-Length"] = fmt.Sprintf("%d", size)
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec("PUT", uri, headers, blob)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// PutBlock saves the given data chunk to the specified block blob with
+// given ID.
+//
+// The API rejects chunks larger than 4 MiB (but this limit is not
+// checked by the SDK).
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd135726.aspx
+func (b BlobStorageClient) PutBlock(container, name, blockID string, chunk []byte) error {
+ return b.PutBlockWithLength(container, name, blockID, uint64(len(chunk)), bytes.NewReader(chunk), nil)
+}
+
+// PutBlockWithLength saves the given data stream of exactly specified size to
+// the block blob with given ID. It is an alternative to PutBlocks where data
+// comes as stream but the length is known in advance.
+//
+// The API rejects requests with size > 4 MiB (but this limit is not
+// checked by the SDK).
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd135726.aspx
+func (b BlobStorageClient) PutBlockWithLength(container, name, blockID string, size uint64, blob io.Reader, extraHeaders map[string]string) error {
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{"comp": {"block"}, "blockid": {blockID}})
+ headers := b.client.getStandardHeaders()
+ headers["x-ms-blob-type"] = string(BlobTypeBlock)
+ headers["Content-Length"] = fmt.Sprintf("%v", size)
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec("PUT", uri, headers, blob)
+ if err != nil {
+ return err
+ }
+
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// PutBlockList saves list of blocks to the specified block blob.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179467.aspx
+func (b BlobStorageClient) PutBlockList(container, name string, blocks []Block) error {
+ blockListXML := prepareBlockListRequest(blocks)
+
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{"comp": {"blocklist"}})
+ headers := b.client.getStandardHeaders()
+ headers["Content-Length"] = fmt.Sprintf("%v", len(blockListXML))
+
+ resp, err := b.client.exec("PUT", uri, headers, strings.NewReader(blockListXML))
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// GetBlockList retrieves list of blocks in the specified block blob.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx
+func (b BlobStorageClient) GetBlockList(container, name string, blockType BlockListType) (BlockListResponse, error) {
+ params := url.Values{"comp": {"blocklist"}, "blocklisttype": {string(blockType)}}
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params)
+ headers := b.client.getStandardHeaders()
+
+ var out BlockListResponse
+ resp, err := b.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return out, err
+ }
+ defer resp.body.Close()
+
+ err = xmlUnmarshal(resp.body, &out)
+ return out, err
+}
+
+// PutPageBlob initializes an empty page blob with specified name and maximum
+// size in bytes (size must be aligned to a 512-byte boundary). A page blob must
+// be created using this method before writing pages.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx
+func (b BlobStorageClient) PutPageBlob(container, name string, size int64, extraHeaders map[string]string) error {
+ path := fmt.Sprintf("%s/%s", container, name)
+ uri := b.client.getEndpoint(blobServiceName, path, url.Values{})
+ headers := b.client.getStandardHeaders()
+ headers["x-ms-blob-type"] = string(BlobTypePage)
+ headers["x-ms-blob-content-length"] = fmt.Sprintf("%v", size)
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// PutPage writes a range of pages to a page blob or clears the given range.
+// In case of 'clear' writes, given chunk is discarded. Ranges must be aligned
+// with 512-byte boundaries and chunk must be of size multiplies by 512.
+//
+// See https://msdn.microsoft.com/en-us/library/ee691975.aspx
+func (b BlobStorageClient) PutPage(container, name string, startByte, endByte int64, writeType PageWriteType, chunk []byte, extraHeaders map[string]string) error {
+ path := fmt.Sprintf("%s/%s", container, name)
+ uri := b.client.getEndpoint(blobServiceName, path, url.Values{"comp": {"page"}})
+ headers := b.client.getStandardHeaders()
+ headers["x-ms-blob-type"] = string(BlobTypePage)
+ headers["x-ms-page-write"] = string(writeType)
+ headers["x-ms-range"] = fmt.Sprintf("bytes=%v-%v", startByte, endByte)
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+ var contentLength int64
+ var data io.Reader
+ if writeType == PageWriteTypeClear {
+ contentLength = 0
+ data = bytes.NewReader([]byte{})
+ } else {
+ contentLength = int64(len(chunk))
+ data = bytes.NewReader(chunk)
+ }
+ headers["Content-Length"] = fmt.Sprintf("%v", contentLength)
+
+ resp, err := b.client.exec("PUT", uri, headers, data)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// GetPageRanges returns the list of valid page ranges for a page blob.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx
+func (b BlobStorageClient) GetPageRanges(container, name string) (GetPageRangesResponse, error) {
+ path := fmt.Sprintf("%s/%s", container, name)
+ uri := b.client.getEndpoint(blobServiceName, path, url.Values{"comp": {"pagelist"}})
+ headers := b.client.getStandardHeaders()
+
+ var out GetPageRangesResponse
+ resp, err := b.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return out, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return out, err
+ }
+ err = xmlUnmarshal(resp.body, &out)
+ return out, err
+}
+
+// PutAppendBlob initializes an empty append blob with specified name. An
+// append blob must be created using this method before appending blocks.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx
+func (b BlobStorageClient) PutAppendBlob(container, name string, extraHeaders map[string]string) error {
+ path := fmt.Sprintf("%s/%s", container, name)
+ uri := b.client.getEndpoint(blobServiceName, path, url.Values{})
+ headers := b.client.getStandardHeaders()
+ headers["x-ms-blob-type"] = string(BlobTypeAppend)
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// AppendBlock appends a block to an append blob.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/mt427365.aspx
+func (b BlobStorageClient) AppendBlock(container, name string, chunk []byte, extraHeaders map[string]string) error {
+ path := fmt.Sprintf("%s/%s", container, name)
+ uri := b.client.getEndpoint(blobServiceName, path, url.Values{"comp": {"appendblock"}})
+ headers := b.client.getStandardHeaders()
+ headers["x-ms-blob-type"] = string(BlobTypeAppend)
+ headers["Content-Length"] = fmt.Sprintf("%v", len(chunk))
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := b.client.exec("PUT", uri, headers, bytes.NewReader(chunk))
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// CopyBlob starts a blob copy operation and waits for the operation to
+// complete. sourceBlob parameter must be a canonical URL to the blob (can be
+// obtained using GetBlobURL method.) There is no SLA on blob copy and therefore
+// this helper method works faster on smaller files.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd894037.aspx
+func (b BlobStorageClient) CopyBlob(container, name, sourceBlob string) error {
+ copyID, err := b.startBlobCopy(container, name, sourceBlob)
+ if err != nil {
+ return err
+ }
+
+ return b.waitForBlobCopy(container, name, copyID)
+}
+
+func (b BlobStorageClient) startBlobCopy(container, name, sourceBlob string) (string, error) {
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{})
+
+ headers := b.client.getStandardHeaders()
+ headers["x-ms-copy-source"] = sourceBlob
+
+ resp, err := b.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return "", err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusAccepted, http.StatusCreated}); err != nil {
+ return "", err
+ }
+
+ copyID := resp.headers.Get("x-ms-copy-id")
+ if copyID == "" {
+ return "", errors.New("Got empty copy id header")
+ }
+ return copyID, nil
+}
+
+func (b BlobStorageClient) waitForBlobCopy(container, name, copyID string) error {
+ for {
+ props, err := b.GetBlobProperties(container, name)
+ if err != nil {
+ return err
+ }
+
+ if props.CopyID != copyID {
+ return errBlobCopyIDMismatch
+ }
+
+ switch props.CopyStatus {
+ case blobCopyStatusSuccess:
+ return nil
+ case blobCopyStatusPending:
+ continue
+ case blobCopyStatusAborted:
+ return errBlobCopyAborted
+ case blobCopyStatusFailed:
+ return fmt.Errorf("storage: blob copy failed. Id=%s Description=%s", props.CopyID, props.CopyStatusDescription)
+ default:
+ return fmt.Errorf("storage: unhandled blob copy status: '%s'", props.CopyStatus)
+ }
+ }
+}
+
+// DeleteBlob deletes the given blob from the specified container.
+// If the blob does not exists at the time of the Delete Blob operation, it
+// returns error. See https://msdn.microsoft.com/en-us/library/azure/dd179413.aspx
+func (b BlobStorageClient) DeleteBlob(container, name string, extraHeaders map[string]string) error {
+ resp, err := b.deleteBlob(container, name, extraHeaders)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusAccepted})
+}
+
+// DeleteBlobIfExists deletes the given blob from the specified container If the
+// blob is deleted with this call, returns true. Otherwise returns false.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179413.aspx
+func (b BlobStorageClient) DeleteBlobIfExists(container, name string, extraHeaders map[string]string) (bool, error) {
+ resp, err := b.deleteBlob(container, name, extraHeaders)
+ if resp != nil && (resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound) {
+ return resp.statusCode == http.StatusAccepted, nil
+ }
+ defer resp.body.Close()
+ return false, err
+}
+
+func (b BlobStorageClient) deleteBlob(container, name string, extraHeaders map[string]string) (*storageResponse, error) {
+ verb := "DELETE"
+ uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{})
+ headers := b.client.getStandardHeaders()
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ return b.client.exec(verb, uri, headers, nil)
+}
+
+// helper method to construct the path to a container given its name
+func pathForContainer(name string) string {
+ return fmt.Sprintf("/%s", name)
+}
+
+// helper method to construct the path to a blob given its container and blob
+// name
+func pathForBlob(container, name string) string {
+ return fmt.Sprintf("/%s/%s", container, name)
+}
+
+// GetBlobSASURI creates an URL to the specified blob which contains the Shared
+// Access Signature with specified permissions and expiration time.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/ee395415.aspx
+func (b BlobStorageClient) GetBlobSASURI(container, name string, expiry time.Time, permissions string) (string, error) {
+ var (
+ signedPermissions = permissions
+ blobURL = b.GetBlobURL(container, name)
+ )
+ canonicalizedResource, err := b.client.buildCanonicalizedResource(blobURL)
+
+ if err != nil {
+ return "", err
+ }
+
+ // "The canonicalizedresouce portion of the string is a canonical path to the signed resource.
+ // It must include the service name (blob, table, queue or file) for version 2015-02-21 or
+ // later, the storage account name, and the resource name, and must be URL-decoded.
+ // -- https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
+
+ // We need to replace + with %2b first to avoid being treated as a space (which is correct for query strings, but not the path component).
+ canonicalizedResource = strings.Replace(canonicalizedResource, "+", "%2b", -1)
+
+ canonicalizedResource, err = url.QueryUnescape(canonicalizedResource)
+ if err != nil {
+ return "", err
+ }
+
+ signedExpiry := expiry.UTC().Format(time.RFC3339)
+ signedResource := "b"
+
+ stringToSign, err := blobSASStringToSign(b.client.apiVersion, canonicalizedResource, signedExpiry, signedPermissions)
+ if err != nil {
+ return "", err
+ }
+
+ sig := b.client.computeHmac256(stringToSign)
+ sasParams := url.Values{
+ "sv": {b.client.apiVersion},
+ "se": {signedExpiry},
+ "sr": {signedResource},
+ "sp": {signedPermissions},
+ "sig": {sig},
+ }
+
+ sasURL, err := url.Parse(blobURL)
+ if err != nil {
+ return "", err
+ }
+ sasURL.RawQuery = sasParams.Encode()
+ return sasURL.String(), nil
+}
+
+func blobSASStringToSign(signedVersion, canonicalizedResource, signedExpiry, signedPermissions string) (string, error) {
+ var signedStart, signedIdentifier, rscc, rscd, rsce, rscl, rsct string
+
+ if signedVersion >= "2015-02-21" {
+ canonicalizedResource = "/blob" + canonicalizedResource
+ }
+
+ // reference: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
+ if signedVersion >= "2013-08-15" {
+ return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedVersion, rscc, rscd, rsce, rscl, rsct), nil
+ }
+ return "", errors.New("storage: not implemented SAS for versions earlier than 2013-08-15")
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/client.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/client.go
new file mode 100644
index 000000000..2816e03ec
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/client.go
@@ -0,0 +1,551 @@
+// Package storage provides clients for Microsoft Azure Storage Services.
+package storage
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+const (
+ // DefaultBaseURL is the domain name used for storage requests when a
+ // default client is created.
+ DefaultBaseURL = "core.windows.net"
+
+ // DefaultAPIVersion is the Azure Storage API version string used when a
+ // basic client is created.
+ DefaultAPIVersion = "2015-02-21"
+
+ defaultUseHTTPS = true
+
+ // StorageEmulatorAccountName is the fixed storage account used by Azure Storage Emulator
+ StorageEmulatorAccountName = "devstoreaccount1"
+
+ // StorageEmulatorAccountKey is the the fixed storage account used by Azure Storage Emulator
+ StorageEmulatorAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
+
+ blobServiceName = "blob"
+ tableServiceName = "table"
+ queueServiceName = "queue"
+ fileServiceName = "file"
+
+ storageEmulatorBlob = "127.0.0.1:10000"
+ storageEmulatorTable = "127.0.0.1:10002"
+ storageEmulatorQueue = "127.0.0.1:10001"
+)
+
+// Client is the object that needs to be constructed to perform
+// operations on the storage account.
+type Client struct {
+ // HTTPClient is the http.Client used to initiate API
+ // requests. If it is nil, http.DefaultClient is used.
+ HTTPClient *http.Client
+
+ accountName string
+ accountKey []byte
+ useHTTPS bool
+ baseURL string
+ apiVersion string
+}
+
+type storageResponse struct {
+ statusCode int
+ headers http.Header
+ body io.ReadCloser
+}
+
+type odataResponse struct {
+ storageResponse
+ odata odataErrorMessage
+}
+
+// AzureStorageServiceError contains fields of the error response from
+// Azure Storage Service REST API. See https://msdn.microsoft.com/en-us/library/azure/dd179382.aspx
+// Some fields might be specific to certain calls.
+type AzureStorageServiceError struct {
+ Code string `xml:"Code"`
+ Message string `xml:"Message"`
+ AuthenticationErrorDetail string `xml:"AuthenticationErrorDetail"`
+ QueryParameterName string `xml:"QueryParameterName"`
+ QueryParameterValue string `xml:"QueryParameterValue"`
+ Reason string `xml:"Reason"`
+ StatusCode int
+ RequestID string
+}
+
+type odataErrorMessageMessage struct {
+ Lang string `json:"lang"`
+ Value string `json:"value"`
+}
+
+type odataErrorMessageInternal struct {
+ Code string `json:"code"`
+ Message odataErrorMessageMessage `json:"message"`
+}
+
+type odataErrorMessage struct {
+ Err odataErrorMessageInternal `json:"odata.error"`
+}
+
+// UnexpectedStatusCodeError is returned when a storage service responds with neither an error
+// nor with an HTTP status code indicating success.
+type UnexpectedStatusCodeError struct {
+ allowed []int
+ got int
+}
+
+func (e UnexpectedStatusCodeError) Error() string {
+ s := func(i int) string { return fmt.Sprintf("%d %s", i, http.StatusText(i)) }
+
+ got := s(e.got)
+ expected := []string{}
+ for _, v := range e.allowed {
+ expected = append(expected, s(v))
+ }
+ return fmt.Sprintf("storage: status code from service response is %s; was expecting %s", got, strings.Join(expected, " or "))
+}
+
+// Got is the actual status code returned by Azure.
+func (e UnexpectedStatusCodeError) Got() int {
+ return e.got
+}
+
+// NewBasicClient constructs a Client with given storage service name and
+// key.
+func NewBasicClient(accountName, accountKey string) (Client, error) {
+ if accountName == StorageEmulatorAccountName {
+ return NewEmulatorClient()
+ }
+ return NewClient(accountName, accountKey, DefaultBaseURL, DefaultAPIVersion, defaultUseHTTPS)
+}
+
+//NewEmulatorClient contructs a Client intended to only work with Azure
+//Storage Emulator
+func NewEmulatorClient() (Client, error) {
+ return NewClient(StorageEmulatorAccountName, StorageEmulatorAccountKey, DefaultBaseURL, DefaultAPIVersion, false)
+}
+
+// NewClient constructs a Client. This should be used if the caller wants
+// to specify whether to use HTTPS, a specific REST API version or a custom
+// storage endpoint than Azure Public Cloud.
+func NewClient(accountName, accountKey, blobServiceBaseURL, apiVersion string, useHTTPS bool) (Client, error) {
+ var c Client
+ if accountName == "" {
+ return c, fmt.Errorf("azure: account name required")
+ } else if accountKey == "" {
+ return c, fmt.Errorf("azure: account key required")
+ } else if blobServiceBaseURL == "" {
+ return c, fmt.Errorf("azure: base storage service url required")
+ }
+
+ key, err := base64.StdEncoding.DecodeString(accountKey)
+ if err != nil {
+ return c, fmt.Errorf("azure: malformed storage account key: %v", err)
+ }
+
+ return Client{
+ accountName: accountName,
+ accountKey: key,
+ useHTTPS: useHTTPS,
+ baseURL: blobServiceBaseURL,
+ apiVersion: apiVersion,
+ }, nil
+}
+
+func (c Client) getBaseURL(service string) string {
+ scheme := "http"
+ if c.useHTTPS {
+ scheme = "https"
+ }
+ host := ""
+ if c.accountName == StorageEmulatorAccountName {
+ switch service {
+ case blobServiceName:
+ host = storageEmulatorBlob
+ case tableServiceName:
+ host = storageEmulatorTable
+ case queueServiceName:
+ host = storageEmulatorQueue
+ }
+ } else {
+ host = fmt.Sprintf("%s.%s.%s", c.accountName, service, c.baseURL)
+ }
+
+ u := &url.URL{
+ Scheme: scheme,
+ Host: host}
+ return u.String()
+}
+
+func (c Client) getEndpoint(service, path string, params url.Values) string {
+ u, err := url.Parse(c.getBaseURL(service))
+ if err != nil {
+ // really should not be happening
+ panic(err)
+ }
+
+ // API doesn't accept path segments not starting with '/'
+ if !strings.HasPrefix(path, "/") {
+ path = fmt.Sprintf("/%v", path)
+ }
+
+ if c.accountName == StorageEmulatorAccountName {
+ path = fmt.Sprintf("/%v%v", StorageEmulatorAccountName, path)
+ }
+
+ u.Path = path
+ u.RawQuery = params.Encode()
+ return u.String()
+}
+
+// GetBlobService returns a BlobStorageClient which can operate on the blob
+// service of the storage account.
+func (c Client) GetBlobService() BlobStorageClient {
+ return BlobStorageClient{c}
+}
+
+// GetQueueService returns a QueueServiceClient which can operate on the queue
+// service of the storage account.
+func (c Client) GetQueueService() QueueServiceClient {
+ return QueueServiceClient{c}
+}
+
+// GetTableService returns a TableServiceClient which can operate on the table
+// service of the storage account.
+func (c Client) GetTableService() TableServiceClient {
+ return TableServiceClient{c}
+}
+
+// GetFileService returns a FileServiceClient which can operate on the file
+// service of the storage account.
+func (c Client) GetFileService() FileServiceClient {
+ return FileServiceClient{c}
+}
+
+func (c Client) createAuthorizationHeader(canonicalizedString string) string {
+ signature := c.computeHmac256(canonicalizedString)
+ return fmt.Sprintf("%s %s:%s", "SharedKey", c.getCanonicalizedAccountName(), signature)
+}
+
+func (c Client) getAuthorizationHeader(verb, url string, headers map[string]string) (string, error) {
+ canonicalizedResource, err := c.buildCanonicalizedResource(url)
+ if err != nil {
+ return "", err
+ }
+
+ canonicalizedString := c.buildCanonicalizedString(verb, headers, canonicalizedResource)
+ return c.createAuthorizationHeader(canonicalizedString), nil
+}
+
+func (c Client) getStandardHeaders() map[string]string {
+ return map[string]string{
+ "x-ms-version": c.apiVersion,
+ "x-ms-date": currentTimeRfc1123Formatted(),
+ }
+}
+
+func (c Client) getCanonicalizedAccountName() string {
+ // since we may be trying to access a secondary storage account, we need to
+ // remove the -secondary part of the storage name
+ return strings.TrimSuffix(c.accountName, "-secondary")
+}
+
+func (c Client) buildCanonicalizedHeader(headers map[string]string) string {
+ cm := make(map[string]string)
+
+ for k, v := range headers {
+ headerName := strings.TrimSpace(strings.ToLower(k))
+ match, _ := regexp.MatchString("x-ms-", headerName)
+ if match {
+ cm[headerName] = v
+ }
+ }
+
+ if len(cm) == 0 {
+ return ""
+ }
+
+ keys := make([]string, 0, len(cm))
+ for key := range cm {
+ keys = append(keys, key)
+ }
+
+ sort.Strings(keys)
+
+ ch := ""
+
+ for i, key := range keys {
+ if i == len(keys)-1 {
+ ch += fmt.Sprintf("%s:%s", key, cm[key])
+ } else {
+ ch += fmt.Sprintf("%s:%s\n", key, cm[key])
+ }
+ }
+ return ch
+}
+
+func (c Client) buildCanonicalizedResourceTable(uri string) (string, error) {
+ errMsg := "buildCanonicalizedResourceTable error: %s"
+ u, err := url.Parse(uri)
+ if err != nil {
+ return "", fmt.Errorf(errMsg, err.Error())
+ }
+
+ cr := "/" + c.getCanonicalizedAccountName()
+
+ if len(u.Path) > 0 {
+ cr += u.Path
+ }
+
+ return cr, nil
+}
+
+func (c Client) buildCanonicalizedResource(uri string) (string, error) {
+ errMsg := "buildCanonicalizedResource error: %s"
+ u, err := url.Parse(uri)
+ if err != nil {
+ return "", fmt.Errorf(errMsg, err.Error())
+ }
+
+ cr := "/" + c.getCanonicalizedAccountName()
+
+ if len(u.Path) > 0 {
+ // Any portion of the CanonicalizedResource string that is derived from
+ // the resource's URI should be encoded exactly as it is in the URI.
+ // -- https://msdn.microsoft.com/en-gb/library/azure/dd179428.aspx
+ cr += u.EscapedPath()
+ }
+
+ params, err := url.ParseQuery(u.RawQuery)
+ if err != nil {
+ return "", fmt.Errorf(errMsg, err.Error())
+ }
+
+ if len(params) > 0 {
+ cr += "\n"
+ keys := make([]string, 0, len(params))
+ for key := range params {
+ keys = append(keys, key)
+ }
+
+ sort.Strings(keys)
+
+ for i, key := range keys {
+ if len(params[key]) > 1 {
+ sort.Strings(params[key])
+ }
+
+ if i == len(keys)-1 {
+ cr += fmt.Sprintf("%s:%s", key, strings.Join(params[key], ","))
+ } else {
+ cr += fmt.Sprintf("%s:%s\n", key, strings.Join(params[key], ","))
+ }
+ }
+ }
+
+ return cr, nil
+}
+
+func (c Client) buildCanonicalizedString(verb string, headers map[string]string, canonicalizedResource string) string {
+ contentLength := headers["Content-Length"]
+ if contentLength == "0" {
+ contentLength = ""
+ }
+ canonicalizedString := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
+ verb,
+ headers["Content-Encoding"],
+ headers["Content-Language"],
+ contentLength,
+ headers["Content-MD5"],
+ headers["Content-Type"],
+ headers["Date"],
+ headers["If-Modified-Since"],
+ headers["If-Match"],
+ headers["If-None-Match"],
+ headers["If-Unmodified-Since"],
+ headers["Range"],
+ c.buildCanonicalizedHeader(headers),
+ canonicalizedResource)
+
+ return canonicalizedString
+}
+
+func (c Client) exec(verb, url string, headers map[string]string, body io.Reader) (*storageResponse, error) {
+ authHeader, err := c.getAuthorizationHeader(verb, url, headers)
+ if err != nil {
+ return nil, err
+ }
+ headers["Authorization"] = authHeader
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(verb, url, body)
+ if err != nil {
+ return nil, errors.New("azure/storage: error creating request: " + err.Error())
+ }
+
+ if clstr, ok := headers["Content-Length"]; ok {
+ // content length header is being signed, but completely ignored by golang.
+ // instead we have to use the ContentLength property on the request struct
+ // (see https://golang.org/src/net/http/request.go?s=18140:18370#L536 and
+ // https://golang.org/src/net/http/transfer.go?s=1739:2467#L49)
+ req.ContentLength, err = strconv.ParseInt(clstr, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ }
+ for k, v := range headers {
+ req.Header.Add(k, v)
+ }
+
+ httpClient := c.HTTPClient
+ if httpClient == nil {
+ httpClient = http.DefaultClient
+ }
+ resp, err := httpClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+
+ statusCode := resp.StatusCode
+ if statusCode >= 400 && statusCode <= 505 {
+ var respBody []byte
+ respBody, err = readResponseBody(resp)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(respBody) == 0 {
+ // no error in response body
+ err = fmt.Errorf("storage: service returned without a response body (%s)", resp.Status)
+ } else {
+ // response contains storage service error object, unmarshal
+ storageErr, errIn := serviceErrFromXML(respBody, resp.StatusCode, resp.Header.Get("x-ms-request-id"))
+ if err != nil { // error unmarshaling the error response
+ err = errIn
+ }
+ err = storageErr
+ }
+ return &storageResponse{
+ statusCode: resp.StatusCode,
+ headers: resp.Header,
+ body: ioutil.NopCloser(bytes.NewReader(respBody)), /* restore the body */
+ }, err
+ }
+
+ return &storageResponse{
+ statusCode: resp.StatusCode,
+ headers: resp.Header,
+ body: resp.Body}, nil
+}
+
+func (c Client) execInternalJSON(verb, url string, headers map[string]string, body io.Reader) (*odataResponse, error) {
+ req, err := http.NewRequest(verb, url, body)
+ for k, v := range headers {
+ req.Header.Add(k, v)
+ }
+
+ httpClient := c.HTTPClient
+ if httpClient == nil {
+ httpClient = http.DefaultClient
+ }
+
+ resp, err := httpClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+
+ respToRet := &odataResponse{}
+ respToRet.body = resp.Body
+ respToRet.statusCode = resp.StatusCode
+ respToRet.headers = resp.Header
+
+ statusCode := resp.StatusCode
+ if statusCode >= 400 && statusCode <= 505 {
+ var respBody []byte
+ respBody, err = readResponseBody(resp)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(respBody) == 0 {
+ // no error in response body
+ err = fmt.Errorf("storage: service returned without a response body (%d)", resp.StatusCode)
+ return respToRet, err
+ }
+ // try unmarshal as odata.error json
+ err = json.Unmarshal(respBody, &respToRet.odata)
+ return respToRet, err
+ }
+
+ return respToRet, nil
+}
+
+func (c Client) createSharedKeyLite(url string, headers map[string]string) (string, error) {
+ can, err := c.buildCanonicalizedResourceTable(url)
+
+ if err != nil {
+ return "", err
+ }
+ strToSign := headers["x-ms-date"] + "\n" + can
+
+ hmac := c.computeHmac256(strToSign)
+ return fmt.Sprintf("SharedKeyLite %s:%s", c.accountName, hmac), nil
+}
+
+func (c Client) execTable(verb, url string, headers map[string]string, body io.Reader) (*odataResponse, error) {
+ var err error
+ headers["Authorization"], err = c.createSharedKeyLite(url, headers)
+ if err != nil {
+ return nil, err
+ }
+
+ return c.execInternalJSON(verb, url, headers, body)
+}
+
+func readResponseBody(resp *http.Response) ([]byte, error) {
+ defer resp.Body.Close()
+ out, err := ioutil.ReadAll(resp.Body)
+ if err == io.EOF {
+ err = nil
+ }
+ return out, err
+}
+
+func serviceErrFromXML(body []byte, statusCode int, requestID string) (AzureStorageServiceError, error) {
+ var storageErr AzureStorageServiceError
+ if err := xml.Unmarshal(body, &storageErr); err != nil {
+ return storageErr, err
+ }
+ storageErr.StatusCode = statusCode
+ storageErr.RequestID = requestID
+ return storageErr, nil
+}
+
+func (e AzureStorageServiceError) Error() string {
+ return fmt.Sprintf("storage: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=%s, RequestId=%s, QueryParameterName=%s, QueryParameterValue=%s",
+ e.StatusCode, e.Code, e.Message, e.RequestID, e.QueryParameterName, e.QueryParameterValue)
+}
+
+// checkRespCode returns UnexpectedStatusError if the given response code is not
+// one of the allowed status codes; otherwise nil.
+func checkRespCode(respCode int, allowed []int) error {
+ for _, v := range allowed {
+ if respCode == v {
+ return nil
+ }
+ }
+ return UnexpectedStatusCodeError{allowed, respCode}
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/file.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/file.go
new file mode 100644
index 000000000..2397587c8
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/file.go
@@ -0,0 +1,352 @@
+package storage
+
+import (
+ "encoding/xml"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// FileServiceClient contains operations for Microsoft Azure File Service.
+type FileServiceClient struct {
+ client Client
+}
+
+// A Share is an entry in ShareListResponse.
+type Share struct {
+ Name string `xml:"Name"`
+ Properties ShareProperties `xml:"Properties"`
+}
+
+// ShareProperties contains various properties of a share returned from
+// various endpoints like ListShares.
+type ShareProperties struct {
+ LastModified string `xml:"Last-Modified"`
+ Etag string `xml:"Etag"`
+ Quota string `xml:"Quota"`
+}
+
+// ShareListResponse contains the response fields from
+// ListShares call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dn167009.aspx
+type ShareListResponse struct {
+ XMLName xml.Name `xml:"EnumerationResults"`
+ Xmlns string `xml:"xmlns,attr"`
+ Prefix string `xml:"Prefix"`
+ Marker string `xml:"Marker"`
+ NextMarker string `xml:"NextMarker"`
+ MaxResults int64 `xml:"MaxResults"`
+ Shares []Share `xml:"Shares>Share"`
+}
+
+// ListSharesParameters defines the set of customizable parameters to make a
+// List Shares call.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dn167009.aspx
+type ListSharesParameters struct {
+ Prefix string
+ Marker string
+ Include string
+ MaxResults uint
+ Timeout uint
+}
+
+// ShareHeaders contains various properties of a file and is an entry
+// in SetShareProperties
+type ShareHeaders struct {
+ Quota string `header:"x-ms-share-quota"`
+}
+
+func (p ListSharesParameters) getParameters() url.Values {
+ out := url.Values{}
+
+ if p.Prefix != "" {
+ out.Set("prefix", p.Prefix)
+ }
+ if p.Marker != "" {
+ out.Set("marker", p.Marker)
+ }
+ if p.Include != "" {
+ out.Set("include", p.Include)
+ }
+ if p.MaxResults != 0 {
+ out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults))
+ }
+ if p.Timeout != 0 {
+ out.Set("timeout", fmt.Sprintf("%v", p.Timeout))
+ }
+
+ return out
+}
+
+// pathForFileShare returns the URL path segment for a File Share resource
+func pathForFileShare(name string) string {
+ return fmt.Sprintf("/%s", name)
+}
+
+// ListShares returns the list of shares in a storage account along with
+// pagination token and other response details.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
+func (f FileServiceClient) ListShares(params ListSharesParameters) (ShareListResponse, error) {
+ q := mergeParams(params.getParameters(), url.Values{"comp": {"list"}})
+ uri := f.client.getEndpoint(fileServiceName, "", q)
+ headers := f.client.getStandardHeaders()
+
+ var out ShareListResponse
+ resp, err := f.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return out, err
+ }
+ defer resp.body.Close()
+
+ err = xmlUnmarshal(resp.body, &out)
+ return out, err
+}
+
+// CreateShare operation creates a new share under the specified account. If the
+// share with the same name already exists, the operation fails.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dn167008.aspx
+func (f FileServiceClient) CreateShare(name string) error {
+ resp, err := f.createShare(name)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// ShareExists returns true if a share with given name exists
+// on the storage account, otherwise returns false.
+func (f FileServiceClient) ShareExists(name string) (bool, error) {
+ uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), url.Values{"restype": {"share"}})
+ headers := f.client.getStandardHeaders()
+
+ resp, err := f.client.exec("HEAD", uri, headers, nil)
+ if resp != nil {
+ defer resp.body.Close()
+ if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound {
+ return resp.statusCode == http.StatusOK, nil
+ }
+ }
+ return false, err
+}
+
+// GetShareURL gets the canonical URL to the share with the specified name in the
+// specified container. This method does not create a publicly accessible URL if
+// the file is private and this method does not check if the file
+// exists.
+func (f FileServiceClient) GetShareURL(name string) string {
+ return f.client.getEndpoint(fileServiceName, pathForFileShare(name), url.Values{})
+}
+
+// CreateShareIfNotExists creates a new share under the specified account if
+// it does not exist. Returns true if container is newly created or false if
+// container already exists.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dn167008.aspx
+func (f FileServiceClient) CreateShareIfNotExists(name string) (bool, error) {
+ resp, err := f.createShare(name)
+ if resp != nil {
+ defer resp.body.Close()
+ if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict {
+ return resp.statusCode == http.StatusCreated, nil
+ }
+ }
+ return false, err
+}
+
+// CreateShare creates a Azure File Share and returns its response
+func (f FileServiceClient) createShare(name string) (*storageResponse, error) {
+ if err := f.checkForStorageEmulator(); err != nil {
+ return nil, err
+ }
+ uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), url.Values{"restype": {"share"}})
+ headers := f.client.getStandardHeaders()
+ return f.client.exec("PUT", uri, headers, nil)
+}
+
+// GetShareProperties provides various information about the specified
+// file. See https://msdn.microsoft.com/en-us/library/azure/dn689099.aspx
+func (f FileServiceClient) GetShareProperties(name string) (*ShareProperties, error) {
+ uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), url.Values{"restype": {"share"}})
+
+ headers := f.client.getStandardHeaders()
+ resp, err := f.client.exec("HEAD", uri, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return nil, err
+ }
+
+ return &ShareProperties{
+ LastModified: resp.headers.Get("Last-Modified"),
+ Etag: resp.headers.Get("Etag"),
+ Quota: resp.headers.Get("x-ms-share-quota"),
+ }, nil
+}
+
+// SetShareProperties replaces the ShareHeaders for the specified file.
+//
+// Some keys may be converted to Camel-Case before sending. All keys
+// are returned in lower case by SetShareProperties. HTTP header names
+// are case-insensitive so case munging should not matter to other
+// applications either.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/mt427368.aspx
+func (f FileServiceClient) SetShareProperties(name string, shareHeaders ShareHeaders) error {
+ params := url.Values{}
+ params.Set("restype", "share")
+ params.Set("comp", "properties")
+
+ uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), params)
+ headers := f.client.getStandardHeaders()
+
+ extraHeaders := headersFromStruct(shareHeaders)
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := f.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusOK})
+}
+
+// DeleteShare operation marks the specified share for deletion. The share
+// and any files contained within it are later deleted during garbage
+// collection.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dn689090.aspx
+func (f FileServiceClient) DeleteShare(name string) error {
+ resp, err := f.deleteShare(name)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusAccepted})
+}
+
+// DeleteShareIfExists operation marks the specified share for deletion if it
+// exists. The share and any files contained within it are later deleted during
+// garbage collection. Returns true if share existed and deleted with this call,
+// false otherwise.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dn689090.aspx
+func (f FileServiceClient) DeleteShareIfExists(name string) (bool, error) {
+ resp, err := f.deleteShare(name)
+ if resp != nil {
+ defer resp.body.Close()
+ if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
+ return resp.statusCode == http.StatusAccepted, nil
+ }
+ }
+ return false, err
+}
+
+// deleteShare makes the call to Delete Share operation endpoint and returns
+// the response
+func (f FileServiceClient) deleteShare(name string) (*storageResponse, error) {
+ if err := f.checkForStorageEmulator(); err != nil {
+ return nil, err
+ }
+ uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), url.Values{"restype": {"share"}})
+ return f.client.exec("DELETE", uri, f.client.getStandardHeaders(), nil)
+}
+
+// SetShareMetadata replaces the metadata for the specified Share.
+//
+// Some keys may be converted to Camel-Case before sending. All keys
+// are returned in lower case by GetShareMetadata. HTTP header names
+// are case-insensitive so case munging should not matter to other
+// applications either.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
+func (f FileServiceClient) SetShareMetadata(name string, metadata map[string]string, extraHeaders map[string]string) error {
+ params := url.Values{}
+ params.Set("restype", "share")
+ params.Set("comp", "metadata")
+
+ uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), params)
+ headers := f.client.getStandardHeaders()
+ for k, v := range metadata {
+ headers[userDefinedMetadataHeaderPrefix+k] = v
+ }
+
+ for k, v := range extraHeaders {
+ headers[k] = v
+ }
+
+ resp, err := f.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusOK})
+}
+
+// GetShareMetadata returns all user-defined metadata for the specified share.
+//
+// All metadata keys will be returned in lower case. (HTTP header
+// names are case-insensitive.)
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
+func (f FileServiceClient) GetShareMetadata(name string) (map[string]string, error) {
+ params := url.Values{}
+ params.Set("restype", "share")
+ params.Set("comp", "metadata")
+
+ uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), params)
+ headers := f.client.getStandardHeaders()
+
+ resp, err := f.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return nil, err
+ }
+
+ metadata := make(map[string]string)
+ for k, v := range resp.headers {
+ // Can't trust CanonicalHeaderKey() to munge case
+ // reliably. "_" is allowed in identifiers:
+ // https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
+ // https://msdn.microsoft.com/library/aa664670(VS.71).aspx
+ // http://tools.ietf.org/html/rfc7230#section-3.2
+ // ...but "_" is considered invalid by
+ // CanonicalMIMEHeaderKey in
+ // https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542
+ // so k can be "X-Ms-Meta-Foo" or "x-ms-meta-foo_bar".
+ k = strings.ToLower(k)
+ if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) {
+ continue
+ }
+ // metadata["foo"] = content of the last X-Ms-Meta-Foo header
+ k = k[len(userDefinedMetadataHeaderPrefix):]
+ metadata[k] = v[len(v)-1]
+ }
+ return metadata, nil
+}
+
+//checkForStorageEmulator determines if the client is setup for use with
+//Azure Storage Emulator, and returns a relevant error
+func (f FileServiceClient) checkForStorageEmulator() error {
+ if f.client.accountName == StorageEmulatorAccountName {
+ return fmt.Errorf("Error: File service is not currently supported by Azure Storage Emulator")
+ }
+ return nil
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go
new file mode 100644
index 000000000..3ecf4aca0
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go
@@ -0,0 +1,306 @@
+package storage
+
+import (
+ "encoding/xml"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+)
+
+const (
+ // casing is per Golang's http.Header canonicalizing the header names.
+ approximateMessagesCountHeader = "X-Ms-Approximate-Messages-Count"
+ userDefinedMetadataHeaderPrefix = "X-Ms-Meta-"
+)
+
+// QueueServiceClient contains operations for Microsoft Azure Queue Storage
+// Service.
+type QueueServiceClient struct {
+ client Client
+}
+
+func pathForQueue(queue string) string { return fmt.Sprintf("/%s", queue) }
+func pathForQueueMessages(queue string) string { return fmt.Sprintf("/%s/messages", queue) }
+func pathForMessage(queue, name string) string { return fmt.Sprintf("/%s/messages/%s", queue, name) }
+
+type putMessageRequest struct {
+ XMLName xml.Name `xml:"QueueMessage"`
+ MessageText string `xml:"MessageText"`
+}
+
+// PutMessageParameters is the set of options can be specified for Put Messsage
+// operation. A zero struct does not use any preferences for the request.
+type PutMessageParameters struct {
+ VisibilityTimeout int
+ MessageTTL int
+}
+
+func (p PutMessageParameters) getParameters() url.Values {
+ out := url.Values{}
+ if p.VisibilityTimeout != 0 {
+ out.Set("visibilitytimeout", strconv.Itoa(p.VisibilityTimeout))
+ }
+ if p.MessageTTL != 0 {
+ out.Set("messagettl", strconv.Itoa(p.MessageTTL))
+ }
+ return out
+}
+
+// GetMessagesParameters is the set of options can be specified for Get
+// Messsages operation. A zero struct does not use any preferences for the
+// request.
+type GetMessagesParameters struct {
+ NumOfMessages int
+ VisibilityTimeout int
+}
+
+func (p GetMessagesParameters) getParameters() url.Values {
+ out := url.Values{}
+ if p.NumOfMessages != 0 {
+ out.Set("numofmessages", strconv.Itoa(p.NumOfMessages))
+ }
+ if p.VisibilityTimeout != 0 {
+ out.Set("visibilitytimeout", strconv.Itoa(p.VisibilityTimeout))
+ }
+ return out
+}
+
+// PeekMessagesParameters is the set of options can be specified for Peek
+// Messsage operation. A zero struct does not use any preferences for the
+// request.
+type PeekMessagesParameters struct {
+ NumOfMessages int
+}
+
+func (p PeekMessagesParameters) getParameters() url.Values {
+ out := url.Values{"peekonly": {"true"}} // Required for peek operation
+ if p.NumOfMessages != 0 {
+ out.Set("numofmessages", strconv.Itoa(p.NumOfMessages))
+ }
+ return out
+}
+
+// GetMessagesResponse represents a response returned from Get Messages
+// operation.
+type GetMessagesResponse struct {
+ XMLName xml.Name `xml:"QueueMessagesList"`
+ QueueMessagesList []GetMessageResponse `xml:"QueueMessage"`
+}
+
+// GetMessageResponse represents a QueueMessage object returned from Get
+// Messages operation response.
+type GetMessageResponse struct {
+ MessageID string `xml:"MessageId"`
+ InsertionTime string `xml:"InsertionTime"`
+ ExpirationTime string `xml:"ExpirationTime"`
+ PopReceipt string `xml:"PopReceipt"`
+ TimeNextVisible string `xml:"TimeNextVisible"`
+ DequeueCount int `xml:"DequeueCount"`
+ MessageText string `xml:"MessageText"`
+}
+
+// PeekMessagesResponse represents a response returned from Get Messages
+// operation.
+type PeekMessagesResponse struct {
+ XMLName xml.Name `xml:"QueueMessagesList"`
+ QueueMessagesList []PeekMessageResponse `xml:"QueueMessage"`
+}
+
+// PeekMessageResponse represents a QueueMessage object returned from Peek
+// Messages operation response.
+type PeekMessageResponse struct {
+ MessageID string `xml:"MessageId"`
+ InsertionTime string `xml:"InsertionTime"`
+ ExpirationTime string `xml:"ExpirationTime"`
+ DequeueCount int `xml:"DequeueCount"`
+ MessageText string `xml:"MessageText"`
+}
+
+// QueueMetadataResponse represents user defined metadata and queue
+// properties on a specific queue.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179384.aspx
+type QueueMetadataResponse struct {
+ ApproximateMessageCount int
+ UserDefinedMetadata map[string]string
+}
+
+// SetMetadata operation sets user-defined metadata on the specified queue.
+// Metadata is associated with the queue as name-value pairs.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179348.aspx
+func (c QueueServiceClient) SetMetadata(name string, metadata map[string]string) error {
+ uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{"comp": []string{"metadata"}})
+ headers := c.client.getStandardHeaders()
+ for k, v := range metadata {
+ headers[userDefinedMetadataHeaderPrefix+k] = v
+ }
+
+ resp, err := c.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
+}
+
+// GetMetadata operation retrieves user-defined metadata and queue
+// properties on the specified queue. Metadata is associated with
+// the queue as name-values pairs.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179384.aspx
+//
+// Because the way Golang's http client (and http.Header in particular)
+// canonicalize header names, the returned metadata names would always
+// be all lower case.
+func (c QueueServiceClient) GetMetadata(name string) (QueueMetadataResponse, error) {
+ qm := QueueMetadataResponse{}
+ qm.UserDefinedMetadata = make(map[string]string)
+ uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{"comp": []string{"metadata"}})
+ headers := c.client.getStandardHeaders()
+ resp, err := c.client.exec("GET", uri, headers, nil)
+ if err != nil {
+ return qm, err
+ }
+ defer resp.body.Close()
+
+ for k, v := range resp.headers {
+ if len(v) != 1 {
+ return qm, fmt.Errorf("Unexpected number of values (%d) in response header '%s'", len(v), k)
+ }
+
+ value := v[0]
+
+ if k == approximateMessagesCountHeader {
+ qm.ApproximateMessageCount, err = strconv.Atoi(value)
+ if err != nil {
+ return qm, fmt.Errorf("Unexpected value in response header '%s': '%s' ", k, value)
+ }
+ } else if strings.HasPrefix(k, userDefinedMetadataHeaderPrefix) {
+ name := strings.TrimPrefix(k, userDefinedMetadataHeaderPrefix)
+ qm.UserDefinedMetadata[strings.ToLower(name)] = value
+ }
+ }
+
+ return qm, checkRespCode(resp.statusCode, []int{http.StatusOK})
+}
+
+// CreateQueue operation creates a queue under the given account.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179342.aspx
+func (c QueueServiceClient) CreateQueue(name string) error {
+ uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{})
+ headers := c.client.getStandardHeaders()
+ resp, err := c.client.exec("PUT", uri, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// DeleteQueue operation permanently deletes the specified queue.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179436.aspx
+func (c QueueServiceClient) DeleteQueue(name string) error {
+ uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{})
+ resp, err := c.client.exec("DELETE", uri, c.client.getStandardHeaders(), nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
+}
+
+// QueueExists returns true if a queue with given name exists.
+func (c QueueServiceClient) QueueExists(name string) (bool, error) {
+ uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{"comp": {"metadata"}})
+ resp, err := c.client.exec("GET", uri, c.client.getStandardHeaders(), nil)
+ if resp != nil && (resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound) {
+ return resp.statusCode == http.StatusOK, nil
+ }
+
+ return false, err
+}
+
+// PutMessage operation adds a new message to the back of the message queue.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179346.aspx
+func (c QueueServiceClient) PutMessage(queue string, message string, params PutMessageParameters) error {
+ uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), params.getParameters())
+ req := putMessageRequest{MessageText: message}
+ body, nn, err := xmlMarshal(req)
+ if err != nil {
+ return err
+ }
+ headers := c.client.getStandardHeaders()
+ headers["Content-Length"] = strconv.Itoa(nn)
+ resp, err := c.client.exec("POST", uri, headers, body)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusCreated})
+}
+
+// ClearMessages operation deletes all messages from the specified queue.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179454.aspx
+func (c QueueServiceClient) ClearMessages(queue string) error {
+ uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), url.Values{})
+ resp, err := c.client.exec("DELETE", uri, c.client.getStandardHeaders(), nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
+}
+
+// GetMessages operation retrieves one or more messages from the front of the
+// queue.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179474.aspx
+func (c QueueServiceClient) GetMessages(queue string, params GetMessagesParameters) (GetMessagesResponse, error) {
+ var r GetMessagesResponse
+ uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), params.getParameters())
+ resp, err := c.client.exec("GET", uri, c.client.getStandardHeaders(), nil)
+ if err != nil {
+ return r, err
+ }
+ defer resp.body.Close()
+ err = xmlUnmarshal(resp.body, &r)
+ return r, err
+}
+
+// PeekMessages retrieves one or more messages from the front of the queue, but
+// does not alter the visibility of the message.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179472.aspx
+func (c QueueServiceClient) PeekMessages(queue string, params PeekMessagesParameters) (PeekMessagesResponse, error) {
+ var r PeekMessagesResponse
+ uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), params.getParameters())
+ resp, err := c.client.exec("GET", uri, c.client.getStandardHeaders(), nil)
+ if err != nil {
+ return r, err
+ }
+ defer resp.body.Close()
+ err = xmlUnmarshal(resp.body, &r)
+ return r, err
+}
+
+// DeleteMessage operation deletes the specified message.
+//
+// See https://msdn.microsoft.com/en-us/library/azure/dd179347.aspx
+func (c QueueServiceClient) DeleteMessage(queue, messageID, popReceipt string) error {
+ uri := c.client.getEndpoint(queueServiceName, pathForMessage(queue, messageID), url.Values{
+ "popreceipt": {popReceipt}})
+ resp, err := c.client.exec("DELETE", uri, c.client.getStandardHeaders(), nil)
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+ return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/table.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/table.go
new file mode 100644
index 000000000..39e997503
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/table.go
@@ -0,0 +1,129 @@
+package storage
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+)
+
+// TableServiceClient contains operations for Microsoft Azure Table Storage
+// Service.
+type TableServiceClient struct {
+ client Client
+}
+
+// AzureTable is the typedef of the Azure Table name
+type AzureTable string
+
+const (
+ tablesURIPath = "/Tables"
+)
+
+type createTableRequest struct {
+ TableName string `json:"TableName"`
+}
+
+func pathForTable(table AzureTable) string { return fmt.Sprintf("%s", table) }
+
+func (c *TableServiceClient) getStandardHeaders() map[string]string {
+ return map[string]string{
+ "x-ms-version": "2015-02-21",
+ "x-ms-date": currentTimeRfc1123Formatted(),
+ "Accept": "application/json;odata=nometadata",
+ "Accept-Charset": "UTF-8",
+ "Content-Type": "application/json",
+ }
+}
+
+// QueryTables returns the tables created in the
+// *TableServiceClient storage account.
+func (c *TableServiceClient) QueryTables() ([]AzureTable, error) {
+ uri := c.client.getEndpoint(tableServiceName, tablesURIPath, url.Values{})
+
+ headers := c.getStandardHeaders()
+ headers["Content-Length"] = "0"
+
+ resp, err := c.client.execTable("GET", uri, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return nil, err
+ }
+
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(resp.body)
+
+ var respArray queryTablesResponse
+ if err := json.Unmarshal(buf.Bytes(), &respArray); err != nil {
+ return nil, err
+ }
+
+ s := make([]AzureTable, len(respArray.TableName))
+ for i, elem := range respArray.TableName {
+ s[i] = AzureTable(elem.TableName)
+ }
+
+ return s, nil
+}
+
+// CreateTable creates the table given the specific
+// name. This function fails if the name is not compliant
+// with the specification or the tables already exists.
+func (c *TableServiceClient) CreateTable(table AzureTable) error {
+ uri := c.client.getEndpoint(tableServiceName, tablesURIPath, url.Values{})
+
+ headers := c.getStandardHeaders()
+
+ req := createTableRequest{TableName: string(table)}
+ buf := new(bytes.Buffer)
+
+ if err := json.NewEncoder(buf).Encode(req); err != nil {
+ return err
+ }
+
+ headers["Content-Length"] = fmt.Sprintf("%d", buf.Len())
+
+ resp, err := c.client.execTable("POST", uri, headers, buf)
+
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// DeleteTable deletes the table given the specific
+// name. This function fails if the table is not present.
+// Be advised: DeleteTable deletes all the entries
+// that may be present.
+func (c *TableServiceClient) DeleteTable(table AzureTable) error {
+ uri := c.client.getEndpoint(tableServiceName, tablesURIPath, url.Values{})
+ uri += fmt.Sprintf("('%s')", string(table))
+
+ headers := c.getStandardHeaders()
+
+ headers["Content-Length"] = "0"
+
+ resp, err := c.client.execTable("DELETE", uri, headers, nil)
+
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
+ return err
+
+ }
+ return nil
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/table_entities.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/table_entities.go
new file mode 100644
index 000000000..1b5919cd1
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/table_entities.go
@@ -0,0 +1,355 @@
+package storage
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "reflect"
+)
+
+const (
+ partitionKeyNode = "PartitionKey"
+ rowKeyNode = "RowKey"
+ tag = "table"
+ tagIgnore = "-"
+ continuationTokenPartitionKeyHeader = "X-Ms-Continuation-Nextpartitionkey"
+ continuationTokenRowHeader = "X-Ms-Continuation-Nextrowkey"
+ maxTopParameter = 1000
+)
+
+type queryTablesResponse struct {
+ TableName []struct {
+ TableName string `json:"TableName"`
+ } `json:"value"`
+}
+
+const (
+ tableOperationTypeInsert = iota
+ tableOperationTypeUpdate = iota
+ tableOperationTypeMerge = iota
+ tableOperationTypeInsertOrReplace = iota
+ tableOperationTypeInsertOrMerge = iota
+)
+
+type tableOperation int
+
+// TableEntity interface specifies
+// the functions needed to support
+// marshaling and unmarshaling into
+// Azure Tables. The struct must only contain
+// simple types because Azure Tables do not
+// support hierarchy.
+type TableEntity interface {
+ PartitionKey() string
+ RowKey() string
+ SetPartitionKey(string) error
+ SetRowKey(string) error
+}
+
+// ContinuationToken is an opaque (ie not useful to inspect)
+// struct that Get... methods can return if there are more
+// entries to be returned than the ones already
+// returned. Just pass it to the same function to continue
+// receiving the remaining entries.
+type ContinuationToken struct {
+ NextPartitionKey string
+ NextRowKey string
+}
+
+type getTableEntriesResponse struct {
+ Elements []map[string]interface{} `json:"value"`
+}
+
+// QueryTableEntities queries the specified table and returns the unmarshaled
+// entities of type retType.
+// top parameter limits the returned entries up to top. Maximum top
+// allowed by Azure API is 1000. In case there are more than top entries to be
+// returned the function will return a non nil *ContinuationToken. You can call the
+// same function again passing the received ContinuationToken as previousContToken
+// parameter in order to get the following entries. The query parameter
+// is the odata query. To retrieve all the entries pass the empty string.
+// The function returns a pointer to a TableEntity slice, the *ContinuationToken
+// if there are more entries to be returned and an error in case something went
+// wrong.
+//
+// Example:
+// entities, cToken, err = tSvc.QueryTableEntities("table", cToken, reflect.TypeOf(entity), 20, "")
+func (c *TableServiceClient) QueryTableEntities(tableName AzureTable, previousContToken *ContinuationToken, retType reflect.Type, top int, query string) ([]TableEntity, *ContinuationToken, error) {
+ if top > maxTopParameter {
+ return nil, nil, fmt.Errorf("top accepts at maximum %d elements. Requested %d instead", maxTopParameter, top)
+ }
+
+ uri := c.client.getEndpoint(tableServiceName, pathForTable(tableName), url.Values{})
+ uri += fmt.Sprintf("?$top=%d", top)
+ if query != "" {
+ uri += fmt.Sprintf("&$filter=%s", url.QueryEscape(query))
+ }
+
+ if previousContToken != nil {
+ uri += fmt.Sprintf("&NextPartitionKey=%s&NextRowKey=%s", previousContToken.NextPartitionKey, previousContToken.NextRowKey)
+ }
+
+ headers := c.getStandardHeaders()
+
+ headers["Content-Length"] = "0"
+
+ resp, err := c.client.execTable("GET", uri, headers, nil)
+
+ if err != nil {
+ return nil, nil, err
+ }
+
+ contToken := extractContinuationTokenFromHeaders(resp.headers)
+
+ if err != nil {
+ return nil, contToken, err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
+ return nil, contToken, err
+ }
+
+ retEntries, err := deserializeEntity(retType, resp.body)
+ if err != nil {
+ return nil, contToken, err
+ }
+
+ return retEntries, contToken, nil
+}
+
+// InsertEntity inserts an entity in the specified table.
+// The function fails if there is an entity with the same
+// PartitionKey and RowKey in the table.
+func (c *TableServiceClient) InsertEntity(table AzureTable, entity TableEntity) error {
+ var err error
+
+ if sc, err := c.execTable(table, entity, false, "POST"); err != nil {
+ return checkRespCode(sc, []int{http.StatusCreated})
+ }
+
+ return err
+}
+
+func (c *TableServiceClient) execTable(table AzureTable, entity TableEntity, specifyKeysInURL bool, method string) (int, error) {
+ uri := c.client.getEndpoint(tableServiceName, pathForTable(table), url.Values{})
+ if specifyKeysInURL {
+ uri += fmt.Sprintf("(PartitionKey='%s',RowKey='%s')", url.QueryEscape(entity.PartitionKey()), url.QueryEscape(entity.RowKey()))
+ }
+
+ headers := c.getStandardHeaders()
+
+ var buf bytes.Buffer
+
+ if err := injectPartitionAndRowKeys(entity, &buf); err != nil {
+ return 0, err
+ }
+
+ headers["Content-Length"] = fmt.Sprintf("%d", buf.Len())
+
+ var err error
+ var resp *odataResponse
+
+ resp, err = c.client.execTable(method, uri, headers, &buf)
+
+ if err != nil {
+ return 0, err
+ }
+
+ defer resp.body.Close()
+
+ return resp.statusCode, nil
+}
+
+// UpdateEntity updates the contents of an entity with the
+// one passed as parameter. The function fails if there is no entity
+// with the same PartitionKey and RowKey in the table.
+func (c *TableServiceClient) UpdateEntity(table AzureTable, entity TableEntity) error {
+ var err error
+
+ if sc, err := c.execTable(table, entity, true, "PUT"); err != nil {
+ return checkRespCode(sc, []int{http.StatusNoContent})
+ }
+ return err
+}
+
+// MergeEntity merges the contents of an entity with the
+// one passed as parameter.
+// The function fails if there is no entity
+// with the same PartitionKey and RowKey in the table.
+func (c *TableServiceClient) MergeEntity(table AzureTable, entity TableEntity) error {
+ var err error
+
+ if sc, err := c.execTable(table, entity, true, "MERGE"); err != nil {
+ return checkRespCode(sc, []int{http.StatusNoContent})
+ }
+ return err
+}
+
+// DeleteEntityWithoutCheck deletes the entity matching by
+// PartitionKey and RowKey. There is no check on IfMatch
+// parameter so the entity is always deleted.
+// The function fails if there is no entity
+// with the same PartitionKey and RowKey in the table.
+func (c *TableServiceClient) DeleteEntityWithoutCheck(table AzureTable, entity TableEntity) error {
+ return c.DeleteEntity(table, entity, "*")
+}
+
+// DeleteEntity deletes the entity matching by
+// PartitionKey, RowKey and ifMatch field.
+// The function fails if there is no entity
+// with the same PartitionKey and RowKey in the table or
+// the ifMatch is different.
+func (c *TableServiceClient) DeleteEntity(table AzureTable, entity TableEntity, ifMatch string) error {
+ uri := c.client.getEndpoint(tableServiceName, pathForTable(table), url.Values{})
+ uri += fmt.Sprintf("(PartitionKey='%s',RowKey='%s')", url.QueryEscape(entity.PartitionKey()), url.QueryEscape(entity.RowKey()))
+
+ headers := c.getStandardHeaders()
+
+ headers["Content-Length"] = "0"
+ headers["If-Match"] = ifMatch
+
+ resp, err := c.client.execTable("DELETE", uri, headers, nil)
+
+ if err != nil {
+ return err
+ }
+ defer resp.body.Close()
+
+ if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// InsertOrReplaceEntity inserts an entity in the specified table
+// or replaced the existing one.
+func (c *TableServiceClient) InsertOrReplaceEntity(table AzureTable, entity TableEntity) error {
+ var err error
+
+ if sc, err := c.execTable(table, entity, true, "PUT"); err != nil {
+ return checkRespCode(sc, []int{http.StatusNoContent})
+ }
+ return err
+}
+
+// InsertOrMergeEntity inserts an entity in the specified table
+// or merges the existing one.
+func (c *TableServiceClient) InsertOrMergeEntity(table AzureTable, entity TableEntity) error {
+ var err error
+
+ if sc, err := c.execTable(table, entity, true, "MERGE"); err != nil {
+ return checkRespCode(sc, []int{http.StatusNoContent})
+ }
+ return err
+}
+
+func injectPartitionAndRowKeys(entity TableEntity, buf *bytes.Buffer) error {
+ if err := json.NewEncoder(buf).Encode(entity); err != nil {
+ return err
+ }
+
+ dec := make(map[string]interface{})
+ if err := json.NewDecoder(buf).Decode(&dec); err != nil {
+ return err
+ }
+
+ // Inject PartitionKey and RowKey
+ dec[partitionKeyNode] = entity.PartitionKey()
+ dec[rowKeyNode] = entity.RowKey()
+
+ // Remove tagged fields
+ // The tag is defined in the const section
+ // This is useful to avoid storing the PartitionKey and RowKey twice.
+ numFields := reflect.ValueOf(entity).Elem().NumField()
+ for i := 0; i < numFields; i++ {
+ f := reflect.ValueOf(entity).Elem().Type().Field(i)
+
+ if f.Tag.Get(tag) == tagIgnore {
+ // we must look for its JSON name in the dictionary
+ // as the user can rename it using a tag
+ jsonName := f.Name
+ if f.Tag.Get("json") != "" {
+ jsonName = f.Tag.Get("json")
+ }
+ delete(dec, jsonName)
+ }
+ }
+
+ buf.Reset()
+
+ if err := json.NewEncoder(buf).Encode(&dec); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func deserializeEntity(retType reflect.Type, reader io.Reader) ([]TableEntity, error) {
+ buf := new(bytes.Buffer)
+
+ var ret getTableEntriesResponse
+ if err := json.NewDecoder(reader).Decode(&ret); err != nil {
+ return nil, err
+ }
+
+ tEntries := make([]TableEntity, len(ret.Elements))
+
+ for i, entry := range ret.Elements {
+
+ buf.Reset()
+ if err := json.NewEncoder(buf).Encode(entry); err != nil {
+ return nil, err
+ }
+
+ dec := make(map[string]interface{})
+ if err := json.NewDecoder(buf).Decode(&dec); err != nil {
+ return nil, err
+ }
+
+ var pKey, rKey string
+ // strip pk and rk
+ for key, val := range dec {
+ switch key {
+ case partitionKeyNode:
+ pKey = val.(string)
+ case rowKeyNode:
+ rKey = val.(string)
+ }
+ }
+
+ delete(dec, partitionKeyNode)
+ delete(dec, rowKeyNode)
+
+ buf.Reset()
+ if err := json.NewEncoder(buf).Encode(dec); err != nil {
+ return nil, err
+ }
+
+ // Create a empty retType instance
+ tEntries[i] = reflect.New(retType.Elem()).Interface().(TableEntity)
+ // Popolate it with the values
+ if err := json.NewDecoder(buf).Decode(&tEntries[i]); err != nil {
+ return nil, err
+ }
+
+ // Reset PartitionKey and RowKey
+ tEntries[i].SetPartitionKey(pKey)
+ tEntries[i].SetRowKey(rKey)
+ }
+
+ return tEntries, nil
+}
+
+func extractContinuationTokenFromHeaders(h http.Header) *ContinuationToken {
+ ct := ContinuationToken{h.Get(continuationTokenPartitionKeyHeader), h.Get(continuationTokenRowHeader)}
+
+ if ct.NextPartitionKey != "" && ct.NextRowKey != "" {
+ return &ct
+ }
+ return nil
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/util.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/util.go
new file mode 100644
index 000000000..d71c6ce55
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/util.go
@@ -0,0 +1,85 @@
+package storage
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "reflect"
+ "time"
+)
+
+func (c Client) computeHmac256(message string) string {
+ h := hmac.New(sha256.New, c.accountKey)
+ h.Write([]byte(message))
+ return base64.StdEncoding.EncodeToString(h.Sum(nil))
+}
+
+func currentTimeRfc1123Formatted() string {
+ return timeRfc1123Formatted(time.Now().UTC())
+}
+
+func timeRfc1123Formatted(t time.Time) string {
+ return t.Format(http.TimeFormat)
+}
+
+func mergeParams(v1, v2 url.Values) url.Values {
+ out := url.Values{}
+ for k, v := range v1 {
+ out[k] = v
+ }
+ for k, v := range v2 {
+ vals, ok := out[k]
+ if ok {
+ vals = append(vals, v...)
+ out[k] = vals
+ } else {
+ out[k] = v
+ }
+ }
+ return out
+}
+
+func prepareBlockListRequest(blocks []Block) string {
+ s := `<?xml version="1.0" encoding="utf-8"?><BlockList>`
+ for _, v := range blocks {
+ s += fmt.Sprintf("<%s>%s</%s>", v.Status, v.ID, v.Status)
+ }
+ s += `</BlockList>`
+ return s
+}
+
+func xmlUnmarshal(body io.Reader, v interface{}) error {
+ data, err := ioutil.ReadAll(body)
+ if err != nil {
+ return err
+ }
+ return xml.Unmarshal(data, v)
+}
+
+func xmlMarshal(v interface{}) (io.Reader, int, error) {
+ b, err := xml.Marshal(v)
+ if err != nil {
+ return nil, 0, err
+ }
+ return bytes.NewReader(b), len(b), nil
+}
+
+func headersFromStruct(v interface{}) map[string]string {
+ headers := make(map[string]string)
+ value := reflect.ValueOf(v)
+ for i := 0; i < value.NumField(); i++ {
+ key := value.Type().Field(i).Tag.Get("header")
+ val := value.Field(i).String()
+ if val != "" {
+ headers[key] = val
+ }
+ }
+ return headers
+}
diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE
index bb6733231..c83641619 100644
--- a/vendor/github.com/davecgh/go-spew/LICENSE
+++ b/vendor/github.com/davecgh/go-spew/LICENSE
@@ -1,6 +1,6 @@
ISC License
-Copyright (c) 2012-2013 Dave Collins <dave@davec.name>
+Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/davecgh/go-spew/README.md
index 556170ae6..262430449 100644
--- a/vendor/github.com/davecgh/go-spew/README.md
+++ b/vendor/github.com/davecgh/go-spew/README.md
@@ -1,11 +1,13 @@
go-spew
=======
-[![Build Status](https://travis-ci.org/davecgh/go-spew.png?branch=master)]
-(https://travis-ci.org/davecgh/go-spew) [![Coverage Status]
-(https://coveralls.io/repos/davecgh/go-spew/badge.png?branch=master)]
+[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)]
+(https://travis-ci.org/davecgh/go-spew) [![ISC License]
+(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status]
+(https://img.shields.io/coveralls/davecgh/go-spew.svg)]
(https://coveralls.io/r/davecgh/go-spew?branch=master)
+
Go-spew implements a deep pretty printer for Go data structures to aid in
debugging. A comprehensive suite of tests with 100% test coverage is provided
to ensure proper functionality. See `test_coverage.txt` for the gocov coverage
@@ -19,7 +21,7 @@ post about it
## Documentation
-[![GoDoc](https://godoc.org/github.com/davecgh/go-spew/spew?status.png)]
+[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
(http://godoc.org/github.com/davecgh/go-spew/spew)
Full `go doc` style documentation for the project can be viewed online without
@@ -160,6 +162,15 @@ options. See the ConfigState documentation for more details.
App Engine or with the "safe" build tag specified.
Pointer method invocation is enabled by default.
+* DisablePointerAddresses
+ DisablePointerAddresses specifies whether to disable the printing of
+ pointer addresses. This is useful when diffing data structures in tests.
+
+* DisableCapacities
+ DisableCapacities specifies whether to disable the printing of capacities
+ for arrays, slices, maps and channels. This is useful when diffing data
+ structures in tests.
+
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
@@ -191,4 +202,4 @@ using the unsafe package.
## License
-Go-spew is licensed under the liberal ISC License.
+Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go
index d42a0bc4a..8a4a6589a 100644
--- a/vendor/github.com/davecgh/go-spew/spew/bypass.go
+++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 Dave Collins <dave@davec.name>
+// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
index e47a4e795..1fe3cf3d5 100644
--- a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
+++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 Dave Collins <dave@davec.name>
+// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go
index 14f02dc15..7c519ff47 100644
--- a/vendor/github.com/davecgh/go-spew/spew/common.go
+++ b/vendor/github.com/davecgh/go-spew/spew/common.go
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go
index 555282723..2e3d22f31 100644
--- a/vendor/github.com/davecgh/go-spew/spew/config.go
+++ b/vendor/github.com/davecgh/go-spew/spew/config.go
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -67,6 +67,15 @@ type ConfigState struct {
// Google App Engine or with the "safe" build tag specified.
DisablePointerMethods bool
+ // DisablePointerAddresses specifies whether to disable the printing of
+ // pointer addresses. This is useful when diffing data structures in tests.
+ DisablePointerAddresses bool
+
+ // DisableCapacities specifies whether to disable the printing of capacities
+ // for arrays, slices, maps and channels. This is useful when diffing
+ // data structures in tests.
+ DisableCapacities bool
+
// ContinueOnMethod specifies whether or not recursion should continue once
// a custom error or Stringer interface is invoked. The default, false,
// means it will print the results of invoking the custom error or Stringer
diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go
index 5be0c4060..aacaac6f1 100644
--- a/vendor/github.com/davecgh/go-spew/spew/doc.go
+++ b/vendor/github.com/davecgh/go-spew/spew/doc.go
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -91,6 +91,15 @@ The following configuration options are available:
which only accept pointer receivers from non-pointer variables.
Pointer method invocation is enabled by default.
+ * DisablePointerAddresses
+ DisablePointerAddresses specifies whether to disable the printing of
+ pointer addresses. This is useful when diffing data structures in tests.
+
+ * DisableCapacities
+ DisableCapacities specifies whether to disable the printing of
+ capacities for arrays, slices, maps and channels. This is useful when
+ diffing data structures in tests.
+
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go
index a0ff95e27..df1d582a7 100644
--- a/vendor/github.com/davecgh/go-spew/spew/dump.go
+++ b/vendor/github.com/davecgh/go-spew/spew/dump.go
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -129,7 +129,7 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
d.w.Write(closeParenBytes)
// Display pointer information.
- if len(pointerChain) > 0 {
+ if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
d.w.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
@@ -282,13 +282,13 @@ func (d *dumpState) dump(v reflect.Value) {
case reflect.Map, reflect.String:
valueLen = v.Len()
}
- if valueLen != 0 || valueCap != 0 {
+ if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
d.w.Write(openParenBytes)
if valueLen != 0 {
d.w.Write(lenEqualsBytes)
printInt(d.w, int64(valueLen), 10)
}
- if valueCap != 0 {
+ if !d.cs.DisableCapacities && valueCap != 0 {
if valueLen != 0 {
d.w.Write(spaceBytes)
}
diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go
index ecf3b80e2..c49875bac 100644
--- a/vendor/github.com/davecgh/go-spew/spew/format.go
+++ b/vendor/github.com/davecgh/go-spew/spew/format.go
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/davecgh/go-spew/spew/spew.go
index d8233f542..32c0e3388 100644
--- a/vendor/github.com/davecgh/go-spew/spew/spew.go
+++ b/vendor/github.com/davecgh/go-spew/spew/spew.go
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/vendor/github.com/huin/goupnp/ssdp/registry.go b/vendor/github.com/huin/goupnp/ssdp/registry.go
index 2f84beaae..d3bc11446 100644
--- a/vendor/github.com/huin/goupnp/ssdp/registry.go
+++ b/vendor/github.com/huin/goupnp/ssdp/registry.go
@@ -18,7 +18,7 @@ const (
)
var (
- maxAgeRx = regexp.MustCompile("max-age=([0-9]+)")
+ maxAgeRx = regexp.MustCompile("max-age= *([0-9]+)")
)
const (
diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go
index bc84adfaf..448277f56 100644
--- a/vendor/github.com/mattn/go-colorable/colorable_windows.go
+++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go
@@ -72,6 +72,7 @@ type Writer struct {
handle syscall.Handle
lastbuf bytes.Buffer
oldattr word
+ oldpos coord
}
func NewColorable(file *os.File) io.Writer {
@@ -83,7 +84,7 @@ func NewColorable(file *os.File) io.Writer {
var csbi consoleScreenBufferInfo
handle := syscall.Handle(file.Fd())
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- return &Writer{out: file, handle: handle, oldattr: csbi.attributes}
+ return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
} else {
return file
}
@@ -644,6 +645,11 @@ loop:
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
}
+ case 's':
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ w.oldpos = csbi.cursorPosition
+ case 'u':
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
}
}
return len(data) - w.lastbuf.Len(), nil