diff --git a/.github/no-response.yml b/.github/no-response.yml
new file mode 100644
index 000000000000..bacbe1631ef1
--- /dev/null
+++ b/.github/no-response.yml
@@ -0,0 +1,13 @@
+# Configuration for probot-no-response - https://github.com/probot/no-response
+
+# Number of days of inactivity before an Issue is closed for lack of response
+daysUntilClose: 14
+# Label requiring a response
+responseRequiredLabel: customer-response-expected
+# Comment to post when closing an Issue for lack of response. Set to `false` to disable
+closeComment: >
+ This issue has been automatically closed because there has been no response
+ to our request for more information from the original author. With only the
+ information that is currently in the issue, we don't have enough information
+ to take action. Please reach out if you have or find the answers we need so
+ that we can investigate further.
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3746de322502..e77bf1ad3f3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,792 +1,1320 @@
# CHANGELOG
-## `v14.3.0`
+## `v38.2.0`
-### Changes
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| attestation | 2018-09-01-preview |
+| eventgrid | 2020-04-01-preview |
+| storagesync | 2019-06-01 |
-- Add exports for max file range and sizes for files in storage.
-- Updated README regarding blob storage support.
-- Add godoc indexer tool.
-- Add apidiff tool.
+## `v38.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| frontdoor | 2019-10-01
2019-11-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| storage | 2019-06-01 |
+
+## `v38.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| containerregistry | 2019-12-01-preview |
+| databoxedge | 2019-08-01 |
+| machinelearningservices | 2020-01-01 |
+| netapp | 2019-10-01 |
+| windowsesu | 2019-09-16-preview |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| anomalydetector | v1.0 |
+| hdinsight | 2015-03-01-preview
2018-06-01-preview |
+| insights | 2015-05-01 |
+| media | 2018-07-01 |
+| personalizer | v1.0 |
+| resourcehealth | 2017-07-01 |
+| servicebus | 2018-01-01-preview |
+| siterecovery | 2018-07-10 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| authorization | 2015-07-01
2017-10-01-preview |
+| blueprint | 2018-11-01-preview |
+| compute | 2018-10-01
2019-03-01
2019-07-01 |
+| containerservice | 2019-11-01 |
+| customerlockbox | 2018-02-28-preview |
+| databricks | 2018-04-01 |
+| datafactory | 2018-06-01 |
+| features | 2019-07-01 |
+| managedservices | 2018-06-01
2019-04-01 |
+| resources | 2015-11-01
2016-02-01
2016-07-01
2016-09-01
2017-05-10
2018-02-01
2018-05-01
2019-03-01
2019-05-01 |
+| security | v1.0
v2.0
v3.0 |
+| servicefabric | 2017-07-01-preview
2018-02-01
2019-03-01
2019-03-01-preview |
+| sql | v3.0 |
+| textanalytics | v2.1 |
+
+## `v37.2.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| containerservice | 2019-11-01 |
+| deploymentmanager | 2019-11-01-preview |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| containerservice | 2017-07-01
2017-08-31
2017-09-30
2018-03-31 |
+| machinelearningservices | 2019-11-01 |
+
+## `v37.1.0`
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| iotcentral | 2018-09-01 |
+
+## `v37.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| azuredata | 2017-03-01-preview |
+| backup | 2019-05-13 |
+| customerlockbox | 2018-02-28-preview |
+| managedapplications | 2019-07-01 |
+| servicefabric | 7.0 |
+| siterecovery | 2018-07-10 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| azurestack | 2017-06-01 |
+| compute | 2018-04-01
2018-06-01
2018-10-01
2019-03-01 |
+| containerregistry | 2019-06-01-preview |
+| containerservice | 2019-10-01 |
+| datashare | 2018-11-01-preview
2019-11-01 |
+| hanaonazure | 2017-11-03-preview |
+| mysql | 2017-12-01
2017-12-01-preview |
+| network | 2019-09-01 |
+| policyinsights | 2019-10-01 |
+| postgresql | 2017-12-01-preview |
+| qnamaker | v4.0 |
+| securityinsight | 2017-08-01-preview |
+| sql | 2015-05-01-preview
2018-06-01-preview |
+| sqlvirtualmachine | 2017-03-01-preview |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| appplatform | 2019-05-01-preview |
+| backup | 2017-07-01 |
+| cdn | 2019-06-15-preview |
+| compute | 2019-07-01 |
+| datafactory | 2018-06-01 |
+| documentdb | 2019-08-01
2019-08-01-preview |
+| network | 2019-08-01 |
+| resourcegraph | 2018-09-01 |
+| security | v1.0
v2.0
v3.0 |
+| sql | 2017-03-01-preview
v3.0 |
+| storage | 2019-06-01 |
+| virtualmachineimagebuilder | 2019-05-01-preview |
+
+## `v36.2.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| media | 2019-05-01-preview |
+| netapp | 2019-08-01 |
+| sql | v3.0 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| containerservice | 2019-06-01 |
+
+## `v36.1.0`
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| eventgrid | 2020-01-01-preview |
+
+## `v36.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| documentdb | 2019-08-01-preview |
+| machinelearningservices | 2019-11-01 |
+| managementgroups | 2019-11-01 |
+| policy | 2019-09-01 |
+| workspaces | 2019-10-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| datafactory | 2018-06-01 |
+| hanaonazure | 2017-11-03-preview |
+| securityinsight | 2017-08-01-preview |
+| storage | 2019-06-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| authoring | luis |
+| network | 2019-04-01
2019-06-01
2019-07-01
2019-08-01
2019-09-01 |
+| serialconsole | 2018-05-01 |
+| signalr | 2018-10-01 |
+| sql | 2018-06-01-preview |
+| timeseriesinsights | 2018-08-15-preview |
+
+### Removed Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| documentdb | 2019-08-01-preview |
+
+## `v35.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| documentdb | 2019-08-01
2019-08-01-preview |
+
+## `v35.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| appconfiguration | 2019-10-01 |
+| authoring | luis |
+| containerservice | 2019-09-30-preview
2019-10-01 |
+| costmanagement | 2019-10-01
2019-10-01 |
+| datashare | 2019-11-01 |
+| hybridcompute | 2019-03-18-preview |
+| peering | 2019-09-01-preview |
+| policyinsights | 2019-10-01 |
+| storagecache | 2019-11-01 |
+| training | customvision |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| advisor | 2017-03-31
2017-04-19 |
+| apimanagement | 2019-01-01 |
+| compute | 2018-10-01 |
+| containerservice | 2019-08-01 |
+| datafactory | 2017-09-01-preview |
+| eventgrid | 2018-01-01 |
+| eventhub | 2018-01-01-preview |
+| maps | 2017-01-01-preview |
+| mysql | 2017-12-01-preview |
+| postgresql | 2017-12-01-preview |
+| qnamakerruntime | v4.0 |
+| sqlvirtualmachine | 2017-03-01-preview |
+| web | 2018-02-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| aad | 2017-01-01
2017-06-01 |
+| appplatform | 2019-05-01-preview |
+| backup | 2016-12-01
2017-07-01 |
+| cdn | 2019-04-15 |
+| cognitiveservices | 2017-04-18 |
+| compute | 2019-03-01
2019-07-01 |
+| containerregistry | 2017-10-01
2018-02-01
2018-09-01 |
+| datafactory | 2018-06-01 |
+| datashare | 2018-11-01-preview |
+| hdinsight | 2015-03-01-preview
2018-06-01-preview |
+| operationalinsights | 2015-03-20 |
+| reservations | 2019-04-01 |
+| security | v3.0 |
+| servicebus | 2017-04-01 |
+| sql | 2014-04-01 |
+| storage | 2019-04-01 |
+| vmwarecloudsimple | 2019-04-01 |
+| web | 2019-08-01 |
+
+### Removed Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| sql | 2018-06-15-preview |
+
+## `v34.4.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| eventgrid | 2020-01-01-preview |
+| sql | 2018-06-15-preview |
+
+## `v34.3.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| network | 2019-09-01 |
+| runtime | luis |
+| storage | 2019-06-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| datamigration | 2018-07-15-preview |
+
+### Removed Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| runtime | luis |
+
+## `v34.2.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| appplatform | 2019-05-01-preview |
+| web | 2019-08-01 |
+
+## `v34.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| features | 2019-07-01 |
+| network | 2019-08-01 |
+| affinitygroup | management |
+| auth | keyvault |
+| hostedservice | management |
+| location | management |
+| mongodb | cosmos-db |
+| networksecuritygroup | management |
+| osimage | management |
+| programmatic | luis |
+| sql | management |
+| storageservice | management |
+| testutils | management |
+| virtualmachine | management |
+| virtualmachinedisk | management |
+| virtualmachineimage | management |
+| virtualnetwork | management |
+| vmutils | management |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| compute | 2019-03-01
2019-07-01 |
+
+Revert deletion of packages in `classic\management` and `keyvault\auth`
+
+## `v34.0.0`
+
+### New Packages
+| Package Name | API Version |
+| -----------: | :---------: |
+| databox | 2019-09-01 |
+| databoxedge | 2019-03-01
2019-07-01 |
+| frontdoor | 2019-04-01
2019-05-01 |
+| healthcareapis | 2019-09-16 |
+| kusto | 2019-09-07 |
+| logic | 2019-05-01 |
+| maintenance | 2018-06-01-preview |
+| storagedatalake | 2019-10-31 |
+| subscriptions | 2019-06-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| appconfiguration | 2019-02-01-preview |
+| datashare | 2018-11-01-preview |
+| eventgrid | 2018-01-01 |
+| eventhub | 2017-04-01 |
+| kusto | 2019-05-15 |
+| network | 2018-07-01
2018-08-01
2018-10-01
2018-11-01
2018-12-01
2019-02-01 |
+| servicebus | 2017-04-01 |
+| sql | 2015-05-01-preview
2017-03-01-preview |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2019-01-01 |
+| compute | 2016-03-30
2017-03-30
2017-12-01
2018-04-01
2018-06-01
2018-10-01
2019-03-01
2019-07-01 |
+| containerregistry | 2019-05-01-preview
2019-06-01-preview |
+| containerservice | 2019-06-01
2019-08-01 |
+| datafactory | 2018-06-01 |
+| datamigration | 2018-03-31-preview
2018-04-19
2018-07-15-preview |
+| documentdb | 2015-04-08 |
+| frontdoor | 2018-08-01-preview |
+| machinelearningservices | 2019-06-01 |
+| managednetwork | 2019-06-01-preview |
+| network | 2019-04-01 |
+| reservations | 2019-04-01 |
+| security | v1.0
v2.0
v3.0 |
+| securityinsight | 2017-08-01-preview |
+| storage | 2019-04-01 |
+
+### Removed Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| affinitygroup | management |
+| anomalyfinder | v2.0 |
+| auth | keyvault |
+| batch | 2015-12-01.2.2
2016-02-01.3.0
2016-07-01.3.1
2017-01-01.4.0
2017-06-01.5.1
2017-09-01.6.0 |
+| computervision | v1.0 |
+| devspaces | 2018-06-01-preview
2019-01-01-preview |
+| edgegateway | 2019-03-01 |
+| frontdoor | preview/2019-04-01
preview/2019-05-01 |
+| hostedservice | management |
+| insights | v1 |
+| location | management |
+| mobileengagement | 2014-12-01 |
+| mongodb | cosmos-db |
+| networksecuritygroup | management |
+| osimage | management |
+| peering | 2019-03-01-preview |
+| portal | 2015-11-01-preview |
+| programmatic | luis |
+| servicefabric | 2019-03-01 |
+| services | 2018-03-01-preview |
+| sql | management |
+| storageservice | management |
+| testutils | management |
+| virtualmachine | management |
+| virtualmachinedisk | management |
+| virtualmachineimage | management |
+| virtualnetwork | management |
+| vmutils | management |
+
+## `v33.4.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| netapp | 2019-07-01 |
+
+## `v33.3.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| network | 2019-07-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| network | 2019-06-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| sql | 2017-10-01-preview
2018-06-01-preview |
+
+## `v33.2.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| sql | 2018-06-01-preview |
+
+## `v33.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| storagecache | 2019-08-01-preview |
+
+## `v33.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| batch | 2019-08-01
2019-08-01.10.0 |
+| computervision | v2.1 |
+| containerregistry | 2019-07 |
+| containerservice | 2019-08-01 |
+| frontdoor | 2019-05-01 |
+| machinelearningservices | 2019-06-01 |
+| managednetwork | 2019-06-01-preview |
+| peering | 2019-08-01-preview |
+| policy | 2019-06-01 |
+| portal | 2018-10-01-preview |
+| servicefabric | 2019-03-01-preview |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| backup | 2016-12-01
2017-07-01 |
+| frontdoor | 2019-04-01 |
+| logic | 2016-06-01
2018-07-01-preview |
+| network | 2018-07-01
2018-08-01
2018-10-01
2018-11-01
2018-12-01 |
+| resources | 2015-11-01
2016-02-01
2016-07-01
2016-09-01
2017-05-10
2018-02-01
2018-05-01
2019-03-01
2019-05-01 |
+| security | v2.0 |
+| sql | 2015-05-01-preview
2017-03-01-preview
2017-10-01-preview |
+| storage | 2019-04-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| billing | 2018-11-01-preview |
+| compute | 2019-03-01
2019-07-01 |
+| datafactory | 2018-06-01 |
+| datamigration | 2017-11-15-preview
2018-03-31-preview
2018-04-19
2018-07-15-preview |
+| hanaonazure | 2017-11-03-preview |
+| healthcareapis | 2018-08-20-preview |
+| inkrecognizer | v1.0 |
+| insights | 2015-05-01 |
+| kusto | 2019-01-21 |
+| network | 2019-02-01
2019-04-01
2019-06-01 |
+| qnamaker | v4.0 |
+| reservations | 2019-04-01 |
+| security | v3.0 |
+| securityinsight | 2017-08-01-preview |
+| servicefabric | 2019-03-01 |
-## `v14.2.0`
+## `v32.6.0`
-### Changes
+### New Packages
-- For blob storage, added GetProperties() method to Container.
-- Added PublicAccess field to ContainerProperties struct.
+| Package Name | API Version |
+| -----------: | :---------: |
+| kusto | 2019-05-15 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| datalake | 2018-06-17 |
-## `v14.1.1`
+## `v32.5.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| servicebus | 2018-01-01-preview |
-- Fixing timestamp marshalling bug in the `storage` package.
-- Updating `profileBuilder` to clear-output folders when it is run by `go generate`.
-- Tweaking Swagger -> SDK config to use "latest" instead of "nightly" and be tied to a particular version of autorest.go.
+## `v32.4.0`
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| datamigration | 2018-07-15-preview |
+
+## `v32.3.0`
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| subscription | 2018-03-01-preview |
+
+## `v32.2.0`
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| hdinsight | 2015-03-01-preview
2018-06-01-preview |
+
+## `v32.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| qnamakerruntime | v4.0 |
+
+### Fixed a bug with the table query continuation token in the ./storage package.
+
+## `v32.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| aad | 2017-04-01 |
+| compute | 2019-07-01 |
+| datashare | 2018-11-01-preview |
+| devops | 2019-07-01-preview |
+| enterpriseknowledgegraphservice | 2018-12-03 |
+| managedservices | 2019-06-01 |
+| migrate | 2018-09-01-preview |
+| mysql | 2017-12-01-preview |
+| network | 2019-06-01 |
+| policy | 2019-01-01 |
+| portal | 2015-08-01-preview
2019-01-01-preview |
+| postgresql | 2017-12-01-preview |
+| windowsiot | 2019-06-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| alertsmanagement | 2019-05-05 |
+| authoring | luis |
+| cdn | 2019-04-15 |
+| datafactory | 2017-09-01-preview |
+| datamigration | 2018-07-15-preview |
+| devices | 2019-03-22-preview |
+| hanaonazure | 2017-11-03-preview |
+| signalr | 2018-10-01 |
+| subscriptions | 2018-06-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| compute | 2019-03-01 |
+| contentmoderator | v1.0 |
+| datafactory | 2018-06-01 |
+| documentdb | 2015-04-08 |
+| dtl | 2018-09-15 |
+| healthcareapis | 2018-08-20-preview |
+| insights | 2018-03-01
2018-09-01
2018-11-01-preview
2019-03-01
2019-06-01 |
+| machinelearningservices | 2019-05-01 |
+| managedservices | 2018-06-01 |
+| network | 2019-04-01 |
+| reservations | 2019-04-01 |
+| security | v1.0
v2.0
v3.0 |
+| securityinsight | 2017-08-01-preview |
+| storage | 2019-04-01 |
+
+## `v31.2.0`
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2019-01-01 |
+
+## `v31.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| alertsmanagement | 2019-03-01 |
+| authorization | 2018-07-01-preview |
+| batch | 2019-04-01 |
+| containerregistry | 2019-06-01-preview |
+| netapp | 2019-06-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| alertsmanagement | 2018-05-05-preview |
+| hdinsight | 2015-03-01-preview
2018-06-01-preview |
+| sqlvirtualmachine | 2017-03-01-preview |
+
+## `v31.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| alertsmanagement | 2019-05-05 |
+| appconfiguration | 2019-02-01-preview |
+| cdn | 2019-06-15-preview |
+| containerservice | 2019-06-01 |
+| insights | 2019-06-01 |
+| machinelearningservices | 2018-03-01-preview
2018-11-19
2019-05-01 |
+| network | 2019-04-01 |
+| resources | 2019-05-01 |
+| servicefabric | 6.5 |
+| softwareplan | 2019-06-01-preview |
+| vmwarecloudsimple | 2019-04-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| cognitiveservices | 2017-04-18 |
+| compute | 2019-03-01 |
+| containerregistry | 2019-04-01
2019-05-01 |
+| hanaonazure | 2017-11-03-preview |
+| hdinsight | 2015-03-01-preview
2018-06-01-preview |
+| insights | 2017-05-01-preview
2018-03-01
2018-09-01
2018-11-01-preview
2019-03-01 |
+| managementgroups | 2018-03-01-preview |
+| media | 2018-07-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| alertsmanagement | 2018-05-05 |
+| authorization | 2015-07-01 |
+| billing | 2018-11-01-preview |
+| blueprint | 2018-11-01-preview |
+| computervision | v2.0 |
+| datafactory | 2017-09-01-preview
2018-06-01 |
+| eventgrid | 2018-01-01 |
+| eventhub | 2015-08-01
2018-01-01-preview |
+| face | v1.0 |
+| netapp | 2019-05-01 |
+| network | 2015-06-15
2016-09-01
2016-12-01
2017-03-01
2017-06-01
2017-08-01
2017-09-01
2017-10-01
2017-11-01
2018-01-01
2018-02-01
2018-04-01
2018-06-01
2018-07-01
2018-08-01
2018-10-01
2018-11-01
2018-12-01
2019-02-01 |
+| reservations | 2019-04-01 |
+| resourcegraph | 2019-04-01 |
+| securityinsight | 2017-08-01-preview |
+| sql | 2015-05-01-preview
2017-03-01-preview |
+| storage | 2019-04-01 |
+
+## `v30.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| batch | 2019-06-01.9.0 |
+| managedservices | 2019-04-01 |
+| personalizer | v1.0 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| authorization | 2017-10-01-preview
2018-01-01-preview
2018-09-01-preview |
+| automation | 2015-10-31
2017-05-15-preview
2018-01-15-preview
2018-06-30-preview |
+| datafactory | 2018-06-01 |
+| datamigration | 2018-07-15-preview |
+| documentdb | 2015-04-08 |
+| formrecognizer | v1.0 |
+| hanaonazure | 2017-11-03-preview |
+| hdinsight | 2018-06-01-preview |
+| postgresql | 2017-12-01 |
+| qnamaker | v4.0 |
+| signalr | 2018-10-01 |
+
+## `v30.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| blockchain | 2018-06-01-preview |
+| containerregistry | 2019-05-01
2019-05-01-preview |
+| costmanagement | 2019-03-01 |
+| devices | 2019-03-22-preview |
+| devspaces | 2019-04-01 |
+| dns | 2018-05-01 |
+| eventgrid | 2019-06-01 |
+| security | v3.0 |
+| servicefabric | 2019-03-01
2019-03-01 |
+
+### Updated Packages
+
+| account | 2016-11-01 |
+| advisor | 2017-04-19 |
+| billing | 2018-11-01-preview |
+| cdn | 2019-04-15 |
+| cognitiveservices | 2017-04-18 |
+| customproviders | 2018-09-01-preview |
+| datafactory | 2018-06-01 |
+| devices | 2018-12-01-preview |
+| eventgrid | 2018-01-01 |
+| hanaonazure | 2017-11-03-preview |
+| kusto | 2019-01-21 |
+| managementpartner | 2018-02-01 |
+| mariadb | 2018-06-01 |
+| mysql | 2017-12-01 |
+| network | 2019-02-01 |
+| operationsmanagement | 2015-11-01-preview |
+| postgresql | 2017-12-01 |
+| servicefabric | 2016-09-01 |
+| web | 2018-02-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| analysisservices | 2017-08-01 |
+| authoring | luis |
+| automation | 2018-01-15-preview
2018-06-30-preview |
+| blueprint | 2018-11-01-preview |
+| compute | 2017-12-01 |
+| computervision | v2.0 |
+| contentmoderator | v1.0 |
+| documentdb | 2015-04-08 |
+| insights | 2015-05-01 |
+| netapp | 2019-05-01 |
+| resources | 2018-05-01 |
+| security | v1.0
v2.0 |
+| servicefabric | 2017-07-01-preview
2018-02-01 |
+| spellcheck | v1.0 |
+| subscriptions | 2016-06-01 |
+
+## `v29.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| cdn | 2019-04-15 |
+| customproviders | 2018-09-01-preview |
+| formrecognizer | v1.0 |
+| inkrecognizer | v1.0 |
+| portal | 2015-11-01-preview |
+| runtime | luis |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| insights | 2018-03-01
2018-09-01
2018-11-01-preview
2019-03-01 |
+| locks | 2016-09-01 |
+| sql | 2014-04-01
2017-10-01-preview |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2019-01-01 |
+| containerservice | 2019-04-30 |
+| graphrbac | 1.6 |
+| sql | 2015-05-01-preview
2017-03-01-preview |
+| storage | 2019-04-01 |
+
+## `v28.1.0`
+
+Fixed build issue in legacy storage package affecting some consumers.
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| resourcegraph | 2018-09-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| eventhub | 2018-01-01-preview |
+
+## `v28.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| containerregistry | 2019-04-01 |
+| containerservice | 2019-04-30 |
+| hybriddata | 2016-06-01 |
+| netapp | 2019-05-01 |
+| network | 2019-02-01 |
+| resources | 2019-03-01 |
+| serialconsole | 2018-05-01 |
+| storage | 2019-04-01 |
+| subscriptions | 2018-06-01 |
+| virtualmachineimagebuilder | 2019-05-01-preview |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| cognitiveservices | 2017-04-18 |
+| consumption | 2019-01-01 |
+| costmanagement | 2019-01-01 |
+| datafactory | 2018-06-01 |
+| eventgrid | 2018-01-01 |
+| iotcentral | 2018-09-01 |
+| qnamaker | v4.0 |
+| sql | 2017-10-01-preview |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2018-06-01-preview
2019-01-01 |
+| billing | 2018-11-01-preview |
+| compute | 2019-03-01 |
+| cosmos-db | 2015-04-08 |
+| documentdb | 2015-04-08 |
+| hanaonazure | 2017-11-03-preview |
+| insights | 2018-03-01
2018-09-01
2018-11-01-preview
2019-03-01 |
+| mysql | 2017-12-01 |
+| network | 2017-06-01
2017-08-01
2017-09-01
2017-10-01
2017-11-01
2018-01-01
2018-02-01
2018-04-01
2018-06-01
2018-07-01
2018-08-01
2018-10-01
2018-11-01
2018-12-01 |
+| operationalinsights | 2015-11-01-preview |
+| policyinsights | 2018-07-01-preview |
+| postgresql | 2017-12-01 |
+| resources | 2018-05-01 |
+| runtime | luis |
+| sql | 2015-05-01-preview
2017-03-01-preview |
+| storagedatalake | 2018-11-09 |
+| subscriptions | 2016-06-01 |
+| virtualmachineimagebuilder | 2019-02-01-preview |
+| web | 2018-02-01 |
+
+### Removed Packages (duplicates)
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| automation | 2017-05-15-preview |
+| compute | 2017-06-01-preview |
+| devices | 2018-12-01-preview |
+| fabric | 2016-05-01 |
+| infrastructureinsights | 2016-05-01 |
+| mariadb | 2018-06-01-preview |
+| postgresql | 2017-04-30-preview
2017-12-01-preview |
+| reservations | 2018-06-01 |
+| storagesync | 2018-10-01 |
+
+## `v27.3.0`
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| anomalydetector | v1.0 |
+
+### Breaking Changes - Preview Only
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| hanaonazure | 2017-11-03-preview |
+
+## `v27.2.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2019-01-01 |
+| reservations | 2019-04-01 |
+
+## `v27.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| compute | 2019-03-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| cdn | 2017-10-12 |
+| compute | 2018-10-01 |
+| containerservice | 2018-08-01-preview
2018-09-30-preview
2019-02-01 |
+| datafactory | 2018-06-01 |
+| hdinsight | 2018-06-01-preview |
+| postgresql | 2017-12-01 |
+| recoveryservices | 2016-06-01 |
+| security | v1.0
v2.0 |
+| securityinsight | 2017-08-01-preview |
+| storage | 2018-02-01
2018-03-01-preview
2018-07-01
2018-11-01 |
+
+### Breaking Changes - Preview Only
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| hdinsight | 2015-03-01-preview |
+
+## `v27.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| billing | 2018-11-01-preview |
+| frontdoor | 2019-04-01 |
+| healthcareapis | 2018-08-20-preview |
+| managedservices | 2018-06-01 |
+| peering | 2019-03-01-preview |
+| resourcegraph | 2019-04-01 |
+| storagesync | 2019-02-01 |
+| virtualmachineimagebuilder | 2018-02-01-preview
2019-02-01-preview |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| adhybridhealthservice | 2014-01-01 |
+| catalog | 2016-11-01-preview |
+| containerregistry | 2017-10-01
2018-02-01
2018-09-01 |
+| eventgrid | 2018-01-01 |
+| eventhub | 2017-04-01 |
+| hanaonazure | 2017-11-03-preview |
+| mysql | 2017-12-01 |
+| postgresql | 2017-12-01 |
+| security | v1.0
v2.0 |
+| servicebus | 2017-04-01 |
+| signalr | 2018-10-01 |
+| sql | 2017-03-01-preview |
+| storage | 2018-11-01 |
-## `v14.1.0`
+### BreakingChanges
-### Changes
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2018-06-01-preview |
+| authoring | luis |
+| blueprint | 2018-11-01-preview |
+| cdn | 2017-10-12 |
+| compute | 2018-10-01 |
+| computervision | v2.0 |
+| datafactory | 2017-09-01-preview
2018-06-01 |
+| devices | 2018-12-01-preview |
+| edgegateway | 2019-03-01 |
+| face | v1.0 |
+| graphrbac | 1.6 |
+| insights | 2018-03-01 |
+| postgresqlapi | postgresql |
+| search | 2015-08-19 |
+| web | 2018-02-01 |
+| webservices | 2017-01-01 |
-- Update README with details on new authentication helpers.
-- Update `latest` profile to point to latest stable API versions.
-- Add new API version for Azure Monitoring service and for Batch Data plane service.
+## `v26.7.0`
-## `v14.0.2`
+| Package Name | API Version |
+| -----------: | :---------: |
+| training | v3.0 |
-### Changes
+## `v26.6.0`
-- Updating `profileBuilder list` to accept an `input` flag instead of reading from `stdin`.
-- Simplifying CI to have less chatter, be faster, and have no special cases.
+## New Packages
-## `v14.0.1`
+| Package Name | API Version |
+| -----------: | :---------: |
+| prediction | v3.0 |
-### Changes
+### Updated Packages
-- Removed the ./services/search/2016-09-01/search package, it was never intended to be included and doesn't work.
+| Package Name | API Version |
+| -----------: | :---------: |
+| marketplaceordering | 2015-06-01 |
+| media | 2018-07-01 |
-## `v14.0.0`
+### Breaking Changes - Preview
-### Breaking Changes
+| Package Name | API Version |
+| -----------: | :---------: |
+| netapp | 2017-08-15 |
-- Removed the ./arm, ./datalake-store and ./dataplane directories. You can find the same packages under ./services
-- The management package was moved to ./services/classic/management
-- Renamed package ./services/redis/mgmt/2017-10-01/cache to ./services/redis/mgmt/2017-10-01/redis
+## `v26.5.0`
+
+### New Packages
-### Changes
+| Package Name | API Version |
+| -----------: | :---------: |
+| anomalydetector | v1.0 |
+| containerservice | 2019-02-01 |
+| storage | 2018-11-01 |
-- Removed the "-beta" suffix.
-- Added various new services.
-- Added ./version package for centralized SDK versioning.
+### Updated Packages
-## `v12.5.0-beta`
+| Package Name | API Version |
+| -----------: | :---------: |
+| network | 2018-12-01 |
+
+## `v26.4.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| insights | 2019-03-01 |
+
+## `v26.3.1`
+
+Remove committed vendored content.
+
+## `v26.3.0`
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| eventgrid | 2019-02-01-preview |
-### Changes
+### Updated Packages
-- Added Container Instance API Versions 2017-10-01-preview, 2017-12-01-preview, and 2018-02-01-preview.
+| Package Name | API Version |
+| -----------: | :---------: |
+| marketplaceordering | 2015-06-01 |
-## `v12.4.0-beta`
+## `v26.2.0`
-### Changes
+### New Packages
-- Added API version 2017-12-01 for the compute package.
+| Package Name | API Version |
+| -----------: | :---------: |
+| mariadb | 2018-06-01 |
+| netapp | 2017-08-15 |
+| security | v2.0 |
+| translatortext | v3.0 |
-## `v12.3.0-beta`
+### Updated Packages
-### Changes
+| Package Name | API Version |
+| -----------: | :---------: |
+| sql | 2015-05-01-preview
2017-03-01-preview |
-- Updated event grid dataplane with latest swagger changes.
-- Added latest event grid management plane API version.
+### Moved Packages
-## `v12.2.0-beta`
+| Package Name | API Version |
+| -----------: | :---------: |
+| security | 2017-08-01-preview -> v1.0 |
-### Changes
+## `v26.1.0`
-#### Storage
+### New Packages
-- Add support for creating a SAS client from an endpoint and SAS token.
-- Fixed bug that wasn't appending SAS token to URI query parameters in all cases.
+| Package Name | API Version |
+| -----------: | :---------: |
+| mixedreality | 2019-02-28 |
+| trafficmanager | 2018-04-01 |
-## `v12.1.1-beta`
+### Updated Packages
-### Changes
+| Package Name | API Version |
+| -----------: | :---------: |
+| mysql | 2017-12-01 |
+| postgresql | 2017-12-01 |
+| search | 2015-08-19 |
-- Removing (at least temporarily) calls to `uuid.NewV1()` due to breaking changes (see https://github.com/Azure/azure-sdk-for-go/issues/947 for more info).
-- Deleted glide files as we are now using dep.
+## `v26.0.0`
-## `v12.1.0-beta`
+### New Packages
-### New Services
+| Package Name | API Version |
+| -----------: | :---------: |
+| anomalyfinder | v2.0 |
+| blueprint | 2018-11-01-preview |
+| costmanagement | 2019-01-01 |
+| devspaces | 2019-01-01-preview |
+| edgegateway | 2019-03-01 |
+| network | 2018-12-01 |
+| privatedns | 2018-09-01 |
-#### Data plane
-- Cognitive Services Computer Vision
-- Cognitive Services Content Moderator
-- Cognitive Services LUIS
+### Updated Packages
-## `v12.0.0-beta`
-
-### Changes
-- Long Running Operations now return a `Future` type. Go routines and return via channel features have been removed.
-- Added support for services that make use of polymorphic types.
-- Operations now make use of the [Context Pattern](https://blog.golang.org/context).
-- Container Services has been moved out of Compute folder in its own folder.
-- Azure Go SDK is now using [dep](https://github.com/golang/dep) for vendoring.
-- The *arm* and *dataplane* folders have been deprecated. Use the *profiles* and the *services* folders instead.
-- Group clients have been renamed to a a service specific name.
-
-### New Services
-
-#### Management Plane
-- Azure Container Service for Kubernetes (AKS)
-- Azure MSI Service
-
-#### Data plane
-- Cognitive Services Custom Search
-- Cognitive Services Entity Search
-- Cognitive Services Image Search
-- Cognitive Services News Search
-- Cognitive Services Video Search
-- Cognitive Services Web Search
-- Cognitive Services Spell Check
-- MongoDb for CosmosDb
-
-
-### Generated code notes
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 515f358fe1e521441aec5d63d62b5f0affcc8ea9
-- [AutoRest Go Generator](https://github.com/Azure/autorest.go) commit: c759908a0d8726eb755afd93353c58e072c345af
-
-## `v11.3.0-beta`
-
-### ARM
-
-- Added storage API version 2017-10-01.
-
-## `v11.2.2-beta`
-
-### Bug Fixes
- - Regenerating `latest` and `preview` profiles after deleting falsely included apimanagement.
-
-## `v11.2.1-beta`
-
-### Bug Fixes
- - Commenting out ignore rule that false-positived on the graphrbac package.
-
-## `v11.2.0-beta`
-
-### Repository Structure
- - Adding support for Multi-API Version paradigm in `services` directory.
- - Adding support for Azure Profile in `profiles` directory.
-
-### Storage
- - Added operations for getting and setting container metadata.
- - Fixed unmarshaling bug on list containers operation.'
-
-### Generated code notes
-
-- Services directory generated from [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 274c99f7bd93d8b98048e31b74a34333cecded74
-- [AutoRest Go Generator](https://github.com/Azure/autorest.go) version: 2.0.41
-
-## `v11.1.1-beta`
-
-### ARM
-
-- Registers resource providers if necessary.
-- Requires go-autorest v9.1.0
-
-### Generated code notes
-
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commits:
- - All services except trafficmanager and containerregistry: 0c2a12b50d8598f68d6715b507f7dd53e163407e
- - trafficmanager and containerregistry: c97a18ed775029207715b09c80761334724740b9
-- [AutoRest Go Generator](https://github.com/Azure/autorest.go) version: 2.0.36
-
-### Storage
-
-- Fixed bug in which blob types were unmarshaed incorrectly.
-
-## `v11.1.0-beta`
-
-### ARM
-
-- trafficmanager and containerregistry SDKs now reflect the services faithfully
-- trafficmanager also has a new operation group: user metrics.
-
-### Generated code notes
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: c97a18ed775029207715b09c80761334724740b9
-- [AutoRest Go Generator](https://github.com/Azure/autorest.go) commit: 5d984152f2e9cff6878ea5060bed7e8d8a2ae1cc
-
-## `v11.0.0-beta`
-
-### ARM
-
-| api | version | note |
-|:------------------------------------|:-------------------|:------------------------------------|
-| arm/analysisservices | 2017-08-01-beta | update |
-| arm/batch | 2017-05-01 | update |
-| arm/cdn | 2017-04-02 | update |
-| arm/cognitiveservices | 2017-04-18 | update |
-| arm/compute | multiple | update |
-| arm/containerregistry | 2017-10-01 | update |
-| arm/customerinsights | 2017-04-26 | update |
-| arm/eventgrid | 2017-09-15-preview | update |
-| arm/eventhub | 2017-04-01 | update |
-| arm/graphrbac | 1.6 | update |
-| arm/iothub | 2017-07-01 | update |
-| arm/keyvault | 2016-10-01 | update |
-| arm/marketplaceordering | 2015-06-01 | new |
-| arm/opertionalinsights | multiple | update |
-| arm/operationsmanagement | 2015-11-01-preview | new |
-| arm/recoveryservices | multiple | update |
-| arm/recoveryservicesbackup | multiple | update |
-| arm/redis | 2017-02-01 | update |
-| arm/relay | 2017-04-01 | update |
-| arm/resourcehealth | 017-07-01 | update |
-| arm/resources/resources | 2017-05-10 | update |
-| arm/servicebus | 2017-04-01 | update |
-| arm/storage | 2017-06-01 | update |
-| arm/streamanalytics | 2016-03-01 | update |
-| arm/trafficmanager | 2017-09-01-preview | update |
-| arm/visualstudio | 2014-04-01-preview | update |
-
-### Data plane
-
-| api | version | note |
-|:------------------------------------|:-------------------|:------------------------------------|
-| dataplane/cognitiveservices/face | 1.0 | new |
-| dataplane/cognitiveservices/textanalytics | v2.0 | new |
-
-### Storage
-
-- Support for queue SAS.
-- Refactored GetSASURI blob operation to be more complete.
-- Added a SAS client for some operations (`container.Exists()`, and `container.ListBlobs()`)
-
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 0c2a12b50d8598f68d6715b507f7dd53e163407e
-- [AutoRest Go Generator](https://github.com/Azure/autorest.go) commit: 678110f012c7cde6528a1e61d125bdc7ea636b7f
-
-## `v10.3.1-beta`
-- Added Apache notice file.
-
-### ARM
-- Fixed package name on some `version.go` files.
-
-### Storage
-- Fixed bug related to SAS URI generation and storage emulator support.
-
-### Generated code notes
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: ad55af74f3f0e2b390a4306532528168ba742fef
-- [AutoRest Go extension](https://github.com/Azure/autorest.go) commit: 28a531c59c82cf67bc90c87095c1d34a936461b4
-
-## `v10.3.0-beta`
-### ARM
-
-| api | version | note |
-|:------------------------------------|:-------------------|:------------------------------------|
-| arm/containerinstance | 2017-08-01-preview | new |
-| arm/eventgrid | 2017-06-15-preview | new |
-
-### ASM
-- Marked as in mainteinance mode.
-- Added Go 1.7 build tags.
-
-### Storage
-- Support for Go 1.7 and Go 1.6 (except table batch operation tests).
-
-### Generated code notes
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: ad55af74f3f0e2b390a4306532528168ba742fef
-- [AutoRest](https://github.com/Azure/autorest) commit: cfb296f153f948f85afab637f7212fcfdc4a8bbb
-
-## `v10.2.1-beta`
-- Fixes polymorphic structs in `mysql` and `postgresql` packages.
-
-## `v10.2.0-beta`
-### ARM
-
-| api | version | note |
-|:------------------------------------|:-------------------|:------------------------------------|
-| arm/cosmos-db | 2015-04-08 | new |
-| arm/mysql | 2017-04-30-preview | new |
-| arm/postgresql | 2017-04-30-preview | new |
-
-### Storage
-- Bug fixes.
-
-### Generated code notes
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 485ded7560c6309efb2f795ec6e46b7436dc6fdb
-- [AutoRest](https://github.com/Azure/autorest) commit: c180952b850e677a8624655abeaded307d95cae3
-
-## `v10.1.0-beta`
-### ARM
-
-| arm/recoveryservicessiterecovery | 2016-08-10 | new |
-| arm/managedapplications | 2016-09-01-preview | new |
-| arm/storsimple8000series | 2017-06-01 | new |
-| arm/streamanalytics | multiple | new |
-
-### Storage
-- Bug fixes.
-
-### Generated code notes
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: a2cdf005407b81edb161c1f7b5c49b5ce8e7f041
-- [AutoRest](https://github.com/Azure/autorest) commit: 8e9c2d3704a04913a175ab76972b7d9597c77687
-
------
-## `v10.0.0-beta`
-### ARM
-In addition to the tabulated changes below, each package had the following updates:
-- Long running operations now run inside a goroutine and return channels for the response and the errors.
-- Some functions changed from returning `autorest.Response` to return the already unmarshaled struct.
-- Uses go-autorest v8.0.0.
-
-| api | version | note |
-|:------------------------------------|:-------------------|:------------------------------------|
-| arm/advisor | 2017-04-19 | new |
-| arm/analysisservices | 2016-05-16 | refactor |
-| arm/apimanagement | 2016-10-10 | update to latest swagger & refactor |
-| arm/appinsights | 2015-05-01 | new |
-| arm/automation | 2015-10-31 | new |
-| arm/billing | 2017-04-24-preview | update to latest swagger & refactor |
-| arm/cdn | 2016-10-02 | refactor |
-| arm/commerce | 2015-06-01-preview | refactor |
-| arm/compute | 2016-04-30-preview | refactor |
-| arm/consumption | 2017-04-24-preview | new |
-| arm/containerregistry | 2017-03-01 | update to latest swagger & refactor |
-| arm/containerservice | 2017-01-31 | update to latest swagger & refactor |
-| arm/customer-insights | 2017-01-01 | refactor |
-| arm/datalake-analytics/account | 2016-11-01 | refactor |
-| arm/datalake-store/account | 2016-11-01 | refactor |
-| arm/devtestlabs | 2016-05-15 | refactor |
-| arm/disk | 2016-04-30-preview | refactor |
-| arm/dns | 2016-04-01 | refactor |
-| arm/documentdb | 2015-04-08 | refactor |
-| arm/eventhub | 2015-08-01 | refactor |
-| arm/graphrbac | 1.6 | refactor |
-| arm/hdinsight | 2015-03-01-preview | new |
-| arm/insights | multiple | new |
-| arm/intune | 2015-01-14-preview | refactor |
-| arm/iothub | 2016-02-03 | refactor |
-| arm/machinelearning/commitmentplans | 2016-05-01-preview | refactor |
-| arm/machinelearning/webservices | 2017-01-01 | update to latest swagger & refactor |
-| arm/monitor | multiple | new |
-| arm/network | 2017-03-01 | update to latest swagger & refactor |
-| arm/notificationhubs | 2017-04-01 | update to latest swagger & refactor |
-| arm/operationalinsights | 2015-11-01-preview | update to latest swagger & refactor |
-| arm/powerbiembedded | 2016-01-29 | refactor |
-| arm/recoveryservices | 2016-12-01 | refactor |
-| arm/recoveryservicesbackup | 2016-12-01 | new |
-| arm/redis | 2016-04-01 | refactor |
-| arm/relay | 2016-07-01 | new |
-| arm/resourcehealth | 2015-01-01 | new |
-| arm/resources/features | 2015-12-01 | refactor |
-| arm/resources/links | 2016-09-01 | refactor |
-| arm/resources/resources | 2016-09-01 | refactor |
-| arm/resources/subscriptions | 2016-06-01 | refactor |
-| arm/scheduler | 2016-03-01 | refactor |
-| arm/servermanagement | 2016-07-01-preview | refactor |
-| arm/servicebus | 2015-08-01 | refactor |
-| arm/servicefabric | 2016-09-01 | new |
-| arm/service-map | 2015-11-01-preview | refactor |
-| arm/sql | multiple | update to latest swagger & refactor |
-| arm/storage | 2016-12-01 | update to latest swagger & refactor |
-| arm/storageimportexport | 2016-11-01 | refactor |
-| arm/web | multiple | refactor |
-
-### Data plane
-| api | version | note |
-|:------------------------------------|:-------------------|:------------------------------------|
-| dataplane/keyvault | 2016-10-01 | refactor |
-
-### Storage
-Storage has returned to this repo.
-It has also been refactored:
-- Blobs, containers, tables, etc are now method receivers. These structs are the ones being
- updated with each operation.
-- When creating a client, the SDK checks if the storage account provided is valid.
-- Added retry logic. It provides the flexibility for user to provide their own retry logic.
-- Added operations:
- - Get table
- - Get entity
- - Get and set queue ACL
- - Table batch
- - Page blob incremental copy
-- All operations that previously had `extraHeaders` as parameter now recieve a struct with well
- defined possible headers and other options. Some functions are easier to use.
-- Storage tests now use HTTP recordings.
-
-### Generated code notes
-- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 519980465d9c195622d466dc4601b1999a448ed5
-- [AutoRest](https://github.com/Azure/autorest) commit: ced950d64e39735b84d41876a56b54b27c227dc7
-
-## `v9.0.0-beta`
-### ARM
-In addition to the tabulated changes below, each package had the following updates:
- - API Version is now associated with individual methods, instead of the client. This was done to
- support composite swaggers, which logically may contain more than one API Version.
- - Version numbers are now calculated in the generator instead of at runtime. This keeps us from
- adding new allocations, while removing the race-conditions that were added.
-
-| api | version | note |
-|:------------------------------------|:-------------------|:-----------------------------------|
-| arm/analysisservices | 2016-05-16 | update to latest swagger |
-| arm/authorization | 2015-07-01 | refactoring |
-| arm/batch | 2017-01-01 | update to latest swagger &refactor |
-| arm/cdn | 2016-10-02 | update to latest swagger |
-| arm/compute | 2016-04-30-preview | update to latest swagger |
-| arm/dns | 2016-04-01 | update to latest swagger &refactor |
-| arm/eventhub | 2015-08-01 | refactoring |
-| arm/logic | 2016-06-01 | update to latest swagger &refactor |
-| arm/notificationshub | 2016-03-01 | update to latest swagger &refactor |
-| arm/redis | 2016-04-01 | update to latest swagger &refactor |
-| arm/resources/resources | 2016-09-01 | update to latest swagger |
-| arm/servicebus | 2015-08-01 | update to latest swagger |
-| arm/sql | 2014-04-01 | update to latest swagger |
-| arm/web | multiple | generating from composite |
-| datalake-analytics/account | 2016-11-01 | update to latest swagger |
-| datalake-store/filesystem | 2016-11-01 | update to latest swagger |
-
-### Storage
-Storage has been moved to its own repository which can be found here:
-https://github.com/Azure/azure-storage-go
-
-For backwards compatibility, a submodule has been added to this repo. However, consuming storage
-via this repository is deprecated and may be deleted in future versions.
-
-## `v8.1.0-beta`
-### ARM
-| api | version | note |
-|:------------------------------------|:-------------------|:-----------------------------------|
-| arm/apimanagement | 2016-07-07 | new |
-| arm/apideployment | 2016-07-07 | new |
-| arm/billing | 2017-02-27-preview | new |
-| arm/compute | 2016-04-30-preview | update to latest swagger |
-| arm/containerservice | 2017-01-31 | update to latest swagger |
-| arm/customer-insights | 2017-01-01 | new |
-| arm/graphrbac | 1.6 | new |
-| arm/networkwatcher | 2016-12-01 | new |
-| arm/operationalinsights | 2015-11-01-preview | new |
-| arm/service-map | 2015-11-01-preview | new |
-| arm/storageimportexport | 2016-11-01 | new |
-
-### Data plane
-| api | version | note |
-|:------------------------------------|:-------------------|:-----------------------------------|
-| dataplane/keyvault | 2016-10-01 | new |
-
-- Uses go-autorest v7.3.0
-
-
-## `v8.0.0-beta`
-### ARM
-- In addition to the tablulated changes below, all updated packages received performance
- improvements to their Version() method.
-- Some validation that was taking place in the runtime was erroneously blocking calls.
- all packages have been updated to take that bug fix.
-
-| api | version | note |
-|:------------------------------------|:-------------------|:-----------------------------------|
-| arm/analysisservices | 2016-05-16 | update to latest swagger |
-| arm/cdn | 2016-10-02 | update to latest swagger |
-| arm/cognitiveservices | 2016-02-01-preview | update to latest swagger |
-| arm/compute | 2016-03-30 | update to latest swagger, refactor |
-| arm/containerregistry | 2016-06-27-preview | update to latest swagger |
-| arm/containerservice | 2016-09-30 | update to latest swagger |
-| arm/datalake-analytics | 2016-11-01 | update to latest swagger |
-| arm/datalake-store | 2016-11-01 | update to latest swagger |
-| arm/disk | 2016-04-30-preview | new |
-| arm/documentdb | 2015-04-08 | update to latest swagger |
-| arm/iothub | 2016-02-03 | update to latest swagger |
-| arm/keyvault | 2015-06-01 | update to latest swagger |
-| arm/logic | 2016-06-01 | update to latest swagger |
-| arm/machinelearning | 2016-05-01-preview | update to latest swagger |
-| arm/mobileengagement | 2014-12-01 | update to latest swagger, refactor |
-| arm/redis | 2016-04-01 | update to latest swagger |
-| arm/resources/locks | 2016-09-01 | refactor |
-| arm/resources/policy | 2016-12-01 | previous version was deleted |
-| arm/resources/resources | 2016-09-01 | update to latest swagger, refactor |
-| arm/scheduler | 2016-03-01 | refactor |
-| arm/search | 2015-08-19 | refactor |
-| arm/web | 2015-08-01 | refactor |
-
-## `v7.0.0-beta`
-
-| api | version | note |
-|:------------------------------------|:-------------------|:-----------------------------------|
-| arm/analysisservices | 2016-05-16 | new |
-| arm/cdn | 2016-10-02 | update to latest swagger |
-| arm/commerce | 2015-06-01-preview | new |
-| arm/containerservice | 2016-09-30 | update to latest swagger |
-| arm/containerregistry | 2016-06-27-preview | new |
-| arm/datalake-analytics/account | 2016-11-01 | update to latest swagger |
-| arm/datalake-store/account | 2016-11-01 | update to latest swagger |
-| arm/datalake-store/filesystem | 2016-11-01 | update to latest swagger |
-| arm/documentdb | 2015-04-08 | new |
-| arm/machinelearning/commitmentplans | 2016-05-01-preview | new |
-| arm/recoveryservices | 2016-06-01 | new |
-| arm/resources/subscriptions | 2016-06-01 | new |
-| arm/search | 2015-08-19 | update to latest swagger |
-| arm/sql | 2014-04-01 | previous version was deleted |
-
-### Storage
-- Can now update messages in storage queues.
-- Added support for blob snapshots and aborting blob copy operations.
-- Added support for getting and setting ACLs on containers.
-- Added various APIs for file and directory manipulation.
-
-### Support for the following swagger extensions was added to the Go generator which affected codegen.
-- x-ms-client-flatten
-- x-ms-paramater-location
-
-## `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
+| Package Name | API Version |
+| commitmentplans | 2016-05-01-preview |
+| computervision | v2.0 |
+| consumption | 2018-10-01 |
+| hanaonazure | 2017-11-03-preview |
+| operationalinsights | 2015-03-20 |
+| webapi | web |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| containerservice | 2018-03-31
2018-08-01-preview
2018-09-30-preview |
+| costmanagement | 2018-08-01-preview |
+| datafactory | 2018-06-01 |
+| eventgrid | 2018-01-01 |
+| face | v1.0 |
+| kusto | 2019-01-21 |
+| policyinsights | 2018-07-01-preview |
+| security | 2017-08-01-preview |
+| securityinsight | 2017-08-01-preview |
+| sql | 2015-05-01-preview
2017-03-01-preview |
+| storagedatalake | 2018-11-09 |
+| textanalytics | v2.1 |
+| web | 2018-02-01 |
+
+### Removed Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| blueprint | 2017-11-11-preview |
+| edgegateway | 2018-07-01 |
+
+## `v25.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| consumption | 2019-01-01 |
+| kusto | 2019-01-21 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| authorization | 2015-07-01 |
+| backup | 2017-07-01 |
+| compute | 2018-10-01 |
+| eventgrid | 2018-01-01 |
+| eventhub | 2017-04-01 |
+| sql | 2017-03-01-preview |
+
+## `v25.0.0`
+
+NOTE: Go 1.8 has been removed from CI due to a transitive dependency no longer supporting it.
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| devices | 2018-12-01-preview |
+| insights | 2018-11-01-preview |
+| securityinsight | 2017-08-01-preview |
+| storagedatalake | 2018-11-09 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| cognitiveservices | 2017-04-18 |
+| containerregistry | 2018-09-01 |
+| eventgrid | 2018-01-01 |
+| hdinsight | 2015-03-01-preview
2018-06-01-preview |
+| network | 2018-11-01 |
+| runtime | luis |
+| sql | 2015-05-01-preview
2017-03-01-preview
2017-10-01-preview |
+| web | 2018-02-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| adhybridhealthservice | 2014-01-01 |
+| backup | 2016-12-01
2017-07-01 |
+| blueprint | 2017-11-11-preview |
+| containerservice | 2018-03-31
2018-08-01-preview
2018-09-30-preview |
+| datafactory | 2017-09-01-preview
2018-06-01 |
+| face | v1.0 |
+| hanaonazure | 2017-11-03-preview |
+| insights | 2017-05-01-preview |
+| logic | 2018-07-01-preview |
+| security | 2017-08-01-preview |
+| storage | 2015-05-01-preview
2015-06-15
2016-01-01
2016-05-01
2016-12-01
2017-06-01
2017-10-01
2018-02-01
2018-03-01-preview
2018-07-01 |
+| virtualmachine | management |
+
+### Removed Packages
+
+NOTE: Some removed packages are preview packages that were incorrectly placed in the stable location. The copies under `preview` still exist.
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2018-01-01 |
+| datafactory | 2017-09-01-preview |
+| dns | 2018-03-01-preview |
+| insights | 2017-09-01 |
+| iothub | 2017-08-21-preview |
+| managedapplications | 2016-09-01-preview |
+| managementpartner | 2018-02-01 |
+| policy | 2015-10-01-preview
2017-06-01-preview |
+| servicefabric | 1.0.0
5.6
6.0
6.1 |
+| storagedatalake | 2018-06-17
2018-11-09 |
+
+## `v24.1.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| edgegateway | 2018-07-01 |
+| network | 2018-11-01 |
+| storagesync | 2018-10-01 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2018-06-01-preview |
+| automation | 2017-05-15-preview
2018-01-15-preview
2018-06-30-preview |
+| classic | management |
+| containerservice | 2018-03-31
2018-08-01-preview
2018-09-30-preview |
+| hanaonazure | 2017-11-03-preview |
+| maps | 2018-05-01 |
+
+## `v24.0.0`
+
+### New Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| batch | 2018-12-01
2018-12-01.8.0 |
+| devices | 2018-12-01-preview |
+| eventgrid | 2019-01-01 |
+| storagedatalake | 2018-06-17
2018-11-09 |
+
+### Updated Packages
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| apimanagement | 2018-01-01
2018-06-01-preview |
+| containerinstance | 2018-10-01 |
+| containerregistry | 2017-10-01
2018-02-01
2018-09-01 |
+| containerservice | 2018-08-01-preview
2018-09-30-preview |
+| costmanagement | 2018-08-01-preview |
+| datafactory | 2018-06-01 |
+| eventhub | 2018-01-01-preview |
+| hanaonazure | 2017-11-03-preview |
+| hdinsight | 2018-11-01-preview |
+| network | 2018-10-01 |
+| resourcehealth | 2015-01-01
2017-07-01 |
+| sql | 2017-03-01-preview |
+| storagesync | 2018-10-01 |
+
+### BreakingChanges
+
+| Package Name | API Version |
+| -----------: | :---------: |
+| authoring | luis |
+| cognitiveservices | 2017-04-18 |
+| computervision | v2.0 |
+| datamigration | 2018-04-19
2018-07-15-preview |
+| labservices | 2018-10-15 |
+| logic | 2018-07-01-preview |
+| media | 2018-07-01 |
+| siterecovery | 2018-01-10 |
+| sqlvirtualmachine | 2017-03-01-preview |
+| workloadmonitor | 2018-08-31-preview |
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 000000000000..0ec91828f850
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1,12 @@
+/documentation/ @joshgav
+/profiles/ @jhendrixMSFT @vladbarosan
+/services/ @jhendrixMSFT @vladbarosan
+/storage/ @jhendrixMSFT @vladbarosan
+/tools/apidiff/ @jhendrixMSFT @vladbarosan
+/tools/generator/ @jhendrixMSFT @vladbarosan
+/tools/indexer/ @jhendrixMSFT @vladbarosan
+/tools/profileBuilder/ @jhendrixMSFT @vladbarosan
+/version/ @jhendrixMSFT @vladbarosan
+.travis.yml @jhendrixMSFT @vladbarosan
+doc.go @joshgav
+findTestedPackages.sh @jhendrixMSFT @vladbarosan
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 9dc7b82e01ab..a07f78593af6 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,3 +1,13 @@
+trigger:
+ paths:
+ exclude:
+ - sdk/
+
+pr:
+ paths:
+ exclude:
+ - sdk/
+
jobs:
- job: Build_Test
strategy:
@@ -18,6 +28,7 @@ jobs:
GOPATH: '$(system.defaultWorkingDirectory)/work'
sdkPath: '$(GOPATH)/src/github.com/$(build.repository.name)'
IGNORE_BREAKING_CHANGES: true
+ go.list.filter: '| grep -v vendor'
steps:
- script: |
@@ -37,13 +48,13 @@ jobs:
go get -u golang.org/x/lint/golint
workingDirectory: '$(sdkPath)'
displayName: 'Install Dependencies'
- - script: go vet $(go list ./... | grep -v vendor)
+ - script: go vet -v $(go list ./... $(go.list.filter))
workingDirectory: '$(sdkPath)'
displayName: 'Vet'
- - script: go build -v $(go list ./... | grep -v vendor)
+ - script: go build -v $(go list ./... $(go.list.filter))
workingDirectory: '$(sdkPath)'
displayName: 'Build'
- - script: go test $(dirname $(find . -path ./vendor -prune -o -name '*_test.go' -print) | sort -u)
+ - script: go test $(dirname $(find . -path ./vendor -prune -o -path ./sdk -prune -o -name '*_test.go' -print) | sort -u)
workingDirectory: '$(sdkPath)'
displayName: 'Run Tests'
- script: go run ./tools/apidiff/main.go packages ./services FETCH_HEAD~1 FETCH_HEAD --copyrepo --breakingchanges || $IGNORE_BREAKING_CHANGES
diff --git a/doc.go b/doc.go
new file mode 100644
index 000000000000..af79e21481b3
--- /dev/null
+++ b/doc.go
@@ -0,0 +1,26 @@
+/*
+Package sdk provides Go packages for managing and using Azure services.
+
+GitHub repo: https://github.com/Azure/azure-sdk-for-go
+
+Official documentation: https://docs.microsoft.com/azure/go
+
+API reference: https://godoc.org/github.com/Azure/azure-sdk-for-go
+
+Samples: https://github.com/Azure-Samples/azure-sdk-for-go-samples
+*/
+package sdk
+
+// Copyright (c) Microsoft and contributors. All rights reserved.
+//
+// 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/eng/common/README.md b/eng/common/README.md
new file mode 100644
index 000000000000..7e9e197fc466
--- /dev/null
+++ b/eng/common/README.md
@@ -0,0 +1,12 @@
+# Common Engineering System
+
+The `eng/common` directory contains engineering files that are common across the various azure-sdk language repos.
+It should remain relatively small and only contain textual based files like scripts, configs, or templates. It
+should not contain binary files as they don't play well with git.
+
+# Updating
+
+Any updates to files in the `eng/common` directory should be made in the [azure-sdk-tools](https://github.com/azure/azure-sdk-tools) repo.
+All changes made will cause a PR to created in all subscribed azure-sdk language repos which will blindly replace all contents of
+the `eng/common` directory in that repo. For that reason do **NOT** make changes to files in this directory in the individual azure-sdk
+languages repos as they will be overwritten the next time an update is taken from the common azure-sdk-tools repo.
\ No newline at end of file
diff --git a/sdk/azcore/core.go b/sdk/azcore/core.go
new file mode 100644
index 000000000000..de01623ffe3b
--- /dev/null
+++ b/sdk/azcore/core.go
@@ -0,0 +1,114 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "errors"
+ "io"
+ "net/http"
+)
+
+// Policy represents an extensibility point for the Pipeline that can mutate the specified
+// Request and react to the received Response.
+type Policy interface {
+ // Do applies the policy to the specified Request. When implementing a Policy, mutate the
+ // request before calling req.Do() to move on to the next policy, and respond to the result
+ // before returning to the caller.
+ Do(ctx context.Context, req *Request) (*Response, error)
+}
+
+// PolicyFunc is a type that implements the Policy interface.
+// Use this type when implementing a stateless policy as a first-class function.
+type PolicyFunc func(context.Context, *Request) (*Response, error)
+
+// Do implements the Policy interface on PolicyFunc.
+func (pf PolicyFunc) Do(ctx context.Context, req *Request) (*Response, error) {
+ return pf(ctx, req)
+}
+
+// Transport represents an HTTP pipeline transport used to send HTTP requests and receive responses.
+type Transport interface {
+ // Do sends the HTTP request and returns the HTTP response or error.
+ Do(ctx context.Context, req *http.Request) (*http.Response, error)
+}
+
+// transportFunc is a type that implements the Transport interface.
+// Use this type when implementing a stateless transport as a first-class function.
+type transportFunc func(context.Context, *http.Request) (*http.Response, error)
+
+// Do implements the Transport interface on transportFunc.
+func (tf transportFunc) Do(ctx context.Context, req *http.Request) (*http.Response, error) {
+ return tf(ctx, req)
+}
+
+// used to adapt a TransportPolicy to a Policy
+type transportPolicy struct {
+ trans Transport
+}
+
+func (tp transportPolicy) Do(ctx context.Context, req *Request) (*Response, error) {
+ resp, err := tp.trans.Do(ctx, req.Request)
+ if err != nil {
+ return nil, err
+ }
+ return &Response{Response: resp}, nil
+}
+
+// Pipeline represents a primitive for sending HTTP requests and receiving responses.
+// Its behavior can be extended by specifying policies during construction.
+type Pipeline struct {
+ policies []Policy
+}
+
+// NewPipeline creates a new goroutine-safe Pipeline object from the specified Policies.
+// If no transport is provided then the default HTTP transport will be used.
+func NewPipeline(transport Transport, policies ...Policy) Pipeline {
+ if transport == nil {
+ transport = DefaultHTTPClientTransport()
+ }
+ // transport policy must always be the last in the slice
+ policies = append(policies, newBodyDownloadPolicy(), transportPolicy{trans: transport})
+ return Pipeline{
+ policies: policies,
+ }
+}
+
+// Do is called for each and every HTTP request. It passes the Context and request through
+// all the Policy objects (which can transform the Request's URL/query parameters/headers)
+// and ultimately sends the transformed HTTP request over the network.
+func (p Pipeline) Do(ctx context.Context, req *Request) (*Response, error) {
+ req.policies = p.policies
+ return req.Next(ctx)
+}
+
+// ReadSeekCloser is the interface that groups the io.ReadCloser and io.Seeker interfaces.
+type ReadSeekCloser interface {
+ io.ReadCloser
+ io.Seeker
+}
+
+type nopCloser struct {
+ io.ReadSeeker
+}
+
+func (n nopCloser) Close() error {
+ return nil
+}
+
+// NopCloser returns a ReadSeekCloser with a no-op close method wrapping the provided io.ReadSeeker.
+func NopCloser(rs io.ReadSeeker) ReadSeekCloser {
+ return nopCloser{rs}
+}
+
+// IterationDone is returned by an iterator's Next method when iteration is complete.
+var IterationDone = errors.New("no more items in iterator")
+
+// Retrier provides methods describing if an error should be considered as transient.
+type Retrier interface {
+ // IsNotRetriable returns true for error types that are not retriable.
+ IsNotRetriable() bool
+}
diff --git a/sdk/azcore/credential.go b/sdk/azcore/credential.go
new file mode 100644
index 000000000000..997872203925
--- /dev/null
+++ b/sdk/azcore/credential.go
@@ -0,0 +1,52 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "time"
+)
+
+// AuthenticationPolicyOptions contains various options used to create a credential policy.
+type AuthenticationPolicyOptions struct {
+ // Options contains the TokenRequestOptions that includes a scopes field which contains
+ // the list of OAuth2 authentication scopes used when requesting a token.
+ // This field is ignored for other forms of authentication (e.g. shared key).
+ Options TokenRequestOptions
+}
+
+// Credential represents any credential type.
+type Credential interface {
+ // AuthenticationPolicy returns a policy that requests the credential and applies it to the HTTP request.
+ AuthenticationPolicy(options AuthenticationPolicyOptions) Policy
+}
+
+// credentialFunc is a type that implements the Credential interface.
+// Use this type when implementing a stateless credential as a first-class function.
+type credentialFunc func(options AuthenticationPolicyOptions) Policy
+
+// AuthenticationPolicy implements the Credential interface on credentialFunc.
+func (cf credentialFunc) AuthenticationPolicy(options AuthenticationPolicyOptions) Policy {
+ return cf(options)
+}
+
+// TokenCredential represents a credential capable of providing an OAuth token.
+type TokenCredential interface {
+ Credential
+ // GetToken requests an access token for the specified set of scopes.
+ GetToken(ctx context.Context, options TokenRequestOptions) (*AccessToken, error)
+}
+
+// AccessToken represents an Azure service bearer access token with expiry information.
+type AccessToken struct {
+ Token string
+ ExpiresOn time.Time
+}
+
+// TokenRequestOptions contain specific parameter that may be used by credentials types when attempting to get a token
+type TokenRequestOptions struct {
+ Scopes []string
+}
diff --git a/sdk/azcore/doc.go b/sdk/azcore/doc.go
new file mode 100644
index 000000000000..6546445bc796
--- /dev/null
+++ b/sdk/azcore/doc.go
@@ -0,0 +1,164 @@
+// +build go1.13
+
+// Copyright 2017 Microsoft Corporation. All rights reserved.
+// Use of this source code is governed by an MIT
+// license that can be found in the LICENSE file.
+
+/*
+Package azcore implements an HTTP request/response middleware pipeline whose
+policy objects mutate an HTTP request's URL, query parameters, and/or headers before
+the request is sent over the wire.
+
+Not all policy objects mutate an HTTP request; some policy objects simply impact the
+flow of requests/responses by performing operations such as logging, retry policies,
+timeouts, failure injection, and deserialization of response payloads.
+
+Implementing the Policy Interface
+
+To implement a policy, define a struct that implements the pipeline.Policy interface's Do method. Your Do
+method is called when an HTTP request wants to be sent over the network. Your Do method can perform any
+operation(s) it desires. For example, it can log the outgoing request, mutate the URL, headers, and/or query
+parameters, inject a failure, etc. Your Do method must then forward the HTTP request to next Policy object
+in a linked-list ensuring that the remaining Policy objects perform their work. Ultimately, the last Policy
+object sends the HTTP request over the network (by calling the HTTPSender's Do method).
+
+When an HTTP response comes back, each Policy object in the linked-list gets a chance to process the response
+(in reverse order). The Policy object can log the response, retry the operation if due to a transient failure
+or timeout, deserialize the response body, etc. Ultimately, the last Policy object returns the HTTP response
+to the code that initiated the original HTTP request.
+
+Here is a template for how to define a pipeline.Policy object:
+
+ type myPolicy struct {
+ node PolicyNode
+ // TODO: Add configuration/setting fields here (if desired)...
+ }
+
+ func (p *myPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
+ // TODO: Mutate/process the HTTP request here...
+ response, err := p.node.Do(ctx, request) // Forward HTTP request to next Policy & get HTTP response
+ // TODO: Mutate/process the HTTP response here...
+ return response, err // Return response/error to previous Policy
+ }
+
+Implementing the Factory Interface
+
+Each Policy struct definition requires a factory struct definition that implements the pipeline.Factory interface's New
+method. The New method is called when application code wants to initiate a new HTTP request. Factory's New method is
+passed a pipeline.PolicyNode object which contains a reference to the owning pipeline.Pipeline object (discussed later) and
+a reference to the next Policy object in the linked list. The New method should create its corresponding Policy object
+passing it the PolicyNode and any other configuration/settings fields appropriate for the specific Policy object.
+
+Here is a template for how to define a pipeline.Policy object:
+
+ // NOTE: Once created & initialized, Factory objects should be goroutine-safe (ex: immutable);
+ // this allows reuse (efficient use of memory) and makes these objects usable by multiple goroutines concurrently.
+ type myPolicyFactory struct {
+ // TODO: Add any configuration/setting fields if desired...
+ }
+
+ func (f *myPolicyFactory) New(node pipeline.PolicyNode) Policy {
+ return &myPolicy{node: node} // TODO: Also initialize any configuration/setting fields here (if desired)...
+ }
+
+Using your Factory and Policy objects via a Pipeline
+
+To use the Factory and Policy objects, an application constructs a slice of Factory objects and passes
+this slice to the pipeline.NewPipeline function.
+
+ func NewPipeline(factories []pipeline.Factory, sender pipeline.HTTPSender) Pipeline
+
+This function also requires an object implementing the HTTPSender interface. For simple scenarios,
+passing nil for HTTPSender causes a standard Go http.Client object to be created and used to actually
+send the HTTP response over the network. For more advanced scenarios, you can pass your own HTTPSender
+object in. This allows sharing of http.Client objects or the use of custom-configured http.Client objects
+or other objects that can simulate the network requests for testing purposes.
+
+Now that you have a pipeline.Pipeline object, you can create a pipeline.Request object (which is a simple
+wrapper around Go's standard http.Request object) and pass it to Pipeline's Do method along with passing a
+context.Context for cancelling the HTTP request (if desired).
+
+ type Pipeline interface {
+ Do(ctx context.Context, methodFactory pipeline.Factory, request pipeline.Request) (pipeline.Response, error)
+ }
+
+Do iterates over the slice of Factory objects and tells each one to create its corresponding
+Policy object. After the linked-list of Policy objects have been created, Do calls the first
+Policy object passing it the Context & HTTP request parameters. These parameters now flow through
+all the Policy objects giving each object a chance to look at and/or mutate the HTTP request.
+The last Policy object sends the message over the network.
+
+When the network operation completes, the HTTP response and error return values pass
+back through the same Policy objects in reverse order. Most Policy objects ignore the
+response/error but some log the result, retry the operation (depending on the exact
+reason the operation failed), or deserialize the response's body. Your own Policy
+objects can do whatever they like when processing outgoing requests or incoming responses.
+
+Note that after an I/O request runs to completion, the Policy objects for that request
+are garbage collected. However, Pipeline object (like Factory objects) are goroutine-safe allowing
+them to be created once and reused over many I/O operations. This allows for efficient use of
+memory and also makes them safely usable by multiple goroutines concurrently.
+
+Inserting a Method-Specific Factory into the Linked-List of Policy Objects
+
+While Pipeline and Factory objects can be reused over many different operations, it is
+common to have special behavior for a specific operation/method. For example, a method
+may need to deserialize the response's body to an instance of a specific data type.
+To accommodate this, the Pipeline's Do method takes an additional method-specific
+Factory object. The Do method tells this Factory to create a Policy object and
+injects this method-specific Policy object into the linked-list of Policy objects.
+
+When creating a Pipeline object, the slice of Factory objects passed must have 1
+(and only 1) entry marking where the method-specific Factory should be injected.
+The Factory marker is obtained by calling the pipeline.MethodFactoryMarker() function:
+
+ func MethodFactoryMarker() pipeline.Factory
+
+Creating an HTTP Request Object
+
+The HTTP request object passed to Pipeline's Do method is not Go's http.Request struct.
+Instead, it is a pipeline.Request struct which is a simple wrapper around Go's standard
+http.Request. You create a pipeline.Request object by calling the pipeline.NewRequest function:
+
+ func NewRequest(method string, url url.URL, options pipeline.RequestOptions) (request pipeline.Request, err error)
+
+To this function, you must pass a pipeline.RequestOptions that looks like this:
+
+ type RequestOptions struct {
+ // The readable and seekable stream to be sent to the server as the request's body.
+ Body io.ReadSeeker
+
+ // The callback method (if not nil) to be invoked to report progress as the stream is uploaded in the HTTP request.
+ Progress ProgressReceiver
+ }
+
+The method and struct ensure that the request's body stream is a read/seekable stream.
+A seekable stream is required so that upon retry, the final Policy object can seek
+the stream back to the beginning before retrying the network request and re-uploading the
+body. In addition, you can associate a ProgressReceiver callback function which will be
+invoked periodically to report progress while bytes are being read from the body stream
+and sent over the network.
+
+Processing the HTTP Response
+
+When an HTTP response comes in from the network, a reference to Go's http.Response struct is
+embedded in a struct that implements the pipeline.Response interface:
+
+ type Response interface {
+ Response() *http.Response
+ }
+
+This interface is returned through all the Policy objects. Each Policy object can call the Response
+interface's Response method to examine (or mutate) the embedded http.Response object.
+
+A Policy object can internally define another struct (implementing the pipeline.Response interface)
+that embeds an http.Response and adds additional fields and return this structure to other Policy
+objects. This allows a Policy object to deserialize the body to some other struct and return the
+original http.Response and the additional struct back through the Policy chain. Other Policy objects
+can see the Response but cannot see the additional struct with the deserialized body. After all the
+Policy objects have returned, the pipeline.Response interface is returned by Pipeline's Do method.
+The caller of this method can perform a type assertion attempting to get back to the struct type
+really returned by the Policy object. If the type assertion is successful, the caller now has
+access to both the http.Response and the deserialized struct object.
+*/
+package azcore
diff --git a/sdk/azcore/error.go b/sdk/azcore/error.go
new file mode 100644
index 000000000000..93d6957e206f
--- /dev/null
+++ b/sdk/azcore/error.go
@@ -0,0 +1,53 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "errors"
+ "fmt"
+)
+
+var (
+ // ErrNoMorePolicies is returned from Request.Next() if there are no more policies in the pipeline.
+ ErrNoMorePolicies = errors.New("no more policies")
+)
+
+// TODO: capture frame info for marshal, unmarshal, and parsing errors
+// built in frame in xerror? %w
+type frameInfo struct {
+ file string
+ line int
+}
+
+func (f frameInfo) String() string {
+ if f.zero() {
+ return ""
+ }
+ return fmt.Sprintf("file: %s, line: %d", f.file, f.line)
+}
+
+func (f frameInfo) zero() bool {
+ return f.file == "" && f.line == 0
+}
+
+// RequestError is returned when the service returns an unsuccessful resopnse code (4xx, 5xx).
+type RequestError struct {
+ msg string
+ resp *Response
+}
+
+func newRequestError(message string, response *Response) error {
+ return RequestError{msg: message, resp: response}
+}
+
+func (re RequestError) Error() string {
+ return re.msg
+}
+
+// Response returns the underlying response.
+func (re RequestError) Response() *Response {
+ return re.resp
+}
diff --git a/sdk/azcore/go.mod b/sdk/azcore/go.mod
new file mode 100644
index 000000000000..637312064cb5
--- /dev/null
+++ b/sdk/azcore/go.mod
@@ -0,0 +1,5 @@
+module github.com/Azure/azure-sdk-for-go/sdk/azcore
+
+require github.com/Azure/azure-sdk-for-go/sdk/internal v0.1.0
+
+go 1.13
diff --git a/sdk/azcore/go.sum b/sdk/azcore/go.sum
new file mode 100644
index 000000000000..6306f1577dcd
--- /dev/null
+++ b/sdk/azcore/go.sum
@@ -0,0 +1,2 @@
+github.com/Azure/azure-sdk-for-go/sdk/internal v0.1.0 h1:sgOdyT1ZAW3nErwCuvlGrkeP03pTtbRBW5MGCXWGZws=
+github.com/Azure/azure-sdk-for-go/sdk/internal v0.1.0/go.mod h1:Q+TCQnSr+clUU0JU+xrHZ3slYCxw17AOFdvWFpQXjAY=
diff --git a/sdk/azcore/headers.go b/sdk/azcore/headers.go
new file mode 100644
index 000000000000..0daa2908ee04
--- /dev/null
+++ b/sdk/azcore/headers.go
@@ -0,0 +1,29 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+// Constants ensuring that header names are correctly spelled and consistently cased.
+const (
+ HeaderAuthorization = "Authorization"
+ HeaderCacheControl = "Cache-Control"
+ HeaderContentEncoding = "Content-Encoding"
+ HeaderContentDisposition = "Content-Disposition"
+ HeaderContentLanguage = "Content-Language"
+ HeaderContentLength = "Content-Length"
+ HeaderContentMD5 = "Content-MD5"
+ HeaderContentType = "Content-Type"
+ HeaderDate = "Date"
+ HeaderIfMatch = "If-Match"
+ HeaderIfModifiedSince = "If-Modified-Since"
+ HeaderIfNoneMatch = "If-None-Match"
+ HeaderIfUnmodifiedSince = "If-Unmodified-Since"
+ HeaderMetadata = "Metadata"
+ HeaderRange = "Range"
+ HeaderURLEncoded = "application/x-www-form-urlencoded"
+ HeaderUserAgent = "User-Agent"
+ HeaderXmsDate = "x-ms-date"
+ HeaderXmsVersion = "x-ms-version"
+)
diff --git a/sdk/azcore/log.go b/sdk/azcore/log.go
new file mode 100644
index 000000000000..211cdd99d622
--- /dev/null
+++ b/sdk/azcore/log.go
@@ -0,0 +1,86 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+// LogClassification is used to group entries. Each group can be toggled on or off.
+type LogClassification string
+
+const (
+ // LogError entries contain detailed error information.
+ // This includes the error message and stack trace.
+ LogError LogClassification = "Error"
+
+ // LogRequest entries contain information about HTTP requests.
+ // This includes information like the URL, query parameters, and headers.
+ LogRequest LogClassification = "Request"
+
+ // LogResponse entries contain information about HTTP responses.
+ // This includes information like the HTTP status code, headers, and request URL.
+ LogResponse LogClassification = "Response"
+
+ // LogRetryPolicy entries contain information specific to the retry policy in use.
+ LogRetryPolicy LogClassification = "RetryPolicy"
+
+ // LogSlowResponse entries contain information for responses that take longer than the specified threshold.
+ LogSlowResponse LogClassification = "SlowResponse"
+)
+
+// Listener is the function signature invoked when writing log entries.
+// A Listener is required to perform its own synchronization if it's
+// expected to be called from multiple Go routines.
+type Listener func(LogClassification, string)
+
+// Logger controls which classifications to log and writing to the underlying log.
+type Logger struct {
+ cls []LogClassification
+ lst Listener
+}
+
+// SetClassifications is used to control which classifications are written to
+// the log. By default all log classifications are written.
+func (l *Logger) SetClassifications(cls ...LogClassification) {
+ l.cls = cls
+}
+
+// SetListener will set the Logger to write to the specified Listener.
+func (l *Logger) SetListener(lst Listener) {
+ l.lst = lst
+}
+
+// Should returns true if the specified log classification should be written to the log.
+// TODO: explain why you would want to call this
+func (l *Logger) Should(cls LogClassification) bool {
+ if l.cls == nil || len(l.cls) == 0 {
+ return true
+ }
+ for _, c := range l.cls {
+ if c == cls {
+ return true
+ }
+ }
+ return false
+}
+
+// Write invokes the underlying Listener with the specified classification and message.
+// If the classification shouldn't be logged or there is no listener then Write does nothing.
+func (l *Logger) Write(cls LogClassification, message string) {
+ if l.lst == nil || !l.Should(cls) {
+ return
+ }
+ l.lst(cls, message)
+}
+
+// for testing purposes
+func (l *Logger) resetClassifications() {
+ l.cls = nil
+}
+
+var log Logger
+
+// Log returns the process-wide logger.
+func Log() *Logger {
+ return &log
+}
diff --git a/sdk/azcore/log_test.go b/sdk/azcore/log_test.go
new file mode 100644
index 000000000000..f9eadbe2c5f8
--- /dev/null
+++ b/sdk/azcore/log_test.go
@@ -0,0 +1,50 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import "testing"
+
+func TestLoggingDefault(t *testing.T) {
+ // ensure logging with nil listener doesn't fail
+ Log().SetListener(nil)
+ Log().Write(LogError, "this should work just fine")
+
+ log := map[LogClassification]string{}
+ Log().SetListener(func(cls LogClassification, msg string) {
+ log[cls] = msg
+ })
+ const req = "this is a request"
+ Log().Write(LogRequest, req)
+ const resp = "this is a response"
+ Log().Write(LogResponse, resp)
+ if l := len(log); l != 2 {
+ t.Fatalf("unexpected log entry count: %d", l)
+ }
+ if log[LogRequest] != req {
+ t.Fatalf("unexpected log request: %s", log[LogRequest])
+ }
+ if log[LogResponse] != resp {
+ t.Fatalf("unexpected log response: %s", log[LogResponse])
+ }
+}
+
+func TestLoggingClassification(t *testing.T) {
+ log := map[LogClassification]string{}
+ Log().SetListener(func(cls LogClassification, msg string) {
+ log[cls] = msg
+ })
+ Log().SetClassifications(LogError)
+ defer Log().resetClassifications()
+ Log().Write(LogSlowResponse, "this shouldn't be in the log")
+ if s, ok := log[LogSlowResponse]; ok {
+ t.Fatalf("unexpected log entry %s", s)
+ }
+ const err = "this is an error"
+ Log().Write(LogError, err)
+ if log[LogError] != err {
+ t.Fatalf("unexpected log entry: %s", log[LogError])
+ }
+}
diff --git a/sdk/azcore/policy_anonymous_credential.go b/sdk/azcore/policy_anonymous_credential.go
new file mode 100644
index 000000000000..6d5977ccd9f6
--- /dev/null
+++ b/sdk/azcore/policy_anonymous_credential.go
@@ -0,0 +1,18 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import "context"
+
+// AnonymousCredential is for use with HTTP(S) requests that read public resource
+// or for use with Shared Access Signatures (SAS).
+func AnonymousCredential() Credential {
+ return credentialFunc(func(AuthenticationPolicyOptions) Policy {
+ return PolicyFunc(func(ctx context.Context, req *Request) (*Response, error) {
+ return req.Next(ctx)
+ })
+ })
+}
diff --git a/sdk/azcore/policy_anonymous_credential_test.go b/sdk/azcore/policy_anonymous_credential_test.go
new file mode 100644
index 000000000000..d860a843f704
--- /dev/null
+++ b/sdk/azcore/policy_anonymous_credential_test.go
@@ -0,0 +1,30 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "net/http"
+ "reflect"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func TestAnonymousCredential(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse(mock.WithStatusCode(http.StatusOK))
+ pl := NewPipeline(srv, AnonymousCredential().AuthenticationPolicy(AuthenticationPolicyOptions{}))
+ req := NewRequest(http.MethodGet, srv.URL())
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !reflect.DeepEqual(req.Header, resp.Request.Header) {
+ t.Fatal("unexpected modification to request headers")
+ }
+}
diff --git a/sdk/azcore/policy_body_download.go b/sdk/azcore/policy_body_download.go
new file mode 100644
index 000000000000..22f5a1b9b415
--- /dev/null
+++ b/sdk/azcore/policy_body_download.go
@@ -0,0 +1,73 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "io/ioutil"
+)
+
+// newBodyDownloadPolicy creates a policy object that downloads the response's body to a []byte.
+func newBodyDownloadPolicy() Policy {
+ return PolicyFunc(func(ctx context.Context, req *Request) (*Response, error) {
+ resp, err := req.Next(ctx)
+ if err != nil {
+ return resp, err
+ }
+ var opValues bodyDownloadPolicyOpValues
+ if req.OperationValue(&opValues); !opValues.skip && resp.Body != nil {
+ // Either bodyDownloadPolicyOpValues was not specified (so skip is false)
+ // or it was specified and skip is false: don't skip downloading the body
+ b, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ err = fmt.Errorf("body download policy: %w", err)
+ }
+ resp.Body = &nopClosingBytesReader{s: b}
+ }
+ return resp, err
+ })
+}
+
+// bodyDownloadPolicyOpValues is the struct containing the per-operation values
+type bodyDownloadPolicyOpValues struct {
+ skip bool
+}
+
+// nopClosingBytesReader is an io.ReadCloser around a byte slice.
+// It also provides direct access to the byte slice.
+type nopClosingBytesReader struct {
+ s []byte
+ i int64
+}
+
+// Bytes returns the underlying byte slice.
+func (r *nopClosingBytesReader) Bytes() []byte {
+ return r.s
+}
+
+// Close implements the io.Closer interface.
+func (*nopClosingBytesReader) Close() error {
+ return nil
+}
+
+// Read implements the io.Reader interface.
+func (r *nopClosingBytesReader) Read(b []byte) (n int, err error) {
+ if r.i >= int64(len(r.s)) {
+ return 0, io.EOF
+ }
+ n = copy(b, r.s[r.i:])
+ r.i += int64(n)
+ return
+}
+
+// Set replaces the existing byte slice with the specified byte slice and resets the reader.
+func (r *nopClosingBytesReader) Set(b []byte) {
+ r.s = b
+ r.i = 0
+}
diff --git a/sdk/azcore/policy_body_download_test.go b/sdk/azcore/policy_body_download_test.go
new file mode 100644
index 000000000000..a46f4dcfd502
--- /dev/null
+++ b/sdk/azcore/policy_body_download_test.go
@@ -0,0 +1,51 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "net/http"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func TestDownloadBody(t *testing.T) {
+ const message = "downloaded"
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse(mock.WithBody([]byte(message)))
+ // download policy is automatically added during pipeline construction
+ pl := NewPipeline(srv)
+ resp, err := pl.Do(context.Background(), NewRequest(http.MethodGet, srv.URL()))
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(resp.payload()) == 0 {
+ t.Fatal("missing payload")
+ }
+ if string(resp.payload()) != message {
+ t.Fatalf("unexpected response: %s", string(resp.payload()))
+ }
+}
+
+func TestSkipBodyDownload(t *testing.T) {
+ const message = "not downloaded"
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse(mock.WithBody([]byte(message)))
+ // download policy is automatically added during pipeline construction
+ pl := NewPipeline(srv)
+ req := NewRequest(http.MethodGet, srv.URL())
+ req.SkipBodyDownload()
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(resp.payload()) > 0 {
+ t.Fatalf("unexpected download: %s", string(resp.payload()))
+ }
+}
diff --git a/sdk/azcore/policy_logging.go b/sdk/azcore/policy_logging.go
new file mode 100644
index 000000000000..5900e64f9c04
--- /dev/null
+++ b/sdk/azcore/policy_logging.go
@@ -0,0 +1,160 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "net/http"
+ "net/url"
+ "runtime"
+ "strings"
+ "time"
+)
+
+// RequestLogOptions configures the retry policy's behavior.
+type RequestLogOptions struct {
+ // LogWarningIfTryOverThreshold logs a warning if a tried operation takes longer than the specified
+ // duration (-1=no logging; 0=default threshold).
+ LogWarningIfTryOverThreshold time.Duration
+}
+
+func (o RequestLogOptions) defaults() RequestLogOptions {
+ if o.LogWarningIfTryOverThreshold == 0 {
+ // It would be good to relate this to https://azure.microsoft.com/en-us/support/legal/sla/storage/v1_2/
+ // But this monitors the time to get the HTTP response; NOT the time to download the response body.
+ o.LogWarningIfTryOverThreshold = 3 * time.Second // Default to 3 seconds
+ }
+ return o
+}
+
+type requestLogPolicy struct {
+ options RequestLogOptions
+}
+
+// NewRequestLogPolicy creates a RequestLogPolicy object configured using the specified options.
+func NewRequestLogPolicy(o RequestLogOptions) Policy {
+ o = o.defaults() // Force defaults to be calculated
+ return &requestLogPolicy{options: o}
+}
+
+// logPolicyOpValues is the struct containing the per-operation values
+type logPolicyOpValues struct {
+ try int32
+ start time.Time
+}
+
+func (p *requestLogPolicy) Do(ctx context.Context, req *Request) (*Response, error) {
+ // Get the per-operation values. These are saved in the Message's map so that they persist across each retry calling into this policy object.
+ var opValues logPolicyOpValues
+ if req.OperationValue(&opValues); opValues.start.IsZero() {
+ opValues.start = time.Now() // If this is the 1st try, record this operation's start time
+ }
+ opValues.try++ // The first try is #1 (not #0)
+ req.SetOperationValue(opValues)
+
+ // Log the outgoing request as informational
+ if Log().Should(LogRequest) {
+ b := &bytes.Buffer{}
+ fmt.Fprintf(b, "==> OUTGOING REQUEST (Try=%d)\n", opValues.try)
+ WriteRequestWithResponse(b, prepareRequestForLogging(req), nil, nil)
+ Log().Write(LogRequest, b.String())
+ }
+
+ // Set the time for this particular retry operation and then Do the operation.
+ tryStart := time.Now()
+ response, err := req.Next(ctx) // Make the request
+ tryEnd := time.Now()
+ tryDuration := tryEnd.Sub(tryStart)
+ opDuration := tryEnd.Sub(opValues.start)
+
+ logClass := LogResponse // Default logging information
+
+ // If the response took too long, we'll upgrade to warning.
+ if p.options.LogWarningIfTryOverThreshold > 0 && tryDuration > p.options.LogWarningIfTryOverThreshold {
+ // Log a warning if the try duration exceeded the specified threshold
+ logClass = LogSlowResponse
+ }
+
+ if err == nil { // We got a response from the service
+ sc := response.StatusCode
+ if ((sc >= 400 && sc <= 499) && sc != http.StatusNotFound && sc != http.StatusConflict && sc != http.StatusPreconditionFailed && sc != http.StatusRequestedRangeNotSatisfiable) || (sc >= 500 && sc <= 599) {
+ logClass = LogError // Promote to Error any 4xx (except those listed is an error) or any 5xx
+ } else {
+ // For other status codes, we leave the level as is.
+ }
+ } else { // This error did not get an HTTP response from the service; upgrade the severity to Error
+ logClass = LogError
+ }
+
+ if Log().Should(logClass) {
+ // We're going to log this; build the string to log
+ b := &bytes.Buffer{}
+ slow := ""
+ if p.options.LogWarningIfTryOverThreshold > 0 && tryDuration > p.options.LogWarningIfTryOverThreshold {
+ slow = fmt.Sprintf("[SLOW >%v]", p.options.LogWarningIfTryOverThreshold)
+ }
+ fmt.Fprintf(b, "==> REQUEST/RESPONSE (Try=%d/%v%s, OpTime=%v) -- ", opValues.try, tryDuration, slow, opDuration)
+ if err != nil { // This HTTP request did not get a response from the service
+ fmt.Fprint(b, "REQUEST ERROR\n")
+ } else {
+ if logClass == LogError {
+ fmt.Fprint(b, "RESPONSE STATUS CODE ERROR\n")
+ } else {
+ fmt.Fprint(b, "RESPONSE SUCCESSFULLY RECEIVED\n")
+ }
+ }
+
+ WriteRequestWithResponse(b, prepareRequestForLogging(req), response, err)
+ if logClass == LogError {
+ b.Write(stack()) // For errors (or lower levels), we append the stack trace (an expensive operation)
+ }
+ Log().Write(logClass, b.String())
+ }
+ return response, err
+}
+
+// RedactSigQueryParam redacts the 'sig' query parameter in URL's raw query to protect secret.
+func RedactSigQueryParam(rawQuery string) (bool, string) {
+ rawQuery = strings.ToLower(rawQuery) // lowercase the string so we can look for ?sig= and &sig=
+ sigFound := strings.Contains(rawQuery, "?sig=")
+ if !sigFound {
+ sigFound = strings.Contains(rawQuery, "&sig=")
+ if !sigFound {
+ return sigFound, rawQuery // [?|&]sig= not found; return same rawQuery passed in (no memory allocation)
+ }
+ }
+ // [?|&]sig= found, redact its value
+ values, _ := url.ParseQuery(rawQuery)
+ for name := range values {
+ if strings.EqualFold(name, "sig") {
+ values[name] = []string{"REDACTED"}
+ }
+ }
+ return sigFound, values.Encode()
+}
+
+func prepareRequestForLogging(req *Request) *Request {
+ request := req
+ if sigFound, rawQuery := RedactSigQueryParam(request.URL.RawQuery); sigFound {
+ // Make copy so we don't destroy the query parameters we actually need to send in the request
+ request = req.copy()
+ request.URL.RawQuery = rawQuery
+ }
+ return request
+}
+
+func stack() []byte {
+ buf := make([]byte, 1024)
+ for {
+ n := runtime.Stack(buf, false)
+ if n < len(buf) {
+ return buf[:n]
+ }
+ buf = make([]byte, 2*len(buf))
+ }
+}
diff --git a/sdk/azcore/policy_logging_test.go b/sdk/azcore/policy_logging_test.go
new file mode 100644
index 000000000000..046a6a448262
--- /dev/null
+++ b/sdk/azcore/policy_logging_test.go
@@ -0,0 +1,116 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "errors"
+ "net/http"
+ "strings"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func TestPolicyLoggingSuccess(t *testing.T) {
+ log := map[LogClassification]string{}
+ Log().SetListener(func(cls LogClassification, s string) {
+ log[cls] = s
+ })
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse()
+ pl := NewPipeline(srv, NewRequestLogPolicy(RequestLogOptions{}))
+ req := NewRequest(http.MethodGet, srv.URL())
+ req.SetQueryParam("one", "fish")
+ req.SetQueryParam("sig", "redact")
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp.StatusCode != http.StatusOK {
+ t.Fatalf("unexpected status code: %d", resp.StatusCode)
+ }
+ if logReq, ok := log[LogRequest]; ok {
+ // Request ==> OUTGOING REQUEST (Try=1)
+ // GET http://127.0.0.1:49475?one=fish&sig=REDACTED
+ // (no headers)
+ if !strings.Contains(logReq, "sig=REDACTED") {
+ t.Fatal("missing redacted sig query param")
+ }
+ if !strings.Contains(logReq, "(no headers)") {
+ t.Fatal("missing (no headers)")
+ }
+ } else {
+ t.Fatal("missing LogRequest")
+ }
+ if logResp, ok := log[LogResponse]; ok {
+ // Response ==> REQUEST/RESPONSE (Try=1/1.0034ms, OpTime=1.0034ms) -- RESPONSE SUCCESSFULLY RECEIVED
+ // GET http://127.0.0.1:49475?one=fish&sig=REDACTED
+ // (no headers)
+ // --------------------------------------------------------------------------------
+ // RESPONSE Status: 200 OK
+ // Content-Length: [0]
+ // Date: [Fri, 22 Nov 2019 23:48:02 GMT]
+ if !strings.Contains(logResp, "RESPONSE Status: 200 OK") {
+ t.Fatal("missing response status")
+ }
+ } else {
+ t.Fatal("missing LogResponse")
+ }
+}
+
+func TestPolicyLoggingError(t *testing.T) {
+ log := map[LogClassification]string{}
+ Log().SetListener(func(cls LogClassification, s string) {
+ log[cls] = s
+ })
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetError(errors.New("bogus error"))
+ pl := NewPipeline(srv, NewRequestLogPolicy(RequestLogOptions{}))
+ req := NewRequest(http.MethodGet, srv.URL())
+ req.Header.Add("header", "one")
+ req.Header.Add("Authorization", "redact")
+ resp, err := pl.Do(context.Background(), req)
+ if err == nil {
+ t.Fatal("unexpected nil error")
+ }
+ if resp != nil {
+ t.Fatal("unexpected respose")
+ }
+ if logReq, ok := log[LogRequest]; ok {
+ // Request ==> OUTGOING REQUEST (Try=1)
+ // GET http://127.0.0.1:50057
+ // Authorization: REDACTED
+ // Header: [one]
+ if !strings.Contains(logReq, "Authorization: REDACTED") {
+ t.Fatal("missing redacted authorization header")
+ }
+ } else {
+ t.Fatal("missing LogRequest")
+ }
+ if logError, ok := log[LogError]; ok {
+ // Error ==> REQUEST/RESPONSE (Try=1/0s, OpTime=0s) -- REQUEST ERROR
+ // GET http://127.0.0.1:50057
+ // Authorization: REDACTED
+ // Header: [one]
+ // --------------------------------------------------------------------------------
+ // ERROR:
+ // bogus error
+ // ...stack track...
+ if !strings.Contains(logError, "Authorization: REDACTED") {
+ t.Fatal("missing redacted authorization header")
+ }
+ if !strings.Contains(logError, "bogus error") {
+ t.Fatal("missing error message")
+ }
+ } else {
+ t.Fatal("missing LogError")
+ }
+}
+
+// TODO: add test for slow response
diff --git a/sdk/azcore/policy_retry.go b/sdk/azcore/policy_retry.go
new file mode 100644
index 000000000000..7d48f98a42b4
--- /dev/null
+++ b/sdk/azcore/policy_retry.go
@@ -0,0 +1,208 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "math/rand"
+ "net/http"
+ "time"
+)
+
+const (
+ defaultMaxTries = 4
+)
+
+// RetryOptions configures the retry policy's behavior.
+type RetryOptions struct {
+ // MaxTries specifies the maximum number of attempts an operation will be tried before producing an error (0=default).
+ // A value of zero means that you accept our default policy. A value of 1 means 1 try and no retries.
+ MaxTries int32
+
+ // TryTimeout indicates the maximum time allowed for any single try of an HTTP request.
+ // A value of zero means that you accept our default timeout. NOTE: When transferring large amounts
+ // of data, the default TryTimeout will probably not be sufficient. You should override this value
+ // based on the bandwidth available to the host machine and proximity to the service. A good
+ // starting point may be something like (60 seconds per MB of anticipated-payload-size).
+ TryTimeout time.Duration
+
+ // RetryDelay specifies the amount of delay to use before retrying an operation (0=default).
+ // The delay increases exponentially with each retry up to a maximum specified by MaxRetryDelay.
+ // If you specify 0, then you must also specify 0 for MaxRetryDelay.
+ // If you specify RetryDelay, then you must also specify MaxRetryDelay, and MaxRetryDelay should be
+ // equal to or greater than RetryDelay.
+ RetryDelay time.Duration
+
+ // MaxRetryDelay specifies the maximum delay allowed before retrying an operation (0=default).
+ // If you specify 0, then you must also specify 0 for RetryDelay.
+ MaxRetryDelay time.Duration
+
+ // StatusCodes specifies the HTTP status codes that indicate the operation should be retried.
+ // If unspecified it will default to the status codes in StatusCodesForRetry.
+ StatusCodes []int
+}
+
+var (
+ // StatusCodesForRetry is the default set of HTTP status code for which the policy will retry.
+ StatusCodesForRetry = [6]int{
+ http.StatusRequestTimeout, // 408
+ http.StatusTooManyRequests, // 429
+ http.StatusInternalServerError, // 500
+ http.StatusBadGateway, // 502
+ http.StatusServiceUnavailable, // 503
+ http.StatusGatewayTimeout, // 504
+ }
+)
+
+// DefaultRetryOptions returns an instance of RetryOptions initialized with default values.
+func DefaultRetryOptions() RetryOptions {
+ return RetryOptions{
+ StatusCodes: StatusCodesForRetry[:],
+ MaxTries: defaultMaxTries,
+ TryTimeout: 1 * time.Minute,
+ RetryDelay: 4 * time.Second,
+ MaxRetryDelay: 120 * time.Second,
+ }
+}
+
+func (o RetryOptions) calcDelay(try int32) time.Duration { // try is >=1; never 0
+ pow := func(number int64, exponent int32) int64 { // pow is nested helper function
+ var result int64 = 1
+ for n := int32(0); n < exponent; n++ {
+ result *= number
+ }
+ return result
+ }
+
+ delay := time.Duration(pow(2, try)-1) * o.RetryDelay
+
+ // Introduce some jitter: [0.0, 1.0) / 2 = [0.0, 0.5) + 0.8 = [0.8, 1.3)
+ delay = time.Duration(delay.Seconds() * (rand.Float64()/2 + 0.8) * float64(time.Second)) // NOTE: We want math/rand; not crypto/rand
+ if delay > o.MaxRetryDelay {
+ delay = o.MaxRetryDelay
+ }
+ return delay
+}
+
+// NewRetryPolicy creates a policy object configured using the specified options.
+// Pass nil to accept the default values; this is the same as passing the result
+// from a call to DefaultRetryOptions().
+func NewRetryPolicy(o *RetryOptions) Policy {
+ if o == nil {
+ def := DefaultRetryOptions()
+ o = &def
+ }
+ return &retryPolicy{options: *o}
+}
+
+type retryPolicy struct {
+ options RetryOptions
+}
+
+func (p *retryPolicy) Do(ctx context.Context, req *Request) (resp *Response, err error) {
+ // Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2)
+ // When to retry: connection failure or temporary/timeout.
+ if req.Body != nil {
+ // wrap the body so we control when it's actually closed
+ rwbody := &retryableRequestBody{body: req.Body.(ReadSeekCloser)}
+ req.Body = rwbody
+ req.Request.GetBody = func() (io.ReadCloser, error) {
+ _, err := rwbody.Seek(0, io.SeekStart) // Seek back to the beginning of the stream
+ return rwbody, err
+ }
+ defer rwbody.realClose()
+ }
+ try := int32(1)
+ shouldLog := Log().Should(LogRetryPolicy)
+ for {
+ resp = nil // reset
+ if shouldLog {
+ Log().Write(LogRetryPolicy, fmt.Sprintf("\n=====> Try=%d\n", try))
+ }
+
+ // For each try, seek to the beginning of the Body stream. We do this even for the 1st try because
+ // the stream may not be at offset 0 when we first get it and we want the same behavior for the
+ // 1st try as for additional tries.
+ err = req.RewindBody()
+ if err != nil {
+ return
+ }
+
+ // Set the time for this particular retry operation and then Do the operation.
+ tryCtx, tryCancel := context.WithTimeout(ctx, p.options.TryTimeout)
+ resp, err = req.Next(tryCtx) // Make the request
+ tryCancel()
+ if shouldLog {
+ Log().Write(LogRetryPolicy, fmt.Sprintf("Err=%v, response=%v\n", err, resp))
+ }
+
+ if err == nil && !resp.HasStatusCode(p.options.StatusCodes...) {
+ // if there is no error and the response code isn't in the list of retry codes then we're done.
+ return
+ } else if ctx.Err() != nil {
+ // don't retry if the parent context has been cancelled or its deadline exceeded
+ return
+ } else if retrier, ok := err.(Retrier); ok && retrier.IsNotRetriable() {
+ // the error says it's not retriable so don't retry
+ return
+ }
+
+ // drain before retrying so nothing is leaked
+ resp.Drain()
+
+ if try == p.options.MaxTries {
+ // max number of tries has been reached, don't sleep again
+ return
+ }
+
+ // use the delay from retry-after if available
+ delay, ok := resp.RetryAfter()
+ if !ok {
+ delay = p.options.calcDelay(try)
+ }
+ if shouldLog {
+ Log().Write(LogRetryPolicy, fmt.Sprintf("Try=%d, Delay=%v\n", try, delay))
+ }
+ select {
+ case <-time.After(delay):
+ try++
+ case <-ctx.Done():
+ err = ctx.Err()
+ return
+ }
+ }
+}
+
+// ********** The following type/methods implement the retryableRequestBody (a ReadSeekCloser)
+
+// This struct is used when sending a body to the network
+type retryableRequestBody struct {
+ body io.ReadSeeker // Seeking is required to support retries
+}
+
+// Read reads a block of data from an inner stream and reports progress
+func (b *retryableRequestBody) Read(p []byte) (n int, err error) {
+ return b.body.Read(p)
+}
+
+func (b *retryableRequestBody) Seek(offset int64, whence int) (offsetFromStart int64, err error) {
+ return b.body.Seek(offset, whence)
+}
+
+func (b *retryableRequestBody) Close() error {
+ // We don't want the underlying transport to close the request body on transient failures so this is a nop.
+ // The retry policy closes the request body upon success.
+ return nil
+}
+
+func (b *retryableRequestBody) realClose() error {
+ if c, ok := b.body.(io.Closer); ok {
+ return c.Close()
+ }
+ return nil
+}
diff --git a/sdk/azcore/policy_retry_test.go b/sdk/azcore/policy_retry_test.go
new file mode 100644
index 000000000000..6a3dc79197cf
--- /dev/null
+++ b/sdk/azcore/policy_retry_test.go
@@ -0,0 +1,251 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "errors"
+ "io"
+ "net/http"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func testRetryOptions() *RetryOptions {
+ def := DefaultRetryOptions()
+ def.RetryDelay = 20 * time.Millisecond
+ return &def
+}
+
+func TestRetryPolicySuccess(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse(mock.WithStatusCode(http.StatusOK))
+ pl := NewPipeline(srv, NewRetryPolicy(nil))
+ req := NewRequest(http.MethodGet, srv.URL())
+ body := newRewindTrackingBody("stuff")
+ req.SetBody(body)
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp.StatusCode != http.StatusOK {
+ t.Fatalf("unexpected status code: %d", resp.StatusCode)
+ }
+ if body.rcount > 0 {
+ t.Fatalf("unexpected rewind count: %d", body.rcount)
+ }
+ if !body.closed {
+ t.Fatal("request body wasn't closed")
+ }
+}
+
+func TestRetryPolicyFailOnStatusCode(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse(mock.WithStatusCode(http.StatusInternalServerError))
+ pl := NewPipeline(srv, NewRetryPolicy(testRetryOptions()))
+ req := NewRequest(http.MethodGet, srv.URL())
+ body := newRewindTrackingBody("stuff")
+ req.SetBody(body)
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp.StatusCode != http.StatusInternalServerError {
+ t.Fatalf("unexpected status code: %d", resp.StatusCode)
+ }
+ if r := srv.Requests(); r != defaultMaxTries {
+ t.Fatalf("wrong retry count, got %d expected %d", r, defaultMaxTries)
+ }
+ if body.rcount != defaultMaxTries-1 {
+ t.Fatalf("unexpected rewind count: %d", body.rcount)
+ }
+ if !body.closed {
+ t.Fatal("request body wasn't closed")
+ }
+}
+
+func TestRetryPolicySuccessWithRetry(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.AppendResponse(mock.WithStatusCode(http.StatusRequestTimeout))
+ srv.AppendResponse(mock.WithStatusCode(http.StatusInternalServerError))
+ srv.AppendResponse()
+ pl := NewPipeline(srv, NewRetryPolicy(testRetryOptions()))
+ req := NewRequest(http.MethodGet, srv.URL())
+ body := newRewindTrackingBody("stuff")
+ req.SetBody(body)
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp.StatusCode != http.StatusOK {
+ t.Fatalf("unexpected status code: %d", resp.StatusCode)
+ }
+ if r := srv.Requests(); r != 3 {
+ t.Fatalf("wrong retry count, got %d expected %d", r, 3)
+ }
+ if body.rcount != 2 {
+ t.Fatalf("unexpected rewind count: %d", body.rcount)
+ }
+ if !body.closed {
+ t.Fatal("request body wasn't closed")
+ }
+}
+
+func TestRetryPolicyFailOnError(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ fakeErr := errors.New("bogus error")
+ srv.SetError(fakeErr)
+ pl := NewPipeline(srv, NewRetryPolicy(testRetryOptions()))
+ req := NewRequest(http.MethodPost, srv.URL())
+ body := newRewindTrackingBody("stuff")
+ req.SetBody(body)
+ resp, err := pl.Do(context.Background(), req)
+ if !errors.Is(err, fakeErr) {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp != nil {
+ t.Fatal("unexpected response")
+ }
+ if r := srv.Requests(); r != defaultMaxTries {
+ t.Fatalf("wrong retry count, got %d expected %d", r, defaultMaxTries)
+ }
+ if body.rcount != defaultMaxTries-1 {
+ t.Fatalf("unexpected rewind count: %d", body.rcount)
+ }
+ if !body.closed {
+ t.Fatal("request body wasn't closed")
+ }
+}
+
+func TestRetryPolicySuccessWithRetryComplex(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.AppendResponse(mock.WithStatusCode(http.StatusRequestTimeout))
+ srv.AppendError(errors.New("bogus error"))
+ srv.AppendResponse(mock.WithStatusCode(http.StatusInternalServerError))
+ srv.AppendResponse(mock.WithStatusCode(http.StatusAccepted))
+ pl := NewPipeline(srv, NewRetryPolicy(testRetryOptions()))
+ req := NewRequest(http.MethodGet, srv.URL())
+ body := newRewindTrackingBody("stuff")
+ req.SetBody(body)
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp.StatusCode != http.StatusAccepted {
+ t.Fatalf("unexpected status code: %d", resp.StatusCode)
+ }
+ if r := srv.Requests(); r != defaultMaxTries {
+ t.Fatalf("wrong retry count, got %d expected %d", r, 3)
+ }
+ if body.rcount != defaultMaxTries-1 {
+ t.Fatalf("unexpected rewind count: %d", body.rcount)
+ }
+ if !body.closed {
+ t.Fatal("request body wasn't closed")
+ }
+}
+
+func TestRetryPolicyRequestTimedOut(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetError(errors.New("bogus error"))
+ pl := NewPipeline(srv, NewRetryPolicy(nil))
+ req := NewRequest(http.MethodPost, srv.URL())
+ body := newRewindTrackingBody("stuff")
+ req.SetBody(body)
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+ resp, err := pl.Do(ctx, req)
+ if !errors.Is(err, context.DeadlineExceeded) {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp != nil {
+ t.Fatal("unexpected response")
+ }
+ if body.rcount > 0 {
+ t.Fatalf("unexpected rewind count: %d", body.rcount)
+ }
+ if !body.closed {
+ t.Fatal("request body wasn't closed")
+ }
+}
+
+type fatalError struct {
+ s string
+}
+
+func (f fatalError) Error() string {
+ return f.s
+}
+
+func (f fatalError) IsNotRetriable() bool {
+ return true
+}
+
+func TestRetryPolicyIsNotRetriable(t *testing.T) {
+ theErr := fatalError{s: "it's dead Jim"}
+ srv, close := mock.NewServer()
+ defer close()
+ srv.AppendResponse(mock.WithStatusCode(http.StatusRequestTimeout))
+ srv.AppendError(theErr)
+ pl := NewPipeline(srv, NewRetryPolicy(testRetryOptions()))
+ _, err := pl.Do(context.Background(), NewRequest(http.MethodGet, srv.URL()))
+ if err == nil {
+ t.Fatal("unexpected nil error")
+ }
+ if !errors.Is(err, theErr) {
+ t.Fatalf("unexpected error type: got %v wanted %v", err, theErr)
+ }
+ if r := srv.Requests(); r != 2 {
+ t.Fatalf("wrong retry count, got %d expected %d", r, 3)
+ }
+}
+
+// TODO: add test for retry failing to read response body
+
+// TODO: add test for per-retry timeout failed but e2e succeeded
+
+func newRewindTrackingBody(s string) *rewindTrackingBody {
+ // there are two rewinds that happen before rewinding for a retry
+ // 1. to get the body's size in SetBody()
+ // 2. the first call to Do() in the retry policy
+ // to offset this we init rcount with -2 so rcount is only > 0 on a rewind due to a retry
+ return &rewindTrackingBody{
+ body: strings.NewReader(s),
+ rcount: -2,
+ }
+}
+
+// used to track the number of times a request body has been rewound
+type rewindTrackingBody struct {
+ body *strings.Reader
+ closed bool // indicates if the body was closed
+ rcount int // number of times a rewind happened
+}
+
+func (r *rewindTrackingBody) Close() error {
+ r.closed = true
+ return nil
+}
+
+func (r *rewindTrackingBody) Read(b []byte) (int, error) {
+ return r.body.Read(b)
+}
+
+func (r *rewindTrackingBody) Seek(offset int64, whence int) (int64, error) {
+ if offset == 0 && whence == io.SeekStart {
+ r.rcount++
+ }
+ return r.body.Seek(offset, whence)
+}
diff --git a/sdk/azcore/policy_telemetry.go b/sdk/azcore/policy_telemetry.go
new file mode 100644
index 000000000000..10c83fb82f2f
--- /dev/null
+++ b/sdk/azcore/policy_telemetry.go
@@ -0,0 +1,53 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "os"
+ "runtime"
+)
+
+// TelemetryOptions configures the telemetry policy's behavior.
+type TelemetryOptions struct {
+ // Value is a string prepended to each request's User-Agent and sent to the service.
+ // The service records the user-agent in logs for diagnostics and tracking of client requests.
+ Value string
+}
+
+type telemetryPolicy struct {
+ telemetryValue string
+}
+
+// NewTelemetryPolicy creates a telemetry policy object that adds telemetry information to outgoing HTTP requests.
+func NewTelemetryPolicy(o TelemetryOptions) Policy {
+ b := &bytes.Buffer{}
+ b.WriteString(o.Value)
+ if b.Len() > 0 {
+ b.WriteRune(' ')
+ }
+ b.WriteString(platformInfo)
+ return &telemetryPolicy{telemetryValue: b.String()}
+}
+
+func (p telemetryPolicy) Do(ctx context.Context, req *Request) (*Response, error) {
+ req.Request.Header.Set(HeaderUserAgent, p.telemetryValue)
+ return req.Next(ctx)
+}
+
+// NOTE: the ONLY function that should write to this variable is this func
+var platformInfo = func() string {
+ operatingSystem := runtime.GOOS // Default OS string
+ switch operatingSystem {
+ case "windows":
+ operatingSystem = os.Getenv("OS") // Get more specific OS information
+ case "linux": // accept default OS info
+ case "freebsd": // accept default OS info
+ }
+ return fmt.Sprintf("(%s; %s)", runtime.Version(), operatingSystem)
+}()
diff --git a/sdk/azcore/policy_telemetry_test.go b/sdk/azcore/policy_telemetry_test.go
new file mode 100644
index 000000000000..2c5dfe3a7f71
--- /dev/null
+++ b/sdk/azcore/policy_telemetry_test.go
@@ -0,0 +1,44 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func TestPolicyTelemetryDefault(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse()
+ pl := NewPipeline(srv, NewTelemetryPolicy(TelemetryOptions{}))
+ resp, err := pl.Do(context.Background(), NewRequest(http.MethodGet, srv.URL()))
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if v := resp.Request.Header.Get(HeaderUserAgent); v != platformInfo {
+ t.Fatalf("unexpected user agent value: %s", v)
+ }
+}
+
+func TestPolicyTelemetryWithCustomInfo(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse()
+ const testValue = "azcore_test"
+ pl := NewPipeline(srv, NewTelemetryPolicy(TelemetryOptions{Value: testValue}))
+ resp, err := pl.Do(context.Background(), NewRequest(http.MethodGet, srv.URL()))
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if v := resp.Request.Header.Get(HeaderUserAgent); v != fmt.Sprintf("%s %s", testValue, platformInfo) {
+ t.Fatalf("unexpected user agent value: %s", v)
+ }
+}
diff --git a/sdk/azcore/policy_unique_request_id.go b/sdk/azcore/policy_unique_request_id.go
new file mode 100644
index 000000000000..c5f9a84f2867
--- /dev/null
+++ b/sdk/azcore/policy_unique_request_id.go
@@ -0,0 +1,26 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/uuid"
+)
+
+const xMsClientRequestID = "x-ms-client-request-id"
+
+// NewUniqueRequestIDPolicy creates a policy object that sets the request's x-ms-client-request-id header if it doesn't already exist.
+func NewUniqueRequestIDPolicy() Policy {
+ return PolicyFunc(func(ctx context.Context, req *Request) (*Response, error) {
+ id := req.Request.Header.Get(xMsClientRequestID)
+ if id == "" {
+ // Add a unique request ID if the caller didn't specify one already
+ req.Request.Header.Set(xMsClientRequestID, uuid.New().String())
+ }
+ return req.Next(ctx)
+ })
+}
diff --git a/sdk/azcore/policy_unique_request_id_test.go b/sdk/azcore/policy_unique_request_id_test.go
new file mode 100644
index 000000000000..66c2141063c1
--- /dev/null
+++ b/sdk/azcore/policy_unique_request_id_test.go
@@ -0,0 +1,45 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "net/http"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func TestUniqueRequestIDPolicy(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse()
+ pl := NewPipeline(srv, NewUniqueRequestIDPolicy())
+ resp, err := pl.Do(context.Background(), NewRequest(http.MethodGet, srv.URL()))
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if resp.Request.Header.Get(xMsClientRequestID) == "" {
+ t.Fatal("missing request ID header")
+ }
+}
+
+func TestUniqueRequestIDPolicyUserDefined(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse()
+ pl := NewPipeline(srv, NewUniqueRequestIDPolicy())
+ req := NewRequest(http.MethodGet, srv.URL())
+ const customID = "my-custom-id"
+ req.Header.Set(xMsClientRequestID, customID)
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if v := resp.Request.Header.Get(xMsClientRequestID); v != customID {
+ t.Fatalf("unexpected request ID value: %s", v)
+ }
+}
diff --git a/sdk/azcore/progress.go b/sdk/azcore/progress.go
new file mode 100644
index 000000000000..8364581b657e
--- /dev/null
+++ b/sdk/azcore/progress.go
@@ -0,0 +1,78 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import "io"
+
+// ********** The following is common between the request body AND the response body.
+
+// ProgressReceiver defines the signature of a callback function invoked as progress is reported.
+type ProgressReceiver func(bytesTransferred int64)
+
+// ********** The following are specific to the request body (a ReadSeekCloser)
+
+// This struct is used when sending a body to the network
+type requestBodyProgress struct {
+ requestBody ReadSeekCloser // Seeking is required to support retries
+ pr ProgressReceiver
+}
+
+// NewRequestBodyProgress adds progress reporting to an HTTP request's body stream.
+func NewRequestBodyProgress(requestBody ReadSeekCloser, pr ProgressReceiver) ReadSeekCloser {
+ return &requestBodyProgress{requestBody: requestBody, pr: pr}
+}
+
+// Read reads a block of data from an inner stream and reports progress
+func (rbp *requestBodyProgress) Read(p []byte) (n int, err error) {
+ n, err = rbp.requestBody.Read(p)
+ if err != nil {
+ return
+ }
+ // Invokes the user's callback method to report progress
+ position, err := rbp.requestBody.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return
+ }
+ rbp.pr(position)
+ return
+}
+
+func (rbp *requestBodyProgress) Seek(offset int64, whence int) (offsetFromStart int64, err error) {
+ return rbp.requestBody.Seek(offset, whence)
+}
+
+// requestBodyProgress supports Close but the underlying stream may not; if it does, Close will close it.
+func (rbp *requestBodyProgress) Close() error {
+ return rbp.requestBody.Close()
+}
+
+// ********** The following are specific to the response body (a ReadCloser)
+
+// This struct is used when sending a body to the network
+type responseBodyProgress struct {
+ responseBody io.ReadCloser
+ pr ProgressReceiver
+ offset int64
+}
+
+// NewResponseBodyProgress adds progress reporting to an HTTP response's body stream.
+func NewResponseBodyProgress(responseBody io.ReadCloser, pr ProgressReceiver) io.ReadCloser {
+ return &responseBodyProgress{responseBody: responseBody, pr: pr, offset: 0}
+}
+
+// Read reads a block of data from an inner stream and reports progress
+func (rbp *responseBodyProgress) Read(p []byte) (n int, err error) {
+ n, err = rbp.responseBody.Read(p)
+ rbp.offset += int64(n)
+
+ // Invokes the user's callback method to report progress
+ rbp.pr(rbp.offset)
+ return
+}
+
+func (rbp *responseBodyProgress) Close() error {
+ return rbp.responseBody.Close()
+}
diff --git a/sdk/azcore/progress_test.go b/sdk/azcore/progress_test.go
new file mode 100644
index 000000000000..61c3830175f0
--- /dev/null
+++ b/sdk/azcore/progress_test.go
@@ -0,0 +1,59 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "bytes"
+ "context"
+ "io/ioutil"
+ "net/http"
+ "reflect"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func TestProgressReporting(t *testing.T) {
+ const contentSize = 4096
+ content := make([]byte, contentSize)
+ for i := 0; i < contentSize; i++ {
+ content[i] = byte(i % 255)
+ }
+ body := bytes.NewReader(content)
+ srv, close := mock.NewServer()
+ defer close()
+ srv.SetResponse(mock.WithBody(content))
+ pl := NewPipeline(srv, NewTelemetryPolicy(TelemetryOptions{}))
+ req := NewRequest(http.MethodGet, srv.URL())
+ req.SkipBodyDownload()
+ var bytesSent int64
+ reqRpt := NewRequestBodyProgress(NopCloser(body), func(bytesTransferred int64) {
+ bytesSent = bytesTransferred
+ })
+ req.SetBody(reqRpt)
+ resp, err := pl.Do(context.Background(), req)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ var bytesReceived int64
+ respRpt := NewResponseBodyProgress(resp.Body, func(bytesTransferred int64) {
+ bytesReceived = bytesTransferred
+ })
+ defer respRpt.Close()
+ b, err := ioutil.ReadAll(respRpt)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if bytesSent != contentSize {
+ t.Fatalf("wrong bytes sent: %d", bytesSent)
+ }
+ if bytesReceived != contentSize {
+ t.Fatalf("wrong bytes received: %d", bytesReceived)
+ }
+ if !reflect.DeepEqual(content, b) {
+ t.Fatal("request and response bodies don't match")
+ }
+}
diff --git a/sdk/azcore/request.go b/sdk/azcore/request.go
new file mode 100644
index 000000000000..7d87b20baa07
--- /dev/null
+++ b/sdk/azcore/request.go
@@ -0,0 +1,196 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "reflect"
+ "strings"
+)
+
+const (
+ contentTypeAppJSON = "application/json"
+ contentTypeAppXML = "application/xml"
+)
+
+// Request is an abstraction over the creation of an HTTP request as it passes through the pipeline.
+type Request struct {
+ *http.Request
+ policies []Policy
+ qp url.Values
+ values opValues
+}
+
+type opValues map[reflect.Type]interface{}
+
+// Set adds/changes a value
+func (ov opValues) set(value interface{}) {
+ ov[reflect.TypeOf(value)] = value
+}
+
+// Get looks for a value set by SetValue first
+func (ov opValues) get(value interface{}) bool {
+ v, ok := ov[reflect.ValueOf(value).Elem().Type()]
+ if ok {
+ reflect.ValueOf(value).Elem().Set(reflect.ValueOf(v))
+ }
+ return ok
+}
+
+// NewRequest creates a new Request with the specified input.
+func NewRequest(httpMethod string, endpoint url.URL) *Request {
+ // removeEmptyPort strips the empty port in ":port" to ""
+ // as mandated by RFC 3986 Section 6.2.3.
+ // adapted from removeEmptyPort() in net/http.go
+ if strings.LastIndex(endpoint.Host, ":") > strings.LastIndex(endpoint.Host, "]") {
+ endpoint.Host = strings.TrimSuffix(endpoint.Host, ":")
+ }
+ return &Request{
+ Request: &http.Request{
+ Method: httpMethod,
+ URL: &endpoint,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: http.Header{},
+ Host: endpoint.Host,
+ },
+ }
+}
+
+// Next calls the next policy in the pipeline.
+// If there are no more policies, nil and ErrNoMorePolicies are returned.
+// This method is intended to be called from pipeline policies.
+// To send a request through a pipeline call Pipeline.Do().
+func (req *Request) Next(ctx context.Context) (*Response, error) {
+ if len(req.policies) == 0 {
+ return nil, ErrNoMorePolicies
+ }
+ nextPolicy := req.policies[0]
+ nextReq := *req
+ nextReq.policies = nextReq.policies[1:]
+ // encode any pending query params
+ if nextReq.qp != nil {
+ nextReq.Request.URL.RawQuery = nextReq.qp.Encode()
+ nextReq.qp = nil
+ }
+ return nextPolicy.Do(ctx, &nextReq)
+}
+
+// MarshalAsJSON calls json.Marshal() to get the JSON encoding of v then calls SetBody.
+// If json.Marshal fails a MarshalError is returned. Any error from SetBody is returned.
+func (req *Request) MarshalAsJSON(v interface{}) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return fmt.Errorf("error marshalling type %s: %w", reflect.TypeOf(v).Name(), err)
+ }
+ req.Header.Set(HeaderContentType, contentTypeAppJSON)
+ return req.SetBody(NopCloser(bytes.NewReader(b)))
+}
+
+// MarshalAsXML calls xml.Marshal() to get the XML encoding of v then calls SetBody.
+// If xml.Marshal fails a MarshalError is returned. Any error from SetBody is returned.
+func (req *Request) MarshalAsXML(v interface{}) error {
+ b, err := xml.Marshal(v)
+ if err != nil {
+ return fmt.Errorf("error marshalling type %s: %w", reflect.TypeOf(v).Name(), err)
+ }
+ req.Header.Set(HeaderContentType, contentTypeAppXML)
+ return req.SetBody(NopCloser(bytes.NewReader(b)))
+}
+
+// SetOperationValue adds/changes a mutable key/value associated with a single operation.
+func (req *Request) SetOperationValue(value interface{}) {
+ if req.values == nil {
+ req.values = opValues{}
+ }
+ req.values.set(value)
+}
+
+// OperationValue looks for a value set by SetOperationValue().
+func (req *Request) OperationValue(value interface{}) bool {
+ if req.values == nil {
+ return false
+ }
+ return req.values.get(value)
+}
+
+// SetQueryParam sets the key to value.
+func (req *Request) SetQueryParam(key, value string) {
+ if req.qp == nil {
+ req.qp = req.Request.URL.Query()
+ }
+ req.qp.Set(key, value)
+}
+
+// SetBody sets the specified ReadSeekCloser as the HTTP request body.
+func (req *Request) SetBody(body ReadSeekCloser) error {
+ // Set the body and content length.
+ size, err := body.Seek(0, io.SeekEnd) // Seek to the end to get the stream's size
+ if err != nil {
+ return err
+ }
+ if size == 0 {
+ body.Close()
+ return nil
+ }
+ _, err = body.Seek(0, io.SeekStart)
+ if err != nil {
+ return err
+ }
+ req.Request.Body = body
+ req.Request.ContentLength = size
+ return nil
+}
+
+// SkipBodyDownload will disable automatic downloading of the response body.
+func (req *Request) SkipBodyDownload() {
+ req.SetOperationValue(bodyDownloadPolicyOpValues{skip: true})
+}
+
+// RewindBody seeks the request's Body stream back to the beginning so it can be resent when retrying an operation.
+func (req *Request) RewindBody() error {
+ if req.Body != nil {
+ // Reset the stream back to the beginning
+ _, err := req.Body.(io.Seeker).Seek(0, io.SeekStart)
+ return err
+ }
+ return nil
+}
+
+// Close closes the request body.
+func (req *Request) Close() error {
+ if req.Body == nil {
+ return nil
+ }
+ return req.Body.Close()
+}
+
+func (req *Request) copy() *Request {
+ clonedURL := *req.URL
+ // Copy the values and immutable references
+ return &Request{
+ Request: &http.Request{
+ Method: req.Method,
+ URL: &clonedURL,
+ Proto: req.Proto,
+ ProtoMajor: req.ProtoMajor,
+ ProtoMinor: req.ProtoMinor,
+ Header: req.Header.Clone(),
+ Host: req.URL.Host,
+ Body: req.Body, // shallow copy
+ ContentLength: req.ContentLength,
+ GetBody: req.GetBody,
+ },
+ }
+}
diff --git a/sdk/azcore/request_test.go b/sdk/azcore/request_test.go
new file mode 100644
index 000000000000..27576d47ee9e
--- /dev/null
+++ b/sdk/azcore/request_test.go
@@ -0,0 +1,81 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "errors"
+ "net/http"
+ "net/url"
+ "testing"
+)
+
+type testJSON struct {
+ SomeInt int
+ SomeString string
+}
+
+type testXML struct {
+ SomeInt int
+ SomeString string
+}
+
+func TestRequestMarshalXML(t *testing.T) {
+ u, err := url.Parse("https://contoso.com")
+ if err != nil {
+ panic(err)
+ }
+ req := NewRequest(http.MethodPost, *u)
+ err = req.MarshalAsXML(testXML{SomeInt: 1, SomeString: "s"})
+ if err != nil {
+ t.Fatalf("marshal failure: %v", err)
+ }
+ if ct := req.Header.Get(HeaderContentType); ct != contentTypeAppXML {
+ t.Fatalf("unexpected content type, got %s wanted %s", ct, contentTypeAppXML)
+ }
+ if req.Body == nil {
+ t.Fatal("unexpected nil request body")
+ }
+ if req.ContentLength == 0 {
+ t.Fatal("unexpected zero content length")
+ }
+}
+
+func TestRequestEmptyPipeline(t *testing.T) {
+ u, err := url.Parse("https://contoso.com")
+ if err != nil {
+ panic(err)
+ }
+ req := NewRequest(http.MethodPost, *u)
+ resp, err := req.Next(context.Background())
+ if resp != nil {
+ t.Fatal("expected nil response")
+ }
+ if !errors.Is(err, ErrNoMorePolicies) {
+ t.Fatalf("expected ErrNoMorePolicies, got %v", err)
+ }
+}
+
+func TestRequestMarshalJSON(t *testing.T) {
+ u, err := url.Parse("https://contoso.com")
+ if err != nil {
+ panic(err)
+ }
+ req := NewRequest(http.MethodPost, *u)
+ err = req.MarshalAsJSON(testJSON{SomeInt: 1, SomeString: "s"})
+ if err != nil {
+ t.Fatalf("marshal failure: %v", err)
+ }
+ if ct := req.Header.Get(HeaderContentType); ct != contentTypeAppJSON {
+ t.Fatalf("unexpected content type, got %s wanted %s", ct, contentTypeAppJSON)
+ }
+ if req.Body == nil {
+ t.Fatal("unexpected nil request body")
+ }
+ if req.ContentLength == 0 {
+ t.Fatal("unexpected zero content length")
+ }
+}
diff --git a/sdk/azcore/response.go b/sdk/azcore/response.go
new file mode 100644
index 000000000000..edb19ad244e3
--- /dev/null
+++ b/sdk/azcore/response.go
@@ -0,0 +1,147 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Response represents the response from an HTTP request.
+type Response struct {
+ *http.Response
+}
+
+func (r *Response) payload() []byte {
+ if r.Body == nil {
+ return nil
+ }
+ // r.Body won't be a nopClosingBytesReader if downloading was skipped
+ if buf, ok := r.Body.(*nopClosingBytesReader); ok {
+ return buf.Bytes()
+ }
+ return nil
+}
+
+// HasStatusCode returns true if the Response's status code is one of the specified values.
+func (r *Response) HasStatusCode(statusCodes ...int) bool {
+ if r == nil {
+ return false
+ }
+ for _, sc := range statusCodes {
+ if r.StatusCode == sc {
+ return true
+ }
+ }
+ return false
+}
+
+// UnmarshalAsJSON calls json.Unmarshal() to unmarshal the received payload into the value pointed to by v.
+// If no payload was received a RequestError is returned. If json.Unmarshal fails a UnmarshalError is returned.
+func (r *Response) UnmarshalAsJSON(v interface{}) error {
+ // TODO: verify early exit is correct
+ if len(r.payload()) == 0 {
+ return nil
+ }
+ r.removeBOM()
+ err := json.Unmarshal(r.payload(), v)
+ if err != nil {
+ err = fmt.Errorf("unmarshalling type %s: %w", reflect.TypeOf(v).Elem().Name(), err)
+ }
+ return err
+}
+
+// UnmarshalAsXML calls xml.Unmarshal() to unmarshal the received payload into the value pointed to by v.
+// If no payload was received a RequestError is returned. If xml.Unmarshal fails a UnmarshalError is returned.
+func (r *Response) UnmarshalAsXML(v interface{}) error {
+ // TODO: verify early exit is correct
+ if len(r.payload()) == 0 {
+ return nil
+ }
+ r.removeBOM()
+ err := xml.Unmarshal(r.payload(), v)
+ if err != nil {
+ err = fmt.Errorf("unmarshalling type %s: %w", reflect.TypeOf(v).Elem().Name(), err)
+ }
+ return err
+}
+
+// Drain reads the response body to completion then closes it. The bytes read are discarded.
+func (r *Response) Drain() {
+ if r != nil && r.Body != nil {
+ io.Copy(ioutil.Discard, r.Body)
+ r.Body.Close()
+ }
+}
+
+// removeBOM removes any byte-order mark prefix from the payload if present.
+func (r *Response) removeBOM() {
+ // UTF8
+ trimmed := bytes.TrimPrefix(r.payload(), []byte("\xef\xbb\xbf"))
+ if len(trimmed) < len(r.payload()) {
+ r.Body.(*nopClosingBytesReader).Set(trimmed)
+ }
+}
+
+// RetryAfter returns (non-zero, true) if the response contains a Retry-After header value
+func (r *Response) RetryAfter() (time.Duration, bool) {
+ if r == nil {
+ return 0, false
+ }
+ if retryAfter, _ := strconv.Atoi(r.Header.Get("Retry-After")); retryAfter > 0 {
+ return time.Duration(retryAfter) * time.Second, true
+ }
+ return 0, false
+}
+
+// WriteRequestWithResponse appends a formatted HTTP request into a Buffer. If request and/or err are
+// not nil, then these are also written into the Buffer.
+func WriteRequestWithResponse(b *bytes.Buffer, request *Request, response *Response, err error) {
+ // Write the request into the buffer.
+ fmt.Fprint(b, " "+request.Method+" "+request.URL.String()+"\n")
+ writeHeader(b, request.Header)
+ if response != nil {
+ fmt.Fprintln(b, " --------------------------------------------------------------------------------")
+ fmt.Fprint(b, " RESPONSE Status: "+response.Status+"\n")
+ writeHeader(b, response.Header)
+ }
+ if err != nil {
+ fmt.Fprintln(b, " --------------------------------------------------------------------------------")
+ fmt.Fprint(b, " ERROR:\n"+err.Error()+"\n")
+ }
+}
+
+// formatHeaders appends an HTTP request's or response's header into a Buffer.
+func writeHeader(b *bytes.Buffer, header http.Header) {
+ if len(header) == 0 {
+ b.WriteString(" (no headers)\n")
+ return
+ }
+ keys := make([]string, 0, len(header))
+ // Alphabetize the headers
+ for k := range header {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ // Redact the value of any Authorization header to prevent security information from persisting in logs
+ value := interface{}("REDACTED")
+ if !strings.EqualFold(k, "Authorization") {
+ value = header[k]
+ }
+ fmt.Fprintf(b, " %s: %+v\n", k, value)
+ }
+}
diff --git a/sdk/azcore/response_test.go b/sdk/azcore/response_test.go
new file mode 100644
index 000000000000..263f0c3db674
--- /dev/null
+++ b/sdk/azcore/response_test.go
@@ -0,0 +1,105 @@
+// +build go1.13
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azcore
+
+import (
+ "context"
+ "net/http"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
+)
+
+func TestResponseUnmarshalXML(t *testing.T) {
+ srv, close := mock.NewServer()
+ defer close()
+ // include UTF8 BOM
+ srv.SetResponse(mock.WithBody([]byte("\xef\xbb\xbf