chore: update DNS providers dependencies. (#915)

This commit is contained in:
Ludovic Fernandez 2019-07-04 18:24:33 +02:00 committed by GitHub
parent 8dcc55b828
commit f5cd138ea6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
525 changed files with 49654 additions and 6925 deletions

177
Gopkg.lock generated
View file

@ -10,33 +10,42 @@
version = "v0.26.0"
[[projects]]
digest = "1:e589e863ce0d0500bb806c716877c2f8caffe2a2b6c2f6c148d535d8eeb92d00"
digest = "1:3fb854fc35fafced21615a93db3c0e324c8cb1d5a89f39dd1e72db0c4200345a"
name = "contrib.go.opencensus.io/exporter/ocagent"
packages = ["."]
pruneopts = "NUT"
revision = "dcb33c7f3b7cfe67e8a2cea10207ede1b7c40764"
version = "v0.4.12"
[[projects]]
digest = "1:387c36a55aa52170ad77c92b1f9a77a2718ecb41c2fdf0a910a5ed2b940b6149"
name = "github.com/Azure/azure-sdk-for-go"
packages = [
"services/dns/mgmt/2017-09-01/dns",
"version",
]
pruneopts = "NUT"
revision = "4e8cbbfb1aeab140cd0fa97fd16b64ee18c3ca6a"
version = "v19.1.0"
revision = "66cf3bc60d4d086e8e566d505b1cd30f5f506639"
version = "v31.0.0"
[[projects]]
digest = "1:0b2163d4a757420217d4e0461128bf5c96be6d1614513b31d35029872a07ad40"
digest = "1:902fe8d968778bd0c0150408f658b56c9951fb6fd677ab0c148eeac3fc053340"
name = "github.com/Azure/go-autorest"
packages = [
"autorest",
"autorest/adal",
"autorest/azure",
"autorest/azure/auth",
"autorest/azure/cli",
"autorest/date",
"autorest/to",
"autorest/validation",
"logger",
"version",
"tracing",
]
pruneopts = "NUT"
revision = "39013ecb48eaf6ced3f4e3e1d95515140ce6b3cf"
version = "v10.15.2"
revision = "09205e8f6711a776499a14cf8adc6bd380db5d81"
version = "v12.2.0"
[[projects]]
digest = "1:5d72bbcc9c8667b11c3dc3cbe681c5a6f71e5096744c0bf7726ab5c6425d5dc4"
@ -76,12 +85,13 @@
version = "v0.7.4"
[[projects]]
digest = "1:823e87ae25170339e2bfd1d6f7c2e27554c6bb5655f91c67b37bd5be45bb6b32"
digest = "1:328d829ec0e36017fc18c65b8eaf258021b90e7ff294412b3dc9a315ee04b68a"
name = "github.com/aliyun/alibaba-cloud-sdk-go"
packages = [
"sdk",
"sdk/auth",
"sdk/auth/credentials",
"sdk/auth/credentials/provider",
"sdk/auth/signers",
"sdk/endpoints",
"sdk/errors",
@ -91,11 +101,11 @@
"services/alidns",
]
pruneopts = "NUT"
revision = "cad214d7d71fba7883fcf3b7e550ba782c15b400"
version = "1.27.7"
revision = "133cfe6c309b3d61b38d7076a852f155619d48ff"
version = "1.60.57"
[[projects]]
digest = "1:1634c57333a07adf7d7e206d3329340f1c36e82bca9e61e2cff08c064ab85046"
digest = "1:2103f1d7935e7569064e90e59b071dd7bc65a1aeb2014688a23465eaf30848c7"
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
@ -107,6 +117,7 @@
"aws/credentials",
"aws/credentials/ec2rolecreds",
"aws/credentials/endpointcreds",
"aws/credentials/processcreds",
"aws/credentials/stscreds",
"aws/csm",
"aws/defaults",
@ -115,6 +126,7 @@
"aws/request",
"aws/session",
"aws/signer/v4",
"internal/ini",
"internal/sdkio",
"internal/sdkrand",
"internal/sdkuri",
@ -132,8 +144,8 @@
"service/sts",
]
pruneopts = "NUT"
revision = "8b15f938ed215522a37275106e847f6f0be85fe8"
version = "v1.15.23"
revision = "06512ecac9db8f44189277d87f426e6dc53cc86b"
version = "v1.20.14"
[[projects]]
digest = "1:cdee563173093e5ae7ab2a19c298e0904129719e1919a3c532b7bb0c3398b818"
@ -144,12 +156,27 @@
version = "v2.1.1"
[[projects]]
digest = "1:03cfacdc6bfd46007c15786c1ece3fa074f89e5193a292f0f26d9e98c99c7cc2"
digest = "1:fdb4ed936abeecb46a8c27dcac83f75c05c87a46d9ec7711411eb785c213fa02"
name = "github.com/census-instrumentation/opencensus-proto"
packages = [
"gen-go/agent/common/v1",
"gen-go/agent/metrics/v1",
"gen-go/agent/trace/v1",
"gen-go/metrics/v1",
"gen-go/resource/v1",
"gen-go/trace/v1",
]
pruneopts = "NUT"
revision = "a105b96453fe85139acc07b68de48f2cbdd71249"
version = "v0.2.0"
[[projects]]
digest = "1:967f24bdc4ffbea9c4cca556caa446805257e64f6a2b1a5f4b69b32a7e888129"
name = "github.com/cloudflare/cloudflare-go"
packages = ["."]
pruneopts = "NUT"
revision = "1f9007fbecae20711133c60519338c41cef1ffb4"
version = "v0.8.5"
revision = "33ef9f42e17f33f6088dfe8c0dc95b916d1edfc6"
version = "v0.9.2"
[[projects]]
branch = "master"
@ -184,28 +211,28 @@
version = "v3.2.0"
[[projects]]
branch = "master"
digest = "1:ec6271918b59b872a2d25e374569a4f75f1839d91e4191470c297b7eaaaf7641"
digest = "1:f9adc21a937e5da643ea14a3488cb7506788876737a5e205394e508627a6eec8"
name = "github.com/dimchansky/utfbom"
packages = ["."]
pruneopts = "NUT"
revision = "5448fe645cb1964ba70ac8f9f2ffe975e61a536c"
revision = "d2133a1ce379ef6fa992b0514a77146c60db9d1c"
version = "v1.1.0"
[[projects]]
digest = "1:5ec1feea329f68f736c43e81a218c18e4e83779fb96d118becb97a9f2f7d6fc4"
digest = "1:d9688055094edd046a71ee85204ea97090ecce6f316b739be3a50f5ca6403ebb"
name = "github.com/dnsimple/dnsimple-go"
packages = ["dnsimple"]
pruneopts = "NUT"
revision = "8f70b647443816578a776f6c6d3e84deb11e1731"
version = "v0.23.0"
revision = "7e193cc468a07cdf74d76de1e6736c709c5a3872"
version = "v0.30.0"
[[projects]]
digest = "1:e73fd806b49d0e5c5d81776f8b33e1c35918cdd6c02dea4f1c2d91e70c8aa378"
digest = "1:efcc176c5cfbe8421dd3eb2562be91c3272e80f61b181e31d5745b7fee29a669"
name = "github.com/exoscale/egoscale"
packages = ["."]
pruneopts = "NUT"
revision = "4e527724b8225e8315d580accd1c4e860202d41b"
version = "v0.17.1"
revision = "8f608c40ae891e0240bb6e696a72437be7069d83"
version = "v0.18.1"
[[projects]]
digest = "1:aa3ed0a71c4e66e4ae6486bf97a3f4cab28edc78df2e50c5ad01dc7d91604b88"
@ -240,18 +267,25 @@
version = "v3.2.0"
[[projects]]
digest = "1:63ccdfbd20f7ccd2399d0647a7d100b122f79c13bb83da9660b1598396fd9f62"
digest = "1:27d8aff388ac8ea2d4057097ef4aad2f98a6a8796477213096160b72b6c87cf2"
name = "github.com/golang/protobuf"
packages = [
"jsonpb",
"proto",
"protoc-gen-go/descriptor",
"protoc-gen-go/generator",
"protoc-gen-go/generator/internal/remap",
"protoc-gen-go/plugin",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/struct",
"ptypes/timestamp",
"ptypes/wrappers",
]
pruneopts = "NUT"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
revision = "b5d812f8a3706043e23a9cd5babf2e5423744d30"
version = "v1.3.1"
[[projects]]
branch = "master"
@ -287,6 +321,18 @@
pruneopts = "NUT"
revision = "a2b0ad6ce68c8302027db1a5f9dbb03b0c8ab072"
[[projects]]
digest = "1:960e8004095e3be6cff988becc8cc9ec1dc0e06887144ed46ff2da86e7c0efea"
name = "github.com/grpc-ecosystem/grpc-gateway"
packages = [
"internal",
"runtime",
"utilities",
]
pruneopts = "NUT"
revision = "d54b3615f714b03edde6d9206fa0476a9169c966"
version = "v1.9.3"
[[projects]]
digest = "1:67474f760e9ac3799f740db2c489e6423a4cde45520673ec123ac831ad849cb8"
name = "github.com/hashicorp/golang-lru"
@ -307,11 +353,11 @@
revision = "8803795a9b7b938fa88ddbd63a77893beee14cd8"
[[projects]]
digest = "1:ac6d01547ec4f7f673311b4663909269bfb8249952de3279799289467837c3cc"
digest = "1:1f2aebae7e7c856562355ec0198d8ca2fa222fb05e5b1b66632a1fce39631885"
name = "github.com/jmespath/go-jmespath"
packages = ["."]
pruneopts = "NUT"
revision = "0b12d6b5"
revision = "c2b33e84"
[[projects]]
digest = "1:8e36686e8b139f8fe240c1d5cf3a145bc675c22ff8e707857cdd3ae17b00d728"
@ -357,20 +403,20 @@
revision = "8b16b4848295edda07b9a828e5a3b285c25c2b9c"
[[projects]]
digest = "1:a0181b662584429828ccdd68d4dbe09ba7ba7414ef01d54b96f152002802ed72"
digest = "1:7981caf0d67995c0acbd352785f45b177a2d089ed40f2005794c0772d0fbfff9"
name = "github.com/linode/linodego"
packages = ["."]
pruneopts = "NUT"
revision = "42d84d42f3f28fe1fe1823c58c11715241eda24e"
version = "v0.7.1"
revision = "7adba57685c129bcd29a9edc7008ec3b05680240"
version = "v0.10.0"
[[projects]]
digest = "1:bcc0ec1552cdcd95ee76052a01273eb35917df74825420b3e3df12c3b8d5e6ed"
digest = "1:7894d93b1bbb3ab412c9b4f2573accc5becbcce2516e1fe5a4d2da1825b2e369"
name = "github.com/miekg/dns"
packages = ["."]
pruneopts = "NUT"
revision = "8aa92d4e02c501ba21e26fb92cf2fb9f23f56917"
version = "v1.1.9"
revision = "b13675009d59c97f3721247d9efa8914e1866a5b"
version = "v1.1.15"
[[projects]]
digest = "1:a4df73029d2c42fabcb6b41e327d2f87e685284ec03edf76921c267d9cfc9c23"
@ -429,15 +475,15 @@
version = "v0.6.0"
[[projects]]
digest = "1:50ba4638005d50396250b601811becb6b11ab13b0b7fa8ccbe119e21ce08a4fa"
digest = "1:482e6a8662dcfd8dc7ebf28b8a1a293b6d453f71bda13e370b3949cb487e6dd6"
name = "github.com/oracle/oci-go-sdk"
packages = [
"common",
"dns",
]
pruneopts = "NUT"
revision = "9ed9700756ebdedc96eaefcccf9322afbd4009ef"
version = "v5.4.0"
revision = "481415e15d394fa0817faedceabb7c59e21133b8"
version = "v5.13.0"
[[projects]]
branch = "master"
@ -472,7 +518,7 @@
revision = "1031fa0ce2f20c1c0e1e1b51951d8ea02c84fa05"
[[projects]]
digest = "1:253f275bd72c42f8d234712d1574c8b222fe9b72838bfaca11b21ace9c0e3d0a"
digest = "1:7ddc1fdd49e0e59eb618fd4af9b5802358178392d7dfefc18f7dd691e81f979f"
name = "github.com/sacloud/libsacloud"
packages = [
".",
@ -482,16 +528,8 @@
"utils/mutexkv",
]
pruneopts = "NUT"
revision = "41c392dee98a83260abbe0fcd5c13beb7c75d103"
version = "v1.21.1"
[[projects]]
digest = "1:6bc0652ea6e39e22ccd522458b8bdd8665bf23bdc5a20eec90056e4dc7e273ca"
name = "github.com/satori/go.uuid"
packages = ["."]
pruneopts = "NUT"
revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
version = "v1.2.0"
revision = "6fb0c01c45716a08d5438f6d85a2a8984cc8a0a8"
version = "v1.25.1"
[[projects]]
digest = "1:b2339e83ce9b5c4f79405f949429a7f68a9a904fed903c672aac1e7ceb7f5f02"
@ -534,7 +572,7 @@
revision = "37e84520dcf74488f67654f9c775b9752c232dc1"
[[projects]]
digest = "1:21ef4b12d6b6c6dfe389caa82f859d1e35eeb24ce61c60d09db57addb6a95781"
digest = "1:4da573eeacb95c9452ae7ddc14b06148a99b29bf98522abb221ef9799426187c"
name = "github.com/transip/gotransip"
packages = [
".",
@ -542,8 +580,8 @@
"util",
]
pruneopts = "NUT"
revision = "c6e2ce0bbb4a601a909e3b7a773358d6b503e663"
version = "v5.8.2"
revision = "efb64632cab7701ec33f1eaeaa738e2207efe68e"
version = "v5.14"
[[projects]]
digest = "1:5dba68a1600a235630e208cb7196b24e58fcbb77bb7a6bec08fcd23f081b0a58"
@ -554,7 +592,7 @@
version = "v1.20.0"
[[projects]]
digest = "1:045bc0ab96bb83bdffd2606f019003da03d1c139d3cb8aad13596863e4dd37d6"
digest = "1:58f2854b50ff8862eb6a347f20dedaac83e1166f4040472e17bc37736841a12f"
name = "go.opencensus.io"
packages = [
".",
@ -562,8 +600,10 @@
"internal/tagencoding",
"metric/metricdata",
"metric/metricproducer",
"plugin/ocgrpc",
"plugin/ochttp",
"plugin/ochttp/propagation/b3",
"plugin/ochttp/propagation/tracecontext",
"resource",
"stats",
"stats/internal",
@ -575,8 +615,8 @@
"trace/tracestate",
]
pruneopts = "NUT"
revision = "8930459677fde1e11e3e1b50bbed1acc850b5665"
version = "v0.20.1"
revision = "43463a80402d8447b7fce0d2c58edf1687ff0b58"
version = "v0.19.3"
[[projects]]
branch = "master"
@ -643,6 +683,14 @@
pruneopts = "NUT"
revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9"
[[projects]]
branch = "master"
digest = "1:382bb5a7fb4034db3b6a2d19e5a4a6bcf52f4750530603c01ca18a172fa3089b"
name = "golang.org/x/sync"
packages = ["semaphore"]
pruneopts = "NUT"
revision = "112230192c580c3556b8cee6403af37a4fc5f28c"
[[projects]]
branch = "master"
digest = "1:e1498a6884b2564efe2a4c4aefce64eb4bc6a4666acfd42db044cf581db4d9cb"
@ -687,7 +735,7 @@
[[projects]]
branch = "master"
digest = "1:887c07769ee52c81222ea1112b11a3947c703da529d1643d85c216b9537d87b8"
digest = "1:867c0e5fbb22d5ae76c8255aa8f4ac3c27eede02d29baa804faa590d42ae44e6"
name = "google.golang.org/api"
packages = [
"dns/v1",
@ -697,6 +745,7 @@
"googleapi/transport",
"internal",
"option",
"support/bundler",
"transport/http",
"transport/http/internal/propagation",
]
@ -724,9 +773,13 @@
[[projects]]
branch = "master"
digest = "1:c3076e7defee87de1236f1814beb588f40a75544c60121e6eb38b3b3721783e2"
digest = "1:5dc13cd8c0b417e12d187938d2ccb2348dda90f6d3d4a3d8402a40677a5ac982"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
packages = [
"googleapis/api/httpbody",
"googleapis/rpc/status",
"protobuf/field_mask",
]
pruneopts = "NUT"
revision = "64821d5d210748c883cd2b809589555ae4654203"
@ -802,7 +855,7 @@
version = "v1.12.0"
[[projects]]
digest = "1:a50fabe7a46692dc7c656310add3d517abe7914df02afd151ef84da884605dc8"
digest = "1:a56dc1133e9c449d41d22ffabd6c2343cd25ab31c9cad0e74a144006810d1544"
name = "gopkg.in/square/go-jose.v2"
packages = [
".",
@ -810,8 +863,8 @@
"json",
]
pruneopts = "NUT"
revision = "ef984e69dd356202fd4e4910d4d9c24468bdf0b8"
version = "v2.1.9"
revision = "730df5f748271903322feb182be83b43ebbbe27d"
version = "v2.3.1"
[solve-meta]
analyzer-name = "dep"

View file

@ -30,81 +30,101 @@
unused-packages = true
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
branch = "master"
name = "golang.org/x/oauth2"
[[constraint]]
branch = "master"
name = "google.golang.org/api"
[[constraint]]
version = "v1.1.9"
name = "github.com/miekg/dns"
version = "1.1.15"
[[constraint]]
name = "gopkg.in/square/go-jose.v2"
version = "2.3.1"
[[constraint]]
name = "golang.org/x/crypto"
branch = "master"
[[constraint]]
name = "golang.org/x/net"
branch = "master"
[[constraint]]
name = "golang.org/x/oauth2"
branch = "master"
[[constraint]]
name = "google.golang.org/api"
branch = "master"
[[constraint]]
name = "github.com/rainycape/memcache"
branch = "master"
[[constraint]]
version = "0.2.0"
name = "github.com/decker502/dnspod-go"
version = "0.2.0"
[[constraint]]
version = "0.23.0"
name = "github.com/dnsimple/dnsimple-go"
version = "0.30.0"
[[constraint]]
branch = "master"
name = "github.com/namedotcom/go"
branch = "master"
[[constraint]]
branch = "master"
name = "github.com/ovh/go-ovh"
[[constraint]]
branch = "master"
[[constraint]]
name = "github.com/timewasted/linode"
branch = "master"
[[constraint]]
version = "0.6.0"
name = "github.com/nrdcg/goinwx"
version = "0.6.0"
[[constraint]]
version = "0.7.1"
name = "github.com/linode/linodego"
version = "0.10.0"
[[constraint]]
branch = "v2"
name = "gopkg.in/ns1/ns1-go.v2"
branch = "v2"
[[constraint]]
version = "1.21.1"
name = "github.com/sacloud/libsacloud"
version = "1.25.1"
[[constraint]]
version = "v5.8.2"
name = "github.com/transip/gotransip"
version = "5.14"
[[constraint]]
version = "0.17.1"
name = "github.com/exoscale/egoscale"
version = "0.18.1"
[[constraint]]
version = "v0.7.4"
name = "github.com/akamai/AkamaiOPEN-edgegrid-golang"
version = "0.7.4"
[[constraint]]
version = "5.4.0"
name = "github.com/oracle/oci-go-sdk"
version = "5.13.0"
[[constraint]]
name = "github.com/labbsr0x/bindman-dns-webhook"
version = "1.0.0"
[[constraint]]
name = "github.com/Azure/azure-sdk-for-go"
version = "31.0.0"
[[constraint]]
name = "github.com/aliyun/alibaba-cloud-sdk-go"
version = "1.60.57"
[[constraint]]
name = "github.com/cloudflare/cloudflare-go"
version = "0.9.2"
[[constraint]]
name = "github.com/cpu/goacmedns"
branch = "master"

View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View file

@ -0,0 +1,38 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
import (
"math/rand"
"time"
)
var randSrc = rand.New(rand.NewSource(time.Now().UnixNano()))
// retries function fn upto n times, if fn returns an error lest it returns nil early.
// It applies exponential backoff in units of (1<<n) + jitter microsends.
func nTriesWithExponentialBackoff(nTries int64, timeBaseUnit time.Duration, fn func() error) (err error) {
for i := int64(0); i < nTries; i++ {
err = fn()
if err == nil {
return nil
}
// Backoff for a time period with a pseudo-random jitter
jitter := time.Duration(randSrc.Float64()*100) * time.Microsecond
ts := jitter + ((1 << uint64(i)) * timeBaseUnit)
<-time.After(ts)
}
return err
}

View file

@ -0,0 +1,97 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
import (
"math/rand"
"sync/atomic"
"time"
)
const (
sDisconnected int32 = 5 + iota
sConnected
)
func (ae *Exporter) setStateDisconnected() {
atomic.StoreInt32(&ae.connectionState, sDisconnected)
select {
case ae.disconnectedCh <- true:
default:
}
}
func (ae *Exporter) setStateConnected() {
atomic.StoreInt32(&ae.connectionState, sConnected)
}
func (ae *Exporter) connected() bool {
return atomic.LoadInt32(&ae.connectionState) == sConnected
}
const defaultConnReattemptPeriod = 10 * time.Second
func (ae *Exporter) indefiniteBackgroundConnection() error {
defer func() {
ae.backgroundConnectionDoneCh <- true
}()
connReattemptPeriod := ae.reconnectionPeriod
if connReattemptPeriod <= 0 {
connReattemptPeriod = defaultConnReattemptPeriod
}
// No strong seeding required, nano time can
// already help with pseudo uniqueness.
rng := rand.New(rand.NewSource(time.Now().UnixNano() + rand.Int63n(1024)))
// maxJitter: 1 + (70% of the connectionReattemptPeriod)
maxJitter := int64(1 + 0.7*float64(connReattemptPeriod))
for {
// Otherwise these will be the normal scenarios to enable
// reconnections if we trip out.
// 1. If we've stopped, return entirely
// 2. Otherwise block until we are disconnected, and
// then retry connecting
select {
case <-ae.stopCh:
return errStopped
case <-ae.disconnectedCh:
// Normal scenario that we'll wait for
}
if err := ae.connect(); err == nil {
ae.setStateConnected()
} else {
ae.setStateDisconnected()
}
// Apply some jitter to avoid lockstep retrials of other
// agent-exporters. Lockstep retrials could result in an
// innocent DDOS, by clogging the machine's resources and network.
jitter := time.Duration(rng.Int63n(maxJitter))
<-time.After(connReattemptPeriod + jitter)
}
}
func (ae *Exporter) connect() error {
cc, err := ae.dialToAgent()
if err != nil {
return err
}
return ae.enableConnectionStreams(cc)
}

View file

@ -0,0 +1,46 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
import (
"os"
commonpb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1"
"go.opencensus.io"
)
// NodeWithStartTime creates a node using nodeName and derives:
// Hostname from the environment
// Pid from the current process
// StartTimestamp from the start time of this process
// Language and library information.
func NodeWithStartTime(nodeName string) *commonpb.Node {
return &commonpb.Node{
Identifier: &commonpb.ProcessIdentifier{
HostName: os.Getenv("HOSTNAME"),
Pid: uint32(os.Getpid()),
StartTimestamp: timeToTimestamp(startTime),
},
LibraryInfo: &commonpb.LibraryInfo{
Language: commonpb.LibraryInfo_GO_LANG,
ExporterVersion: Version,
CoreLibraryVersion: opencensus.Version(),
},
ServiceInfo: &commonpb.ServiceInfo{
Name: nodeName,
},
Attributes: make(map[string]string),
}
}

View file

@ -0,0 +1,496 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
import (
"context"
"errors"
"fmt"
"sync"
"time"
"google.golang.org/api/support/bundler"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/resource"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
commonpb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1"
agentmetricspb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1"
agenttracepb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1"
metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1"
resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
)
var startupMu sync.Mutex
var startTime time.Time
func init() {
startupMu.Lock()
startTime = time.Now()
startupMu.Unlock()
}
var _ trace.Exporter = (*Exporter)(nil)
var _ view.Exporter = (*Exporter)(nil)
type Exporter struct {
connectionState int32
// mu protects the non-atomic and non-channel variables
mu sync.RWMutex
// senderMu protects the concurrent unsafe traceExporter client
senderMu sync.RWMutex
started bool
stopped bool
agentAddress string
serviceName string
canDialInsecure bool
traceExporter agenttracepb.TraceService_ExportClient
metricsExporter agentmetricspb.MetricsService_ExportClient
nodeInfo *commonpb.Node
grpcClientConn *grpc.ClientConn
reconnectionPeriod time.Duration
resource *resourcepb.Resource
compressor string
headers map[string]string
startOnce sync.Once
stopCh chan bool
disconnectedCh chan bool
backgroundConnectionDoneCh chan bool
traceBundler *bundler.Bundler
// viewDataBundler is the bundler to enable conversion
// from OpenCensus-Go view.Data to metricspb.Metric.
// Please do not confuse it with metricsBundler!
viewDataBundler *bundler.Bundler
clientTransportCredentials credentials.TransportCredentials
}
func NewExporter(opts ...ExporterOption) (*Exporter, error) {
exp, err := NewUnstartedExporter(opts...)
if err != nil {
return nil, err
}
if err := exp.Start(); err != nil {
return nil, err
}
return exp, nil
}
const spanDataBufferSize = 300
func NewUnstartedExporter(opts ...ExporterOption) (*Exporter, error) {
e := new(Exporter)
for _, opt := range opts {
opt.withExporter(e)
}
traceBundler := bundler.NewBundler((*trace.SpanData)(nil), func(bundle interface{}) {
e.uploadTraces(bundle.([]*trace.SpanData))
})
traceBundler.DelayThreshold = 2 * time.Second
traceBundler.BundleCountThreshold = spanDataBufferSize
e.traceBundler = traceBundler
viewDataBundler := bundler.NewBundler((*view.Data)(nil), func(bundle interface{}) {
e.uploadViewData(bundle.([]*view.Data))
})
viewDataBundler.DelayThreshold = 2 * time.Second
viewDataBundler.BundleCountThreshold = 500 // TODO: (@odeke-em) make this configurable.
e.viewDataBundler = viewDataBundler
e.nodeInfo = NodeWithStartTime(e.serviceName)
e.resource = resourceProtoFromEnv()
return e, nil
}
const (
maxInitialConfigRetries = 10
maxInitialTracesRetries = 10
)
var (
errAlreadyStarted = errors.New("already started")
errNotStarted = errors.New("not started")
errStopped = errors.New("stopped")
errNoConnection = errors.New("no active connection")
)
// Start dials to the agent, establishing a connection to it. It also
// initiates the Config and Trace services by sending over the initial
// messages that consist of the node identifier. Start invokes a background
// connector that will reattempt connections to the agent periodically
// if the connection dies.
func (ae *Exporter) Start() error {
var err = errAlreadyStarted
ae.startOnce.Do(func() {
ae.mu.Lock()
defer ae.mu.Unlock()
ae.started = true
ae.disconnectedCh = make(chan bool, 1)
ae.stopCh = make(chan bool)
ae.backgroundConnectionDoneCh = make(chan bool)
ae.setStateDisconnected()
go ae.indefiniteBackgroundConnection()
err = nil
})
return err
}
func (ae *Exporter) prepareAgentAddress() string {
if ae.agentAddress != "" {
return ae.agentAddress
}
return fmt.Sprintf("%s:%d", DefaultAgentHost, DefaultAgentPort)
}
func (ae *Exporter) enableConnectionStreams(cc *grpc.ClientConn) error {
ae.mu.RLock()
started := ae.started
nodeInfo := ae.nodeInfo
ae.mu.RUnlock()
if !started {
return errNotStarted
}
ae.mu.Lock()
// If the previous clientConn was non-nil, close it
if ae.grpcClientConn != nil {
_ = ae.grpcClientConn.Close()
}
ae.grpcClientConn = cc
ae.mu.Unlock()
if err := ae.createTraceServiceConnection(ae.grpcClientConn, nodeInfo); err != nil {
return err
}
return ae.createMetricsServiceConnection(ae.grpcClientConn, nodeInfo)
}
func (ae *Exporter) createTraceServiceConnection(cc *grpc.ClientConn, node *commonpb.Node) error {
// Initiate the trace service by sending over node identifier info.
traceSvcClient := agenttracepb.NewTraceServiceClient(cc)
ctx := context.Background()
if len(ae.headers) > 0 {
ctx = metadata.NewOutgoingContext(ctx, metadata.New(ae.headers))
}
traceExporter, err := traceSvcClient.Export(ctx)
if err != nil {
return fmt.Errorf("Exporter.Start:: TraceServiceClient: %v", err)
}
firstTraceMessage := &agenttracepb.ExportTraceServiceRequest{
Node: node,
Resource: ae.resource,
}
if err := traceExporter.Send(firstTraceMessage); err != nil {
return fmt.Errorf("Exporter.Start:: Failed to initiate the Config service: %v", err)
}
ae.mu.Lock()
ae.traceExporter = traceExporter
ae.mu.Unlock()
// Initiate the config service by sending over node identifier info.
configStream, err := traceSvcClient.Config(context.Background())
if err != nil {
return fmt.Errorf("Exporter.Start:: ConfigStream: %v", err)
}
firstCfgMessage := &agenttracepb.CurrentLibraryConfig{Node: node}
if err := configStream.Send(firstCfgMessage); err != nil {
return fmt.Errorf("Exporter.Start:: Failed to initiate the Config service: %v", err)
}
// In the background, handle trace configurations that are beamed down
// by the agent, but also reply to it with the applied configuration.
go ae.handleConfigStreaming(configStream)
return nil
}
func (ae *Exporter) createMetricsServiceConnection(cc *grpc.ClientConn, node *commonpb.Node) error {
metricsSvcClient := agentmetricspb.NewMetricsServiceClient(cc)
metricsExporter, err := metricsSvcClient.Export(context.Background())
if err != nil {
return fmt.Errorf("MetricsExporter: failed to start the service client: %v", err)
}
// Initiate the metrics service by sending over the first message just containing the Node and Resource.
firstMetricsMessage := &agentmetricspb.ExportMetricsServiceRequest{
Node: node,
Resource: ae.resource,
}
if err := metricsExporter.Send(firstMetricsMessage); err != nil {
return fmt.Errorf("MetricsExporter:: failed to send the first message: %v", err)
}
ae.mu.Lock()
ae.metricsExporter = metricsExporter
ae.mu.Unlock()
// With that we are good to go and can start sending metrics
return nil
}
func (ae *Exporter) dialToAgent() (*grpc.ClientConn, error) {
addr := ae.prepareAgentAddress()
var dialOpts []grpc.DialOption
if ae.clientTransportCredentials != nil {
dialOpts = append(dialOpts, grpc.WithTransportCredentials(ae.clientTransportCredentials))
} else if ae.canDialInsecure {
dialOpts = append(dialOpts, grpc.WithInsecure())
}
if ae.compressor != "" {
dialOpts = append(dialOpts, grpc.WithDefaultCallOptions(grpc.UseCompressor(ae.compressor)))
}
dialOpts = append(dialOpts, grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
ctx := context.Background()
if len(ae.headers) > 0 {
ctx = metadata.NewOutgoingContext(ctx, metadata.New(ae.headers))
}
return grpc.DialContext(ctx, addr, dialOpts...)
}
func (ae *Exporter) handleConfigStreaming(configStream agenttracepb.TraceService_ConfigClient) error {
// Note: We haven't yet implemented configuration sending so we
// should NOT be changing connection states within this function for now.
for {
recv, err := configStream.Recv()
if err != nil {
// TODO: Check if this is a transient error or exponential backoff-able.
return err
}
cfg := recv.Config
if cfg == nil {
continue
}
// Otherwise now apply the trace configuration sent down from the agent
if psamp := cfg.GetProbabilitySampler(); psamp != nil {
trace.ApplyConfig(trace.Config{DefaultSampler: trace.ProbabilitySampler(psamp.SamplingProbability)})
} else if csamp := cfg.GetConstantSampler(); csamp != nil {
alwaysSample := csamp.Decision == tracepb.ConstantSampler_ALWAYS_ON
if alwaysSample {
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
} else {
trace.ApplyConfig(trace.Config{DefaultSampler: trace.NeverSample()})
}
} else { // TODO: Add the rate limiting sampler here
}
// Then finally send back to upstream the newly applied configuration
err = configStream.Send(&agenttracepb.CurrentLibraryConfig{Config: &tracepb.TraceConfig{Sampler: cfg.Sampler}})
if err != nil {
return err
}
}
}
// Stop shuts down all the connections and resources
// related to the exporter.
func (ae *Exporter) Stop() error {
ae.mu.RLock()
cc := ae.grpcClientConn
started := ae.started
stopped := ae.stopped
ae.mu.RUnlock()
if !started {
return errNotStarted
}
if stopped {
// TODO: tell the user that we've already stopped, so perhaps a sentinel error?
return nil
}
ae.Flush()
// Now close the underlying gRPC connection.
var err error
if cc != nil {
err = cc.Close()
}
// At this point we can change the state variables: started and stopped
ae.mu.Lock()
ae.started = false
ae.stopped = true
ae.mu.Unlock()
close(ae.stopCh)
// Ensure that the backgroundConnector returns
<-ae.backgroundConnectionDoneCh
return err
}
func (ae *Exporter) ExportSpan(sd *trace.SpanData) {
if sd == nil {
return
}
_ = ae.traceBundler.Add(sd, 1)
}
func (ae *Exporter) ExportTraceServiceRequest(batch *agenttracepb.ExportTraceServiceRequest) error {
if batch == nil || len(batch.Spans) == 0 {
return nil
}
select {
case <-ae.stopCh:
return errStopped
default:
if !ae.connected() {
return errNoConnection
}
ae.senderMu.Lock()
err := ae.traceExporter.Send(batch)
ae.senderMu.Unlock()
if err != nil {
ae.setStateDisconnected()
return err
}
return nil
}
}
func (ae *Exporter) ExportView(vd *view.Data) {
if vd == nil {
return
}
_ = ae.viewDataBundler.Add(vd, 1)
}
func ocSpanDataToPbSpans(sdl []*trace.SpanData) []*tracepb.Span {
if len(sdl) == 0 {
return nil
}
protoSpans := make([]*tracepb.Span, 0, len(sdl))
for _, sd := range sdl {
if sd != nil {
protoSpans = append(protoSpans, ocSpanToProtoSpan(sd))
}
}
return protoSpans
}
func (ae *Exporter) uploadTraces(sdl []*trace.SpanData) {
select {
case <-ae.stopCh:
return
default:
if !ae.connected() {
return
}
protoSpans := ocSpanDataToPbSpans(sdl)
if len(protoSpans) == 0 {
return
}
ae.senderMu.Lock()
err := ae.traceExporter.Send(&agenttracepb.ExportTraceServiceRequest{
Spans: protoSpans,
})
ae.senderMu.Unlock()
if err != nil {
ae.setStateDisconnected()
}
}
}
func ocViewDataToPbMetrics(vdl []*view.Data) []*metricspb.Metric {
if len(vdl) == 0 {
return nil
}
metrics := make([]*metricspb.Metric, 0, len(vdl))
for _, vd := range vdl {
if vd != nil {
vmetric, err := viewDataToMetric(vd)
// TODO: (@odeke-em) somehow report this error, if it is non-nil.
if err == nil && vmetric != nil {
metrics = append(metrics, vmetric)
}
}
}
return metrics
}
func (ae *Exporter) uploadViewData(vdl []*view.Data) {
select {
case <-ae.stopCh:
return
default:
if !ae.connected() {
return
}
protoMetrics := ocViewDataToPbMetrics(vdl)
if len(protoMetrics) == 0 {
return
}
err := ae.metricsExporter.Send(&agentmetricspb.ExportMetricsServiceRequest{
Metrics: protoMetrics,
// TODO:(@odeke-em)
// a) Figure out how to derive a Node from the environment
// b) Figure out how to derive a Resource from the environment
// or better letting users of the exporter configure it.
})
if err != nil {
ae.setStateDisconnected()
}
}
}
func (ae *Exporter) Flush() {
ae.traceBundler.Flush()
ae.viewDataBundler.Flush()
}
func resourceProtoFromEnv() *resourcepb.Resource {
rs, _ := resource.FromEnv(context.Background())
if rs == nil {
return nil
}
rprs := &resourcepb.Resource{
Type: rs.Type,
}
if rs.Labels != nil {
rprs.Labels = make(map[string]string)
for k, v := range rs.Labels {
rprs.Labels[k] = v
}
}
return rprs
}

View file

@ -0,0 +1,128 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
import (
"time"
"google.golang.org/grpc/credentials"
)
const (
DefaultAgentPort uint16 = 55678
DefaultAgentHost string = "localhost"
)
type ExporterOption interface {
withExporter(e *Exporter)
}
type insecureGrpcConnection int
var _ ExporterOption = (*insecureGrpcConnection)(nil)
func (igc *insecureGrpcConnection) withExporter(e *Exporter) {
e.canDialInsecure = true
}
// WithInsecure disables client transport security for the exporter's gRPC connection
// just like grpc.WithInsecure() https://godoc.org/google.golang.org/grpc#WithInsecure
// does. Note, by default, client security is required unless WithInsecure is used.
func WithInsecure() ExporterOption { return new(insecureGrpcConnection) }
type addressSetter string
func (as addressSetter) withExporter(e *Exporter) {
e.agentAddress = string(as)
}
var _ ExporterOption = (*addressSetter)(nil)
// WithAddress allows one to set the address that the exporter will
// connect to the agent on. If unset, it will instead try to use
// connect to DefaultAgentHost:DefaultAgentPort
func WithAddress(addr string) ExporterOption {
return addressSetter(addr)
}
type serviceNameSetter string
func (sns serviceNameSetter) withExporter(e *Exporter) {
e.serviceName = string(sns)
}
var _ ExporterOption = (*serviceNameSetter)(nil)
// WithServiceName allows one to set/override the service name
// that the exporter will report to the agent.
func WithServiceName(serviceName string) ExporterOption {
return serviceNameSetter(serviceName)
}
type reconnectionPeriod time.Duration
func (rp reconnectionPeriod) withExporter(e *Exporter) {
e.reconnectionPeriod = time.Duration(rp)
}
func WithReconnectionPeriod(rp time.Duration) ExporterOption {
return reconnectionPeriod(rp)
}
type compressorSetter string
func (c compressorSetter) withExporter(e *Exporter) {
e.compressor = string(c)
}
// UseCompressor will set the compressor for the gRPC client to use when sending requests.
// It is the responsibility of the caller to ensure that the compressor set has been registered
// with google.golang.org/grpc/encoding. This can be done by encoding.RegisterCompressor. Some
// compressors auto-register on import, such as gzip, which can be registered by calling
// `import _ "google.golang.org/grpc/encoding/gzip"`
func UseCompressor(compressorName string) ExporterOption {
return compressorSetter(compressorName)
}
type headerSetter map[string]string
func (h headerSetter) withExporter(e *Exporter) {
e.headers = map[string]string(h)
}
// WithHeaders will send the provided headers when the gRPC stream connection
// is instantiated
func WithHeaders(headers map[string]string) ExporterOption {
return headerSetter(headers)
}
type clientCredentials struct {
credentials.TransportCredentials
}
var _ ExporterOption = (*clientCredentials)(nil)
// WithTLSCredentials allows the connection to use TLS credentials
// when talking to the server. It takes in grpc.TransportCredentials instead
// of say a Certificate file or a tls.Certificate, because the retrieving
// these credentials can be done in many ways e.g. plain file, in code tls.Config
// or by certificate rotation, so it is up to the caller to decide what to use.
func WithTLSCredentials(creds credentials.TransportCredentials) ExporterOption {
return &clientCredentials{TransportCredentials: creds}
}
func (cc *clientCredentials) withExporter(e *Exporter) {
e.clientTransportCredentials = cc.TransportCredentials
}

View file

@ -0,0 +1,248 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
import (
"math"
"time"
"go.opencensus.io/trace"
"go.opencensus.io/trace/tracestate"
tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
"github.com/golang/protobuf/ptypes/timestamp"
)
const (
maxAnnotationEventsPerSpan = 32
maxMessageEventsPerSpan = 128
)
func ocSpanToProtoSpan(sd *trace.SpanData) *tracepb.Span {
if sd == nil {
return nil
}
var namePtr *tracepb.TruncatableString
if sd.Name != "" {
namePtr = &tracepb.TruncatableString{Value: sd.Name}
}
return &tracepb.Span{
TraceId: sd.TraceID[:],
SpanId: sd.SpanID[:],
ParentSpanId: sd.ParentSpanID[:],
Status: ocStatusToProtoStatus(sd.Status),
StartTime: timeToTimestamp(sd.StartTime),
EndTime: timeToTimestamp(sd.EndTime),
Links: ocLinksToProtoLinks(sd.Links),
Kind: ocSpanKindToProtoSpanKind(sd.SpanKind),
Name: namePtr,
Attributes: ocAttributesToProtoAttributes(sd.Attributes),
TimeEvents: ocTimeEventsToProtoTimeEvents(sd.Annotations, sd.MessageEvents),
Tracestate: ocTracestateToProtoTracestate(sd.Tracestate),
}
}
var blankStatus trace.Status
func ocStatusToProtoStatus(status trace.Status) *tracepb.Status {
if status == blankStatus {
return nil
}
return &tracepb.Status{
Code: status.Code,
Message: status.Message,
}
}
func ocLinksToProtoLinks(links []trace.Link) *tracepb.Span_Links {
if len(links) == 0 {
return nil
}
sl := make([]*tracepb.Span_Link, 0, len(links))
for _, ocLink := range links {
// This redefinition is necessary to prevent ocLink.*ID[:] copies
// being reused -- in short we need a new ocLink per iteration.
ocLink := ocLink
sl = append(sl, &tracepb.Span_Link{
TraceId: ocLink.TraceID[:],
SpanId: ocLink.SpanID[:],
Type: ocLinkTypeToProtoLinkType(ocLink.Type),
})
}
return &tracepb.Span_Links{
Link: sl,
}
}
func ocLinkTypeToProtoLinkType(oct trace.LinkType) tracepb.Span_Link_Type {
switch oct {
case trace.LinkTypeChild:
return tracepb.Span_Link_CHILD_LINKED_SPAN
case trace.LinkTypeParent:
return tracepb.Span_Link_PARENT_LINKED_SPAN
default:
return tracepb.Span_Link_TYPE_UNSPECIFIED
}
}
func ocAttributesToProtoAttributes(attrs map[string]interface{}) *tracepb.Span_Attributes {
if len(attrs) == 0 {
return nil
}
outMap := make(map[string]*tracepb.AttributeValue)
for k, v := range attrs {
switch v := v.(type) {
case bool:
outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_BoolValue{BoolValue: v}}
case int:
outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_IntValue{IntValue: int64(v)}}
case int64:
outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_IntValue{IntValue: v}}
case string:
outMap[k] = &tracepb.AttributeValue{
Value: &tracepb.AttributeValue_StringValue{
StringValue: &tracepb.TruncatableString{Value: v},
},
}
}
}
return &tracepb.Span_Attributes{
AttributeMap: outMap,
}
}
// This code is mostly copied from
// https://github.com/census-ecosystem/opencensus-go-exporter-stackdriver/blob/master/trace_proto.go#L46
func ocTimeEventsToProtoTimeEvents(as []trace.Annotation, es []trace.MessageEvent) *tracepb.Span_TimeEvents {
if len(as) == 0 && len(es) == 0 {
return nil
}
timeEvents := &tracepb.Span_TimeEvents{}
var annotations, droppedAnnotationsCount int
var messageEvents, droppedMessageEventsCount int
// Transform annotations
for i, a := range as {
if annotations >= maxAnnotationEventsPerSpan {
droppedAnnotationsCount = len(as) - i
break
}
annotations++
timeEvents.TimeEvent = append(timeEvents.TimeEvent,
&tracepb.Span_TimeEvent{
Time: timeToTimestamp(a.Time),
Value: transformAnnotationToTimeEvent(&a),
},
)
}
// Transform message events
for i, e := range es {
if messageEvents >= maxMessageEventsPerSpan {
droppedMessageEventsCount = len(es) - i
break
}
messageEvents++
timeEvents.TimeEvent = append(timeEvents.TimeEvent,
&tracepb.Span_TimeEvent{
Time: timeToTimestamp(e.Time),
Value: transformMessageEventToTimeEvent(&e),
},
)
}
// Process dropped counter
timeEvents.DroppedAnnotationsCount = clip32(droppedAnnotationsCount)
timeEvents.DroppedMessageEventsCount = clip32(droppedMessageEventsCount)
return timeEvents
}
func transformAnnotationToTimeEvent(a *trace.Annotation) *tracepb.Span_TimeEvent_Annotation_ {
return &tracepb.Span_TimeEvent_Annotation_{
Annotation: &tracepb.Span_TimeEvent_Annotation{
Description: &tracepb.TruncatableString{Value: a.Message},
Attributes: ocAttributesToProtoAttributes(a.Attributes),
},
}
}
func transformMessageEventToTimeEvent(e *trace.MessageEvent) *tracepb.Span_TimeEvent_MessageEvent_ {
return &tracepb.Span_TimeEvent_MessageEvent_{
MessageEvent: &tracepb.Span_TimeEvent_MessageEvent{
Type: tracepb.Span_TimeEvent_MessageEvent_Type(e.EventType),
Id: uint64(e.MessageID),
UncompressedSize: uint64(e.UncompressedByteSize),
CompressedSize: uint64(e.CompressedByteSize),
},
}
}
// clip32 clips an int to the range of an int32.
func clip32(x int) int32 {
if x < math.MinInt32 {
return math.MinInt32
}
if x > math.MaxInt32 {
return math.MaxInt32
}
return int32(x)
}
func timeToTimestamp(t time.Time) *timestamp.Timestamp {
nanoTime := t.UnixNano()
return &timestamp.Timestamp{
Seconds: nanoTime / 1e9,
Nanos: int32(nanoTime % 1e9),
}
}
func ocSpanKindToProtoSpanKind(kind int) tracepb.Span_SpanKind {
switch kind {
case trace.SpanKindClient:
return tracepb.Span_CLIENT
case trace.SpanKindServer:
return tracepb.Span_SERVER
default:
return tracepb.Span_SPAN_KIND_UNSPECIFIED
}
}
func ocTracestateToProtoTracestate(ts *tracestate.Tracestate) *tracepb.Span_Tracestate {
if ts == nil {
return nil
}
return &tracepb.Span_Tracestate{
Entries: ocTracestateEntriesToProtoTracestateEntries(ts.Entries()),
}
}
func ocTracestateEntriesToProtoTracestateEntries(entries []tracestate.Entry) []*tracepb.Span_Tracestate_Entry {
protoEntries := make([]*tracepb.Span_Tracestate_Entry, 0, len(entries))
for _, entry := range entries {
protoEntries = append(protoEntries, &tracepb.Span_Tracestate_Entry{
Key: entry.Key,
Value: entry.Value,
})
}
return protoEntries
}

View file

@ -0,0 +1,274 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
import (
"errors"
"time"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
"github.com/golang/protobuf/ptypes/timestamp"
metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1"
)
var (
errNilMeasure = errors.New("expecting a non-nil stats.Measure")
errNilView = errors.New("expecting a non-nil view.View")
errNilViewData = errors.New("expecting a non-nil view.Data")
)
func viewDataToMetric(vd *view.Data) (*metricspb.Metric, error) {
if vd == nil {
return nil, errNilViewData
}
descriptor, err := viewToMetricDescriptor(vd.View)
if err != nil {
return nil, err
}
timeseries, err := viewDataToTimeseries(vd)
if err != nil {
return nil, err
}
metric := &metricspb.Metric{
MetricDescriptor: descriptor,
Timeseries: timeseries,
}
return metric, nil
}
func viewToMetricDescriptor(v *view.View) (*metricspb.MetricDescriptor, error) {
if v == nil {
return nil, errNilView
}
if v.Measure == nil {
return nil, errNilMeasure
}
desc := &metricspb.MetricDescriptor{
Name: stringOrCall(v.Name, v.Measure.Name),
Description: stringOrCall(v.Description, v.Measure.Description),
Unit: v.Measure.Unit(),
Type: aggregationToMetricDescriptorType(v),
LabelKeys: tagKeysToLabelKeys(v.TagKeys),
}
return desc, nil
}
func stringOrCall(first string, call func() string) string {
if first != "" {
return first
}
return call()
}
type measureType uint
const (
measureUnknown measureType = iota
measureInt64
measureFloat64
)
func measureTypeFromMeasure(m stats.Measure) measureType {
switch m.(type) {
default:
return measureUnknown
case *stats.Float64Measure:
return measureFloat64
case *stats.Int64Measure:
return measureInt64
}
}
func aggregationToMetricDescriptorType(v *view.View) metricspb.MetricDescriptor_Type {
if v == nil || v.Aggregation == nil {
return metricspb.MetricDescriptor_UNSPECIFIED
}
if v.Measure == nil {
return metricspb.MetricDescriptor_UNSPECIFIED
}
switch v.Aggregation.Type {
case view.AggTypeCount:
// Cumulative on int64
return metricspb.MetricDescriptor_CUMULATIVE_INT64
case view.AggTypeDistribution:
// Cumulative types
return metricspb.MetricDescriptor_CUMULATIVE_DISTRIBUTION
case view.AggTypeLastValue:
// Gauge types
switch measureTypeFromMeasure(v.Measure) {
case measureFloat64:
return metricspb.MetricDescriptor_GAUGE_DOUBLE
case measureInt64:
return metricspb.MetricDescriptor_GAUGE_INT64
}
case view.AggTypeSum:
// Cumulative types
switch measureTypeFromMeasure(v.Measure) {
case measureFloat64:
return metricspb.MetricDescriptor_CUMULATIVE_DOUBLE
case measureInt64:
return metricspb.MetricDescriptor_CUMULATIVE_INT64
}
}
// For all other cases, return unspecified.
return metricspb.MetricDescriptor_UNSPECIFIED
}
func tagKeysToLabelKeys(tagKeys []tag.Key) []*metricspb.LabelKey {
labelKeys := make([]*metricspb.LabelKey, 0, len(tagKeys))
for _, tagKey := range tagKeys {
labelKeys = append(labelKeys, &metricspb.LabelKey{
Key: tagKey.Name(),
})
}
return labelKeys
}
func viewDataToTimeseries(vd *view.Data) ([]*metricspb.TimeSeries, error) {
if vd == nil || len(vd.Rows) == 0 {
return nil, nil
}
// Given that view.Data only contains Start, End
// the timestamps for all the row data will be the exact same
// per aggregation. However, the values will differ.
// Each row has its own tags.
startTimestamp := timeToProtoTimestamp(vd.Start)
endTimestamp := timeToProtoTimestamp(vd.End)
mType := measureTypeFromMeasure(vd.View.Measure)
timeseries := make([]*metricspb.TimeSeries, 0, len(vd.Rows))
// It is imperative that the ordering of "LabelValues" matches those
// of the Label keys in the metric descriptor.
for _, row := range vd.Rows {
labelValues := labelValuesFromTags(row.Tags)
point := rowToPoint(vd.View, row, endTimestamp, mType)
timeseries = append(timeseries, &metricspb.TimeSeries{
StartTimestamp: startTimestamp,
LabelValues: labelValues,
Points: []*metricspb.Point{point},
})
}
if len(timeseries) == 0 {
return nil, nil
}
return timeseries, nil
}
func timeToProtoTimestamp(t time.Time) *timestamp.Timestamp {
unixNano := t.UnixNano()
return &timestamp.Timestamp{
Seconds: int64(unixNano / 1e9),
Nanos: int32(unixNano % 1e9),
}
}
func rowToPoint(v *view.View, row *view.Row, endTimestamp *timestamp.Timestamp, mType measureType) *metricspb.Point {
pt := &metricspb.Point{
Timestamp: endTimestamp,
}
switch data := row.Data.(type) {
case *view.CountData:
pt.Value = &metricspb.Point_Int64Value{Int64Value: data.Value}
case *view.DistributionData:
pt.Value = &metricspb.Point_DistributionValue{
DistributionValue: &metricspb.DistributionValue{
Count: data.Count,
Sum: float64(data.Count) * data.Mean, // because Mean := Sum/Count
// TODO: Add Exemplar
Buckets: bucketsToProtoBuckets(data.CountPerBucket),
BucketOptions: &metricspb.DistributionValue_BucketOptions{
Type: &metricspb.DistributionValue_BucketOptions_Explicit_{
Explicit: &metricspb.DistributionValue_BucketOptions_Explicit{
Bounds: v.Aggregation.Buckets,
},
},
},
SumOfSquaredDeviation: data.SumOfSquaredDev,
}}
case *view.LastValueData:
setPointValue(pt, data.Value, mType)
case *view.SumData:
setPointValue(pt, data.Value, mType)
}
return pt
}
// Not returning anything from this function because metricspb.Point.is_Value is an unexported
// interface hence we just have to set its value by pointer.
func setPointValue(pt *metricspb.Point, value float64, mType measureType) {
if mType == measureInt64 {
pt.Value = &metricspb.Point_Int64Value{Int64Value: int64(value)}
} else {
pt.Value = &metricspb.Point_DoubleValue{DoubleValue: value}
}
}
func bucketsToProtoBuckets(countPerBucket []int64) []*metricspb.DistributionValue_Bucket {
distBuckets := make([]*metricspb.DistributionValue_Bucket, len(countPerBucket))
for i := 0; i < len(countPerBucket); i++ {
count := countPerBucket[i]
distBuckets[i] = &metricspb.DistributionValue_Bucket{
Count: count,
}
}
return distBuckets
}
func labelValuesFromTags(tags []tag.Tag) []*metricspb.LabelValue {
if len(tags) == 0 {
return nil
}
labelValues := make([]*metricspb.LabelValue, 0, len(tags))
for _, tag_ := range tags {
labelValues = append(labelValues, &metricspb.LabelValue{
Value: tag_.Value,
// It is imperative that we set the "HasValue" attribute,
// in order to distinguish missing a label from the empty string.
// https://godoc.org/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1#LabelValue.HasValue
//
// OpenCensus-Go uses non-pointers for tags as seen by this function's arguments,
// so the best case that we can use to distinguish missing labels/tags from the
// empty string is by checking if the Tag.Key.Name() != "" to indicate that we have
// a value.
HasValue: tag_.Key.Name() != "",
})
}
return labelValues
}

View file

@ -0,0 +1,17 @@
// Copyright 2018, OpenCensus Authors
//
// 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.
package ocagent
const Version = "0.0.1"

View file

@ -18,13 +18,18 @@ package dns
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"context"
"encoding/json"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
"github.com/Azure/go-autorest/tracing"
"net/http"
)
// The package's fully qualified name.
const fqdn = "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns"
// RecordType enumerates the values for record type.
type RecordType string
@ -68,6 +73,18 @@ type ARecord struct {
Ipv4Address *string `json:"ipv4Address,omitempty"`
}
// AzureEntityResource the resource model definition for a Azure Resource Manager resource with an etag.
type AzureEntityResource struct {
// Etag - READ-ONLY; Resource Etag.
Etag *string `json:"etag,omitempty"`
// ID - READ-ONLY; Fully qualified resource Id for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}
ID *string `json:"id,omitempty"`
// Name - READ-ONLY; The name of the resource
Name *string `json:"name,omitempty"`
// Type - READ-ONLY; The type of the resource. Ex- Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts.
Type *string `json:"type,omitempty"`
}
// CaaRecord a CAA record.
type CaaRecord struct {
// Flags - The flags for this CAA record as an integer between 0 and 255.
@ -116,6 +133,17 @@ type NsRecord struct {
Nsdname *string `json:"nsdname,omitempty"`
}
// ProxyResource the resource model definition for a ARM proxy resource. It will have everything other than
// required location and tags
type ProxyResource struct {
// ID - READ-ONLY; Fully qualified resource Id for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}
ID *string `json:"id,omitempty"`
// Name - READ-ONLY; The name of the resource
Name *string `json:"name,omitempty"`
// Type - READ-ONLY; The type of the resource. Ex- Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts.
Type *string `json:"type,omitempty"`
}
// PtrRecord a PTR record.
type PtrRecord struct {
// Ptrdname - The PTR target domain name for this PTR record.
@ -125,11 +153,11 @@ type PtrRecord struct {
// RecordSet describes a DNS record set (a collection of DNS records with the same name and type).
type RecordSet struct {
autorest.Response `json:"-"`
// ID - The ID of the record set.
// ID - READ-ONLY; The ID of the record set.
ID *string `json:"id,omitempty"`
// Name - The name of the record set.
// Name - READ-ONLY; The name of the record set.
Name *string `json:"name,omitempty"`
// Type - The type of the record set.
// Type - READ-ONLY; The type of the record set.
Type *string `json:"type,omitempty"`
// Etag - The etag of the record set.
Etag *string `json:"etag,omitempty"`
@ -140,15 +168,6 @@ type RecordSet struct {
// MarshalJSON is the custom marshaler for RecordSet.
func (rs RecordSet) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if rs.ID != nil {
objectMap["id"] = rs.ID
}
if rs.Name != nil {
objectMap["name"] = rs.Name
}
if rs.Type != nil {
objectMap["type"] = rs.Type
}
if rs.Etag != nil {
objectMap["etag"] = rs.Etag
}
@ -223,7 +242,7 @@ type RecordSetListResult struct {
autorest.Response `json:"-"`
// Value - Information about the record sets in the response.
Value *[]RecordSet `json:"value,omitempty"`
// NextLink - The continuation token for the next page of results.
// NextLink - READ-ONLY; The continuation token for the next page of results.
NextLink *string `json:"nextLink,omitempty"`
}
@ -233,14 +252,24 @@ type RecordSetListResultIterator struct {
page RecordSetListResultPage
}
// Next advances to the next value. If there was an error making
// NextWithContext advances to the next value. If there was an error making
// the request the iterator does not advance and the error is returned.
func (iter *RecordSetListResultIterator) Next() error {
func (iter *RecordSetListResultIterator) NextWithContext(ctx context.Context) (err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetListResultIterator.NextWithContext")
defer func() {
sc := -1
if iter.Response().Response.Response != nil {
sc = iter.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
iter.i++
if iter.i < len(iter.page.Values()) {
return nil
}
err := iter.page.Next()
err = iter.page.NextWithContext(ctx)
if err != nil {
iter.i--
return err
@ -249,6 +278,13 @@ func (iter *RecordSetListResultIterator) Next() error {
return nil
}
// Next advances to the next value. If there was an error making
// the request the iterator does not advance and the error is returned.
// Deprecated: Use NextWithContext() instead.
func (iter *RecordSetListResultIterator) Next() error {
return iter.NextWithContext(context.Background())
}
// NotDone returns true if the enumeration should be started or is not yet complete.
func (iter RecordSetListResultIterator) NotDone() bool {
return iter.page.NotDone() && iter.i < len(iter.page.Values())
@ -268,6 +304,11 @@ func (iter RecordSetListResultIterator) Value() RecordSet {
return iter.page.Values()[iter.i]
}
// Creates a new instance of the RecordSetListResultIterator type.
func NewRecordSetListResultIterator(page RecordSetListResultPage) RecordSetListResultIterator {
return RecordSetListResultIterator{page: page}
}
// IsEmpty returns true if the ListResult contains no values.
func (rslr RecordSetListResult) IsEmpty() bool {
return rslr.Value == nil || len(*rslr.Value) == 0
@ -275,11 +316,11 @@ func (rslr RecordSetListResult) IsEmpty() bool {
// recordSetListResultPreparer prepares a request to retrieve the next set of results.
// It returns nil if no more results exist.
func (rslr RecordSetListResult) recordSetListResultPreparer() (*http.Request, error) {
func (rslr RecordSetListResult) recordSetListResultPreparer(ctx context.Context) (*http.Request, error) {
if rslr.NextLink == nil || len(to.String(rslr.NextLink)) < 1 {
return nil, nil
}
return autorest.Prepare(&http.Request{},
return autorest.Prepare((&http.Request{}).WithContext(ctx),
autorest.AsJSON(),
autorest.AsGet(),
autorest.WithBaseURL(to.String(rslr.NextLink)))
@ -287,14 +328,24 @@ func (rslr RecordSetListResult) recordSetListResultPreparer() (*http.Request, er
// RecordSetListResultPage contains a page of RecordSet values.
type RecordSetListResultPage struct {
fn func(RecordSetListResult) (RecordSetListResult, error)
fn func(context.Context, RecordSetListResult) (RecordSetListResult, error)
rslr RecordSetListResult
}
// Next advances to the next page of values. If there was an error making
// NextWithContext advances to the next page of values. If there was an error making
// the request the page does not advance and the error is returned.
func (page *RecordSetListResultPage) Next() error {
next, err := page.fn(page.rslr)
func (page *RecordSetListResultPage) NextWithContext(ctx context.Context) (err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetListResultPage.NextWithContext")
defer func() {
sc := -1
if page.Response().Response.Response != nil {
sc = page.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
next, err := page.fn(ctx, page.rslr)
if err != nil {
return err
}
@ -302,6 +353,13 @@ func (page *RecordSetListResultPage) Next() error {
return nil
}
// Next advances to the next page of values. If there was an error making
// the request the page does not advance and the error is returned.
// Deprecated: Use NextWithContext() instead.
func (page *RecordSetListResultPage) Next() error {
return page.NextWithContext(context.Background())
}
// NotDone returns true if the page enumeration should be started or is not yet complete.
func (page RecordSetListResultPage) NotDone() bool {
return !page.rslr.IsEmpty()
@ -320,13 +378,18 @@ func (page RecordSetListResultPage) Values() []RecordSet {
return *page.rslr.Value
}
// Creates a new instance of the RecordSetListResultPage type.
func NewRecordSetListResultPage(getNextPage func(context.Context, RecordSetListResult) (RecordSetListResult, error)) RecordSetListResultPage {
return RecordSetListResultPage{fn: getNextPage}
}
// RecordSetProperties represents the properties of the records in the record set.
type RecordSetProperties struct {
// Metadata - The metadata attached to the record set.
Metadata map[string]*string `json:"metadata"`
// TTL - The TTL (time-to-live) of the records in the record set.
TTL *int64 `json:"TTL,omitempty"`
// Fqdn - Fully qualified domain name of the record set.
// Fqdn - READ-ONLY; Fully qualified domain name of the record set.
Fqdn *string `json:"fqdn,omitempty"`
// ARecords - The list of A records in the record set.
ARecords *[]ARecord `json:"ARecords,omitempty"`
@ -359,9 +422,6 @@ func (rsp RecordSetProperties) MarshalJSON() ([]byte, error) {
if rsp.TTL != nil {
objectMap["TTL"] = rsp.TTL
}
if rsp.Fqdn != nil {
objectMap["fqdn"] = rsp.Fqdn
}
if rsp.ARecords != nil {
objectMap["ARecords"] = rsp.ARecords
}
@ -401,39 +461,14 @@ type RecordSetUpdateParameters struct {
RecordSet *RecordSet `json:"RecordSet,omitempty"`
}
// Resource common properties of an Azure Resource Manager resource
// Resource ...
type Resource struct {
// ID - Resource ID.
// ID - READ-ONLY; Fully qualified resource Id for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}
ID *string `json:"id,omitempty"`
// Name - Resource name.
// Name - READ-ONLY; The name of the resource
Name *string `json:"name,omitempty"`
// Type - Resource type.
// Type - READ-ONLY; The type of the resource. Ex- Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts.
Type *string `json:"type,omitempty"`
// Location - Resource location.
Location *string `json:"location,omitempty"`
// Tags - Resource tags.
Tags map[string]*string `json:"tags"`
}
// MarshalJSON is the custom marshaler for Resource.
func (r Resource) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if r.ID != nil {
objectMap["id"] = r.ID
}
if r.Name != nil {
objectMap["name"] = r.Name
}
if r.Type != nil {
objectMap["type"] = r.Type
}
if r.Location != nil {
objectMap["location"] = r.Location
}
if r.Tags != nil {
objectMap["tags"] = r.Tags
}
return json.Marshal(objectMap)
}
// SoaRecord an SOA record.
@ -472,6 +507,32 @@ type SubResource struct {
ID *string `json:"id,omitempty"`
}
// TrackedResource the resource model definition for a ARM tracked top level resource
type TrackedResource struct {
// Tags - Resource tags.
Tags map[string]*string `json:"tags"`
// Location - The geo-location where the resource lives
Location *string `json:"location,omitempty"`
// ID - READ-ONLY; Fully qualified resource Id for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}
ID *string `json:"id,omitempty"`
// Name - READ-ONLY; The name of the resource
Name *string `json:"name,omitempty"`
// Type - READ-ONLY; The type of the resource. Ex- Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts.
Type *string `json:"type,omitempty"`
}
// MarshalJSON is the custom marshaler for TrackedResource.
func (tr TrackedResource) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if tr.Tags != nil {
objectMap["tags"] = tr.Tags
}
if tr.Location != nil {
objectMap["location"] = tr.Location
}
return json.Marshal(objectMap)
}
// TxtRecord a TXT record.
type TxtRecord struct {
// Value - The text value of this TXT record.
@ -485,16 +546,16 @@ type Zone struct {
Etag *string `json:"etag,omitempty"`
// ZoneProperties - The properties of the zone.
*ZoneProperties `json:"properties,omitempty"`
// ID - Resource ID.
ID *string `json:"id,omitempty"`
// Name - Resource name.
Name *string `json:"name,omitempty"`
// Type - Resource type.
Type *string `json:"type,omitempty"`
// Location - Resource location.
Location *string `json:"location,omitempty"`
// Tags - Resource tags.
Tags map[string]*string `json:"tags"`
// Location - The geo-location where the resource lives
Location *string `json:"location,omitempty"`
// ID - READ-ONLY; Fully qualified resource Id for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}
ID *string `json:"id,omitempty"`
// Name - READ-ONLY; The name of the resource
Name *string `json:"name,omitempty"`
// Type - READ-ONLY; The type of the resource. Ex- Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts.
Type *string `json:"type,omitempty"`
}
// MarshalJSON is the custom marshaler for Zone.
@ -506,21 +567,12 @@ func (z Zone) MarshalJSON() ([]byte, error) {
if z.ZoneProperties != nil {
objectMap["properties"] = z.ZoneProperties
}
if z.ID != nil {
objectMap["id"] = z.ID
}
if z.Name != nil {
objectMap["name"] = z.Name
}
if z.Type != nil {
objectMap["type"] = z.Type
if z.Tags != nil {
objectMap["tags"] = z.Tags
}
if z.Location != nil {
objectMap["location"] = z.Location
}
if z.Tags != nil {
objectMap["tags"] = z.Tags
}
return json.Marshal(objectMap)
}
@ -551,6 +603,24 @@ func (z *Zone) UnmarshalJSON(body []byte) error {
}
z.ZoneProperties = &zoneProperties
}
case "tags":
if v != nil {
var tags map[string]*string
err = json.Unmarshal(*v, &tags)
if err != nil {
return err
}
z.Tags = tags
}
case "location":
if v != nil {
var location string
err = json.Unmarshal(*v, &location)
if err != nil {
return err
}
z.Location = &location
}
case "id":
if v != nil {
var ID string
@ -578,24 +648,6 @@ func (z *Zone) UnmarshalJSON(body []byte) error {
}
z.Type = &typeVar
}
case "location":
if v != nil {
var location string
err = json.Unmarshal(*v, &location)
if err != nil {
return err
}
z.Location = &location
}
case "tags":
if v != nil {
var tags map[string]*string
err = json.Unmarshal(*v, &tags)
if err != nil {
return err
}
z.Tags = tags
}
}
}
@ -607,7 +659,7 @@ type ZoneListResult struct {
autorest.Response `json:"-"`
// Value - Information about the DNS zones.
Value *[]Zone `json:"value,omitempty"`
// NextLink - The continuation token for the next page of results.
// NextLink - READ-ONLY; The continuation token for the next page of results.
NextLink *string `json:"nextLink,omitempty"`
}
@ -617,14 +669,24 @@ type ZoneListResultIterator struct {
page ZoneListResultPage
}
// Next advances to the next value. If there was an error making
// NextWithContext advances to the next value. If there was an error making
// the request the iterator does not advance and the error is returned.
func (iter *ZoneListResultIterator) Next() error {
func (iter *ZoneListResultIterator) NextWithContext(ctx context.Context) (err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZoneListResultIterator.NextWithContext")
defer func() {
sc := -1
if iter.Response().Response.Response != nil {
sc = iter.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
iter.i++
if iter.i < len(iter.page.Values()) {
return nil
}
err := iter.page.Next()
err = iter.page.NextWithContext(ctx)
if err != nil {
iter.i--
return err
@ -633,6 +695,13 @@ func (iter *ZoneListResultIterator) Next() error {
return nil
}
// Next advances to the next value. If there was an error making
// the request the iterator does not advance and the error is returned.
// Deprecated: Use NextWithContext() instead.
func (iter *ZoneListResultIterator) Next() error {
return iter.NextWithContext(context.Background())
}
// NotDone returns true if the enumeration should be started or is not yet complete.
func (iter ZoneListResultIterator) NotDone() bool {
return iter.page.NotDone() && iter.i < len(iter.page.Values())
@ -652,6 +721,11 @@ func (iter ZoneListResultIterator) Value() Zone {
return iter.page.Values()[iter.i]
}
// Creates a new instance of the ZoneListResultIterator type.
func NewZoneListResultIterator(page ZoneListResultPage) ZoneListResultIterator {
return ZoneListResultIterator{page: page}
}
// IsEmpty returns true if the ListResult contains no values.
func (zlr ZoneListResult) IsEmpty() bool {
return zlr.Value == nil || len(*zlr.Value) == 0
@ -659,11 +733,11 @@ func (zlr ZoneListResult) IsEmpty() bool {
// zoneListResultPreparer prepares a request to retrieve the next set of results.
// It returns nil if no more results exist.
func (zlr ZoneListResult) zoneListResultPreparer() (*http.Request, error) {
func (zlr ZoneListResult) zoneListResultPreparer(ctx context.Context) (*http.Request, error) {
if zlr.NextLink == nil || len(to.String(zlr.NextLink)) < 1 {
return nil, nil
}
return autorest.Prepare(&http.Request{},
return autorest.Prepare((&http.Request{}).WithContext(ctx),
autorest.AsJSON(),
autorest.AsGet(),
autorest.WithBaseURL(to.String(zlr.NextLink)))
@ -671,14 +745,24 @@ func (zlr ZoneListResult) zoneListResultPreparer() (*http.Request, error) {
// ZoneListResultPage contains a page of Zone values.
type ZoneListResultPage struct {
fn func(ZoneListResult) (ZoneListResult, error)
fn func(context.Context, ZoneListResult) (ZoneListResult, error)
zlr ZoneListResult
}
// Next advances to the next page of values. If there was an error making
// NextWithContext advances to the next page of values. If there was an error making
// the request the page does not advance and the error is returned.
func (page *ZoneListResultPage) Next() error {
next, err := page.fn(page.zlr)
func (page *ZoneListResultPage) NextWithContext(ctx context.Context) (err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZoneListResultPage.NextWithContext")
defer func() {
sc := -1
if page.Response().Response.Response != nil {
sc = page.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
next, err := page.fn(ctx, page.zlr)
if err != nil {
return err
}
@ -686,6 +770,13 @@ func (page *ZoneListResultPage) Next() error {
return nil
}
// Next advances to the next page of values. If there was an error making
// the request the page does not advance and the error is returned.
// Deprecated: Use NextWithContext() instead.
func (page *ZoneListResultPage) Next() error {
return page.NextWithContext(context.Background())
}
// NotDone returns true if the page enumeration should be started or is not yet complete.
func (page ZoneListResultPage) NotDone() bool {
return !page.zlr.IsEmpty()
@ -704,13 +795,18 @@ func (page ZoneListResultPage) Values() []Zone {
return *page.zlr.Value
}
// Creates a new instance of the ZoneListResultPage type.
func NewZoneListResultPage(getNextPage func(context.Context, ZoneListResult) (ZoneListResult, error)) ZoneListResultPage {
return ZoneListResultPage{fn: getNextPage}
}
// ZoneProperties represents the properties of the zone.
type ZoneProperties struct {
// MaxNumberOfRecordSets - The maximum number of record sets that can be created in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
// MaxNumberOfRecordSets - READ-ONLY; The maximum number of record sets that can be created in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
MaxNumberOfRecordSets *int64 `json:"maxNumberOfRecordSets,omitempty"`
// NumberOfRecordSets - The current number of record sets in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
// NumberOfRecordSets - READ-ONLY; The current number of record sets in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
NumberOfRecordSets *int64 `json:"numberOfRecordSets,omitempty"`
// NameServers - The name servers for this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
// NameServers - READ-ONLY; The name servers for this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
NameServers *[]string `json:"nameServers,omitempty"`
}
@ -723,7 +819,7 @@ type ZonesDeleteFuture struct {
// If the operation has not completed it will return an error.
func (future *ZonesDeleteFuture) Result(client ZonesClient) (ar autorest.Response, err error) {
var done bool
done, err = future.Done(client)
done, err = future.DoneWithContext(context.Background(), client)
if err != nil {
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", future.Response(), "Polling failure")
return

View file

@ -22,6 +22,7 @@ import (
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/validation"
"github.com/Azure/go-autorest/tracing"
"net/http"
)
@ -49,15 +50,27 @@ func NewRecordSetsClientWithBaseURI(baseURI string, subscriptionID string) Recor
// created (they are created when the DNS zone is created).
// parameters - parameters supplied to the CreateOrUpdate operation.
// ifMatch - the etag of the record set. Omit this value to always overwrite the current record set. Specify
// the last-seen etag value to prevent accidentally overwritting any concurrent changes.
// the last-seen etag value to prevent accidentally overwriting any concurrent changes.
// ifNoneMatch - set to '*' to allow a new record set to be created, but to prevent updating an existing record
// set. Other values will be ignored.
func (client RecordSetsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string, ifNoneMatch string) (result RecordSet, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.CreateOrUpdate")
defer func() {
sc := -1
if result.Response.Response != nil {
sc = result.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.RecordSetsClient", "CreateOrUpdate", err.Error())
}
@ -97,6 +110,9 @@ func (client RecordSetsClient) CreateOrUpdatePreparer(ctx context.Context, resou
"api-version": APIVersion,
}
parameters.ID = nil
parameters.Name = nil
parameters.Type = nil
preparer := autorest.CreatePreparer(
autorest.AsContentType("application/json; charset=utf-8"),
autorest.AsPut(),
@ -145,11 +161,23 @@ func (client RecordSetsClient) CreateOrUpdateResponder(resp *http.Response) (res
// ifMatch - the etag of the record set. Omit this value to always delete the current record set. Specify the
// last-seen etag value to prevent accidentally deleting any concurrent changes.
func (client RecordSetsClient) Delete(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, ifMatch string) (result autorest.Response, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.Delete")
defer func() {
sc := -1
if result.Response != nil {
sc = result.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.RecordSetsClient", "Delete", err.Error())
}
@ -227,11 +255,23 @@ func (client RecordSetsClient) DeleteResponder(resp *http.Response) (result auto
// relativeRecordSetName - the name of the record set, relative to the name of the zone.
// recordType - the type of DNS record in this record set.
func (client RecordSetsClient) Get(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType) (result RecordSet, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.Get")
defer func() {
sc := -1
if result.Response.Response != nil {
sc = result.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.RecordSetsClient", "Get", err.Error())
}
@ -308,11 +348,23 @@ func (client RecordSetsClient) GetResponder(resp *http.Response) (result RecordS
// enumerations. If this parameter is specified, Enumeration will return only records that end with
// .<recordSetNameSuffix>
func (client RecordSetsClient) ListByDNSZone(ctx context.Context, resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string) (result RecordSetListResultPage, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.ListByDNSZone")
defer func() {
sc := -1
if result.rslr.Response.Response != nil {
sc = result.rslr.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.RecordSetsClient", "ListByDNSZone", err.Error())
}
@ -386,8 +438,8 @@ func (client RecordSetsClient) ListByDNSZoneResponder(resp *http.Response) (resu
}
// listByDNSZoneNextResults retrieves the next set of results, if any.
func (client RecordSetsClient) listByDNSZoneNextResults(lastResults RecordSetListResult) (result RecordSetListResult, err error) {
req, err := lastResults.recordSetListResultPreparer()
func (client RecordSetsClient) listByDNSZoneNextResults(ctx context.Context, lastResults RecordSetListResult) (result RecordSetListResult, err error) {
req, err := lastResults.recordSetListResultPreparer(ctx)
if err != nil {
return result, autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByDNSZoneNextResults", nil, "Failure preparing next results request")
}
@ -408,6 +460,16 @@ func (client RecordSetsClient) listByDNSZoneNextResults(lastResults RecordSetLis
// ListByDNSZoneComplete enumerates all values, automatically crossing page boundaries as required.
func (client RecordSetsClient) ListByDNSZoneComplete(ctx context.Context, resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string) (result RecordSetListResultIterator, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.ListByDNSZone")
defer func() {
sc := -1
if result.Response().Response.Response != nil {
sc = result.page.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
result.page, err = client.ListByDNSZone(ctx, resourceGroupName, zoneName, top, recordsetnamesuffix)
return
}
@ -422,11 +484,23 @@ func (client RecordSetsClient) ListByDNSZoneComplete(ctx context.Context, resour
// enumerations. If this parameter is specified, Enumeration will return only records that end with
// .<recordSetNameSuffix>
func (client RecordSetsClient) ListByType(ctx context.Context, resourceGroupName string, zoneName string, recordType RecordType, top *int32, recordsetnamesuffix string) (result RecordSetListResultPage, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.ListByType")
defer func() {
sc := -1
if result.rslr.Response.Response != nil {
sc = result.rslr.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.RecordSetsClient", "ListByType", err.Error())
}
@ -501,8 +575,8 @@ func (client RecordSetsClient) ListByTypeResponder(resp *http.Response) (result
}
// listByTypeNextResults retrieves the next set of results, if any.
func (client RecordSetsClient) listByTypeNextResults(lastResults RecordSetListResult) (result RecordSetListResult, err error) {
req, err := lastResults.recordSetListResultPreparer()
func (client RecordSetsClient) listByTypeNextResults(ctx context.Context, lastResults RecordSetListResult) (result RecordSetListResult, err error) {
req, err := lastResults.recordSetListResultPreparer(ctx)
if err != nil {
return result, autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByTypeNextResults", nil, "Failure preparing next results request")
}
@ -523,6 +597,16 @@ func (client RecordSetsClient) listByTypeNextResults(lastResults RecordSetListRe
// ListByTypeComplete enumerates all values, automatically crossing page boundaries as required.
func (client RecordSetsClient) ListByTypeComplete(ctx context.Context, resourceGroupName string, zoneName string, recordType RecordType, top *int32, recordsetnamesuffix string) (result RecordSetListResultIterator, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.ListByType")
defer func() {
sc := -1
if result.Response().Response.Response != nil {
sc = result.page.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
result.page, err = client.ListByType(ctx, resourceGroupName, zoneName, recordType, top, recordsetnamesuffix)
return
}
@ -535,13 +619,25 @@ func (client RecordSetsClient) ListByTypeComplete(ctx context.Context, resourceG
// recordType - the type of DNS record in this record set.
// parameters - parameters supplied to the Update operation.
// ifMatch - the etag of the record set. Omit this value to always overwrite the current record set. Specify
// the last-seen etag value to prevent accidentally overwritting concurrent changes.
// the last-seen etag value to prevent accidentally overwriting concurrent changes.
func (client RecordSetsClient) Update(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string) (result RecordSet, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/RecordSetsClient.Update")
defer func() {
sc := -1
if result.Response.Response != nil {
sc = result.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.RecordSetsClient", "Update", err.Error())
}
@ -581,6 +677,9 @@ func (client RecordSetsClient) UpdatePreparer(ctx context.Context, resourceGroup
"api-version": APIVersion,
}
parameters.ID = nil
parameters.Name = nil
parameters.Type = nil
preparer := autorest.CreatePreparer(
autorest.AsContentType("application/json; charset=utf-8"),
autorest.AsPatch(),

View file

@ -22,6 +22,7 @@ import (
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/validation"
"github.com/Azure/go-autorest/tracing"
"net/http"
)
@ -46,15 +47,27 @@ func NewZonesClientWithBaseURI(baseURI string, subscriptionID string) ZonesClien
// zoneName - the name of the DNS zone (without a terminating dot).
// parameters - parameters supplied to the CreateOrUpdate operation.
// ifMatch - the etag of the DNS zone. Omit this value to always overwrite the current zone. Specify the
// last-seen etag value to prevent accidentally overwritting any concurrent changes.
// last-seen etag value to prevent accidentally overwriting any concurrent changes.
// ifNoneMatch - set to '*' to allow a new DNS zone to be created, but to prevent updating an existing zone.
// Other values will be ignored.
func (client ZonesClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, zoneName string, parameters Zone, ifMatch string, ifNoneMatch string) (result Zone, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZonesClient.CreateOrUpdate")
defer func() {
sc := -1
if result.Response.Response != nil {
sc = result.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.ZonesClient", "CreateOrUpdate", err.Error())
}
@ -138,11 +151,23 @@ func (client ZonesClient) CreateOrUpdateResponder(resp *http.Response) (result Z
// ifMatch - the etag of the DNS zone. Omit this value to always delete the current zone. Specify the last-seen
// etag value to prevent accidentally deleting any concurrent changes.
func (client ZonesClient) Delete(ctx context.Context, resourceGroupName string, zoneName string, ifMatch string) (result ZonesDeleteFuture, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZonesClient.Delete")
defer func() {
sc := -1
if result.Response() != nil {
sc = result.Response().StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.ZonesClient", "Delete", err.Error())
}
@ -195,10 +220,6 @@ func (client ZonesClient) DeleteSender(req *http.Request) (future ZonesDeleteFut
if err != nil {
return
}
err = autorest.Respond(resp, azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent))
if err != nil {
return
}
future.Future, err = azure.NewFutureFromResponse(resp)
return
}
@ -220,11 +241,23 @@ func (client ZonesClient) DeleteResponder(resp *http.Response) (result autorest.
// resourceGroupName - the name of the resource group. The name is case insensitive.
// zoneName - the name of the DNS zone (without a terminating dot).
func (client ZonesClient) Get(ctx context.Context, resourceGroupName string, zoneName string) (result Zone, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZonesClient.Get")
defer func() {
sc := -1
if result.Response.Response != nil {
sc = result.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.ZonesClient", "Get", err.Error())
}
@ -294,6 +327,22 @@ func (client ZonesClient) GetResponder(resp *http.Response) (result Zone, err er
// Parameters:
// top - the maximum number of DNS zones to return. If not specified, returns up to 100 zones.
func (client ZonesClient) List(ctx context.Context, top *int32) (result ZoneListResultPage, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZonesClient.List")
defer func() {
sc := -1
if result.zlr.Response.Response != nil {
sc = result.zlr.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.ZonesClient", "List", err.Error())
}
result.fn = client.listNextResults
req, err := client.ListPreparer(ctx, top)
if err != nil {
@ -359,8 +408,8 @@ func (client ZonesClient) ListResponder(resp *http.Response) (result ZoneListRes
}
// listNextResults retrieves the next set of results, if any.
func (client ZonesClient) listNextResults(lastResults ZoneListResult) (result ZoneListResult, err error) {
req, err := lastResults.zoneListResultPreparer()
func (client ZonesClient) listNextResults(ctx context.Context, lastResults ZoneListResult) (result ZoneListResult, err error) {
req, err := lastResults.zoneListResultPreparer(ctx)
if err != nil {
return result, autorest.NewErrorWithError(err, "dns.ZonesClient", "listNextResults", nil, "Failure preparing next results request")
}
@ -381,6 +430,16 @@ func (client ZonesClient) listNextResults(lastResults ZoneListResult) (result Zo
// ListComplete enumerates all values, automatically crossing page boundaries as required.
func (client ZonesClient) ListComplete(ctx context.Context, top *int32) (result ZoneListResultIterator, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZonesClient.List")
defer func() {
sc := -1
if result.Response().Response.Response != nil {
sc = result.page.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
result.page, err = client.List(ctx, top)
return
}
@ -390,11 +449,23 @@ func (client ZonesClient) ListComplete(ctx context.Context, top *int32) (result
// resourceGroupName - the name of the resource group. The name is case insensitive.
// top - the maximum number of record sets to return. If not specified, returns up to 100 record sets.
func (client ZonesClient) ListByResourceGroup(ctx context.Context, resourceGroupName string, top *int32) (result ZoneListResultPage, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZonesClient.ListByResourceGroup")
defer func() {
sc := -1
if result.zlr.Response.Response != nil {
sc = result.zlr.Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
if err := validation.Validate([]validation.Validation{
{TargetValue: resourceGroupName,
Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil},
{Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil},
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil {
{Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}},
{TargetValue: client.SubscriptionID,
Constraints: []validation.Constraint{{Target: "client.SubscriptionID", Name: validation.MinLength, Rule: 1, Chain: nil}}}}); err != nil {
return result, validation.NewError("dns.ZonesClient", "ListByResourceGroup", err.Error())
}
@ -464,8 +535,8 @@ func (client ZonesClient) ListByResourceGroupResponder(resp *http.Response) (res
}
// listByResourceGroupNextResults retrieves the next set of results, if any.
func (client ZonesClient) listByResourceGroupNextResults(lastResults ZoneListResult) (result ZoneListResult, err error) {
req, err := lastResults.zoneListResultPreparer()
func (client ZonesClient) listByResourceGroupNextResults(ctx context.Context, lastResults ZoneListResult) (result ZoneListResult, err error) {
req, err := lastResults.zoneListResultPreparer(ctx)
if err != nil {
return result, autorest.NewErrorWithError(err, "dns.ZonesClient", "listByResourceGroupNextResults", nil, "Failure preparing next results request")
}
@ -486,6 +557,16 @@ func (client ZonesClient) listByResourceGroupNextResults(lastResults ZoneListRes
// ListByResourceGroupComplete enumerates all values, automatically crossing page boundaries as required.
func (client ZonesClient) ListByResourceGroupComplete(ctx context.Context, resourceGroupName string, top *int32) (result ZoneListResultIterator, err error) {
if tracing.IsEnabled() {
ctx = tracing.StartSpan(ctx, fqdn+"/ZonesClient.ListByResourceGroup")
defer func() {
sc := -1
if result.Response().Response.Response != nil {
sc = result.page.Response().Response.Response.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
}
result.page, err = client.ListByResourceGroup(ctx, resourceGroupName, top)
return
}

View file

@ -18,4 +18,4 @@ package version
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// Number contains the semantic version of this SDK.
const Number = "v19.1.0"
const Number = "v31.0.0"

View file

@ -19,10 +19,6 @@ import (
"net/url"
)
const (
activeDirectoryAPIVersion = "1.0"
)
// OAuthConfig represents the endpoints needed
// in OAuth operations
type OAuthConfig struct {
@ -46,11 +42,25 @@ func validateStringParam(param, name string) error {
// NewOAuthConfig returns an OAuthConfig with tenant specific urls
func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
apiVer := "1.0"
return NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, tenantID, &apiVer)
}
// NewOAuthConfigWithAPIVersion returns an OAuthConfig with tenant specific urls.
// If apiVersion is not nil the "api-version" query parameter will be appended to the endpoint URLs with the specified value.
func NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, tenantID string, apiVersion *string) (*OAuthConfig, error) {
if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil {
return nil, err
}
api := ""
// it's legal for tenantID to be empty so don't validate it
const activeDirectoryEndpointTemplate = "%s/oauth2/%s?api-version=%s"
if apiVersion != nil {
if err := validateStringParam(*apiVersion, "apiVersion"); err != nil {
return nil, err
}
api = fmt.Sprintf("?api-version=%s", *apiVersion)
}
const activeDirectoryEndpointTemplate = "%s/oauth2/%s%s"
u, err := url.Parse(activeDirectoryEndpoint)
if err != nil {
return nil, err
@ -59,15 +69,15 @@ func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, err
if err != nil {
return nil, err
}
authorizeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "authorize", activeDirectoryAPIVersion))
authorizeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "authorize", api))
if err != nil {
return nil, err
}
tokenURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "token", activeDirectoryAPIVersion))
tokenURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "token", api))
if err != nil {
return nil, err
}
deviceCodeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "devicecode", activeDirectoryAPIVersion))
deviceCodeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "devicecode", api))
if err != nil {
return nil, err
}

View file

@ -38,7 +38,7 @@ func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
return sf(r)
}
// SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the
// SendDecorator takes and possibly decorates, by wrapping, a Sender. Decorators may affect the
// http.Request and pass it along or, first, pass the http.Request along then react to the
// http.Response result.
type SendDecorator func(Sender) Sender

View file

@ -29,13 +29,12 @@ import (
"net"
"net/http"
"net/url"
"strconv"
"strings"
"sync"
"time"
"github.com/Azure/go-autorest/autorest/date"
"github.com/Azure/go-autorest/version"
"github.com/Azure/go-autorest/tracing"
"github.com/dgrijalva/jwt-go"
)
@ -97,18 +96,27 @@ type RefresherWithContext interface {
type TokenRefreshCallback func(Token) error
// Token encapsulates the access token used to authorize Azure requests.
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow#service-to-service-access-token-response
type Token struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn string `json:"expires_in"`
ExpiresOn string `json:"expires_on"`
NotBefore string `json:"not_before"`
ExpiresIn json.Number `json:"expires_in"`
ExpiresOn json.Number `json:"expires_on"`
NotBefore json.Number `json:"not_before"`
Resource string `json:"resource"`
Type string `json:"token_type"`
}
func newToken() Token {
return Token{
ExpiresIn: "0",
ExpiresOn: "0",
NotBefore: "0",
}
}
// IsZero returns true if the token object is zero-initialized.
func (t Token) IsZero() bool {
return t == Token{}
@ -116,12 +124,12 @@ func (t Token) IsZero() bool {
// Expires returns the time.Time when the Token expires.
func (t Token) Expires() time.Time {
s, err := strconv.Atoi(t.ExpiresOn)
s, err := t.ExpiresOn.Float64()
if err != nil {
s = -3600
}
expiration := date.NewUnixTimeFromSeconds(float64(s))
expiration := date.NewUnixTimeFromSeconds(s)
return time.Time(expiration).UTC()
}
@ -218,6 +226,8 @@ func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalTo
token := jwt.New(jwt.SigningMethodRS256)
token.Header["x5t"] = thumbprint
x5c := []string{base64.StdEncoding.EncodeToString(secret.Certificate.Raw)}
token.Header["x5c"] = x5c
token.Claims = jwt.MapClaims{
"aud": spt.inner.OauthConfig.TokenEndpoint.String(),
"iss": spt.inner.ClientID,
@ -375,8 +385,13 @@ func (spt *ServicePrincipalToken) UnmarshalJSON(data []byte) error {
if err != nil {
return err
}
// Don't override the refreshLock or the sender if those have been already set.
if spt.refreshLock == nil {
spt.refreshLock = &sync.RWMutex{}
spt.sender = &http.Client{}
}
if spt.sender == nil {
spt.sender = &http.Client{Transport: tracing.Transport}
}
return nil
}
@ -414,6 +429,7 @@ func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, reso
}
spt := &ServicePrincipalToken{
inner: servicePrincipalToken{
Token: newToken(),
OauthConfig: oauthConfig,
Secret: secret,
ClientID: id,
@ -422,7 +438,7 @@ func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, reso
RefreshWithin: defaultRefresh,
},
refreshLock: &sync.RWMutex{},
sender: &http.Client{},
sender: &http.Client{Transport: tracing.Transport},
refreshCallbacks: callbacks,
}
return spt, nil
@ -653,6 +669,7 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI
spt := &ServicePrincipalToken{
inner: servicePrincipalToken{
Token: newToken(),
OauthConfig: OAuthConfig{
TokenEndpoint: *msiEndpointURL,
},
@ -662,7 +679,7 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI
RefreshWithin: defaultRefresh,
},
refreshLock: &sync.RWMutex{},
sender: &http.Client{},
sender: &http.Client{Transport: tracing.Transport},
refreshCallbacks: callbacks,
MaxMSIRefreshAttempts: defaultMaxMSIRefreshAttempts,
}
@ -779,7 +796,7 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
if err != nil {
return fmt.Errorf("adal: Failed to build the refresh request. Error = '%v'", err)
}
req.Header.Add("User-Agent", version.UserAgent())
req.Header.Add("User-Agent", UserAgent())
req = req.WithContext(ctx)
if !isIMDS(spt.inner.OauthConfig.TokenEndpoint) {
v := url.Values{}

View file

@ -1,4 +1,9 @@
package version
package adal
import (
"fmt"
"runtime"
)
// Copyright 2017 Microsoft Corporation
//
@ -14,24 +19,27 @@ package version
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"fmt"
"runtime"
)
// Number contains the semantic version of this SDK.
const Number = "v10.15.2"
const number = "v1.0.0"
var (
userAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s",
ua = fmt.Sprintf("Go/%s (%s-%s) go-autorest/adal/%s",
runtime.Version(),
runtime.GOARCH,
runtime.GOOS,
Number,
number,
)
)
// UserAgent returns a string containing the Go version, system archityecture and OS, and the go-autorest version.
// UserAgent returns a string containing the Go version, system architecture and OS, and the adal version.
func UserAgent() string {
return userAgent
return ua
}
// AddToUserAgent adds an extension to the current user agent
func AddToUserAgent(extension string) error {
if extension != "" {
ua = fmt.Sprintf("%s %s", ua, extension)
return nil
}
return fmt.Errorf("Extension was empty, User Agent remained as '%s'", ua)
}

View file

@ -15,12 +15,14 @@ package autorest
// limitations under the License.
import (
"encoding/base64"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/tracing"
)
const (
@ -30,6 +32,8 @@ const (
apiKeyAuthorizerHeader = "Ocp-Apim-Subscription-Key"
bingAPISdkHeader = "X-BingApis-SDK-Client"
golangBingAPISdkHeaderValue = "Go-SDK"
authorization = "Authorization"
basic = "Basic"
)
// Authorizer is the interface that provides a PrepareDecorator used to supply request
@ -68,7 +72,7 @@ func NewAPIKeyAuthorizer(headers map[string]interface{}, queryParameters map[str
return &APIKeyAuthorizer{headers: headers, queryParameters: queryParameters}
}
// WithAuthorization returns a PrepareDecorator that adds an HTTP headers and Query Paramaters
// WithAuthorization returns a PrepareDecorator that adds an HTTP headers and Query Parameters.
func (aka *APIKeyAuthorizer) WithAuthorization() PrepareDecorator {
return func(p Preparer) Preparer {
return DecoratePreparer(p, WithHeaders(aka.headers), WithQueryParameters(aka.queryParameters))
@ -147,7 +151,7 @@ type BearerAuthorizerCallback struct {
// is invoked when the HTTP request is submitted.
func NewBearerAuthorizerCallback(sender Sender, callback BearerAuthorizerCallbackFunc) *BearerAuthorizerCallback {
if sender == nil {
sender = &http.Client{}
sender = &http.Client{Transport: tracing.Transport}
}
return &BearerAuthorizerCallback{sender: sender, callback: callback}
}
@ -257,3 +261,27 @@ func (egta EventGridKeyAuthorizer) WithAuthorization() PrepareDecorator {
}
return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
}
// BasicAuthorizer implements basic HTTP authorization by adding the Authorization HTTP header
// with the value "Basic <TOKEN>" where <TOKEN> is a base64-encoded username:password tuple.
type BasicAuthorizer struct {
userName string
password string
}
// NewBasicAuthorizer creates a new BasicAuthorizer with the specified username and password.
func NewBasicAuthorizer(userName, password string) *BasicAuthorizer {
return &BasicAuthorizer{
userName: userName,
password: password,
}
}
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
// value is "Basic " followed by the base64-encoded username:password tuple.
func (ba *BasicAuthorizer) WithAuthorization() PrepareDecorator {
headers := make(map[string]interface{})
headers[authorization] = basic + " " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", ba.userName, ba.password)))
return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
}

View file

@ -26,6 +26,7 @@ import (
"time"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/tracing"
)
const (
@ -44,24 +45,14 @@ var pollingCodes = [...]int{http.StatusNoContent, http.StatusAccepted, http.Stat
// Future provides a mechanism to access the status and results of an asynchronous request.
// Since futures are stateful they should be passed by value to avoid race conditions.
type Future struct {
req *http.Request // legacy
pt pollingTracker
}
// NewFuture returns a new Future object initialized with the specified request.
// Deprecated: Please use NewFutureFromResponse instead.
func NewFuture(req *http.Request) Future {
return Future{req: req}
}
// NewFutureFromResponse returns a new Future object initialized
// with the initial response from an asynchronous operation.
func NewFutureFromResponse(resp *http.Response) (Future, error) {
pt, err := createPollingTracker(resp)
if err != nil {
return Future{}, err
}
return Future{pt: pt}, nil
return Future{pt: pt}, err
}
// Response returns the last HTTP response.
@ -88,29 +79,25 @@ func (f Future) PollingMethod() PollingMethodType {
return f.pt.pollingMethod()
}
// Done queries the service to see if the operation has completed.
func (f *Future) Done(sender autorest.Sender) (bool, error) {
// support for legacy Future implementation
if f.req != nil {
resp, err := sender.Do(f.req)
if err != nil {
return false, err
// DoneWithContext queries the service to see if the operation has completed.
func (f *Future) DoneWithContext(ctx context.Context, sender autorest.Sender) (done bool, err error) {
ctx = tracing.StartSpan(ctx, "github.com/Azure/go-autorest/autorest/azure/async.DoneWithContext")
defer func() {
sc := -1
resp := f.Response()
if resp != nil {
sc = resp.StatusCode
}
pt, err := createPollingTracker(resp)
if err != nil {
return false, err
}
f.pt = pt
f.req = nil
}
// end legacy
tracing.EndSpan(ctx, sc, err)
}()
if f.pt == nil {
return false, autorest.NewError("Future", "Done", "future is not initialized")
}
if f.pt.hasTerminated() {
return true, f.pt.pollingError()
}
if err := f.pt.pollForStatus(sender); err != nil {
if err := f.pt.pollForStatus(ctx, sender); err != nil {
return false, err
}
if err := f.pt.checkForErrors(); err != nil {
@ -119,7 +106,10 @@ func (f *Future) Done(sender autorest.Sender) (bool, error) {
if err := f.pt.updatePollingState(f.pt.provisioningStateApplicable()); err != nil {
return false, err
}
if err := f.pt.updateHeaders(); err != nil {
if err := f.pt.initPollingMethod(); err != nil {
return false, err
}
if err := f.pt.updatePollingMethod(); err != nil {
return false, err
}
return f.pt.hasTerminated(), f.pt.pollingError()
@ -151,24 +141,35 @@ func (f Future) GetPollingDelay() (time.Duration, bool) {
return d, true
}
// WaitForCompletion will return when one of the following conditions is met: the long
// running operation has completed, the provided context is cancelled, or the client's
// polling duration has been exceeded. It will retry failed polling attempts based on
// the retry value defined in the client up to the maximum retry attempts.
// Deprecated: Please use WaitForCompletionRef() instead.
func (f Future) WaitForCompletion(ctx context.Context, client autorest.Client) error {
return f.WaitForCompletionRef(ctx, client)
}
// WaitForCompletionRef will return when one of the following conditions is met: the long
// running operation has completed, the provided context is cancelled, or the client's
// polling duration has been exceeded. It will retry failed polling attempts based on
// the retry value defined in the client up to the maximum retry attempts.
func (f *Future) WaitForCompletionRef(ctx context.Context, client autorest.Client) error {
ctx, cancel := context.WithTimeout(ctx, client.PollingDuration)
// If no deadline is specified in the context then the client.PollingDuration will be
// used to determine if a default deadline should be used.
// If PollingDuration is greater than zero the value will be used as the context's timeout.
// If PollingDuration is zero then no default deadline will be used.
func (f *Future) WaitForCompletionRef(ctx context.Context, client autorest.Client) (err error) {
ctx = tracing.StartSpan(ctx, "github.com/Azure/go-autorest/autorest/azure/async.WaitForCompletionRef")
defer func() {
sc := -1
resp := f.Response()
if resp != nil {
sc = resp.StatusCode
}
tracing.EndSpan(ctx, sc, err)
}()
cancelCtx := ctx
// if the provided context already has a deadline don't override it
_, hasDeadline := ctx.Deadline()
if d := client.PollingDuration; !hasDeadline && d != 0 {
var cancel context.CancelFunc
cancelCtx, cancel = context.WithTimeout(ctx, d)
defer cancel()
done, err := f.Done(client)
for attempts := 0; !done; done, err = f.Done(client) {
}
done, err := f.DoneWithContext(ctx, client)
for attempts := 0; !done; done, err = f.DoneWithContext(ctx, client) {
if attempts >= client.RetryAttempts {
return autorest.NewErrorWithError(err, "Future", "WaitForCompletion", f.pt.latestResponse(), "the number of retries has been exceeded")
}
@ -192,12 +193,12 @@ func (f *Future) WaitForCompletionRef(ctx context.Context, client autorest.Clien
attempts++
}
// wait until the delay elapses or the context is cancelled
delayElapsed := autorest.DelayForBackoff(delay, delayAttempt, ctx.Done())
delayElapsed := autorest.DelayForBackoff(delay, delayAttempt, cancelCtx.Done())
if !delayElapsed {
return autorest.NewErrorWithError(ctx.Err(), "Future", "WaitForCompletion", f.pt.latestResponse(), "context has been cancelled")
return autorest.NewErrorWithError(cancelCtx.Err(), "Future", "WaitForCompletion", f.pt.latestResponse(), "context has been cancelled")
}
}
return err
return
}
// MarshalJSON implements the json.Marshaler interface.
@ -264,7 +265,7 @@ type pollingTracker interface {
// these methods can differ per tracker
// checks the response headers and status code to determine the polling mechanism
updateHeaders() error
updatePollingMethod() error
// checks the response for tracker-specific error conditions
checkForErrors() error
@ -274,11 +275,15 @@ type pollingTracker interface {
// methods common to all trackers
// initializes a tracker's polling URL and method, called for each iteration.
// these values can be overridden by each polling tracker as required.
initPollingMethod() error
// initializes the tracker's internal state, call this when the tracker is created
initializeState() error
// makes an HTTP request to check the status of the LRO
pollForStatus(sender autorest.Sender) error
pollForStatus(ctx context.Context, sender autorest.Sender) error
// updates internal tracker state, call this after each call to pollForStatus
updatePollingState(provStateApl bool) error
@ -370,7 +375,7 @@ func (pt *pollingTrackerBase) initializeState() error {
pt.updateErrorFromResponse()
return pt.pollingError()
}
return nil
return pt.initPollingMethod()
}
func (pt pollingTrackerBase) getProvisioningState() *string {
@ -392,6 +397,10 @@ func (pt *pollingTrackerBase) updateRawBody() error {
if err != nil {
return autorest.NewErrorWithError(err, "pollingTrackerBase", "updateRawBody", nil, "failed to read response body")
}
// observed in 204 responses over HTTP/2.0; the content length is -1 but body is empty
if len(b) == 0 {
return nil
}
// put the body back so it's available to other callers
pt.resp.Body = ioutil.NopCloser(bytes.NewReader(b))
if err = json.Unmarshal(b, &pt.rawBody); err != nil {
@ -401,15 +410,13 @@ func (pt *pollingTrackerBase) updateRawBody() error {
return nil
}
func (pt *pollingTrackerBase) pollForStatus(sender autorest.Sender) error {
func (pt *pollingTrackerBase) pollForStatus(ctx context.Context, sender autorest.Sender) error {
req, err := http.NewRequest(http.MethodGet, pt.URI, nil)
if err != nil {
return autorest.NewErrorWithError(err, "pollingTrackerBase", "pollForStatus", nil, "failed to create HTTP request")
}
// attach the context from the original request if available (it will be absent for deserialized futures)
if pt.resp != nil {
req = req.WithContext(pt.resp.Request.Context())
}
req = req.WithContext(ctx)
pt.resp, err = sender.Do(req)
if err != nil {
return autorest.NewErrorWithError(err, "pollingTrackerBase", "pollForStatus", nil, "failed to send HTTP request")
@ -421,6 +428,7 @@ func (pt *pollingTrackerBase) pollForStatus(sender autorest.Sender) error {
} else {
// check response body for error content
pt.updateErrorFromResponse()
err = pt.pollingError()
}
return err
}
@ -437,7 +445,7 @@ func (pt *pollingTrackerBase) updateErrorFromResponse() {
re := respErr{}
defer pt.resp.Body.Close()
var b []byte
if b, err = ioutil.ReadAll(pt.resp.Body); err != nil {
if b, err = ioutil.ReadAll(pt.resp.Body); err != nil || len(b) == 0 {
goto Default
}
if err = json.Unmarshal(b, &re); err != nil {
@ -552,13 +560,33 @@ func (pt pollingTrackerBase) baseCheckForErrors() error {
return nil
}
// default initialization of polling URL/method. each verb tracker will update this as required.
func (pt *pollingTrackerBase) initPollingMethod() error {
if ao, err := getURLFromAsyncOpHeader(pt.resp); err != nil {
return err
} else if ao != "" {
pt.URI = ao
pt.Pm = PollingAsyncOperation
return nil
}
if lh, err := getURLFromLocationHeader(pt.resp); err != nil {
return err
} else if lh != "" {
pt.URI = lh
pt.Pm = PollingLocation
return nil
}
// it's ok if we didn't find a polling header, this will be handled elsewhere
return nil
}
// DELETE
type pollingTrackerDelete struct {
pollingTrackerBase
}
func (pt *pollingTrackerDelete) updateHeaders() error {
func (pt *pollingTrackerDelete) updatePollingMethod() error {
// for 201 the Location header is required
if pt.resp.StatusCode == http.StatusCreated {
if lh, err := getURLFromLocationHeader(pt.resp); err != nil {
@ -614,7 +642,7 @@ type pollingTrackerPatch struct {
pollingTrackerBase
}
func (pt *pollingTrackerPatch) updateHeaders() error {
func (pt *pollingTrackerPatch) updatePollingMethod() error {
// by default we can use the original URL for polling and final GET
if pt.URI == "" {
pt.URI = pt.resp.Request.URL.String()
@ -635,7 +663,7 @@ func (pt *pollingTrackerPatch) updateHeaders() error {
}
}
// for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary
// note the absense of the "final GET" mechanism for PATCH
// note the absence of the "final GET" mechanism for PATCH
if pt.resp.StatusCode == http.StatusAccepted {
ao, err := getURLFromAsyncOpHeader(pt.resp)
if err != nil {
@ -672,7 +700,7 @@ type pollingTrackerPost struct {
pollingTrackerBase
}
func (pt *pollingTrackerPost) updateHeaders() error {
func (pt *pollingTrackerPost) updatePollingMethod() error {
// 201 requires Location header
if pt.resp.StatusCode == http.StatusCreated {
if lh, err := getURLFromLocationHeader(pt.resp); err != nil {
@ -728,7 +756,7 @@ type pollingTrackerPut struct {
pollingTrackerBase
}
func (pt *pollingTrackerPut) updateHeaders() error {
func (pt *pollingTrackerPut) updatePollingMethod() error {
// by default we can use the original URL for polling and final GET
if pt.URI == "" {
pt.URI = pt.resp.Request.URL.String()
@ -766,8 +794,6 @@ func (pt *pollingTrackerPut) updateHeaders() error {
pt.URI = lh
pt.Pm = PollingLocation
}
// when both headers are returned we use the value in the Location header for the final GET
pt.FinalGetURI = lh
}
// make sure a polling URL was found
if pt.URI == "" {
@ -822,7 +848,7 @@ func createPollingTracker(resp *http.Response) (pollingTracker, error) {
// this initializes the polling header values, we do this during creation in case the
// initial response send us invalid values; this way the API call will return a non-nil
// error (not doing this means the error shows up in Future.Done)
return pt, pt.updateHeaders()
return pt, pt.updatePollingMethod()
}
// gets the polling URL from the Azure-AsyncOperation header.
@ -857,43 +883,6 @@ func isValidURL(s string) bool {
return err == nil && u.IsAbs()
}
// DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure
// long-running operation. It will delay between requests for the duration specified in the
// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled via
// the context associated with the http.Request.
// Deprecated: Prefer using Futures to allow for non-blocking async operations.
func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator {
return func(s autorest.Sender) autorest.Sender {
return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
resp, err := s.Do(r)
if err != nil {
return resp, err
}
if !autorest.ResponseHasStatusCode(resp, pollingCodes[:]...) {
return resp, nil
}
future, err := NewFutureFromResponse(resp)
if err != nil {
return resp, err
}
// retry until either the LRO completes or we receive an error
var done bool
for done, err = future.Done(s); !done && err == nil; done, err = future.Done(s) {
// check for Retry-After delay, if not present use the specified polling delay
if pd, ok := future.GetPollingDelay(); ok {
delay = pd
}
// wait until the delay elapses or the context is cancelled
if delayElapsed := autorest.DelayForBackoff(delay, 0, r.Context().Done()); !delayElapsed {
return future.Response(),
autorest.NewErrorWithError(r.Context().Err(), "azure", "DoPollForAsynchronous", future.Response(), "context has been cancelled")
}
}
return future.Response(), err
})
}
}
// PollingMethodType defines a type used for enumerating polling mechanisms.
type PollingMethodType string

View file

@ -31,26 +31,42 @@ import (
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/azure/cli"
"github.com/dimchansky/utfbom"
"golang.org/x/crypto/pkcs12"
)
// The possible keys in the Values map.
const (
SubscriptionID = "AZURE_SUBSCRIPTION_ID"
TenantID = "AZURE_TENANT_ID"
ClientID = "AZURE_CLIENT_ID"
ClientSecret = "AZURE_CLIENT_SECRET"
CertificatePath = "AZURE_CERTIFICATE_PATH"
CertificatePassword = "AZURE_CERTIFICATE_PASSWORD"
Username = "AZURE_USERNAME"
Password = "AZURE_PASSWORD"
EnvironmentName = "AZURE_ENVIRONMENT"
Resource = "AZURE_AD_RESOURCE"
ActiveDirectoryEndpoint = "ActiveDirectoryEndpoint"
ResourceManagerEndpoint = "ResourceManagerEndpoint"
GraphResourceID = "GraphResourceID"
SQLManagementEndpoint = "SQLManagementEndpoint"
GalleryEndpoint = "GalleryEndpoint"
ManagementEndpoint = "ManagementEndpoint"
)
// NewAuthorizerFromEnvironment creates an Authorizer configured from environment variables in the order:
// 1. Client credentials
// 2. Client certificate
// 3. Username password
// 4. MSI
func NewAuthorizerFromEnvironment() (autorest.Authorizer, error) {
settings, err := getAuthenticationSettings()
settings, err := GetSettingsFromEnvironment()
if err != nil {
return nil, err
}
if settings.resource == "" {
settings.resource = settings.environment.ResourceManagerEndpoint
}
return settings.getAuthorizer()
return settings.GetAuthorizer()
}
// NewAuthorizerFromEnvironmentWithResource creates an Authorizer configured from environment variables in the order:
@ -59,134 +75,364 @@ func NewAuthorizerFromEnvironment() (autorest.Authorizer, error) {
// 3. Username password
// 4. MSI
func NewAuthorizerFromEnvironmentWithResource(resource string) (autorest.Authorizer, error) {
settings, err := getAuthenticationSettings()
settings, err := GetSettingsFromEnvironment()
if err != nil {
return nil, err
}
settings.resource = resource
return settings.getAuthorizer()
settings.Values[Resource] = resource
return settings.GetAuthorizer()
}
type settings struct {
tenantID string
clientID string
clientSecret string
certificatePath string
certificatePassword string
username string
password string
envName string
resource string
environment azure.Environment
// EnvironmentSettings contains the available authentication settings.
type EnvironmentSettings struct {
Values map[string]string
Environment azure.Environment
}
func getAuthenticationSettings() (s settings, err error) {
s = settings{
tenantID: os.Getenv("AZURE_TENANT_ID"),
clientID: os.Getenv("AZURE_CLIENT_ID"),
clientSecret: os.Getenv("AZURE_CLIENT_SECRET"),
certificatePath: os.Getenv("AZURE_CERTIFICATE_PATH"),
certificatePassword: os.Getenv("AZURE_CERTIFICATE_PASSWORD"),
username: os.Getenv("AZURE_USERNAME"),
password: os.Getenv("AZURE_PASSWORD"),
envName: os.Getenv("AZURE_ENVIRONMENT"),
resource: os.Getenv("AZURE_AD_RESOURCE"),
// GetSettingsFromEnvironment returns the available authentication settings from the environment.
func GetSettingsFromEnvironment() (s EnvironmentSettings, err error) {
s = EnvironmentSettings{
Values: map[string]string{},
}
if s.envName == "" {
s.environment = azure.PublicCloud
s.setValue(SubscriptionID)
s.setValue(TenantID)
s.setValue(ClientID)
s.setValue(ClientSecret)
s.setValue(CertificatePath)
s.setValue(CertificatePassword)
s.setValue(Username)
s.setValue(Password)
s.setValue(EnvironmentName)
s.setValue(Resource)
if v := s.Values[EnvironmentName]; v == "" {
s.Environment = azure.PublicCloud
} else {
s.environment, err = azure.EnvironmentFromName(s.envName)
s.Environment, err = azure.EnvironmentFromName(v)
}
if s.Values[Resource] == "" {
s.Values[Resource] = s.Environment.ResourceManagerEndpoint
}
return
}
func (settings settings) getAuthorizer() (autorest.Authorizer, error) {
// GetSubscriptionID returns the available subscription ID or an empty string.
func (settings EnvironmentSettings) GetSubscriptionID() string {
return settings.Values[SubscriptionID]
}
// adds the specified environment variable value to the Values map if it exists
func (settings EnvironmentSettings) setValue(key string) {
if v := os.Getenv(key); v != "" {
settings.Values[key] = v
}
}
// helper to return client and tenant IDs
func (settings EnvironmentSettings) getClientAndTenant() (string, string) {
clientID := settings.Values[ClientID]
tenantID := settings.Values[TenantID]
return clientID, tenantID
}
// GetClientCredentials creates a config object from the available client credentials.
// An error is returned if no client credentials are available.
func (settings EnvironmentSettings) GetClientCredentials() (ClientCredentialsConfig, error) {
secret := settings.Values[ClientSecret]
if secret == "" {
return ClientCredentialsConfig{}, errors.New("missing client secret")
}
clientID, tenantID := settings.getClientAndTenant()
config := NewClientCredentialsConfig(clientID, secret, tenantID)
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
config.Resource = settings.Values[Resource]
return config, nil
}
// GetClientCertificate creates a config object from the available certificate credentials.
// An error is returned if no certificate credentials are available.
func (settings EnvironmentSettings) GetClientCertificate() (ClientCertificateConfig, error) {
certPath := settings.Values[CertificatePath]
if certPath == "" {
return ClientCertificateConfig{}, errors.New("missing certificate path")
}
certPwd := settings.Values[CertificatePassword]
clientID, tenantID := settings.getClientAndTenant()
config := NewClientCertificateConfig(certPath, certPwd, clientID, tenantID)
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
config.Resource = settings.Values[Resource]
return config, nil
}
// GetUsernamePassword creates a config object from the available username/password credentials.
// An error is returned if no username/password credentials are available.
func (settings EnvironmentSettings) GetUsernamePassword() (UsernamePasswordConfig, error) {
username := settings.Values[Username]
password := settings.Values[Password]
if username == "" || password == "" {
return UsernamePasswordConfig{}, errors.New("missing username/password")
}
clientID, tenantID := settings.getClientAndTenant()
config := NewUsernamePasswordConfig(username, password, clientID, tenantID)
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
config.Resource = settings.Values[Resource]
return config, nil
}
// GetMSI creates a MSI config object from the available client ID.
func (settings EnvironmentSettings) GetMSI() MSIConfig {
config := NewMSIConfig()
config.Resource = settings.Values[Resource]
config.ClientID = settings.Values[ClientID]
return config
}
// GetDeviceFlow creates a device-flow config object from the available client and tenant IDs.
func (settings EnvironmentSettings) GetDeviceFlow() DeviceFlowConfig {
clientID, tenantID := settings.getClientAndTenant()
config := NewDeviceFlowConfig(clientID, tenantID)
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
config.Resource = settings.Values[Resource]
return config
}
// GetAuthorizer creates an Authorizer configured from environment variables in the order:
// 1. Client credentials
// 2. Client certificate
// 3. Username password
// 4. MSI
func (settings EnvironmentSettings) GetAuthorizer() (autorest.Authorizer, error) {
//1.Client Credentials
if settings.clientSecret != "" {
config := NewClientCredentialsConfig(settings.clientID, settings.clientSecret, settings.tenantID)
config.AADEndpoint = settings.environment.ActiveDirectoryEndpoint
config.Resource = settings.resource
return config.Authorizer()
if c, e := settings.GetClientCredentials(); e == nil {
return c.Authorizer()
}
//2. Client Certificate
if settings.certificatePath != "" {
config := NewClientCertificateConfig(settings.certificatePath, settings.certificatePassword, settings.clientID, settings.tenantID)
config.AADEndpoint = settings.environment.ActiveDirectoryEndpoint
config.Resource = settings.resource
return config.Authorizer()
if c, e := settings.GetClientCertificate(); e == nil {
return c.Authorizer()
}
//3. Username Password
if settings.username != "" && settings.password != "" {
config := NewUsernamePasswordConfig(settings.username, settings.password, settings.clientID, settings.tenantID)
config.AADEndpoint = settings.environment.ActiveDirectoryEndpoint
config.Resource = settings.resource
return config.Authorizer()
if c, e := settings.GetUsernamePassword(); e == nil {
return c.Authorizer()
}
// 4. MSI
config := NewMSIConfig()
config.Resource = settings.resource
config.ClientID = settings.clientID
return config.Authorizer()
return settings.GetMSI().Authorizer()
}
// NewAuthorizerFromFile creates an Authorizer configured from a configuration file.
// NewAuthorizerFromFile creates an Authorizer configured from a configuration file in the following order.
// 1. Client credentials
// 2. Client certificate
func NewAuthorizerFromFile(baseURI string) (autorest.Authorizer, error) {
settings, err := GetSettingsFromFile()
if err != nil {
return nil, err
}
if a, err := settings.ClientCredentialsAuthorizer(baseURI); err == nil {
return a, err
}
if a, err := settings.ClientCertificateAuthorizer(baseURI); err == nil {
return a, err
}
return nil, errors.New("auth file missing client and certificate credentials")
}
// NewAuthorizerFromFileWithResource creates an Authorizer configured from a configuration file in the following order.
// 1. Client credentials
// 2. Client certificate
func NewAuthorizerFromFileWithResource(resource string) (autorest.Authorizer, error) {
s, err := GetSettingsFromFile()
if err != nil {
return nil, err
}
if a, err := s.ClientCredentialsAuthorizerWithResource(resource); err == nil {
return a, err
}
if a, err := s.ClientCertificateAuthorizerWithResource(resource); err == nil {
return a, err
}
return nil, errors.New("auth file missing client and certificate credentials")
}
// NewAuthorizerFromCLI creates an Authorizer configured from Azure CLI 2.0 for local development scenarios.
func NewAuthorizerFromCLI() (autorest.Authorizer, error) {
settings, err := GetSettingsFromEnvironment()
if err != nil {
return nil, err
}
if settings.Values[Resource] == "" {
settings.Values[Resource] = settings.Environment.ResourceManagerEndpoint
}
return NewAuthorizerFromCLIWithResource(settings.Values[Resource])
}
// NewAuthorizerFromCLIWithResource creates an Authorizer configured from Azure CLI 2.0 for local development scenarios.
func NewAuthorizerFromCLIWithResource(resource string) (autorest.Authorizer, error) {
token, err := cli.GetTokenFromCLI(resource)
if err != nil {
return nil, err
}
adalToken, err := token.ToADALToken()
if err != nil {
return nil, err
}
return autorest.NewBearerAuthorizer(&adalToken), nil
}
// GetSettingsFromFile returns the available authentication settings from an Azure CLI authentication file.
func GetSettingsFromFile() (FileSettings, error) {
s := FileSettings{}
fileLocation := os.Getenv("AZURE_AUTH_LOCATION")
if fileLocation == "" {
return nil, errors.New("auth file not found. Environment variable AZURE_AUTH_LOCATION is not set")
return s, errors.New("environment variable AZURE_AUTH_LOCATION is not set")
}
contents, err := ioutil.ReadFile(fileLocation)
if err != nil {
return nil, err
return s, err
}
// Auth file might be encoded
decoded, err := decode(contents)
if err != nil {
return nil, err
return s, err
}
file := file{}
err = json.Unmarshal(decoded, &file)
authFile := map[string]interface{}{}
err = json.Unmarshal(decoded, &authFile)
if err != nil {
return s, err
}
s.Values = map[string]string{}
s.setKeyValue(ClientID, authFile["clientId"])
s.setKeyValue(ClientSecret, authFile["clientSecret"])
s.setKeyValue(CertificatePath, authFile["clientCertificate"])
s.setKeyValue(CertificatePassword, authFile["clientCertificatePassword"])
s.setKeyValue(SubscriptionID, authFile["subscriptionId"])
s.setKeyValue(TenantID, authFile["tenantId"])
s.setKeyValue(ActiveDirectoryEndpoint, authFile["activeDirectoryEndpointUrl"])
s.setKeyValue(ResourceManagerEndpoint, authFile["resourceManagerEndpointUrl"])
s.setKeyValue(GraphResourceID, authFile["activeDirectoryGraphResourceId"])
s.setKeyValue(SQLManagementEndpoint, authFile["sqlManagementEndpointUrl"])
s.setKeyValue(GalleryEndpoint, authFile["galleryEndpointUrl"])
s.setKeyValue(ManagementEndpoint, authFile["managementEndpointUrl"])
return s, nil
}
// FileSettings contains the available authentication settings.
type FileSettings struct {
Values map[string]string
}
// GetSubscriptionID returns the available subscription ID or an empty string.
func (settings FileSettings) GetSubscriptionID() string {
return settings.Values[SubscriptionID]
}
// adds the specified value to the Values map if it isn't nil
func (settings FileSettings) setKeyValue(key string, val interface{}) {
if val != nil {
settings.Values[key] = val.(string)
}
}
// returns the specified AAD endpoint or the public cloud endpoint if unspecified
func (settings FileSettings) getAADEndpoint() string {
if v, ok := settings.Values[ActiveDirectoryEndpoint]; ok {
return v
}
return azure.PublicCloud.ActiveDirectoryEndpoint
}
// ServicePrincipalTokenFromClientCredentials creates a ServicePrincipalToken from the available client credentials.
func (settings FileSettings) ServicePrincipalTokenFromClientCredentials(baseURI string) (*adal.ServicePrincipalToken, error) {
resource, err := settings.getResourceForToken(baseURI)
if err != nil {
return nil, err
}
return settings.ServicePrincipalTokenFromClientCredentialsWithResource(resource)
}
resource, err := getResourceForToken(file, baseURI)
// ClientCredentialsAuthorizer creates an authorizer from the available client credentials.
func (settings FileSettings) ClientCredentialsAuthorizer(baseURI string) (autorest.Authorizer, error) {
resource, err := settings.getResourceForToken(baseURI)
if err != nil {
return nil, err
}
return settings.ClientCredentialsAuthorizerWithResource(resource)
}
config, err := adal.NewOAuthConfig(file.ActiveDirectoryEndpoint, file.TenantID)
// ServicePrincipalTokenFromClientCredentialsWithResource creates a ServicePrincipalToken
// from the available client credentials and the specified resource.
func (settings FileSettings) ServicePrincipalTokenFromClientCredentialsWithResource(resource string) (*adal.ServicePrincipalToken, error) {
if _, ok := settings.Values[ClientSecret]; !ok {
return nil, errors.New("missing client secret")
}
config, err := adal.NewOAuthConfig(settings.getAADEndpoint(), settings.Values[TenantID])
if err != nil {
return nil, err
}
return adal.NewServicePrincipalToken(*config, settings.Values[ClientID], settings.Values[ClientSecret], resource)
}
spToken, err := adal.NewServicePrincipalToken(*config, file.ClientID, file.ClientSecret, resource)
func (settings FileSettings) clientCertificateConfigWithResource(resource string) (ClientCertificateConfig, error) {
if _, ok := settings.Values[CertificatePath]; !ok {
return ClientCertificateConfig{}, errors.New("missing certificate path")
}
cfg := NewClientCertificateConfig(settings.Values[CertificatePath], settings.Values[CertificatePassword], settings.Values[ClientID], settings.Values[TenantID])
cfg.AADEndpoint = settings.getAADEndpoint()
cfg.Resource = resource
return cfg, nil
}
// ClientCredentialsAuthorizerWithResource creates an authorizer from the available client credentials and the specified resource.
func (settings FileSettings) ClientCredentialsAuthorizerWithResource(resource string) (autorest.Authorizer, error) {
spToken, err := settings.ServicePrincipalTokenFromClientCredentialsWithResource(resource)
if err != nil {
return nil, err
}
return autorest.NewBearerAuthorizer(spToken), nil
}
// File represents the authentication file
type file struct {
ClientID string `json:"clientId,omitempty"`
ClientSecret string `json:"clientSecret,omitempty"`
SubscriptionID string `json:"subscriptionId,omitempty"`
TenantID string `json:"tenantId,omitempty"`
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpointUrl,omitempty"`
ResourceManagerEndpoint string `json:"resourceManagerEndpointUrl,omitempty"`
GraphResourceID string `json:"activeDirectoryGraphResourceId,omitempty"`
SQLManagementEndpoint string `json:"sqlManagementEndpointUrl,omitempty"`
GalleryEndpoint string `json:"galleryEndpointUrl,omitempty"`
ManagementEndpoint string `json:"managementEndpointUrl,omitempty"`
// ServicePrincipalTokenFromClientCertificate creates a ServicePrincipalToken from the available certificate credentials.
func (settings FileSettings) ServicePrincipalTokenFromClientCertificate(baseURI string) (*adal.ServicePrincipalToken, error) {
resource, err := settings.getResourceForToken(baseURI)
if err != nil {
return nil, err
}
return settings.ServicePrincipalTokenFromClientCertificateWithResource(resource)
}
// ClientCertificateAuthorizer creates an authorizer from the available certificate credentials.
func (settings FileSettings) ClientCertificateAuthorizer(baseURI string) (autorest.Authorizer, error) {
resource, err := settings.getResourceForToken(baseURI)
if err != nil {
return nil, err
}
return settings.ClientCertificateAuthorizerWithResource(resource)
}
// ServicePrincipalTokenFromClientCertificateWithResource creates a ServicePrincipalToken from the available certificate credentials.
func (settings FileSettings) ServicePrincipalTokenFromClientCertificateWithResource(resource string) (*adal.ServicePrincipalToken, error) {
cfg, err := settings.clientCertificateConfigWithResource(resource)
if err != nil {
return nil, err
}
return cfg.ServicePrincipalToken()
}
// ClientCertificateAuthorizerWithResource creates an authorizer from the available certificate credentials and the specified resource.
func (settings FileSettings) ClientCertificateAuthorizerWithResource(resource string) (autorest.Authorizer, error) {
cfg, err := settings.clientCertificateConfigWithResource(resource)
if err != nil {
return nil, err
}
return cfg.Authorizer()
}
func decode(b []byte) ([]byte, error) {
@ -211,7 +457,7 @@ func decode(b []byte) ([]byte, error) {
return ioutil.ReadAll(reader)
}
func getResourceForToken(f file, baseURI string) (string, error) {
func (settings FileSettings) getResourceForToken(baseURI string) (string, error) {
// Compare dafault base URI from the SDK to the endpoints from the public cloud
// Base URI and token resource are the same string. This func finds the authentication
// file field that matches the SDK base URI. The SDK defines the public cloud
@ -221,15 +467,15 @@ func getResourceForToken(f file, baseURI string) (string, error) {
}
switch baseURI {
case azure.PublicCloud.ServiceManagementEndpoint:
return f.ManagementEndpoint, nil
return settings.Values[ManagementEndpoint], nil
case azure.PublicCloud.ResourceManagerEndpoint:
return f.ResourceManagerEndpoint, nil
return settings.Values[ResourceManagerEndpoint], nil
case azure.PublicCloud.ActiveDirectoryEndpoint:
return f.ActiveDirectoryEndpoint, nil
return settings.Values[ActiveDirectoryEndpoint], nil
case azure.PublicCloud.GalleryEndpoint:
return f.GalleryEndpoint, nil
return settings.Values[GalleryEndpoint], nil
case azure.PublicCloud.GraphEndpoint:
return f.GraphResourceID, nil
return settings.Values[GraphResourceID], nil
}
return "", fmt.Errorf("auth: base URI not found in endpoints")
}
@ -304,18 +550,21 @@ type ClientCredentialsConfig struct {
Resource string
}
// Authorizer gets the authorizer from client credentials.
func (ccc ClientCredentialsConfig) Authorizer() (autorest.Authorizer, error) {
// ServicePrincipalToken creates a ServicePrincipalToken from client credentials.
func (ccc ClientCredentialsConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthConfig, err := adal.NewOAuthConfig(ccc.AADEndpoint, ccc.TenantID)
if err != nil {
return nil, err
}
return adal.NewServicePrincipalToken(*oauthConfig, ccc.ClientID, ccc.ClientSecret, ccc.Resource)
}
spToken, err := adal.NewServicePrincipalToken(*oauthConfig, ccc.ClientID, ccc.ClientSecret, ccc.Resource)
// Authorizer gets the authorizer from client credentials.
func (ccc ClientCredentialsConfig) Authorizer() (autorest.Authorizer, error) {
spToken, err := ccc.ServicePrincipalToken()
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from client credentials: %v", err)
}
return autorest.NewBearerAuthorizer(spToken), nil
}
@ -329,26 +578,29 @@ type ClientCertificateConfig struct {
Resource string
}
// Authorizer gets an authorizer object from client certificate.
func (ccc ClientCertificateConfig) Authorizer() (autorest.Authorizer, error) {
// ServicePrincipalToken creates a ServicePrincipalToken from client certificate.
func (ccc ClientCertificateConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthConfig, err := adal.NewOAuthConfig(ccc.AADEndpoint, ccc.TenantID)
if err != nil {
return nil, err
}
certData, err := ioutil.ReadFile(ccc.CertificatePath)
if err != nil {
return nil, fmt.Errorf("failed to read the certificate file (%s): %v", ccc.CertificatePath, err)
}
certificate, rsaPrivateKey, err := decodePkcs12(certData, ccc.CertificatePassword)
if err != nil {
return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err)
}
return adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, ccc.ClientID, certificate, rsaPrivateKey, ccc.Resource)
}
spToken, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, ccc.ClientID, certificate, rsaPrivateKey, ccc.Resource)
// Authorizer gets an authorizer object from client certificate.
func (ccc ClientCertificateConfig) Authorizer() (autorest.Authorizer, error) {
spToken, err := ccc.ServicePrincipalToken()
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from certificate auth: %v", err)
}
return autorest.NewBearerAuthorizer(spToken), nil
}
@ -362,26 +614,30 @@ type DeviceFlowConfig struct {
// Authorizer gets the authorizer from device flow.
func (dfc DeviceFlowConfig) Authorizer() (autorest.Authorizer, error) {
oauthClient := &autorest.Client{}
spToken, err := dfc.ServicePrincipalToken()
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from device flow: %v", err)
}
return autorest.NewBearerAuthorizer(spToken), nil
}
// ServicePrincipalToken gets the service principal token from device flow.
func (dfc DeviceFlowConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthConfig, err := adal.NewOAuthConfig(dfc.AADEndpoint, dfc.TenantID)
if err != nil {
return nil, err
}
oauthClient := &autorest.Client{}
deviceCode, err := adal.InitiateDeviceAuth(oauthClient, *oauthConfig, dfc.ClientID, dfc.Resource)
if err != nil {
return nil, fmt.Errorf("failed to start device auth flow: %s", err)
}
log.Println(*deviceCode.Message)
token, err := adal.WaitForUserCompletion(oauthClient, deviceCode)
if err != nil {
return nil, fmt.Errorf("failed to finish device auth flow: %s", err)
}
spToken, err := adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, dfc.ClientID, dfc.Resource, *token)
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from device flow: %v", err)
}
return autorest.NewBearerAuthorizer(spToken), nil
return adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, dfc.ClientID, dfc.Resource, *token)
}
func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
@ -408,17 +664,21 @@ type UsernamePasswordConfig struct {
Resource string
}
// ServicePrincipalToken creates a ServicePrincipalToken from username and password.
func (ups UsernamePasswordConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthConfig, err := adal.NewOAuthConfig(ups.AADEndpoint, ups.TenantID)
if err != nil {
return nil, err
}
return adal.NewServicePrincipalTokenFromUsernamePassword(*oauthConfig, ups.ClientID, ups.Username, ups.Password, ups.Resource)
}
// Authorizer gets the authorizer from a username and a password.
func (ups UsernamePasswordConfig) Authorizer() (autorest.Authorizer, error) {
oauthConfig, err := adal.NewOAuthConfig(ups.AADEndpoint, ups.TenantID)
spToken, err := adal.NewServicePrincipalTokenFromUsernamePassword(*oauthConfig, ups.ClientID, ups.Username, ups.Password, ups.Resource)
spToken, err := ups.ServicePrincipalToken()
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from username and password auth: %v", err)
}
return autorest.NewBearerAuthorizer(spToken), nil
}
@ -435,10 +695,18 @@ func (mc MSIConfig) Authorizer() (autorest.Authorizer, error) {
return nil, err
}
spToken, err := adal.NewServicePrincipalTokenFromMSI(msiEndpoint, mc.Resource)
var spToken *adal.ServicePrincipalToken
if mc.ClientID == "" {
spToken, err = adal.NewServicePrincipalTokenFromMSI(msiEndpoint, mc.Resource)
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from MSI: %v", err)
}
} else {
spToken, err = adal.NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, mc.Resource, mc.ClientID)
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from MSI for user assigned identity: %v", err)
}
}
return autorest.NewBearerAuthorizer(spToken), nil
}

View file

@ -0,0 +1,79 @@
package cli
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/dimchansky/utfbom"
"github.com/mitchellh/go-homedir"
)
// Profile represents a Profile from the Azure CLI
type Profile struct {
InstallationID string `json:"installationId"`
Subscriptions []Subscription `json:"subscriptions"`
}
// Subscription represents a Subscription from the Azure CLI
type Subscription struct {
EnvironmentName string `json:"environmentName"`
ID string `json:"id"`
IsDefault bool `json:"isDefault"`
Name string `json:"name"`
State string `json:"state"`
TenantID string `json:"tenantId"`
User *User `json:"user"`
}
// User represents a User from the Azure CLI
type User struct {
Name string `json:"name"`
Type string `json:"type"`
}
const azureProfileJSON = "azureProfile.json"
// ProfilePath returns the path where the Azure Profile is stored from the Azure CLI
func ProfilePath() (string, error) {
if cfgDir := os.Getenv("AZURE_CONFIG_DIR"); cfgDir != "" {
return filepath.Join(cfgDir, azureProfileJSON), nil
}
return homedir.Expand("~/.azure/" + azureProfileJSON)
}
// LoadProfile restores a Profile object from a file located at 'path'.
func LoadProfile(path string) (result Profile, err error) {
var contents []byte
contents, err = ioutil.ReadFile(path)
if err != nil {
err = fmt.Errorf("failed to open file (%s) while loading token: %v", path, err)
return
}
reader := utfbom.SkipOnly(bytes.NewReader(contents))
dec := json.NewDecoder(reader)
if err = dec.Decode(&result); err != nil {
err = fmt.Errorf("failed to decode contents of file (%s) into a Profile representation: %v", path, err)
return
}
return
}

View file

@ -0,0 +1,170 @@
package cli
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"bytes"
"encoding/json"
"fmt"
"os"
"os/exec"
"regexp"
"runtime"
"strconv"
"time"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/date"
"github.com/mitchellh/go-homedir"
)
// Token represents an AccessToken from the Azure CLI
type Token struct {
AccessToken string `json:"accessToken"`
Authority string `json:"_authority"`
ClientID string `json:"_clientId"`
ExpiresOn string `json:"expiresOn"`
IdentityProvider string `json:"identityProvider"`
IsMRRT bool `json:"isMRRT"`
RefreshToken string `json:"refreshToken"`
Resource string `json:"resource"`
TokenType string `json:"tokenType"`
UserID string `json:"userId"`
}
// ToADALToken converts an Azure CLI `Token`` to an `adal.Token``
func (t Token) ToADALToken() (converted adal.Token, err error) {
tokenExpirationDate, err := ParseExpirationDate(t.ExpiresOn)
if err != nil {
err = fmt.Errorf("Error parsing Token Expiration Date %q: %+v", t.ExpiresOn, err)
return
}
difference := tokenExpirationDate.Sub(date.UnixEpoch())
converted = adal.Token{
AccessToken: t.AccessToken,
Type: t.TokenType,
ExpiresIn: "3600",
ExpiresOn: json.Number(strconv.Itoa(int(difference.Seconds()))),
RefreshToken: t.RefreshToken,
Resource: t.Resource,
}
return
}
// AccessTokensPath returns the path where access tokens are stored from the Azure CLI
// TODO(#199): add unit test.
func AccessTokensPath() (string, error) {
// Azure-CLI allows user to customize the path of access tokens thorugh environment variable.
var accessTokenPath = os.Getenv("AZURE_ACCESS_TOKEN_FILE")
var err error
// Fallback logic to default path on non-cloud-shell environment.
// TODO(#200): remove the dependency on hard-coding path.
if accessTokenPath == "" {
accessTokenPath, err = homedir.Expand("~/.azure/accessTokens.json")
}
return accessTokenPath, err
}
// ParseExpirationDate parses either a Azure CLI or CloudShell date into a time object
func ParseExpirationDate(input string) (*time.Time, error) {
// CloudShell (and potentially the Azure CLI in future)
expirationDate, cloudShellErr := time.Parse(time.RFC3339, input)
if cloudShellErr != nil {
// Azure CLI (Python) e.g. 2017-08-31 19:48:57.998857 (plus the local timezone)
const cliFormat = "2006-01-02 15:04:05.999999"
expirationDate, cliErr := time.ParseInLocation(cliFormat, input, time.Local)
if cliErr == nil {
return &expirationDate, nil
}
return nil, fmt.Errorf("Error parsing expiration date %q.\n\nCloudShell Error: \n%+v\n\nCLI Error:\n%+v", input, cloudShellErr, cliErr)
}
return &expirationDate, nil
}
// LoadTokens restores a set of Token objects from a file located at 'path'.
func LoadTokens(path string) ([]Token, error) {
file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open file (%s) while loading token: %v", path, err)
}
defer file.Close()
var tokens []Token
dec := json.NewDecoder(file)
if err = dec.Decode(&tokens); err != nil {
return nil, fmt.Errorf("failed to decode contents of file (%s) into a `cli.Token` representation: %v", path, err)
}
return tokens, nil
}
// GetTokenFromCLI gets a token using Azure CLI 2.0 for local development scenarios.
func GetTokenFromCLI(resource string) (*Token, error) {
// This is the path that a developer can set to tell this class what the install path for Azure CLI is.
const azureCLIPath = "AzureCLIPath"
// The default install paths are used to find Azure CLI. This is for security, so that any path in the calling program's Path environment is not used to execute Azure CLI.
azureCLIDefaultPathWindows := fmt.Sprintf("%s\\Microsoft SDKs\\Azure\\CLI2\\wbin; %s\\Microsoft SDKs\\Azure\\CLI2\\wbin", os.Getenv("ProgramFiles(x86)"), os.Getenv("ProgramFiles"))
// Default path for non-Windows.
const azureCLIDefaultPath = "/bin:/sbin:/usr/bin:/usr/local/bin"
// Validate resource, since it gets sent as a command line argument to Azure CLI
const invalidResourceErrorTemplate = "Resource %s is not in expected format. Only alphanumeric characters, [dot], [colon], [hyphen], and [forward slash] are allowed."
match, err := regexp.MatchString("^[0-9a-zA-Z-.:/]+$", resource)
if err != nil {
return nil, err
}
if !match {
return nil, fmt.Errorf(invalidResourceErrorTemplate, resource)
}
// Execute Azure CLI to get token
var cliCmd *exec.Cmd
if runtime.GOOS == "windows" {
cliCmd = exec.Command(fmt.Sprintf("%s\\system32\\cmd.exe", os.Getenv("windir")))
cliCmd.Env = os.Environ()
cliCmd.Env = append(cliCmd.Env, fmt.Sprintf("PATH=%s;%s", os.Getenv(azureCLIPath), azureCLIDefaultPathWindows))
cliCmd.Args = append(cliCmd.Args, "/c", "az")
} else {
cliCmd = exec.Command("az")
cliCmd.Env = os.Environ()
cliCmd.Env = append(cliCmd.Env, fmt.Sprintf("PATH=%s:%s", os.Getenv(azureCLIPath), azureCLIDefaultPath))
}
cliCmd.Args = append(cliCmd.Args, "account", "get-access-token", "-o", "json", "--resource", resource)
var stderr bytes.Buffer
cliCmd.Stderr = &stderr
output, err := cliCmd.Output()
if err != nil {
return nil, fmt.Errorf("Invoking Azure CLI failed with the following error: %s", stderr.String())
}
tokenResponse := Token{}
err = json.Unmarshal(output, &tokenResponse)
if err != nil {
return nil, err
}
return &tokenResponse, err
}

View file

@ -22,9 +22,14 @@ import (
"strings"
)
// EnvironmentFilepathName captures the name of the environment variable containing the path to the file
// to be used while populating the Azure Environment.
const EnvironmentFilepathName = "AZURE_ENVIRONMENT_FILEPATH"
const (
// EnvironmentFilepathName captures the name of the environment variable containing the path to the file
// to be used while populating the Azure Environment.
EnvironmentFilepathName = "AZURE_ENVIRONMENT_FILEPATH"
// NotAvailable is used for endpoints and resource IDs that are not available for a given cloud.
NotAvailable = "N/A"
)
var environments = map[string]Environment{
"AZURECHINACLOUD": ChinaCloud,
@ -33,6 +38,16 @@ var environments = map[string]Environment{
"AZUREUSGOVERNMENTCLOUD": USGovernmentCloud,
}
// ResourceIdentifier contains a set of Azure resource IDs.
type ResourceIdentifier struct {
Graph string `json:"graph"`
KeyVault string `json:"keyVault"`
Datalake string `json:"datalake"`
Batch string `json:"batch"`
OperationalInsights string `json:"operationalInsights"`
Storage string `json:"storage"`
}
// Environment represents a set of endpoints for each of Azure's Clouds.
type Environment struct {
Name string `json:"name"`
@ -54,7 +69,9 @@ type Environment struct {
ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"`
ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"`
ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"`
CosmosDBDNSSuffix string `json:"cosmosDBDNSSuffix"`
TokenAudience string `json:"tokenAudience"`
ResourceIdentifiers ResourceIdentifier `json:"resourceIdentifiers"`
}
var (
@ -79,7 +96,16 @@ var (
ServiceManagementVMDNSSuffix: "cloudapp.net",
ResourceManagerVMDNSSuffix: "cloudapp.azure.com",
ContainerRegistryDNSSuffix: "azurecr.io",
CosmosDBDNSSuffix: "documents.azure.com",
TokenAudience: "https://management.azure.com/",
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.windows.net/",
KeyVault: "https://vault.azure.net",
Datalake: "https://datalake.azure.net/",
Batch: "https://batch.core.windows.net/",
OperationalInsights: "https://api.loganalytics.io",
Storage: "https://storage.azure.com/",
},
}
// USGovernmentCloud is the cloud environment for the US Government
@ -102,8 +128,17 @@ var (
ServiceBusEndpointSuffix: "servicebus.usgovcloudapi.net",
ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
ResourceManagerVMDNSSuffix: "cloudapp.windowsazure.us",
ContainerRegistryDNSSuffix: "azurecr.io",
ContainerRegistryDNSSuffix: "azurecr.us",
CosmosDBDNSSuffix: "documents.azure.us",
TokenAudience: "https://management.usgovcloudapi.net/",
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.windows.net/",
KeyVault: "https://vault.usgovcloudapi.net",
Datalake: NotAvailable,
Batch: "https://batch.core.usgovcloudapi.net/",
OperationalInsights: "https://api.loganalytics.us",
Storage: "https://storage.azure.com/",
},
}
// ChinaCloud is the cloud environment operated in China
@ -126,8 +161,17 @@ var (
ServiceBusEndpointSuffix: "servicebus.chinacloudapi.cn",
ServiceManagementVMDNSSuffix: "chinacloudapp.cn",
ResourceManagerVMDNSSuffix: "cloudapp.azure.cn",
ContainerRegistryDNSSuffix: "azurecr.io",
ContainerRegistryDNSSuffix: "azurecr.cn",
CosmosDBDNSSuffix: "documents.azure.cn",
TokenAudience: "https://management.chinacloudapi.cn/",
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.chinacloudapi.cn/",
KeyVault: "https://vault.azure.cn",
Datalake: NotAvailable,
Batch: "https://batch.chinacloudapi.cn/",
OperationalInsights: NotAvailable,
Storage: "https://storage.azure.com/",
},
}
// GermanCloud is the cloud environment operated in Germany
@ -150,8 +194,17 @@ var (
ServiceBusEndpointSuffix: "servicebus.cloudapi.de",
ServiceManagementVMDNSSuffix: "azurecloudapp.de",
ResourceManagerVMDNSSuffix: "cloudapp.microsoftazure.de",
ContainerRegistryDNSSuffix: "azurecr.io",
ContainerRegistryDNSSuffix: NotAvailable,
CosmosDBDNSSuffix: "documents.microsoftazure.de",
TokenAudience: "https://management.microsoftazure.de/",
ResourceIdentifiers: ResourceIdentifier{
Graph: "https://graph.cloudapi.de/",
KeyVault: "https://vault.microsoftazure.de",
Datalake: NotAvailable,
Batch: "https://batch.cloudapi.de/",
OperationalInsights: NotAvailable,
Storage: "https://storage.azure.com/",
},
}
)

View file

@ -140,8 +140,8 @@ func register(client autorest.Client, originalReq *http.Request, re RequestError
}
// poll for registered provisioning state
now := time.Now()
for err == nil && time.Since(now) < client.PollingDuration {
registrationStartTime := time.Now()
for err == nil && (client.PollingDuration == 0 || (client.PollingDuration != 0 && time.Since(registrationStartTime) < client.PollingDuration)) {
// taken from the resources SDK
// https://github.com/Azure/azure-sdk-for-go/blob/9f366792afa3e0ddaecdc860e793ba9d75e76c27/arm/resources/resources/providers.go#L45
preparer := autorest.CreatePreparer(
@ -183,7 +183,7 @@ func register(client autorest.Client, originalReq *http.Request, re RequestError
return originalReq.Context().Err()
}
}
if !(time.Since(now) < client.PollingDuration) {
if client.PollingDuration != 0 && !(time.Since(registrationStartTime) < client.PollingDuration) {
return errors.New("polling for resource provider registration has exceeded the polling duration")
}
return err

View file

@ -16,6 +16,7 @@ package autorest
import (
"bytes"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
@ -26,7 +27,7 @@ import (
"time"
"github.com/Azure/go-autorest/logger"
"github.com/Azure/go-autorest/version"
"github.com/Azure/go-autorest/tracing"
)
const (
@ -72,6 +73,22 @@ type Response struct {
*http.Response `json:"-"`
}
// IsHTTPStatus returns true if the returned HTTP status code matches the provided status code.
// If there was no response (i.e. the underlying http.Response is nil) the return value is false.
func (r Response) IsHTTPStatus(statusCode int) bool {
if r.Response == nil {
return false
}
return r.Response.StatusCode == statusCode
}
// HasHTTPStatus returns true if the returned HTTP status code matches one of the provided status codes.
// If there was no response (i.e. the underlying http.Response is nil) or not status codes are provided
// the return value is false.
func (r Response) HasHTTPStatus(statusCodes ...int) bool {
return ResponseHasStatusCode(r.Response, statusCodes...)
}
// LoggingInspector implements request and response inspectors that log the full request and
// response to a supplied log.
type LoggingInspector struct {
@ -147,6 +164,7 @@ type Client struct {
PollingDelay time.Duration
// PollingDuration sets the maximum polling time after which an error is returned.
// Setting this to zero will use the provided context to control the duration.
PollingDuration time.Duration
// RetryAttempts sets the default number of retry attempts for client.
@ -168,14 +186,32 @@ type Client struct {
// NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed
// string.
func NewClientWithUserAgent(ua string) Client {
return newClient(ua, tls.RenegotiateNever)
}
// ClientOptions contains various Client configuration options.
type ClientOptions struct {
// UserAgent is an optional user-agent string to append to the default user agent.
UserAgent string
// Renegotiation is an optional setting to control client-side TLS renegotiation.
Renegotiation tls.RenegotiationSupport
}
// NewClientWithOptions returns an instance of a Client with the specified values.
func NewClientWithOptions(options ClientOptions) Client {
return newClient(options.UserAgent, options.Renegotiation)
}
func newClient(ua string, renegotiation tls.RenegotiationSupport) Client {
c := Client{
PollingDelay: DefaultPollingDelay,
PollingDuration: DefaultPollingDuration,
RetryAttempts: DefaultRetryAttempts,
RetryDuration: DefaultRetryDuration,
UserAgent: version.UserAgent(),
UserAgent: UserAgent(),
}
c.Sender = c.sender()
c.Sender = c.sender(renegotiation)
c.AddToUserAgent(ua)
return c
}
@ -219,18 +255,39 @@ func (c Client) Do(r *http.Request) (*http.Response, error) {
return true, v
},
})
resp, err := SendWithSender(c.sender(), r)
resp, err := SendWithSender(c.sender(tls.RenegotiateNever), r)
logger.Instance.WriteResponse(resp, logger.Filter{})
Respond(resp, c.ByInspecting())
return resp, err
}
// sender returns the Sender to which to send requests.
func (c Client) sender() Sender {
func (c Client) sender(renengotiation tls.RenegotiationSupport) Sender {
if c.Sender == nil {
j, _ := cookiejar.New(nil)
return &http.Client{Jar: j}
// Use behaviour compatible with DefaultTransport, but require TLS minimum version.
var defaultTransport = http.DefaultTransport.(*http.Transport)
transport := tracing.Transport
// for non-default values of TLS renegotiation create a new tracing transport.
// updating tracing.Transport affects all clients which is not what we want.
if renengotiation != tls.RenegotiateNever {
transport = tracing.NewTransport()
}
transport.Base = &http.Transport{
Proxy: defaultTransport.Proxy,
DialContext: defaultTransport.DialContext,
MaxIdleConns: defaultTransport.MaxIdleConns,
IdleConnTimeout: defaultTransport.IdleConnTimeout,
TLSHandshakeTimeout: defaultTransport.TLSHandshakeTimeout,
ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
Renegotiation: renengotiation,
},
}
j, _ := cookiejar.New(nil)
return &http.Client{Jar: j, Transport: transport}
}
return c.Sender
}

View file

@ -17,6 +17,7 @@ package autorest
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
@ -190,6 +191,9 @@ func AsGet() PrepareDecorator { return WithMethod("GET") }
// AsHead returns a PrepareDecorator that sets the HTTP method to HEAD.
func AsHead() PrepareDecorator { return WithMethod("HEAD") }
// AsMerge returns a PrepareDecorator that sets the HTTP method to MERGE.
func AsMerge() PrepareDecorator { return WithMethod("MERGE") }
// AsOptions returns a PrepareDecorator that sets the HTTP method to OPTIONS.
func AsOptions() PrepareDecorator { return WithMethod("OPTIONS") }
@ -225,6 +229,25 @@ func WithBaseURL(baseURL string) PrepareDecorator {
}
}
// WithBytes returns a PrepareDecorator that takes a list of bytes
// which passes the bytes directly to the body
func WithBytes(input *[]byte) PrepareDecorator {
return func(p Preparer) Preparer {
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
r, err := p.Prepare(r)
if err == nil {
if input == nil {
return r, fmt.Errorf("Input Bytes was nil")
}
r.ContentLength = int64(len(*input))
r.Body = ioutil.NopCloser(bytes.NewReader(*input))
}
return r, err
})
}
}
// WithCustomBaseURL returns a PrepareDecorator that replaces brace-enclosed keys within the
// request base URL (i.e., http.Request.URL) with the corresponding values from the passed map.
func WithCustomBaseURL(baseURL string, urlParameters map[string]interface{}) PrepareDecorator {
@ -377,6 +400,28 @@ func WithJSON(v interface{}) PrepareDecorator {
}
}
// WithXML returns a PrepareDecorator that encodes the data passed as XML into the body of the
// request and sets the Content-Length header.
func WithXML(v interface{}) PrepareDecorator {
return func(p Preparer) Preparer {
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
r, err := p.Prepare(r)
if err == nil {
b, err := xml.Marshal(v)
if err == nil {
// we have to tack on an XML header
withHeader := xml.Header + string(b)
bytesWithHeader := []byte(withHeader)
r.ContentLength = int64(len(bytesWithHeader))
r.Body = ioutil.NopCloser(bytes.NewReader(bytesWithHeader))
}
}
return r, err
})
}
}
// WithPath returns a PrepareDecorator that adds the supplied path to the request URL. If the path
// is absolute (that is, it begins with a "/"), it replaces the existing path.
func WithPath(path string) PrepareDecorator {

View file

@ -153,6 +153,25 @@ func ByClosingIfError() RespondDecorator {
}
}
// ByUnmarshallingBytes returns a RespondDecorator that copies the Bytes returned in the
// response Body into the value pointed to by v.
func ByUnmarshallingBytes(v *[]byte) RespondDecorator {
return func(r Responder) Responder {
return ResponderFunc(func(resp *http.Response) error {
err := r.Respond(resp)
if err == nil {
bytes, errInner := ioutil.ReadAll(resp.Body)
if errInner != nil {
err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
} else {
*v = bytes
}
}
return err
})
}
}
// ByUnmarshallingJSON returns a RespondDecorator that decodes a JSON document returned in the
// response Body into the value pointed to by v.
func ByUnmarshallingJSON(v interface{}) RespondDecorator {

View file

@ -21,6 +21,8 @@ import (
"net/http"
"strconv"
"time"
"github.com/Azure/go-autorest/tracing"
)
// Sender is the interface that wraps the Do method to send HTTP requests.
@ -38,7 +40,7 @@ func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
return sf(r)
}
// SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the
// SendDecorator takes and possibly decorates, by wrapping, a Sender. Decorators may affect the
// http.Request and pass it along or, first, pass the http.Request along then react to the
// http.Response result.
type SendDecorator func(Sender) Sender
@ -68,7 +70,7 @@ func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
//
// Send will not poll or retry requests.
func Send(r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
return SendWithSender(&http.Client{}, r, decorators...)
return SendWithSender(&http.Client{Transport: tracing.Transport}, r, decorators...)
}
// SendWithSender sends the passed http.Request, through the provided Sender, returning the
@ -216,8 +218,7 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
rr := NewRetriableRequest(r)
// Increment to add the first call (attempts denotes number of retries)
attempts++
for attempt := 0; attempt < attempts; {
for attempt := 0; attempt < attempts+1; {
err = rr.Prepare()
if err != nil {
return resp, err
@ -234,7 +235,7 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
}
delayed := DelayWithRetryAfter(resp, r.Context().Done())
if !delayed && !DelayForBackoff(backoff, attempt, r.Context().Done()) {
return nil, r.Context().Err()
return resp, r.Context().Err()
}
// don't count a 429 against the number of attempts
// so that we continue to retry until it succeeds
@ -247,16 +248,24 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
}
}
// DelayWithRetryAfter invokes time.After for the duration specified in the "Retry-After" header in
// responses with status code 429
// DelayWithRetryAfter invokes time.After for the duration specified in the "Retry-After" header.
// The value of Retry-After can be either the number of seconds or a date in RFC1123 format.
// The function returns true after successfully waiting for the specified duration. If there is
// no Retry-After header or the wait is cancelled the return value is false.
func DelayWithRetryAfter(resp *http.Response, cancel <-chan struct{}) bool {
if resp == nil {
return false
}
retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
if resp.StatusCode == http.StatusTooManyRequests && retryAfter > 0 {
var dur time.Duration
ra := resp.Header.Get("Retry-After")
if retryAfter, _ := strconv.Atoi(ra); retryAfter > 0 {
dur = time.Duration(retryAfter) * time.Second
} else if t, err := time.Parse(time.RFC1123, ra); err == nil {
dur = t.Sub(time.Now())
}
if dur > 0 {
select {
case <-time.After(time.Duration(retryAfter) * time.Second):
case <-time.After(dur):
return true
case <-cancel:
return false

View file

@ -145,3 +145,8 @@ func Float64(i *float64) float64 {
func Float64Ptr(i float64) *float64 {
return &i
}
// ByteSlicePtr returns a pointer to the passed byte slice.
func ByteSlicePtr(b []byte) *[]byte {
return &b
}

View file

@ -157,7 +157,7 @@ func AsStringSlice(s interface{}) ([]string, error) {
}
// String method converts interface v to string. If interface is a list, it
// joins list elements using the seperator. Note that only sep[0] will be used for
// joins list elements using the separator. Note that only sep[0] will be used for
// joining if any separator is specified.
func String(v interface{}, sep ...string) string {
if len(sep) == 0 {

View file

@ -398,11 +398,3 @@ func toInt64(v interface{}) (int64, bool) {
}
return 0, false
}
// NewErrorWithValidationError appends package type and method name in
// validation error.
//
// Deprecated: Please use validation.NewError() instead.
func NewErrorWithValidationError(err error, packageType, method string) error {
return NewError(packageType, method, err.Error())
}

View file

@ -1,7 +1,5 @@
package autorest
import "github.com/Azure/go-autorest/version"
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -16,7 +14,28 @@ import "github.com/Azure/go-autorest/version"
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"fmt"
"runtime"
)
const number = "v12.2.0"
var (
userAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s",
runtime.Version(),
runtime.GOARCH,
runtime.GOOS,
number,
)
)
// UserAgent returns a string containing the Go version, system architecture and OS, and the go-autorest version.
func UserAgent() string {
return userAgent
}
// Version returns the semantic version (see http://semver.org).
func Version() string {
return version.Number
return number
}

View file

@ -162,7 +162,7 @@ type Writer interface {
// WriteResponse writes the specified HTTP response to the logger if the log level is greater than
// or equal to LogInfo. The response body, if set, is logged at level LogDebug or higher.
// Custom filters can be specified to exclude URL, header, and/or body content from the log.
// By default no respone content is excluded.
// By default no response content is excluded.
WriteResponse(resp *http.Response, filter Filter)
}
@ -318,7 +318,7 @@ func (fl fileLogger) WriteResponse(resp *http.Response, filter Filter) {
// returns true if the provided body should be included in the log
func (fl fileLogger) shouldLogBody(header http.Header, body io.ReadCloser) bool {
ct := header.Get("Content-Type")
return fl.logLevel >= LogDebug && body != nil && strings.Index(ct, "application/octet-stream") == -1
return fl.logLevel >= LogDebug && body != nil && !strings.Contains(ct, "application/octet-stream")
}
// creates standard header for log entries, it contains a timestamp and the log level

195
vendor/github.com/Azure/go-autorest/tracing/tracing.go generated vendored Normal file
View file

@ -0,0 +1,195 @@
package tracing
// Copyright 2018 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"context"
"fmt"
"net/http"
"os"
"contrib.go.opencensus.io/exporter/ocagent"
"go.opencensus.io/plugin/ochttp"
"go.opencensus.io/plugin/ochttp/propagation/tracecontext"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
)
var (
// Transport is the default tracing RoundTripper. The custom options setter will control
// if traces are being emitted or not.
Transport = NewTransport()
// enabled is the flag for marking if tracing is enabled.
enabled = false
// Sampler is the tracing sampler. If tracing is disabled it will never sample. Otherwise
// it will be using the parent sampler or the default.
sampler = trace.NeverSample()
// Views for metric instrumentation.
views = map[string]*view.View{}
// the trace exporter
traceExporter trace.Exporter
)
func init() {
enableFromEnv()
}
func enableFromEnv() {
_, ok := os.LookupEnv("AZURE_SDK_TRACING_ENABLED")
_, legacyOk := os.LookupEnv("AZURE_SDK_TRACING_ENABELD")
if ok || legacyOk {
agentEndpoint, ok := os.LookupEnv("OCAGENT_TRACE_EXPORTER_ENDPOINT")
if ok {
EnableWithAIForwarding(agentEndpoint)
} else {
Enable()
}
}
}
// NewTransport returns a new instance of a tracing-aware RoundTripper.
func NewTransport() *ochttp.Transport {
return &ochttp.Transport{
Propagation: &tracecontext.HTTPFormat{},
GetStartOptions: getStartOptions,
}
}
// IsEnabled returns true if monitoring is enabled for the sdk.
func IsEnabled() bool {
return enabled
}
// Enable will start instrumentation for metrics and traces.
func Enable() error {
enabled = true
sampler = nil
err := initStats()
return err
}
// Disable will disable instrumentation for metrics and traces.
func Disable() {
disableStats()
sampler = trace.NeverSample()
if traceExporter != nil {
trace.UnregisterExporter(traceExporter)
}
enabled = false
}
// EnableWithAIForwarding will start instrumentation and will connect to app insights forwarder
// exporter making the metrics and traces available in app insights.
func EnableWithAIForwarding(agentEndpoint string) (err error) {
err = Enable()
if err != nil {
return err
}
traceExporter, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithAddress(agentEndpoint))
if err != nil {
return err
}
trace.RegisterExporter(traceExporter)
return
}
// getStartOptions is the custom options setter for the ochttp package.
func getStartOptions(*http.Request) trace.StartOptions {
return trace.StartOptions{
Sampler: sampler,
}
}
// initStats registers the views for the http metrics
func initStats() (err error) {
clientViews := []*view.View{
ochttp.ClientCompletedCount,
ochttp.ClientRoundtripLatencyDistribution,
ochttp.ClientReceivedBytesDistribution,
ochttp.ClientSentBytesDistribution,
}
for _, cv := range clientViews {
vn := fmt.Sprintf("Azure/go-autorest/tracing-%s", cv.Name)
views[vn] = cv.WithName(vn)
err = view.Register(views[vn])
if err != nil {
return err
}
}
return
}
// disableStats will unregister the previously registered metrics
func disableStats() {
for _, v := range views {
view.Unregister(v)
}
}
// StartSpan starts a trace span
func StartSpan(ctx context.Context, name string) context.Context {
ctx, _ = trace.StartSpan(ctx, name, trace.WithSampler(sampler))
return ctx
}
// EndSpan ends a previously started span stored in the context
func EndSpan(ctx context.Context, httpStatusCode int, err error) {
span := trace.FromContext(ctx)
if span == nil {
return
}
if err != nil {
span.SetStatus(trace.Status{Message: err.Error(), Code: toTraceStatusCode(httpStatusCode)})
}
span.End()
}
// toTraceStatusCode converts HTTP Codes to OpenCensus codes as defined
// at https://github.com/census-instrumentation/opencensus-specs/blob/master/trace/HTTP.md#status
func toTraceStatusCode(httpStatusCode int) int32 {
switch {
case http.StatusOK <= httpStatusCode && httpStatusCode < http.StatusBadRequest:
return trace.StatusCodeOK
case httpStatusCode == http.StatusBadRequest:
return trace.StatusCodeInvalidArgument
case httpStatusCode == http.StatusUnauthorized: // 401 is actually unauthenticated.
return trace.StatusCodeUnauthenticated
case httpStatusCode == http.StatusForbidden:
return trace.StatusCodePermissionDenied
case httpStatusCode == http.StatusNotFound:
return trace.StatusCodeNotFound
case httpStatusCode == http.StatusTooManyRequests:
return trace.StatusCodeResourceExhausted
case httpStatusCode == 499:
return trace.StatusCodeCancelled
case httpStatusCode == http.StatusNotImplemented:
return trace.StatusCodeUnimplemented
case httpStatusCode == http.StatusServiceUnavailable:
return trace.StatusCodeUnavailable
case httpStatusCode == http.StatusGatewayTimeout:
return trace.StatusCodeDeadlineExceeded
default:
return trace.StatusCodeUnknown
}
}

View file

@ -0,0 +1,12 @@
package credentials
type BearerTokenCredential struct {
BearerToken string
}
// NewBearerTokenCredential return a BearerTokenCredential object
func NewBearerTokenCredential(token string) *BearerTokenCredential {
return &BearerTokenCredential{
BearerToken: token,
}
}

View file

@ -1,17 +1,5 @@
package credentials
// Deprecated: Use EcsRamRoleCredential in this package instead.
type StsRoleNameOnEcsCredential struct {
RoleName string
}
// Deprecated: Use NewEcsRamRoleCredential in this package instead.
func NewStsRoleNameOnEcsCredential(roleName string) *StsRoleNameOnEcsCredential {
return &StsRoleNameOnEcsCredential{
RoleName: roleName,
}
}
func (oldCred *StsRoleNameOnEcsCredential) ToEcsRamRoleCredential() *EcsRamRoleCredential {
return &EcsRamRoleCredential{
RoleName: oldCred.RoleName,
@ -27,3 +15,15 @@ func NewEcsRamRoleCredential(roleName string) *EcsRamRoleCredential {
RoleName: roleName,
}
}
// Deprecated: Use EcsRamRoleCredential in this package instead.
type StsRoleNameOnEcsCredential struct {
RoleName string
}
// Deprecated: Use NewEcsRamRoleCredential in this package instead.
func NewStsRoleNameOnEcsCredential(roleName string) *StsRoleNameOnEcsCredential {
return &StsRoleNameOnEcsCredential{
RoleName: roleName,
}
}

View file

@ -0,0 +1,30 @@
package provider
import (
"errors"
"os"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
)
type EnvProvider struct{}
var ProviderEnv = new(EnvProvider)
func NewEnvProvider() Provider {
return &EnvProvider{}
}
func (p *EnvProvider) Resolve() (auth.Credential, error) {
accessKeyID, ok1 := os.LookupEnv(ENVAccessKeyID)
accessKeySecret, ok2 := os.LookupEnv(ENVAccessKeySecret)
if !ok1 || !ok2 {
return nil, nil
}
if accessKeyID == "" || accessKeySecret == "" {
return nil, errors.New("Environmental variable (ALIBABACLOUD_ACCESS_KEY_ID or ALIBABACLOUD_ACCESS_KEY_SECRET) is empty")
}
return credentials.NewAccessKeyCredential(accessKeyID, accessKeySecret), nil
}

View file

@ -0,0 +1,92 @@
package provider
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
)
var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"
type InstanceCredentialsProvider struct{}
var ProviderInstance = new(InstanceCredentialsProvider)
var HookGet = func(fn func(string) (int, []byte, error)) func(string) (int, []byte, error) {
return fn
}
func NewInstanceCredentialsProvider() Provider {
return &InstanceCredentialsProvider{}
}
func (p *InstanceCredentialsProvider) Resolve() (auth.Credential, error) {
roleName, ok := os.LookupEnv(ENVEcsMetadata)
if !ok {
return nil, nil
}
if roleName == "" {
return nil, errors.New("Environmental variable 'ALIBABA_CLOUD_ECS_METADATA' are empty")
}
status, content, err := HookGet(get)(securityCredURL + roleName)
if err != nil {
return nil, err
}
if status != 200 {
if status == 404 {
return nil, fmt.Errorf("The role was not found in the instance")
}
return nil, fmt.Errorf("Received %d when getting security credentials for %s", status, roleName)
}
body := make(map[string]interface{})
if err := json.Unmarshal(content, &body); err != nil {
return nil, err
}
accessKeyID, err := extractString(body, "AccessKeyId")
if err != nil {
return nil, err
}
accessKeySecret, err := extractString(body, "AccessKeySecret")
if err != nil {
return nil, err
}
securityToken, err := extractString(body, "SecurityToken")
if err != nil {
return nil, err
}
return credentials.NewStsTokenCredential(accessKeyID, accessKeySecret, securityToken), nil
}
func get(url string) (status int, content []byte, err error) {
httpClient := http.DefaultClient
httpClient.Timeout = time.Second * 1
resp, err := httpClient.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
content, err = ioutil.ReadAll(resp.Body)
return resp.StatusCode, content, err
}
func extractString(m map[string]interface{}, key string) (string, error) {
raw, ok := m[key]
if !ok {
return "", fmt.Errorf("%s not in map", key)
}
str, ok := raw.(string)
if !ok {
return "", fmt.Errorf("%s is not a string in map", key)
}
return str, nil
}

View file

@ -0,0 +1,158 @@
package provider
import (
"bufio"
"errors"
"os"
"runtime"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
ini "gopkg.in/ini.v1"
)
type ProfileProvider struct {
Profile string
}
var ProviderProfile = NewProfileProvider()
// NewProfileProvider receive zero or more parameters,
// when length of name is 0, the value of field Profile will be "default",
// and when there are multiple inputs, the function will take the
// first one and discard the other values.
func NewProfileProvider(name ...string) Provider {
p := new(ProfileProvider)
if len(name) == 0 {
p.Profile = "default"
} else {
p.Profile = name[0]
}
return p
}
// Resolve implements the Provider interface
// when credential type is rsa_key_pair, the content of private_key file
// must be able to be parsed directly into the required string
// that NewRsaKeyPairCredential function needed
func (p *ProfileProvider) Resolve() (auth.Credential, error) {
path, ok := os.LookupEnv(ENVCredentialFile)
if !ok {
path, err := checkDefaultPath()
if err != nil {
return nil, err
}
if path == "" {
return nil, nil
}
} else if path == "" {
return nil, errors.New("Environment variable '" + ENVCredentialFile + "' cannot be empty")
}
ini, err := ini.Load(path)
if err != nil {
return nil, errors.New("ERROR: Can not open file" + err.Error())
}
section, err := ini.GetSection(p.Profile)
if err != nil {
return nil, errors.New("ERROR: Can not load section" + err.Error())
}
value, err := section.GetKey("type")
if err != nil {
return nil, errors.New("ERROR: Can not find credential type" + err.Error())
}
switch value.String() {
case "access_key":
value1, err1 := section.GetKey("access_key_id")
value2, err2 := section.GetKey("access_key_secret")
if err1 != nil || err2 != nil {
return nil, errors.New("ERROR: Failed to get value")
}
if value1.String() == "" || value2.String() == "" {
return nil, errors.New("ERROR: Value can't be empty")
}
return credentials.NewAccessKeyCredential(value1.String(), value2.String()), nil
case "ecs_ram_role":
value1, err1 := section.GetKey("role_name")
if err1 != nil {
return nil, errors.New("ERROR: Failed to get value")
}
if value1.String() == "" {
return nil, errors.New("ERROR: Value can't be empty")
}
return credentials.NewEcsRamRoleCredential(value1.String()), nil
case "ram_role_arn":
value1, err1 := section.GetKey("access_key_id")
value2, err2 := section.GetKey("access_key_secret")
value3, err3 := section.GetKey("role_arn")
value4, err4 := section.GetKey("role_session_name")
if err1 != nil || err2 != nil || err3 != nil || err4 != nil {
return nil, errors.New("ERROR: Failed to get value")
}
if value1.String() == "" || value2.String() == "" || value3.String() == "" || value4.String() == "" {
return nil, errors.New("ERROR: Value can't be empty")
}
return credentials.NewRamRoleArnCredential(value1.String(), value2.String(), value3.String(), value4.String(), 3600), nil
case "rsa_key_pair":
value1, err1 := section.GetKey("public_key_id")
value2, err2 := section.GetKey("private_key_file")
if err1 != nil || err2 != nil {
return nil, errors.New("ERROR: Failed to get value")
}
if value1.String() == "" || value2.String() == "" {
return nil, errors.New("ERROR: Value can't be empty")
}
file, err := os.Open(value2.String())
if err != nil {
return nil, errors.New("ERROR: Can not get private_key")
}
defer file.Close()
var privateKey string
scan := bufio.NewScanner(file)
var data string
for scan.Scan() {
if strings.HasPrefix(scan.Text(), "----") {
continue
}
data += scan.Text() + "\n"
}
return credentials.NewRsaKeyPairCredential(privateKey, value1.String(), 3600), nil
default:
return nil, errors.New("ERROR: Failed to get credential")
}
}
// GetHomePath return home directory according to the system.
// if the environmental virables does not exist, will return empty
func GetHomePath() string {
if runtime.GOOS == "windows" {
path, ok := os.LookupEnv("USERPROFILE")
if !ok {
return ""
}
return path
}
path, ok := os.LookupEnv("HOME")
if !ok {
return ""
}
return path
}
func checkDefaultPath() (path string, err error) {
path = GetHomePath()
if path == "" {
return "", errors.New("The default credential file path is invalid")
}
path = strings.Replace("~/.alibabacloud/credentials", "~", path, 1)
_, err = os.Stat(path)
if err != nil {
return "", nil
}
return path, nil
}

View file

@ -0,0 +1,19 @@
package provider
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
)
//Environmental virables that may be used by the provider
const (
ENVAccessKeyID = "ALIBABA_CLOUD_ACCESS_KEY_ID"
ENVAccessKeySecret = "ALIBABA_CLOUD_ACCESS_KEY_SECRET"
ENVCredentialFile = "ALIBABA_CLOUD_CREDENTIALS_FILE"
ENVEcsMetadata = "ALIBABA_CLOUD_ECS_METADATA"
PATHCredentialFile = "~/.alibabacloud/credentials"
)
// When you want to customize the provider, you only need to implement the method of the interface.
type Provider interface {
Resolve() (auth.Credential, error)
}

View file

@ -0,0 +1,34 @@
package provider
import (
"errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
)
type ProviderChain struct {
Providers []Provider
}
var defaultproviders = []Provider{ProviderEnv, ProviderProfile, ProviderInstance}
var DefaultChain = NewProviderChain(defaultproviders)
func NewProviderChain(providers []Provider) Provider {
return &ProviderChain{
Providers: providers,
}
}
func (p *ProviderChain) Resolve() (auth.Credential, error) {
for _, provider := range p.Providers {
creds, err := provider.Resolve()
if err != nil {
return nil, err
} else if err == nil && creds == nil {
continue
}
return creds, err
}
return nil, errors.New("No credential found")
}

View file

@ -15,6 +15,7 @@ type RamRoleArnCredential struct {
RoleArn string
RoleSessionName string
RoleSessionExpiration int
Policy string
}
// Deprecated: Use RamRoleArnCredential in this package instead.
@ -47,3 +48,14 @@ func NewRamRoleArnCredential(accessKeyId, accessKeySecret, roleArn, roleSessionN
RoleSessionExpiration: roleSessionExpiration,
}
}
func NewRamRoleArnWithPolicyCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName, policy string, roleSessionExpiration int) *RamRoleArnCredential {
return &RamRoleArnCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
RoleSessionName: roleSessionName,
RoleSessionExpiration: roleSessionExpiration,
Policy: policy,
}
}

View file

@ -16,22 +16,33 @@ package auth
import (
"bytes"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
"sort"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
var debug utils.Debug
var hookGetDate = func(fn func() string) string {
return fn()
}
func init() {
debug = utils.Init("sdk")
}
func signRoaRequest(request requests.AcsRequest, signer Signer, regionId string) (err error) {
completeROASignParams(request, signer, regionId)
stringToSign := buildRoaStringToSign(request)
request.SetStringToSign(stringToSign)
signature := signer.Sign(stringToSign, "")
accessKeyId, err := signer.GetAccessKeyId()
if err != nil {
return nil
return err
}
signature := signer.Sign(stringToSign, "")
request.GetHeaders()["Authorization"] = "acs " + accessKeyId + ":" + signature
return
@ -51,13 +62,16 @@ func completeROASignParams(request requests.AcsRequest, signer Signer, regionId
headerParams["x-acs-security-token"] = value
continue
}
if key == "BearerToken" {
headerParams["x-acs-bearer-token"] = value
continue
}
queryParams[key] = value
}
}
// complete header params
headerParams["Date"] = utils.GetTimeInFormatRFC2616()
headerParams["Date"] = hookGetDate(utils.GetTimeInFormatRFC2616)
headerParams["x-acs-signature-method"] = signer.GetName()
headerParams["x-acs-signature-version"] = signer.GetVersion()
if request.GetFormParams() != nil && len(request.GetFormParams()) > 0 {
@ -110,6 +124,7 @@ func buildRoaStringToSign(request requests.AcsRequest) (stringToSign string) {
// append query params
stringToSignBuilder.WriteString(request.BuildQueries())
stringToSign = stringToSignBuilder.String()
debug("stringToSign: %s", stringToSign)
return
}

View file

@ -15,13 +15,17 @@
package auth
import (
"net/url"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
"net/url"
"sort"
"strings"
)
var hookGetNonce = func(fn func() string) string {
return fn()
}
func signRpcRequest(request requests.AcsRequest, signer Signer, regionId string) (err error) {
err = completeRpcSignParams(request, signer, regionId)
if err != nil {
@ -44,11 +48,11 @@ func completeRpcSignParams(request requests.AcsRequest, signer Signer, regionId
queryParams["Version"] = request.GetVersion()
queryParams["Action"] = request.GetActionName()
queryParams["Format"] = request.GetAcceptFormat()
queryParams["Timestamp"] = utils.GetTimeInFormatISO8601()
queryParams["Timestamp"] = hookGetDate(utils.GetTimeInFormatISO8601)
queryParams["SignatureMethod"] = signer.GetName()
queryParams["SignatureType"] = signer.GetType()
queryParams["SignatureVersion"] = signer.GetVersion()
queryParams["SignatureNonce"] = utils.GetUUIDV4()
queryParams["SignatureNonce"] = hookGetNonce(utils.GetUUID)
queryParams["AccessKeyId"], err = signer.GetAccessKeyId()
if err != nil {
@ -80,12 +84,6 @@ func buildRpcStringToSign(request requests.AcsRequest) (stringToSign string) {
signParams[key] = value
}
// sort params by key
var paramKeySlice []string
for key := range signParams {
paramKeySlice = append(paramKeySlice, key)
}
sort.Strings(paramKeySlice)
stringToSign = utils.GetUrlFormedMap(signParams)
stringToSign = strings.Replace(stringToSign, "+", "%20", -1)
stringToSign = strings.Replace(stringToSign, "*", "%2A", -1)

View file

@ -16,12 +16,13 @@ package auth
import (
"fmt"
"reflect"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"reflect"
)
type Signer interface {
@ -31,20 +32,22 @@ type Signer interface {
GetAccessKeyId() (string, error)
GetExtraParam() map[string]string
Sign(stringToSign, secretSuffix string) string
Shutdown()
}
func NewSignerWithCredential(credential Credential, commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)) (signer Signer, err error) {
switch instance := credential.(type) {
case *credentials.AccessKeyCredential:
{
signer, err = signers.NewAccessKeySigner(instance)
signer = signers.NewAccessKeySigner(instance)
}
case *credentials.StsTokenCredential:
{
signer, err = signers.NewStsTokenSigner(instance)
signer = signers.NewStsTokenSigner(instance)
}
case *credentials.BearerTokenCredential:
{
signer = signers.NewBearerTokenSigner(instance)
}
case *credentials.RamRoleArnCredential:
{
signer, err = signers.NewRamRoleArnSigner(instance, commonApi)
@ -55,11 +58,11 @@ func NewSignerWithCredential(credential Credential, commonApi func(request *requ
}
case *credentials.EcsRamRoleCredential:
{
signer, err = signers.NewEcsRamRoleSigner(instance, commonApi)
signer = signers.NewEcsRamRoleSigner(instance, commonApi)
}
case *credentials.BaseCredential: // deprecated user interface
{
signer, err = signers.NewAccessKeySigner(instance.ToAccessKeyCredential())
signer = signers.NewAccessKeySigner(instance.ToAccessKeyCredential())
}
case *credentials.StsRoleArnCredential: // deprecated user interface
{
@ -67,7 +70,7 @@ func NewSignerWithCredential(credential Credential, commonApi func(request *requ
}
case *credentials.StsRoleNameOnEcsCredential: // deprecated user interface
{
signer, err = signers.NewEcsRamRoleSigner(instance.ToEcsRamRoleCredential(), commonApi)
signer = signers.NewEcsRamRoleSigner(instance.ToEcsRamRoleCredential(), commonApi)
}
default:
message := fmt.Sprintf(errors.UnsupportedCredentialErrorMessage, reflect.TypeOf(credential))
@ -80,7 +83,7 @@ func Sign(request requests.AcsRequest, signer Signer, regionId string) (err erro
switch request.GetStyle() {
case requests.ROA:
{
signRoaRequest(request, signer, regionId)
err = signRoaRequest(request, signer, regionId)
}
case requests.RPC:
{

View file

@ -22,11 +22,7 @@ import (
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"fmt"
/*"encoding/pem"
"io/ioutil"
"os/user"
"crypto/sha256"*/)
)
func ShaHmac1(source, secret string) string {
key := []byte(secret)
@ -38,13 +34,14 @@ func ShaHmac1(source, secret string) string {
}
func Sha256WithRsa(source, secret string) string {
// block, _ := pem.Decode([]byte(secret))
decodeString, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
fmt.Println("DecodeString err", err)
panic(err)
}
private, err := x509.ParsePKCS8PrivateKey(decodeString)
if err != nil {
fmt.Println("ParsePKCS8PrivateKey err", err)
panic(err)
}
h := crypto.Hash.New(crypto.SHA256)
@ -53,11 +50,8 @@ func Sha256WithRsa(source, secret string) string {
signature, err := rsa.SignPKCS1v15(rand.Reader, private.(*rsa.PrivateKey),
crypto.SHA256, hashed)
if err != nil {
fmt.Println("Error from signing:", err)
return ""
panic(err)
}
signedString := base64.StdEncoding.EncodeToString(signature)
//fmt.Printf("Encoded: %v\n", signedString)
return signedString
return base64.StdEncoding.EncodeToString(signature)
}

View file

@ -15,12 +15,13 @@
package signers
import (
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"time"
)
const defaultInAdvanceScale = 0.8
const defaultInAdvanceScale = 0.95
type credentialUpdater struct {
credentialExpiration int

View file

@ -26,10 +26,10 @@ func (signer *AccessKeySigner) GetExtraParam() map[string]string {
return nil
}
func NewAccessKeySigner(credential *credentials.AccessKeyCredential) (*AccessKeySigner, error) {
func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner {
return &AccessKeySigner{
credential: credential,
}, nil
}
}
func (*AccessKeySigner) GetName() string {
@ -52,7 +52,3 @@ func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *AccessKeySigner) Shutdown() {
}

View file

@ -0,0 +1,35 @@
package signers
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
)
type BearerTokenSigner struct {
credential *credentials.BearerTokenCredential
}
func NewBearerTokenSigner(credential *credentials.BearerTokenCredential) *BearerTokenSigner {
return &BearerTokenSigner{
credential: credential,
}
}
func (signer *BearerTokenSigner) GetExtraParam() map[string]string {
return map[string]string{"BearerToken": signer.credential.BearerToken}
}
func (*BearerTokenSigner) GetName() string {
return ""
}
func (*BearerTokenSigner) GetType() string {
return "BEARERTOKEN"
}
func (*BearerTokenSigner) GetVersion() string {
return "1.0"
}
func (signer *BearerTokenSigner) GetAccessKeyId() (accessKeyId string, err error) {
return "", nil
}
func (signer *BearerTokenSigner) Sign(stringToSign, secretSuffix string) string {
return ""
}

View file

@ -17,15 +17,18 @@ package signers
import (
"encoding/json"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/jmespath/go-jmespath"
"net/http"
"strings"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
jmespath "github.com/jmespath/go-jmespath"
)
var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"
type EcsRamRoleSigner struct {
*credentialUpdater
sessionCredential *SessionCredential
@ -33,7 +36,7 @@ type EcsRamRoleSigner struct {
commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)
}
func NewEcsRamRoleSigner(credential *credentials.EcsRamRoleCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *EcsRamRoleSigner, err error) {
func NewEcsRamRoleSigner(credential *credentials.EcsRamRoleCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *EcsRamRoleSigner) {
signer = &EcsRamRoleSigner{
credential: credential,
commonApi: commonApi,
@ -46,7 +49,7 @@ func NewEcsRamRoleSigner(credential *credentials.EcsRamRoleCredential, commonApi
refreshApi: signer.refreshApi,
}
return
return signer
}
func (*EcsRamRoleSigner) GetName() string {
@ -64,9 +67,12 @@ func (*EcsRamRoleSigner) GetVersion() string {
func (signer *EcsRamRoleSigner) GetAccessKeyId() (accessKeyId string, err error) {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
if err != nil {
return
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
}
if signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0 {
return "", nil
}
return signer.sessionCredential.AccessKeyId, nil
}
@ -82,76 +88,66 @@ func (signer *EcsRamRoleSigner) GetExtraParam() map[string]string {
}
func (signer *EcsRamRoleSigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeyId + secretSuffix
secret := signer.sessionCredential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *EcsRamRoleSigner) buildCommonRequest() (request *requests.CommonRequest, err error) {
request = requests.NewCommonRequest()
return
}
func (signer *EcsRamRoleSigner) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
requestUrl := "http://100.100.100.200/latest/meta-data/ram/security-credentials/" + signer.credential.RoleName
requestUrl := securityCredURL + signer.credential.RoleName
httpRequest, err := http.NewRequest(requests.GET, requestUrl, strings.NewReader(""))
if err != nil {
fmt.Println("refresh Ecs sts token err", err)
err = fmt.Errorf("refresh Ecs sts token err: %s", err.Error())
return
}
httpClient := &http.Client{}
httpResponse, err := httpClient.Do(httpRequest)
if err != nil {
fmt.Println("refresh Ecs sts token err", err)
err = fmt.Errorf("refresh Ecs sts token err: %s", err.Error())
return
}
response = responses.NewCommonResponse()
err = responses.Unmarshal(response, httpResponse, "")
return
}
func (signer *EcsRamRoleSigner) refreshCredential(response *responses.CommonResponse) (err error) {
if response.GetHttpStatus() != http.StatusOK {
fmt.Println("refresh Ecs sts token err, httpStatus: " + string(response.GetHttpStatus()) + ", message = " + response.GetHttpContentString())
return
return fmt.Errorf("refresh Ecs sts token err, httpStatus: %d, message = %s", response.GetHttpStatus(), response.GetHttpContentString())
}
var data interface{}
err = json.Unmarshal(response.GetHttpContentBytes(), &data)
if err != nil {
fmt.Println("refresh Ecs sts token err, json.Unmarshal fail", err)
return
return fmt.Errorf("refresh Ecs sts token err, json.Unmarshal fail: %s", err.Error())
}
code, err := jmespath.Search("Code", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get Code", err)
return
return fmt.Errorf("refresh Ecs sts token err, fail to get Code: %s", err.Error())
}
if code.(string) != "Success" {
fmt.Println("refresh Ecs sts token err, Code is not Success", err)
return
return fmt.Errorf("refresh Ecs sts token err, Code is not Success")
}
accessKeyId, err := jmespath.Search("AccessKeyId", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get AccessKeyId", err)
return
return fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeyId: %s", err.Error())
}
accessKeySecret, err := jmespath.Search("AccessKeySecret", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get AccessKeySecret", err)
return
return fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeySecret: %s", err.Error())
}
securityToken, err := jmespath.Search("SecurityToken", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get SecurityToken", err)
return
return fmt.Errorf("refresh Ecs sts token err, fail to get SecurityToken: %s", err.Error())
}
expiration, err := jmespath.Search("Expiration", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get Expiration", err)
return
return fmt.Errorf("refresh Ecs sts token err, fail to get Expiration: %s", err.Error())
}
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil || expiration == nil {
return
}
@ -169,7 +165,3 @@ func (signer *EcsRamRoleSigner) refreshCredential(response *responses.CommonResp
func (signer *EcsRamRoleSigner) GetSessionCredential() *SessionCredential {
return signer.sessionCredential
}
func (signer *EcsRamRoleSigner) Shutdown() {
}

View file

@ -17,13 +17,14 @@ package signers
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/jmespath/go-jmespath"
"net/http"
"strconv"
jmespath "github.com/jmespath/go-jmespath"
)
type SignerKeyPair struct {
@ -70,28 +71,33 @@ func (*SignerKeyPair) GetVersion() string {
return "1.0"
}
func (signer *SignerKeyPair) GetAccessKeyId() (accessKeyId string, err error) {
func (signer *SignerKeyPair) ensureCredential() error {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
return signer.updateCredential()
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
return nil
}
func (signer *SignerKeyPair) GetAccessKeyId() (accessKeyId string, err error) {
err = signer.ensureCredential()
if err != nil {
return
}
return signer.sessionCredential.AccessKeyId, err
if signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0 {
accessKeyId = ""
return
}
accessKeyId = signer.sessionCredential.AccessKeyId
return
}
func (signer *SignerKeyPair) GetExtraParam() map[string]string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
signer.updateCredential()
}
if signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0 {
return make(map[string]string)
}
return make(map[string]string)
}
func (signer *SignerKeyPair) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeyId + secretSuffix
secret := signer.sessionCredential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
@ -101,14 +107,15 @@ func (signer *SignerKeyPair) buildCommonRequest() (request *requests.CommonReque
request.Version = "2015-04-01"
request.ApiName = "GenerateSessionAccessKey"
request.Scheme = requests.HTTPS
request.SetDomain("sts.ap-northeast-1.aliyuncs.com")
request.QueryParams["PublicKeyId"] = signer.credential.PublicKeyId
request.QueryParams["DurationSeconds"] = strconv.Itoa(signer.credentialExpiration)
return
}
func (signerKeyPair *SignerKeyPair) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
signerV2, err := NewSignerV2(signerKeyPair.credential)
return signerKeyPair.commonApi(request, signerV2)
func (signer *SignerKeyPair) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
signerV2 := NewSignerV2(signer.credential)
return signer.commonApi(request, signerV2)
}
func (signer *SignerKeyPair) refreshCredential(response *responses.CommonResponse) (err error) {
@ -120,18 +127,15 @@ func (signer *SignerKeyPair) refreshCredential(response *responses.CommonRespons
var data interface{}
err = json.Unmarshal(response.GetHttpContentBytes(), &data)
if err != nil {
fmt.Println("refresh KeyPair err, json.Unmarshal fail", err)
return
return fmt.Errorf("refresh KeyPair err, json.Unmarshal fail: %s", err.Error())
}
accessKeyId, err := jmespath.Search("SessionAccessKey.SessionAccessKeyId", data)
if err != nil {
fmt.Println("refresh KeyPair err, fail to get SessionAccessKeyId", err)
return
return fmt.Errorf("refresh KeyPair err, fail to get SessionAccessKeyId: %s", err.Error())
}
accessKeySecret, err := jmespath.Search("SessionAccessKey.SessionAccessKeySecret", data)
if err != nil {
fmt.Println("refresh KeyPair err, fail to get SessionAccessKeySecret", err)
return
return fmt.Errorf("refresh KeyPair err, fail to get SessionAccessKeySecret: %s", err.Error())
}
if accessKeyId == nil || accessKeySecret == nil {
return
@ -142,7 +146,3 @@ func (signer *SignerKeyPair) refreshCredential(response *responses.CommonRespons
}
return
}
func (signer *SignerKeyPair) Shutdown() {
}

View file

@ -17,14 +17,15 @@ package signers
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/jmespath/go-jmespath"
"net/http"
"strconv"
"time"
jmespath "github.com/jmespath/go-jmespath"
)
const (
@ -84,10 +85,15 @@ func (*RamRoleArnSigner) GetVersion() string {
func (signer *RamRoleArnSigner) GetAccessKeyId() (accessKeyId string, err error) {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
if err != nil {
return
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
}
if signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0 {
return "", err
}
return signer.sessionCredential.AccessKeyId, nil
}
@ -113,6 +119,9 @@ func (signer *RamRoleArnSigner) buildCommonRequest() (request *requests.CommonRe
request.ApiName = "AssumeRole"
request.Scheme = requests.HTTPS
request.QueryParams["RoleArn"] = signer.credential.RoleArn
if signer.credential.Policy != "" {
request.QueryParams["Policy"] = signer.credential.Policy
}
request.QueryParams["RoleSessionName"] = signer.credential.RoleSessionName
request.QueryParams["DurationSeconds"] = strconv.Itoa(signer.credentialExpiration)
return
@ -123,7 +132,7 @@ func (signer *RamRoleArnSigner) refreshApi(request *requests.CommonRequest) (res
AccessKeyId: signer.credential.AccessKeyId,
AccessKeySecret: signer.credential.AccessKeySecret,
}
signerV1, err := NewAccessKeySigner(credential)
signerV1 := NewAccessKeySigner(credential)
return signer.commonApi(request, signerV1)
}
@ -136,23 +145,19 @@ func (signer *RamRoleArnSigner) refreshCredential(response *responses.CommonResp
var data interface{}
err = json.Unmarshal(response.GetHttpContentBytes(), &data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, json.Unmarshal fail", err)
return
return fmt.Errorf("refresh RoleArn sts token err, json.Unmarshal fail: %s", err.Error())
}
accessKeyId, err := jmespath.Search("Credentials.AccessKeyId", data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, fail to get AccessKeyId", err)
return
return fmt.Errorf("refresh RoleArn sts token err, fail to get AccessKeyId: %s", err.Error())
}
accessKeySecret, err := jmespath.Search("Credentials.AccessKeySecret", data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, fail to get AccessKeySecret", err)
return
return fmt.Errorf("refresh RoleArn sts token err, fail to get AccessKeySecret: %s", err.Error())
}
securityToken, err := jmespath.Search("Credentials.SecurityToken", data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, fail to get SecurityToken", err)
return
return fmt.Errorf("refresh RoleArn sts token err, fail to get SecurityToken: %s", err.Error())
}
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
return
@ -168,7 +173,3 @@ func (signer *RamRoleArnSigner) refreshCredential(response *responses.CommonResp
func (signer *RamRoleArnSigner) GetSessionCredential() *SessionCredential {
return signer.sessionCredential
}
func (signer *RamRoleArnSigner) Shutdown() {
}

View file

@ -22,10 +22,10 @@ type StsTokenSigner struct {
credential *credentials.StsTokenCredential
}
func NewStsTokenSigner(credential *credentials.StsTokenCredential) (*StsTokenSigner, error) {
func NewStsTokenSigner(credential *credentials.StsTokenCredential) *StsTokenSigner {
return &StsTokenSigner{
credential: credential,
}, nil
}
}
func (*StsTokenSigner) GetName() string {
@ -52,7 +52,3 @@ func (signer *StsTokenSigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *StsTokenSigner) Shutdown() {
}

View file

@ -26,10 +26,10 @@ func (signer *SignerV2) GetExtraParam() map[string]string {
return nil
}
func NewSignerV2(credential *credentials.RsaKeyPairCredential) (*SignerV2, error) {
func NewSignerV2(credential *credentials.RsaKeyPairCredential) *SignerV2 {
return &SignerV2{
credential: credential,
}, nil
}
}
func (*SignerV2) GetName() string {
@ -52,7 +52,3 @@ func (signer *SignerV2) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.PrivateKey
return Sha256WithRsa(stringToSign, secret)
}
func (signer *SignerV2) Shutdown() {
}

View file

@ -15,28 +15,62 @@
package sdk
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"net"
"net/http"
"strconv"
"sync"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
// this value will be replaced while build: -ldflags="-X sdk.version=x.x.x"
var Version = "0.0.1"
var debug utils.Debug
func init() {
debug = utils.Init("sdk")
}
// Version this value will be replaced while build: -ldflags="-X sdk.version=x.x.x"
var Version = "0.0.1"
var defaultConnectTimeout = 5 * time.Second
var defaultReadTimeout = 10 * time.Second
var DefaultUserAgent = fmt.Sprintf("AlibabaCloud (%s; %s) Golang/%s Core/%s", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), Version)
var hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
return fn
}
// Client the type Client
type Client struct {
isInsecure bool
regionId string
config *Config
httpProxy string
httpsProxy string
noProxy string
logger *Logger
userAgent map[string]string
signer auth.Signer
httpClient *http.Client
asyncTaskQueue chan func()
readTimeout time.Duration
connectTimeout time.Duration
debug bool
isRunning bool
@ -48,14 +82,56 @@ func (client *Client) Init() (err error) {
panic("not support yet")
}
func (client *Client) SetHTTPSInsecure(isInsecure bool) {
client.isInsecure = isInsecure
}
func (client *Client) GetHTTPSInsecure() bool {
return client.isInsecure
}
func (client *Client) SetHttpsProxy(httpsProxy string) {
client.httpsProxy = httpsProxy
}
func (client *Client) GetHttpsProxy() string {
return client.httpsProxy
}
func (client *Client) SetHttpProxy(httpProxy string) {
client.httpProxy = httpProxy
}
func (client *Client) GetHttpProxy() string {
return client.httpProxy
}
func (client *Client) SetNoProxy(noProxy string) {
client.noProxy = noProxy
}
func (client *Client) GetNoProxy() string {
return client.noProxy
}
// InitWithProviderChain will get credential from the providerChain,
// the RsaKeyPairCredential Only applicable to regionID `ap-northeast-1`,
// if your providerChain may return a credential type with RsaKeyPairCredential,
// please ensure your regionID is `ap-northeast-1`.
func (client *Client) InitWithProviderChain(regionId string, provider provider.Provider) (err error) {
config := client.InitClientConfig()
credential, err := provider.Resolve()
if err != nil {
return
}
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithOptions(regionId string, config *Config, credential auth.Credential) (err error) {
client.isRunning = true
client.asyncChanLock = new(sync.RWMutex)
client.regionId = regionId
client.config = config
if err != nil {
return
}
client.httpClient = &http.Client{}
if config.HttpTransport != nil {
@ -75,6 +151,58 @@ func (client *Client) InitWithOptions(regionId string, config *Config, credentia
return
}
func (client *Client) SetReadTimeout(readTimeout time.Duration) {
client.readTimeout = readTimeout
}
func (client *Client) SetConnectTimeout(connectTimeout time.Duration) {
client.connectTimeout = connectTimeout
}
func (client *Client) GetReadTimeout() time.Duration {
return client.readTimeout
}
func (client *Client) GetConnectTimeout() time.Duration {
return client.connectTimeout
}
func (client *Client) getHttpProxy(scheme string) (proxy *url.URL, err error) {
if scheme == "https" {
if client.GetHttpsProxy() != "" {
proxy, err = url.Parse(client.httpsProxy)
} else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" {
proxy, err = url.Parse(rawurl)
} else if rawurl := os.Getenv("https_proxy"); rawurl != "" {
proxy, err = url.Parse(rawurl)
}
} else {
if client.GetHttpProxy() != "" {
proxy, err = url.Parse(client.httpProxy)
} else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" {
proxy, err = url.Parse(rawurl)
} else if rawurl := os.Getenv("http_proxy"); rawurl != "" {
proxy, err = url.Parse(rawurl)
}
}
return proxy, err
}
func (client *Client) getNoProxy(scheme string) []string {
var urls []string
if client.GetNoProxy() != "" {
urls = strings.Split(client.noProxy, ",")
} else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" {
urls = strings.Split(rawurl, ",")
} else if rawurl := os.Getenv("no_proxy"); rawurl != "" {
urls = strings.Split(rawurl, ",")
}
return urls
}
// EnableAsync enable the async task queue
func (client *Client) EnableAsync(routinePoolSize, maxTaskQueueSize int) {
client.asyncTaskQueue = make(chan func(), maxTaskQueueSize)
for i := 0; i < routinePoolSize; i++ {
@ -121,6 +249,18 @@ func (client *Client) InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret,
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithRamRoleArnAndPolicy(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName, policy string) (err error) {
config := client.InitClientConfig()
credential := &credentials.RamRoleArnCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
RoleSessionName: roleSessionName,
Policy: policy,
}
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithRsaKeyPair(regionId, publicKeyId, privateKey string, sessionExpiration int) (err error) {
config := client.InitClientConfig()
credential := &credentials.RsaKeyPairCredential{
@ -139,6 +279,14 @@ func (client *Client) InitWithEcsRamRole(regionId, roleName string) (err error)
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithBearerToken(regionId, bearerToken string) (err error) {
config := client.InitClientConfig()
credential := &credentials.BearerTokenCredential{
BearerToken: bearerToken,
}
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitClientConfig() (config *Config) {
if client.config != nil {
return client.config
@ -151,7 +299,7 @@ func (client *Client) DoAction(request requests.AcsRequest, response responses.A
return client.DoActionWithSigner(request, response, nil)
}
func (client *Client) BuildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (err error) {
func (client *Client) buildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (httpRequest *http.Request, err error) {
// add clientVersion
request.GetHeaders()["x-sdk-core-version"] = Version
@ -174,52 +322,6 @@ func (client *Client) BuildRequestWithSigner(request requests.AcsRequest, signer
return
}
request.SetDomain(endpoint)
// init request params
err = requests.InitParams(request)
if err != nil {
return
}
// signature
var finalSigner auth.Signer
if signer != nil {
finalSigner = signer
} else {
finalSigner = client.signer
}
httpRequest, err := buildHttpRequest(request, finalSigner, regionId)
if client.config.UserAgent != "" {
httpRequest.Header.Set("User-Agent", client.config.UserAgent)
}
return err
}
func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
// add clientVersion
request.GetHeaders()["x-sdk-core-version"] = Version
regionId := client.regionId
if len(request.GetRegionId()) > 0 {
regionId = request.GetRegionId()
}
// resolve endpoint
resolveParam := &endpoints.ResolveParam{
Domain: request.GetDomain(),
Product: request.GetProduct(),
RegionId: regionId,
LocationProduct: request.GetLocationServiceCode(),
LocationEndpointType: request.GetLocationEndpointType(),
CommonApi: client.ProcessCommonRequest,
}
endpoint, err := endpoints.Resolve(resolveParam)
if err != nil {
return
}
request.SetDomain(endpoint)
if request.GetScheme() == "" {
request.SetScheme(client.config.Scheme)
}
@ -236,36 +338,211 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
} else {
finalSigner = client.signer
}
httpRequest, err := buildHttpRequest(request, finalSigner, regionId)
if client.config.UserAgent != "" {
httpRequest.Header.Set("User-Agent", client.config.UserAgent)
httpRequest, err = buildHttpRequest(request, finalSigner, regionId)
if err == nil {
userAgent := DefaultUserAgent + getSendUserAgent(client.config.UserAgent, client.userAgent, request.GetUserAgent())
httpRequest.Header.Set("User-Agent", userAgent)
}
return
}
func getSendUserAgent(configUserAgent string, clientUserAgent, requestUserAgent map[string]string) string {
realUserAgent := ""
for key1, value1 := range clientUserAgent {
for key2, _ := range requestUserAgent {
if key1 == key2 {
key1 = ""
}
}
if key1 != "" {
realUserAgent += fmt.Sprintf(" %s/%s", key1, value1)
}
}
for key, value := range requestUserAgent {
realUserAgent += fmt.Sprintf(" %s/%s", key, value)
}
if configUserAgent != "" {
return realUserAgent + fmt.Sprintf(" Extra/%s", configUserAgent)
}
return realUserAgent
}
func (client *Client) AppendUserAgent(key, value string) {
newkey := true
if client.userAgent == nil {
client.userAgent = make(map[string]string)
}
if strings.ToLower(key) != "core" && strings.ToLower(key) != "go" {
for tag, _ := range client.userAgent {
if tag == key {
client.userAgent[tag] = value
newkey = false
}
}
if newkey {
client.userAgent[key] = value
}
}
}
func (client *Client) BuildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (err error) {
_, err = client.buildRequestWithSigner(request, signer)
return
}
func (client *Client) getTimeout(request requests.AcsRequest) (time.Duration, time.Duration) {
readTimeout := defaultReadTimeout
connectTimeout := defaultConnectTimeout
reqReadTimeout := request.GetReadTimeout()
reqConnectTimeout := request.GetConnectTimeout()
if reqReadTimeout != 0*time.Millisecond {
readTimeout = reqReadTimeout
} else if client.readTimeout != 0*time.Millisecond {
readTimeout = client.readTimeout
} else if client.httpClient.Timeout != 0 && client.httpClient.Timeout != 10000000000 {
readTimeout = client.httpClient.Timeout
}
if reqConnectTimeout != 0*time.Millisecond {
connectTimeout = reqConnectTimeout
} else if client.connectTimeout != 0*time.Millisecond {
connectTimeout = client.connectTimeout
}
return readTimeout, connectTimeout
}
func Timeout(connectTimeout time.Duration) func(cxt context.Context, net, addr string) (c net.Conn, err error) {
return func(ctx context.Context, network, address string) (net.Conn, error) {
return (&net.Dialer{
Timeout: connectTimeout,
DualStack: true,
}).DialContext(ctx, network, address)
}
}
func (client *Client) setTimeout(request requests.AcsRequest) {
readTimeout, connectTimeout := client.getTimeout(request)
client.httpClient.Timeout = readTimeout
if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
trans.DialContext = Timeout(connectTimeout)
client.httpClient.Transport = trans
} else {
client.httpClient.Transport = &http.Transport{
DialContext: Timeout(connectTimeout),
}
}
}
func (client *Client) getHTTPSInsecure(request requests.AcsRequest) (insecure bool) {
if request.GetHTTPSInsecure() != nil {
insecure = *request.GetHTTPSInsecure()
} else {
insecure = client.GetHTTPSInsecure()
}
return insecure
}
func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
fieldMap := make(map[string]string)
initLogMsg(fieldMap)
defer func() {
client.printLog(fieldMap, err)
}()
httpRequest, err := client.buildRequestWithSigner(request, signer)
if err != nil {
return
}
client.setTimeout(request)
proxy, err := client.getHttpProxy(httpRequest.URL.Scheme)
if err != nil {
return err
}
noProxy := client.getNoProxy(httpRequest.URL.Scheme)
var flag bool
for _, value := range noProxy {
if value == httpRequest.Host {
flag = true
break
}
}
// Set whether to ignore certificate validation.
// Default InsecureSkipVerify is false.
if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
trans.TLSClientConfig = &tls.Config{
InsecureSkipVerify: client.getHTTPSInsecure(request),
}
if proxy != nil && !flag {
trans.Proxy = http.ProxyURL(proxy)
}
client.httpClient.Transport = trans
}
var httpResponse *http.Response
for retryTimes := 0; retryTimes <= client.config.MaxRetryTime; retryTimes++ {
httpResponse, err = client.httpClient.Do(httpRequest)
if proxy != nil && proxy.User != nil {
if password, passwordSet := proxy.User.Password(); passwordSet {
httpRequest.SetBasicAuth(proxy.User.Username(), password)
}
}
if retryTimes > 0 {
client.printLog(fieldMap, err)
initLogMsg(fieldMap)
}
putMsgToMap(fieldMap, httpRequest)
debug("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto)
debug("> Host: %s", httpRequest.Host)
for key, value := range httpRequest.Header {
debug("> %s: %v", key, strings.Join(value, ""))
}
debug(">")
debug(" Retry Times: %d.", retryTimes)
var timeout bool
startTime := time.Now()
fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05")
httpResponse, err = hookDo(client.httpClient.Do)(httpRequest)
fieldMap["{cost}"] = time.Now().Sub(startTime).String()
if err == nil {
fieldMap["{code}"] = strconv.Itoa(httpResponse.StatusCode)
fieldMap["{res_headers}"] = TransToString(httpResponse.Header)
debug("< %s %s", httpResponse.Proto, httpResponse.Status)
for key, value := range httpResponse.Header {
debug("< %s: %v", key, strings.Join(value, ""))
}
}
debug("<")
// receive error
if err != nil {
debug(" Error: %s.", err.Error())
if !client.config.AutoRetry {
return
} else if timeout = isTimeout(err); !timeout {
// if not timeout error, return
return
} else if retryTimes >= client.config.MaxRetryTime {
// timeout but reached the max retry times, return
timeoutErrorMsg := fmt.Sprintf(errors.TimeoutErrorMessage, strconv.Itoa(retryTimes+1), strconv.Itoa(retryTimes+1))
times := strconv.Itoa(retryTimes + 1)
timeoutErrorMsg := fmt.Sprintf(errors.TimeoutErrorMessage, times, times)
if strings.Contains(err.Error(), "Client.Timeout") {
timeoutErrorMsg += " Read timeout. Please set a valid ReadTimeout."
} else {
timeoutErrorMsg += " Connect timeout. Please set a valid ConnectTimeout."
}
err = errors.NewClientError(errors.TimeoutErrorCode, timeoutErrorMsg, err)
return
}
}
// if status code >= 500 or timeout, will trigger retry
if client.config.AutoRetry && (timeout || isServerError(httpResponse)) {
if client.config.AutoRetry && (err != nil || isServerError(httpResponse)) {
client.setTimeout(request)
// rewrite signatureNonce and signature
httpRequest, err = buildHttpRequest(request, finalSigner, regionId)
httpRequest, err = client.buildRequestWithSigner(request, signer)
// buildHttpRequest(request, finalSigner, regionId)
if err != nil {
return
}
@ -273,6 +550,7 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
}
break
}
err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
// wrap server errors
if serverErr, ok := err.(*errors.ServerError); ok {
@ -283,6 +561,18 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
return
}
func putMsgToMap(fieldMap map[string]string, request *http.Request) {
fieldMap["{host}"] = request.Host
fieldMap["{method}"] = request.Method
fieldMap["{uri}"] = request.URL.RequestURI()
fieldMap["{pid}"] = strconv.Itoa(os.Getpid())
fieldMap["{version}"] = strings.Split(request.Proto, "/")[1]
hostname, _ := os.Hostname()
fieldMap["{hostname}"] = hostname
fieldMap["{req_headers}"] = TransToString(request.Header)
fieldMap["{target}"] = request.URL.Path + request.URL.RawQuery
}
func buildHttpRequest(request requests.AcsRequest, singer auth.Signer, regionId string) (httpRequest *http.Request, err error) {
err = auth.Sign(request, singer, regionId)
if err != nil {
@ -305,14 +595,6 @@ func buildHttpRequest(request requests.AcsRequest, singer auth.Signer, regionId
return
}
func isTimeout(err error) bool {
if err == nil {
return false
}
netErr, isNetError := err.(net.Error)
return isNetError && netErr.Timeout()
}
func isServerError(httpResponse *http.Response) bool {
return httpResponse.StatusCode >= http.StatusInternalServerError
}
@ -345,6 +627,18 @@ func NewClient() (client *Client, err error) {
return
}
func NewClientWithProvider(regionId string, providers ...provider.Provider) (client *Client, err error) {
client = &Client{}
var pc provider.Provider
if len(providers) == 0 {
pc = provider.DefaultChain
} else {
pc = provider.NewProviderChain(providers)
}
err = client.InitWithProviderChain(regionId, pc)
return
}
func NewClientWithOptions(regionId string, config *Config, credential auth.Credential) (client *Client, err error) {
client = &Client{}
err = client.InitWithOptions(regionId, config, credential)
@ -369,6 +663,12 @@ func NewClientWithRamRoleArn(regionId string, accessKeyId, accessKeySecret, role
return
}
func NewClientWithRamRoleArnAndPolicy(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName, policy string) (client *Client, err error) {
client = &Client{}
err = client.InitWithRamRoleArnAndPolicy(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName, policy)
return
}
func NewClientWithEcsRamRole(regionId string, roleName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithEcsRamRole(regionId, roleName)
@ -381,14 +681,10 @@ func NewClientWithRsaKeyPair(regionId string, publicKeyId, privateKey string, se
return
}
// Deprecated: Use NewClientWithRamRoleArn in this package instead.
func NewClientWithStsRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
return NewClientWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
}
// Deprecated: Use NewClientWithEcsRamRole in this package instead.
func NewClientWithStsRoleNameOnEcs(regionId string, roleName string) (client *Client, err error) {
return NewClientWithEcsRamRole(regionId, roleName)
func NewClientWithBearerToken(regionId, bearerToken string) (client *Client, err error) {
client = &Client{}
err = client.InitWithBearerToken(regionId, bearerToken)
return
}
func (client *Client) ProcessCommonRequest(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
@ -404,16 +700,26 @@ func (client *Client) ProcessCommonRequestWithSigner(request *requests.CommonReq
response = responses.NewCommonResponse()
err = client.DoActionWithSigner(request, response, signer)
return
} else {
panic("should not be here")
}
panic("should not be here")
}
func (client *Client) Shutdown() {
client.signer.Shutdown()
// lock the addAsync()
client.asyncChanLock.Lock()
defer client.asyncChanLock.Unlock()
client.isRunning = false
if client.asyncTaskQueue != nil {
close(client.asyncTaskQueue)
}
client.isRunning = false
}
// Deprecated: Use NewClientWithRamRoleArn in this package instead.
func NewClientWithStsRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
return NewClientWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
}
// Deprecated: Use NewClientWithEcsRamRole in this package instead.
func NewClientWithStsRoleNameOnEcs(regionId string, roleName string) (client *Client, err error) {
return NewClientWithEcsRamRole(regionId, roleName)
}

View file

@ -15,9 +15,10 @@
package sdk
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
"net/http"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
type Config struct {
@ -39,11 +40,6 @@ func NewConfig() (config *Config) {
return
}
func (c *Config) WithTimeout(timeout time.Duration) *Config {
c.Timeout = timeout
return c
}
func (c *Config) WithAutoRetry(isAutoRetry bool) *Config {
c.AutoRetry = isAutoRetry
return c
@ -59,6 +55,16 @@ func (c *Config) WithUserAgent(userAgent string) *Config {
return c
}
func (c *Config) WithDebug(isDebug bool) *Config {
c.Debug = isDebug
return c
}
func (c *Config) WithTimeout(timeout time.Duration) *Config {
c.Timeout = timeout
return c
}
func (c *Config) WithHttpTransport(httpTransport *http.Transport) *Config {
c.HttpTransport = httpTransport
return c
@ -79,7 +85,7 @@ func (c *Config) WithGoRoutinePoolSize(goRoutinePoolSize int) *Config {
return c
}
func (c *Config) WithDebug(isDebug bool) *Config {
c.Debug = isDebug
func (c *Config) WithScheme(scheme string) *Config {
c.Scheme = scheme
return c
}

File diff suppressed because it is too large Load diff

View file

@ -16,13 +16,19 @@ package endpoints
import (
"fmt"
"github.com/jmespath/go-jmespath"
"strings"
"github.com/jmespath/go-jmespath"
)
type LocalGlobalResolver struct {
}
func (resolver *LocalGlobalResolver) GetName() (name string) {
name = "local global resolver"
return
}
func (resolver *LocalGlobalResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
// get the global endpoints configs
endpointExpression := fmt.Sprintf("products[?code=='%s'].global_endpoint", strings.ToLower(param.Product))
@ -30,7 +36,7 @@ func (resolver *LocalGlobalResolver) TryResolve(param *ResolveParam) (endpoint s
if err == nil && endpointData != nil && len(endpointData.([]interface{})) > 0 {
endpoint = endpointData.([]interface{})[0].(string)
support = len(endpoint) > 0
return endpoint, support, nil
return
}
support = false
return

View file

@ -16,24 +16,31 @@ package endpoints
import (
"fmt"
"github.com/jmespath/go-jmespath"
"strings"
"github.com/jmespath/go-jmespath"
)
type LocalRegionalResolver struct {
}
func (resolver *LocalRegionalResolver) GetName() (name string) {
name = "local regional resolver"
return
}
func (resolver *LocalRegionalResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
// get the regional endpoints configs
regionalExpression := fmt.Sprintf("products[?code=='%s'].regional_endpoints", strings.ToLower(param.Product))
regionalData, err := jmespath.Search(regionalExpression, getEndpointConfigData())
if err == nil && regionalData != nil && len(regionalData.([]interface{})) > 0 {
endpointExpression := fmt.Sprintf("[0][?region=='%s'].endpoint", strings.ToLower(param.RegionId))
endpointData, err := jmespath.Search(endpointExpression, regionalData)
var endpointData interface{}
endpointData, err = jmespath.Search(endpointExpression, regionalData)
if err == nil && endpointData != nil && len(endpointData.([]interface{})) > 0 {
endpoint = endpointData.([]interface{})[0].(string)
support = len(endpoint) > 0
return endpoint, support, nil
return
}
}
support = false

View file

@ -15,28 +15,51 @@ package endpoints
import (
"encoding/json"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"sync"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
)
const (
// EndpointCacheExpireTime ...
EndpointCacheExpireTime = 3600 //Seconds
)
var lastClearTimePerProduct = struct {
// Cache caches endpoint for specific product and region
type Cache struct {
sync.RWMutex
cache map[string]int64
}{cache: make(map[string]int64)}
cache map[string]interface{}
}
var endpointCache = struct {
sync.RWMutex
cache map[string]string
}{cache: make(map[string]string)}
// Get ...
func (c *Cache) Get(k string) (v interface{}) {
c.RLock()
v = c.cache[k]
c.RUnlock()
return
}
// Set ...
func (c *Cache) Set(k string, v interface{}) {
c.Lock()
c.cache[k] = v
c.Unlock()
}
var lastClearTimePerProduct = &Cache{cache: make(map[string]interface{})}
var endpointCache = &Cache{cache: make(map[string]interface{})}
// LocationResolver ...
type LocationResolver struct {
}
func (resolver *LocationResolver) GetName() (name string) {
name = "location resolver"
return
}
// TryResolve resolves endpoint giving product and region
func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
if len(param.LocationProduct) <= 0 {
support = false
@ -45,8 +68,10 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
//get from cache
cacheKey := param.Product + "#" + param.RegionId
if endpointCache.cache != nil && len(endpointCache.cache[cacheKey]) > 0 && !CheckCacheIsExpire(cacheKey) {
endpoint = endpointCache.cache[cacheKey]
var ok bool
endpoint, ok = endpointCache.Get(cacheKey).(string)
if ok && len(endpoint) > 0 && !CheckCacheIsExpire(cacheKey) {
support = true
return
}
@ -57,7 +82,7 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
getEndpointRequest.Product = "Location"
getEndpointRequest.Version = "2015-06-12"
getEndpointRequest.ApiName = "DescribeEndpoints"
getEndpointRequest.Domain = "location.aliyuncs.com"
getEndpointRequest.Domain = "location-readonly.aliyuncs.com"
getEndpointRequest.Method = "GET"
getEndpointRequest.Scheme = requests.HTTPS
@ -70,13 +95,23 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
}
response, err := param.CommonApi(getEndpointRequest)
var getEndpointResponse GetEndpointResponse
if err != nil {
support = false
return
}
if !response.IsSuccess() {
support = false
return
}
json.Unmarshal([]byte(response.GetHttpContentString()), &getEndpointResponse)
var getEndpointResponse GetEndpointResponse
err = json.Unmarshal([]byte(response.GetHttpContentString()), &getEndpointResponse)
if err != nil {
support = false
return
}
if !getEndpointResponse.Success || getEndpointResponse.Endpoints == nil {
support = false
return
@ -87,12 +122,8 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
}
if len(getEndpointResponse.Endpoints.Endpoint[0].Endpoint) > 0 {
endpoint = getEndpointResponse.Endpoints.Endpoint[0].Endpoint
endpointCache.Lock()
endpointCache.cache[cacheKey] = endpoint
endpointCache.Unlock()
lastClearTimePerProduct.Lock()
lastClearTimePerProduct.cache[cacheKey] = time.Now().Unix()
lastClearTimePerProduct.Unlock()
endpointCache.Set(cacheKey, endpoint)
lastClearTimePerProduct.Set(cacheKey, time.Now().Unix())
support = true
return
}
@ -101,13 +132,16 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
return
}
// CheckCacheIsExpire ...
func CheckCacheIsExpire(cacheKey string) bool {
lastClearTime := lastClearTimePerProduct.cache[cacheKey]
lastClearTime, ok := lastClearTimePerProduct.Get(cacheKey).(int64)
if !ok {
return true
}
if lastClearTime <= 0 {
lastClearTime = time.Now().Unix()
lastClearTimePerProduct.Lock()
lastClearTimePerProduct.cache[cacheKey] = lastClearTime
lastClearTimePerProduct.Unlock()
lastClearTimePerProduct.Set(cacheKey, lastClearTime)
}
now := time.Now().Unix()
@ -119,18 +153,21 @@ func CheckCacheIsExpire(cacheKey string) bool {
return false
}
// GetEndpointResponse ...
type GetEndpointResponse struct {
Endpoints *EndpointsObj
RequestId string
Success bool
}
// EndpointsObj ...
type EndpointsObj struct {
Endpoint []EndpointObj
}
// EndpointObj ...
type EndpointObj struct {
Protocols map[string]string
// Protocols map[string]string
Type string
Namespace string
Id string

View file

@ -23,15 +23,24 @@ const keyFormatter = "%s::%s"
var endpointMapping = make(map[string]string)
// AddEndpointMapping Use product id and region id as key to store the endpoint into inner map
func AddEndpointMapping(regionId, productId, endpoint string) (err error) {
key := fmt.Sprintf(keyFormatter, strings.ToLower(regionId), strings.ToLower(productId))
endpointMapping[key] = endpoint
return nil
}
// MappingResolver the mapping resolver type
type MappingResolver struct {
}
// GetName get the resolver name: "mapping resolver"
func (resolver *MappingResolver) GetName() (name string) {
name = "mapping resolver"
return
}
// TryResolve use Product and RegionId as key to find endpoint from inner map
func (resolver *MappingResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
key := fmt.Sprintf(keyFormatter, strings.ToLower(param.RegionId), strings.ToLower(param.Product))
endpoint, contains := endpointMapping[key]

View file

@ -17,12 +17,20 @@ package endpoints
import (
"encoding/json"
"fmt"
"sync"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"sync"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
var debug utils.Debug
func init() {
debug = utils.Init("sdk")
}
const (
ResolveEndpointUserGuideLink = ""
)
@ -32,20 +40,30 @@ var resolvers []Resolver
type Resolver interface {
TryResolve(param *ResolveParam) (endpoint string, support bool, err error)
GetName() (name string)
}
// Resolve resolve endpoint with params
// It will resolve with each supported resolver until anyone resolved
func Resolve(param *ResolveParam) (endpoint string, err error) {
supportedResolvers := getAllResolvers()
var lastErr error
for _, resolver := range supportedResolvers {
endpoint, supported, err := resolver.TryResolve(param)
endpoint, supported, resolveErr := resolver.TryResolve(param)
if resolveErr != nil {
lastErr = resolveErr
}
if supported {
return endpoint, err
debug("resolve endpoint with %s\n", param)
debug("\t%s by resolver(%s)\n", endpoint, resolver.GetName())
return endpoint, nil
}
}
// not support
errorMsg := fmt.Sprintf(errors.CanNotResolveEndpointErrorMessage, param, ResolveEndpointUserGuideLink)
err = errors.NewClientError(errors.CanNotResolveEndpointErrorCode, errorMsg, nil)
err = errors.NewClientError(errors.CanNotResolveEndpointErrorCode, errorMsg, lastErr)
return
}

View file

@ -14,9 +14,17 @@
package endpoints
// SimpleHostResolver the simple host resolver type
type SimpleHostResolver struct {
}
// GetName get the resolver name: "simple host resolver"
func (resolver *SimpleHostResolver) GetName() (name string) {
name = "simple host resolver"
return
}
// TryResolve if the Domain exist in param, use it as endpoint
func (resolver *SimpleHostResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
if support = len(param.Domain) > 0; support {
endpoint = param.Domain

View file

@ -60,7 +60,7 @@ func NewClientError(errorCode, message string, originErr error) Error {
}
func (err *ClientError) Error() string {
clientErrMsg := fmt.Sprintf("[%s] %s", err.errorCode, err.message)
clientErrMsg := fmt.Sprintf("[%s] %s", err.ErrorCode(), err.message)
if err.originError != nil {
return clientErrMsg + "\ncaused by:\n" + err.originError.Error()
}

View file

@ -17,6 +17,7 @@ package errors
import (
"encoding/json"
"fmt"
"github.com/jmespath/go-jmespath"
)
@ -35,7 +36,7 @@ type ServerError struct {
}
type ServerErrorWrapper interface {
tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError)
tryWrap(error *ServerError, wrapInfo map[string]string) bool
}
func (err *ServerError) Error() string {
@ -81,9 +82,9 @@ func NewServerError(httpStatus int, responseContent, comment string) Error {
func WrapServerError(originError *ServerError, wrapInfo map[string]string) *ServerError {
for _, wrapper := range wrapperList {
ok, newError := wrapper.tryWrap(originError, wrapInfo)
ok := wrapper.tryWrap(originError, wrapInfo)
if ok {
return newError
return originError
}
}
return originError

View file

@ -1,29 +1,45 @@
package errors
import "strings"
import (
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
const SignatureDostNotMatchErrorCode = "SignatureDoesNotMatch"
const MessagePrefix = "Specified signature is not matched with our calculation. server string to sign is:"
const IncompleteSignatureErrorCode = "IncompleteSignature"
const MessageContain = "server string to sign is:"
var debug utils.Debug
func init() {
debug = utils.Init("sdk")
}
type SignatureDostNotMatchWrapper struct {
}
func (*SignatureDostNotMatchWrapper) tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError) {
func (*SignatureDostNotMatchWrapper) tryWrap(error *ServerError, wrapInfo map[string]string) (ok bool) {
clientStringToSign := wrapInfo["StringToSign"]
if error.errorCode == SignatureDostNotMatchErrorCode && clientStringToSign != "" {
if (error.errorCode == SignatureDostNotMatchErrorCode || error.errorCode == IncompleteSignatureErrorCode) && clientStringToSign != "" {
message := error.message
if strings.HasPrefix(message, MessagePrefix) {
serverStringToSign := message[len(MessagePrefix):]
if strings.Contains(message, MessageContain) {
str := strings.Split(message, MessageContain)
serverStringToSign := str[1]
if clientStringToSign == serverStringToSign {
// user secret is error
error.recommend = "Please check you AccessKeySecret"
error.recommend = "InvalidAccessKeySecret: Please check you AccessKeySecret"
} else {
debug("Client StringToSign: %s", clientStringToSign)
debug("Server StringToSign: %s", serverStringToSign)
error.recommend = "This may be a bug with the SDK and we hope you can submit this question in the " +
"github issue(https://github.com/aliyun/alibaba-cloud-sdk-go/issues), thanks very much"
}
}
return true, error
} else {
return false, nil
ok = true
return
}
ok = false
return
}

View file

@ -0,0 +1,116 @@
package sdk
import (
"encoding/json"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
"io"
"log"
"os"
"strings"
"time"
)
var logChannel string
var defaultChannel = "AlibabaCloud"
type Logger struct {
*log.Logger
formatTemplate string
isOpen bool
lastLogMsg string
}
var defaultLoggerTemplate = `{time} {channel}: "{method} {uri} HTTP/{version}" {code} {cost} {hostname}`
var loggerParam = []string{"{time}", "{start_time}", "{ts}", "{channel}", "{pid}", "{host}", "{method}", "{uri}", "{version}", "{target}", "{hostname}", "{code}", "{error}", "{req_headers}", "{res_headers}", "{cost}"}
func initLogMsg(fieldMap map[string]string) {
for _, value := range loggerParam {
fieldMap[value] = ""
}
}
func (client *Client) GetLogger() *Logger {
return client.logger
}
func (client *Client) GetLoggerMsg() string {
if client.logger == nil {
client.SetLogger("", "", os.Stdout, "")
}
return client.logger.lastLogMsg
}
func (client *Client) SetLogger(level string, channel string, out io.Writer, template string) {
if level == "" {
level = "info"
}
logChannel = "AlibabaCloud"
if channel != "" {
logChannel = channel
}
log := log.New(out, "["+strings.ToUpper(level)+"]", log.Lshortfile)
if template == "" {
template = defaultLoggerTemplate
}
client.logger = &Logger{
Logger: log,
formatTemplate: template,
isOpen: true,
}
}
func (client *Client) OpenLogger() {
if client.logger == nil {
client.SetLogger("", "", os.Stdout, "")
}
client.logger.isOpen = true
}
func (client *Client) CloseLogger() {
if client.logger != nil {
client.logger.isOpen = false
}
}
func (client *Client) SetTemplate(template string) {
if client.logger == nil {
client.SetLogger("", "", os.Stdout, "")
}
client.logger.formatTemplate = template
}
func (client *Client) GetTemplate() string {
if client.logger == nil {
client.SetLogger("", "", os.Stdout, "")
}
return client.logger.formatTemplate
}
func TransToString(object interface{}) string {
byt, err := json.Marshal(object)
if err != nil {
return ""
}
return string(byt)
}
func (client *Client) printLog(fieldMap map[string]string, err error) {
if err != nil {
fieldMap["{error}"] = err.Error()
}
fieldMap["{time}"] = time.Now().Format("2006-01-02 15:04:05")
fieldMap["{ts}"] = utils.GetTimeInFormatISO8601()
fieldMap["{channel}"] = logChannel
if client.logger != nil {
logMsg := client.logger.formatTemplate
for key, value := range fieldMap {
logMsg = strings.Replace(logMsg, key, value, -1)
}
client.logger.lastLogMsg = logMsg
if client.logger.isOpen == true {
client.logger.Output(2, logMsg)
}
}
}

View file

@ -15,11 +15,15 @@
package requests
import (
"encoding/json"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"io"
"reflect"
"strconv"
"strings"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
)
const (
@ -58,8 +62,6 @@ type AcsRequest interface {
GetDomain() string
GetPort() string
GetRegionId() string
GetUrl() string
GetQueries() string
GetHeaders() map[string]string
GetQueryParams() map[string]string
GetFormParams() map[string]string
@ -68,10 +70,19 @@ type AcsRequest interface {
GetStyle() string
GetProduct() string
GetVersion() string
SetVersion(version string)
GetActionName() string
GetAcceptFormat() string
GetLocationServiceCode() string
GetLocationEndpointType() string
GetReadTimeout() time.Duration
GetConnectTimeout() time.Duration
SetReadTimeout(readTimeout time.Duration)
SetConnectTimeout(connectTimeout time.Duration)
SetHTTPSInsecure(isInsecure bool)
GetHTTPSInsecure() *bool
GetUserAgent() map[string]string
SetStringToSign(stringToSign string)
GetStringToSign() string
@ -95,7 +106,11 @@ type baseRequest struct {
Domain string
Port string
RegionId string
ReadTimeout time.Duration
ConnectTimeout time.Duration
isInsecure *bool
userAgent map[string]string
product string
version string
@ -124,10 +139,38 @@ func (request *baseRequest) GetFormParams() map[string]string {
return request.FormParams
}
func (request *baseRequest) GetReadTimeout() time.Duration {
return request.ReadTimeout
}
func (request *baseRequest) GetConnectTimeout() time.Duration {
return request.ConnectTimeout
}
func (request *baseRequest) SetReadTimeout(readTimeout time.Duration) {
request.ReadTimeout = readTimeout
}
func (request *baseRequest) SetConnectTimeout(connectTimeout time.Duration) {
request.ConnectTimeout = connectTimeout
}
func (request *baseRequest) GetHTTPSInsecure() *bool {
return request.isInsecure
}
func (request *baseRequest) SetHTTPSInsecure(isInsecure bool) {
request.isInsecure = &isInsecure
}
func (request *baseRequest) GetContent() []byte {
return request.Content
}
func (request *baseRequest) SetVersion(version string) {
request.version = version
}
func (request *baseRequest) GetVersion() string {
return request.version
}
@ -140,6 +183,28 @@ func (request *baseRequest) SetContent(content []byte) {
request.Content = content
}
func (request *baseRequest) GetUserAgent() map[string]string {
return request.userAgent
}
func (request *baseRequest) AppendUserAgent(key, value string) {
newkey := true
if request.userAgent == nil {
request.userAgent = make(map[string]string)
}
if strings.ToLower(key) != "core" && strings.ToLower(key) != "go" {
for tag, _ := range request.userAgent {
if tag == key {
request.userAgent[tag] = value
newkey = false
}
}
if newkey {
request.userAgent[key] = value
}
}
}
func (request *baseRequest) addHeaderParam(key, value string) {
request.Headers[key] = value
}
@ -201,7 +266,7 @@ func (request *baseRequest) GetHeaders() map[string]string {
}
func (request *baseRequest) SetContentType(contentType string) {
request.Headers["Content-Type"] = contentType
request.addHeaderParam("Content-Type", contentType)
}
func (request *baseRequest) GetContentType() (contentType string, contains bool) {
@ -254,6 +319,10 @@ func flatRepeatedList(dataValue reflect.Value, request AcsRequest, position, pre
// simple param
key := prefix + name
value := dataValue.Field(i).String()
if dataValue.Field(i).Kind().String() == "map" {
byt, _ := json.Marshal(dataValue.Field(i).Interface())
value = string(byt)
}
err = addParam(request, fieldPosition, key, value)
if err != nil {
return
@ -269,7 +338,7 @@ func flatRepeatedList(dataValue reflect.Value, request AcsRequest, position, pre
for m := 0; m < repeatedFieldValue.Len(); m++ {
elementValue := repeatedFieldValue.Index(m)
key := prefix + name + "." + strconv.Itoa(m+1)
if elementValue.Type().String() == "string" {
if elementValue.Type().Kind().String() == "string" {
value := elementValue.String()
err = addParam(request, fieldPosition, key, value)
if err != nil {

View file

@ -3,8 +3,8 @@ package requests
import (
"bytes"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"io"
"sort"
"strings"
)
@ -14,6 +14,7 @@ type CommonRequest struct {
Version string
ApiName string
Product string
ServiceCode string
// roa params
PathPattern string
@ -33,22 +34,27 @@ func NewCommonRequest() (request *CommonRequest) {
func (request *CommonRequest) String() string {
request.TransToAcsRequest()
request.BuildQueries()
request.BuildUrl()
resultBuilder := bytes.Buffer{}
mapOutput := func(m map[string]string) {
if len(m) > 0 {
for key, value := range m {
resultBuilder.WriteString(key + ": " + value + "\n")
sortedKeys := make([]string, 0)
for k := range m {
sortedKeys = append(sortedKeys, k)
}
// sort 'string' key in increasing order
sort.Strings(sortedKeys)
for _, key := range sortedKeys {
resultBuilder.WriteString(key + ": " + m[key] + "\n")
}
}
}
// Request Line
resultBuilder.WriteString("\n")
resultBuilder.WriteString(fmt.Sprintf("%s %s %s/1.1\n", request.Method, request.GetQueries(), strings.ToUpper(request.Scheme)))
resultBuilder.WriteString(fmt.Sprintf("%s %s %s/1.1\n", request.Method, request.BuildQueries(), strings.ToUpper(request.Scheme)))
// Headers
resultBuilder.WriteString("Host" + ": " + request.Domain + "\n")
@ -66,16 +72,6 @@ func (request *CommonRequest) String() string {
}
func (request *CommonRequest) TransToAcsRequest() {
if len(request.Version) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "Common request [version] is required", nil)
}
if len(request.ApiName) == 0 && len(request.PathPattern) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "At least one of [ApiName] and [PathPattern] should has a value", nil)
}
if len(request.Domain) == 0 && len(request.Product) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "At least one of [Domain] and [Product] should has a value", nil)
}
if len(request.PathPattern) > 0 {
roaRequest := &RoaRequest{}
roaRequest.initWithCommonRequest(request)
@ -85,36 +81,20 @@ func (request *CommonRequest) TransToAcsRequest() {
rpcRequest.baseRequest = request.baseRequest
rpcRequest.product = request.Product
rpcRequest.version = request.Version
rpcRequest.locationServiceCode = request.ServiceCode
rpcRequest.actionName = request.ApiName
request.Ontology = rpcRequest
}
}
func (request *CommonRequest) BuildUrl() string {
if len(request.Port) > 0 {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.BuildQueries()
}
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.BuildQueries()
return request.Ontology.BuildUrl()
}
func (request *CommonRequest) BuildQueries() string {
return request.Ontology.BuildQueries()
}
func (request *CommonRequest) GetUrl() string {
if len(request.Port) > 0 {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
}
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.GetQueries()
}
func (request *CommonRequest) GetQueries() string {
return request.Ontology.GetQueries()
}
func (request *CommonRequest) GetBodyReader() io.Reader {
return request.Ontology.GetBodyReader()
}

View file

@ -16,11 +16,13 @@ package requests
import (
"bytes"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
"fmt"
"io"
"net/url"
"sort"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
type RoaRequest struct {
@ -44,29 +46,23 @@ func (request *RoaRequest) GetBodyReader() io.Reader {
}
}
func (request *RoaRequest) GetQueries() string {
return request.queries
}
// for sign method, need not url encoded
func (request *RoaRequest) BuildQueries() string {
return request.buildQueries(false)
return request.buildQueries()
}
func (request *RoaRequest) buildQueries(needParamEncode bool) string {
// replace path params with value
func (request *RoaRequest) buildPath() string {
path := request.pathPattern
for key, value := range request.PathParams {
path = strings.Replace(path, "["+key+"]", value, 1)
}
return path
}
func (request *RoaRequest) buildQueries() string {
// replace path params with value
path := request.buildPath()
queryParams := request.QueryParams
// check if path contains params
splitArray := strings.Split(path, "?")
path = splitArray[0]
if len(splitArray) > 1 && len(splitArray[1]) > 0 {
queryParams[splitArray[1]] = ""
}
// sort QueryParams by key
var queryKeys []string
for key := range queryParams {
@ -85,20 +81,25 @@ func (request *RoaRequest) buildQueries(needParamEncode bool) string {
urlBuilder.WriteString(queryKey)
if value := queryParams[queryKey]; len(value) > 0 {
urlBuilder.WriteString("=")
if needParamEncode {
urlBuilder.WriteString(url.QueryEscape(value))
} else {
urlBuilder.WriteString(value)
}
}
if i < len(queryKeys)-1 {
urlBuilder.WriteString("&")
}
}
result := urlBuilder.String()
result = popStandardUrlencode(result)
request.queries = result
return request.queries
return result
}
func (request *RoaRequest) buildQueryString() string {
queryParams := request.QueryParams
// sort QueryParams by key
q := url.Values{}
for key, value := range queryParams {
q.Add(key, value)
}
return q.Encode()
}
func popStandardUrlencode(stringToSign string) (result string) {
@ -108,13 +109,18 @@ func popStandardUrlencode(stringToSign string) (result string) {
return
}
func (request *RoaRequest) GetUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
}
func (request *RoaRequest) BuildUrl() string {
// for network trans, need url encoded
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.buildQueries(true)
scheme := strings.ToLower(request.Scheme)
domain := request.Domain
port := request.Port
path := request.buildPath()
url := fmt.Sprintf("%s://%s:%s%s", scheme, domain, port, path)
querystring := request.buildQueryString()
if len(querystring) > 0 {
url = fmt.Sprintf("%s?%s", url, querystring)
}
return url
}
func (request *RoaRequest) addPathParam(key, value string) {
@ -128,19 +134,19 @@ func (request *RoaRequest) InitWithApiInfo(product, version, action, uriPattern,
request.pathPattern = uriPattern
request.locationServiceCode = serviceCode
request.locationEndpointType = endpointType
//request.product = product
request.product = product
//request.version = version
//request.actionName = action
request.actionName = action
}
func (request *RoaRequest) initWithCommonRequest(commonRequest *CommonRequest) {
request.baseRequest = commonRequest.baseRequest
request.PathParams = commonRequest.PathParams
//request.product = commonRequest.Product
request.product = commonRequest.Product
//request.version = commonRequest.Version
request.Headers["x-acs-version"] = commonRequest.Version
//request.actionName = commonRequest.ApiName
request.actionName = commonRequest.ApiName
request.pathPattern = commonRequest.PathPattern
request.locationServiceCode = ""
request.locationServiceCode = commonRequest.ServiceCode
request.locationEndpointType = ""
}

View file

@ -15,9 +15,11 @@
package requests
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
"fmt"
"io"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
type RpcRequest struct {
@ -47,16 +49,12 @@ func (request *RpcRequest) BuildQueries() string {
return request.queries
}
func (request *RpcRequest) GetQueries() string {
return request.queries
}
func (request *RpcRequest) BuildUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.BuildQueries()
}
func (request *RpcRequest) GetUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.GetQueries()
url := fmt.Sprintf("%s://%s", strings.ToLower(request.Scheme), request.Domain)
if len(request.Port) > 0 {
url = fmt.Sprintf("%s:%s", url, request.Port)
}
return url + request.BuildQueries()
}
func (request *RpcRequest) GetVersion() string {

View file

@ -2,13 +2,13 @@ package responses
import (
"encoding/json"
"github.com/json-iterator/go"
"io"
"math"
"strconv"
"strings"
"sync"
"unsafe"
jsoniter "github.com/json-iterator/go"
)
const maxUint = ^uint(0)
@ -16,13 +16,15 @@ const maxInt = int(maxUint >> 1)
const minInt = -maxInt - 1
var jsonParser jsoniter.API
var initJson = &sync.Once{}
func initJsonParserOnce() {
initJson.Do(func() {
func init() {
registerBetterFuzzyDecoder()
jsonParser = jsoniter.ConfigCompatibleWithStandardLibrary
})
jsonParser = jsoniter.Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
CaseSensitive: true,
}.Froze()
}
func registerBetterFuzzyDecoder() {
@ -211,21 +213,6 @@ func (decoder *fuzzyBoolDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Itera
}
}
type tolerateEmptyArrayDecoder struct {
valDecoder jsoniter.ValDecoder
}
func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if iter.WhatIsNext() == jsoniter.ArrayValue {
iter.Skip()
newIter := iter.Pool().BorrowIterator([]byte("{}"))
defer iter.Pool().ReturnIterator(newIter)
decoder.valDecoder.Decode(ptr, newIter)
} else {
decoder.valDecoder.Decode(ptr, iter)
}
}
type nullableFuzzyIntegerDecoder struct {
fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator)
}
@ -336,6 +323,6 @@ func (decoder *nullableFuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jso
iter.ReadNil()
*((*float64)(ptr)) = 0
default:
iter.ReportError("nullableFuzzyFloat32Decoder", "not number or string")
iter.ReportError("nullableFuzzyFloat64Decoder", "not number or string")
}
}

View file

@ -18,10 +18,12 @@ import (
"bytes"
"encoding/xml"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"io/ioutil"
"net/http"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
)
type AcsResponse interface {
@ -34,6 +36,13 @@ type AcsResponse interface {
parseFromHttpResponse(httpResponse *http.Response) error
}
var debug utils.Debug
func init() {
debug = utils.Init("sdk")
}
// Unmarshal object from http response body to target Response
func Unmarshal(response AcsResponse, httpResponse *http.Response, format string) (err error) {
err = response.parseFromHttpResponse(httpResponse)
if err != nil {
@ -43,7 +52,8 @@ func Unmarshal(response AcsResponse, httpResponse *http.Response, format string)
err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), "")
return
}
if _, isCommonResponse := response.(CommonResponse); isCommonResponse {
if _, isCommonResponse := response.(*CommonResponse); isCommonResponse {
// common response need not unmarshal
return
}
@ -53,7 +63,6 @@ func Unmarshal(response AcsResponse, httpResponse *http.Response, format string)
}
if strings.ToUpper(format) == "JSON" {
initJsonParserOnce()
err = jsonParser.Unmarshal(response.GetHttpContentBytes(), response)
if err != nil {
err = errors.NewClientError(errors.JsonUnmarshalErrorCode, errors.JsonUnmarshalErrorMessage, err)
@ -106,6 +115,7 @@ func (baseResponse *BaseResponse) parseFromHttpResponse(httpResponse *http.Respo
if err != nil {
return
}
debug("%s", string(body))
baseResponse.httpStatus = httpResponse.StatusCode
baseResponse.httpHeaders = httpResponse.Header
baseResponse.httpContentBytes = body
@ -117,7 +127,7 @@ func (baseResponse *BaseResponse) parseFromHttpResponse(httpResponse *http.Respo
func (baseResponse *BaseResponse) String() string {
resultBuilder := bytes.Buffer{}
// statusCode
resultBuilder.WriteString("\n")
// resultBuilder.WriteString("\n")
resultBuilder.WriteString(fmt.Sprintf("%s %s\n", baseResponse.originHttpResponse.Proto, baseResponse.originHttpResponse.Status))
// httpHeaders
//resultBuilder.WriteString("Headers:\n")

View file

@ -0,0 +1,36 @@
package utils
import (
"fmt"
"os"
"strings"
)
type Debug func(format string, v ...interface{})
var hookGetEnv = func() string {
return os.Getenv("DEBUG")
}
var hookPrint = func(input string) {
fmt.Println(input)
}
func Init(flag string) Debug {
enable := false
env := hookGetEnv()
parts := strings.Split(env, ",")
for _, part := range parts {
if part == flag {
enable = true
break
}
}
return func(format string, v ...interface{}) {
if enable {
hookPrint(fmt.Sprintf(format, v...))
}
}
}

View file

@ -16,27 +16,35 @@ package utils
import (
"crypto/md5"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/satori/go.uuid"
"hash"
rand2 "math/rand"
"net/url"
"reflect"
"strconv"
"time"
)
// if you use go 1.10 or higher, you can hack this util by these to avoid "TimeZone.zip not found" on Windows
var LoadLocationFromTZData func(name string, data []byte) (*time.Location, error) = nil
var TZData []byte = nil
type UUID [16]byte
func GetUUIDV4() (uuidHex string) {
uuidV4 := uuid.NewV4()
uuidHex = hex.EncodeToString(uuidV4.Bytes())
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func GetUUID() (uuidHex string) {
uuid := NewUUID()
uuidHex = hex.EncodeToString(uuid[:])
return
}
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand2.Intn(len(letterBytes))]
}
return string(b)
}
func GetMD5Base64(bytes []byte) (base64Value string) {
md5Ctx := md5.New()
md5Ctx.Write(bytes)
@ -45,29 +53,15 @@ func GetMD5Base64(bytes []byte) (base64Value string) {
return
}
func GetGMTLocation() (*time.Location, error) {
if LoadLocationFromTZData != nil && TZData != nil {
return LoadLocationFromTZData("GMT", TZData)
} else {
return time.LoadLocation("GMT")
}
}
func GetTimeInFormatISO8601() (timeStr string) {
gmt, err := GetGMTLocation()
gmt := time.FixedZone("GMT", 0)
if err != nil {
panic(err)
}
return time.Now().In(gmt).Format("2006-01-02T15:04:05Z")
}
func GetTimeInFormatRFC2616() (timeStr string) {
gmt, err := GetGMTLocation()
gmt := time.FixedZone("GMT", 0)
if err != nil {
panic(err)
}
return time.Now().In(gmt).Format("Mon, 02 Jan 2006 15:04:05 GMT")
}
@ -80,17 +74,6 @@ func GetUrlFormedMap(source map[string]string) (urlEncoded string) {
return
}
func GetFromJsonString(jsonString, key string) (result string, err error) {
var responseMap map[string]*json.RawMessage
err = json.Unmarshal([]byte(jsonString), &responseMap)
if err != nil {
return
}
fmt.Println(string(*responseMap[key]))
err = json.Unmarshal(*responseMap[key], &result)
return
}
func InitStructWithDefaultTag(bean interface{}) {
configType := reflect.TypeOf(bean)
for i := 0; i < configType.Elem().NumField(); i++ {
@ -115,3 +98,44 @@ func InitStructWithDefaultTag(bean interface{}) {
}
}
}
func NewUUID() UUID {
ns := UUID{}
safeRandom(ns[:])
u := newFromHash(md5.New(), ns, RandStringBytes(16))
u[6] = (u[6] & 0x0f) | (byte(2) << 4)
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
return u
}
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
u := UUID{}
h.Write(ns[:])
h.Write([]byte(name))
copy(u[:], h.Sum(nil))
return u
}
func safeRandom(dest []byte) {
if _, err := rand.Read(dest); err != nil {
panic(err)
}
}
func (u UUID) String() string {
buf := make([]byte, 36)
hex.Encode(buf[0:8], u[0:4])
buf[8] = '-'
hex.Encode(buf[9:13], u[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], u[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], u[8:10])
buf[23] = '-'
hex.Encode(buf[24:], u[10:])
return string(buf)
}

View file

@ -1,106 +0,0 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// AddBatchDomainRecords invokes the alidns.AddBatchDomainRecords API synchronously
// api document: https://help.aliyun.com/api/alidns/addbatchdomainrecords.html
func (client *Client) AddBatchDomainRecords(request *AddBatchDomainRecordsRequest) (response *AddBatchDomainRecordsResponse, err error) {
response = CreateAddBatchDomainRecordsResponse()
err = client.DoAction(request, response)
return
}
// AddBatchDomainRecordsWithChan invokes the alidns.AddBatchDomainRecords API asynchronously
// api document: https://help.aliyun.com/api/alidns/addbatchdomainrecords.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddBatchDomainRecordsWithChan(request *AddBatchDomainRecordsRequest) (<-chan *AddBatchDomainRecordsResponse, <-chan error) {
responseChan := make(chan *AddBatchDomainRecordsResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.AddBatchDomainRecords(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// AddBatchDomainRecordsWithCallback invokes the alidns.AddBatchDomainRecords API asynchronously
// api document: https://help.aliyun.com/api/alidns/addbatchdomainrecords.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddBatchDomainRecordsWithCallback(request *AddBatchDomainRecordsRequest, callback func(response *AddBatchDomainRecordsResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *AddBatchDomainRecordsResponse
var err error
defer close(result)
response, err = client.AddBatchDomainRecords(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// AddBatchDomainRecordsRequest is the request struct for api AddBatchDomainRecords
type AddBatchDomainRecordsRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Records string `position:"Query" name:"Records"`
}
// AddBatchDomainRecordsResponse is the response struct for api AddBatchDomainRecords
type AddBatchDomainRecordsResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
TraceId string `json:"TraceId" xml:"TraceId"`
}
// CreateAddBatchDomainRecordsRequest creates a request to invoke AddBatchDomainRecords API
func CreateAddBatchDomainRecordsRequest() (request *AddBatchDomainRecordsRequest) {
request = &AddBatchDomainRecordsRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "AddBatchDomainRecords", "", "")
return
}
// CreateAddBatchDomainRecordsResponse creates a response to parse from AddBatchDomainRecords response
func CreateAddBatchDomainRecordsResponse() (response *AddBatchDomainRecordsResponse) {
response = &AddBatchDomainRecordsResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -76,10 +76,9 @@ func (client *Client) AddDomainWithCallback(request *AddDomainRequest, callback
// AddDomainRequest is the request struct for api AddDomain
type AddDomainRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
GroupId string `position:"Query" name:"GroupId"`
DomainName string `position:"Query" name:"DomainName"`
Lang string `position:"Query" name:"Lang"`
}
// AddDomainResponse is the response struct for api AddDomain
@ -99,7 +98,7 @@ func CreateAddDomainRequest() (request *AddDomainRequest) {
request = &AddDomainRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "AddDomain", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "AddDomain", "alidns", "openAPI")
return
}

View file

@ -76,8 +76,8 @@ func (client *Client) AddDomainGroupWithCallback(request *AddDomainGroupRequest,
// AddDomainGroupRequest is the request struct for api AddDomainGroup
type AddDomainGroupRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Lang string `position:"Query" name:"Lang"`
GroupName string `position:"Query" name:"GroupName"`
}
@ -94,7 +94,7 @@ func CreateAddDomainGroupRequest() (request *AddDomainGroupRequest) {
request = &AddDomainGroupRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "AddDomainGroup", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "AddDomainGroup", "alidns", "openAPI")
return
}

View file

@ -76,15 +76,15 @@ func (client *Client) AddDomainRecordWithCallback(request *AddDomainRecordReques
// AddDomainRecordRequest is the request struct for api AddDomainRecord
type AddDomainRecordRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
RR string `position:"Query" name:"RR"`
Line string `position:"Query" name:"Line"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
RR string `position:"Query" name:"RR"`
Lang string `position:"Query" name:"Lang"`
Type string `position:"Query" name:"Type"`
Priority requests.Integer `position:"Query" name:"Priority"`
Value string `position:"Query" name:"Value"`
TTL requests.Integer `position:"Query" name:"TTL"`
Priority requests.Integer `position:"Query" name:"Priority"`
Line string `position:"Query" name:"Line"`
}
// AddDomainRecordResponse is the response struct for api AddDomainRecord
@ -99,7 +99,7 @@ func CreateAddDomainRecordRequest() (request *AddDomainRecordRequest) {
request = &AddDomainRecordRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "AddDomainRecord", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "AddDomainRecord", "alidns", "openAPI")
return
}

View file

@ -0,0 +1,110 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// AddGtmAccessStrategy invokes the alidns.AddGtmAccessStrategy API synchronously
// api document: https://help.aliyun.com/api/alidns/addgtmaccessstrategy.html
func (client *Client) AddGtmAccessStrategy(request *AddGtmAccessStrategyRequest) (response *AddGtmAccessStrategyResponse, err error) {
response = CreateAddGtmAccessStrategyResponse()
err = client.DoAction(request, response)
return
}
// AddGtmAccessStrategyWithChan invokes the alidns.AddGtmAccessStrategy API asynchronously
// api document: https://help.aliyun.com/api/alidns/addgtmaccessstrategy.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddGtmAccessStrategyWithChan(request *AddGtmAccessStrategyRequest) (<-chan *AddGtmAccessStrategyResponse, <-chan error) {
responseChan := make(chan *AddGtmAccessStrategyResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.AddGtmAccessStrategy(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// AddGtmAccessStrategyWithCallback invokes the alidns.AddGtmAccessStrategy API asynchronously
// api document: https://help.aliyun.com/api/alidns/addgtmaccessstrategy.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddGtmAccessStrategyWithCallback(request *AddGtmAccessStrategyRequest, callback func(response *AddGtmAccessStrategyResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *AddGtmAccessStrategyResponse
var err error
defer close(result)
response, err = client.AddGtmAccessStrategy(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// AddGtmAccessStrategyRequest is the request struct for api AddGtmAccessStrategy
type AddGtmAccessStrategyRequest struct {
*requests.RpcRequest
StrategyName string `position:"Query" name:"StrategyName"`
DefaultAddrPoolId string `position:"Query" name:"DefaultAddrPoolId"`
AccessLines string `position:"Query" name:"AccessLines"`
InstanceId string `position:"Query" name:"InstanceId"`
FailoverAddrPoolId string `position:"Query" name:"FailoverAddrPoolId"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Lang string `position:"Query" name:"Lang"`
}
// AddGtmAccessStrategyResponse is the response struct for api AddGtmAccessStrategy
type AddGtmAccessStrategyResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
StrategyId string `json:"StrategyId" xml:"StrategyId"`
}
// CreateAddGtmAccessStrategyRequest creates a request to invoke AddGtmAccessStrategy API
func CreateAddGtmAccessStrategyRequest() (request *AddGtmAccessStrategyRequest) {
request = &AddGtmAccessStrategyRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "AddGtmAccessStrategy", "alidns", "openAPI")
return
}
// CreateAddGtmAccessStrategyResponse creates a response to parse from AddGtmAccessStrategy response
func CreateAddGtmAccessStrategyResponse() (response *AddGtmAccessStrategyResponse) {
response = &AddGtmAccessStrategyResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -0,0 +1,117 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// AddGtmAddressPool invokes the alidns.AddGtmAddressPool API synchronously
// api document: https://help.aliyun.com/api/alidns/addgtmaddresspool.html
func (client *Client) AddGtmAddressPool(request *AddGtmAddressPoolRequest) (response *AddGtmAddressPoolResponse, err error) {
response = CreateAddGtmAddressPoolResponse()
err = client.DoAction(request, response)
return
}
// AddGtmAddressPoolWithChan invokes the alidns.AddGtmAddressPool API asynchronously
// api document: https://help.aliyun.com/api/alidns/addgtmaddresspool.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddGtmAddressPoolWithChan(request *AddGtmAddressPoolRequest) (<-chan *AddGtmAddressPoolResponse, <-chan error) {
responseChan := make(chan *AddGtmAddressPoolResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.AddGtmAddressPool(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// AddGtmAddressPoolWithCallback invokes the alidns.AddGtmAddressPool API asynchronously
// api document: https://help.aliyun.com/api/alidns/addgtmaddresspool.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddGtmAddressPoolWithCallback(request *AddGtmAddressPoolRequest, callback func(response *AddGtmAddressPoolResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *AddGtmAddressPoolResponse
var err error
defer close(result)
response, err = client.AddGtmAddressPool(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// AddGtmAddressPoolRequest is the request struct for api AddGtmAddressPool
type AddGtmAddressPoolRequest struct {
*requests.RpcRequest
InstanceId string `position:"Query" name:"InstanceId"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Name string `position:"Query" name:"Name"`
Lang string `position:"Query" name:"Lang"`
Type string `position:"Query" name:"Type"`
Addr *[]AddGtmAddressPoolAddr `position:"Query" name:"Addr" type:"Repeated"`
MinAvailableAddrNum requests.Integer `position:"Query" name:"MinAvailableAddrNum"`
}
// AddGtmAddressPoolAddr is a repeated param struct in AddGtmAddressPoolRequest
type AddGtmAddressPoolAddr struct {
Mode string `name:"Mode"`
LbaWeight string `name:"LbaWeight"`
Value string `name:"Value"`
}
// AddGtmAddressPoolResponse is the response struct for api AddGtmAddressPool
type AddGtmAddressPoolResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
AddrPoolId string `json:"AddrPoolId" xml:"AddrPoolId"`
}
// CreateAddGtmAddressPoolRequest creates a request to invoke AddGtmAddressPool API
func CreateAddGtmAddressPoolRequest() (request *AddGtmAddressPoolRequest) {
request = &AddGtmAddressPoolRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "AddGtmAddressPool", "alidns", "openAPI")
return
}
// CreateAddGtmAddressPoolResponse creates a response to parse from AddGtmAddressPool response
func CreateAddGtmAddressPoolResponse() (response *AddGtmAddressPoolResponse) {
response = &AddGtmAddressPoolResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -0,0 +1,119 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// AddGtmMonitor invokes the alidns.AddGtmMonitor API synchronously
// api document: https://help.aliyun.com/api/alidns/addgtmmonitor.html
func (client *Client) AddGtmMonitor(request *AddGtmMonitorRequest) (response *AddGtmMonitorResponse, err error) {
response = CreateAddGtmMonitorResponse()
err = client.DoAction(request, response)
return
}
// AddGtmMonitorWithChan invokes the alidns.AddGtmMonitor API asynchronously
// api document: https://help.aliyun.com/api/alidns/addgtmmonitor.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddGtmMonitorWithChan(request *AddGtmMonitorRequest) (<-chan *AddGtmMonitorResponse, <-chan error) {
responseChan := make(chan *AddGtmMonitorResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.AddGtmMonitor(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// AddGtmMonitorWithCallback invokes the alidns.AddGtmMonitor API asynchronously
// api document: https://help.aliyun.com/api/alidns/addgtmmonitor.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) AddGtmMonitorWithCallback(request *AddGtmMonitorRequest, callback func(response *AddGtmMonitorResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *AddGtmMonitorResponse
var err error
defer close(result)
response, err = client.AddGtmMonitor(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// AddGtmMonitorRequest is the request struct for api AddGtmMonitor
type AddGtmMonitorRequest struct {
*requests.RpcRequest
MonitorExtendInfo string `position:"Query" name:"MonitorExtendInfo"`
AddrPoolId string `position:"Query" name:"AddrPoolId"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Name string `position:"Query" name:"Name"`
EvaluationCount requests.Integer `position:"Query" name:"EvaluationCount"`
ProtocolType string `position:"Query" name:"ProtocolType"`
Interval requests.Integer `position:"Query" name:"Interval"`
Lang string `position:"Query" name:"Lang"`
Timeout requests.Integer `position:"Query" name:"Timeout"`
IspCityNode *[]AddGtmMonitorIspCityNode `position:"Query" name:"IspCityNode" type:"Repeated"`
}
// AddGtmMonitorIspCityNode is a repeated param struct in AddGtmMonitorRequest
type AddGtmMonitorIspCityNode struct {
CityCode string `name:"CityCode"`
IspCode string `name:"IspCode"`
}
// AddGtmMonitorResponse is the response struct for api AddGtmMonitor
type AddGtmMonitorResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
MonitorConfigId string `json:"MonitorConfigId" xml:"MonitorConfigId"`
}
// CreateAddGtmMonitorRequest creates a request to invoke AddGtmMonitor API
func CreateAddGtmMonitorRequest() (request *AddGtmMonitorRequest) {
request = &AddGtmMonitorRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "AddGtmMonitor", "alidns", "openAPI")
return
}
// CreateAddGtmMonitorResponse creates a response to parse from AddGtmMonitor response
func CreateAddGtmMonitorResponse() (response *AddGtmMonitorResponse) {
response = &AddGtmMonitorResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -1,106 +0,0 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// ApplyForRetrievalDomainName invokes the alidns.ApplyForRetrievalDomainName API synchronously
// api document: https://help.aliyun.com/api/alidns/applyforretrievaldomainname.html
func (client *Client) ApplyForRetrievalDomainName(request *ApplyForRetrievalDomainNameRequest) (response *ApplyForRetrievalDomainNameResponse, err error) {
response = CreateApplyForRetrievalDomainNameResponse()
err = client.DoAction(request, response)
return
}
// ApplyForRetrievalDomainNameWithChan invokes the alidns.ApplyForRetrievalDomainName API asynchronously
// api document: https://help.aliyun.com/api/alidns/applyforretrievaldomainname.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ApplyForRetrievalDomainNameWithChan(request *ApplyForRetrievalDomainNameRequest) (<-chan *ApplyForRetrievalDomainNameResponse, <-chan error) {
responseChan := make(chan *ApplyForRetrievalDomainNameResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.ApplyForRetrievalDomainName(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// ApplyForRetrievalDomainNameWithCallback invokes the alidns.ApplyForRetrievalDomainName API asynchronously
// api document: https://help.aliyun.com/api/alidns/applyforretrievaldomainname.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ApplyForRetrievalDomainNameWithCallback(request *ApplyForRetrievalDomainNameRequest, callback func(response *ApplyForRetrievalDomainNameResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *ApplyForRetrievalDomainNameResponse
var err error
defer close(result)
response, err = client.ApplyForRetrievalDomainName(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// ApplyForRetrievalDomainNameRequest is the request struct for api ApplyForRetrievalDomainName
type ApplyForRetrievalDomainNameRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
}
// ApplyForRetrievalDomainNameResponse is the response struct for api ApplyForRetrievalDomainName
type ApplyForRetrievalDomainNameResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
DomainName string `json:"DomainName" xml:"DomainName"`
}
// CreateApplyForRetrievalDomainNameRequest creates a request to invoke ApplyForRetrievalDomainName API
func CreateApplyForRetrievalDomainNameRequest() (request *ApplyForRetrievalDomainNameRequest) {
request = &ApplyForRetrievalDomainNameRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "ApplyForRetrievalDomainName", "", "")
return
}
// CreateApplyForRetrievalDomainNameResponse creates a response to parse from ApplyForRetrievalDomainName response
func CreateApplyForRetrievalDomainNameResponse() (response *ApplyForRetrievalDomainNameResponse) {
response = &ApplyForRetrievalDomainNameResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -76,10 +76,10 @@ func (client *Client) ChangeDomainGroupWithCallback(request *ChangeDomainGroupRe
// ChangeDomainGroupRequest is the request struct for api ChangeDomainGroup
type ChangeDomainGroupRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
GroupId string `position:"Query" name:"GroupId"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
GroupId string `position:"Query" name:"GroupId"`
Lang string `position:"Query" name:"Lang"`
}
// ChangeDomainGroupResponse is the response struct for api ChangeDomainGroup
@ -95,7 +95,7 @@ func CreateChangeDomainGroupRequest() (request *ChangeDomainGroupRequest) {
request = &ChangeDomainGroupRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "ChangeDomainGroup", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "ChangeDomainGroup", "alidns", "openAPI")
return
}

View file

@ -76,11 +76,11 @@ func (client *Client) ChangeDomainOfDnsProductWithCallback(request *ChangeDomain
// ChangeDomainOfDnsProductRequest is the request struct for api ChangeDomainOfDnsProduct
type ChangeDomainOfDnsProductRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
InstanceId string `position:"Query" name:"InstanceId"`
NewDomain string `position:"Query" name:"NewDomain"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Force requests.Boolean `position:"Query" name:"Force"`
Lang string `position:"Query" name:"Lang"`
}
// ChangeDomainOfDnsProductResponse is the response struct for api ChangeDomainOfDnsProduct
@ -95,7 +95,7 @@ func CreateChangeDomainOfDnsProductRequest() (request *ChangeDomainOfDnsProductR
request = &ChangeDomainOfDnsProductRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "ChangeDomainOfDnsProduct", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "ChangeDomainOfDnsProduct", "alidns", "openAPI")
return
}

View file

@ -76,10 +76,10 @@ func (client *Client) CheckDomainRecordWithCallback(request *CheckDomainRecordRe
// CheckDomainRecordRequest is the request struct for api CheckDomainRecord
type CheckDomainRecordRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
RR string `position:"Query" name:"RR"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
RR string `position:"Query" name:"RR"`
Lang string `position:"Query" name:"Lang"`
Type string `position:"Query" name:"Type"`
Value string `position:"Query" name:"Value"`
}
@ -96,7 +96,7 @@ func CreateCheckDomainRecordRequest() (request *CheckDomainRecordRequest) {
request = &CheckDomainRecordRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "CheckDomainRecord", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "CheckDomainRecord", "alidns", "openAPI")
return
}

View file

@ -0,0 +1,111 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// CreateInstance invokes the alidns.CreateInstance API synchronously
// api document: https://help.aliyun.com/api/alidns/createinstance.html
func (client *Client) CreateInstance(request *CreateInstanceRequest) (response *CreateInstanceResponse, err error) {
response = CreateCreateInstanceResponse()
err = client.DoAction(request, response)
return
}
// CreateInstanceWithChan invokes the alidns.CreateInstance API asynchronously
// api document: https://help.aliyun.com/api/alidns/createinstance.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) CreateInstanceWithChan(request *CreateInstanceRequest) (<-chan *CreateInstanceResponse, <-chan error) {
responseChan := make(chan *CreateInstanceResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.CreateInstance(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// CreateInstanceWithCallback invokes the alidns.CreateInstance API asynchronously
// api document: https://help.aliyun.com/api/alidns/createinstance.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) CreateInstanceWithCallback(request *CreateInstanceRequest, callback func(response *CreateInstanceResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *CreateInstanceResponse
var err error
defer close(result)
response, err = client.CreateInstance(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// CreateInstanceRequest is the request struct for api CreateInstance
type CreateInstanceRequest struct {
*requests.RpcRequest
Month requests.Integer `position:"Query" name:"Month"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
Lang string `position:"Query" name:"Lang"`
InstanceVersion string `position:"Query" name:"InstanceVersion"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
Token string `position:"Query" name:"Token"`
}
// CreateInstanceResponse is the response struct for api CreateInstance
type CreateInstanceResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
OrderId string `json:"OrderId" xml:"OrderId"`
InstanceId string `json:"InstanceId" xml:"InstanceId"`
}
// CreateCreateInstanceRequest creates a request to invoke CreateInstance API
func CreateCreateInstanceRequest() (request *CreateInstanceRequest) {
request = &CreateInstanceRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "CreateInstance", "alidns", "openAPI")
return
}
// CreateCreateInstanceResponse creates a response to parse from CreateInstance response
func CreateCreateInstanceResponse() (response *CreateInstanceResponse) {
response = &CreateInstanceResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -1,106 +0,0 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// DeleteBatchDomainRecords invokes the alidns.DeleteBatchDomainRecords API synchronously
// api document: https://help.aliyun.com/api/alidns/deletebatchdomainrecords.html
func (client *Client) DeleteBatchDomainRecords(request *DeleteBatchDomainRecordsRequest) (response *DeleteBatchDomainRecordsResponse, err error) {
response = CreateDeleteBatchDomainRecordsResponse()
err = client.DoAction(request, response)
return
}
// DeleteBatchDomainRecordsWithChan invokes the alidns.DeleteBatchDomainRecords API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletebatchdomainrecords.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteBatchDomainRecordsWithChan(request *DeleteBatchDomainRecordsRequest) (<-chan *DeleteBatchDomainRecordsResponse, <-chan error) {
responseChan := make(chan *DeleteBatchDomainRecordsResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DeleteBatchDomainRecords(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DeleteBatchDomainRecordsWithCallback invokes the alidns.DeleteBatchDomainRecords API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletebatchdomainrecords.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteBatchDomainRecordsWithCallback(request *DeleteBatchDomainRecordsRequest, callback func(response *DeleteBatchDomainRecordsResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DeleteBatchDomainRecordsResponse
var err error
defer close(result)
response, err = client.DeleteBatchDomainRecords(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DeleteBatchDomainRecordsRequest is the request struct for api DeleteBatchDomainRecords
type DeleteBatchDomainRecordsRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Records string `position:"Query" name:"Records"`
}
// DeleteBatchDomainRecordsResponse is the response struct for api DeleteBatchDomainRecords
type DeleteBatchDomainRecordsResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
TraceId string `json:"TraceId" xml:"TraceId"`
}
// CreateDeleteBatchDomainRecordsRequest creates a request to invoke DeleteBatchDomainRecords API
func CreateDeleteBatchDomainRecordsRequest() (request *DeleteBatchDomainRecordsRequest) {
request = &DeleteBatchDomainRecordsRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteBatchDomainRecords", "", "")
return
}
// CreateDeleteBatchDomainRecordsResponse creates a response to parse from DeleteBatchDomainRecords response
func CreateDeleteBatchDomainRecordsResponse() (response *DeleteBatchDomainRecordsResponse) {
response = &DeleteBatchDomainRecordsResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -1,106 +0,0 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// DeleteBatchDomains invokes the alidns.DeleteBatchDomains API synchronously
// api document: https://help.aliyun.com/api/alidns/deletebatchdomains.html
func (client *Client) DeleteBatchDomains(request *DeleteBatchDomainsRequest) (response *DeleteBatchDomainsResponse, err error) {
response = CreateDeleteBatchDomainsResponse()
err = client.DoAction(request, response)
return
}
// DeleteBatchDomainsWithChan invokes the alidns.DeleteBatchDomains API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletebatchdomains.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteBatchDomainsWithChan(request *DeleteBatchDomainsRequest) (<-chan *DeleteBatchDomainsResponse, <-chan error) {
responseChan := make(chan *DeleteBatchDomainsResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DeleteBatchDomains(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DeleteBatchDomainsWithCallback invokes the alidns.DeleteBatchDomains API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletebatchdomains.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteBatchDomainsWithCallback(request *DeleteBatchDomainsRequest, callback func(response *DeleteBatchDomainsResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DeleteBatchDomainsResponse
var err error
defer close(result)
response, err = client.DeleteBatchDomains(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DeleteBatchDomainsRequest is the request struct for api DeleteBatchDomains
type DeleteBatchDomainsRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Domains string `position:"Query" name:"Domains"`
}
// DeleteBatchDomainsResponse is the response struct for api DeleteBatchDomains
type DeleteBatchDomainsResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
TraceId string `json:"TraceId" xml:"TraceId"`
}
// CreateDeleteBatchDomainsRequest creates a request to invoke DeleteBatchDomains API
func CreateDeleteBatchDomainsRequest() (request *DeleteBatchDomainsRequest) {
request = &DeleteBatchDomainsRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteBatchDomains", "", "")
return
}
// CreateDeleteBatchDomainsResponse creates a response to parse from DeleteBatchDomains response
func CreateDeleteBatchDomainsResponse() (response *DeleteBatchDomainsResponse) {
response = &DeleteBatchDomainsResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -76,9 +76,9 @@ func (client *Client) DeleteDomainWithCallback(request *DeleteDomainRequest, cal
// DeleteDomainRequest is the request struct for api DeleteDomain
type DeleteDomainRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
Lang string `position:"Query" name:"Lang"`
}
// DeleteDomainResponse is the response struct for api DeleteDomain
@ -93,7 +93,7 @@ func CreateDeleteDomainRequest() (request *DeleteDomainRequest) {
request = &DeleteDomainRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteDomain", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteDomain", "alidns", "openAPI")
return
}

View file

@ -76,9 +76,9 @@ func (client *Client) DeleteDomainGroupWithCallback(request *DeleteDomainGroupRe
// DeleteDomainGroupRequest is the request struct for api DeleteDomainGroup
type DeleteDomainGroupRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
GroupId string `position:"Query" name:"GroupId"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Lang string `position:"Query" name:"Lang"`
}
// DeleteDomainGroupResponse is the response struct for api DeleteDomainGroup
@ -93,7 +93,7 @@ func CreateDeleteDomainGroupRequest() (request *DeleteDomainGroupRequest) {
request = &DeleteDomainGroupRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteDomainGroup", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteDomainGroup", "alidns", "openAPI")
return
}

View file

@ -76,9 +76,9 @@ func (client *Client) DeleteDomainRecordWithCallback(request *DeleteDomainRecord
// DeleteDomainRecordRequest is the request struct for api DeleteDomainRecord
type DeleteDomainRecordRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
RecordId string `position:"Query" name:"RecordId"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Lang string `position:"Query" name:"Lang"`
}
// DeleteDomainRecordResponse is the response struct for api DeleteDomainRecord
@ -93,7 +93,7 @@ func CreateDeleteDomainRecordRequest() (request *DeleteDomainRecordRequest) {
request = &DeleteDomainRecordRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteDomainRecord", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteDomainRecord", "alidns", "openAPI")
return
}

View file

@ -0,0 +1,105 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// DeleteGtmAccessStrategy invokes the alidns.DeleteGtmAccessStrategy API synchronously
// api document: https://help.aliyun.com/api/alidns/deletegtmaccessstrategy.html
func (client *Client) DeleteGtmAccessStrategy(request *DeleteGtmAccessStrategyRequest) (response *DeleteGtmAccessStrategyResponse, err error) {
response = CreateDeleteGtmAccessStrategyResponse()
err = client.DoAction(request, response)
return
}
// DeleteGtmAccessStrategyWithChan invokes the alidns.DeleteGtmAccessStrategy API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletegtmaccessstrategy.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteGtmAccessStrategyWithChan(request *DeleteGtmAccessStrategyRequest) (<-chan *DeleteGtmAccessStrategyResponse, <-chan error) {
responseChan := make(chan *DeleteGtmAccessStrategyResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DeleteGtmAccessStrategy(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DeleteGtmAccessStrategyWithCallback invokes the alidns.DeleteGtmAccessStrategy API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletegtmaccessstrategy.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteGtmAccessStrategyWithCallback(request *DeleteGtmAccessStrategyRequest, callback func(response *DeleteGtmAccessStrategyResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DeleteGtmAccessStrategyResponse
var err error
defer close(result)
response, err = client.DeleteGtmAccessStrategy(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DeleteGtmAccessStrategyRequest is the request struct for api DeleteGtmAccessStrategy
type DeleteGtmAccessStrategyRequest struct {
*requests.RpcRequest
UserClientIp string `position:"Query" name:"UserClientIp"`
StrategyId string `position:"Query" name:"StrategyId"`
Lang string `position:"Query" name:"Lang"`
}
// DeleteGtmAccessStrategyResponse is the response struct for api DeleteGtmAccessStrategy
type DeleteGtmAccessStrategyResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateDeleteGtmAccessStrategyRequest creates a request to invoke DeleteGtmAccessStrategy API
func CreateDeleteGtmAccessStrategyRequest() (request *DeleteGtmAccessStrategyRequest) {
request = &DeleteGtmAccessStrategyRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteGtmAccessStrategy", "alidns", "openAPI")
return
}
// CreateDeleteGtmAccessStrategyResponse creates a response to parse from DeleteGtmAccessStrategy response
func CreateDeleteGtmAccessStrategyResponse() (response *DeleteGtmAccessStrategyResponse) {
response = &DeleteGtmAccessStrategyResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -0,0 +1,105 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// DeleteGtmAddressPool invokes the alidns.DeleteGtmAddressPool API synchronously
// api document: https://help.aliyun.com/api/alidns/deletegtmaddresspool.html
func (client *Client) DeleteGtmAddressPool(request *DeleteGtmAddressPoolRequest) (response *DeleteGtmAddressPoolResponse, err error) {
response = CreateDeleteGtmAddressPoolResponse()
err = client.DoAction(request, response)
return
}
// DeleteGtmAddressPoolWithChan invokes the alidns.DeleteGtmAddressPool API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletegtmaddresspool.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteGtmAddressPoolWithChan(request *DeleteGtmAddressPoolRequest) (<-chan *DeleteGtmAddressPoolResponse, <-chan error) {
responseChan := make(chan *DeleteGtmAddressPoolResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DeleteGtmAddressPool(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DeleteGtmAddressPoolWithCallback invokes the alidns.DeleteGtmAddressPool API asynchronously
// api document: https://help.aliyun.com/api/alidns/deletegtmaddresspool.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteGtmAddressPoolWithCallback(request *DeleteGtmAddressPoolRequest, callback func(response *DeleteGtmAddressPoolResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DeleteGtmAddressPoolResponse
var err error
defer close(result)
response, err = client.DeleteGtmAddressPool(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DeleteGtmAddressPoolRequest is the request struct for api DeleteGtmAddressPool
type DeleteGtmAddressPoolRequest struct {
*requests.RpcRequest
AddrPoolId string `position:"Query" name:"AddrPoolId"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Lang string `position:"Query" name:"Lang"`
}
// DeleteGtmAddressPoolResponse is the response struct for api DeleteGtmAddressPool
type DeleteGtmAddressPoolResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateDeleteGtmAddressPoolRequest creates a request to invoke DeleteGtmAddressPool API
func CreateDeleteGtmAddressPoolRequest() (request *DeleteGtmAddressPoolRequest) {
request = &DeleteGtmAddressPoolRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteGtmAddressPool", "alidns", "openAPI")
return
}
// CreateDeleteGtmAddressPoolResponse creates a response to parse from DeleteGtmAddressPool response
func CreateDeleteGtmAddressPoolResponse() (response *DeleteGtmAddressPoolResponse) {
response = &DeleteGtmAddressPoolResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -76,10 +76,10 @@ func (client *Client) DeleteSubDomainRecordsWithCallback(request *DeleteSubDomai
// DeleteSubDomainRecordsRequest is the request struct for api DeleteSubDomainRecords
type DeleteSubDomainRecordsRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
RR string `position:"Query" name:"RR"`
UserClientIp string `position:"Query" name:"UserClientIp"`
DomainName string `position:"Query" name:"DomainName"`
RR string `position:"Query" name:"RR"`
Lang string `position:"Query" name:"Lang"`
Type string `position:"Query" name:"Type"`
}
@ -96,7 +96,7 @@ func CreateDeleteSubDomainRecordsRequest() (request *DeleteSubDomainRecordsReque
request = &DeleteSubDomainRecordsRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteSubDomainRecords", "", "")
request.InitWithApiInfo("Alidns", "2015-01-09", "DeleteSubDomainRecords", "alidns", "openAPI")
return
}

View file

@ -1,110 +0,0 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeBatchResult invokes the alidns.DescribeBatchResult API synchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresult.html
func (client *Client) DescribeBatchResult(request *DescribeBatchResultRequest) (response *DescribeBatchResultResponse, err error) {
response = CreateDescribeBatchResultResponse()
err = client.DoAction(request, response)
return
}
// DescribeBatchResultWithChan invokes the alidns.DescribeBatchResult API asynchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresult.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeBatchResultWithChan(request *DescribeBatchResultRequest) (<-chan *DescribeBatchResultResponse, <-chan error) {
responseChan := make(chan *DescribeBatchResultResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeBatchResult(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeBatchResultWithCallback invokes the alidns.DescribeBatchResult API asynchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresult.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeBatchResultWithCallback(request *DescribeBatchResultRequest, callback func(response *DescribeBatchResultResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeBatchResultResponse
var err error
defer close(result)
response, err = client.DescribeBatchResult(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeBatchResultRequest is the request struct for api DescribeBatchResult
type DescribeBatchResultRequest struct {
*requests.RpcRequest
Lang string `position:"Query" name:"Lang"`
UserClientIp string `position:"Query" name:"UserClientIp"`
TraceId string `position:"Query" name:"TraceId"`
}
// DescribeBatchResultResponse is the response struct for api DescribeBatchResult
type DescribeBatchResultResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
TraceId string `json:"TraceId" xml:"TraceId"`
Status int `json:"Status" xml:"Status"`
BatchCount int `json:"BatchCount" xml:"BatchCount"`
SuccessNumber int `json:"SuccessNumber" xml:"SuccessNumber"`
FailResults FailResults `json:"FailResults" xml:"FailResults"`
}
// CreateDescribeBatchResultRequest creates a request to invoke DescribeBatchResult API
func CreateDescribeBatchResultRequest() (request *DescribeBatchResultRequest) {
request = &DescribeBatchResultRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DescribeBatchResult", "", "")
return
}
// CreateDescribeBatchResultResponse creates a response to parse from DescribeBatchResult response
func CreateDescribeBatchResultResponse() (response *DescribeBatchResultResponse) {
response = &DescribeBatchResultResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -0,0 +1,113 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeBatchResultCount invokes the alidns.DescribeBatchResultCount API synchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresultcount.html
func (client *Client) DescribeBatchResultCount(request *DescribeBatchResultCountRequest) (response *DescribeBatchResultCountResponse, err error) {
response = CreateDescribeBatchResultCountResponse()
err = client.DoAction(request, response)
return
}
// DescribeBatchResultCountWithChan invokes the alidns.DescribeBatchResultCount API asynchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresultcount.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeBatchResultCountWithChan(request *DescribeBatchResultCountRequest) (<-chan *DescribeBatchResultCountResponse, <-chan error) {
responseChan := make(chan *DescribeBatchResultCountResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeBatchResultCount(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeBatchResultCountWithCallback invokes the alidns.DescribeBatchResultCount API asynchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresultcount.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeBatchResultCountWithCallback(request *DescribeBatchResultCountRequest, callback func(response *DescribeBatchResultCountResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeBatchResultCountResponse
var err error
defer close(result)
response, err = client.DescribeBatchResultCount(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeBatchResultCountRequest is the request struct for api DescribeBatchResultCount
type DescribeBatchResultCountRequest struct {
*requests.RpcRequest
BatchType string `position:"Query" name:"BatchType"`
UserClientIp string `position:"Query" name:"UserClientIp"`
Lang string `position:"Query" name:"Lang"`
TaskId requests.Integer `position:"Query" name:"TaskId"`
}
// DescribeBatchResultCountResponse is the response struct for api DescribeBatchResultCount
type DescribeBatchResultCountResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
Status int `json:"Status" xml:"Status"`
TotalCount int `json:"TotalCount" xml:"TotalCount"`
SuccessCount int `json:"SuccessCount" xml:"SuccessCount"`
FailedCount int `json:"FailedCount" xml:"FailedCount"`
Reason string `json:"Reason" xml:"Reason"`
BatchType string `json:"BatchType" xml:"BatchType"`
TaskId int `json:"TaskId" xml:"TaskId"`
}
// CreateDescribeBatchResultCountRequest creates a request to invoke DescribeBatchResultCount API
func CreateDescribeBatchResultCountRequest() (request *DescribeBatchResultCountRequest) {
request = &DescribeBatchResultCountRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DescribeBatchResultCount", "alidns", "openAPI")
return
}
// CreateDescribeBatchResultCountResponse creates a response to parse from DescribeBatchResultCount response
func CreateDescribeBatchResultCountResponse() (response *DescribeBatchResultCountResponse) {
response = &DescribeBatchResultCountResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View file

@ -0,0 +1,112 @@
package alidns
//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeBatchResultDetail invokes the alidns.DescribeBatchResultDetail API synchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresultdetail.html
func (client *Client) DescribeBatchResultDetail(request *DescribeBatchResultDetailRequest) (response *DescribeBatchResultDetailResponse, err error) {
response = CreateDescribeBatchResultDetailResponse()
err = client.DoAction(request, response)
return
}
// DescribeBatchResultDetailWithChan invokes the alidns.DescribeBatchResultDetail API asynchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresultdetail.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeBatchResultDetailWithChan(request *DescribeBatchResultDetailRequest) (<-chan *DescribeBatchResultDetailResponse, <-chan error) {
responseChan := make(chan *DescribeBatchResultDetailResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeBatchResultDetail(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeBatchResultDetailWithCallback invokes the alidns.DescribeBatchResultDetail API asynchronously
// api document: https://help.aliyun.com/api/alidns/describebatchresultdetail.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeBatchResultDetailWithCallback(request *DescribeBatchResultDetailRequest, callback func(response *DescribeBatchResultDetailResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeBatchResultDetailResponse
var err error
defer close(result)
response, err = client.DescribeBatchResultDetail(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeBatchResultDetailRequest is the request struct for api DescribeBatchResultDetail
type DescribeBatchResultDetailRequest struct {
*requests.RpcRequest
BatchType string `position:"Query" name:"BatchType"`
UserClientIp string `position:"Query" name:"UserClientIp"`
PageSize requests.Integer `position:"Query" name:"PageSize"`
Lang string `position:"Query" name:"Lang"`
PageNumber requests.Integer `position:"Query" name:"PageNumber"`
TaskId requests.Integer `position:"Query" name:"TaskId"`
}
// DescribeBatchResultDetailResponse is the response struct for api DescribeBatchResultDetail
type DescribeBatchResultDetailResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
TotalCount int `json:"TotalCount" xml:"TotalCount"`
PageNumber int `json:"PageNumber" xml:"PageNumber"`
PageSize int `json:"PageSize" xml:"PageSize"`
BatchResultDetails BatchResultDetails `json:"BatchResultDetails" xml:"BatchResultDetails"`
}
// CreateDescribeBatchResultDetailRequest creates a request to invoke DescribeBatchResultDetail API
func CreateDescribeBatchResultDetailRequest() (request *DescribeBatchResultDetailRequest) {
request = &DescribeBatchResultDetailRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Alidns", "2015-01-09", "DescribeBatchResultDetail", "alidns", "openAPI")
return
}
// CreateDescribeBatchResultDetailResponse creates a response to parse from DescribeBatchResultDetail response
func CreateDescribeBatchResultDetailResponse() (response *DescribeBatchResultDetailResponse) {
response = &DescribeBatchResultDetailResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

Some files were not shown because too many files have changed in this diff Show more