mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
vendor: update buildkit to v0.20.0-rc1
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
@@ -97,6 +97,7 @@ type Opt struct {
|
||||
ContainerdAddress string
|
||||
ContainerdNamespace string
|
||||
Callbacks exporter.BuildkitCallbacks
|
||||
CDISpecDirs []string
|
||||
}
|
||||
|
||||
// Builder can build using BuildKit backend
|
||||
|
||||
@@ -45,6 +45,7 @@ import (
|
||||
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
|
||||
"github.com/moby/buildkit/solver"
|
||||
"github.com/moby/buildkit/solver/bboltcachestorage"
|
||||
"github.com/moby/buildkit/solver/llbsolver/cdidevices"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/moby/buildkit/util/apicaps"
|
||||
"github.com/moby/buildkit/util/archutil"
|
||||
@@ -59,6 +60,7 @@ import (
|
||||
"go.etcd.io/bbolt"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"go.opentelemetry.io/otel/sdk/trace"
|
||||
"tags.cncf.io/container-device-interface/pkg/cdi"
|
||||
)
|
||||
|
||||
func newController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) {
|
||||
@@ -110,6 +112,11 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
|
||||
dns := getDNSConfig(opt.DNSConfig)
|
||||
|
||||
cdiManager, err := getCDIManager(opt.CDISpecDirs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workerOpts := containerd.WorkerOptions{
|
||||
Root: opt.Root,
|
||||
Address: opt.ContainerdAddress,
|
||||
@@ -123,6 +130,7 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
NetworkOpt: nc,
|
||||
ApparmorProfile: opt.ApparmorProfile,
|
||||
Selinux: false,
|
||||
CDIManager: cdiManager,
|
||||
}
|
||||
|
||||
wo, err := containerd.NewWorkerOpt(workerOpts, ctd.WithTimeout(60*time.Second))
|
||||
@@ -144,7 +152,7 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
wo.RegistryHosts = opt.RegistryHosts
|
||||
wo.Labels = getLabels(opt, wo.Labels)
|
||||
|
||||
exec, err := newExecutor(opt.Root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile)
|
||||
exec, err := newExecutor(opt.Root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile, cdiManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -318,7 +326,12 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
|
||||
dns := getDNSConfig(opt.DNSConfig)
|
||||
|
||||
exec, err := newExecutor(root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile)
|
||||
cdiManager, err := getCDIManager(opt.CDISpecDirs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exec, err := newExecutor(root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile, cdiManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -386,6 +399,7 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
LeaseManager: lm,
|
||||
GarbageCollect: mdb.GarbageCollect,
|
||||
Labels: getLabels(opt, nil),
|
||||
CDIManager: cdiManager,
|
||||
}
|
||||
|
||||
wc := &worker.Controller{}
|
||||
@@ -529,3 +543,24 @@ func getLabels(opt Opt, labels map[string]string) map[string]string {
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
||||
func getCDIManager(specDirs []string) (*cdidevices.Manager, error) {
|
||||
// TODO: intentionally not returning nil here on empty specDirs as not handled in all code-paths yet
|
||||
cdiCache, err := func() (*cdi.Cache, error) {
|
||||
cdiCache, err := cdi.NewCache(
|
||||
cdi.WithSpecDirs(specDirs...),
|
||||
cdi.WithAutoRefresh(false),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cdiCache.Refresh(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cdiCache, nil
|
||||
}()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CDI registry initialization failure")
|
||||
}
|
||||
return cdidevices.NewManager(cdiCache), nil
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
resourcestypes "github.com/moby/buildkit/executor/resources/types"
|
||||
"github.com/moby/buildkit/executor/runcexecutor"
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/moby/buildkit/solver/llbsolver/cdidevices"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/moby/buildkit/util/network"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
|
||||
const networkName = "bridge"
|
||||
|
||||
func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfig *oci.DNSConfig, rootless bool, idmap idtools.IdentityMapping, apparmorProfile string) (executor.Executor, error) {
|
||||
func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfig *oci.DNSConfig, rootless bool, idmap idtools.IdentityMapping, apparmorProfile string, cdiManager *cdidevices.Manager) (executor.Executor, error) {
|
||||
netRoot := filepath.Join(root, "net")
|
||||
networkProviders := map[pb.NetMode]network.Provider{
|
||||
pb.NetMode_UNSET: &bridgeProvider{Controller: net, Root: netRoot},
|
||||
@@ -74,6 +75,7 @@ func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfi
|
||||
DNS: dnsConfig,
|
||||
ApparmorProfile: apparmorProfile,
|
||||
ResourceMonitor: rm,
|
||||
CDIManager: cdiManager,
|
||||
}, networkProviders)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
"github.com/moby/buildkit/executor"
|
||||
"github.com/moby/buildkit/executor/oci"
|
||||
resourcetypes "github.com/moby/buildkit/executor/resources/types"
|
||||
"github.com/moby/buildkit/solver/llbsolver/cdidevices"
|
||||
)
|
||||
|
||||
func newExecutor(_, _ string, _ *libnetwork.Controller, _ *oci.DNSConfig, _ bool, _ idtools.IdentityMapping, _ string) (executor.Executor, error) {
|
||||
func newExecutor(_, _ string, _ *libnetwork.Controller, _ *oci.DNSConfig, _ bool, _ idtools.IdentityMapping, _ string, _ *cdidevices.Manager) (executor.Executor, error) {
|
||||
return &stubExecutor{}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/moby/buildkit/snapshot"
|
||||
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
|
||||
"github.com/moby/buildkit/solver"
|
||||
"github.com/moby/buildkit/solver/llbsolver/cdidevices"
|
||||
"github.com/moby/buildkit/solver/llbsolver/mounts"
|
||||
"github.com/moby/buildkit/solver/llbsolver/ops"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
@@ -86,6 +87,7 @@ type Opt struct {
|
||||
Exporter exporter.Exporter
|
||||
Layers LayerAccess
|
||||
Platforms []ocispec.Platform
|
||||
CDIManager *cdidevices.Manager
|
||||
}
|
||||
|
||||
// Worker is a local worker instance with dedicated snapshotter, cache, and so on.
|
||||
@@ -480,6 +482,10 @@ func (w *Worker) CacheManager() cache.Manager {
|
||||
return w.Opt.CacheManager
|
||||
}
|
||||
|
||||
func (w *Worker) CDIManager() *cdidevices.Manager {
|
||||
return w.Opt.CDIManager
|
||||
}
|
||||
|
||||
type discardProgress struct{}
|
||||
|
||||
func (*discardProgress) WriteProgress(_ pkgprogress.Progress) error {
|
||||
|
||||
@@ -400,6 +400,11 @@ func initBuildkit(ctx context.Context, d *daemon.Daemon) (_ builderOptions, clos
|
||||
return builderOptions{}, closeFn, err
|
||||
}
|
||||
|
||||
var cdiSpecDirs []string
|
||||
if d.Features()["cdi"] {
|
||||
cdiSpecDirs = d.Config().CDISpecDirs
|
||||
}
|
||||
|
||||
cfg := d.Config()
|
||||
bk, err := buildkit.New(ctx, buildkit.Opt{
|
||||
SessionManager: sm,
|
||||
@@ -423,6 +428,7 @@ func initBuildkit(ctx context.Context, d *daemon.Daemon) (_ builderOptions, clos
|
||||
Exported: d.ImageExportedByBuildkit,
|
||||
Named: d.ImageNamedByBuildkit,
|
||||
},
|
||||
CDISpecDirs: cdiSpecDirs,
|
||||
})
|
||||
if err != nil {
|
||||
return builderOptions{}, closeFn, errors.Wrap(err, "error creating buildkit instance")
|
||||
|
||||
@@ -63,7 +63,7 @@ require (
|
||||
github.com/miekg/dns v1.1.57
|
||||
github.com/mistifyio/go-zfs/v3 v3.0.1
|
||||
github.com/mitchellh/copystructure v1.2.0
|
||||
github.com/moby/buildkit v0.19.0
|
||||
github.com/moby/buildkit v0.20.0-rc1.0.20250212151618-2f7007eec399
|
||||
github.com/moby/docker-image-spec v1.3.1
|
||||
github.com/moby/ipvs v1.1.0
|
||||
github.com/moby/locker v1.0.1
|
||||
@@ -121,6 +121,9 @@ require (
|
||||
cloud.google.com/go v0.112.0 // indirect
|
||||
cloud.google.com/go/longrunning v0.5.4 // indirect
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect
|
||||
@@ -203,7 +206,7 @@ require (
|
||||
github.com/tinylib/msgp v1.1.8 // indirect
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a // indirect
|
||||
github.com/tonistiigi/go-actions-cache v0.0.0-20241210095730-017636a73805 // indirect
|
||||
github.com/tonistiigi/go-actions-cache v0.0.0-20250211194249-bd99cf5bbc65 // indirect
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect
|
||||
|
||||
26
vendor.sum
26
vendor.sum
@@ -17,8 +17,20 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 h1:dIScnXFlF784X79oi7MzVT6GWqr/W1uUt0pB5CsDs9M=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2/go.mod h1:gCLVsLfv1egrcZu+GoJATN5ts75F2s62ih/457eWzOw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0 h1:mlmW46Q0B79I+Aj4azKC6xDMFN9a9SyZWESlGWYXbFs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0/go.mod h1:PXe2h+LKcWTX9afWdZoHyODqR4fBa5boUM/8uJfZ0Jo=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/Graylog2/go-gelf v0.0.0-20191017102106-1550ee647df0 h1:cOjLyhBhe91glgZZNbQUg9BJC57l6BiSKov0Ivv7k0U=
|
||||
@@ -163,8 +175,12 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v27.5.1+incompatible h1:JB9cieUT9YNiMITtIsguaN55PLOHhBSz3LKVc6cqWaY=
|
||||
github.com/docker/cli v27.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||
@@ -367,8 +383,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs=
|
||||
github.com/moby/buildkit v0.19.0 h1:w9G1p7sArvCGNkpWstAqJfRQTXBKukMyMK1bsah1HNo=
|
||||
github.com/moby/buildkit v0.19.0/go.mod h1:WiHBFTgWV8eB1AmPxIWsAlKjUACAwm3X/14xOV4VWew=
|
||||
github.com/moby/buildkit v0.20.0-rc1.0.20250212151618-2f7007eec399 h1:5D+c0/9DQkncvcLqFGYu7it8riR9kTonRIQpgUUg6r4=
|
||||
github.com/moby/buildkit v0.20.0-rc1.0.20250212151618-2f7007eec399/go.mod h1:mtRqVBkksyvFm+ljU1u+cigDh36TdFvlEGfz/XbYTiI=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ=
|
||||
@@ -448,6 +464,8 @@ github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee h1:P6U24L02WMfj9ym
|
||||
github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY=
|
||||
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
|
||||
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -536,8 +554,8 @@ github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 h1:eUk79E1
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a h1:EfGw4G0x/8qXWgtcZ6KVaPS+wpWOQMaypczzP8ojkMY=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a/go.mod h1:Dl/9oEjK7IqnjAm21Okx/XIxUCFJzvh+XdVHUlBwXTw=
|
||||
github.com/tonistiigi/go-actions-cache v0.0.0-20241210095730-017636a73805 h1:l2x1Ubj8f5xhPzZI428ZQ6+BDafGovpdk2ITnD3twTw=
|
||||
github.com/tonistiigi/go-actions-cache v0.0.0-20241210095730-017636a73805/go.mod h1:xsu+XeKT9piH/5f9Y1Zsv5krQqI34CWkIusbs5027IM=
|
||||
github.com/tonistiigi/go-actions-cache v0.0.0-20250211194249-bd99cf5bbc65 h1:57xLt2zJ6in5Au6plQUKm1gfasse4j3h9lrvoor2xPs=
|
||||
github.com/tonistiigi/go-actions-cache v0.0.0-20250211194249-bd99cf5bbc65/go.mod h1:h0oRlVs3NoFIHysRQ4rU1+RG4QmU0M2JVSwTYrB4igk=
|
||||
github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0=
|
||||
github.com/tonistiigi/go-archvariant v1.0.0/go.mod h1:TxFmO5VS6vMq2kvs3ht04iPXtu2rUT/erOnGFYfk5Ho=
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 h1:7I5c2Ig/5FgqkYOh/N87NzoyI9U15qUPXhDD8uCupv8=
|
||||
|
||||
842
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
generated
vendored
Normal file
842
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,842 @@
|
||||
# Release History
|
||||
|
||||
## 1.16.0 (2024-10-17)
|
||||
|
||||
### Features Added
|
||||
|
||||
* Added field `Kind` to `runtime.StartSpanOptions` to allow a kind to be set when starting a span.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* `BearerTokenPolicy` now rewinds request bodies before retrying
|
||||
|
||||
## 1.15.0 (2024-10-14)
|
||||
|
||||
### Features Added
|
||||
|
||||
* `BearerTokenPolicy` handles CAE claims challenges
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Omit the `ResponseError.RawResponse` field from JSON marshaling so instances can be marshaled.
|
||||
* Fixed an integer overflow in the retry policy.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Update dependencies.
|
||||
|
||||
## 1.14.0 (2024-08-07)
|
||||
|
||||
### Features Added
|
||||
|
||||
* Added field `Attributes` to `runtime.StartSpanOptions` to simplify creating spans with attributes.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Include the HTTP verb and URL in `log.EventRetryPolicy` log entries so it's clear which operation is being retried.
|
||||
|
||||
## 1.13.0 (2024-07-16)
|
||||
|
||||
### Features Added
|
||||
|
||||
- Added runtime.NewRequestFromRequest(), allowing for a policy.Request to be created from an existing *http.Request.
|
||||
|
||||
## 1.12.0 (2024-06-06)
|
||||
|
||||
### Features Added
|
||||
|
||||
* Added field `StatusCodes` to `runtime.FetcherForNextLinkOptions` allowing for additional HTTP status codes indicating success.
|
||||
* Added func `NewUUID` to the `runtime` package for generating UUIDs.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Fixed an issue that prevented pollers using the `Operation-Location` strategy from unmarshaling the final result in some cases.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Updated dependencies.
|
||||
|
||||
## 1.11.1 (2024-04-02)
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Pollers that use the `Location` header won't consider `http.StatusRequestTimeout` a terminal failure.
|
||||
* `runtime.Poller[T].Result` won't consider non-terminal error responses as terminal.
|
||||
|
||||
## 1.11.0 (2024-04-01)
|
||||
|
||||
### Features Added
|
||||
|
||||
* Added `StatusCodes` to `arm/policy.RegistrationOptions` to allow supporting non-standard HTTP status codes during registration.
|
||||
* Added field `InsecureAllowCredentialWithHTTP` to `azcore.ClientOptions` and dependent authentication pipeline policies.
|
||||
* Added type `MultipartContent` to the `streaming` package to support multipart/form payloads with custom Content-Type and file name.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* `runtime.SetMultipartFormData` won't try to stringify `[]byte` values.
|
||||
* Pollers that use the `Location` header won't consider `http.StatusTooManyRequests` a terminal failure.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Update dependencies.
|
||||
|
||||
## 1.10.0 (2024-02-29)
|
||||
|
||||
### Features Added
|
||||
|
||||
* Added logging event `log.EventResponseError` that will contain the contents of `ResponseError.Error()` whenever an `azcore.ResponseError` is created.
|
||||
* Added `runtime.NewResponseErrorWithErrorCode` for creating an `azcore.ResponseError` with a caller-supplied error code.
|
||||
* Added type `MatchConditions` for use in conditional requests.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Fixed a potential race condition between `NullValue` and `IsNullValue`.
|
||||
* `runtime.EncodeQueryParams` will escape semicolons before calling `url.ParseQuery`.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Update dependencies.
|
||||
|
||||
## 1.9.2 (2024-02-06)
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* `runtime.MarshalAsByteArray` and `runtime.MarshalAsJSON` will preserve the preexisting value of the `Content-Type` header.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Update to latest version of `internal`.
|
||||
|
||||
## 1.9.1 (2023-12-11)
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* The `retry-after-ms` and `x-ms-retry-after-ms` headers weren't being checked during retries.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Update dependencies.
|
||||
|
||||
## 1.9.0 (2023-11-06)
|
||||
|
||||
### Breaking Changes
|
||||
> These changes affect only code written against previous beta versions of `v1.7.0` and `v1.8.0`
|
||||
* The function `NewTokenCredential` has been removed from the `fake` package. Use a literal `&fake.TokenCredential{}` instead.
|
||||
* The field `TracingNamespace` in `runtime.PipelineOptions` has been replaced by `TracingOptions`.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Fixed an issue that could cause some allowed HTTP header values to not show up in logs.
|
||||
* Include error text instead of error type in traces when the transport returns an error.
|
||||
* Fixed an issue that could cause an HTTP/2 request to hang when the TCP connection becomes unresponsive.
|
||||
* Block key and SAS authentication for non TLS protected endpoints.
|
||||
* Passing a `nil` credential value will no longer cause a panic. Instead, the authentication is skipped.
|
||||
* Calling `Error` on a zero-value `azcore.ResponseError` will no longer panic.
|
||||
* Fixed an issue in `fake.PagerResponder[T]` that would cause a trailing error to be omitted when iterating over pages.
|
||||
* Context values created by `azcore` will no longer flow across disjoint HTTP requests.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Skip generating trace info for no-op tracers.
|
||||
* The `clientName` paramater in client constructors has been renamed to `moduleName`.
|
||||
|
||||
## 1.9.0-beta.1 (2023-10-05)
|
||||
|
||||
### Other Changes
|
||||
|
||||
* The beta features for tracing and fakes have been reinstated.
|
||||
|
||||
## 1.8.0 (2023-10-05)
|
||||
|
||||
### Features Added
|
||||
|
||||
* This includes the following features from `v1.8.0-beta.N` releases.
|
||||
* Claims and CAE for authentication.
|
||||
* New `messaging` package.
|
||||
* Various helpers in the `runtime` package.
|
||||
* Deprecation of `runtime.With*` funcs and their replacements in the `policy` package.
|
||||
* Added types `KeyCredential` and `SASCredential` to the `azcore` package.
|
||||
* Includes their respective constructor functions.
|
||||
* Added types `KeyCredentialPolicy` and `SASCredentialPolicy` to the `azcore/runtime` package.
|
||||
* Includes their respective constructor functions and options types.
|
||||
|
||||
### Breaking Changes
|
||||
> These changes affect only code written against beta versions of `v1.8.0`
|
||||
* The beta features for tracing and fakes have been omitted for this release.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Fixed an issue that could cause some ARM RPs to not be automatically registered.
|
||||
* Block bearer token authentication for non TLS protected endpoints.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Updated dependencies.
|
||||
|
||||
## 1.8.0-beta.3 (2023-09-07)
|
||||
|
||||
### Features Added
|
||||
|
||||
* Added function `FetcherForNextLink` and `FetcherForNextLinkOptions` to the `runtime` package to centralize creation of `Pager[T].Fetcher` from a next link URL.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Suppress creating spans for nested SDK API calls. The HTTP span will be a child of the outer API span.
|
||||
|
||||
### Other Changes
|
||||
|
||||
* The following functions in the `runtime` package are now exposed from the `policy` package, and the `runtime` versions have been deprecated.
|
||||
* `WithCaptureResponse`
|
||||
* `WithHTTPHeader`
|
||||
* `WithRetryOptions`
|
||||
|
||||
## 1.7.2 (2023-09-06)
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Fix default HTTP transport to work in WASM modules.
|
||||
|
||||
## 1.8.0-beta.2 (2023-08-14)
|
||||
|
||||
### Features Added
|
||||
|
||||
* Added function `SanitizePagerPollerPath` to the `server` package to centralize sanitization and formalize the contract.
|
||||
* Added `TokenRequestOptions.EnableCAE` to indicate whether to request a CAE token.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
> This change affects only code written against beta version `v1.8.0-beta.1`.
|
||||
* `messaging.CloudEvent` deserializes JSON objects as `[]byte`, instead of `json.RawMessage`. See the documentation for CloudEvent.Data for more information.
|
||||
|
||||
> This change affects only code written against beta versions `v1.7.0-beta.2` and `v1.8.0-beta.1`.
|
||||
* Removed parameter from method `Span.End()` and its type `tracing.SpanEndOptions`. This API GA'ed in `v1.2.0` so we cannot change it.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
* Propagate any query parameters when constructing a fake poller and/or injecting next links.
|
||||
|
||||
## 1.7.1 (2023-08-14)
|
||||
|
||||
## Bugs Fixed
|
||||
|
||||
* Enable TLS renegotiation in the default transport policy.
|
||||
|
||||
## 1.8.0-beta.1 (2023-07-12)
|
||||
|
||||
### Features Added
|
||||
|
||||
- `messaging/CloudEvent` allows you to serialize/deserialize CloudEvents, as described in the CloudEvents 1.0 specification: [link](https://github.com/cloudevents/spec)
|
||||
|
||||
### Other Changes
|
||||
|
||||
* The beta features for CAE, tracing, and fakes have been reinstated.
|
||||
|
||||
## 1.7.0 (2023-07-12)
|
||||
|
||||
### Features Added
|
||||
* Added method `WithClientName()` to type `azcore.Client` to support shallow cloning of a client with a new name used for tracing.
|
||||
|
||||
### Breaking Changes
|
||||
> These changes affect only code written against beta versions v1.7.0-beta.1 or v1.7.0-beta.2
|
||||
* The beta features for CAE, tracing, and fakes have been omitted for this release.
|
||||
|
||||
## 1.7.0-beta.2 (2023-06-06)
|
||||
|
||||
### Breaking Changes
|
||||
> These changes affect only code written against beta version v1.7.0-beta.1
|
||||
* Method `SpanFromContext()` on type `tracing.Tracer` had the `bool` return value removed.
|
||||
* This includes the field `SpanFromContext` in supporting type `tracing.TracerOptions`.
|
||||
* Method `AddError()` has been removed from type `tracing.Span`.
|
||||
* Method `Span.End()` now requires an argument of type `*tracing.SpanEndOptions`.
|
||||
|
||||
## 1.6.1 (2023-06-06)
|
||||
|
||||
### Bugs Fixed
|
||||
* Fixed an issue in `azcore.NewClient()` and `arm.NewClient()` that could cause an incorrect module name to be used in telemetry.
|
||||
|
||||
### Other Changes
|
||||
* This version contains all bug fixes from `v1.7.0-beta.1`
|
||||
|
||||
## 1.7.0-beta.1 (2023-05-24)
|
||||
|
||||
### Features Added
|
||||
* Restored CAE support for ARM clients.
|
||||
* Added supporting features to enable distributed tracing.
|
||||
* Added func `runtime.StartSpan()` for use by SDKs to start spans.
|
||||
* Added method `WithContext()` to `runtime.Request` to support shallow cloning with a new context.
|
||||
* Added field `TracingNamespace` to `runtime.PipelineOptions`.
|
||||
* Added field `Tracer` to `runtime.NewPollerOptions` and `runtime.NewPollerFromResumeTokenOptions` types.
|
||||
* Added field `SpanFromContext` to `tracing.TracerOptions`.
|
||||
* Added methods `Enabled()`, `SetAttributes()`, and `SpanFromContext()` to `tracing.Tracer`.
|
||||
* Added supporting pipeline policies to include HTTP spans when creating clients.
|
||||
* Added package `fake` to support generated fakes packages in SDKs.
|
||||
* The package contains public surface area exposed by fake servers and supporting APIs intended only for use by the fake server implementations.
|
||||
* Added an internal fake poller implementation.
|
||||
|
||||
### Bugs Fixed
|
||||
* Retry policy always clones the underlying `*http.Request` before invoking the next policy.
|
||||
* Added some non-standard error codes to the list of error codes for unregistered resource providers.
|
||||
|
||||
## 1.6.0 (2023-05-04)
|
||||
|
||||
### Features Added
|
||||
* Added support for ARM cross-tenant authentication. Set the `AuxiliaryTenants` field of `arm.ClientOptions` to enable.
|
||||
* Added `TenantID` field to `policy.TokenRequestOptions`.
|
||||
|
||||
## 1.5.0 (2023-04-06)
|
||||
|
||||
### Features Added
|
||||
* Added `ShouldRetry` to `policy.RetryOptions` for finer-grained control over when to retry.
|
||||
|
||||
### Breaking Changes
|
||||
> These changes affect only code written against a beta version such as v1.5.0-beta.1
|
||||
> These features will return in v1.6.0-beta.1.
|
||||
* Removed `TokenRequestOptions.Claims` and `.TenantID`
|
||||
* Removed ARM client support for CAE and cross-tenant auth.
|
||||
|
||||
### Bugs Fixed
|
||||
* Added non-conformant LRO terminal states `Cancelled` and `Completed`.
|
||||
|
||||
### Other Changes
|
||||
* Updated to latest `internal` module.
|
||||
|
||||
## 1.5.0-beta.1 (2023-03-02)
|
||||
|
||||
### Features Added
|
||||
* This release includes the features added in v1.4.0-beta.1
|
||||
|
||||
## 1.4.0 (2023-03-02)
|
||||
> This release doesn't include features added in v1.4.0-beta.1. They will return in v1.5.0-beta.1.
|
||||
|
||||
### Features Added
|
||||
* Add `Clone()` method for `arm/policy.ClientOptions`.
|
||||
|
||||
### Bugs Fixed
|
||||
* ARM's RP registration policy will no longer swallow unrecognized errors.
|
||||
* Fixed an issue in `runtime.NewPollerFromResumeToken()` when resuming a `Poller` with a custom `PollingHandler`.
|
||||
* Fixed wrong policy copy in `arm/runtime.NewPipeline()`.
|
||||
|
||||
## 1.4.0-beta.1 (2023-02-02)
|
||||
|
||||
### Features Added
|
||||
* Added support for ARM cross-tenant authentication. Set the `AuxiliaryTenants` field of `arm.ClientOptions` to enable.
|
||||
* Added `Claims` and `TenantID` fields to `policy.TokenRequestOptions`.
|
||||
* ARM bearer token policy handles CAE challenges.
|
||||
|
||||
## 1.3.1 (2023-02-02)
|
||||
|
||||
### Other Changes
|
||||
* Update dependencies to latest versions.
|
||||
|
||||
## 1.3.0 (2023-01-06)
|
||||
|
||||
### Features Added
|
||||
* Added `BearerTokenOptions.AuthorizationHandler` to enable extending `runtime.BearerTokenPolicy`
|
||||
with custom authorization logic
|
||||
* Added `Client` types and matching constructors to the `azcore` and `arm` packages. These represent a basic client for HTTP and ARM respectively.
|
||||
|
||||
### Other Changes
|
||||
* Updated `internal` module to latest version.
|
||||
* `policy/Request.SetBody()` allows replacing a request's body with an empty one
|
||||
|
||||
## 1.2.0 (2022-11-04)
|
||||
|
||||
### Features Added
|
||||
* Added `ClientOptions.APIVersion` field, which overrides the default version a client
|
||||
requests of the service, if the client supports this (all ARM clients do).
|
||||
* Added package `tracing` that contains the building blocks for distributed tracing.
|
||||
* Added field `TracingProvider` to type `policy.ClientOptions` that will be used to set the per-client tracing implementation.
|
||||
|
||||
### Bugs Fixed
|
||||
* Fixed an issue in `runtime.SetMultipartFormData` to properly handle slices of `io.ReadSeekCloser`.
|
||||
* Fixed the MaxRetryDelay default to be 60s.
|
||||
* Failure to poll the state of an LRO will now return an `*azcore.ResponseError` for poller types that require this behavior.
|
||||
* Fixed a bug in `runtime.NewPipeline` that would cause pipeline-specified allowed headers and query parameters to be lost.
|
||||
|
||||
### Other Changes
|
||||
* Retain contents of read-only fields when sending requests.
|
||||
|
||||
## 1.1.4 (2022-10-06)
|
||||
|
||||
### Bugs Fixed
|
||||
* Don't retry a request if the `Retry-After` delay is greater than the configured `RetryOptions.MaxRetryDelay`.
|
||||
* `runtime.JoinPaths`: do not unconditionally add a forward slash before the query string
|
||||
|
||||
### Other Changes
|
||||
* Removed logging URL from retry policy as it's redundant.
|
||||
* Retry policy logs when it exits due to a non-retriable status code.
|
||||
|
||||
## 1.1.3 (2022-09-01)
|
||||
|
||||
### Bugs Fixed
|
||||
* Adjusted the initial retry delay to 800ms per the Azure SDK guidelines.
|
||||
|
||||
## 1.1.2 (2022-08-09)
|
||||
|
||||
### Other Changes
|
||||
* Fixed various doc bugs.
|
||||
|
||||
## 1.1.1 (2022-06-30)
|
||||
|
||||
### Bugs Fixed
|
||||
* Avoid polling when a RELO LRO synchronously terminates.
|
||||
|
||||
## 1.1.0 (2022-06-03)
|
||||
|
||||
### Other Changes
|
||||
* The one-second floor for `Frequency` when calling `PollUntilDone()` has been removed when running tests.
|
||||
|
||||
## 1.0.0 (2022-05-12)
|
||||
|
||||
### Features Added
|
||||
* Added interface `runtime.PollingHandler` to support custom poller implementations.
|
||||
* Added field `PollingHandler` of this type to `runtime.NewPollerOptions[T]` and `runtime.NewPollerFromResumeTokenOptions[T]`.
|
||||
|
||||
### Breaking Changes
|
||||
* Renamed `cloud.Configuration.LoginEndpoint` to `.ActiveDirectoryAuthorityHost`
|
||||
* Renamed `cloud.AzurePublicCloud` to `cloud.AzurePublic`
|
||||
* Removed `AuxiliaryTenants` field from `arm/ClientOptions` and `arm/policy/BearerTokenOptions`
|
||||
* Removed `TokenRequestOptions.TenantID`
|
||||
* `Poller[T].PollUntilDone()` now takes an `options *PollUntilDoneOptions` param instead of `freq time.Duration`
|
||||
* Removed `arm/runtime.Poller[T]`, `arm/runtime.NewPoller[T]()` and `arm/runtime.NewPollerFromResumeToken[T]()`
|
||||
* Removed `arm/runtime.FinalStateVia` and related `const` values
|
||||
* Renamed `runtime.PageProcessor` to `runtime.PagingHandler`
|
||||
* The `arm/runtime.ProviderRepsonse` and `arm/runtime.Provider` types are no longer exported.
|
||||
* Renamed `NewRequestIdPolicy()` to `NewRequestIDPolicy()`
|
||||
* `TokenCredential.GetToken` now returns `AccessToken` by value.
|
||||
|
||||
### Bugs Fixed
|
||||
* When per-try timeouts are enabled, only cancel the context after the body has been read and closed.
|
||||
* The `Operation-Location` poller now properly handles `final-state-via` values.
|
||||
* Improvements in `runtime.Poller[T]`
|
||||
* `Poll()` shouldn't cache errors, allowing for additional retries when in a non-terminal state.
|
||||
* `Result()` will cache the terminal result or error but not transient errors, allowing for additional retries.
|
||||
|
||||
### Other Changes
|
||||
* Updated to latest `internal` module and absorbed breaking changes.
|
||||
* Use `temporal.Resource` and deleted copy.
|
||||
* The internal poller implementation has been refactored.
|
||||
* The implementation in `internal/pollers/poller.go` has been merged into `runtime/poller.go` with some slight modification.
|
||||
* The internal poller types had their methods updated to conform to the `runtime.PollingHandler` interface.
|
||||
* The creation of resume tokens has been refactored so that implementers of `runtime.PollingHandler` don't need to know about it.
|
||||
* `NewPipeline()` places policies from `ClientOptions` after policies from `PipelineOptions`
|
||||
* Default User-Agent headers no longer include `azcore` version information
|
||||
|
||||
## 0.23.1 (2022-04-14)
|
||||
|
||||
### Bugs Fixed
|
||||
* Include XML header when marshalling XML content.
|
||||
* Handle XML namespaces when searching for error code.
|
||||
* Handle `odata.error` when searching for error code.
|
||||
|
||||
## 0.23.0 (2022-04-04)
|
||||
|
||||
### Features Added
|
||||
* Added `runtime.Pager[T any]` and `runtime.Poller[T any]` supporting types for central, generic, implementations.
|
||||
* Added `cloud` package with a new API for cloud configuration
|
||||
* Added `FinalStateVia` field to `runtime.NewPollerOptions[T any]` type.
|
||||
|
||||
### Breaking Changes
|
||||
* Removed the `Poller` type-alias to the internal poller implementation.
|
||||
* Added `Ptr[T any]` and `SliceOfPtrs[T any]` in the `to` package and removed all non-generic implementations.
|
||||
* `NullValue` and `IsNullValue` now take a generic type parameter instead of an interface func parameter.
|
||||
* Replaced `arm.Endpoint` with `cloud` API
|
||||
* Removed the `endpoint` parameter from `NewRPRegistrationPolicy()`
|
||||
* `arm/runtime.NewPipeline()` and `.NewRPRegistrationPolicy()` now return an `error`
|
||||
* Refactored `NewPoller` and `NewPollerFromResumeToken` funcs in `arm/runtime` and `runtime` packages.
|
||||
* Removed the `pollerID` parameter as it's no longer required.
|
||||
* Created optional parameter structs and moved optional parameters into them.
|
||||
* Changed `FinalStateVia` field to a `const` type.
|
||||
|
||||
### Other Changes
|
||||
* Converted expiring resource and dependent types to use generics.
|
||||
|
||||
## 0.22.0 (2022-03-03)
|
||||
|
||||
### Features Added
|
||||
* Added header `WWW-Authenticate` to the default allow-list of headers for logging.
|
||||
* Added a pipeline policy that enables the retrieval of HTTP responses from API calls.
|
||||
* Added `runtime.WithCaptureResponse` to enable the policy at the API level (off by default).
|
||||
|
||||
### Breaking Changes
|
||||
* Moved `WithHTTPHeader` and `WithRetryOptions` from the `policy` package to the `runtime` package.
|
||||
|
||||
## 0.21.1 (2022-02-04)
|
||||
|
||||
### Bugs Fixed
|
||||
* Restore response body after reading in `Poller.FinalResponse()`. (#16911)
|
||||
* Fixed bug in `NullValue` that could lead to incorrect comparisons for empty maps/slices (#16969)
|
||||
|
||||
### Other Changes
|
||||
* `BearerTokenPolicy` is more resilient to transient authentication failures. (#16789)
|
||||
|
||||
## 0.21.0 (2022-01-11)
|
||||
|
||||
### Features Added
|
||||
* Added `AllowedHeaders` and `AllowedQueryParams` to `policy.LogOptions` to control which headers and query parameters are written to the logger.
|
||||
* Added `azcore.ResponseError` type which is returned from APIs when a non-success HTTP status code is received.
|
||||
|
||||
### Breaking Changes
|
||||
* Moved `[]policy.Policy` parameters of `arm/runtime.NewPipeline` and `runtime.NewPipeline` into a new struct, `runtime.PipelineOptions`
|
||||
* Renamed `arm/ClientOptions.Host` to `.Endpoint`
|
||||
* Moved `Request.SkipBodyDownload` method to function `runtime.SkipBodyDownload`
|
||||
* Removed `azcore.HTTPResponse` interface type
|
||||
* `arm.NewPoller()` and `runtime.NewPoller()` no longer require an `eu` parameter
|
||||
* `runtime.NewResponseError()` no longer requires an `error` parameter
|
||||
|
||||
## 0.20.0 (2021-10-22)
|
||||
|
||||
### Breaking Changes
|
||||
* Removed `arm.Connection`
|
||||
* Removed `azcore.Credential` and `.NewAnonymousCredential()`
|
||||
* `NewRPRegistrationPolicy` now requires an `azcore.TokenCredential`
|
||||
* `runtime.NewPipeline` has a new signature that simplifies implementing custom authentication
|
||||
* `arm/runtime.RegistrationOptions` embeds `policy.ClientOptions`
|
||||
* Contents in the `log` package have been slightly renamed.
|
||||
* Removed `AuthenticationOptions` in favor of `policy.BearerTokenOptions`
|
||||
* Changed parameters for `NewBearerTokenPolicy()`
|
||||
* Moved policy config options out of `arm/runtime` and into `arm/policy`
|
||||
|
||||
### Features Added
|
||||
* Updating Documentation
|
||||
* Added string typdef `arm.Endpoint` to provide a hint toward expected ARM client endpoints
|
||||
* `azcore.ClientOptions` contains common pipeline configuration settings
|
||||
* Added support for multi-tenant authorization in `arm/runtime`
|
||||
* Require one second minimum when calling `PollUntilDone()`
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed a potential panic when creating the default Transporter.
|
||||
* Close LRO initial response body when creating a poller.
|
||||
* Fixed a panic when recursively cloning structs that contain time.Time.
|
||||
|
||||
## 0.19.0 (2021-08-25)
|
||||
|
||||
### Breaking Changes
|
||||
* Split content out of `azcore` into various packages. The intent is to separate content based on its usage (common, uncommon, SDK authors).
|
||||
* `azcore` has all core functionality.
|
||||
* `log` contains facilities for configuring in-box logging.
|
||||
* `policy` is used for configuring pipeline options and creating custom pipeline policies.
|
||||
* `runtime` contains various helpers used by SDK authors and generated content.
|
||||
* `streaming` has helpers for streaming IO operations.
|
||||
* `NewTelemetryPolicy()` now requires module and version parameters and the `Value` option has been removed.
|
||||
* As a result, the `Request.Telemetry()` method has been removed.
|
||||
* The telemetry policy now includes the SDK prefix `azsdk-go-` so callers no longer need to provide it.
|
||||
* The `*http.Request` in `runtime.Request` is no longer anonymously embedded. Use the `Raw()` method to access it.
|
||||
* The `UserAgent` and `Version` constants have been made internal, `Module` and `Version` respectively.
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed an issue in the retry policy where the request body could be overwritten after a rewind.
|
||||
|
||||
### Other Changes
|
||||
* Moved modules `armcore` and `to` content into `arm` and `to` packages respectively.
|
||||
* The `Pipeline()` method on `armcore.Connection` has been replaced by `NewPipeline()` in `arm.Connection`. It takes module and version parameters used by the telemetry policy.
|
||||
* Poller logic has been consolidated across ARM and core implementations.
|
||||
* This required some changes to the internal interfaces for core pollers.
|
||||
* The core poller types have been improved, including more logging and test coverage.
|
||||
|
||||
## 0.18.1 (2021-08-20)
|
||||
|
||||
### Features Added
|
||||
* Adds an `ETag` type for comparing etags and handling etags on requests
|
||||
* Simplifies the `requestBodyProgess` and `responseBodyProgress` into a single `progress` object
|
||||
|
||||
### Bugs Fixed
|
||||
* `JoinPaths` will preserve query parameters encoded in the `root` url.
|
||||
|
||||
### Other Changes
|
||||
* Bumps dependency on `internal` module to the latest version (v0.7.0)
|
||||
|
||||
## 0.18.0 (2021-07-29)
|
||||
### Features Added
|
||||
* Replaces methods from Logger type with two package methods for interacting with the logging functionality.
|
||||
* `azcore.SetClassifications` replaces `azcore.Logger().SetClassifications`
|
||||
* `azcore.SetListener` replaces `azcore.Logger().SetListener`
|
||||
|
||||
### Breaking Changes
|
||||
* Removes `Logger` type from `azcore`
|
||||
|
||||
|
||||
## 0.17.0 (2021-07-27)
|
||||
### Features Added
|
||||
* Adding TenantID to TokenRequestOptions (https://github.com/Azure/azure-sdk-for-go/pull/14879)
|
||||
* Adding AuxiliaryTenants to AuthenticationOptions (https://github.com/Azure/azure-sdk-for-go/pull/15123)
|
||||
|
||||
### Breaking Changes
|
||||
* Rename `AnonymousCredential` to `NewAnonymousCredential` (https://github.com/Azure/azure-sdk-for-go/pull/15104)
|
||||
* rename `AuthenticationPolicyOptions` to `AuthenticationOptions` (https://github.com/Azure/azure-sdk-for-go/pull/15103)
|
||||
* Make Header constants private (https://github.com/Azure/azure-sdk-for-go/pull/15038)
|
||||
|
||||
|
||||
## 0.16.2 (2021-05-26)
|
||||
### Features Added
|
||||
* Improved support for byte arrays [#14715](https://github.com/Azure/azure-sdk-for-go/pull/14715)
|
||||
|
||||
|
||||
## 0.16.1 (2021-05-19)
|
||||
### Features Added
|
||||
* Add license.txt to azcore module [#14682](https://github.com/Azure/azure-sdk-for-go/pull/14682)
|
||||
|
||||
|
||||
## 0.16.0 (2021-05-07)
|
||||
### Features Added
|
||||
* Remove extra `*` in UnmarshalAsByteArray() [#14642](https://github.com/Azure/azure-sdk-for-go/pull/14642)
|
||||
|
||||
|
||||
## 0.15.1 (2021-05-06)
|
||||
### Features Added
|
||||
* Cache the original request body on Request [#14634](https://github.com/Azure/azure-sdk-for-go/pull/14634)
|
||||
|
||||
|
||||
## 0.15.0 (2021-05-05)
|
||||
### Features Added
|
||||
* Add support for null map and slice
|
||||
* Export `Response.Payload` method
|
||||
|
||||
### Breaking Changes
|
||||
* remove `Response.UnmarshalError` as it's no longer required
|
||||
|
||||
|
||||
## 0.14.5 (2021-04-23)
|
||||
### Features Added
|
||||
* Add `UnmarshalError()` on `azcore.Response`
|
||||
|
||||
|
||||
## 0.14.4 (2021-04-22)
|
||||
### Features Added
|
||||
* Support for basic LRO polling
|
||||
* Added type `LROPoller` and supporting types for basic polling on long running operations.
|
||||
* rename poller param and added doc comment
|
||||
|
||||
### Bugs Fixed
|
||||
* Fixed content type detection bug in logging.
|
||||
|
||||
|
||||
## 0.14.3 (2021-03-29)
|
||||
### Features Added
|
||||
* Add support for multi-part form data
|
||||
* Added method `WriteMultipartFormData()` to Request.
|
||||
|
||||
|
||||
## 0.14.2 (2021-03-17)
|
||||
### Features Added
|
||||
* Add support for encoding JSON null values
|
||||
* Adds `NullValue()` and `IsNullValue()` functions for setting and detecting sentinel values used for encoding a JSON null.
|
||||
* Documentation fixes
|
||||
|
||||
### Bugs Fixed
|
||||
* Fixed improper error wrapping
|
||||
|
||||
|
||||
## 0.14.1 (2021-02-08)
|
||||
### Features Added
|
||||
* Add `Pager` and `Poller` interfaces to azcore
|
||||
|
||||
|
||||
## 0.14.0 (2021-01-12)
|
||||
### Features Added
|
||||
* Accept zero-value options for default values
|
||||
* Specify zero-value options structs to accept default values.
|
||||
* Remove `DefaultXxxOptions()` methods.
|
||||
* Do not silently change TryTimeout on negative values
|
||||
* make per-try timeout opt-in
|
||||
|
||||
|
||||
## 0.13.4 (2020-11-20)
|
||||
### Features Added
|
||||
* Include telemetry string in User Agent
|
||||
|
||||
|
||||
## 0.13.3 (2020-11-20)
|
||||
### Features Added
|
||||
* Updating response body handling on `azcore.Response`
|
||||
|
||||
|
||||
## 0.13.2 (2020-11-13)
|
||||
### Features Added
|
||||
* Remove implementation of stateless policies as first-class functions.
|
||||
|
||||
|
||||
## 0.13.1 (2020-11-05)
|
||||
### Features Added
|
||||
* Add `Telemetry()` method to `azcore.Request()`
|
||||
|
||||
|
||||
## 0.13.0 (2020-10-14)
|
||||
### Features Added
|
||||
* Rename `log` to `logger` to avoid name collision with the log package.
|
||||
* Documentation improvements
|
||||
* Simplified `DefaultHTTPClientTransport()` implementation
|
||||
|
||||
|
||||
## 0.12.1 (2020-10-13)
|
||||
### Features Added
|
||||
* Update `internal` module dependence to `v0.5.0`
|
||||
|
||||
|
||||
## 0.12.0 (2020-10-08)
|
||||
### Features Added
|
||||
* Removed storage specific content
|
||||
* Removed internal content to prevent API clutter
|
||||
* Refactored various policy options to conform with our options pattern
|
||||
|
||||
|
||||
## 0.11.0 (2020-09-22)
|
||||
### Features Added
|
||||
|
||||
* Removed `LogError` and `LogSlowResponse`.
|
||||
* Renamed `options` in `RequestLogOptions`.
|
||||
* Updated `NewRequestLogPolicy()` to follow standard pattern for options.
|
||||
* Refactored `requestLogPolicy.Do()` per above changes.
|
||||
* Cleaned up/added logging in retry policy.
|
||||
* Export `NewResponseError()`
|
||||
* Fix `RequestLogOptions` comment
|
||||
|
||||
|
||||
## 0.10.1 (2020-09-17)
|
||||
### Features Added
|
||||
* Add default console logger
|
||||
* Default console logger writes to stderr. To enable it, set env var `AZURE_SDK_GO_LOGGING` to the value 'all'.
|
||||
* Added `Logger.Writef()` to reduce the need for `ShouldLog()` checks.
|
||||
* Add `LogLongRunningOperation`
|
||||
|
||||
|
||||
## 0.10.0 (2020-09-10)
|
||||
### Features Added
|
||||
* The `request` and `transport` interfaces have been refactored to align with the patterns in the standard library.
|
||||
* `NewRequest()` now uses `http.NewRequestWithContext()` and performs additional validation, it also requires a context parameter.
|
||||
* The `Policy` and `Transport` interfaces have had their context parameter removed as the context is associated with the underlying `http.Request`.
|
||||
* `Pipeline.Do()` will validate the HTTP request before sending it through the pipeline, avoiding retries on a malformed request.
|
||||
* The `Retrier` interface has been replaced with the `NonRetriableError` interface, and the retry policy updated to test for this.
|
||||
* `Request.SetBody()` now requires a content type parameter for setting the request's MIME type.
|
||||
* moved path concatenation into `JoinPaths()` func
|
||||
|
||||
|
||||
## 0.9.6 (2020-08-18)
|
||||
### Features Added
|
||||
* Improvements to body download policy
|
||||
* Always download the response body for error responses, i.e. HTTP status codes >= 400.
|
||||
* Simplify variable declarations
|
||||
|
||||
|
||||
## 0.9.5 (2020-08-11)
|
||||
### Features Added
|
||||
* Set the Content-Length header in `Request.SetBody`
|
||||
|
||||
|
||||
## 0.9.4 (2020-08-03)
|
||||
### Features Added
|
||||
* Fix cancellation of per try timeout
|
||||
* Per try timeout is used to ensure that an HTTP operation doesn't take too long, e.g. that a GET on some URL doesn't take an inordinant amount of time.
|
||||
* Once the HTTP request returns, the per try timeout should be cancelled, not when the response has been read to completion.
|
||||
* Do not drain response body if there are no more retries
|
||||
* Do not retry non-idempotent operations when body download fails
|
||||
|
||||
|
||||
## 0.9.3 (2020-07-28)
|
||||
### Features Added
|
||||
* Add support for custom HTTP request headers
|
||||
* Inserts an internal policy into the pipeline that can extract HTTP header values from the caller's context, adding them to the request.
|
||||
* Use `azcore.WithHTTPHeader` to add HTTP headers to a context.
|
||||
* Remove method specific to Go 1.14
|
||||
|
||||
|
||||
## 0.9.2 (2020-07-28)
|
||||
### Features Added
|
||||
* Omit read-only content from request payloads
|
||||
* If any field in a payload's object graph contains `azure:"ro"`, make a clone of the object graph, omitting all fields with this annotation.
|
||||
* Verify no fields were dropped
|
||||
* Handle embedded struct types
|
||||
* Added test for cloning by value
|
||||
* Add messages to failures
|
||||
|
||||
|
||||
## 0.9.1 (2020-07-22)
|
||||
### Features Added
|
||||
* Updated dependency on internal module to fix race condition.
|
||||
|
||||
|
||||
## 0.9.0 (2020-07-09)
|
||||
### Features Added
|
||||
* Add `HTTPResponse` interface to be used by callers to access the raw HTTP response from an error in the event of an API call failure.
|
||||
* Updated `sdk/internal` dependency to latest version.
|
||||
* Rename package alias
|
||||
|
||||
|
||||
## 0.8.2 (2020-06-29)
|
||||
### Features Added
|
||||
* Added missing documentation comments
|
||||
|
||||
### Bugs Fixed
|
||||
* Fixed a bug in body download policy.
|
||||
|
||||
|
||||
## 0.8.1 (2020-06-26)
|
||||
### Features Added
|
||||
* Miscellaneous clean-up reported by linters
|
||||
|
||||
|
||||
## 0.8.0 (2020-06-01)
|
||||
### Features Added
|
||||
* Differentiate between standard and URL encoding.
|
||||
|
||||
|
||||
## 0.7.1 (2020-05-27)
|
||||
### Features Added
|
||||
* Add support for for base64 encoding and decoding of payloads.
|
||||
|
||||
|
||||
## 0.7.0 (2020-05-12)
|
||||
### Features Added
|
||||
* Change `RetryAfter()` to a function.
|
||||
|
||||
|
||||
## 0.6.0 (2020-04-29)
|
||||
### Features Added
|
||||
* Updating `RetryAfter` to only return the detaion in the RetryAfter header
|
||||
|
||||
|
||||
## 0.5.0 (2020-03-23)
|
||||
### Features Added
|
||||
* Export `TransportFunc`
|
||||
|
||||
### Breaking Changes
|
||||
* Removed `IterationDone`
|
||||
|
||||
|
||||
## 0.4.1 (2020-02-25)
|
||||
### Features Added
|
||||
* Ensure per-try timeout is properly cancelled
|
||||
* Explicitly call cancel the per-try timeout when the response body has been read/closed by the body download policy.
|
||||
* When the response body is returned to the caller for reading/closing, wrap it in a `responseBodyReader` that will cancel the timeout when the body is closed.
|
||||
* `Logger.Should()` will return false if no listener is set.
|
||||
|
||||
|
||||
## 0.4.0 (2020-02-18)
|
||||
### Features Added
|
||||
* Enable custom `RetryOptions` to be specified per API call
|
||||
* Added `WithRetryOptions()` that adds a custom `RetryOptions` to the provided context, allowing custom settings per API call.
|
||||
* Remove 429 from the list of default HTTP status codes for retry.
|
||||
* Change StatusCodesForRetry to a slice so consumers can append to it.
|
||||
* Added support for retry-after in HTTP-date format.
|
||||
* Cleaned up some comments specific to storage.
|
||||
* Remove `Request.SetQueryParam()`
|
||||
* Renamed `MaxTries` to `MaxRetries`
|
||||
|
||||
## 0.3.0 (2020-01-16)
|
||||
### Features Added
|
||||
* Added `DefaultRetryOptions` to create initialized default options.
|
||||
|
||||
### Breaking Changes
|
||||
* Removed `Response.CheckStatusCode()`
|
||||
|
||||
|
||||
## 0.2.0 (2020-01-15)
|
||||
### Features Added
|
||||
* Add support for marshalling and unmarshalling JSON
|
||||
* Removed `Response.Payload` field
|
||||
* Exit early when unmarsahlling if there is no payload
|
||||
|
||||
|
||||
## 0.1.0 (2020-01-10)
|
||||
### Features Added
|
||||
* Initial release
|
||||
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/LICENSE.txt
generated
vendored
Normal file
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
39
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/README.md
generated
vendored
Normal file
39
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/README.md
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Azure Core Client Module for Go
|
||||
|
||||
[](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore)
|
||||
[](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=1843&branchName=main)
|
||||
[](https://img.shields.io/azure-devops/coverage/azure-sdk/public/1843/main)
|
||||
|
||||
The `azcore` module provides a set of common interfaces and types for Go SDK client modules.
|
||||
These modules follow the [Azure SDK Design Guidelines for Go](https://azure.github.io/azure-sdk/golang_introduction.html).
|
||||
|
||||
## Getting started
|
||||
|
||||
This project uses [Go modules](https://github.com/golang/go/wiki/Modules) for versioning and dependency management.
|
||||
|
||||
Typically, you will not need to explicitly install `azcore` as it will be installed as a client module dependency.
|
||||
To add the latest version to your `go.mod` file, execute the following command.
|
||||
|
||||
```bash
|
||||
go get github.com/Azure/azure-sdk-for-go/sdk/azcore
|
||||
```
|
||||
|
||||
General documentation and examples can be found on [pkg.go.dev](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore).
|
||||
|
||||
## Contributing
|
||||
This project welcomes contributions and suggestions. Most contributions require
|
||||
you to agree to a Contributor License Agreement (CLA) declaring that you have
|
||||
the right to, and actually do, grant us the rights to use your contribution.
|
||||
For details, visit [https://cla.microsoft.com](https://cla.microsoft.com).
|
||||
|
||||
When you submit a pull request, a CLA-bot will automatically determine whether
|
||||
you need to provide a CLA and decorate the PR appropriately (e.g., label,
|
||||
comment). Simply follow the instructions provided by the bot. You will only
|
||||
need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the
|
||||
[Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information, see the
|
||||
[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any
|
||||
additional questions or comments.
|
||||
29
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/ci.yml
generated
vendored
Normal file
29
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file.
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
- feature/*
|
||||
- hotfix/*
|
||||
- release/*
|
||||
paths:
|
||||
include:
|
||||
- sdk/azcore/
|
||||
- eng/
|
||||
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
- feature/*
|
||||
- hotfix/*
|
||||
- release/*
|
||||
paths:
|
||||
include:
|
||||
- sdk/azcore/
|
||||
- eng/
|
||||
|
||||
extends:
|
||||
template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml
|
||||
parameters:
|
||||
ServiceDirectory: azcore
|
||||
44
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud/cloud.go
generated
vendored
Normal file
44
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud/cloud.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package cloud
|
||||
|
||||
var (
|
||||
// AzureChina contains configuration for Azure China.
|
||||
AzureChina = Configuration{
|
||||
ActiveDirectoryAuthorityHost: "https://login.chinacloudapi.cn/", Services: map[ServiceName]ServiceConfiguration{},
|
||||
}
|
||||
// AzureGovernment contains configuration for Azure Government.
|
||||
AzureGovernment = Configuration{
|
||||
ActiveDirectoryAuthorityHost: "https://login.microsoftonline.us/", Services: map[ServiceName]ServiceConfiguration{},
|
||||
}
|
||||
// AzurePublic contains configuration for Azure Public Cloud.
|
||||
AzurePublic = Configuration{
|
||||
ActiveDirectoryAuthorityHost: "https://login.microsoftonline.com/", Services: map[ServiceName]ServiceConfiguration{},
|
||||
}
|
||||
)
|
||||
|
||||
// ServiceName identifies a cloud service.
|
||||
type ServiceName string
|
||||
|
||||
// ResourceManager is a global constant identifying Azure Resource Manager.
|
||||
const ResourceManager ServiceName = "resourceManager"
|
||||
|
||||
// ServiceConfiguration configures a specific cloud service such as Azure Resource Manager.
|
||||
type ServiceConfiguration struct {
|
||||
// Audience is the audience the client will request for its access tokens.
|
||||
Audience string
|
||||
// Endpoint is the service's base URL.
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
// Configuration configures a cloud.
|
||||
type Configuration struct {
|
||||
// ActiveDirectoryAuthorityHost is the base URL of the cloud's Azure Active Directory.
|
||||
ActiveDirectoryAuthorityHost string
|
||||
// Services contains configuration for the cloud's services.
|
||||
Services map[ServiceName]ServiceConfiguration
|
||||
}
|
||||
53
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud/doc.go
generated
vendored
Normal file
53
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud/doc.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
Package cloud implements a configuration API for applications deployed to sovereign or private Azure clouds.
|
||||
|
||||
Azure SDK client configuration defaults are appropriate for Azure Public Cloud (sometimes referred to as
|
||||
"Azure Commercial" or simply "Microsoft Azure"). This package enables applications deployed to other
|
||||
Azure Clouds to configure clients appropriately.
|
||||
|
||||
This package contains predefined configuration for well-known sovereign clouds such as Azure Government and
|
||||
Azure China. Azure SDK clients accept this configuration via the Cloud field of azcore.ClientOptions. For
|
||||
example, configuring a credential and ARM client for Azure Government:
|
||||
|
||||
opts := azcore.ClientOptions{Cloud: cloud.AzureGovernment}
|
||||
cred, err := azidentity.NewDefaultAzureCredential(
|
||||
&azidentity.DefaultAzureCredentialOptions{ClientOptions: opts},
|
||||
)
|
||||
handle(err)
|
||||
|
||||
client, err := armsubscription.NewClient(
|
||||
cred, &arm.ClientOptions{ClientOptions: opts},
|
||||
)
|
||||
handle(err)
|
||||
|
||||
Applications deployed to a private cloud such as Azure Stack create a Configuration object with
|
||||
appropriate values:
|
||||
|
||||
c := cloud.Configuration{
|
||||
ActiveDirectoryAuthorityHost: "https://...",
|
||||
Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
|
||||
cloud.ResourceManager: {
|
||||
Audience: "...",
|
||||
Endpoint: "https://...",
|
||||
},
|
||||
},
|
||||
}
|
||||
opts := azcore.ClientOptions{Cloud: c}
|
||||
|
||||
cred, err := azidentity.NewDefaultAzureCredential(
|
||||
&azidentity.DefaultAzureCredentialOptions{ClientOptions: opts},
|
||||
)
|
||||
handle(err)
|
||||
|
||||
client, err := armsubscription.NewClient(
|
||||
cred, &arm.ClientOptions{ClientOptions: opts},
|
||||
)
|
||||
handle(err)
|
||||
*/
|
||||
package cloud
|
||||
173
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/core.go
generated
vendored
Normal file
173
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/core.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package azcore
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing"
|
||||
)
|
||||
|
||||
// AccessToken represents an Azure service bearer access token with expiry information.
|
||||
type AccessToken = exported.AccessToken
|
||||
|
||||
// TokenCredential represents a credential capable of providing an OAuth token.
|
||||
type TokenCredential = exported.TokenCredential
|
||||
|
||||
// KeyCredential contains an authentication key used to authenticate to an Azure service.
|
||||
type KeyCredential = exported.KeyCredential
|
||||
|
||||
// NewKeyCredential creates a new instance of [KeyCredential] with the specified values.
|
||||
// - key is the authentication key
|
||||
func NewKeyCredential(key string) *KeyCredential {
|
||||
return exported.NewKeyCredential(key)
|
||||
}
|
||||
|
||||
// SASCredential contains a shared access signature used to authenticate to an Azure service.
|
||||
type SASCredential = exported.SASCredential
|
||||
|
||||
// NewSASCredential creates a new instance of [SASCredential] with the specified values.
|
||||
// - sas is the shared access signature
|
||||
func NewSASCredential(sas string) *SASCredential {
|
||||
return exported.NewSASCredential(sas)
|
||||
}
|
||||
|
||||
// holds sentinel values used to send nulls
|
||||
var nullables map[reflect.Type]any = map[reflect.Type]any{}
|
||||
var nullablesMu sync.RWMutex
|
||||
|
||||
// NullValue is used to send an explicit 'null' within a request.
|
||||
// This is typically used in JSON-MERGE-PATCH operations to delete a value.
|
||||
func NullValue[T any]() T {
|
||||
t := shared.TypeOfT[T]()
|
||||
|
||||
nullablesMu.RLock()
|
||||
v, found := nullables[t]
|
||||
nullablesMu.RUnlock()
|
||||
|
||||
if found {
|
||||
// return the sentinel object
|
||||
return v.(T)
|
||||
}
|
||||
|
||||
// promote to exclusive lock and check again (double-checked locking pattern)
|
||||
nullablesMu.Lock()
|
||||
defer nullablesMu.Unlock()
|
||||
v, found = nullables[t]
|
||||
|
||||
if !found {
|
||||
var o reflect.Value
|
||||
if k := t.Kind(); k == reflect.Map {
|
||||
o = reflect.MakeMap(t)
|
||||
} else if k == reflect.Slice {
|
||||
// empty slices appear to all point to the same data block
|
||||
// which causes comparisons to become ambiguous. so we create
|
||||
// a slice with len/cap of one which ensures a unique address.
|
||||
o = reflect.MakeSlice(t, 1, 1)
|
||||
} else {
|
||||
o = reflect.New(t.Elem())
|
||||
}
|
||||
v = o.Interface()
|
||||
nullables[t] = v
|
||||
}
|
||||
// return the sentinel object
|
||||
return v.(T)
|
||||
}
|
||||
|
||||
// IsNullValue returns true if the field contains a null sentinel value.
|
||||
// This is used by custom marshallers to properly encode a null value.
|
||||
func IsNullValue[T any](v T) bool {
|
||||
// see if our map has a sentinel object for this *T
|
||||
t := reflect.TypeOf(v)
|
||||
nullablesMu.RLock()
|
||||
defer nullablesMu.RUnlock()
|
||||
|
||||
if o, found := nullables[t]; found {
|
||||
o1 := reflect.ValueOf(o)
|
||||
v1 := reflect.ValueOf(v)
|
||||
// we found it; return true if v points to the sentinel object.
|
||||
// NOTE: maps and slices can only be compared to nil, else you get
|
||||
// a runtime panic. so we compare addresses instead.
|
||||
return o1.Pointer() == v1.Pointer()
|
||||
}
|
||||
// no sentinel object for this *t
|
||||
return false
|
||||
}
|
||||
|
||||
// ClientOptions contains optional settings for a client's pipeline.
|
||||
// Instances can be shared across calls to SDK client constructors when uniform configuration is desired.
|
||||
// Zero-value fields will have their specified default values applied during use.
|
||||
type ClientOptions = policy.ClientOptions
|
||||
|
||||
// Client is a basic HTTP client. It consists of a pipeline and tracing provider.
|
||||
type Client struct {
|
||||
pl runtime.Pipeline
|
||||
tr tracing.Tracer
|
||||
|
||||
// cached on the client to support shallow copying with new values
|
||||
tp tracing.Provider
|
||||
modVer string
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewClient creates a new Client instance with the provided values.
|
||||
// - moduleName - the fully qualified name of the module where the client is defined; used by the telemetry policy and tracing provider.
|
||||
// - moduleVersion - the semantic version of the module; used by the telemetry policy and tracing provider.
|
||||
// - plOpts - pipeline configuration options; can be the zero-value
|
||||
// - options - optional client configurations; pass nil to accept the default values
|
||||
func NewClient(moduleName, moduleVersion string, plOpts runtime.PipelineOptions, options *ClientOptions) (*Client, error) {
|
||||
if options == nil {
|
||||
options = &ClientOptions{}
|
||||
}
|
||||
|
||||
if !options.Telemetry.Disabled {
|
||||
if err := shared.ValidateModVer(moduleVersion); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
pl := runtime.NewPipeline(moduleName, moduleVersion, plOpts, options)
|
||||
|
||||
tr := options.TracingProvider.NewTracer(moduleName, moduleVersion)
|
||||
if tr.Enabled() && plOpts.Tracing.Namespace != "" {
|
||||
tr.SetAttributes(tracing.Attribute{Key: shared.TracingNamespaceAttrName, Value: plOpts.Tracing.Namespace})
|
||||
}
|
||||
|
||||
return &Client{
|
||||
pl: pl,
|
||||
tr: tr,
|
||||
tp: options.TracingProvider,
|
||||
modVer: moduleVersion,
|
||||
namespace: plOpts.Tracing.Namespace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Pipeline returns the pipeline for this client.
|
||||
func (c *Client) Pipeline() runtime.Pipeline {
|
||||
return c.pl
|
||||
}
|
||||
|
||||
// Tracer returns the tracer for this client.
|
||||
func (c *Client) Tracer() tracing.Tracer {
|
||||
return c.tr
|
||||
}
|
||||
|
||||
// WithClientName returns a shallow copy of the Client with its tracing client name changed to clientName.
|
||||
// Note that the values for module name and version will be preserved from the source Client.
|
||||
// - clientName - the fully qualified name of the client ("package.Client"); this is used by the tracing provider when creating spans
|
||||
func (c *Client) WithClientName(clientName string) *Client {
|
||||
tr := c.tp.NewTracer(clientName, c.modVer)
|
||||
if tr.Enabled() && c.namespace != "" {
|
||||
tr.SetAttributes(tracing.Attribute{Key: shared.TracingNamespaceAttrName, Value: c.namespace})
|
||||
}
|
||||
return &Client{pl: c.pl, tr: tr, tp: c.tp, modVer: c.modVer, namespace: c.namespace}
|
||||
}
|
||||
264
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/doc.go
generated
vendored
Normal file
264
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/doc.go
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
||||
// Use of this source code is governed by an MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package azcore implements an HTTP request/response middleware pipeline used by Azure SDK clients.
|
||||
|
||||
The middleware consists of three components.
|
||||
|
||||
- One or more Policy instances.
|
||||
- A Transporter instance.
|
||||
- A Pipeline instance that combines the Policy and Transporter instances.
|
||||
|
||||
# Implementing the Policy Interface
|
||||
|
||||
A Policy can be implemented in two ways; as a first-class function for a stateless Policy, or as
|
||||
a method on a type for a stateful Policy. Note that HTTP requests made via the same pipeline share
|
||||
the same Policy instances, so if a Policy mutates its state it MUST be properly synchronized to
|
||||
avoid race conditions.
|
||||
|
||||
A Policy's Do method is called when an HTTP request wants to be sent over the network. The Do method can
|
||||
perform any operation(s) it desires. For example, it can log the outgoing request, mutate the URL, headers,
|
||||
and/or query parameters, inject a failure, etc. Once the Policy has successfully completed its request
|
||||
work, it must call the Next() method on the *policy.Request instance in order to pass the request to the
|
||||
next Policy in the chain.
|
||||
|
||||
When an HTTP response comes back, the Policy then gets a chance to process the response/error. The Policy instance
|
||||
can log the response, retry the operation if it failed due to a transient error or timeout, unmarshal the response
|
||||
body, etc. Once the Policy has successfully completed its response work, it must return the *http.Response
|
||||
and error instances to its caller.
|
||||
|
||||
Template for implementing a stateless Policy:
|
||||
|
||||
type policyFunc func(*policy.Request) (*http.Response, error)
|
||||
|
||||
// Do implements the Policy interface on policyFunc.
|
||||
func (pf policyFunc) Do(req *policy.Request) (*http.Response, error) {
|
||||
return pf(req)
|
||||
}
|
||||
|
||||
func NewMyStatelessPolicy() policy.Policy {
|
||||
return policyFunc(func(req *policy.Request) (*http.Response, error) {
|
||||
// TODO: mutate/process Request here
|
||||
|
||||
// forward Request to next Policy & get Response/error
|
||||
resp, err := req.Next()
|
||||
|
||||
// TODO: mutate/process Response/error here
|
||||
|
||||
// return Response/error to previous Policy
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
|
||||
Template for implementing a stateful Policy:
|
||||
|
||||
type MyStatefulPolicy struct {
|
||||
// TODO: add configuration/setting fields here
|
||||
}
|
||||
|
||||
// TODO: add initialization args to NewMyStatefulPolicy()
|
||||
func NewMyStatefulPolicy() policy.Policy {
|
||||
return &MyStatefulPolicy{
|
||||
// TODO: initialize configuration/setting fields here
|
||||
}
|
||||
}
|
||||
|
||||
func (p *MyStatefulPolicy) Do(req *policy.Request) (resp *http.Response, err error) {
|
||||
// TODO: mutate/process Request here
|
||||
|
||||
// forward Request to next Policy & get Response/error
|
||||
resp, err := req.Next()
|
||||
|
||||
// TODO: mutate/process Response/error here
|
||||
|
||||
// return Response/error to previous Policy
|
||||
return resp, err
|
||||
}
|
||||
|
||||
# Implementing the Transporter Interface
|
||||
|
||||
The Transporter interface is responsible for sending the HTTP request and returning the corresponding
|
||||
HTTP response or error. The Transporter is invoked by the last Policy in the chain. The default Transporter
|
||||
implementation uses a shared http.Client from the standard library.
|
||||
|
||||
The same stateful/stateless rules for Policy implementations apply to Transporter implementations.
|
||||
|
||||
# Using Policy and Transporter Instances Via a Pipeline
|
||||
|
||||
To use the Policy and Transporter instances, an application passes them to the runtime.NewPipeline function.
|
||||
|
||||
func NewPipeline(transport Transporter, policies ...Policy) Pipeline
|
||||
|
||||
The specified Policy instances form a chain and are invoked in the order provided to NewPipeline
|
||||
followed by the Transporter.
|
||||
|
||||
Once the Pipeline has been created, create a runtime.Request instance and pass it to Pipeline's Do method.
|
||||
|
||||
func NewRequest(ctx context.Context, httpMethod string, endpoint string) (*Request, error)
|
||||
|
||||
func (p Pipeline) Do(req *Request) (*http.Request, error)
|
||||
|
||||
The Pipeline.Do method sends the specified Request through the chain of Policy and Transporter
|
||||
instances. The response/error is then sent through the same chain of Policy instances in reverse
|
||||
order. For example, assuming there are Policy types PolicyA, PolicyB, and PolicyC along with
|
||||
TransportA.
|
||||
|
||||
pipeline := NewPipeline(TransportA, PolicyA, PolicyB, PolicyC)
|
||||
|
||||
The flow of Request and Response looks like the following:
|
||||
|
||||
policy.Request -> PolicyA -> PolicyB -> PolicyC -> TransportA -----+
|
||||
|
|
||||
HTTP(S) endpoint
|
||||
|
|
||||
caller <--------- PolicyA <- PolicyB <- PolicyC <- http.Response-+
|
||||
|
||||
# Creating a Request Instance
|
||||
|
||||
The Request instance passed to Pipeline's Do method is a wrapper around an *http.Request. It also
|
||||
contains some internal state and provides various convenience methods. You create a Request instance
|
||||
by calling the runtime.NewRequest function:
|
||||
|
||||
func NewRequest(ctx context.Context, httpMethod string, endpoint string) (*Request, error)
|
||||
|
||||
If the Request should contain a body, call the SetBody method.
|
||||
|
||||
func (req *Request) SetBody(body ReadSeekCloser, contentType string) error
|
||||
|
||||
A seekable stream is required so that upon retry, the retry Policy instance can seek the stream
|
||||
back to the beginning before retrying the network request and re-uploading the body.
|
||||
|
||||
# Sending an Explicit Null
|
||||
|
||||
Operations like JSON-MERGE-PATCH send a JSON null to indicate a value should be deleted.
|
||||
|
||||
{
|
||||
"delete-me": null
|
||||
}
|
||||
|
||||
This requirement conflicts with the SDK's default marshalling that specifies "omitempty" as
|
||||
a means to resolve the ambiguity between a field to be excluded and its zero-value.
|
||||
|
||||
type Widget struct {
|
||||
Name *string `json:",omitempty"`
|
||||
Count *int `json:",omitempty"`
|
||||
}
|
||||
|
||||
In the above example, Name and Count are defined as pointer-to-type to disambiguate between
|
||||
a missing value (nil) and a zero-value (0) which might have semantic differences.
|
||||
|
||||
In a PATCH operation, any fields left as nil are to have their values preserved. When updating
|
||||
a Widget's count, one simply specifies the new value for Count, leaving Name nil.
|
||||
|
||||
To fulfill the requirement for sending a JSON null, the NullValue() function can be used.
|
||||
|
||||
w := Widget{
|
||||
Count: azcore.NullValue[*int](),
|
||||
}
|
||||
|
||||
This sends an explict "null" for Count, indicating that any current value for Count should be deleted.
|
||||
|
||||
# Processing the Response
|
||||
|
||||
When the HTTP response is received, the *http.Response is returned directly. Each Policy instance
|
||||
can inspect/mutate the *http.Response.
|
||||
|
||||
# Built-in Logging
|
||||
|
||||
To enable logging, set environment variable AZURE_SDK_GO_LOGGING to "all" before executing your program.
|
||||
|
||||
By default the logger writes to stderr. This can be customized by calling log.SetListener, providing
|
||||
a callback that writes to the desired location. Any custom logging implementation MUST provide its
|
||||
own synchronization to handle concurrent invocations.
|
||||
|
||||
See the docs for the log package for further details.
|
||||
|
||||
# Pageable Operations
|
||||
|
||||
Pageable operations return potentially large data sets spread over multiple GET requests. The result of
|
||||
each GET is a "page" of data consisting of a slice of items.
|
||||
|
||||
Pageable operations can be identified by their New*Pager naming convention and return type of *runtime.Pager[T].
|
||||
|
||||
func (c *WidgetClient) NewListWidgetsPager(o *Options) *runtime.Pager[PageResponse]
|
||||
|
||||
The call to WidgetClient.NewListWidgetsPager() returns an instance of *runtime.Pager[T] for fetching pages
|
||||
and determining if there are more pages to fetch. No IO calls are made until the NextPage() method is invoked.
|
||||
|
||||
pager := widgetClient.NewListWidgetsPager(nil)
|
||||
for pager.More() {
|
||||
page, err := pager.NextPage(context.TODO())
|
||||
// handle err
|
||||
for _, widget := range page.Values {
|
||||
// process widget
|
||||
}
|
||||
}
|
||||
|
||||
# Long-Running Operations
|
||||
|
||||
Long-running operations (LROs) are operations consisting of an initial request to start the operation followed
|
||||
by polling to determine when the operation has reached a terminal state. An LRO's terminal state is one
|
||||
of the following values.
|
||||
|
||||
- Succeeded - the LRO completed successfully
|
||||
- Failed - the LRO failed to complete
|
||||
- Canceled - the LRO was canceled
|
||||
|
||||
LROs can be identified by their Begin* prefix and their return type of *runtime.Poller[T].
|
||||
|
||||
func (c *WidgetClient) BeginCreateOrUpdate(ctx context.Context, w Widget, o *Options) (*runtime.Poller[Response], error)
|
||||
|
||||
When a call to WidgetClient.BeginCreateOrUpdate() returns a nil error, it means that the LRO has started.
|
||||
It does _not_ mean that the widget has been created or updated (or failed to be created/updated).
|
||||
|
||||
The *runtime.Poller[T] provides APIs for determining the state of the LRO. To wait for the LRO to complete,
|
||||
call the PollUntilDone() method.
|
||||
|
||||
poller, err := widgetClient.BeginCreateOrUpdate(context.TODO(), Widget{}, nil)
|
||||
// handle err
|
||||
result, err := poller.PollUntilDone(context.TODO(), nil)
|
||||
// handle err
|
||||
// use result
|
||||
|
||||
The call to PollUntilDone() will block the current goroutine until the LRO has reached a terminal state or the
|
||||
context is canceled/timed out.
|
||||
|
||||
Note that LROs can take anywhere from several seconds to several minutes. The duration is operation-dependent. Due to
|
||||
this variant behavior, pollers do _not_ have a preconfigured time-out. Use a context with the appropriate cancellation
|
||||
mechanism as required.
|
||||
|
||||
# Resume Tokens
|
||||
|
||||
Pollers provide the ability to serialize their state into a "resume token" which can be used by another process to
|
||||
recreate the poller. This is achieved via the runtime.Poller[T].ResumeToken() method.
|
||||
|
||||
token, err := poller.ResumeToken()
|
||||
// handle error
|
||||
|
||||
Note that a token can only be obtained for a poller that's in a non-terminal state. Also note that any subsequent calls
|
||||
to poller.Poll() might change the poller's state. In this case, a new token should be created.
|
||||
|
||||
After the token has been obtained, it can be used to recreate an instance of the originating poller.
|
||||
|
||||
poller, err := widgetClient.BeginCreateOrUpdate(nil, Widget{}, &Options{
|
||||
ResumeToken: token,
|
||||
})
|
||||
|
||||
When resuming a poller, no IO is performed, and zero-value arguments can be used for everything but the Options.ResumeToken.
|
||||
|
||||
Resume tokens are unique per service client and operation. Attempting to resume a poller for LRO BeginB() with a token from LRO
|
||||
BeginA() will result in an error.
|
||||
|
||||
# Fakes
|
||||
|
||||
The fake package contains types used for constructing in-memory fake servers used in unit tests.
|
||||
This allows writing tests to cover various success/error conditions without the need for connecting to a live service.
|
||||
|
||||
Please see https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/samples/fakes for details and examples on how to use fakes.
|
||||
*/
|
||||
package azcore
|
||||
17
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/errors.go
generated
vendored
Normal file
17
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/errors.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package azcore
|
||||
|
||||
import "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
|
||||
// ResponseError is returned when a request is made to a service and
|
||||
// the service returns a non-success HTTP status code.
|
||||
// Use errors.As() to access this type in the error chain.
|
||||
//
|
||||
// When marshaling instances, the RawResponse field will be omitted.
|
||||
// However, the contents returned by Error() will be preserved.
|
||||
type ResponseError = exported.ResponseError
|
||||
57
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/etag.go
generated
vendored
Normal file
57
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/etag.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package azcore
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ETag is a property used for optimistic concurrency during updates
|
||||
// ETag is a validator based on https://tools.ietf.org/html/rfc7232#section-2.3.2
|
||||
// An ETag can be empty ("").
|
||||
type ETag string
|
||||
|
||||
// ETagAny is an ETag that represents everything, the value is "*"
|
||||
const ETagAny ETag = "*"
|
||||
|
||||
// Equals does a strong comparison of two ETags. Equals returns true when both
|
||||
// ETags are not weak and the values of the underlying strings are equal.
|
||||
func (e ETag) Equals(other ETag) bool {
|
||||
return !e.IsWeak() && !other.IsWeak() && e == other
|
||||
}
|
||||
|
||||
// WeakEquals does a weak comparison of two ETags. Two ETags are equivalent if their opaque-tags match
|
||||
// character-by-character, regardless of either or both being tagged as "weak".
|
||||
func (e ETag) WeakEquals(other ETag) bool {
|
||||
getStart := func(e1 ETag) int {
|
||||
if e1.IsWeak() {
|
||||
return 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
aStart := getStart(e)
|
||||
bStart := getStart(other)
|
||||
|
||||
aVal := e[aStart:]
|
||||
bVal := other[bStart:]
|
||||
|
||||
return aVal == bVal
|
||||
}
|
||||
|
||||
// IsWeak specifies whether the ETag is strong or weak.
|
||||
func (e ETag) IsWeak() bool {
|
||||
return len(e) >= 4 && strings.HasPrefix(string(e), "W/\"") && strings.HasSuffix(string(e), "\"")
|
||||
}
|
||||
|
||||
// MatchConditions specifies HTTP options for conditional requests.
|
||||
type MatchConditions struct {
|
||||
// Optionally limit requests to resources that have a matching ETag.
|
||||
IfMatch *ETag
|
||||
|
||||
// Optionally limit requests to resources that do not match the ETag.
|
||||
IfNoneMatch *ETag
|
||||
}
|
||||
175
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go
generated
vendored
Normal file
175
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type nopCloser struct {
|
||||
io.ReadSeeker
|
||||
}
|
||||
|
||||
func (n nopCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NopCloser returns a ReadSeekCloser with a no-op close method wrapping the provided io.ReadSeeker.
|
||||
// Exported as streaming.NopCloser().
|
||||
func NopCloser(rs io.ReadSeeker) io.ReadSeekCloser {
|
||||
return nopCloser{rs}
|
||||
}
|
||||
|
||||
// HasStatusCode returns true if the Response's status code is one of the specified values.
|
||||
// Exported as runtime.HasStatusCode().
|
||||
func HasStatusCode(resp *http.Response, statusCodes ...int) bool {
|
||||
if resp == nil {
|
||||
return false
|
||||
}
|
||||
for _, sc := range statusCodes {
|
||||
if resp.StatusCode == sc {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AccessToken represents an Azure service bearer access token with expiry information.
|
||||
// Exported as azcore.AccessToken.
|
||||
type AccessToken struct {
|
||||
Token string
|
||||
ExpiresOn time.Time
|
||||
}
|
||||
|
||||
// TokenRequestOptions contain specific parameter that may be used by credentials types when attempting to get a token.
|
||||
// Exported as policy.TokenRequestOptions.
|
||||
type TokenRequestOptions struct {
|
||||
// Claims are any additional claims required for the token to satisfy a conditional access policy, such as a
|
||||
// service may return in a claims challenge following an authorization failure. If a service returned the
|
||||
// claims value base64 encoded, it must be decoded before setting this field.
|
||||
Claims string
|
||||
|
||||
// EnableCAE indicates whether to enable Continuous Access Evaluation (CAE) for the requested token. When true,
|
||||
// azidentity credentials request CAE tokens for resource APIs supporting CAE. Clients are responsible for
|
||||
// handling CAE challenges. If a client that doesn't handle CAE challenges receives a CAE token, it may end up
|
||||
// in a loop retrying an API call with a token that has been revoked due to CAE.
|
||||
EnableCAE bool
|
||||
|
||||
// Scopes contains the list of permission scopes required for the token.
|
||||
Scopes []string
|
||||
|
||||
// TenantID identifies the tenant from which to request the token. azidentity credentials authenticate in
|
||||
// their configured default tenants when this field isn't set.
|
||||
TenantID string
|
||||
}
|
||||
|
||||
// TokenCredential represents a credential capable of providing an OAuth token.
|
||||
// Exported as azcore.TokenCredential.
|
||||
type TokenCredential interface {
|
||||
// GetToken requests an access token for the specified set of scopes.
|
||||
GetToken(ctx context.Context, options TokenRequestOptions) (AccessToken, error)
|
||||
}
|
||||
|
||||
// DecodeByteArray will base-64 decode the provided string into v.
|
||||
// Exported as runtime.DecodeByteArray()
|
||||
func DecodeByteArray(s string, v *[]byte, format Base64Encoding) error {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
payload := string(s)
|
||||
if payload[0] == '"' {
|
||||
// remove surrounding quotes
|
||||
payload = payload[1 : len(payload)-1]
|
||||
}
|
||||
switch format {
|
||||
case Base64StdFormat:
|
||||
decoded, err := base64.StdEncoding.DecodeString(payload)
|
||||
if err == nil {
|
||||
*v = decoded
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
case Base64URLFormat:
|
||||
// use raw encoding as URL format should not contain any '=' characters
|
||||
decoded, err := base64.RawURLEncoding.DecodeString(payload)
|
||||
if err == nil {
|
||||
*v = decoded
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
default:
|
||||
return fmt.Errorf("unrecognized byte array format: %d", format)
|
||||
}
|
||||
}
|
||||
|
||||
// KeyCredential contains an authentication key used to authenticate to an Azure service.
|
||||
// Exported as azcore.KeyCredential.
|
||||
type KeyCredential struct {
|
||||
cred *keyCredential
|
||||
}
|
||||
|
||||
// NewKeyCredential creates a new instance of [KeyCredential] with the specified values.
|
||||
// - key is the authentication key
|
||||
func NewKeyCredential(key string) *KeyCredential {
|
||||
return &KeyCredential{cred: newKeyCredential(key)}
|
||||
}
|
||||
|
||||
// Update replaces the existing key with the specified value.
|
||||
func (k *KeyCredential) Update(key string) {
|
||||
k.cred.Update(key)
|
||||
}
|
||||
|
||||
// SASCredential contains a shared access signature used to authenticate to an Azure service.
|
||||
// Exported as azcore.SASCredential.
|
||||
type SASCredential struct {
|
||||
cred *keyCredential
|
||||
}
|
||||
|
||||
// NewSASCredential creates a new instance of [SASCredential] with the specified values.
|
||||
// - sas is the shared access signature
|
||||
func NewSASCredential(sas string) *SASCredential {
|
||||
return &SASCredential{cred: newKeyCredential(sas)}
|
||||
}
|
||||
|
||||
// Update replaces the existing shared access signature with the specified value.
|
||||
func (k *SASCredential) Update(sas string) {
|
||||
k.cred.Update(sas)
|
||||
}
|
||||
|
||||
// KeyCredentialGet returns the key for cred.
|
||||
func KeyCredentialGet(cred *KeyCredential) string {
|
||||
return cred.cred.Get()
|
||||
}
|
||||
|
||||
// SASCredentialGet returns the shared access sig for cred.
|
||||
func SASCredentialGet(cred *SASCredential) string {
|
||||
return cred.cred.Get()
|
||||
}
|
||||
|
||||
type keyCredential struct {
|
||||
key atomic.Value // string
|
||||
}
|
||||
|
||||
func newKeyCredential(key string) *keyCredential {
|
||||
keyCred := keyCredential{}
|
||||
keyCred.key.Store(key)
|
||||
return &keyCred
|
||||
}
|
||||
|
||||
func (k *keyCredential) Get() string {
|
||||
return k.key.Load().(string)
|
||||
}
|
||||
|
||||
func (k *keyCredential) Update(key string) {
|
||||
k.key.Store(key)
|
||||
}
|
||||
77
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/pipeline.go
generated
vendored
Normal file
77
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/pipeline.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Policy represents an extensibility point for the Pipeline that can mutate the specified
|
||||
// Request and react to the received Response.
|
||||
// Exported as policy.Policy.
|
||||
type Policy interface {
|
||||
// Do applies the policy to the specified Request. When implementing a Policy, mutate the
|
||||
// request before calling req.Next() to move on to the next policy, and respond to the result
|
||||
// before returning to the caller.
|
||||
Do(req *Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// Pipeline represents a primitive for sending HTTP requests and receiving responses.
|
||||
// Its behavior can be extended by specifying policies during construction.
|
||||
// Exported as runtime.Pipeline.
|
||||
type Pipeline struct {
|
||||
policies []Policy
|
||||
}
|
||||
|
||||
// Transporter represents an HTTP pipeline transport used to send HTTP requests and receive responses.
|
||||
// Exported as policy.Transporter.
|
||||
type Transporter interface {
|
||||
// Do sends the HTTP request and returns the HTTP response or error.
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// used to adapt a TransportPolicy to a Policy
|
||||
type transportPolicy struct {
|
||||
trans Transporter
|
||||
}
|
||||
|
||||
func (tp transportPolicy) Do(req *Request) (*http.Response, error) {
|
||||
if tp.trans == nil {
|
||||
return nil, errors.New("missing transporter")
|
||||
}
|
||||
resp, err := tp.trans.Do(req.Raw())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if resp == nil {
|
||||
// there was no response and no error (rare but can happen)
|
||||
// this ensures the retry policy will retry the request
|
||||
return nil, errors.New("received nil response")
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// NewPipeline creates a new Pipeline object from the specified Policies.
|
||||
// Not directly exported, but used as part of runtime.NewPipeline().
|
||||
func NewPipeline(transport Transporter, policies ...Policy) Pipeline {
|
||||
// transport policy must always be the last in the slice
|
||||
policies = append(policies, transportPolicy{trans: transport})
|
||||
return Pipeline{
|
||||
policies: policies,
|
||||
}
|
||||
}
|
||||
|
||||
// Do is called for each and every HTTP request. It passes the request through all
|
||||
// the Policy objects (which can transform the Request's URL/query parameters/headers)
|
||||
// and ultimately sends the transformed HTTP request over the network.
|
||||
func (p Pipeline) Do(req *Request) (*http.Response, error) {
|
||||
if req == nil {
|
||||
return nil, errors.New("request cannot be nil")
|
||||
}
|
||||
req.policies = p.policies
|
||||
return req.Next()
|
||||
}
|
||||
260
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/request.go
generated
vendored
Normal file
260
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/request.go
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
)
|
||||
|
||||
// Base64Encoding is usesd to specify which base-64 encoder/decoder to use when
|
||||
// encoding/decoding a slice of bytes to/from a string.
|
||||
// Exported as runtime.Base64Encoding
|
||||
type Base64Encoding int
|
||||
|
||||
const (
|
||||
// Base64StdFormat uses base64.StdEncoding for encoding and decoding payloads.
|
||||
Base64StdFormat Base64Encoding = 0
|
||||
|
||||
// Base64URLFormat uses base64.RawURLEncoding for encoding and decoding payloads.
|
||||
Base64URLFormat Base64Encoding = 1
|
||||
)
|
||||
|
||||
// EncodeByteArray will base-64 encode the byte slice v.
|
||||
// Exported as runtime.EncodeByteArray()
|
||||
func EncodeByteArray(v []byte, format Base64Encoding) string {
|
||||
if format == Base64URLFormat {
|
||||
return base64.RawURLEncoding.EncodeToString(v)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(v)
|
||||
}
|
||||
|
||||
// Request is an abstraction over the creation of an HTTP request as it passes through the pipeline.
|
||||
// Don't use this type directly, use NewRequest() instead.
|
||||
// Exported as policy.Request.
|
||||
type Request struct {
|
||||
req *http.Request
|
||||
body io.ReadSeekCloser
|
||||
policies []Policy
|
||||
values opValues
|
||||
}
|
||||
|
||||
type opValues map[reflect.Type]any
|
||||
|
||||
// Set adds/changes a value
|
||||
func (ov opValues) set(value any) {
|
||||
ov[reflect.TypeOf(value)] = value
|
||||
}
|
||||
|
||||
// Get looks for a value set by SetValue first
|
||||
func (ov opValues) get(value any) bool {
|
||||
v, ok := ov[reflect.ValueOf(value).Elem().Type()]
|
||||
if ok {
|
||||
reflect.ValueOf(value).Elem().Set(reflect.ValueOf(v))
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// NewRequestFromRequest creates a new policy.Request with an existing *http.Request
|
||||
// Exported as runtime.NewRequestFromRequest().
|
||||
func NewRequestFromRequest(req *http.Request) (*Request, error) {
|
||||
policyReq := &Request{req: req}
|
||||
|
||||
if req.Body != nil {
|
||||
// we can avoid a body copy here if the underlying stream is already a
|
||||
// ReadSeekCloser.
|
||||
readSeekCloser, isReadSeekCloser := req.Body.(io.ReadSeekCloser)
|
||||
|
||||
if !isReadSeekCloser {
|
||||
// since this is an already populated http.Request we want to copy
|
||||
// over its body, if it has one.
|
||||
bodyBytes, err := io.ReadAll(req.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := req.Body.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
readSeekCloser = NopCloser(bytes.NewReader(bodyBytes))
|
||||
}
|
||||
|
||||
// SetBody also takes care of updating the http.Request's body
|
||||
// as well, so they should stay in-sync from this point.
|
||||
if err := policyReq.SetBody(readSeekCloser, req.Header.Get("Content-Type")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return policyReq, nil
|
||||
}
|
||||
|
||||
// NewRequest creates a new Request with the specified input.
|
||||
// Exported as runtime.NewRequest().
|
||||
func NewRequest(ctx context.Context, httpMethod string, endpoint string) (*Request, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, httpMethod, endpoint, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.URL.Host == "" {
|
||||
return nil, errors.New("no Host in request URL")
|
||||
}
|
||||
if !(req.URL.Scheme == "http" || req.URL.Scheme == "https") {
|
||||
return nil, fmt.Errorf("unsupported protocol scheme %s", req.URL.Scheme)
|
||||
}
|
||||
return &Request{req: req}, nil
|
||||
}
|
||||
|
||||
// Body returns the original body specified when the Request was created.
|
||||
func (req *Request) Body() io.ReadSeekCloser {
|
||||
return req.body
|
||||
}
|
||||
|
||||
// Raw returns the underlying HTTP request.
|
||||
func (req *Request) Raw() *http.Request {
|
||||
return req.req
|
||||
}
|
||||
|
||||
// Next calls the next policy in the pipeline.
|
||||
// If there are no more policies, nil and an error are returned.
|
||||
// This method is intended to be called from pipeline policies.
|
||||
// To send a request through a pipeline call Pipeline.Do().
|
||||
func (req *Request) Next() (*http.Response, error) {
|
||||
if len(req.policies) == 0 {
|
||||
return nil, errors.New("no more policies")
|
||||
}
|
||||
nextPolicy := req.policies[0]
|
||||
nextReq := *req
|
||||
nextReq.policies = nextReq.policies[1:]
|
||||
return nextPolicy.Do(&nextReq)
|
||||
}
|
||||
|
||||
// SetOperationValue adds/changes a mutable key/value associated with a single operation.
|
||||
func (req *Request) SetOperationValue(value any) {
|
||||
if req.values == nil {
|
||||
req.values = opValues{}
|
||||
}
|
||||
req.values.set(value)
|
||||
}
|
||||
|
||||
// OperationValue looks for a value set by SetOperationValue().
|
||||
func (req *Request) OperationValue(value any) bool {
|
||||
if req.values == nil {
|
||||
return false
|
||||
}
|
||||
return req.values.get(value)
|
||||
}
|
||||
|
||||
// SetBody sets the specified ReadSeekCloser as the HTTP request body, and sets Content-Type and Content-Length
|
||||
// accordingly. If the ReadSeekCloser is nil or empty, Content-Length won't be set. If contentType is "",
|
||||
// Content-Type won't be set, and if it was set, will be deleted.
|
||||
// Use streaming.NopCloser to turn an io.ReadSeeker into an io.ReadSeekCloser.
|
||||
func (req *Request) SetBody(body io.ReadSeekCloser, contentType string) error {
|
||||
// clobber the existing Content-Type to preserve behavior
|
||||
return SetBody(req, body, contentType, true)
|
||||
}
|
||||
|
||||
// RewindBody seeks the request's Body stream back to the beginning so it can be resent when retrying an operation.
|
||||
func (req *Request) RewindBody() error {
|
||||
if req.body != nil {
|
||||
// Reset the stream back to the beginning and restore the body
|
||||
_, err := req.body.Seek(0, io.SeekStart)
|
||||
req.req.Body = req.body
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the request body.
|
||||
func (req *Request) Close() error {
|
||||
if req.body == nil {
|
||||
return nil
|
||||
}
|
||||
return req.body.Close()
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the request with its context changed to ctx.
|
||||
func (req *Request) Clone(ctx context.Context) *Request {
|
||||
r2 := *req
|
||||
r2.req = req.req.Clone(ctx)
|
||||
return &r2
|
||||
}
|
||||
|
||||
// WithContext returns a shallow copy of the request with its context changed to ctx.
|
||||
func (req *Request) WithContext(ctx context.Context) *Request {
|
||||
r2 := new(Request)
|
||||
*r2 = *req
|
||||
r2.req = r2.req.WithContext(ctx)
|
||||
return r2
|
||||
}
|
||||
|
||||
// not exported but dependent on Request
|
||||
|
||||
// PolicyFunc is a type that implements the Policy interface.
|
||||
// Use this type when implementing a stateless policy as a first-class function.
|
||||
type PolicyFunc func(*Request) (*http.Response, error)
|
||||
|
||||
// Do implements the Policy interface on policyFunc.
|
||||
func (pf PolicyFunc) Do(req *Request) (*http.Response, error) {
|
||||
return pf(req)
|
||||
}
|
||||
|
||||
// SetBody sets the specified ReadSeekCloser as the HTTP request body, and sets Content-Type and Content-Length accordingly.
|
||||
// - req is the request to modify
|
||||
// - body is the request body; if nil or empty, Content-Length won't be set
|
||||
// - contentType is the value for the Content-Type header; if empty, Content-Type will be deleted
|
||||
// - clobberContentType when true, will overwrite the existing value of Content-Type with contentType
|
||||
func SetBody(req *Request, body io.ReadSeekCloser, contentType string, clobberContentType bool) error {
|
||||
var err error
|
||||
var size int64
|
||||
if body != nil {
|
||||
size, err = body.Seek(0, io.SeekEnd) // Seek to the end to get the stream's size
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if size == 0 {
|
||||
// treat an empty stream the same as a nil one: assign req a nil body
|
||||
body = nil
|
||||
// RFC 9110 specifies a client shouldn't set Content-Length on a request containing no content
|
||||
// (Del is a no-op when the header has no value)
|
||||
req.req.Header.Del(shared.HeaderContentLength)
|
||||
} else {
|
||||
_, err = body.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.req.Header.Set(shared.HeaderContentLength, strconv.FormatInt(size, 10))
|
||||
req.Raw().GetBody = func() (io.ReadCloser, error) {
|
||||
_, err := body.Seek(0, io.SeekStart) // Seek back to the beginning of the stream
|
||||
return body, err
|
||||
}
|
||||
}
|
||||
// keep a copy of the body argument. this is to handle cases
|
||||
// where req.Body is replaced, e.g. httputil.DumpRequest and friends.
|
||||
req.body = body
|
||||
req.req.Body = body
|
||||
req.req.ContentLength = size
|
||||
if contentType == "" {
|
||||
// Del is a no-op when the header has no value
|
||||
req.req.Header.Del(shared.HeaderContentType)
|
||||
} else if req.req.Header.Get(shared.HeaderContentType) == "" || clobberContentType {
|
||||
req.req.Header.Set(shared.HeaderContentType, contentType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
201
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/response_error.go
generated
vendored
Normal file
201
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/response_error.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/exported"
|
||||
)
|
||||
|
||||
// NewResponseError creates a new *ResponseError from the provided HTTP response.
|
||||
// Exported as runtime.NewResponseError().
|
||||
func NewResponseError(resp *http.Response) error {
|
||||
// prefer the error code in the response header
|
||||
if ec := resp.Header.Get(shared.HeaderXMSErrorCode); ec != "" {
|
||||
return NewResponseErrorWithErrorCode(resp, ec)
|
||||
}
|
||||
|
||||
// if we didn't get x-ms-error-code, check in the response body
|
||||
body, err := exported.Payload(resp, nil)
|
||||
if err != nil {
|
||||
// since we're not returning the ResponseError in this
|
||||
// case we also don't want to write it to the log.
|
||||
return err
|
||||
}
|
||||
|
||||
var errorCode string
|
||||
if len(body) > 0 {
|
||||
if fromJSON := extractErrorCodeJSON(body); fromJSON != "" {
|
||||
errorCode = fromJSON
|
||||
} else if fromXML := extractErrorCodeXML(body); fromXML != "" {
|
||||
errorCode = fromXML
|
||||
}
|
||||
}
|
||||
|
||||
return NewResponseErrorWithErrorCode(resp, errorCode)
|
||||
}
|
||||
|
||||
// NewResponseErrorWithErrorCode creates an *azcore.ResponseError from the provided HTTP response and errorCode.
|
||||
// Exported as runtime.NewResponseErrorWithErrorCode().
|
||||
func NewResponseErrorWithErrorCode(resp *http.Response, errorCode string) error {
|
||||
respErr := &ResponseError{
|
||||
ErrorCode: errorCode,
|
||||
StatusCode: resp.StatusCode,
|
||||
RawResponse: resp,
|
||||
}
|
||||
log.Write(log.EventResponseError, respErr.Error())
|
||||
return respErr
|
||||
}
|
||||
|
||||
func extractErrorCodeJSON(body []byte) string {
|
||||
var rawObj map[string]any
|
||||
if err := json.Unmarshal(body, &rawObj); err != nil {
|
||||
// not a JSON object
|
||||
return ""
|
||||
}
|
||||
|
||||
// check if this is a wrapped error, i.e. { "error": { ... } }
|
||||
// if so then unwrap it
|
||||
if wrapped, ok := rawObj["error"]; ok {
|
||||
unwrapped, ok := wrapped.(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
rawObj = unwrapped
|
||||
} else if wrapped, ok := rawObj["odata.error"]; ok {
|
||||
// check if this a wrapped odata error, i.e. { "odata.error": { ... } }
|
||||
unwrapped, ok := wrapped.(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
rawObj = unwrapped
|
||||
}
|
||||
|
||||
// now check for the error code
|
||||
code, ok := rawObj["code"]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
codeStr, ok := code.(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return codeStr
|
||||
}
|
||||
|
||||
func extractErrorCodeXML(body []byte) string {
|
||||
// regular expression is much easier than dealing with the XML parser
|
||||
rx := regexp.MustCompile(`<(?:\w+:)?[c|C]ode>\s*(\w+)\s*<\/(?:\w+:)?[c|C]ode>`)
|
||||
res := rx.FindStringSubmatch(string(body))
|
||||
if len(res) != 2 {
|
||||
return ""
|
||||
}
|
||||
// first submatch is the entire thing, second one is the captured error code
|
||||
return res[1]
|
||||
}
|
||||
|
||||
// ResponseError is returned when a request is made to a service and
|
||||
// the service returns a non-success HTTP status code.
|
||||
// Use errors.As() to access this type in the error chain.
|
||||
// Exported as azcore.ResponseError.
|
||||
type ResponseError struct {
|
||||
// ErrorCode is the error code returned by the resource provider if available.
|
||||
ErrorCode string
|
||||
|
||||
// StatusCode is the HTTP status code as defined in https://pkg.go.dev/net/http#pkg-constants.
|
||||
StatusCode int
|
||||
|
||||
// RawResponse is the underlying HTTP response.
|
||||
RawResponse *http.Response `json:"-"`
|
||||
|
||||
errMsg string
|
||||
}
|
||||
|
||||
// Error implements the error interface for type ResponseError.
|
||||
// Note that the message contents are not contractual and can change over time.
|
||||
func (e *ResponseError) Error() string {
|
||||
if e.errMsg != "" {
|
||||
return e.errMsg
|
||||
}
|
||||
|
||||
const separator = "--------------------------------------------------------------------------------"
|
||||
// write the request method and URL with response status code
|
||||
msg := &bytes.Buffer{}
|
||||
if e.RawResponse != nil {
|
||||
if e.RawResponse.Request != nil {
|
||||
fmt.Fprintf(msg, "%s %s://%s%s\n", e.RawResponse.Request.Method, e.RawResponse.Request.URL.Scheme, e.RawResponse.Request.URL.Host, e.RawResponse.Request.URL.Path)
|
||||
} else {
|
||||
fmt.Fprintln(msg, "Request information not available")
|
||||
}
|
||||
fmt.Fprintln(msg, separator)
|
||||
fmt.Fprintf(msg, "RESPONSE %d: %s\n", e.RawResponse.StatusCode, e.RawResponse.Status)
|
||||
} else {
|
||||
fmt.Fprintln(msg, "Missing RawResponse")
|
||||
fmt.Fprintln(msg, separator)
|
||||
}
|
||||
if e.ErrorCode != "" {
|
||||
fmt.Fprintf(msg, "ERROR CODE: %s\n", e.ErrorCode)
|
||||
} else {
|
||||
fmt.Fprintln(msg, "ERROR CODE UNAVAILABLE")
|
||||
}
|
||||
if e.RawResponse != nil {
|
||||
fmt.Fprintln(msg, separator)
|
||||
body, err := exported.Payload(e.RawResponse, nil)
|
||||
if err != nil {
|
||||
// this really shouldn't fail at this point as the response
|
||||
// body is already cached (it was read in NewResponseError)
|
||||
fmt.Fprintf(msg, "Error reading response body: %v", err)
|
||||
} else if len(body) > 0 {
|
||||
if err := json.Indent(msg, body, "", " "); err != nil {
|
||||
// failed to pretty-print so just dump it verbatim
|
||||
fmt.Fprint(msg, string(body))
|
||||
}
|
||||
// the standard library doesn't have a pretty-printer for XML
|
||||
fmt.Fprintln(msg)
|
||||
} else {
|
||||
fmt.Fprintln(msg, "Response contained no body")
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(msg, separator)
|
||||
|
||||
e.errMsg = msg.String()
|
||||
return e.errMsg
|
||||
}
|
||||
|
||||
// internal type used for marshaling/unmarshaling
|
||||
type responseError struct {
|
||||
ErrorCode string `json:"errorCode"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
}
|
||||
|
||||
func (e ResponseError) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(responseError{
|
||||
ErrorCode: e.ErrorCode,
|
||||
StatusCode: e.StatusCode,
|
||||
ErrorMessage: e.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
func (e *ResponseError) UnmarshalJSON(data []byte) error {
|
||||
re := responseError{}
|
||||
if err := json.Unmarshal(data, &re); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.ErrorCode = re.ErrorCode
|
||||
e.StatusCode = re.StatusCode
|
||||
e.errMsg = re.ErrorMessage
|
||||
return nil
|
||||
}
|
||||
50
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log/log.go
generated
vendored
Normal file
50
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log/log.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
// This is an internal helper package to combine the complete logging APIs.
|
||||
package log
|
||||
|
||||
import (
|
||||
azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
)
|
||||
|
||||
type Event = log.Event
|
||||
|
||||
const (
|
||||
EventRequest = azlog.EventRequest
|
||||
EventResponse = azlog.EventResponse
|
||||
EventResponseError = azlog.EventResponseError
|
||||
EventRetryPolicy = azlog.EventRetryPolicy
|
||||
EventLRO = azlog.EventLRO
|
||||
)
|
||||
|
||||
// Write invokes the underlying listener with the specified event and message.
|
||||
// If the event shouldn't be logged or there is no listener then Write does nothing.
|
||||
func Write(cls log.Event, msg string) {
|
||||
log.Write(cls, msg)
|
||||
}
|
||||
|
||||
// Writef invokes the underlying listener with the specified event and formatted message.
|
||||
// If the event shouldn't be logged or there is no listener then Writef does nothing.
|
||||
func Writef(cls log.Event, format string, a ...any) {
|
||||
log.Writef(cls, format, a...)
|
||||
}
|
||||
|
||||
// SetListener will set the Logger to write to the specified listener.
|
||||
func SetListener(lst func(Event, string)) {
|
||||
log.SetListener(lst)
|
||||
}
|
||||
|
||||
// Should returns true if the specified log event should be written to the log.
|
||||
// By default all log events will be logged. Call SetEvents() to limit
|
||||
// the log events for logging.
|
||||
// If no listener has been set this will return false.
|
||||
// Calling this method is useful when the message to log is computationally expensive
|
||||
// and you want to avoid the overhead if its log event is not enabled.
|
||||
func Should(cls log.Event) bool {
|
||||
return log.Should(cls)
|
||||
}
|
||||
159
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async/async.go
generated
vendored
Normal file
159
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async/async.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package async
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/poller"
|
||||
)
|
||||
|
||||
// see https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/async-api-reference.md
|
||||
|
||||
// Applicable returns true if the LRO is using Azure-AsyncOperation.
|
||||
func Applicable(resp *http.Response) bool {
|
||||
return resp.Header.Get(shared.HeaderAzureAsync) != ""
|
||||
}
|
||||
|
||||
// CanResume returns true if the token can rehydrate this poller type.
|
||||
func CanResume(token map[string]any) bool {
|
||||
_, ok := token["asyncURL"]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Poller is an LRO poller that uses the Azure-AsyncOperation pattern.
|
||||
type Poller[T any] struct {
|
||||
pl exported.Pipeline
|
||||
|
||||
resp *http.Response
|
||||
|
||||
// The URL from Azure-AsyncOperation header.
|
||||
AsyncURL string `json:"asyncURL"`
|
||||
|
||||
// The URL from Location header.
|
||||
LocURL string `json:"locURL"`
|
||||
|
||||
// The URL from the initial LRO request.
|
||||
OrigURL string `json:"origURL"`
|
||||
|
||||
// The HTTP method from the initial LRO request.
|
||||
Method string `json:"method"`
|
||||
|
||||
// The value of final-state-via from swagger, can be the empty string.
|
||||
FinalState pollers.FinalStateVia `json:"finalState"`
|
||||
|
||||
// The LRO's current state.
|
||||
CurState string `json:"state"`
|
||||
}
|
||||
|
||||
// New creates a new Poller from the provided initial response and final-state type.
|
||||
// Pass nil for response to create an empty Poller for rehydration.
|
||||
func New[T any](pl exported.Pipeline, resp *http.Response, finalState pollers.FinalStateVia) (*Poller[T], error) {
|
||||
if resp == nil {
|
||||
log.Write(log.EventLRO, "Resuming Azure-AsyncOperation poller.")
|
||||
return &Poller[T]{pl: pl}, nil
|
||||
}
|
||||
log.Write(log.EventLRO, "Using Azure-AsyncOperation poller.")
|
||||
asyncURL := resp.Header.Get(shared.HeaderAzureAsync)
|
||||
if asyncURL == "" {
|
||||
return nil, errors.New("response is missing Azure-AsyncOperation header")
|
||||
}
|
||||
if !poller.IsValidURL(asyncURL) {
|
||||
return nil, fmt.Errorf("invalid polling URL %s", asyncURL)
|
||||
}
|
||||
// check for provisioning state. if the operation is a RELO
|
||||
// and terminates synchronously this will prevent extra polling.
|
||||
// it's ok if there's no provisioning state.
|
||||
state, _ := poller.GetProvisioningState(resp)
|
||||
if state == "" {
|
||||
state = poller.StatusInProgress
|
||||
}
|
||||
p := &Poller[T]{
|
||||
pl: pl,
|
||||
resp: resp,
|
||||
AsyncURL: asyncURL,
|
||||
LocURL: resp.Header.Get(shared.HeaderLocation),
|
||||
OrigURL: resp.Request.URL.String(),
|
||||
Method: resp.Request.Method,
|
||||
FinalState: finalState,
|
||||
CurState: state,
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Done returns true if the LRO is in a terminal state.
|
||||
func (p *Poller[T]) Done() bool {
|
||||
return poller.IsTerminalState(p.CurState)
|
||||
}
|
||||
|
||||
// Poll retrieves the current state of the LRO.
|
||||
func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) {
|
||||
err := pollers.PollHelper(ctx, p.AsyncURL, p.pl, func(resp *http.Response) (string, error) {
|
||||
if !poller.StatusCodeValid(resp) {
|
||||
p.resp = resp
|
||||
return "", exported.NewResponseError(resp)
|
||||
}
|
||||
state, err := poller.GetStatus(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if state == "" {
|
||||
return "", errors.New("the response did not contain a status")
|
||||
}
|
||||
p.resp = resp
|
||||
p.CurState = state
|
||||
return p.CurState, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.resp, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Result(ctx context.Context, out *T) error {
|
||||
if p.resp.StatusCode == http.StatusNoContent {
|
||||
return nil
|
||||
} else if poller.Failed(p.CurState) {
|
||||
return exported.NewResponseError(p.resp)
|
||||
}
|
||||
var req *exported.Request
|
||||
var err error
|
||||
if p.Method == http.MethodPatch || p.Method == http.MethodPut {
|
||||
// for PATCH and PUT, the final GET is on the original resource URL
|
||||
req, err = exported.NewRequest(ctx, http.MethodGet, p.OrigURL)
|
||||
} else if p.Method == http.MethodPost {
|
||||
if p.FinalState == pollers.FinalStateViaAzureAsyncOp {
|
||||
// no final GET required
|
||||
} else if p.FinalState == pollers.FinalStateViaOriginalURI {
|
||||
req, err = exported.NewRequest(ctx, http.MethodGet, p.OrigURL)
|
||||
} else if p.LocURL != "" {
|
||||
// ideally FinalState would be set to "location" but it isn't always.
|
||||
// must check last due to more permissive condition.
|
||||
req, err = exported.NewRequest(ctx, http.MethodGet, p.LocURL)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if a final GET request has been created, execute it
|
||||
if req != nil {
|
||||
resp, err := p.pl.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.resp = resp
|
||||
}
|
||||
|
||||
return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), "", out)
|
||||
}
|
||||
135
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body/body.go
generated
vendored
Normal file
135
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body/body.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package body
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/poller"
|
||||
)
|
||||
|
||||
// Kind is the identifier of this type in a resume token.
|
||||
const kind = "body"
|
||||
|
||||
// Applicable returns true if the LRO is using no headers, just provisioning state.
|
||||
// This is only applicable to PATCH and PUT methods and assumes no polling headers.
|
||||
func Applicable(resp *http.Response) bool {
|
||||
// we can't check for absense of headers due to some misbehaving services
|
||||
// like redis that return a Location header but don't actually use that protocol
|
||||
return resp.Request.Method == http.MethodPatch || resp.Request.Method == http.MethodPut
|
||||
}
|
||||
|
||||
// CanResume returns true if the token can rehydrate this poller type.
|
||||
func CanResume(token map[string]any) bool {
|
||||
t, ok := token["type"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
tt, ok := t.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return tt == kind
|
||||
}
|
||||
|
||||
// Poller is an LRO poller that uses the Body pattern.
|
||||
type Poller[T any] struct {
|
||||
pl exported.Pipeline
|
||||
|
||||
resp *http.Response
|
||||
|
||||
// The poller's type, used for resume token processing.
|
||||
Type string `json:"type"`
|
||||
|
||||
// The URL for polling.
|
||||
PollURL string `json:"pollURL"`
|
||||
|
||||
// The LRO's current state.
|
||||
CurState string `json:"state"`
|
||||
}
|
||||
|
||||
// New creates a new Poller from the provided initial response.
|
||||
// Pass nil for response to create an empty Poller for rehydration.
|
||||
func New[T any](pl exported.Pipeline, resp *http.Response) (*Poller[T], error) {
|
||||
if resp == nil {
|
||||
log.Write(log.EventLRO, "Resuming Body poller.")
|
||||
return &Poller[T]{pl: pl}, nil
|
||||
}
|
||||
log.Write(log.EventLRO, "Using Body poller.")
|
||||
p := &Poller[T]{
|
||||
pl: pl,
|
||||
resp: resp,
|
||||
Type: kind,
|
||||
PollURL: resp.Request.URL.String(),
|
||||
}
|
||||
// default initial state to InProgress. depending on the HTTP
|
||||
// status code and provisioning state, we might change the value.
|
||||
curState := poller.StatusInProgress
|
||||
provState, err := poller.GetProvisioningState(resp)
|
||||
if err != nil && !errors.Is(err, poller.ErrNoBody) {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode == http.StatusCreated && provState != "" {
|
||||
// absense of provisioning state is ok for a 201, means the operation is in progress
|
||||
curState = provState
|
||||
} else if resp.StatusCode == http.StatusOK {
|
||||
if provState != "" {
|
||||
curState = provState
|
||||
} else if provState == "" {
|
||||
// for a 200, absense of provisioning state indicates success
|
||||
curState = poller.StatusSucceeded
|
||||
}
|
||||
} else if resp.StatusCode == http.StatusNoContent {
|
||||
curState = poller.StatusSucceeded
|
||||
}
|
||||
p.CurState = curState
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Done() bool {
|
||||
return poller.IsTerminalState(p.CurState)
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) {
|
||||
err := pollers.PollHelper(ctx, p.PollURL, p.pl, func(resp *http.Response) (string, error) {
|
||||
if !poller.StatusCodeValid(resp) {
|
||||
p.resp = resp
|
||||
return "", exported.NewResponseError(resp)
|
||||
}
|
||||
if resp.StatusCode == http.StatusNoContent {
|
||||
p.resp = resp
|
||||
p.CurState = poller.StatusSucceeded
|
||||
return p.CurState, nil
|
||||
}
|
||||
state, err := poller.GetProvisioningState(resp)
|
||||
if errors.Is(err, poller.ErrNoBody) {
|
||||
// a missing response body in non-204 case is an error
|
||||
return "", err
|
||||
} else if state == "" {
|
||||
// a response body without provisioning state is considered terminal success
|
||||
state = poller.StatusSucceeded
|
||||
} else if err != nil {
|
||||
return "", err
|
||||
}
|
||||
p.resp = resp
|
||||
p.CurState = state
|
||||
return p.CurState, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.resp, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Result(ctx context.Context, out *T) error {
|
||||
return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), "", out)
|
||||
}
|
||||
133
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/fake/fake.go
generated
vendored
Normal file
133
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/fake/fake.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/poller"
|
||||
)
|
||||
|
||||
// Applicable returns true if the LRO is a fake.
|
||||
func Applicable(resp *http.Response) bool {
|
||||
return resp.Header.Get(shared.HeaderFakePollerStatus) != ""
|
||||
}
|
||||
|
||||
// CanResume returns true if the token can rehydrate this poller type.
|
||||
func CanResume(token map[string]any) bool {
|
||||
_, ok := token["fakeURL"]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Poller is an LRO poller that uses the Core-Fake-Poller pattern.
|
||||
type Poller[T any] struct {
|
||||
pl exported.Pipeline
|
||||
|
||||
resp *http.Response
|
||||
|
||||
// The API name from CtxAPINameKey
|
||||
APIName string `json:"apiName"`
|
||||
|
||||
// The URL from Core-Fake-Poller header.
|
||||
FakeURL string `json:"fakeURL"`
|
||||
|
||||
// The LRO's current state.
|
||||
FakeStatus string `json:"status"`
|
||||
}
|
||||
|
||||
// lroStatusURLSuffix is the URL path suffix for a faked LRO.
|
||||
const lroStatusURLSuffix = "/get/fake/status"
|
||||
|
||||
// New creates a new Poller from the provided initial response.
|
||||
// Pass nil for response to create an empty Poller for rehydration.
|
||||
func New[T any](pl exported.Pipeline, resp *http.Response) (*Poller[T], error) {
|
||||
if resp == nil {
|
||||
log.Write(log.EventLRO, "Resuming Core-Fake-Poller poller.")
|
||||
return &Poller[T]{pl: pl}, nil
|
||||
}
|
||||
|
||||
log.Write(log.EventLRO, "Using Core-Fake-Poller poller.")
|
||||
fakeStatus := resp.Header.Get(shared.HeaderFakePollerStatus)
|
||||
if fakeStatus == "" {
|
||||
return nil, errors.New("response is missing Fake-Poller-Status header")
|
||||
}
|
||||
|
||||
ctxVal := resp.Request.Context().Value(shared.CtxAPINameKey{})
|
||||
if ctxVal == nil {
|
||||
return nil, errors.New("missing value for CtxAPINameKey")
|
||||
}
|
||||
|
||||
apiName, ok := ctxVal.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected string for CtxAPINameKey, the type was %T", ctxVal)
|
||||
}
|
||||
|
||||
qp := ""
|
||||
if resp.Request.URL.RawQuery != "" {
|
||||
qp = "?" + resp.Request.URL.RawQuery
|
||||
}
|
||||
|
||||
p := &Poller[T]{
|
||||
pl: pl,
|
||||
resp: resp,
|
||||
APIName: apiName,
|
||||
// NOTE: any changes to this path format MUST be reflected in SanitizePollerPath()
|
||||
FakeURL: fmt.Sprintf("%s://%s%s%s%s", resp.Request.URL.Scheme, resp.Request.URL.Host, resp.Request.URL.Path, lroStatusURLSuffix, qp),
|
||||
FakeStatus: fakeStatus,
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Done returns true if the LRO is in a terminal state.
|
||||
func (p *Poller[T]) Done() bool {
|
||||
return poller.IsTerminalState(p.FakeStatus)
|
||||
}
|
||||
|
||||
// Poll retrieves the current state of the LRO.
|
||||
func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) {
|
||||
ctx = context.WithValue(ctx, shared.CtxAPINameKey{}, p.APIName)
|
||||
err := pollers.PollHelper(ctx, p.FakeURL, p.pl, func(resp *http.Response) (string, error) {
|
||||
if !poller.StatusCodeValid(resp) {
|
||||
p.resp = resp
|
||||
return "", exported.NewResponseError(resp)
|
||||
}
|
||||
fakeStatus := resp.Header.Get(shared.HeaderFakePollerStatus)
|
||||
if fakeStatus == "" {
|
||||
return "", errors.New("response is missing Fake-Poller-Status header")
|
||||
}
|
||||
p.resp = resp
|
||||
p.FakeStatus = fakeStatus
|
||||
return p.FakeStatus, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.resp, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Result(ctx context.Context, out *T) error {
|
||||
if p.resp.StatusCode == http.StatusNoContent {
|
||||
return nil
|
||||
} else if poller.Failed(p.FakeStatus) {
|
||||
return exported.NewResponseError(p.resp)
|
||||
}
|
||||
|
||||
return pollers.ResultHelper(p.resp, poller.Failed(p.FakeStatus), "", out)
|
||||
}
|
||||
|
||||
// SanitizePollerPath removes any fake-appended suffix from a URL's path.
|
||||
func SanitizePollerPath(path string) string {
|
||||
return strings.TrimSuffix(path, lroStatusURLSuffix)
|
||||
}
|
||||
123
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc/loc.go
generated
vendored
Normal file
123
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc/loc.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package loc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/poller"
|
||||
)
|
||||
|
||||
// Kind is the identifier of this type in a resume token.
|
||||
const kind = "loc"
|
||||
|
||||
// Applicable returns true if the LRO is using Location.
|
||||
func Applicable(resp *http.Response) bool {
|
||||
return resp.Header.Get(shared.HeaderLocation) != ""
|
||||
}
|
||||
|
||||
// CanResume returns true if the token can rehydrate this poller type.
|
||||
func CanResume(token map[string]any) bool {
|
||||
t, ok := token["type"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
tt, ok := t.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return tt == kind
|
||||
}
|
||||
|
||||
// Poller is an LRO poller that uses the Location pattern.
|
||||
type Poller[T any] struct {
|
||||
pl exported.Pipeline
|
||||
resp *http.Response
|
||||
|
||||
Type string `json:"type"`
|
||||
PollURL string `json:"pollURL"`
|
||||
CurState string `json:"state"`
|
||||
}
|
||||
|
||||
// New creates a new Poller from the provided initial response.
|
||||
// Pass nil for response to create an empty Poller for rehydration.
|
||||
func New[T any](pl exported.Pipeline, resp *http.Response) (*Poller[T], error) {
|
||||
if resp == nil {
|
||||
log.Write(log.EventLRO, "Resuming Location poller.")
|
||||
return &Poller[T]{pl: pl}, nil
|
||||
}
|
||||
log.Write(log.EventLRO, "Using Location poller.")
|
||||
locURL := resp.Header.Get(shared.HeaderLocation)
|
||||
if locURL == "" {
|
||||
return nil, errors.New("response is missing Location header")
|
||||
}
|
||||
if !poller.IsValidURL(locURL) {
|
||||
return nil, fmt.Errorf("invalid polling URL %s", locURL)
|
||||
}
|
||||
// check for provisioning state. if the operation is a RELO
|
||||
// and terminates synchronously this will prevent extra polling.
|
||||
// it's ok if there's no provisioning state.
|
||||
state, _ := poller.GetProvisioningState(resp)
|
||||
if state == "" {
|
||||
state = poller.StatusInProgress
|
||||
}
|
||||
return &Poller[T]{
|
||||
pl: pl,
|
||||
resp: resp,
|
||||
Type: kind,
|
||||
PollURL: locURL,
|
||||
CurState: state,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Done() bool {
|
||||
return poller.IsTerminalState(p.CurState)
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) {
|
||||
err := pollers.PollHelper(ctx, p.PollURL, p.pl, func(resp *http.Response) (string, error) {
|
||||
// location polling can return an updated polling URL
|
||||
if h := resp.Header.Get(shared.HeaderLocation); h != "" {
|
||||
p.PollURL = h
|
||||
}
|
||||
// if provisioning state is available, use that. this is only
|
||||
// for some ARM LRO scenarios (e.g. DELETE with a Location header)
|
||||
// so if it's missing then use HTTP status code.
|
||||
provState, _ := poller.GetProvisioningState(resp)
|
||||
p.resp = resp
|
||||
if provState != "" {
|
||||
p.CurState = provState
|
||||
} else if resp.StatusCode == http.StatusAccepted {
|
||||
p.CurState = poller.StatusInProgress
|
||||
} else if resp.StatusCode > 199 && resp.StatusCode < 300 {
|
||||
// any 2xx other than a 202 indicates success
|
||||
p.CurState = poller.StatusSucceeded
|
||||
} else if pollers.IsNonTerminalHTTPStatusCode(resp) {
|
||||
// the request timed out or is being throttled.
|
||||
// DO NOT include this as a terminal failure. preserve
|
||||
// the existing state and return the response.
|
||||
} else {
|
||||
p.CurState = poller.StatusFailed
|
||||
}
|
||||
return p.CurState, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.resp, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Result(ctx context.Context, out *T) error {
|
||||
return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), "", out)
|
||||
}
|
||||
150
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op/op.go
generated
vendored
Normal file
150
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op/op.go
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package op
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/poller"
|
||||
)
|
||||
|
||||
// Applicable returns true if the LRO is using Operation-Location.
|
||||
func Applicable(resp *http.Response) bool {
|
||||
return resp.Header.Get(shared.HeaderOperationLocation) != ""
|
||||
}
|
||||
|
||||
// CanResume returns true if the token can rehydrate this poller type.
|
||||
func CanResume(token map[string]any) bool {
|
||||
_, ok := token["oplocURL"]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Poller is an LRO poller that uses the Operation-Location pattern.
|
||||
type Poller[T any] struct {
|
||||
pl exported.Pipeline
|
||||
resp *http.Response
|
||||
|
||||
OpLocURL string `json:"oplocURL"`
|
||||
LocURL string `json:"locURL"`
|
||||
OrigURL string `json:"origURL"`
|
||||
Method string `json:"method"`
|
||||
FinalState pollers.FinalStateVia `json:"finalState"`
|
||||
CurState string `json:"state"`
|
||||
}
|
||||
|
||||
// New creates a new Poller from the provided initial response.
|
||||
// Pass nil for response to create an empty Poller for rehydration.
|
||||
func New[T any](pl exported.Pipeline, resp *http.Response, finalState pollers.FinalStateVia) (*Poller[T], error) {
|
||||
if resp == nil {
|
||||
log.Write(log.EventLRO, "Resuming Operation-Location poller.")
|
||||
return &Poller[T]{pl: pl}, nil
|
||||
}
|
||||
log.Write(log.EventLRO, "Using Operation-Location poller.")
|
||||
opURL := resp.Header.Get(shared.HeaderOperationLocation)
|
||||
if opURL == "" {
|
||||
return nil, errors.New("response is missing Operation-Location header")
|
||||
}
|
||||
if !poller.IsValidURL(opURL) {
|
||||
return nil, fmt.Errorf("invalid Operation-Location URL %s", opURL)
|
||||
}
|
||||
locURL := resp.Header.Get(shared.HeaderLocation)
|
||||
// Location header is optional
|
||||
if locURL != "" && !poller.IsValidURL(locURL) {
|
||||
return nil, fmt.Errorf("invalid Location URL %s", locURL)
|
||||
}
|
||||
// default initial state to InProgress. if the
|
||||
// service sent us a status then use that instead.
|
||||
curState := poller.StatusInProgress
|
||||
status, err := poller.GetStatus(resp)
|
||||
if err != nil && !errors.Is(err, poller.ErrNoBody) {
|
||||
return nil, err
|
||||
}
|
||||
if status != "" {
|
||||
curState = status
|
||||
}
|
||||
|
||||
return &Poller[T]{
|
||||
pl: pl,
|
||||
resp: resp,
|
||||
OpLocURL: opURL,
|
||||
LocURL: locURL,
|
||||
OrigURL: resp.Request.URL.String(),
|
||||
Method: resp.Request.Method,
|
||||
FinalState: finalState,
|
||||
CurState: curState,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Done() bool {
|
||||
return poller.IsTerminalState(p.CurState)
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) {
|
||||
err := pollers.PollHelper(ctx, p.OpLocURL, p.pl, func(resp *http.Response) (string, error) {
|
||||
if !poller.StatusCodeValid(resp) {
|
||||
p.resp = resp
|
||||
return "", exported.NewResponseError(resp)
|
||||
}
|
||||
state, err := poller.GetStatus(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if state == "" {
|
||||
return "", errors.New("the response did not contain a status")
|
||||
}
|
||||
p.resp = resp
|
||||
p.CurState = state
|
||||
return p.CurState, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.resp, nil
|
||||
}
|
||||
|
||||
func (p *Poller[T]) Result(ctx context.Context, out *T) error {
|
||||
var req *exported.Request
|
||||
var err error
|
||||
|
||||
// when the payload is included with the status monitor on
|
||||
// terminal success it's in the "result" JSON property
|
||||
payloadPath := "result"
|
||||
|
||||
if p.FinalState == pollers.FinalStateViaLocation && p.LocURL != "" {
|
||||
req, err = exported.NewRequest(ctx, http.MethodGet, p.LocURL)
|
||||
} else if rl, rlErr := poller.GetResourceLocation(p.resp); rlErr != nil && !errors.Is(rlErr, poller.ErrNoBody) {
|
||||
return rlErr
|
||||
} else if rl != "" {
|
||||
req, err = exported.NewRequest(ctx, http.MethodGet, rl)
|
||||
} else if p.Method == http.MethodPatch || p.Method == http.MethodPut {
|
||||
req, err = exported.NewRequest(ctx, http.MethodGet, p.OrigURL)
|
||||
} else if p.Method == http.MethodPost && p.LocURL != "" {
|
||||
req, err = exported.NewRequest(ctx, http.MethodGet, p.LocURL)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if a final GET request has been created, execute it
|
||||
if req != nil {
|
||||
// no JSON path when making a final GET request
|
||||
payloadPath = ""
|
||||
resp, err := p.pl.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.resp = resp
|
||||
}
|
||||
|
||||
return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), payloadPath, out)
|
||||
}
|
||||
24
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/poller.go
generated
vendored
Normal file
24
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/poller.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package pollers
|
||||
|
||||
// FinalStateVia is the enumerated type for the possible final-state-via values.
|
||||
type FinalStateVia string
|
||||
|
||||
const (
|
||||
// FinalStateViaAzureAsyncOp indicates the final payload comes from the Azure-AsyncOperation URL.
|
||||
FinalStateViaAzureAsyncOp FinalStateVia = "azure-async-operation"
|
||||
|
||||
// FinalStateViaLocation indicates the final payload comes from the Location URL.
|
||||
FinalStateViaLocation FinalStateVia = "location"
|
||||
|
||||
// FinalStateViaOriginalURI indicates the final payload comes from the original URL.
|
||||
FinalStateViaOriginalURI FinalStateVia = "original-uri"
|
||||
|
||||
// FinalStateViaOpLocation indicates the final payload comes from the Operation-Location URL.
|
||||
FinalStateViaOpLocation FinalStateVia = "operation-location"
|
||||
)
|
||||
212
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/util.go
generated
vendored
Normal file
212
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/util.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package pollers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
azexported "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/poller"
|
||||
)
|
||||
|
||||
// getTokenTypeName creates a type name from the type parameter T.
|
||||
func getTokenTypeName[T any]() (string, error) {
|
||||
tt := shared.TypeOfT[T]()
|
||||
var n string
|
||||
if tt.Kind() == reflect.Pointer {
|
||||
n = "*"
|
||||
tt = tt.Elem()
|
||||
}
|
||||
n += tt.Name()
|
||||
if n == "" {
|
||||
return "", errors.New("nameless types are not allowed")
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
type resumeTokenWrapper[T any] struct {
|
||||
Type string `json:"type"`
|
||||
Token T `json:"token"`
|
||||
}
|
||||
|
||||
// NewResumeToken creates a resume token from the specified type.
|
||||
// An error is returned if the generic type has no name (e.g. struct{}).
|
||||
func NewResumeToken[TResult, TSource any](from TSource) (string, error) {
|
||||
n, err := getTokenTypeName[TResult]()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
b, err := json.Marshal(resumeTokenWrapper[TSource]{
|
||||
Type: n,
|
||||
Token: from,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// ExtractToken returns the poller-specific token information from the provided token value.
|
||||
func ExtractToken(token string) ([]byte, error) {
|
||||
raw := map[string]json.RawMessage{}
|
||||
if err := json.Unmarshal([]byte(token), &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// this is dependent on the type resumeTokenWrapper[T]
|
||||
tk, ok := raw["token"]
|
||||
if !ok {
|
||||
return nil, errors.New("missing token value")
|
||||
}
|
||||
return tk, nil
|
||||
}
|
||||
|
||||
// IsTokenValid returns an error if the specified token isn't applicable for generic type T.
|
||||
func IsTokenValid[T any](token string) error {
|
||||
raw := map[string]any{}
|
||||
if err := json.Unmarshal([]byte(token), &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
t, ok := raw["type"]
|
||||
if !ok {
|
||||
return errors.New("missing type value")
|
||||
}
|
||||
tt, ok := t.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type format %T", t)
|
||||
}
|
||||
n, err := getTokenTypeName[T]()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tt != n {
|
||||
return fmt.Errorf("cannot resume from this poller token. token is for type %s, not %s", tt, n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// used if the operation synchronously completed
|
||||
type NopPoller[T any] struct {
|
||||
resp *http.Response
|
||||
result T
|
||||
}
|
||||
|
||||
// NewNopPoller creates a NopPoller from the provided response.
|
||||
// It unmarshals the response body into an instance of T.
|
||||
func NewNopPoller[T any](resp *http.Response) (*NopPoller[T], error) {
|
||||
np := &NopPoller[T]{resp: resp}
|
||||
if resp.StatusCode == http.StatusNoContent {
|
||||
return np, nil
|
||||
}
|
||||
payload, err := exported.Payload(resp, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(payload) == 0 {
|
||||
return np, nil
|
||||
}
|
||||
if err = json.Unmarshal(payload, &np.result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return np, nil
|
||||
}
|
||||
|
||||
func (*NopPoller[T]) Done() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *NopPoller[T]) Poll(context.Context) (*http.Response, error) {
|
||||
return p.resp, nil
|
||||
}
|
||||
|
||||
func (p *NopPoller[T]) Result(ctx context.Context, out *T) error {
|
||||
*out = p.result
|
||||
return nil
|
||||
}
|
||||
|
||||
// PollHelper creates and executes the request, calling update() with the response.
|
||||
// If the request fails, the update func is not called.
|
||||
// The update func returns the state of the operation for logging purposes or an error
|
||||
// if it fails to extract the required state from the response.
|
||||
func PollHelper(ctx context.Context, endpoint string, pl azexported.Pipeline, update func(resp *http.Response) (string, error)) error {
|
||||
req, err := azexported.NewRequest(ctx, http.MethodGet, endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := pl.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
state, err := update(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Writef(log.EventLRO, "State %s", state)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResultHelper processes the response as success or failure.
|
||||
// In the success case, it unmarshals the payload into either a new instance of T or out.
|
||||
// In the failure case, it creates an *azcore.Response error from the response.
|
||||
func ResultHelper[T any](resp *http.Response, failed bool, jsonPath string, out *T) error {
|
||||
// short-circuit the simple success case with no response body to unmarshal
|
||||
if resp.StatusCode == http.StatusNoContent {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
if !poller.StatusCodeValid(resp) || failed {
|
||||
// the LRO failed. unmarshall the error and update state
|
||||
return azexported.NewResponseError(resp)
|
||||
}
|
||||
|
||||
// success case
|
||||
payload, err := exported.Payload(resp, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if jsonPath != "" && len(payload) > 0 {
|
||||
// extract the payload from the specified JSON path.
|
||||
// do this before the zero-length check in case there
|
||||
// is no payload.
|
||||
jsonBody := map[string]json.RawMessage{}
|
||||
if err = json.Unmarshal(payload, &jsonBody); err != nil {
|
||||
return err
|
||||
}
|
||||
payload = jsonBody[jsonPath]
|
||||
}
|
||||
|
||||
if len(payload) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(payload, out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNonTerminalHTTPStatusCode returns true if the HTTP status code should be
|
||||
// considered non-terminal thus eligible for retry.
|
||||
func IsNonTerminalHTTPStatusCode(resp *http.Response) bool {
|
||||
return exported.HasStatusCode(resp,
|
||||
http.StatusRequestTimeout, // 408
|
||||
http.StatusTooManyRequests, // 429
|
||||
http.StatusInternalServerError, // 500
|
||||
http.StatusBadGateway, // 502
|
||||
http.StatusServiceUnavailable, // 503
|
||||
http.StatusGatewayTimeout, // 504
|
||||
)
|
||||
}
|
||||
44
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
generated
vendored
Normal file
44
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package shared
|
||||
|
||||
const (
|
||||
ContentTypeAppJSON = "application/json"
|
||||
ContentTypeAppXML = "application/xml"
|
||||
ContentTypeTextPlain = "text/plain"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderAuxiliaryAuthorization = "x-ms-authorization-auxiliary"
|
||||
HeaderAzureAsync = "Azure-AsyncOperation"
|
||||
HeaderContentLength = "Content-Length"
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderFakePollerStatus = "Fake-Poller-Status"
|
||||
HeaderLocation = "Location"
|
||||
HeaderOperationLocation = "Operation-Location"
|
||||
HeaderRetryAfter = "Retry-After"
|
||||
HeaderRetryAfterMS = "Retry-After-Ms"
|
||||
HeaderUserAgent = "User-Agent"
|
||||
HeaderWWWAuthenticate = "WWW-Authenticate"
|
||||
HeaderXMSClientRequestID = "x-ms-client-request-id"
|
||||
HeaderXMSRequestID = "x-ms-request-id"
|
||||
HeaderXMSErrorCode = "x-ms-error-code"
|
||||
HeaderXMSRetryAfterMS = "x-ms-retry-after-ms"
|
||||
)
|
||||
|
||||
const BearerTokenPrefix = "Bearer "
|
||||
|
||||
const TracingNamespaceAttrName = "az.namespace"
|
||||
|
||||
const (
|
||||
// Module is the name of the calling module used in telemetry data.
|
||||
Module = "azcore"
|
||||
|
||||
// Version is the semantic version (see http://semver.org) of this module.
|
||||
Version = "v1.16.0"
|
||||
)
|
||||
149
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/shared.go
generated
vendored
Normal file
149
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/shared.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package shared
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NOTE: when adding a new context key type, it likely needs to be
|
||||
// added to the deny-list of key types in ContextWithDeniedValues
|
||||
|
||||
// CtxWithHTTPHeaderKey is used as a context key for adding/retrieving http.Header.
|
||||
type CtxWithHTTPHeaderKey struct{}
|
||||
|
||||
// CtxWithRetryOptionsKey is used as a context key for adding/retrieving RetryOptions.
|
||||
type CtxWithRetryOptionsKey struct{}
|
||||
|
||||
// CtxWithCaptureResponse is used as a context key for retrieving the raw response.
|
||||
type CtxWithCaptureResponse struct{}
|
||||
|
||||
// CtxWithTracingTracer is used as a context key for adding/retrieving tracing.Tracer.
|
||||
type CtxWithTracingTracer struct{}
|
||||
|
||||
// CtxAPINameKey is used as a context key for adding/retrieving the API name.
|
||||
type CtxAPINameKey struct{}
|
||||
|
||||
// Delay waits for the duration to elapse or the context to be cancelled.
|
||||
func Delay(ctx context.Context, delay time.Duration) error {
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// RetryAfter returns non-zero if the response contains one of the headers with a "retry after" value.
|
||||
// Headers are checked in the following order: retry-after-ms, x-ms-retry-after-ms, retry-after
|
||||
func RetryAfter(resp *http.Response) time.Duration {
|
||||
if resp == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
type retryData struct {
|
||||
header string
|
||||
units time.Duration
|
||||
|
||||
// custom is used when the regular algorithm failed and is optional.
|
||||
// the returned duration is used verbatim (units is not applied).
|
||||
custom func(string) time.Duration
|
||||
}
|
||||
|
||||
nop := func(string) time.Duration { return 0 }
|
||||
|
||||
// the headers are listed in order of preference
|
||||
retries := []retryData{
|
||||
{
|
||||
header: HeaderRetryAfterMS,
|
||||
units: time.Millisecond,
|
||||
custom: nop,
|
||||
},
|
||||
{
|
||||
header: HeaderXMSRetryAfterMS,
|
||||
units: time.Millisecond,
|
||||
custom: nop,
|
||||
},
|
||||
{
|
||||
header: HeaderRetryAfter,
|
||||
units: time.Second,
|
||||
|
||||
// retry-after values are expressed in either number of
|
||||
// seconds or an HTTP-date indicating when to try again
|
||||
custom: func(ra string) time.Duration {
|
||||
t, err := time.Parse(time.RFC1123, ra)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return time.Until(t)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, retry := range retries {
|
||||
v := resp.Header.Get(retry.header)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if retryAfter, _ := strconv.Atoi(v); retryAfter > 0 {
|
||||
return time.Duration(retryAfter) * retry.units
|
||||
} else if d := retry.custom(v); d > 0 {
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// TypeOfT returns the type of the generic type param.
|
||||
func TypeOfT[T any]() reflect.Type {
|
||||
// you can't, at present, obtain the type of
|
||||
// a type parameter, so this is the trick
|
||||
return reflect.TypeOf((*T)(nil)).Elem()
|
||||
}
|
||||
|
||||
// TransportFunc is a helper to use a first-class func to satisfy the Transporter interface.
|
||||
type TransportFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
// Do implements the Transporter interface for the TransportFunc type.
|
||||
func (pf TransportFunc) Do(req *http.Request) (*http.Response, error) {
|
||||
return pf(req)
|
||||
}
|
||||
|
||||
// ValidateModVer verifies that moduleVersion is a valid semver 2.0 string.
|
||||
func ValidateModVer(moduleVersion string) error {
|
||||
modVerRegx := regexp.MustCompile(`^v\d+\.\d+\.\d+(?:-[a-zA-Z0-9_.-]+)?$`)
|
||||
if !modVerRegx.MatchString(moduleVersion) {
|
||||
return fmt.Errorf("malformed moduleVersion param value %s", moduleVersion)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextWithDeniedValues wraps an existing [context.Context], denying access to certain context values.
|
||||
// Pipeline policies that create new requests to be sent down their own pipeline MUST wrap the caller's
|
||||
// context with an instance of this type. This is to prevent context values from flowing across disjoint
|
||||
// requests which can have unintended side-effects.
|
||||
type ContextWithDeniedValues struct {
|
||||
context.Context
|
||||
}
|
||||
|
||||
// Value implements part of the [context.Context] interface.
|
||||
// It acts as a deny-list for certain context keys.
|
||||
func (c *ContextWithDeniedValues) Value(key any) any {
|
||||
switch key.(type) {
|
||||
case CtxAPINameKey, CtxWithCaptureResponse, CtxWithHTTPHeaderKey, CtxWithRetryOptionsKey, CtxWithTracingTracer:
|
||||
return nil
|
||||
default:
|
||||
return c.Context.Value(key)
|
||||
}
|
||||
}
|
||||
10
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/log/doc.go
generated
vendored
Normal file
10
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/log/doc.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
||||
// Use of this source code is governed by an MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package log contains functionality for configuring logging behavior.
|
||||
// Default logging to stderr can be enabled by setting environment variable AZURE_SDK_GO_LOGGING to "all".
|
||||
package log
|
||||
55
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/log/log.go
generated
vendored
Normal file
55
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/log/log.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
// Package log provides functionality for configuring logging facilities.
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
)
|
||||
|
||||
// Event is used to group entries. Each group can be toggled on or off.
|
||||
type Event = log.Event
|
||||
|
||||
const (
|
||||
// EventRequest entries contain information about HTTP requests.
|
||||
// This includes information like the URL, query parameters, and headers.
|
||||
EventRequest Event = "Request"
|
||||
|
||||
// EventResponse entries contain information about HTTP responses.
|
||||
// This includes information like the HTTP status code, headers, and request URL.
|
||||
EventResponse Event = "Response"
|
||||
|
||||
// EventResponseError entries contain information about HTTP responses that returned
|
||||
// an *azcore.ResponseError (i.e. responses with a non 2xx HTTP status code).
|
||||
// This includes the contents of ResponseError.Error().
|
||||
EventResponseError Event = "ResponseError"
|
||||
|
||||
// EventRetryPolicy entries contain information specific to the retry policy in use.
|
||||
EventRetryPolicy Event = "Retry"
|
||||
|
||||
// EventLRO entries contain information specific to long-running operations.
|
||||
// This includes information like polling location, operation state, and sleep intervals.
|
||||
EventLRO Event = "LongRunningOperation"
|
||||
)
|
||||
|
||||
// SetEvents is used to control which events are written to
|
||||
// the log. By default all log events are writen.
|
||||
// NOTE: this is not goroutine safe and should be called before using SDK clients.
|
||||
func SetEvents(cls ...Event) {
|
||||
log.SetEvents(cls...)
|
||||
}
|
||||
|
||||
// SetListener will set the Logger to write to the specified Listener.
|
||||
// NOTE: this is not goroutine safe and should be called before using SDK clients.
|
||||
func SetListener(lst func(Event, string)) {
|
||||
log.SetListener(lst)
|
||||
}
|
||||
|
||||
// for testing purposes
|
||||
func resetEvents() {
|
||||
log.TestResetEvents()
|
||||
}
|
||||
10
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/doc.go
generated
vendored
Normal file
10
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/doc.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
||||
// Use of this source code is governed by an MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package policy contains the definitions needed for configuring in-box pipeline policies
|
||||
// and creating custom policies.
|
||||
package policy
|
||||
198
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/policy.go
generated
vendored
Normal file
198
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/policy.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package policy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing"
|
||||
)
|
||||
|
||||
// Policy represents an extensibility point for the Pipeline that can mutate the specified
|
||||
// Request and react to the received Response.
|
||||
type Policy = exported.Policy
|
||||
|
||||
// Transporter represents an HTTP pipeline transport used to send HTTP requests and receive responses.
|
||||
type Transporter = exported.Transporter
|
||||
|
||||
// Request is an abstraction over the creation of an HTTP request as it passes through the pipeline.
|
||||
// Don't use this type directly, use runtime.NewRequest() instead.
|
||||
type Request = exported.Request
|
||||
|
||||
// ClientOptions contains optional settings for a client's pipeline.
|
||||
// Instances can be shared across calls to SDK client constructors when uniform configuration is desired.
|
||||
// Zero-value fields will have their specified default values applied during use.
|
||||
type ClientOptions struct {
|
||||
// APIVersion overrides the default version requested of the service.
|
||||
// Set with caution as this package version has not been tested with arbitrary service versions.
|
||||
APIVersion string
|
||||
|
||||
// Cloud specifies a cloud for the client. The default is Azure Public Cloud.
|
||||
Cloud cloud.Configuration
|
||||
|
||||
// InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
|
||||
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
|
||||
// WARNING: setting this to true will allow sending the credential in clear text. Use with caution.
|
||||
InsecureAllowCredentialWithHTTP bool
|
||||
|
||||
// Logging configures the built-in logging policy.
|
||||
Logging LogOptions
|
||||
|
||||
// Retry configures the built-in retry policy.
|
||||
Retry RetryOptions
|
||||
|
||||
// Telemetry configures the built-in telemetry policy.
|
||||
Telemetry TelemetryOptions
|
||||
|
||||
// TracingProvider configures the tracing provider.
|
||||
// It defaults to a no-op tracer.
|
||||
TracingProvider tracing.Provider
|
||||
|
||||
// Transport sets the transport for HTTP requests.
|
||||
Transport Transporter
|
||||
|
||||
// PerCallPolicies contains custom policies to inject into the pipeline.
|
||||
// Each policy is executed once per request.
|
||||
PerCallPolicies []Policy
|
||||
|
||||
// PerRetryPolicies contains custom policies to inject into the pipeline.
|
||||
// Each policy is executed once per request, and for each retry of that request.
|
||||
PerRetryPolicies []Policy
|
||||
}
|
||||
|
||||
// LogOptions configures the logging policy's behavior.
|
||||
type LogOptions struct {
|
||||
// IncludeBody indicates if request and response bodies should be included in logging.
|
||||
// The default value is false.
|
||||
// NOTE: enabling this can lead to disclosure of sensitive information, use with care.
|
||||
IncludeBody bool
|
||||
|
||||
// AllowedHeaders is the slice of headers to log with their values intact.
|
||||
// All headers not in the slice will have their values REDACTED.
|
||||
// Applies to request and response headers.
|
||||
AllowedHeaders []string
|
||||
|
||||
// AllowedQueryParams is the slice of query parameters to log with their values intact.
|
||||
// All query parameters not in the slice will have their values REDACTED.
|
||||
AllowedQueryParams []string
|
||||
}
|
||||
|
||||
// RetryOptions configures the retry policy's behavior.
|
||||
// Zero-value fields will have their specified default values applied during use.
|
||||
// This allows for modification of a subset of fields.
|
||||
type RetryOptions struct {
|
||||
// MaxRetries specifies the maximum number of attempts a failed operation will be retried
|
||||
// before producing an error.
|
||||
// The default value is three. A value less than zero means one try and no retries.
|
||||
MaxRetries int32
|
||||
|
||||
// TryTimeout indicates the maximum time allowed for any single try of an HTTP request.
|
||||
// This is disabled by default. Specify a value greater than zero to enable.
|
||||
// NOTE: Setting this to a small value might cause premature HTTP request time-outs.
|
||||
TryTimeout time.Duration
|
||||
|
||||
// RetryDelay specifies the initial amount of delay to use before retrying an operation.
|
||||
// The value is used only if the HTTP response does not contain a Retry-After header.
|
||||
// The delay increases exponentially with each retry up to the maximum specified by MaxRetryDelay.
|
||||
// The default value is four seconds. A value less than zero means no delay between retries.
|
||||
RetryDelay time.Duration
|
||||
|
||||
// MaxRetryDelay specifies the maximum delay allowed before retrying an operation.
|
||||
// Typically the value is greater than or equal to the value specified in RetryDelay.
|
||||
// The default Value is 60 seconds. A value less than zero means there is no cap.
|
||||
MaxRetryDelay time.Duration
|
||||
|
||||
// StatusCodes specifies the HTTP status codes that indicate the operation should be retried.
|
||||
// A nil slice will use the following values.
|
||||
// http.StatusRequestTimeout 408
|
||||
// http.StatusTooManyRequests 429
|
||||
// http.StatusInternalServerError 500
|
||||
// http.StatusBadGateway 502
|
||||
// http.StatusServiceUnavailable 503
|
||||
// http.StatusGatewayTimeout 504
|
||||
// Specifying values will replace the default values.
|
||||
// Specifying an empty slice will disable retries for HTTP status codes.
|
||||
StatusCodes []int
|
||||
|
||||
// ShouldRetry evaluates if the retry policy should retry the request.
|
||||
// When specified, the function overrides comparison against the list of
|
||||
// HTTP status codes and error checking within the retry policy. Context
|
||||
// and NonRetriable errors remain evaluated before calling ShouldRetry.
|
||||
// The *http.Response and error parameters are mutually exclusive, i.e.
|
||||
// if one is nil, the other is not nil.
|
||||
// A return value of true means the retry policy should retry.
|
||||
ShouldRetry func(*http.Response, error) bool
|
||||
}
|
||||
|
||||
// TelemetryOptions configures the telemetry policy's behavior.
|
||||
type TelemetryOptions struct {
|
||||
// ApplicationID is an application-specific identification string to add to the User-Agent.
|
||||
// It has a maximum length of 24 characters and must not contain any spaces.
|
||||
ApplicationID string
|
||||
|
||||
// Disabled will prevent the addition of any telemetry data to the User-Agent.
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
// TokenRequestOptions contain specific parameter that may be used by credentials types when attempting to get a token.
|
||||
type TokenRequestOptions = exported.TokenRequestOptions
|
||||
|
||||
// BearerTokenOptions configures the bearer token policy's behavior.
|
||||
type BearerTokenOptions struct {
|
||||
// AuthorizationHandler allows SDK developers to run client-specific logic when BearerTokenPolicy must authorize a request.
|
||||
// When this field isn't set, the policy follows its default behavior of authorizing every request with a bearer token from
|
||||
// its given credential.
|
||||
AuthorizationHandler AuthorizationHandler
|
||||
|
||||
// InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
|
||||
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
|
||||
// WARNING: setting this to true will allow sending the bearer token in clear text. Use with caution.
|
||||
InsecureAllowCredentialWithHTTP bool
|
||||
}
|
||||
|
||||
// AuthorizationHandler allows SDK developers to insert custom logic that runs when BearerTokenPolicy must authorize a request.
|
||||
type AuthorizationHandler struct {
|
||||
// OnRequest provides TokenRequestOptions the policy can use to acquire a token for a request. The policy calls OnRequest
|
||||
// whenever it needs a token and may call it multiple times for the same request. Its func parameter authorizes the request
|
||||
// with a token from the policy's credential. Implementations that need to perform I/O should use the Request's context,
|
||||
// available from Request.Raw().Context(). When OnRequest returns an error, the policy propagates that error and doesn't send
|
||||
// the request. When OnRequest is nil, the policy follows its default behavior, which is to authorize the request with a token
|
||||
// from its credential according to its configuration.
|
||||
OnRequest func(*Request, func(TokenRequestOptions) error) error
|
||||
|
||||
// OnChallenge allows clients to implement custom HTTP authentication challenge handling. BearerTokenPolicy calls it upon
|
||||
// receiving a 401 response containing multiple Bearer challenges or a challenge BearerTokenPolicy itself can't handle.
|
||||
// OnChallenge is responsible for parsing challenge(s) (the Response's WWW-Authenticate header) and reauthorizing the
|
||||
// Request accordingly. Its func argument authorizes the Request with a token from the policy's credential using the given
|
||||
// TokenRequestOptions. OnChallenge should honor the Request's context, available from Request.Raw().Context(). When
|
||||
// OnChallenge returns nil, the policy will send the Request again.
|
||||
OnChallenge func(*Request, *http.Response, func(TokenRequestOptions) error) error
|
||||
}
|
||||
|
||||
// WithCaptureResponse applies the HTTP response retrieval annotation to the parent context.
|
||||
// The resp parameter will contain the HTTP response after the request has completed.
|
||||
func WithCaptureResponse(parent context.Context, resp **http.Response) context.Context {
|
||||
return context.WithValue(parent, shared.CtxWithCaptureResponse{}, resp)
|
||||
}
|
||||
|
||||
// WithHTTPHeader adds the specified http.Header to the parent context.
|
||||
// Use this to specify custom HTTP headers at the API-call level.
|
||||
// Any overlapping headers will have their values replaced with the values specified here.
|
||||
func WithHTTPHeader(parent context.Context, header http.Header) context.Context {
|
||||
return context.WithValue(parent, shared.CtxWithHTTPHeaderKey{}, header)
|
||||
}
|
||||
|
||||
// WithRetryOptions adds the specified RetryOptions to the parent context.
|
||||
// Use this to specify custom RetryOptions at the API-call level.
|
||||
func WithRetryOptions(parent context.Context, options RetryOptions) context.Context {
|
||||
return context.WithValue(parent, shared.CtxWithRetryOptionsKey{}, options)
|
||||
}
|
||||
10
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/doc.go
generated
vendored
Normal file
10
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/doc.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
||||
// Use of this source code is governed by an MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package runtime contains various facilities for creating requests and handling responses.
|
||||
// The content is intended for SDK authors.
|
||||
package runtime
|
||||
27
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/errors.go
generated
vendored
Normal file
27
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/errors.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
)
|
||||
|
||||
// NewResponseError creates an *azcore.ResponseError from the provided HTTP response.
|
||||
// Call this when a service request returns a non-successful status code.
|
||||
// The error code will be extracted from the *http.Response, either from the x-ms-error-code
|
||||
// header (preferred) or attempted to be parsed from the response body.
|
||||
func NewResponseError(resp *http.Response) error {
|
||||
return exported.NewResponseError(resp)
|
||||
}
|
||||
|
||||
// NewResponseErrorWithErrorCode creates an *azcore.ResponseError from the provided HTTP response and errorCode.
|
||||
// Use this variant when the error code is in a non-standard location.
|
||||
func NewResponseErrorWithErrorCode(resp *http.Response, errorCode string) error {
|
||||
return exported.NewResponseErrorWithErrorCode(resp, errorCode)
|
||||
}
|
||||
137
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go
generated
vendored
Normal file
137
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing"
|
||||
)
|
||||
|
||||
// PagingHandler contains the required data for constructing a Pager.
|
||||
type PagingHandler[T any] struct {
|
||||
// More returns a boolean indicating if there are more pages to fetch.
|
||||
// It uses the provided page to make the determination.
|
||||
More func(T) bool
|
||||
|
||||
// Fetcher fetches the first and subsequent pages.
|
||||
Fetcher func(context.Context, *T) (T, error)
|
||||
|
||||
// Tracer contains the Tracer from the client that's creating the Pager.
|
||||
Tracer tracing.Tracer
|
||||
}
|
||||
|
||||
// Pager provides operations for iterating over paged responses.
|
||||
type Pager[T any] struct {
|
||||
current *T
|
||||
handler PagingHandler[T]
|
||||
tracer tracing.Tracer
|
||||
firstPage bool
|
||||
}
|
||||
|
||||
// NewPager creates an instance of Pager using the specified PagingHandler.
|
||||
// Pass a non-nil T for firstPage if the first page has already been retrieved.
|
||||
func NewPager[T any](handler PagingHandler[T]) *Pager[T] {
|
||||
return &Pager[T]{
|
||||
handler: handler,
|
||||
tracer: handler.Tracer,
|
||||
firstPage: true,
|
||||
}
|
||||
}
|
||||
|
||||
// More returns true if there are more pages to retrieve.
|
||||
func (p *Pager[T]) More() bool {
|
||||
if p.current != nil {
|
||||
return p.handler.More(*p.current)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// NextPage advances the pager to the next page.
|
||||
func (p *Pager[T]) NextPage(ctx context.Context) (T, error) {
|
||||
if p.current != nil {
|
||||
if p.firstPage {
|
||||
// we get here if it's an LRO-pager, we already have the first page
|
||||
p.firstPage = false
|
||||
return *p.current, nil
|
||||
} else if !p.handler.More(*p.current) {
|
||||
return *new(T), errors.New("no more pages")
|
||||
}
|
||||
} else {
|
||||
// non-LRO case, first page
|
||||
p.firstPage = false
|
||||
}
|
||||
|
||||
var err error
|
||||
ctx, endSpan := StartSpan(ctx, fmt.Sprintf("%s.NextPage", shortenTypeName(reflect.TypeOf(*p).Name())), p.tracer, nil)
|
||||
defer func() { endSpan(err) }()
|
||||
|
||||
resp, err := p.handler.Fetcher(ctx, p.current)
|
||||
if err != nil {
|
||||
return *new(T), err
|
||||
}
|
||||
p.current = &resp
|
||||
return *p.current, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface for Pager[T].
|
||||
func (p *Pager[T]) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &p.current)
|
||||
}
|
||||
|
||||
// FetcherForNextLinkOptions contains the optional values for [FetcherForNextLink].
|
||||
type FetcherForNextLinkOptions struct {
|
||||
// NextReq is the func to be called when requesting subsequent pages.
|
||||
// Used for paged operations that have a custom next link operation.
|
||||
NextReq func(context.Context, string) (*policy.Request, error)
|
||||
|
||||
// StatusCodes contains additional HTTP status codes indicating success.
|
||||
// The default value is http.StatusOK.
|
||||
StatusCodes []int
|
||||
}
|
||||
|
||||
// FetcherForNextLink is a helper containing boilerplate code to simplify creating a PagingHandler[T].Fetcher from a next link URL.
|
||||
// - ctx is the [context.Context] controlling the lifetime of the HTTP operation
|
||||
// - pl is the [Pipeline] used to dispatch the HTTP request
|
||||
// - nextLink is the URL used to fetch the next page. the empty string indicates the first page is to be requested
|
||||
// - firstReq is the func to be called when creating the request for the first page
|
||||
// - options contains any optional parameters, pass nil to accept the default values
|
||||
func FetcherForNextLink(ctx context.Context, pl Pipeline, nextLink string, firstReq func(context.Context) (*policy.Request, error), options *FetcherForNextLinkOptions) (*http.Response, error) {
|
||||
var req *policy.Request
|
||||
var err error
|
||||
if options == nil {
|
||||
options = &FetcherForNextLinkOptions{}
|
||||
}
|
||||
if nextLink == "" {
|
||||
req, err = firstReq(ctx)
|
||||
} else if nextLink, err = EncodeQueryParams(nextLink); err == nil {
|
||||
if options.NextReq != nil {
|
||||
req, err = options.NextReq(ctx, nextLink)
|
||||
} else {
|
||||
req, err = NewRequest(ctx, http.MethodGet, nextLink)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := pl.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
successCodes := []int{http.StatusOK}
|
||||
successCodes = append(successCodes, options.StatusCodes...)
|
||||
if !HasStatusCode(resp, successCodes...) {
|
||||
return nil, NewResponseError(resp)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
94
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pipeline.go
generated
vendored
Normal file
94
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pipeline.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
)
|
||||
|
||||
// PipelineOptions contains Pipeline options for SDK developers
|
||||
type PipelineOptions struct {
|
||||
// AllowedHeaders is the slice of headers to log with their values intact.
|
||||
// All headers not in the slice will have their values REDACTED.
|
||||
// Applies to request and response headers.
|
||||
AllowedHeaders []string
|
||||
|
||||
// AllowedQueryParameters is the slice of query parameters to log with their values intact.
|
||||
// All query parameters not in the slice will have their values REDACTED.
|
||||
AllowedQueryParameters []string
|
||||
|
||||
// APIVersion overrides the default version requested of the service.
|
||||
// Set with caution as this package version has not been tested with arbitrary service versions.
|
||||
APIVersion APIVersionOptions
|
||||
|
||||
// PerCall contains custom policies to inject into the pipeline.
|
||||
// Each policy is executed once per request.
|
||||
PerCall []policy.Policy
|
||||
|
||||
// PerRetry contains custom policies to inject into the pipeline.
|
||||
// Each policy is executed once per request, and for each retry of that request.
|
||||
PerRetry []policy.Policy
|
||||
|
||||
// Tracing contains options used to configure distributed tracing.
|
||||
Tracing TracingOptions
|
||||
}
|
||||
|
||||
// TracingOptions contains tracing options for SDK developers.
|
||||
type TracingOptions struct {
|
||||
// Namespace contains the value to use for the az.namespace span attribute.
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// Pipeline represents a primitive for sending HTTP requests and receiving responses.
|
||||
// Its behavior can be extended by specifying policies during construction.
|
||||
type Pipeline = exported.Pipeline
|
||||
|
||||
// NewPipeline creates a pipeline from connection options, with any additional policies as specified.
|
||||
// Policies from ClientOptions are placed after policies from PipelineOptions.
|
||||
// The module and version parameters are used by the telemetry policy, when enabled.
|
||||
func NewPipeline(module, version string, plOpts PipelineOptions, options *policy.ClientOptions) Pipeline {
|
||||
cp := policy.ClientOptions{}
|
||||
if options != nil {
|
||||
cp = *options
|
||||
}
|
||||
if len(plOpts.AllowedHeaders) > 0 {
|
||||
headers := make([]string, len(plOpts.AllowedHeaders)+len(cp.Logging.AllowedHeaders))
|
||||
copy(headers, plOpts.AllowedHeaders)
|
||||
headers = append(headers, cp.Logging.AllowedHeaders...)
|
||||
cp.Logging.AllowedHeaders = headers
|
||||
}
|
||||
if len(plOpts.AllowedQueryParameters) > 0 {
|
||||
qp := make([]string, len(plOpts.AllowedQueryParameters)+len(cp.Logging.AllowedQueryParams))
|
||||
copy(qp, plOpts.AllowedQueryParameters)
|
||||
qp = append(qp, cp.Logging.AllowedQueryParams...)
|
||||
cp.Logging.AllowedQueryParams = qp
|
||||
}
|
||||
// we put the includeResponsePolicy at the very beginning so that the raw response
|
||||
// is populated with the final response (some policies might mutate the response)
|
||||
policies := []policy.Policy{exported.PolicyFunc(includeResponsePolicy)}
|
||||
if cp.APIVersion != "" {
|
||||
policies = append(policies, newAPIVersionPolicy(cp.APIVersion, &plOpts.APIVersion))
|
||||
}
|
||||
if !cp.Telemetry.Disabled {
|
||||
policies = append(policies, NewTelemetryPolicy(module, version, &cp.Telemetry))
|
||||
}
|
||||
policies = append(policies, plOpts.PerCall...)
|
||||
policies = append(policies, cp.PerCallPolicies...)
|
||||
policies = append(policies, NewRetryPolicy(&cp.Retry))
|
||||
policies = append(policies, plOpts.PerRetry...)
|
||||
policies = append(policies, cp.PerRetryPolicies...)
|
||||
policies = append(policies, exported.PolicyFunc(httpHeaderPolicy))
|
||||
policies = append(policies, newHTTPTracePolicy(cp.Logging.AllowedQueryParams))
|
||||
policies = append(policies, NewLogPolicy(&cp.Logging))
|
||||
policies = append(policies, exported.PolicyFunc(bodyDownloadPolicy))
|
||||
transport := cp.Transport
|
||||
if transport == nil {
|
||||
transport = defaultHTTPClient
|
||||
}
|
||||
return exported.NewPipeline(transport, policies...)
|
||||
}
|
||||
75
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_api_version.go
generated
vendored
Normal file
75
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_api_version.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
)
|
||||
|
||||
// APIVersionOptions contains options for API versions
|
||||
type APIVersionOptions struct {
|
||||
// Location indicates where to set the version on a request, for example in a header or query param
|
||||
Location APIVersionLocation
|
||||
// Name is the name of the header or query parameter, for example "api-version"
|
||||
Name string
|
||||
}
|
||||
|
||||
// APIVersionLocation indicates which part of a request identifies the service version
|
||||
type APIVersionLocation int
|
||||
|
||||
const (
|
||||
// APIVersionLocationQueryParam indicates a query parameter
|
||||
APIVersionLocationQueryParam = 0
|
||||
// APIVersionLocationHeader indicates a header
|
||||
APIVersionLocationHeader = 1
|
||||
)
|
||||
|
||||
// newAPIVersionPolicy constructs an APIVersionPolicy. If version is "", Do will be a no-op. If version
|
||||
// isn't empty and opts.Name is empty, Do will return an error.
|
||||
func newAPIVersionPolicy(version string, opts *APIVersionOptions) *apiVersionPolicy {
|
||||
if opts == nil {
|
||||
opts = &APIVersionOptions{}
|
||||
}
|
||||
return &apiVersionPolicy{location: opts.Location, name: opts.Name, version: version}
|
||||
}
|
||||
|
||||
// apiVersionPolicy enables users to set the API version of every request a client sends.
|
||||
type apiVersionPolicy struct {
|
||||
// location indicates whether "name" refers to a query parameter or header.
|
||||
location APIVersionLocation
|
||||
|
||||
// name of the query param or header whose value should be overridden; provided by the client.
|
||||
name string
|
||||
|
||||
// version is the value (provided by the user) that replaces the default version value.
|
||||
version string
|
||||
}
|
||||
|
||||
// Do sets the request's API version, if the policy is configured to do so, replacing any prior value.
|
||||
func (a *apiVersionPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
if a.version != "" {
|
||||
if a.name == "" {
|
||||
// user set ClientOptions.APIVersion but the client ctor didn't set PipelineOptions.APIVersionOptions
|
||||
return nil, errors.New("this client doesn't support overriding its API version")
|
||||
}
|
||||
switch a.location {
|
||||
case APIVersionLocationHeader:
|
||||
req.Raw().Header.Set(a.name, a.version)
|
||||
case APIVersionLocationQueryParam:
|
||||
q := req.Raw().URL.Query()
|
||||
q.Set(a.name, a.version)
|
||||
req.Raw().URL.RawQuery = q.Encode()
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown APIVersionLocation %d", a.location)
|
||||
}
|
||||
}
|
||||
return req.Next()
|
||||
}
|
||||
236
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_bearer_token.go
generated
vendored
Normal file
236
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_bearer_token.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/temporal"
|
||||
)
|
||||
|
||||
// BearerTokenPolicy authorizes requests with bearer tokens acquired from a TokenCredential.
|
||||
// It handles [Continuous Access Evaluation] (CAE) challenges. Clients needing to handle
|
||||
// additional authentication challenges, or needing more control over authorization, should
|
||||
// provide a [policy.AuthorizationHandler] in [policy.BearerTokenOptions].
|
||||
//
|
||||
// [Continuous Access Evaluation]: https://learn.microsoft.com/entra/identity/conditional-access/concept-continuous-access-evaluation
|
||||
type BearerTokenPolicy struct {
|
||||
// mainResource is the resource to be retreived using the tenant specified in the credential
|
||||
mainResource *temporal.Resource[exported.AccessToken, acquiringResourceState]
|
||||
// the following fields are read-only
|
||||
authzHandler policy.AuthorizationHandler
|
||||
cred exported.TokenCredential
|
||||
scopes []string
|
||||
allowHTTP bool
|
||||
}
|
||||
|
||||
type acquiringResourceState struct {
|
||||
req *policy.Request
|
||||
p *BearerTokenPolicy
|
||||
tro policy.TokenRequestOptions
|
||||
}
|
||||
|
||||
// acquire acquires or updates the resource; only one
|
||||
// thread/goroutine at a time ever calls this function
|
||||
func acquire(state acquiringResourceState) (newResource exported.AccessToken, newExpiration time.Time, err error) {
|
||||
tk, err := state.p.cred.GetToken(&shared.ContextWithDeniedValues{Context: state.req.Raw().Context()}, state.tro)
|
||||
if err != nil {
|
||||
return exported.AccessToken{}, time.Time{}, err
|
||||
}
|
||||
return tk, tk.ExpiresOn, nil
|
||||
}
|
||||
|
||||
// NewBearerTokenPolicy creates a policy object that authorizes requests with bearer tokens.
|
||||
// cred: an azcore.TokenCredential implementation such as a credential object from azidentity
|
||||
// scopes: the list of permission scopes required for the token.
|
||||
// opts: optional settings. Pass nil to accept default values; this is the same as passing a zero-value options.
|
||||
func NewBearerTokenPolicy(cred exported.TokenCredential, scopes []string, opts *policy.BearerTokenOptions) *BearerTokenPolicy {
|
||||
if opts == nil {
|
||||
opts = &policy.BearerTokenOptions{}
|
||||
}
|
||||
ah := opts.AuthorizationHandler
|
||||
if ah.OnRequest == nil {
|
||||
// Set a default OnRequest that simply requests a token with the given scopes. OnChallenge
|
||||
// doesn't get a default so the policy can use a nil check to determine whether the caller
|
||||
// provided an implementation.
|
||||
ah.OnRequest = func(_ *policy.Request, authNZ func(policy.TokenRequestOptions) error) error {
|
||||
// authNZ sets EnableCAE: true in all cases, no need to duplicate that here
|
||||
return authNZ(policy.TokenRequestOptions{Scopes: scopes})
|
||||
}
|
||||
}
|
||||
return &BearerTokenPolicy{
|
||||
authzHandler: ah,
|
||||
cred: cred,
|
||||
scopes: scopes,
|
||||
mainResource: temporal.NewResource(acquire),
|
||||
allowHTTP: opts.InsecureAllowCredentialWithHTTP,
|
||||
}
|
||||
}
|
||||
|
||||
// authenticateAndAuthorize returns a function which authorizes req with a token from the policy's credential
|
||||
func (b *BearerTokenPolicy) authenticateAndAuthorize(req *policy.Request) func(policy.TokenRequestOptions) error {
|
||||
return func(tro policy.TokenRequestOptions) error {
|
||||
tro.EnableCAE = true
|
||||
as := acquiringResourceState{p: b, req: req, tro: tro}
|
||||
tk, err := b.mainResource.Get(as)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Raw().Header.Set(shared.HeaderAuthorization, shared.BearerTokenPrefix+tk.Token)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Do authorizes a request with a bearer token
|
||||
func (b *BearerTokenPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
// skip adding the authorization header if no TokenCredential was provided.
|
||||
// this prevents a panic that might be hard to diagnose and allows testing
|
||||
// against http endpoints that don't require authentication.
|
||||
if b.cred == nil {
|
||||
return req.Next()
|
||||
}
|
||||
|
||||
if err := checkHTTPSForAuth(req, b.allowHTTP); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := b.authzHandler.OnRequest(req, b.authenticateAndAuthorize(req))
|
||||
if err != nil {
|
||||
return nil, errorinfo.NonRetriableError(err)
|
||||
}
|
||||
|
||||
res, err := req.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err = b.handleChallenge(req, res, false)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// handleChallenge handles authentication challenges either directly (for CAE challenges) or by calling
|
||||
// the AuthorizationHandler. It's a no-op when the response doesn't include an authentication challenge.
|
||||
// It will recurse at most once, to handle a CAE challenge following a non-CAE challenge handled by the
|
||||
// AuthorizationHandler.
|
||||
func (b *BearerTokenPolicy) handleChallenge(req *policy.Request, res *http.Response, recursed bool) (*http.Response, error) {
|
||||
var err error
|
||||
if res.StatusCode == http.StatusUnauthorized {
|
||||
b.mainResource.Expire()
|
||||
if res.Header.Get(shared.HeaderWWWAuthenticate) != "" {
|
||||
caeChallenge, parseErr := parseCAEChallenge(res)
|
||||
if parseErr != nil {
|
||||
return res, parseErr
|
||||
}
|
||||
switch {
|
||||
case caeChallenge != nil:
|
||||
authNZ := func(tro policy.TokenRequestOptions) error {
|
||||
// Take the TokenRequestOptions provided by OnRequest and add the challenge claims. The value
|
||||
// will be empty at time of writing because CAE is the only feature involving claims. If in
|
||||
// the future some client needs to specify unrelated claims, this function may need to merge
|
||||
// them with the challenge claims.
|
||||
tro.Claims = caeChallenge.params["claims"]
|
||||
return b.authenticateAndAuthorize(req)(tro)
|
||||
}
|
||||
if err = b.authzHandler.OnRequest(req, authNZ); err == nil {
|
||||
if err = req.RewindBody(); err == nil {
|
||||
res, err = req.Next()
|
||||
}
|
||||
}
|
||||
case b.authzHandler.OnChallenge != nil && !recursed:
|
||||
if err = b.authzHandler.OnChallenge(req, res, b.authenticateAndAuthorize(req)); err == nil {
|
||||
if err = req.RewindBody(); err == nil {
|
||||
if res, err = req.Next(); err == nil {
|
||||
res, err = b.handleChallenge(req, res, true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// don't retry challenge handling errors
|
||||
err = errorinfo.NonRetriableError(err)
|
||||
}
|
||||
default:
|
||||
// return the response to the pipeline
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func checkHTTPSForAuth(req *policy.Request, allowHTTP bool) error {
|
||||
if strings.ToLower(req.Raw().URL.Scheme) != "https" && !allowHTTP {
|
||||
return errorinfo.NonRetriableError(errors.New("authenticated requests are not permitted for non TLS protected (https) endpoints"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseCAEChallenge returns a *authChallenge representing Response's CAE challenge (nil when Response has none).
|
||||
// If Response includes a CAE challenge having invalid claims, it returns a NonRetriableError.
|
||||
func parseCAEChallenge(res *http.Response) (*authChallenge, error) {
|
||||
var (
|
||||
caeChallenge *authChallenge
|
||||
err error
|
||||
)
|
||||
for _, c := range parseChallenges(res) {
|
||||
if c.scheme == "Bearer" {
|
||||
if claims := c.params["claims"]; claims != "" && c.params["error"] == "insufficient_claims" {
|
||||
if b, de := base64.StdEncoding.DecodeString(claims); de == nil {
|
||||
c.params["claims"] = string(b)
|
||||
caeChallenge = &c
|
||||
} else {
|
||||
// don't include the decoding error because it's something
|
||||
// unhelpful like "illegal base64 data at input byte 42"
|
||||
err = errorinfo.NonRetriableError(errors.New("authentication challenge contains invalid claims: " + claims))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return caeChallenge, err
|
||||
}
|
||||
|
||||
var (
|
||||
challenge, challengeParams *regexp.Regexp
|
||||
once = &sync.Once{}
|
||||
)
|
||||
|
||||
type authChallenge struct {
|
||||
scheme string
|
||||
params map[string]string
|
||||
}
|
||||
|
||||
// parseChallenges assumes authentication challenges have quoted parameter values
|
||||
func parseChallenges(res *http.Response) []authChallenge {
|
||||
once.Do(func() {
|
||||
// matches challenges having quoted parameters, capturing scheme and parameters
|
||||
challenge = regexp.MustCompile(`(?:(\w+) ((?:\w+="[^"]*",?\s*)+))`)
|
||||
// captures parameter names and values in a match of the above expression
|
||||
challengeParams = regexp.MustCompile(`(\w+)="([^"]*)"`)
|
||||
})
|
||||
parsed := []authChallenge{}
|
||||
// WWW-Authenticate can have multiple values, each containing multiple challenges
|
||||
for _, h := range res.Header.Values(shared.HeaderWWWAuthenticate) {
|
||||
for _, sm := range challenge.FindAllStringSubmatch(h, -1) {
|
||||
// sm is [challenge, scheme, params] (see regexp documentation on submatches)
|
||||
c := authChallenge{
|
||||
params: make(map[string]string),
|
||||
scheme: sm[1],
|
||||
}
|
||||
for _, sm := range challengeParams.FindAllStringSubmatch(sm[2], -1) {
|
||||
// sm is [key="value", key, value] (see regexp documentation on submatches)
|
||||
c.params[sm[1]] = sm[2]
|
||||
}
|
||||
parsed = append(parsed, c)
|
||||
}
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
72
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_body_download.go
generated
vendored
Normal file
72
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_body_download.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo"
|
||||
)
|
||||
|
||||
// bodyDownloadPolicy creates a policy object that downloads the response's body to a []byte.
|
||||
func bodyDownloadPolicy(req *policy.Request) (*http.Response, error) {
|
||||
resp, err := req.Next()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
var opValues bodyDownloadPolicyOpValues
|
||||
// don't skip downloading error response bodies
|
||||
if req.OperationValue(&opValues); opValues.Skip && resp.StatusCode < 400 {
|
||||
return resp, err
|
||||
}
|
||||
// Either bodyDownloadPolicyOpValues was not specified (so skip is false)
|
||||
// or it was specified and skip is false: don't skip downloading the body
|
||||
_, err = Payload(resp)
|
||||
if err != nil {
|
||||
return resp, newBodyDownloadError(err, req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// bodyDownloadPolicyOpValues is the struct containing the per-operation values
|
||||
type bodyDownloadPolicyOpValues struct {
|
||||
Skip bool
|
||||
}
|
||||
|
||||
type bodyDownloadError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func newBodyDownloadError(err error, req *policy.Request) error {
|
||||
// on failure, only retry the request for idempotent operations.
|
||||
// we currently identify them as DELETE, GET, and PUT requests.
|
||||
if m := strings.ToUpper(req.Raw().Method); m == http.MethodDelete || m == http.MethodGet || m == http.MethodPut {
|
||||
// error is safe for retry
|
||||
return err
|
||||
}
|
||||
// wrap error to avoid retries
|
||||
return &bodyDownloadError{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *bodyDownloadError) Error() string {
|
||||
return fmt.Sprintf("body download policy: %s", b.err.Error())
|
||||
}
|
||||
|
||||
func (b *bodyDownloadError) NonRetriable() {
|
||||
// marker method
|
||||
}
|
||||
|
||||
func (b *bodyDownloadError) Unwrap() error {
|
||||
return b.err
|
||||
}
|
||||
|
||||
var _ errorinfo.NonRetriable = (*bodyDownloadError)(nil)
|
||||
40
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_http_header.go
generated
vendored
Normal file
40
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_http_header.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
)
|
||||
|
||||
// newHTTPHeaderPolicy creates a policy object that adds custom HTTP headers to a request
|
||||
func httpHeaderPolicy(req *policy.Request) (*http.Response, error) {
|
||||
// check if any custom HTTP headers have been specified
|
||||
if header := req.Raw().Context().Value(shared.CtxWithHTTPHeaderKey{}); header != nil {
|
||||
for k, v := range header.(http.Header) {
|
||||
// use Set to replace any existing value
|
||||
// it also canonicalizes the header key
|
||||
req.Raw().Header.Set(k, v[0])
|
||||
// add any remaining values
|
||||
for i := 1; i < len(v); i++ {
|
||||
req.Raw().Header.Add(k, v[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return req.Next()
|
||||
}
|
||||
|
||||
// WithHTTPHeader adds the specified http.Header to the parent context.
|
||||
// Use this to specify custom HTTP headers at the API-call level.
|
||||
// Any overlapping headers will have their values replaced with the values specified here.
|
||||
// Deprecated: use [policy.WithHTTPHeader] instead.
|
||||
func WithHTTPHeader(parent context.Context, header http.Header) context.Context {
|
||||
return policy.WithHTTPHeader(parent, header)
|
||||
}
|
||||
154
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_http_trace.go
generated
vendored
Normal file
154
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_http_trace.go
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing"
|
||||
)
|
||||
|
||||
const (
|
||||
attrHTTPMethod = "http.method"
|
||||
attrHTTPURL = "http.url"
|
||||
attrHTTPUserAgent = "http.user_agent"
|
||||
attrHTTPStatusCode = "http.status_code"
|
||||
|
||||
attrAZClientReqID = "az.client_request_id"
|
||||
attrAZServiceReqID = "az.service_request_id"
|
||||
|
||||
attrNetPeerName = "net.peer.name"
|
||||
)
|
||||
|
||||
// newHTTPTracePolicy creates a new instance of the httpTracePolicy.
|
||||
// - allowedQueryParams contains the user-specified query parameters that don't need to be redacted from the trace
|
||||
func newHTTPTracePolicy(allowedQueryParams []string) exported.Policy {
|
||||
return &httpTracePolicy{allowedQP: getAllowedQueryParams(allowedQueryParams)}
|
||||
}
|
||||
|
||||
// httpTracePolicy is a policy that creates a trace for the HTTP request and its response
|
||||
type httpTracePolicy struct {
|
||||
allowedQP map[string]struct{}
|
||||
}
|
||||
|
||||
// Do implements the pipeline.Policy interfaces for the httpTracePolicy type.
|
||||
func (h *httpTracePolicy) Do(req *policy.Request) (resp *http.Response, err error) {
|
||||
rawTracer := req.Raw().Context().Value(shared.CtxWithTracingTracer{})
|
||||
if tracer, ok := rawTracer.(tracing.Tracer); ok && tracer.Enabled() {
|
||||
attributes := []tracing.Attribute{
|
||||
{Key: attrHTTPMethod, Value: req.Raw().Method},
|
||||
{Key: attrHTTPURL, Value: getSanitizedURL(*req.Raw().URL, h.allowedQP)},
|
||||
{Key: attrNetPeerName, Value: req.Raw().URL.Host},
|
||||
}
|
||||
|
||||
if ua := req.Raw().Header.Get(shared.HeaderUserAgent); ua != "" {
|
||||
attributes = append(attributes, tracing.Attribute{Key: attrHTTPUserAgent, Value: ua})
|
||||
}
|
||||
if reqID := req.Raw().Header.Get(shared.HeaderXMSClientRequestID); reqID != "" {
|
||||
attributes = append(attributes, tracing.Attribute{Key: attrAZClientReqID, Value: reqID})
|
||||
}
|
||||
|
||||
ctx := req.Raw().Context()
|
||||
ctx, span := tracer.Start(ctx, "HTTP "+req.Raw().Method, &tracing.SpanOptions{
|
||||
Kind: tracing.SpanKindClient,
|
||||
Attributes: attributes,
|
||||
})
|
||||
|
||||
defer func() {
|
||||
if resp != nil {
|
||||
span.SetAttributes(tracing.Attribute{Key: attrHTTPStatusCode, Value: resp.StatusCode})
|
||||
if resp.StatusCode > 399 {
|
||||
span.SetStatus(tracing.SpanStatusError, resp.Status)
|
||||
}
|
||||
if reqID := resp.Header.Get(shared.HeaderXMSRequestID); reqID != "" {
|
||||
span.SetAttributes(tracing.Attribute{Key: attrAZServiceReqID, Value: reqID})
|
||||
}
|
||||
} else if err != nil {
|
||||
var urlErr *url.Error
|
||||
if errors.As(err, &urlErr) {
|
||||
// calling *url.Error.Error() will include the unsanitized URL
|
||||
// which we don't want. in addition, we already have the HTTP verb
|
||||
// and sanitized URL in the trace so we aren't losing any info
|
||||
err = urlErr.Err
|
||||
}
|
||||
span.SetStatus(tracing.SpanStatusError, err.Error())
|
||||
}
|
||||
span.End()
|
||||
}()
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
}
|
||||
resp, err = req.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// StartSpanOptions contains the optional values for StartSpan.
|
||||
type StartSpanOptions struct {
|
||||
// Kind indicates the kind of Span.
|
||||
Kind tracing.SpanKind
|
||||
// Attributes contains key-value pairs of attributes for the span.
|
||||
Attributes []tracing.Attribute
|
||||
}
|
||||
|
||||
// StartSpan starts a new tracing span.
|
||||
// You must call the returned func to terminate the span. Pass the applicable error
|
||||
// if the span will exit with an error condition.
|
||||
// - ctx is the parent context of the newly created context
|
||||
// - name is the name of the span. this is typically the fully qualified name of an API ("Client.Method")
|
||||
// - tracer is the client's Tracer for creating spans
|
||||
// - options contains optional values. pass nil to accept any default values
|
||||
func StartSpan(ctx context.Context, name string, tracer tracing.Tracer, options *StartSpanOptions) (context.Context, func(error)) {
|
||||
if !tracer.Enabled() {
|
||||
return ctx, func(err error) {}
|
||||
}
|
||||
|
||||
// we MUST propagate the active tracer before returning so that the trace policy can access it
|
||||
ctx = context.WithValue(ctx, shared.CtxWithTracingTracer{}, tracer)
|
||||
|
||||
if activeSpan := ctx.Value(ctxActiveSpan{}); activeSpan != nil {
|
||||
// per the design guidelines, if a SDK method Foo() calls SDK method Bar(),
|
||||
// then the span for Bar() must be suppressed. however, if Bar() makes a REST
|
||||
// call, then Bar's HTTP span must be a child of Foo's span.
|
||||
// however, there is an exception to this rule. if the SDK method Foo() is a
|
||||
// messaging producer/consumer, and it takes a callback that's a SDK method
|
||||
// Bar(), then the span for Bar() must _not_ be suppressed.
|
||||
if kind := activeSpan.(tracing.SpanKind); kind == tracing.SpanKindClient || kind == tracing.SpanKindInternal {
|
||||
return ctx, func(err error) {}
|
||||
}
|
||||
}
|
||||
|
||||
if options == nil {
|
||||
options = &StartSpanOptions{}
|
||||
}
|
||||
if options.Kind == 0 {
|
||||
options.Kind = tracing.SpanKindInternal
|
||||
}
|
||||
|
||||
ctx, span := tracer.Start(ctx, name, &tracing.SpanOptions{
|
||||
Kind: options.Kind,
|
||||
Attributes: options.Attributes,
|
||||
})
|
||||
ctx = context.WithValue(ctx, ctxActiveSpan{}, options.Kind)
|
||||
return ctx, func(err error) {
|
||||
if err != nil {
|
||||
errType := strings.Replace(fmt.Sprintf("%T", err), "*exported.", "*azcore.", 1)
|
||||
span.SetStatus(tracing.SpanStatusError, fmt.Sprintf("%s:\n%s", errType, err.Error()))
|
||||
}
|
||||
span.End()
|
||||
}
|
||||
}
|
||||
|
||||
// ctxActiveSpan is used as a context key for indicating a SDK client span is in progress.
|
||||
type ctxActiveSpan struct{}
|
||||
35
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_include_response.go
generated
vendored
Normal file
35
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_include_response.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
)
|
||||
|
||||
// includeResponsePolicy creates a policy that retrieves the raw HTTP response upon request
|
||||
func includeResponsePolicy(req *policy.Request) (*http.Response, error) {
|
||||
resp, err := req.Next()
|
||||
if resp == nil {
|
||||
return resp, err
|
||||
}
|
||||
if httpOutRaw := req.Raw().Context().Value(shared.CtxWithCaptureResponse{}); httpOutRaw != nil {
|
||||
httpOut := httpOutRaw.(**http.Response)
|
||||
*httpOut = resp
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// WithCaptureResponse applies the HTTP response retrieval annotation to the parent context.
|
||||
// The resp parameter will contain the HTTP response after the request has completed.
|
||||
// Deprecated: use [policy.WithCaptureResponse] instead.
|
||||
func WithCaptureResponse(parent context.Context, resp **http.Response) context.Context {
|
||||
return policy.WithCaptureResponse(parent, resp)
|
||||
}
|
||||
64
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_key_credential.go
generated
vendored
Normal file
64
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_key_credential.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
)
|
||||
|
||||
// KeyCredentialPolicy authorizes requests with a [azcore.KeyCredential].
|
||||
type KeyCredentialPolicy struct {
|
||||
cred *exported.KeyCredential
|
||||
header string
|
||||
prefix string
|
||||
allowHTTP bool
|
||||
}
|
||||
|
||||
// KeyCredentialPolicyOptions contains the optional values configuring [KeyCredentialPolicy].
|
||||
type KeyCredentialPolicyOptions struct {
|
||||
// InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
|
||||
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
|
||||
// WARNING: setting this to true will allow sending the authentication key in clear text. Use with caution.
|
||||
InsecureAllowCredentialWithHTTP bool
|
||||
|
||||
// Prefix is used if the key requires a prefix before it's inserted into the HTTP request.
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// NewKeyCredentialPolicy creates a new instance of [KeyCredentialPolicy].
|
||||
// - cred is the [azcore.KeyCredential] used to authenticate with the service
|
||||
// - header is the name of the HTTP request header in which the key is placed
|
||||
// - options contains optional configuration, pass nil to accept the default values
|
||||
func NewKeyCredentialPolicy(cred *exported.KeyCredential, header string, options *KeyCredentialPolicyOptions) *KeyCredentialPolicy {
|
||||
if options == nil {
|
||||
options = &KeyCredentialPolicyOptions{}
|
||||
}
|
||||
return &KeyCredentialPolicy{
|
||||
cred: cred,
|
||||
header: header,
|
||||
prefix: options.Prefix,
|
||||
allowHTTP: options.InsecureAllowCredentialWithHTTP,
|
||||
}
|
||||
}
|
||||
|
||||
// Do implementes the Do method on the [policy.Polilcy] interface.
|
||||
func (k *KeyCredentialPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
// skip adding the authorization header if no KeyCredential was provided.
|
||||
// this prevents a panic that might be hard to diagnose and allows testing
|
||||
// against http endpoints that don't require authentication.
|
||||
if k.cred != nil {
|
||||
if err := checkHTTPSForAuth(req, k.allowHTTP); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val := exported.KeyCredentialGet(k.cred)
|
||||
if k.prefix != "" {
|
||||
val = k.prefix + val
|
||||
}
|
||||
req.Raw().Header.Add(k.header, val)
|
||||
}
|
||||
return req.Next()
|
||||
}
|
||||
264
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_logging.go
generated
vendored
Normal file
264
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_logging.go
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/diag"
|
||||
)
|
||||
|
||||
type logPolicy struct {
|
||||
includeBody bool
|
||||
allowedHeaders map[string]struct{}
|
||||
allowedQP map[string]struct{}
|
||||
}
|
||||
|
||||
// NewLogPolicy creates a request/response logging policy object configured using the specified options.
|
||||
// Pass nil to accept the default values; this is the same as passing a zero-value options.
|
||||
func NewLogPolicy(o *policy.LogOptions) policy.Policy {
|
||||
if o == nil {
|
||||
o = &policy.LogOptions{}
|
||||
}
|
||||
// construct default hash set of allowed headers
|
||||
allowedHeaders := map[string]struct{}{
|
||||
"accept": {},
|
||||
"cache-control": {},
|
||||
"connection": {},
|
||||
"content-length": {},
|
||||
"content-type": {},
|
||||
"date": {},
|
||||
"etag": {},
|
||||
"expires": {},
|
||||
"if-match": {},
|
||||
"if-modified-since": {},
|
||||
"if-none-match": {},
|
||||
"if-unmodified-since": {},
|
||||
"last-modified": {},
|
||||
"ms-cv": {},
|
||||
"pragma": {},
|
||||
"request-id": {},
|
||||
"retry-after": {},
|
||||
"server": {},
|
||||
"traceparent": {},
|
||||
"transfer-encoding": {},
|
||||
"user-agent": {},
|
||||
"www-authenticate": {},
|
||||
"x-ms-request-id": {},
|
||||
"x-ms-client-request-id": {},
|
||||
"x-ms-return-client-request-id": {},
|
||||
}
|
||||
// add any caller-specified allowed headers to the set
|
||||
for _, ah := range o.AllowedHeaders {
|
||||
allowedHeaders[strings.ToLower(ah)] = struct{}{}
|
||||
}
|
||||
// now do the same thing for query params
|
||||
allowedQP := getAllowedQueryParams(o.AllowedQueryParams)
|
||||
return &logPolicy{
|
||||
includeBody: o.IncludeBody,
|
||||
allowedHeaders: allowedHeaders,
|
||||
allowedQP: allowedQP,
|
||||
}
|
||||
}
|
||||
|
||||
// getAllowedQueryParams merges the default set of allowed query parameters
|
||||
// with a custom set (usually comes from client options).
|
||||
func getAllowedQueryParams(customAllowedQP []string) map[string]struct{} {
|
||||
allowedQP := map[string]struct{}{
|
||||
"api-version": {},
|
||||
}
|
||||
for _, qp := range customAllowedQP {
|
||||
allowedQP[strings.ToLower(qp)] = struct{}{}
|
||||
}
|
||||
return allowedQP
|
||||
}
|
||||
|
||||
// logPolicyOpValues is the struct containing the per-operation values
|
||||
type logPolicyOpValues struct {
|
||||
try int32
|
||||
start time.Time
|
||||
}
|
||||
|
||||
func (p *logPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
// Get the per-operation values. These are saved in the Message's map so that they persist across each retry calling into this policy object.
|
||||
var opValues logPolicyOpValues
|
||||
if req.OperationValue(&opValues); opValues.start.IsZero() {
|
||||
opValues.start = time.Now() // If this is the 1st try, record this operation's start time
|
||||
}
|
||||
opValues.try++ // The first try is #1 (not #0)
|
||||
req.SetOperationValue(opValues)
|
||||
|
||||
// Log the outgoing request as informational
|
||||
if log.Should(log.EventRequest) {
|
||||
b := &bytes.Buffer{}
|
||||
fmt.Fprintf(b, "==> OUTGOING REQUEST (Try=%d)\n", opValues.try)
|
||||
p.writeRequestWithResponse(b, req, nil, nil)
|
||||
var err error
|
||||
if p.includeBody {
|
||||
err = writeReqBody(req, b)
|
||||
}
|
||||
log.Write(log.EventRequest, b.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Set the time for this particular retry operation and then Do the operation.
|
||||
tryStart := time.Now()
|
||||
response, err := req.Next() // Make the request
|
||||
tryEnd := time.Now()
|
||||
tryDuration := tryEnd.Sub(tryStart)
|
||||
opDuration := tryEnd.Sub(opValues.start)
|
||||
|
||||
if log.Should(log.EventResponse) {
|
||||
// We're going to log this; build the string to log
|
||||
b := &bytes.Buffer{}
|
||||
fmt.Fprintf(b, "==> REQUEST/RESPONSE (Try=%d/%v, OpTime=%v) -- ", opValues.try, tryDuration, opDuration)
|
||||
if err != nil { // This HTTP request did not get a response from the service
|
||||
fmt.Fprint(b, "REQUEST ERROR\n")
|
||||
} else {
|
||||
fmt.Fprint(b, "RESPONSE RECEIVED\n")
|
||||
}
|
||||
|
||||
p.writeRequestWithResponse(b, req, response, err)
|
||||
if err != nil {
|
||||
// skip frames runtime.Callers() and runtime.StackTrace()
|
||||
b.WriteString(diag.StackTrace(2, 32))
|
||||
} else if p.includeBody {
|
||||
err = writeRespBody(response, b)
|
||||
}
|
||||
log.Write(log.EventResponse, b.String())
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
|
||||
const redactedValue = "REDACTED"
|
||||
|
||||
// getSanitizedURL returns a sanitized string for the provided url.URL
|
||||
func getSanitizedURL(u url.URL, allowedQueryParams map[string]struct{}) string {
|
||||
// redact applicable query params
|
||||
qp := u.Query()
|
||||
for k := range qp {
|
||||
if _, ok := allowedQueryParams[strings.ToLower(k)]; !ok {
|
||||
qp.Set(k, redactedValue)
|
||||
}
|
||||
}
|
||||
u.RawQuery = qp.Encode()
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// writeRequestWithResponse appends a formatted HTTP request into a Buffer. If request and/or err are
|
||||
// not nil, then these are also written into the Buffer.
|
||||
func (p *logPolicy) writeRequestWithResponse(b *bytes.Buffer, req *policy.Request, resp *http.Response, err error) {
|
||||
// Write the request into the buffer.
|
||||
fmt.Fprint(b, " "+req.Raw().Method+" "+getSanitizedURL(*req.Raw().URL, p.allowedQP)+"\n")
|
||||
p.writeHeader(b, req.Raw().Header)
|
||||
if resp != nil {
|
||||
fmt.Fprintln(b, " --------------------------------------------------------------------------------")
|
||||
fmt.Fprint(b, " RESPONSE Status: "+resp.Status+"\n")
|
||||
p.writeHeader(b, resp.Header)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintln(b, " --------------------------------------------------------------------------------")
|
||||
fmt.Fprint(b, " ERROR:\n"+err.Error()+"\n")
|
||||
}
|
||||
}
|
||||
|
||||
// formatHeaders appends an HTTP request's or response's header into a Buffer.
|
||||
func (p *logPolicy) writeHeader(b *bytes.Buffer, header http.Header) {
|
||||
if len(header) == 0 {
|
||||
b.WriteString(" (no headers)\n")
|
||||
return
|
||||
}
|
||||
keys := make([]string, 0, len(header))
|
||||
// Alphabetize the headers
|
||||
for k := range header {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
// don't use Get() as it will canonicalize k which might cause a mismatch
|
||||
value := header[k][0]
|
||||
// redact all header values not in the allow-list
|
||||
if _, ok := p.allowedHeaders[strings.ToLower(k)]; !ok {
|
||||
value = redactedValue
|
||||
}
|
||||
fmt.Fprintf(b, " %s: %+v\n", k, value)
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if the request/response body should be logged.
|
||||
// this is determined by looking at the content-type header value.
|
||||
func shouldLogBody(b *bytes.Buffer, contentType string) bool {
|
||||
contentType = strings.ToLower(contentType)
|
||||
if strings.HasPrefix(contentType, "text") ||
|
||||
strings.Contains(contentType, "json") ||
|
||||
strings.Contains(contentType, "xml") {
|
||||
return true
|
||||
}
|
||||
fmt.Fprintf(b, " Skip logging body for %s\n", contentType)
|
||||
return false
|
||||
}
|
||||
|
||||
// writes to a buffer, used for logging purposes
|
||||
func writeReqBody(req *policy.Request, b *bytes.Buffer) error {
|
||||
if req.Raw().Body == nil {
|
||||
fmt.Fprint(b, " Request contained no body\n")
|
||||
return nil
|
||||
}
|
||||
if ct := req.Raw().Header.Get(shared.HeaderContentType); !shouldLogBody(b, ct) {
|
||||
return nil
|
||||
}
|
||||
body, err := io.ReadAll(req.Raw().Body)
|
||||
if err != nil {
|
||||
fmt.Fprintf(b, " Failed to read request body: %s\n", err.Error())
|
||||
return err
|
||||
}
|
||||
if err := req.RewindBody(); err != nil {
|
||||
return err
|
||||
}
|
||||
logBody(b, body)
|
||||
return nil
|
||||
}
|
||||
|
||||
// writes to a buffer, used for logging purposes
|
||||
func writeRespBody(resp *http.Response, b *bytes.Buffer) error {
|
||||
ct := resp.Header.Get(shared.HeaderContentType)
|
||||
if ct == "" {
|
||||
fmt.Fprint(b, " Response contained no body\n")
|
||||
return nil
|
||||
} else if !shouldLogBody(b, ct) {
|
||||
return nil
|
||||
}
|
||||
body, err := Payload(resp)
|
||||
if err != nil {
|
||||
fmt.Fprintf(b, " Failed to read response body: %s\n", err.Error())
|
||||
return err
|
||||
}
|
||||
if len(body) > 0 {
|
||||
logBody(b, body)
|
||||
} else {
|
||||
fmt.Fprint(b, " Response contained no body\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func logBody(b *bytes.Buffer, body []byte) {
|
||||
fmt.Fprintln(b, " --------------------------------------------------------------------------------")
|
||||
fmt.Fprintln(b, string(body))
|
||||
fmt.Fprintln(b, " --------------------------------------------------------------------------------")
|
||||
}
|
||||
34
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_request_id.go
generated
vendored
Normal file
34
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_request_id.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/uuid"
|
||||
)
|
||||
|
||||
type requestIDPolicy struct{}
|
||||
|
||||
// NewRequestIDPolicy returns a policy that add the x-ms-client-request-id header
|
||||
func NewRequestIDPolicy() policy.Policy {
|
||||
return &requestIDPolicy{}
|
||||
}
|
||||
|
||||
func (r *requestIDPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
if req.Raw().Header.Get(shared.HeaderXMSClientRequestID) == "" {
|
||||
id, err := uuid.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Raw().Header.Set(shared.HeaderXMSClientRequestID, id.String())
|
||||
}
|
||||
|
||||
return req.Next()
|
||||
}
|
||||
276
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_retry.go
generated
vendored
Normal file
276
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_retry.go
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/exported"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxRetries = 3
|
||||
)
|
||||
|
||||
func setDefaults(o *policy.RetryOptions) {
|
||||
if o.MaxRetries == 0 {
|
||||
o.MaxRetries = defaultMaxRetries
|
||||
} else if o.MaxRetries < 0 {
|
||||
o.MaxRetries = 0
|
||||
}
|
||||
|
||||
// SDK guidelines specify the default MaxRetryDelay is 60 seconds
|
||||
if o.MaxRetryDelay == 0 {
|
||||
o.MaxRetryDelay = 60 * time.Second
|
||||
} else if o.MaxRetryDelay < 0 {
|
||||
// not really an unlimited cap, but sufficiently large enough to be considered as such
|
||||
o.MaxRetryDelay = math.MaxInt64
|
||||
}
|
||||
if o.RetryDelay == 0 {
|
||||
o.RetryDelay = 800 * time.Millisecond
|
||||
} else if o.RetryDelay < 0 {
|
||||
o.RetryDelay = 0
|
||||
}
|
||||
if o.StatusCodes == nil {
|
||||
// NOTE: if you change this list, you MUST update the docs in policy/policy.go
|
||||
o.StatusCodes = []int{
|
||||
http.StatusRequestTimeout, // 408
|
||||
http.StatusTooManyRequests, // 429
|
||||
http.StatusInternalServerError, // 500
|
||||
http.StatusBadGateway, // 502
|
||||
http.StatusServiceUnavailable, // 503
|
||||
http.StatusGatewayTimeout, // 504
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func calcDelay(o policy.RetryOptions, try int32) time.Duration { // try is >=1; never 0
|
||||
// avoid overflow when shifting left
|
||||
factor := time.Duration(math.MaxInt64)
|
||||
if try < 63 {
|
||||
factor = time.Duration(int64(1<<try) - 1)
|
||||
}
|
||||
|
||||
delay := factor * o.RetryDelay
|
||||
if delay < factor {
|
||||
// overflow has happened so set to max value
|
||||
delay = time.Duration(math.MaxInt64)
|
||||
}
|
||||
|
||||
// Introduce jitter: [0.0, 1.0) / 2 = [0.0, 0.5) + 0.8 = [0.8, 1.3)
|
||||
jitterMultiplier := rand.Float64()/2 + 0.8 // NOTE: We want math/rand; not crypto/rand
|
||||
|
||||
delayFloat := float64(delay) * jitterMultiplier
|
||||
if delayFloat > float64(math.MaxInt64) {
|
||||
// the jitter pushed us over MaxInt64, so just use MaxInt64
|
||||
delay = time.Duration(math.MaxInt64)
|
||||
} else {
|
||||
delay = time.Duration(delayFloat)
|
||||
}
|
||||
|
||||
if delay > o.MaxRetryDelay { // MaxRetryDelay is backfilled with non-negative value
|
||||
delay = o.MaxRetryDelay
|
||||
}
|
||||
|
||||
return delay
|
||||
}
|
||||
|
||||
// NewRetryPolicy creates a policy object configured using the specified options.
|
||||
// Pass nil to accept the default values; this is the same as passing a zero-value options.
|
||||
func NewRetryPolicy(o *policy.RetryOptions) policy.Policy {
|
||||
if o == nil {
|
||||
o = &policy.RetryOptions{}
|
||||
}
|
||||
p := &retryPolicy{options: *o}
|
||||
return p
|
||||
}
|
||||
|
||||
type retryPolicy struct {
|
||||
options policy.RetryOptions
|
||||
}
|
||||
|
||||
func (p *retryPolicy) Do(req *policy.Request) (resp *http.Response, err error) {
|
||||
options := p.options
|
||||
// check if the retry options have been overridden for this call
|
||||
if override := req.Raw().Context().Value(shared.CtxWithRetryOptionsKey{}); override != nil {
|
||||
options = override.(policy.RetryOptions)
|
||||
}
|
||||
setDefaults(&options)
|
||||
// Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2)
|
||||
// When to retry: connection failure or temporary/timeout.
|
||||
var rwbody *retryableRequestBody
|
||||
if req.Body() != nil {
|
||||
// wrap the body so we control when it's actually closed.
|
||||
// do this outside the for loop so defers don't accumulate.
|
||||
rwbody = &retryableRequestBody{body: req.Body()}
|
||||
defer rwbody.realClose()
|
||||
}
|
||||
try := int32(1)
|
||||
for {
|
||||
resp = nil // reset
|
||||
// unfortunately we don't have access to the custom allow-list of query params, so we'll redact everything but the default allowed QPs
|
||||
log.Writef(log.EventRetryPolicy, "=====> Try=%d for %s %s", try, req.Raw().Method, getSanitizedURL(*req.Raw().URL, getAllowedQueryParams(nil)))
|
||||
|
||||
// For each try, seek to the beginning of the Body stream. We do this even for the 1st try because
|
||||
// the stream may not be at offset 0 when we first get it and we want the same behavior for the
|
||||
// 1st try as for additional tries.
|
||||
err = req.RewindBody()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// RewindBody() restores Raw().Body to its original state, so set our rewindable after
|
||||
if rwbody != nil {
|
||||
req.Raw().Body = rwbody
|
||||
}
|
||||
|
||||
if options.TryTimeout == 0 {
|
||||
clone := req.Clone(req.Raw().Context())
|
||||
resp, err = clone.Next()
|
||||
} else {
|
||||
// Set the per-try time for this particular retry operation and then Do the operation.
|
||||
tryCtx, tryCancel := context.WithTimeout(req.Raw().Context(), options.TryTimeout)
|
||||
clone := req.Clone(tryCtx)
|
||||
resp, err = clone.Next() // Make the request
|
||||
// if the body was already downloaded or there was an error it's safe to cancel the context now
|
||||
if err != nil {
|
||||
tryCancel()
|
||||
} else if exported.PayloadDownloaded(resp) {
|
||||
tryCancel()
|
||||
} else {
|
||||
// must cancel the context after the body has been read and closed
|
||||
resp.Body = &contextCancelReadCloser{cf: tryCancel, body: resp.Body}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
log.Writef(log.EventRetryPolicy, "response %d", resp.StatusCode)
|
||||
} else {
|
||||
log.Writef(log.EventRetryPolicy, "error %v", err)
|
||||
}
|
||||
|
||||
if ctxErr := req.Raw().Context().Err(); ctxErr != nil {
|
||||
// don't retry if the parent context has been cancelled or its deadline exceeded
|
||||
err = ctxErr
|
||||
log.Writef(log.EventRetryPolicy, "abort due to %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// check if the error is not retriable
|
||||
var nre errorinfo.NonRetriable
|
||||
if errors.As(err, &nre) {
|
||||
// the error says it's not retriable so don't retry
|
||||
log.Writef(log.EventRetryPolicy, "non-retriable error %T", nre)
|
||||
return
|
||||
}
|
||||
|
||||
if options.ShouldRetry != nil {
|
||||
// a non-nil ShouldRetry overrides our HTTP status code check
|
||||
if !options.ShouldRetry(resp, err) {
|
||||
// predicate says we shouldn't retry
|
||||
log.Write(log.EventRetryPolicy, "exit due to ShouldRetry")
|
||||
return
|
||||
}
|
||||
} else if err == nil && !HasStatusCode(resp, options.StatusCodes...) {
|
||||
// if there is no error and the response code isn't in the list of retry codes then we're done.
|
||||
log.Write(log.EventRetryPolicy, "exit due to non-retriable status code")
|
||||
return
|
||||
}
|
||||
|
||||
if try == options.MaxRetries+1 {
|
||||
// max number of tries has been reached, don't sleep again
|
||||
log.Writef(log.EventRetryPolicy, "MaxRetries %d exceeded", options.MaxRetries)
|
||||
return
|
||||
}
|
||||
|
||||
// use the delay from retry-after if available
|
||||
delay := shared.RetryAfter(resp)
|
||||
if delay <= 0 {
|
||||
delay = calcDelay(options, try)
|
||||
} else if delay > options.MaxRetryDelay {
|
||||
// the retry-after delay exceeds the the cap so don't retry
|
||||
log.Writef(log.EventRetryPolicy, "Retry-After delay %s exceeds MaxRetryDelay of %s", delay, options.MaxRetryDelay)
|
||||
return
|
||||
}
|
||||
|
||||
// drain before retrying so nothing is leaked
|
||||
Drain(resp)
|
||||
|
||||
log.Writef(log.EventRetryPolicy, "End Try #%d, Delay=%v", try, delay)
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
try++
|
||||
case <-req.Raw().Context().Done():
|
||||
err = req.Raw().Context().Err()
|
||||
log.Writef(log.EventRetryPolicy, "abort due to %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRetryOptions adds the specified RetryOptions to the parent context.
|
||||
// Use this to specify custom RetryOptions at the API-call level.
|
||||
// Deprecated: use [policy.WithRetryOptions] instead.
|
||||
func WithRetryOptions(parent context.Context, options policy.RetryOptions) context.Context {
|
||||
return policy.WithRetryOptions(parent, options)
|
||||
}
|
||||
|
||||
// ********** The following type/methods implement the retryableRequestBody (a ReadSeekCloser)
|
||||
|
||||
// This struct is used when sending a body to the network
|
||||
type retryableRequestBody struct {
|
||||
body io.ReadSeeker // Seeking is required to support retries
|
||||
}
|
||||
|
||||
// Read reads a block of data from an inner stream and reports progress
|
||||
func (b *retryableRequestBody) Read(p []byte) (n int, err error) {
|
||||
return b.body.Read(p)
|
||||
}
|
||||
|
||||
func (b *retryableRequestBody) Seek(offset int64, whence int) (offsetFromStart int64, err error) {
|
||||
return b.body.Seek(offset, whence)
|
||||
}
|
||||
|
||||
func (b *retryableRequestBody) Close() error {
|
||||
// We don't want the underlying transport to close the request body on transient failures so this is a nop.
|
||||
// The retry policy closes the request body upon success.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *retryableRequestBody) realClose() error {
|
||||
if c, ok := b.body.(io.Closer); ok {
|
||||
return c.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ********** The following type/methods implement the contextCancelReadCloser
|
||||
|
||||
// contextCancelReadCloser combines an io.ReadCloser with a cancel func.
|
||||
// it ensures the cancel func is invoked once the body has been read and closed.
|
||||
type contextCancelReadCloser struct {
|
||||
cf context.CancelFunc
|
||||
body io.ReadCloser
|
||||
}
|
||||
|
||||
func (rc *contextCancelReadCloser) Read(p []byte) (n int, err error) {
|
||||
return rc.body.Read(p)
|
||||
}
|
||||
|
||||
func (rc *contextCancelReadCloser) Close() error {
|
||||
err := rc.body.Close()
|
||||
rc.cf()
|
||||
return err
|
||||
}
|
||||
55
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_sas_credential.go
generated
vendored
Normal file
55
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_sas_credential.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
)
|
||||
|
||||
// SASCredentialPolicy authorizes requests with a [azcore.SASCredential].
|
||||
type SASCredentialPolicy struct {
|
||||
cred *exported.SASCredential
|
||||
header string
|
||||
allowHTTP bool
|
||||
}
|
||||
|
||||
// SASCredentialPolicyOptions contains the optional values configuring [SASCredentialPolicy].
|
||||
type SASCredentialPolicyOptions struct {
|
||||
// InsecureAllowCredentialWithHTTP enables authenticated requests over HTTP.
|
||||
// By default, authenticated requests to an HTTP endpoint are rejected by the client.
|
||||
// WARNING: setting this to true will allow sending the authentication key in clear text. Use with caution.
|
||||
InsecureAllowCredentialWithHTTP bool
|
||||
}
|
||||
|
||||
// NewSASCredentialPolicy creates a new instance of [SASCredentialPolicy].
|
||||
// - cred is the [azcore.SASCredential] used to authenticate with the service
|
||||
// - header is the name of the HTTP request header in which the shared access signature is placed
|
||||
// - options contains optional configuration, pass nil to accept the default values
|
||||
func NewSASCredentialPolicy(cred *exported.SASCredential, header string, options *SASCredentialPolicyOptions) *SASCredentialPolicy {
|
||||
if options == nil {
|
||||
options = &SASCredentialPolicyOptions{}
|
||||
}
|
||||
return &SASCredentialPolicy{
|
||||
cred: cred,
|
||||
header: header,
|
||||
allowHTTP: options.InsecureAllowCredentialWithHTTP,
|
||||
}
|
||||
}
|
||||
|
||||
// Do implementes the Do method on the [policy.Polilcy] interface.
|
||||
func (k *SASCredentialPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
// skip adding the authorization header if no SASCredential was provided.
|
||||
// this prevents a panic that might be hard to diagnose and allows testing
|
||||
// against http endpoints that don't require authentication.
|
||||
if k.cred != nil {
|
||||
if err := checkHTTPSForAuth(req, k.allowHTTP); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Raw().Header.Add(k.header, exported.SASCredentialGet(k.cred))
|
||||
}
|
||||
return req.Next()
|
||||
}
|
||||
83
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_telemetry.go
generated
vendored
Normal file
83
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_telemetry.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
)
|
||||
|
||||
type telemetryPolicy struct {
|
||||
telemetryValue string
|
||||
}
|
||||
|
||||
// NewTelemetryPolicy creates a telemetry policy object that adds telemetry information to outgoing HTTP requests.
|
||||
// The format is [<application_id> ]azsdk-go-<mod>/<ver> <platform_info>.
|
||||
// Pass nil to accept the default values; this is the same as passing a zero-value options.
|
||||
func NewTelemetryPolicy(mod, ver string, o *policy.TelemetryOptions) policy.Policy {
|
||||
if o == nil {
|
||||
o = &policy.TelemetryOptions{}
|
||||
}
|
||||
tp := telemetryPolicy{}
|
||||
if o.Disabled {
|
||||
return &tp
|
||||
}
|
||||
b := &bytes.Buffer{}
|
||||
// normalize ApplicationID
|
||||
if o.ApplicationID != "" {
|
||||
o.ApplicationID = strings.ReplaceAll(o.ApplicationID, " ", "/")
|
||||
if len(o.ApplicationID) > 24 {
|
||||
o.ApplicationID = o.ApplicationID[:24]
|
||||
}
|
||||
b.WriteString(o.ApplicationID)
|
||||
b.WriteRune(' ')
|
||||
}
|
||||
// mod might be the fully qualified name. in that case, we just want the package name
|
||||
if i := strings.LastIndex(mod, "/"); i > -1 {
|
||||
mod = mod[i+1:]
|
||||
}
|
||||
b.WriteString(formatTelemetry(mod, ver))
|
||||
b.WriteRune(' ')
|
||||
b.WriteString(platformInfo)
|
||||
tp.telemetryValue = b.String()
|
||||
return &tp
|
||||
}
|
||||
|
||||
func formatTelemetry(comp, ver string) string {
|
||||
return fmt.Sprintf("azsdk-go-%s/%s", comp, ver)
|
||||
}
|
||||
|
||||
func (p telemetryPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
if p.telemetryValue == "" {
|
||||
return req.Next()
|
||||
}
|
||||
// preserve the existing User-Agent string
|
||||
if ua := req.Raw().Header.Get(shared.HeaderUserAgent); ua != "" {
|
||||
p.telemetryValue = fmt.Sprintf("%s %s", p.telemetryValue, ua)
|
||||
}
|
||||
req.Raw().Header.Set(shared.HeaderUserAgent, p.telemetryValue)
|
||||
return req.Next()
|
||||
}
|
||||
|
||||
// NOTE: the ONLY function that should write to this variable is this func
|
||||
var platformInfo = func() string {
|
||||
operatingSystem := runtime.GOOS // Default OS string
|
||||
switch operatingSystem {
|
||||
case "windows":
|
||||
operatingSystem = os.Getenv("OS") // Get more specific OS information
|
||||
case "linux": // accept default OS info
|
||||
case "freebsd": // accept default OS info
|
||||
}
|
||||
return fmt.Sprintf("(%s; %s)", runtime.Version(), operatingSystem)
|
||||
}()
|
||||
389
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go
generated
vendored
Normal file
389
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go
generated
vendored
Normal file
@@ -0,0 +1,389 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/fake"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/poller"
|
||||
)
|
||||
|
||||
// FinalStateVia is the enumerated type for the possible final-state-via values.
|
||||
type FinalStateVia = pollers.FinalStateVia
|
||||
|
||||
const (
|
||||
// FinalStateViaAzureAsyncOp indicates the final payload comes from the Azure-AsyncOperation URL.
|
||||
FinalStateViaAzureAsyncOp = pollers.FinalStateViaAzureAsyncOp
|
||||
|
||||
// FinalStateViaLocation indicates the final payload comes from the Location URL.
|
||||
FinalStateViaLocation = pollers.FinalStateViaLocation
|
||||
|
||||
// FinalStateViaOriginalURI indicates the final payload comes from the original URL.
|
||||
FinalStateViaOriginalURI = pollers.FinalStateViaOriginalURI
|
||||
|
||||
// FinalStateViaOpLocation indicates the final payload comes from the Operation-Location URL.
|
||||
FinalStateViaOpLocation = pollers.FinalStateViaOpLocation
|
||||
)
|
||||
|
||||
// NewPollerOptions contains the optional parameters for NewPoller.
|
||||
type NewPollerOptions[T any] struct {
|
||||
// FinalStateVia contains the final-state-via value for the LRO.
|
||||
FinalStateVia FinalStateVia
|
||||
|
||||
// Response contains a preconstructed response type.
|
||||
// The final payload will be unmarshaled into it and returned.
|
||||
Response *T
|
||||
|
||||
// Handler[T] contains a custom polling implementation.
|
||||
Handler PollingHandler[T]
|
||||
|
||||
// Tracer contains the Tracer from the client that's creating the Poller.
|
||||
Tracer tracing.Tracer
|
||||
}
|
||||
|
||||
// NewPoller creates a Poller based on the provided initial response.
|
||||
func NewPoller[T any](resp *http.Response, pl exported.Pipeline, options *NewPollerOptions[T]) (*Poller[T], error) {
|
||||
if options == nil {
|
||||
options = &NewPollerOptions[T]{}
|
||||
}
|
||||
result := options.Response
|
||||
if result == nil {
|
||||
result = new(T)
|
||||
}
|
||||
if options.Handler != nil {
|
||||
return &Poller[T]{
|
||||
op: options.Handler,
|
||||
resp: resp,
|
||||
result: result,
|
||||
tracer: options.Tracer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
// this is a back-stop in case the swagger is incorrect (i.e. missing one or more status codes for success).
|
||||
// ideally the codegen should return an error if the initial response failed and not even create a poller.
|
||||
if !poller.StatusCodeValid(resp) {
|
||||
return nil, errors.New("the operation failed or was cancelled")
|
||||
}
|
||||
|
||||
// determine the polling method
|
||||
var opr PollingHandler[T]
|
||||
var err error
|
||||
if fake.Applicable(resp) {
|
||||
opr, err = fake.New[T](pl, resp)
|
||||
} else if async.Applicable(resp) {
|
||||
// async poller must be checked first as it can also have a location header
|
||||
opr, err = async.New[T](pl, resp, options.FinalStateVia)
|
||||
} else if op.Applicable(resp) {
|
||||
// op poller must be checked before loc as it can also have a location header
|
||||
opr, err = op.New[T](pl, resp, options.FinalStateVia)
|
||||
} else if loc.Applicable(resp) {
|
||||
opr, err = loc.New[T](pl, resp)
|
||||
} else if body.Applicable(resp) {
|
||||
// must test body poller last as it's a subset of the other pollers.
|
||||
// TODO: this is ambiguous for PATCH/PUT if it returns a 200 with no polling headers (sync completion)
|
||||
opr, err = body.New[T](pl, resp)
|
||||
} else if m := resp.Request.Method; resp.StatusCode == http.StatusAccepted && (m == http.MethodDelete || m == http.MethodPost) {
|
||||
// if we get here it means we have a 202 with no polling headers.
|
||||
// for DELETE and POST this is a hard error per ARM RPC spec.
|
||||
return nil, errors.New("response is missing polling URL")
|
||||
} else {
|
||||
opr, err = pollers.NewNopPoller[T](resp)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Poller[T]{
|
||||
op: opr,
|
||||
resp: resp,
|
||||
result: result,
|
||||
tracer: options.Tracer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewPollerFromResumeTokenOptions contains the optional parameters for NewPollerFromResumeToken.
|
||||
type NewPollerFromResumeTokenOptions[T any] struct {
|
||||
// Response contains a preconstructed response type.
|
||||
// The final payload will be unmarshaled into it and returned.
|
||||
Response *T
|
||||
|
||||
// Handler[T] contains a custom polling implementation.
|
||||
Handler PollingHandler[T]
|
||||
|
||||
// Tracer contains the Tracer from the client that's creating the Poller.
|
||||
Tracer tracing.Tracer
|
||||
}
|
||||
|
||||
// NewPollerFromResumeToken creates a Poller from a resume token string.
|
||||
func NewPollerFromResumeToken[T any](token string, pl exported.Pipeline, options *NewPollerFromResumeTokenOptions[T]) (*Poller[T], error) {
|
||||
if options == nil {
|
||||
options = &NewPollerFromResumeTokenOptions[T]{}
|
||||
}
|
||||
result := options.Response
|
||||
if result == nil {
|
||||
result = new(T)
|
||||
}
|
||||
|
||||
if err := pollers.IsTokenValid[T](token); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw, err := pollers.ExtractToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var asJSON map[string]any
|
||||
if err := json.Unmarshal(raw, &asJSON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opr := options.Handler
|
||||
// now rehydrate the poller based on the encoded poller type
|
||||
if fake.CanResume(asJSON) {
|
||||
opr, _ = fake.New[T](pl, nil)
|
||||
} else if opr != nil {
|
||||
log.Writef(log.EventLRO, "Resuming custom poller %T.", opr)
|
||||
} else if async.CanResume(asJSON) {
|
||||
opr, _ = async.New[T](pl, nil, "")
|
||||
} else if body.CanResume(asJSON) {
|
||||
opr, _ = body.New[T](pl, nil)
|
||||
} else if loc.CanResume(asJSON) {
|
||||
opr, _ = loc.New[T](pl, nil)
|
||||
} else if op.CanResume(asJSON) {
|
||||
opr, _ = op.New[T](pl, nil, "")
|
||||
} else {
|
||||
return nil, fmt.Errorf("unhandled poller token %s", string(raw))
|
||||
}
|
||||
if err := json.Unmarshal(raw, &opr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Poller[T]{
|
||||
op: opr,
|
||||
result: result,
|
||||
tracer: options.Tracer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PollingHandler[T] abstracts the differences among poller implementations.
|
||||
type PollingHandler[T any] interface {
|
||||
// Done returns true if the LRO has reached a terminal state.
|
||||
Done() bool
|
||||
|
||||
// Poll fetches the latest state of the LRO.
|
||||
Poll(context.Context) (*http.Response, error)
|
||||
|
||||
// Result is called once the LRO has reached a terminal state. It populates the out parameter
|
||||
// with the result of the operation.
|
||||
Result(ctx context.Context, out *T) error
|
||||
}
|
||||
|
||||
// Poller encapsulates a long-running operation, providing polling facilities until the operation reaches a terminal state.
|
||||
type Poller[T any] struct {
|
||||
op PollingHandler[T]
|
||||
resp *http.Response
|
||||
err error
|
||||
result *T
|
||||
tracer tracing.Tracer
|
||||
done bool
|
||||
}
|
||||
|
||||
// PollUntilDoneOptions contains the optional values for the Poller[T].PollUntilDone() method.
|
||||
type PollUntilDoneOptions struct {
|
||||
// Frequency is the time to wait between polling intervals in absence of a Retry-After header. Allowed minimum is one second.
|
||||
// Pass zero to accept the default value (30s).
|
||||
Frequency time.Duration
|
||||
}
|
||||
|
||||
// PollUntilDone will poll the service endpoint until a terminal state is reached, an error is received, or the context expires.
|
||||
// It internally uses Poll(), Done(), and Result() in its polling loop, sleeping for the specified duration between intervals.
|
||||
// options: pass nil to accept the default values.
|
||||
// NOTE: the default polling frequency is 30 seconds which works well for most operations. However, some operations might
|
||||
// benefit from a shorter or longer duration.
|
||||
func (p *Poller[T]) PollUntilDone(ctx context.Context, options *PollUntilDoneOptions) (res T, err error) {
|
||||
if options == nil {
|
||||
options = &PollUntilDoneOptions{}
|
||||
}
|
||||
cp := *options
|
||||
if cp.Frequency == 0 {
|
||||
cp.Frequency = 30 * time.Second
|
||||
}
|
||||
|
||||
ctx, endSpan := StartSpan(ctx, fmt.Sprintf("%s.PollUntilDone", shortenTypeName(reflect.TypeOf(*p).Name())), p.tracer, nil)
|
||||
defer func() { endSpan(err) }()
|
||||
|
||||
// skip the floor check when executing tests so they don't take so long
|
||||
if isTest := flag.Lookup("test.v"); isTest == nil && cp.Frequency < time.Second {
|
||||
err = errors.New("polling frequency minimum is one second")
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
logPollUntilDoneExit := func(v any) {
|
||||
log.Writef(log.EventLRO, "END PollUntilDone() for %T: %v, total time: %s", p.op, v, time.Since(start))
|
||||
}
|
||||
log.Writef(log.EventLRO, "BEGIN PollUntilDone() for %T", p.op)
|
||||
if p.resp != nil {
|
||||
// initial check for a retry-after header existing on the initial response
|
||||
if retryAfter := shared.RetryAfter(p.resp); retryAfter > 0 {
|
||||
log.Writef(log.EventLRO, "initial Retry-After delay for %s", retryAfter.String())
|
||||
if err = shared.Delay(ctx, retryAfter); err != nil {
|
||||
logPollUntilDoneExit(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// begin polling the endpoint until a terminal state is reached
|
||||
for {
|
||||
var resp *http.Response
|
||||
resp, err = p.Poll(ctx)
|
||||
if err != nil {
|
||||
logPollUntilDoneExit(err)
|
||||
return
|
||||
}
|
||||
if p.Done() {
|
||||
logPollUntilDoneExit("succeeded")
|
||||
res, err = p.Result(ctx)
|
||||
return
|
||||
}
|
||||
d := cp.Frequency
|
||||
if retryAfter := shared.RetryAfter(resp); retryAfter > 0 {
|
||||
log.Writef(log.EventLRO, "Retry-After delay for %s", retryAfter.String())
|
||||
d = retryAfter
|
||||
} else {
|
||||
log.Writef(log.EventLRO, "delay for %s", d.String())
|
||||
}
|
||||
if err = shared.Delay(ctx, d); err != nil {
|
||||
logPollUntilDoneExit(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Poll fetches the latest state of the LRO. It returns an HTTP response or error.
|
||||
// If Poll succeeds, the poller's state is updated and the HTTP response is returned.
|
||||
// If Poll fails, the poller's state is unmodified and the error is returned.
|
||||
// Calling Poll on an LRO that has reached a terminal state will return the last HTTP response.
|
||||
func (p *Poller[T]) Poll(ctx context.Context) (resp *http.Response, err error) {
|
||||
if p.Done() {
|
||||
// the LRO has reached a terminal state, don't poll again
|
||||
resp = p.resp
|
||||
return
|
||||
}
|
||||
|
||||
ctx, endSpan := StartSpan(ctx, fmt.Sprintf("%s.Poll", shortenTypeName(reflect.TypeOf(*p).Name())), p.tracer, nil)
|
||||
defer func() { endSpan(err) }()
|
||||
|
||||
resp, err = p.op.Poll(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.resp = resp
|
||||
return
|
||||
}
|
||||
|
||||
// Done returns true if the LRO has reached a terminal state.
|
||||
// Once a terminal state is reached, call Result().
|
||||
func (p *Poller[T]) Done() bool {
|
||||
return p.op.Done()
|
||||
}
|
||||
|
||||
// Result returns the result of the LRO and is meant to be used in conjunction with Poll and Done.
|
||||
// If the LRO completed successfully, a populated instance of T is returned.
|
||||
// If the LRO failed or was canceled, an *azcore.ResponseError error is returned.
|
||||
// Calling this on an LRO in a non-terminal state will return an error.
|
||||
func (p *Poller[T]) Result(ctx context.Context) (res T, err error) {
|
||||
if !p.Done() {
|
||||
err = errors.New("poller is in a non-terminal state")
|
||||
return
|
||||
}
|
||||
if p.done {
|
||||
// the result has already been retrieved, return the cached value
|
||||
if p.err != nil {
|
||||
err = p.err
|
||||
return
|
||||
}
|
||||
res = *p.result
|
||||
return
|
||||
}
|
||||
|
||||
ctx, endSpan := StartSpan(ctx, fmt.Sprintf("%s.Result", shortenTypeName(reflect.TypeOf(*p).Name())), p.tracer, nil)
|
||||
defer func() { endSpan(err) }()
|
||||
|
||||
err = p.op.Result(ctx, p.result)
|
||||
var respErr *exported.ResponseError
|
||||
if errors.As(err, &respErr) {
|
||||
if pollers.IsNonTerminalHTTPStatusCode(respErr.RawResponse) {
|
||||
// the request failed in a non-terminal way.
|
||||
// don't cache the error or mark the Poller as done
|
||||
return
|
||||
}
|
||||
// the LRO failed. record the error
|
||||
p.err = err
|
||||
} else if err != nil {
|
||||
// the call to Result failed, don't cache anything in this case
|
||||
return
|
||||
}
|
||||
p.done = true
|
||||
if p.err != nil {
|
||||
err = p.err
|
||||
return
|
||||
}
|
||||
res = *p.result
|
||||
return
|
||||
}
|
||||
|
||||
// ResumeToken returns a value representing the poller that can be used to resume
|
||||
// the LRO at a later time. ResumeTokens are unique per service operation.
|
||||
// The token's format should be considered opaque and is subject to change.
|
||||
// Calling this on an LRO in a terminal state will return an error.
|
||||
func (p *Poller[T]) ResumeToken() (string, error) {
|
||||
if p.Done() {
|
||||
return "", errors.New("poller is in a terminal state")
|
||||
}
|
||||
tk, err := pollers.NewResumeToken[T](p.op)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tk, err
|
||||
}
|
||||
|
||||
// extracts the type name from the string returned from reflect.Value.Name()
|
||||
func shortenTypeName(s string) string {
|
||||
// the value is formatted as follows
|
||||
// Poller[module/Package.Type].Method
|
||||
// we want to shorten the generic type parameter string to Type
|
||||
// anything we don't recognize will be left as-is
|
||||
begin := strings.Index(s, "[")
|
||||
end := strings.Index(s, "]")
|
||||
if begin == -1 || end == -1 {
|
||||
return s
|
||||
}
|
||||
|
||||
typeName := s[begin+1 : end]
|
||||
if i := strings.LastIndex(typeName, "."); i > -1 {
|
||||
typeName = typeName[i+1:]
|
||||
}
|
||||
return s[:begin+1] + typeName + s[end:]
|
||||
}
|
||||
281
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/request.go
generated
vendored
Normal file
281
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/request.go
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/uuid"
|
||||
)
|
||||
|
||||
// Base64Encoding is usesd to specify which base-64 encoder/decoder to use when
|
||||
// encoding/decoding a slice of bytes to/from a string.
|
||||
type Base64Encoding = exported.Base64Encoding
|
||||
|
||||
const (
|
||||
// Base64StdFormat uses base64.StdEncoding for encoding and decoding payloads.
|
||||
Base64StdFormat Base64Encoding = exported.Base64StdFormat
|
||||
|
||||
// Base64URLFormat uses base64.RawURLEncoding for encoding and decoding payloads.
|
||||
Base64URLFormat Base64Encoding = exported.Base64URLFormat
|
||||
)
|
||||
|
||||
// NewRequest creates a new policy.Request with the specified input.
|
||||
// The endpoint MUST be properly encoded before calling this function.
|
||||
func NewRequest(ctx context.Context, httpMethod string, endpoint string) (*policy.Request, error) {
|
||||
return exported.NewRequest(ctx, httpMethod, endpoint)
|
||||
}
|
||||
|
||||
// NewRequestFromRequest creates a new policy.Request with an existing *http.Request
|
||||
func NewRequestFromRequest(req *http.Request) (*policy.Request, error) {
|
||||
return exported.NewRequestFromRequest(req)
|
||||
}
|
||||
|
||||
// EncodeQueryParams will parse and encode any query parameters in the specified URL.
|
||||
// Any semicolons will automatically be escaped.
|
||||
func EncodeQueryParams(u string) (string, error) {
|
||||
before, after, found := strings.Cut(u, "?")
|
||||
if !found {
|
||||
return u, nil
|
||||
}
|
||||
// starting in Go 1.17, url.ParseQuery will reject semicolons in query params.
|
||||
// so, we must escape them first. note that this assumes that semicolons aren't
|
||||
// being used as query param separators which is per the current RFC.
|
||||
// for more info:
|
||||
// https://github.com/golang/go/issues/25192
|
||||
// https://github.com/golang/go/issues/50034
|
||||
qp, err := url.ParseQuery(strings.ReplaceAll(after, ";", "%3B"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return before + "?" + qp.Encode(), nil
|
||||
}
|
||||
|
||||
// JoinPaths concatenates multiple URL path segments into one path,
|
||||
// inserting path separation characters as required. JoinPaths will preserve
|
||||
// query parameters in the root path
|
||||
func JoinPaths(root string, paths ...string) string {
|
||||
if len(paths) == 0 {
|
||||
return root
|
||||
}
|
||||
|
||||
qps := ""
|
||||
if strings.Contains(root, "?") {
|
||||
splitPath := strings.Split(root, "?")
|
||||
root, qps = splitPath[0], splitPath[1]
|
||||
}
|
||||
|
||||
p := path.Join(paths...)
|
||||
// path.Join will remove any trailing slashes.
|
||||
// if one was provided, preserve it.
|
||||
if strings.HasSuffix(paths[len(paths)-1], "/") && !strings.HasSuffix(p, "/") {
|
||||
p += "/"
|
||||
}
|
||||
|
||||
if qps != "" {
|
||||
p = p + "?" + qps
|
||||
}
|
||||
|
||||
if strings.HasSuffix(root, "/") && strings.HasPrefix(p, "/") {
|
||||
root = root[:len(root)-1]
|
||||
} else if !strings.HasSuffix(root, "/") && !strings.HasPrefix(p, "/") {
|
||||
p = "/" + p
|
||||
}
|
||||
return root + p
|
||||
}
|
||||
|
||||
// EncodeByteArray will base-64 encode the byte slice v.
|
||||
func EncodeByteArray(v []byte, format Base64Encoding) string {
|
||||
return exported.EncodeByteArray(v, format)
|
||||
}
|
||||
|
||||
// MarshalAsByteArray will base-64 encode the byte slice v, then calls SetBody.
|
||||
// The encoded value is treated as a JSON string.
|
||||
func MarshalAsByteArray(req *policy.Request, v []byte, format Base64Encoding) error {
|
||||
// send as a JSON string
|
||||
encode := fmt.Sprintf("\"%s\"", EncodeByteArray(v, format))
|
||||
// tsp generated code can set Content-Type so we must prefer that
|
||||
return exported.SetBody(req, exported.NopCloser(strings.NewReader(encode)), shared.ContentTypeAppJSON, false)
|
||||
}
|
||||
|
||||
// MarshalAsJSON calls json.Marshal() to get the JSON encoding of v then calls SetBody.
|
||||
func MarshalAsJSON(req *policy.Request, v any) error {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling type %T: %s", v, err)
|
||||
}
|
||||
// tsp generated code can set Content-Type so we must prefer that
|
||||
return exported.SetBody(req, exported.NopCloser(bytes.NewReader(b)), shared.ContentTypeAppJSON, false)
|
||||
}
|
||||
|
||||
// MarshalAsXML calls xml.Marshal() to get the XML encoding of v then calls SetBody.
|
||||
func MarshalAsXML(req *policy.Request, v any) error {
|
||||
b, err := xml.Marshal(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling type %T: %s", v, err)
|
||||
}
|
||||
// inclue the XML header as some services require it
|
||||
b = []byte(xml.Header + string(b))
|
||||
return req.SetBody(exported.NopCloser(bytes.NewReader(b)), shared.ContentTypeAppXML)
|
||||
}
|
||||
|
||||
// SetMultipartFormData writes the specified keys/values as multi-part form fields with the specified value.
|
||||
// File content must be specified as an [io.ReadSeekCloser] or [streaming.MultipartContent].
|
||||
// Byte slices will be treated as JSON. All other values are treated as string values.
|
||||
func SetMultipartFormData(req *policy.Request, formData map[string]any) error {
|
||||
body := bytes.Buffer{}
|
||||
writer := multipart.NewWriter(&body)
|
||||
|
||||
writeContent := func(fieldname, filename string, src io.Reader) error {
|
||||
fd, err := writer.CreateFormFile(fieldname, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// copy the data to the form file
|
||||
if _, err = io.Copy(fd, src); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
quoteEscaper := strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||
|
||||
writeMultipartContent := func(fieldname string, mpc streaming.MultipartContent) error {
|
||||
if mpc.Body == nil {
|
||||
return errors.New("streaming.MultipartContent.Body cannot be nil")
|
||||
}
|
||||
|
||||
// use fieldname for the file name when unspecified
|
||||
filename := fieldname
|
||||
|
||||
if mpc.ContentType == "" && mpc.Filename == "" {
|
||||
return writeContent(fieldname, filename, mpc.Body)
|
||||
}
|
||||
if mpc.Filename != "" {
|
||||
filename = mpc.Filename
|
||||
}
|
||||
// this is pretty much copied from multipart.Writer.CreateFormFile
|
||||
// but lets us set the caller provided Content-Type and filename
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition",
|
||||
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
|
||||
quoteEscaper.Replace(fieldname), quoteEscaper.Replace(filename)))
|
||||
contentType := "application/octet-stream"
|
||||
if mpc.ContentType != "" {
|
||||
contentType = mpc.ContentType
|
||||
}
|
||||
h.Set("Content-Type", contentType)
|
||||
fd, err := writer.CreatePart(h)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// copy the data to the form file
|
||||
if _, err = io.Copy(fd, mpc.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// the same as multipart.Writer.WriteField but lets us specify the Content-Type
|
||||
writeField := func(fieldname, contentType string, value string) error {
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition",
|
||||
fmt.Sprintf(`form-data; name="%s"`, quoteEscaper.Replace(fieldname)))
|
||||
h.Set("Content-Type", contentType)
|
||||
fd, err := writer.CreatePart(h)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = fd.Write([]byte(value)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for k, v := range formData {
|
||||
if rsc, ok := v.(io.ReadSeekCloser); ok {
|
||||
if err := writeContent(k, k, rsc); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
} else if rscs, ok := v.([]io.ReadSeekCloser); ok {
|
||||
for _, rsc := range rscs {
|
||||
if err := writeContent(k, k, rsc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
} else if mpc, ok := v.(streaming.MultipartContent); ok {
|
||||
if err := writeMultipartContent(k, mpc); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
} else if mpcs, ok := v.([]streaming.MultipartContent); ok {
|
||||
for _, mpc := range mpcs {
|
||||
if err := writeMultipartContent(k, mpc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var content string
|
||||
contentType := shared.ContentTypeTextPlain
|
||||
switch tt := v.(type) {
|
||||
case []byte:
|
||||
// JSON, don't quote it
|
||||
content = string(tt)
|
||||
contentType = shared.ContentTypeAppJSON
|
||||
case string:
|
||||
content = tt
|
||||
default:
|
||||
// ensure the value is in string format
|
||||
content = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
if err := writeField(k, contentType, content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := writer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return req.SetBody(exported.NopCloser(bytes.NewReader(body.Bytes())), writer.FormDataContentType())
|
||||
}
|
||||
|
||||
// SkipBodyDownload will disable automatic downloading of the response body.
|
||||
func SkipBodyDownload(req *policy.Request) {
|
||||
req.SetOperationValue(bodyDownloadPolicyOpValues{Skip: true})
|
||||
}
|
||||
|
||||
// CtxAPINameKey is used as a context key for adding/retrieving the API name.
|
||||
type CtxAPINameKey = shared.CtxAPINameKey
|
||||
|
||||
// NewUUID returns a new UUID using the RFC4122 algorithm.
|
||||
func NewUUID() (string, error) {
|
||||
u, err := uuid.New()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return u.String(), nil
|
||||
}
|
||||
109
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/response.go
generated
vendored
Normal file
109
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/response.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
azexported "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/exported"
|
||||
)
|
||||
|
||||
// Payload reads and returns the response body or an error.
|
||||
// On a successful read, the response body is cached.
|
||||
// Subsequent reads will access the cached value.
|
||||
func Payload(resp *http.Response) ([]byte, error) {
|
||||
return exported.Payload(resp, nil)
|
||||
}
|
||||
|
||||
// HasStatusCode returns true if the Response's status code is one of the specified values.
|
||||
func HasStatusCode(resp *http.Response, statusCodes ...int) bool {
|
||||
return exported.HasStatusCode(resp, statusCodes...)
|
||||
}
|
||||
|
||||
// UnmarshalAsByteArray will base-64 decode the received payload and place the result into the value pointed to by v.
|
||||
func UnmarshalAsByteArray(resp *http.Response, v *[]byte, format Base64Encoding) error {
|
||||
p, err := Payload(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return DecodeByteArray(string(p), v, format)
|
||||
}
|
||||
|
||||
// UnmarshalAsJSON calls json.Unmarshal() to unmarshal the received payload into the value pointed to by v.
|
||||
func UnmarshalAsJSON(resp *http.Response, v any) error {
|
||||
payload, err := Payload(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: verify early exit is correct
|
||||
if len(payload) == 0 {
|
||||
return nil
|
||||
}
|
||||
err = removeBOM(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(payload, v)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unmarshalling type %T: %s", v, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarshalAsXML calls xml.Unmarshal() to unmarshal the received payload into the value pointed to by v.
|
||||
func UnmarshalAsXML(resp *http.Response, v any) error {
|
||||
payload, err := Payload(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: verify early exit is correct
|
||||
if len(payload) == 0 {
|
||||
return nil
|
||||
}
|
||||
err = removeBOM(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = xml.Unmarshal(payload, v)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unmarshalling type %T: %s", v, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Drain reads the response body to completion then closes it. The bytes read are discarded.
|
||||
func Drain(resp *http.Response) {
|
||||
if resp != nil && resp.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// removeBOM removes any byte-order mark prefix from the payload if present.
|
||||
func removeBOM(resp *http.Response) error {
|
||||
_, err := exported.Payload(resp, &exported.PayloadOptions{
|
||||
BytesModifier: func(b []byte) []byte {
|
||||
// UTF8
|
||||
return bytes.TrimPrefix(b, []byte("\xef\xbb\xbf"))
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeByteArray will base-64 decode the provided string into v.
|
||||
func DecodeByteArray(s string, v *[]byte, format Base64Encoding) error {
|
||||
return azexported.DecodeByteArray(s, v, format)
|
||||
}
|
||||
15
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_dialer_other.go
generated
vendored
Normal file
15
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_dialer_other.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build !wasm
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
|
||||
return dialer.DialContext
|
||||
}
|
||||
15
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_dialer_wasm.go
generated
vendored
Normal file
15
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_dialer_wasm.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build (js && wasm) || wasip1
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
|
||||
return nil
|
||||
}
|
||||
48
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_http_client.go
generated
vendored
Normal file
48
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_http_client.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
var defaultHTTPClient *http.Client
|
||||
|
||||
func init() {
|
||||
defaultTransport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: defaultTransportDialContext(&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}),
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 10,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
TLSClientConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
Renegotiation: tls.RenegotiateFreelyAsClient,
|
||||
},
|
||||
}
|
||||
// TODO: evaluate removing this once https://github.com/golang/go/issues/59690 has been fixed
|
||||
if http2Transport, err := http2.ConfigureTransports(defaultTransport); err == nil {
|
||||
// if the connection has been idle for 10 seconds, send a ping frame for a health check
|
||||
http2Transport.ReadIdleTimeout = 10 * time.Second
|
||||
// if there's no response to the ping within the timeout, the connection will be closed
|
||||
http2Transport.PingTimeout = 5 * time.Second
|
||||
}
|
||||
defaultHTTPClient = &http.Client{
|
||||
Transport: defaultTransport,
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/doc.go
generated
vendored
Normal file
9
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/doc.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
||||
// Use of this source code is governed by an MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package streaming contains helpers for streaming IO operations and progress reporting.
|
||||
package streaming
|
||||
89
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/progress.go
generated
vendored
Normal file
89
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/progress.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package streaming
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
|
||||
)
|
||||
|
||||
type progress struct {
|
||||
rc io.ReadCloser
|
||||
rsc io.ReadSeekCloser
|
||||
pr func(bytesTransferred int64)
|
||||
offset int64
|
||||
}
|
||||
|
||||
// NopCloser returns a ReadSeekCloser with a no-op close method wrapping the provided io.ReadSeeker.
|
||||
// In addition to adding a Close method to an io.ReadSeeker, this can also be used to wrap an
|
||||
// io.ReadSeekCloser with a no-op Close method to allow explicit control of when the io.ReedSeekCloser
|
||||
// has its underlying stream closed.
|
||||
func NopCloser(rs io.ReadSeeker) io.ReadSeekCloser {
|
||||
return exported.NopCloser(rs)
|
||||
}
|
||||
|
||||
// NewRequestProgress adds progress reporting to an HTTP request's body stream.
|
||||
func NewRequestProgress(body io.ReadSeekCloser, pr func(bytesTransferred int64)) io.ReadSeekCloser {
|
||||
return &progress{
|
||||
rc: body,
|
||||
rsc: body,
|
||||
pr: pr,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// NewResponseProgress adds progress reporting to an HTTP response's body stream.
|
||||
func NewResponseProgress(body io.ReadCloser, pr func(bytesTransferred int64)) io.ReadCloser {
|
||||
return &progress{
|
||||
rc: body,
|
||||
rsc: nil,
|
||||
pr: pr,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads a block of data from an inner stream and reports progress
|
||||
func (p *progress) Read(b []byte) (n int, err error) {
|
||||
n, err = p.rc.Read(b)
|
||||
if err != nil && err != io.EOF {
|
||||
return
|
||||
}
|
||||
p.offset += int64(n)
|
||||
// Invokes the user's callback method to report progress
|
||||
p.pr(p.offset)
|
||||
return
|
||||
}
|
||||
|
||||
// Seek only expects a zero or from beginning.
|
||||
func (p *progress) Seek(offset int64, whence int) (int64, error) {
|
||||
// This should only ever be called with offset = 0 and whence = io.SeekStart
|
||||
n, err := p.rsc.Seek(offset, whence)
|
||||
if err == nil {
|
||||
p.offset = int64(n)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// requestBodyProgress supports Close but the underlying stream may not; if it does, Close will close it.
|
||||
func (p *progress) Close() error {
|
||||
return p.rc.Close()
|
||||
}
|
||||
|
||||
// MultipartContent contains streaming content used in multipart/form payloads.
|
||||
type MultipartContent struct {
|
||||
// Body contains the required content body.
|
||||
Body io.ReadSeekCloser
|
||||
|
||||
// ContentType optionally specifies the HTTP Content-Type for this Body.
|
||||
// The default value is application/octet-stream.
|
||||
ContentType string
|
||||
|
||||
// Filename optionally specifies the filename for this Body.
|
||||
// The default value is the field name for the multipart/form section.
|
||||
Filename string
|
||||
}
|
||||
9
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/doc.go
generated
vendored
Normal file
9
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/doc.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
||||
// Use of this source code is governed by an MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package to contains various type-conversion helper functions.
|
||||
package to
|
||||
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/to.go
generated
vendored
Normal file
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/to.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package to
|
||||
|
||||
// Ptr returns a pointer to the provided value.
|
||||
func Ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
// SliceOfPtrs returns a slice of *T from the specified values.
|
||||
func SliceOfPtrs[T any](vv ...T) []*T {
|
||||
slc := make([]*T, len(vv))
|
||||
for i := range vv {
|
||||
slc[i] = Ptr(vv[i])
|
||||
}
|
||||
return slc
|
||||
}
|
||||
41
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing/constants.go
generated
vendored
Normal file
41
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing/constants.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package tracing
|
||||
|
||||
// SpanKind represents the role of a Span inside a Trace. Often, this defines how a Span will be processed and visualized by various backends.
|
||||
type SpanKind int
|
||||
|
||||
const (
|
||||
// SpanKindInternal indicates the span represents an internal operation within an application.
|
||||
SpanKindInternal SpanKind = 1
|
||||
|
||||
// SpanKindServer indicates the span covers server-side handling of a request.
|
||||
SpanKindServer SpanKind = 2
|
||||
|
||||
// SpanKindClient indicates the span describes a request to a remote service.
|
||||
SpanKindClient SpanKind = 3
|
||||
|
||||
// SpanKindProducer indicates the span was created by a messaging producer.
|
||||
SpanKindProducer SpanKind = 4
|
||||
|
||||
// SpanKindConsumer indicates the span was created by a messaging consumer.
|
||||
SpanKindConsumer SpanKind = 5
|
||||
)
|
||||
|
||||
// SpanStatus represents the status of a span.
|
||||
type SpanStatus int
|
||||
|
||||
const (
|
||||
// SpanStatusUnset is the default status code.
|
||||
SpanStatusUnset SpanStatus = 0
|
||||
|
||||
// SpanStatusError indicates the operation contains an error.
|
||||
SpanStatusError SpanStatus = 1
|
||||
|
||||
// SpanStatusOK indicates the operation completed successfully.
|
||||
SpanStatusOK SpanStatus = 2
|
||||
)
|
||||
191
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing/tracing.go
generated
vendored
Normal file
191
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing/tracing.go
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
// Package tracing contains the definitions needed to support distributed tracing.
|
||||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// ProviderOptions contains the optional values when creating a Provider.
|
||||
type ProviderOptions struct {
|
||||
// for future expansion
|
||||
}
|
||||
|
||||
// NewProvider creates a new Provider with the specified values.
|
||||
// - newTracerFn is the underlying implementation for creating Tracer instances
|
||||
// - options contains optional values; pass nil to accept the default value
|
||||
func NewProvider(newTracerFn func(name, version string) Tracer, options *ProviderOptions) Provider {
|
||||
return Provider{
|
||||
newTracerFn: newTracerFn,
|
||||
}
|
||||
}
|
||||
|
||||
// Provider is the factory that creates Tracer instances.
|
||||
// It defaults to a no-op provider.
|
||||
type Provider struct {
|
||||
newTracerFn func(name, version string) Tracer
|
||||
}
|
||||
|
||||
// NewTracer creates a new Tracer for the specified module name and version.
|
||||
// - module - the fully qualified name of the module
|
||||
// - version - the version of the module
|
||||
func (p Provider) NewTracer(module, version string) (tracer Tracer) {
|
||||
if p.newTracerFn != nil {
|
||||
tracer = p.newTracerFn(module, version)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TracerOptions contains the optional values when creating a Tracer.
|
||||
type TracerOptions struct {
|
||||
// SpanFromContext contains the implementation for the Tracer.SpanFromContext method.
|
||||
SpanFromContext func(context.Context) Span
|
||||
}
|
||||
|
||||
// NewTracer creates a Tracer with the specified values.
|
||||
// - newSpanFn is the underlying implementation for creating Span instances
|
||||
// - options contains optional values; pass nil to accept the default value
|
||||
func NewTracer(newSpanFn func(ctx context.Context, spanName string, options *SpanOptions) (context.Context, Span), options *TracerOptions) Tracer {
|
||||
if options == nil {
|
||||
options = &TracerOptions{}
|
||||
}
|
||||
return Tracer{
|
||||
newSpanFn: newSpanFn,
|
||||
spanFromContextFn: options.SpanFromContext,
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer is the factory that creates Span instances.
|
||||
type Tracer struct {
|
||||
attrs []Attribute
|
||||
newSpanFn func(ctx context.Context, spanName string, options *SpanOptions) (context.Context, Span)
|
||||
spanFromContextFn func(ctx context.Context) Span
|
||||
}
|
||||
|
||||
// Start creates a new span and a context.Context that contains it.
|
||||
// - ctx is the parent context for this span. If it contains a Span, the newly created span will be a child of that span, else it will be a root span
|
||||
// - spanName identifies the span within a trace, it's typically the fully qualified API name
|
||||
// - options contains optional values for the span, pass nil to accept any defaults
|
||||
func (t Tracer) Start(ctx context.Context, spanName string, options *SpanOptions) (context.Context, Span) {
|
||||
if t.newSpanFn != nil {
|
||||
opts := SpanOptions{}
|
||||
if options != nil {
|
||||
opts = *options
|
||||
}
|
||||
opts.Attributes = append(opts.Attributes, t.attrs...)
|
||||
return t.newSpanFn(ctx, spanName, &opts)
|
||||
}
|
||||
return ctx, Span{}
|
||||
}
|
||||
|
||||
// SetAttributes sets attrs to be applied to each Span. If a key from attrs
|
||||
// already exists for an attribute of the Span it will be overwritten with
|
||||
// the value contained in attrs.
|
||||
func (t *Tracer) SetAttributes(attrs ...Attribute) {
|
||||
t.attrs = append(t.attrs, attrs...)
|
||||
}
|
||||
|
||||
// Enabled returns true if this Tracer is capable of creating Spans.
|
||||
func (t Tracer) Enabled() bool {
|
||||
return t.newSpanFn != nil
|
||||
}
|
||||
|
||||
// SpanFromContext returns the Span associated with the current context.
|
||||
// If the provided context has no Span, false is returned.
|
||||
func (t Tracer) SpanFromContext(ctx context.Context) Span {
|
||||
if t.spanFromContextFn != nil {
|
||||
return t.spanFromContextFn(ctx)
|
||||
}
|
||||
return Span{}
|
||||
}
|
||||
|
||||
// SpanOptions contains optional settings for creating a span.
|
||||
type SpanOptions struct {
|
||||
// Kind indicates the kind of Span.
|
||||
Kind SpanKind
|
||||
|
||||
// Attributes contains key-value pairs of attributes for the span.
|
||||
Attributes []Attribute
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SpanImpl abstracts the underlying implementation for Span,
|
||||
// allowing it to work with various tracing implementations.
|
||||
// Any zero-values will have their default, no-op behavior.
|
||||
type SpanImpl struct {
|
||||
// End contains the implementation for the Span.End method.
|
||||
End func()
|
||||
|
||||
// SetAttributes contains the implementation for the Span.SetAttributes method.
|
||||
SetAttributes func(...Attribute)
|
||||
|
||||
// AddEvent contains the implementation for the Span.AddEvent method.
|
||||
AddEvent func(string, ...Attribute)
|
||||
|
||||
// SetStatus contains the implementation for the Span.SetStatus method.
|
||||
SetStatus func(SpanStatus, string)
|
||||
}
|
||||
|
||||
// NewSpan creates a Span with the specified implementation.
|
||||
func NewSpan(impl SpanImpl) Span {
|
||||
return Span{
|
||||
impl: impl,
|
||||
}
|
||||
}
|
||||
|
||||
// Span is a single unit of a trace. A trace can contain multiple spans.
|
||||
// A zero-value Span provides a no-op implementation.
|
||||
type Span struct {
|
||||
impl SpanImpl
|
||||
}
|
||||
|
||||
// End terminates the span and MUST be called before the span leaves scope.
|
||||
// Any further updates to the span will be ignored after End is called.
|
||||
func (s Span) End() {
|
||||
if s.impl.End != nil {
|
||||
s.impl.End()
|
||||
}
|
||||
}
|
||||
|
||||
// SetAttributes sets the specified attributes on the Span.
|
||||
// Any existing attributes with the same keys will have their values overwritten.
|
||||
func (s Span) SetAttributes(attrs ...Attribute) {
|
||||
if s.impl.SetAttributes != nil {
|
||||
s.impl.SetAttributes(attrs...)
|
||||
}
|
||||
}
|
||||
|
||||
// AddEvent adds a named event with an optional set of attributes to the span.
|
||||
func (s Span) AddEvent(name string, attrs ...Attribute) {
|
||||
if s.impl.AddEvent != nil {
|
||||
s.impl.AddEvent(name, attrs...)
|
||||
}
|
||||
}
|
||||
|
||||
// SetStatus sets the status on the span along with a description.
|
||||
func (s Span) SetStatus(code SpanStatus, desc string) {
|
||||
if s.impl.SetStatus != nil {
|
||||
s.impl.SetStatus(code, desc)
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Attribute is a key-value pair.
|
||||
type Attribute struct {
|
||||
// Key is the name of the attribute.
|
||||
Key string
|
||||
|
||||
// Value is the attribute's value.
|
||||
// Types that are natively supported include int64, float64, int, bool, string.
|
||||
// Any other type will be formatted per rules of fmt.Sprintf("%v").
|
||||
Value any
|
||||
}
|
||||
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/LICENSE.txt
generated
vendored
Normal file
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
51
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/diag/diag.go
generated
vendored
Normal file
51
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/diag/diag.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package diag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Caller returns the file and line number of a frame on the caller's stack.
|
||||
// If the funtion fails an empty string is returned.
|
||||
// skipFrames - the number of frames to skip when determining the caller.
|
||||
// Passing a value of 0 will return the immediate caller of this function.
|
||||
func Caller(skipFrames int) string {
|
||||
if pc, file, line, ok := runtime.Caller(skipFrames + 1); ok {
|
||||
// the skipFrames + 1 is to skip ourselves
|
||||
frame := runtime.FuncForPC(pc)
|
||||
return fmt.Sprintf("%s()\n\t%s:%d", frame.Name(), file, line)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// StackTrace returns a formatted stack trace string.
|
||||
// If the funtion fails an empty string is returned.
|
||||
// skipFrames - the number of stack frames to skip before composing the trace string.
|
||||
// totalFrames - the maximum number of stack frames to include in the trace string.
|
||||
func StackTrace(skipFrames, totalFrames int) string {
|
||||
pcCallers := make([]uintptr, totalFrames)
|
||||
if frames := runtime.Callers(skipFrames, pcCallers); frames == 0 {
|
||||
return ""
|
||||
}
|
||||
frames := runtime.CallersFrames(pcCallers)
|
||||
sb := strings.Builder{}
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
sb.WriteString(frame.Function)
|
||||
sb.WriteString("()\n\t")
|
||||
sb.WriteString(frame.File)
|
||||
sb.WriteRune(':')
|
||||
sb.WriteString(fmt.Sprintf("%d\n", frame.Line))
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/diag/doc.go
generated
vendored
Normal file
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/diag/doc.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package diag
|
||||
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo/doc.go
generated
vendored
Normal file
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo/doc.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package errorinfo
|
||||
46
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo/errorinfo.go
generated
vendored
Normal file
46
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo/errorinfo.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package errorinfo
|
||||
|
||||
// NonRetriable represents a non-transient error. This works in
|
||||
// conjunction with the retry policy, indicating that the error condition
|
||||
// is idempotent, so no retries will be attempted.
|
||||
// Use errors.As() to access this interface in the error chain.
|
||||
type NonRetriable interface {
|
||||
error
|
||||
NonRetriable()
|
||||
}
|
||||
|
||||
// NonRetriableError marks the specified error as non-retriable.
|
||||
// This function takes an error as input and returns a new error that is marked as non-retriable.
|
||||
func NonRetriableError(err error) error {
|
||||
return &nonRetriableError{err}
|
||||
}
|
||||
|
||||
// nonRetriableError is a struct that embeds the error interface.
|
||||
// It is used to represent errors that should not be retried.
|
||||
type nonRetriableError struct {
|
||||
error
|
||||
}
|
||||
|
||||
// Error method for nonRetriableError struct.
|
||||
// It returns the error message of the embedded error.
|
||||
func (p *nonRetriableError) Error() string {
|
||||
return p.error.Error()
|
||||
}
|
||||
|
||||
// NonRetriable is a marker method for nonRetriableError struct.
|
||||
// Non-functional and indicates that the error is non-retriable.
|
||||
func (*nonRetriableError) NonRetriable() {
|
||||
// marker method
|
||||
}
|
||||
|
||||
// Unwrap method for nonRetriableError struct.
|
||||
// It returns the original error that was marked as non-retriable.
|
||||
func (p *nonRetriableError) Unwrap() error {
|
||||
return p.error
|
||||
}
|
||||
129
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/exported/exported.go
generated
vendored
Normal file
129
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/exported/exported.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HasStatusCode returns true if the Response's status code is one of the specified values.
|
||||
// Exported as runtime.HasStatusCode().
|
||||
func HasStatusCode(resp *http.Response, statusCodes ...int) bool {
|
||||
if resp == nil {
|
||||
return false
|
||||
}
|
||||
for _, sc := range statusCodes {
|
||||
if resp.StatusCode == sc {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// PayloadOptions contains the optional values for the Payload func.
|
||||
// NOT exported but used by azcore.
|
||||
type PayloadOptions struct {
|
||||
// BytesModifier receives the downloaded byte slice and returns an updated byte slice.
|
||||
// Use this to modify the downloaded bytes in a payload (e.g. removing a BOM).
|
||||
BytesModifier func([]byte) []byte
|
||||
}
|
||||
|
||||
// Payload reads and returns the response body or an error.
|
||||
// On a successful read, the response body is cached.
|
||||
// Subsequent reads will access the cached value.
|
||||
// Exported as runtime.Payload() WITHOUT the opts parameter.
|
||||
func Payload(resp *http.Response, opts *PayloadOptions) ([]byte, error) {
|
||||
if resp.Body == nil {
|
||||
// this shouldn't happen in real-world scenarios as a
|
||||
// response with no body should set it to http.NoBody
|
||||
return nil, nil
|
||||
}
|
||||
modifyBytes := func(b []byte) []byte { return b }
|
||||
if opts != nil && opts.BytesModifier != nil {
|
||||
modifyBytes = opts.BytesModifier
|
||||
}
|
||||
|
||||
// r.Body won't be a nopClosingBytesReader if downloading was skipped
|
||||
if buf, ok := resp.Body.(*nopClosingBytesReader); ok {
|
||||
bytesBody := modifyBytes(buf.Bytes())
|
||||
buf.Set(bytesBody)
|
||||
return bytesBody, nil
|
||||
}
|
||||
|
||||
bytesBody, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bytesBody = modifyBytes(bytesBody)
|
||||
resp.Body = &nopClosingBytesReader{s: bytesBody}
|
||||
return bytesBody, nil
|
||||
}
|
||||
|
||||
// PayloadDownloaded returns true if the response body has already been downloaded.
|
||||
// This implies that the Payload() func above has been previously called.
|
||||
// NOT exported but used by azcore.
|
||||
func PayloadDownloaded(resp *http.Response) bool {
|
||||
_, ok := resp.Body.(*nopClosingBytesReader)
|
||||
return ok
|
||||
}
|
||||
|
||||
// nopClosingBytesReader is an io.ReadSeekCloser around a byte slice.
|
||||
// It also provides direct access to the byte slice to avoid rereading.
|
||||
type nopClosingBytesReader struct {
|
||||
s []byte
|
||||
i int64
|
||||
}
|
||||
|
||||
// Bytes returns the underlying byte slice.
|
||||
func (r *nopClosingBytesReader) Bytes() []byte {
|
||||
return r.s
|
||||
}
|
||||
|
||||
// Close implements the io.Closer interface.
|
||||
func (*nopClosingBytesReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read implements the io.Reader interface.
|
||||
func (r *nopClosingBytesReader) Read(b []byte) (n int, err error) {
|
||||
if r.i >= int64(len(r.s)) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n = copy(b, r.s[r.i:])
|
||||
r.i += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
// Set replaces the existing byte slice with the specified byte slice and resets the reader.
|
||||
func (r *nopClosingBytesReader) Set(b []byte) {
|
||||
r.s = b
|
||||
r.i = 0
|
||||
}
|
||||
|
||||
// Seek implements the io.Seeker interface.
|
||||
func (r *nopClosingBytesReader) Seek(offset int64, whence int) (int64, error) {
|
||||
var i int64
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
i = offset
|
||||
case io.SeekCurrent:
|
||||
i = r.i + offset
|
||||
case io.SeekEnd:
|
||||
i = int64(len(r.s)) + offset
|
||||
default:
|
||||
return 0, errors.New("nopClosingBytesReader: invalid whence")
|
||||
}
|
||||
if i < 0 {
|
||||
return 0, errors.New("nopClosingBytesReader: negative position")
|
||||
}
|
||||
r.i = i
|
||||
return i, nil
|
||||
}
|
||||
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/log/doc.go
generated
vendored
Normal file
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/log/doc.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package log
|
||||
104
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/log/log.go
generated
vendored
Normal file
104
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/log/log.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: The following are exported as public surface area from azcore. DO NOT MODIFY
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Event is used to group entries. Each group can be toggled on or off.
|
||||
type Event string
|
||||
|
||||
// SetEvents is used to control which events are written to
|
||||
// the log. By default all log events are writen.
|
||||
func SetEvents(cls ...Event) {
|
||||
log.cls = cls
|
||||
}
|
||||
|
||||
// SetListener will set the Logger to write to the specified listener.
|
||||
func SetListener(lst func(Event, string)) {
|
||||
log.lst = lst
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// END PUBLIC SURFACE AREA
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Should returns true if the specified log event should be written to the log.
|
||||
// By default all log events will be logged. Call SetEvents() to limit
|
||||
// the log events for logging.
|
||||
// If no listener has been set this will return false.
|
||||
// Calling this method is useful when the message to log is computationally expensive
|
||||
// and you want to avoid the overhead if its log event is not enabled.
|
||||
func Should(cls Event) bool {
|
||||
if log.lst == nil {
|
||||
return false
|
||||
}
|
||||
if log.cls == nil || len(log.cls) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, c := range log.cls {
|
||||
if c == cls {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Write invokes the underlying listener with the specified event and message.
|
||||
// If the event shouldn't be logged or there is no listener then Write does nothing.
|
||||
func Write(cls Event, message string) {
|
||||
if !Should(cls) {
|
||||
return
|
||||
}
|
||||
log.lst(cls, message)
|
||||
}
|
||||
|
||||
// Writef invokes the underlying listener with the specified event and formatted message.
|
||||
// If the event shouldn't be logged or there is no listener then Writef does nothing.
|
||||
func Writef(cls Event, format string, a ...interface{}) {
|
||||
if !Should(cls) {
|
||||
return
|
||||
}
|
||||
log.lst(cls, fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// TestResetEvents is used for TESTING PURPOSES ONLY.
|
||||
func TestResetEvents() {
|
||||
log.cls = nil
|
||||
}
|
||||
|
||||
// logger controls which events to log and writing to the underlying log.
|
||||
type logger struct {
|
||||
cls []Event
|
||||
lst func(Event, string)
|
||||
}
|
||||
|
||||
// the process-wide logger
|
||||
var log logger
|
||||
|
||||
func init() {
|
||||
initLogging()
|
||||
}
|
||||
|
||||
// split out for testing purposes
|
||||
func initLogging() {
|
||||
if cls := os.Getenv("AZURE_SDK_GO_LOGGING"); cls == "all" {
|
||||
// cls could be enhanced to support a comma-delimited list of log events
|
||||
log.lst = func(cls Event, msg string) {
|
||||
// simple console logger, it writes to stderr in the following format:
|
||||
// [time-stamp] Event: message
|
||||
fmt.Fprintf(os.Stderr, "[%s] %s: %s\n", time.Now().Format(time.StampMicro), cls, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
155
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/poller/util.go
generated
vendored
Normal file
155
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/poller/util.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package poller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/exported"
|
||||
)
|
||||
|
||||
// the well-known set of LRO status/provisioning state values.
|
||||
const (
|
||||
StatusSucceeded = "Succeeded"
|
||||
StatusCanceled = "Canceled"
|
||||
StatusFailed = "Failed"
|
||||
StatusInProgress = "InProgress"
|
||||
)
|
||||
|
||||
// these are non-conformant states that we've seen in the wild.
|
||||
// we support them for back-compat.
|
||||
const (
|
||||
StatusCancelled = "Cancelled"
|
||||
StatusCompleted = "Completed"
|
||||
)
|
||||
|
||||
// IsTerminalState returns true if the LRO's state is terminal.
|
||||
func IsTerminalState(s string) bool {
|
||||
return Failed(s) || Succeeded(s)
|
||||
}
|
||||
|
||||
// Failed returns true if the LRO's state is terminal failure.
|
||||
func Failed(s string) bool {
|
||||
return strings.EqualFold(s, StatusFailed) || strings.EqualFold(s, StatusCanceled) || strings.EqualFold(s, StatusCancelled)
|
||||
}
|
||||
|
||||
// Succeeded returns true if the LRO's state is terminal success.
|
||||
func Succeeded(s string) bool {
|
||||
return strings.EqualFold(s, StatusSucceeded) || strings.EqualFold(s, StatusCompleted)
|
||||
}
|
||||
|
||||
// returns true if the LRO response contains a valid HTTP status code
|
||||
func StatusCodeValid(resp *http.Response) bool {
|
||||
return exported.HasStatusCode(resp, http.StatusOK, http.StatusAccepted, http.StatusCreated, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// IsValidURL verifies that the URL is valid and absolute.
|
||||
func IsValidURL(s string) bool {
|
||||
u, err := url.Parse(s)
|
||||
return err == nil && u.IsAbs()
|
||||
}
|
||||
|
||||
// ErrNoBody is returned if the response didn't contain a body.
|
||||
var ErrNoBody = errors.New("the response did not contain a body")
|
||||
|
||||
// GetJSON reads the response body into a raw JSON object.
|
||||
// It returns ErrNoBody if there was no content.
|
||||
func GetJSON(resp *http.Response) (map[string]any, error) {
|
||||
body, err := exported.Payload(resp, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(body) == 0 {
|
||||
return nil, ErrNoBody
|
||||
}
|
||||
// unmarshall the body to get the value
|
||||
var jsonBody map[string]any
|
||||
if err = json.Unmarshal(body, &jsonBody); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return jsonBody, nil
|
||||
}
|
||||
|
||||
// provisioningState returns the provisioning state from the response or the empty string.
|
||||
func provisioningState(jsonBody map[string]any) string {
|
||||
jsonProps, ok := jsonBody["properties"]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
props, ok := jsonProps.(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
rawPs, ok := props["provisioningState"]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
ps, ok := rawPs.(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
// status returns the status from the response or the empty string.
|
||||
func status(jsonBody map[string]any) string {
|
||||
rawStatus, ok := jsonBody["status"]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
status, ok := rawStatus.(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// GetStatus returns the LRO's status from the response body.
|
||||
// Typically used for Azure-AsyncOperation flows.
|
||||
// If there is no status in the response body the empty string is returned.
|
||||
func GetStatus(resp *http.Response) (string, error) {
|
||||
jsonBody, err := GetJSON(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return status(jsonBody), nil
|
||||
}
|
||||
|
||||
// GetProvisioningState returns the LRO's state from the response body.
|
||||
// If there is no state in the response body the empty string is returned.
|
||||
func GetProvisioningState(resp *http.Response) (string, error) {
|
||||
jsonBody, err := GetJSON(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return provisioningState(jsonBody), nil
|
||||
}
|
||||
|
||||
// GetResourceLocation returns the LRO's resourceLocation value from the response body.
|
||||
// Typically used for Operation-Location flows.
|
||||
// If there is no resourceLocation in the response body the empty string is returned.
|
||||
func GetResourceLocation(resp *http.Response) (string, error) {
|
||||
jsonBody, err := GetJSON(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
v, ok := jsonBody["resourceLocation"]
|
||||
if !ok {
|
||||
// it might be ok if the field doesn't exist, the caller must make that determination
|
||||
return "", nil
|
||||
}
|
||||
vv, ok := v.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("the resourceLocation value %v was not in string format", v)
|
||||
}
|
||||
return vv, nil
|
||||
}
|
||||
123
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/temporal/resource.go
generated
vendored
Normal file
123
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/temporal/resource.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package temporal
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AcquireResource abstracts a method for refreshing a temporal resource.
|
||||
type AcquireResource[TResource, TState any] func(state TState) (newResource TResource, newExpiration time.Time, err error)
|
||||
|
||||
// Resource is a temporal resource (usually a credential) that requires periodic refreshing.
|
||||
type Resource[TResource, TState any] struct {
|
||||
// cond is used to synchronize access to the shared resource embodied by the remaining fields
|
||||
cond *sync.Cond
|
||||
|
||||
// acquiring indicates that some thread/goroutine is in the process of acquiring/updating the resource
|
||||
acquiring bool
|
||||
|
||||
// resource contains the value of the shared resource
|
||||
resource TResource
|
||||
|
||||
// expiration indicates when the shared resource expires; it is 0 if the resource was never acquired
|
||||
expiration time.Time
|
||||
|
||||
// lastAttempt indicates when a thread/goroutine last attempted to acquire/update the resource
|
||||
lastAttempt time.Time
|
||||
|
||||
// acquireResource is the callback function that actually acquires the resource
|
||||
acquireResource AcquireResource[TResource, TState]
|
||||
}
|
||||
|
||||
// NewResource creates a new Resource that uses the specified AcquireResource for refreshing.
|
||||
func NewResource[TResource, TState any](ar AcquireResource[TResource, TState]) *Resource[TResource, TState] {
|
||||
return &Resource[TResource, TState]{cond: sync.NewCond(&sync.Mutex{}), acquireResource: ar}
|
||||
}
|
||||
|
||||
// Get returns the underlying resource.
|
||||
// If the resource is fresh, no refresh is performed.
|
||||
func (er *Resource[TResource, TState]) Get(state TState) (TResource, error) {
|
||||
// If the resource is expiring within this time window, update it eagerly.
|
||||
// This allows other threads/goroutines to keep running by using the not-yet-expired
|
||||
// resource value while one thread/goroutine updates the resource.
|
||||
const window = 5 * time.Minute // This example updates the resource 5 minutes prior to expiration
|
||||
const backoff = 30 * time.Second // Minimum wait time between eager update attempts
|
||||
|
||||
now, acquire, expired := time.Now(), false, false
|
||||
|
||||
// acquire exclusive lock
|
||||
er.cond.L.Lock()
|
||||
resource := er.resource
|
||||
|
||||
for {
|
||||
expired = er.expiration.IsZero() || er.expiration.Before(now)
|
||||
if expired {
|
||||
// The resource was never acquired or has expired
|
||||
if !er.acquiring {
|
||||
// If another thread/goroutine is not acquiring/updating the resource, this thread/goroutine will do it
|
||||
er.acquiring, acquire = true, true
|
||||
break
|
||||
}
|
||||
// Getting here means that this thread/goroutine will wait for the updated resource
|
||||
} else if er.expiration.Add(-window).Before(now) {
|
||||
// The resource is valid but is expiring within the time window
|
||||
if !er.acquiring && er.lastAttempt.Add(backoff).Before(now) {
|
||||
// If another thread/goroutine is not acquiring/renewing the resource, and none has attempted
|
||||
// to do so within the last 30 seconds, this thread/goroutine will do it
|
||||
er.acquiring, acquire = true, true
|
||||
break
|
||||
}
|
||||
// This thread/goroutine will use the existing resource value while another updates it
|
||||
resource = er.resource
|
||||
break
|
||||
} else {
|
||||
// The resource is not close to expiring, this thread/goroutine should use its current value
|
||||
resource = er.resource
|
||||
break
|
||||
}
|
||||
// If we get here, wait for the new resource value to be acquired/updated
|
||||
er.cond.Wait()
|
||||
}
|
||||
er.cond.L.Unlock() // Release the lock so no threads/goroutines are blocked
|
||||
|
||||
var err error
|
||||
if acquire {
|
||||
// This thread/goroutine has been selected to acquire/update the resource
|
||||
var expiration time.Time
|
||||
var newValue TResource
|
||||
er.lastAttempt = now
|
||||
newValue, expiration, err = er.acquireResource(state)
|
||||
|
||||
// Atomically, update the shared resource's new value & expiration.
|
||||
er.cond.L.Lock()
|
||||
if err == nil {
|
||||
// Update resource & expiration, return the new value
|
||||
resource = newValue
|
||||
er.resource, er.expiration = resource, expiration
|
||||
} else if !expired {
|
||||
// An eager update failed. Discard the error and return the current--still valid--resource value
|
||||
err = nil
|
||||
}
|
||||
er.acquiring = false // Indicate that no thread/goroutine is currently acquiring the resource
|
||||
|
||||
// Wake up any waiting threads/goroutines since there is a resource they can ALL use
|
||||
er.cond.L.Unlock()
|
||||
er.cond.Broadcast()
|
||||
}
|
||||
return resource, err // Return the resource this thread/goroutine can use
|
||||
}
|
||||
|
||||
// Expire marks the resource as expired, ensuring it's refreshed on the next call to Get().
|
||||
func (er *Resource[TResource, TState]) Expire() {
|
||||
er.cond.L.Lock()
|
||||
defer er.cond.L.Unlock()
|
||||
|
||||
// Reset the expiration as if we never got this resource to begin with
|
||||
er.expiration = time.Time{}
|
||||
}
|
||||
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/uuid/doc.go
generated
vendored
Normal file
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/uuid/doc.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package uuid
|
||||
76
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/uuid/uuid.go
generated
vendored
Normal file
76
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// The UUID reserved variants.
|
||||
const (
|
||||
reservedRFC4122 byte = 0x40
|
||||
)
|
||||
|
||||
// A UUID representation compliant with specification in RFC4122 document.
|
||||
type UUID [16]byte
|
||||
|
||||
// New returns a new UUID using the RFC4122 algorithm.
|
||||
func New() (UUID, error) {
|
||||
u := UUID{}
|
||||
// Set all bits to pseudo-random values.
|
||||
// NOTE: this takes a process-wide lock
|
||||
_, err := rand.Read(u[:])
|
||||
if err != nil {
|
||||
return u, err
|
||||
}
|
||||
u[8] = (u[8] | reservedRFC4122) & 0x7F // u.setVariant(ReservedRFC4122)
|
||||
|
||||
var version byte = 4
|
||||
u[6] = (u[6] & 0xF) | (version << 4) // u.setVersion(4)
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// String returns the UUID in "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" format.
|
||||
func (u UUID) String() string {
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
|
||||
}
|
||||
|
||||
// Parse parses a string formatted as "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
// or "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" into a UUID.
|
||||
func Parse(s string) (UUID, error) {
|
||||
var uuid UUID
|
||||
// ensure format
|
||||
switch len(s) {
|
||||
case 36:
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 38:
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
s = s[1:37]
|
||||
default:
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
// parse chunks
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
b, err := strconv.ParseUint(s[x:x+2], 16, 8)
|
||||
if err != nil {
|
||||
return uuid, fmt.Errorf("invalid UUID format: %s", err)
|
||||
}
|
||||
uuid[i] = byte(b)
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/LICENSE.txt
generated
vendored
Normal file
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
472
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/client.go
generated
vendored
Normal file
472
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/client.go
generated
vendored
Normal file
@@ -0,0 +1,472 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blob
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
|
||||
)
|
||||
|
||||
// ClientOptions contains the optional parameters when creating a Client.
|
||||
type ClientOptions base.ClientOptions
|
||||
|
||||
// Client represents a URL to an Azure Storage blob; the blob may be a block blob, append blob, or page blob.
|
||||
type Client base.Client[generated.BlobClient]
|
||||
|
||||
// NewClient creates an instance of Client with the specified values.
|
||||
// - blobURL - the URL of the blob e.g. https://<account>.blob.core.windows.net/container/blob.txt
|
||||
// - cred - an Azure AD credential, typically obtained via the azidentity module
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
|
||||
audience := base.GetAudience((*base.ClientOptions)(options))
|
||||
conOptions := shared.GetClientOptions(options)
|
||||
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
|
||||
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
|
||||
|
||||
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*Client)(base.NewBlobClient(blobURL, azClient, &cred, (*base.ClientOptions)(conOptions))), nil
|
||||
}
|
||||
|
||||
// NewClientWithNoCredential creates an instance of Client with the specified values.
|
||||
// This is used to anonymously access a blob or with a shared access signature (SAS) token.
|
||||
// - blobURL - the URL of the blob e.g. https://<account>.blob.core.windows.net/container/blob.txt?<sas token>
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClientWithNoCredential(blobURL string, options *ClientOptions) (*Client, error) {
|
||||
conOptions := shared.GetClientOptions(options)
|
||||
|
||||
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*Client)(base.NewBlobClient(blobURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil
|
||||
}
|
||||
|
||||
// NewClientWithSharedKeyCredential creates an instance of Client with the specified values.
|
||||
// - blobURL - the URL of the blob e.g. https://<account>.blob.core.windows.net/container/blob.txt
|
||||
// - cred - a SharedKeyCredential created with the matching blob's storage account and access key
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClientWithSharedKeyCredential(blobURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) {
|
||||
authPolicy := exported.NewSharedKeyCredPolicy(cred)
|
||||
conOptions := shared.GetClientOptions(options)
|
||||
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
|
||||
|
||||
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*Client)(base.NewBlobClient(blobURL, azClient, cred, (*base.ClientOptions)(conOptions))), nil
|
||||
}
|
||||
|
||||
// NewClientFromConnectionString creates an instance of Client with the specified values.
|
||||
// - connectionString - a connection string for the desired storage account
|
||||
// - containerName - the name of the container within the storage account
|
||||
// - blobName - the name of the blob within the container
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClientFromConnectionString(connectionString, containerName, blobName string, options *ClientOptions) (*Client, error) {
|
||||
parsed, err := shared.ParseConnectionString(connectionString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsed.ServiceURL = runtime.JoinPaths(parsed.ServiceURL, containerName, blobName)
|
||||
|
||||
if parsed.AccountKey != "" && parsed.AccountName != "" {
|
||||
credential, err := exported.NewSharedKeyCredential(parsed.AccountName, parsed.AccountKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewClientWithSharedKeyCredential(parsed.ServiceURL, credential, options)
|
||||
}
|
||||
|
||||
return NewClientWithNoCredential(parsed.ServiceURL, options)
|
||||
}
|
||||
|
||||
func (b *Client) generated() *generated.BlobClient {
|
||||
return base.InnerClient((*base.Client[generated.BlobClient])(b))
|
||||
}
|
||||
|
||||
func (b *Client) sharedKey() *SharedKeyCredential {
|
||||
return base.SharedKey((*base.Client[generated.BlobClient])(b))
|
||||
}
|
||||
|
||||
func (b *Client) credential() any {
|
||||
return base.Credential((*base.Client[generated.BlobClient])(b))
|
||||
}
|
||||
|
||||
func (b *Client) getClientOptions() *base.ClientOptions {
|
||||
return base.GetClientOptions((*base.Client[generated.BlobClient])(b))
|
||||
}
|
||||
|
||||
// URL returns the URL endpoint used by the Client object.
|
||||
func (b *Client) URL() string {
|
||||
return b.generated().Endpoint()
|
||||
}
|
||||
|
||||
// WithSnapshot creates a new Client object identical to the source but with the specified snapshot timestamp.
|
||||
// Pass "" to remove the snapshot returning a URL to the base blob.
|
||||
func (b *Client) WithSnapshot(snapshot string) (*Client, error) {
|
||||
p, err := ParseURL(b.URL())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Snapshot = snapshot
|
||||
|
||||
return (*Client)(base.NewBlobClient(p.String(), b.generated().InternalClient(), b.credential(), b.getClientOptions())), nil
|
||||
}
|
||||
|
||||
// WithVersionID creates a new AppendBlobURL object identical to the source but with the specified version id.
|
||||
// Pass "" to remove the versionID returning a URL to the base blob.
|
||||
func (b *Client) WithVersionID(versionID string) (*Client, error) {
|
||||
p, err := ParseURL(b.URL())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.VersionID = versionID
|
||||
|
||||
return (*Client)(base.NewBlobClient(p.String(), b.generated().InternalClient(), b.credential(), b.getClientOptions())), nil
|
||||
}
|
||||
|
||||
// Delete marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection.
|
||||
// Note that deleting a blob also deletes all its snapshots.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob.
|
||||
func (b *Client) Delete(ctx context.Context, o *DeleteOptions) (DeleteResponse, error) {
|
||||
deleteOptions, leaseInfo, accessConditions := o.format()
|
||||
resp, err := b.generated().Delete(ctx, deleteOptions, leaseInfo, accessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Undelete restores the contents and metadata of a soft-deleted blob and any associated soft-deleted snapshots.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/undelete-blob.
|
||||
func (b *Client) Undelete(ctx context.Context, o *UndeleteOptions) (UndeleteResponse, error) {
|
||||
undeleteOptions := o.format()
|
||||
resp, err := b.generated().Undelete(ctx, undeleteOptions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// SetTier operation sets the tier on a blob. The operation is allowed on a page
|
||||
// blob in a premium storage account and on a block blob in a blob storage account (locally
|
||||
// redundant storage only). A premium page blob's tier determines the allowed size, IOPs, and
|
||||
// bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation
|
||||
// does not update the blob's ETag.
|
||||
// For detailed information about block blob level tiers see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers.
|
||||
func (b *Client) SetTier(ctx context.Context, tier AccessTier, o *SetTierOptions) (SetTierResponse, error) {
|
||||
opts, leaseAccessConditions, modifiedAccessConditions := o.format()
|
||||
resp, err := b.generated().SetTier(ctx, tier, opts, leaseAccessConditions, modifiedAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// GetProperties returns the blob's properties.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties.
|
||||
func (b *Client) GetProperties(ctx context.Context, options *GetPropertiesOptions) (GetPropertiesResponse, error) {
|
||||
opts, leaseAccessConditions, cpkInfo, modifiedAccessConditions := options.format()
|
||||
resp, err := b.generated().GetProperties(ctx, opts, leaseAccessConditions, cpkInfo, modifiedAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// SetHTTPHeaders changes a blob's HTTP headers.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
|
||||
func (b *Client) SetHTTPHeaders(ctx context.Context, httpHeaders HTTPHeaders, o *SetHTTPHeadersOptions) (SetHTTPHeadersResponse, error) {
|
||||
opts, leaseAccessConditions, modifiedAccessConditions := o.format()
|
||||
resp, err := b.generated().SetHTTPHeaders(ctx, opts, &httpHeaders, leaseAccessConditions, modifiedAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// SetMetadata changes a blob's metadata.
|
||||
// https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata.
|
||||
func (b *Client) SetMetadata(ctx context.Context, metadata map[string]*string, o *SetMetadataOptions) (SetMetadataResponse, error) {
|
||||
basics := generated.BlobClientSetMetadataOptions{Metadata: metadata}
|
||||
leaseAccessConditions, cpkInfo, cpkScope, modifiedAccessConditions := o.format()
|
||||
resp, err := b.generated().SetMetadata(ctx, &basics, leaseAccessConditions, cpkInfo, cpkScope, modifiedAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// CreateSnapshot creates a read-only snapshot of a blob.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/snapshot-blob.
|
||||
func (b *Client) CreateSnapshot(ctx context.Context, options *CreateSnapshotOptions) (CreateSnapshotResponse, error) {
|
||||
// CreateSnapshot does NOT panic if the user tries to create a snapshot using a URL that already has a snapshot query parameter
|
||||
// because checking this would be a performance hit for a VERY unusual path, and we don't think the common case should suffer this
|
||||
// performance hit.
|
||||
opts, cpkInfo, cpkScope, modifiedAccessConditions, leaseAccessConditions := options.format()
|
||||
resp, err := b.generated().CreateSnapshot(ctx, opts, cpkInfo, cpkScope, modifiedAccessConditions, leaseAccessConditions)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// StartCopyFromURL copies the data at the source URL to a blob.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob.
|
||||
func (b *Client) StartCopyFromURL(ctx context.Context, copySource string, options *StartCopyFromURLOptions) (StartCopyFromURLResponse, error) {
|
||||
opts, sourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions := options.format()
|
||||
resp, err := b.generated().StartCopyFromURL(ctx, copySource, opts, sourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/abort-copy-blob.
|
||||
func (b *Client) AbortCopyFromURL(ctx context.Context, copyID string, options *AbortCopyFromURLOptions) (AbortCopyFromURLResponse, error) {
|
||||
opts, leaseAccessConditions := options.format()
|
||||
resp, err := b.generated().AbortCopyFromURL(ctx, copyID, opts, leaseAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// SetTags operation enables users to set tags on a blob or specific blob version, but not snapshot.
|
||||
// Each call to this operation replaces all existing tags attached to the blob.
|
||||
// To remove all tags from the blob, call this operation with no tags set.
|
||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags
|
||||
func (b *Client) SetTags(ctx context.Context, tags map[string]string, options *SetTagsOptions) (SetTagsResponse, error) {
|
||||
serializedTags := shared.SerializeBlobTags(tags)
|
||||
blobSetTagsOptions, modifiedAccessConditions, leaseAccessConditions := options.format()
|
||||
resp, err := b.generated().SetTags(ctx, *serializedTags, blobSetTagsOptions, modifiedAccessConditions, leaseAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// GetTags operation enables users to get tags on a blob or specific blob version, or snapshot.
|
||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags
|
||||
func (b *Client) GetTags(ctx context.Context, options *GetTagsOptions) (GetTagsResponse, error) {
|
||||
blobGetTagsOptions, modifiedAccessConditions, leaseAccessConditions := options.format()
|
||||
resp, err := b.generated().GetTags(ctx, blobGetTagsOptions, modifiedAccessConditions, leaseAccessConditions)
|
||||
return resp, err
|
||||
|
||||
}
|
||||
|
||||
// SetImmutabilityPolicy operation enables users to set the immutability policy on a blob. Mode defaults to "Unlocked".
|
||||
// https://learn.microsoft.com/en-us/azure/storage/blobs/immutable-storage-overview
|
||||
func (b *Client) SetImmutabilityPolicy(ctx context.Context, expiryTime time.Time, options *SetImmutabilityPolicyOptions) (SetImmutabilityPolicyResponse, error) {
|
||||
blobSetImmutabilityPolicyOptions, modifiedAccessConditions := options.format()
|
||||
blobSetImmutabilityPolicyOptions.ImmutabilityPolicyExpiry = &expiryTime
|
||||
resp, err := b.generated().SetImmutabilityPolicy(ctx, blobSetImmutabilityPolicyOptions, modifiedAccessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// DeleteImmutabilityPolicy operation enables users to delete the immutability policy on a blob.
|
||||
// https://learn.microsoft.com/en-us/azure/storage/blobs/immutable-storage-overview
|
||||
func (b *Client) DeleteImmutabilityPolicy(ctx context.Context, options *DeleteImmutabilityPolicyOptions) (DeleteImmutabilityPolicyResponse, error) {
|
||||
deleteImmutabilityOptions := options.format()
|
||||
resp, err := b.generated().DeleteImmutabilityPolicy(ctx, deleteImmutabilityOptions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// SetLegalHold operation enables users to set legal hold on a blob.
|
||||
// https://learn.microsoft.com/en-us/azure/storage/blobs/immutable-storage-overview
|
||||
func (b *Client) SetLegalHold(ctx context.Context, legalHold bool, options *SetLegalHoldOptions) (SetLegalHoldResponse, error) {
|
||||
setLegalHoldOptions := options.format()
|
||||
resp, err := b.generated().SetLegalHold(ctx, legalHold, setLegalHoldOptions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// CopyFromURL synchronously copies the data at the source URL to a block blob, with sizes up to 256 MB.
|
||||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url.
|
||||
func (b *Client) CopyFromURL(ctx context.Context, copySource string, options *CopyFromURLOptions) (CopyFromURLResponse, error) {
|
||||
copyOptions, smac, mac, lac, cpkScopeInfo := options.format()
|
||||
resp, err := b.generated().CopyFromURL(ctx, copySource, copyOptions, smac, mac, lac, cpkScopeInfo)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// GetAccountInfo provides account level information
|
||||
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/get-account-information?tabs=shared-access-signatures.
|
||||
func (b *Client) GetAccountInfo(ctx context.Context, o *GetAccountInfoOptions) (GetAccountInfoResponse, error) {
|
||||
getAccountInfoOptions := o.format()
|
||||
resp, err := b.generated().GetAccountInfo(ctx, getAccountInfoOptions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// GetSASURL is a convenience method for generating a SAS token for the currently pointed at blob.
|
||||
// It can only be used if the credential supplied during creation was a SharedKeyCredential.
|
||||
func (b *Client) GetSASURL(permissions sas.BlobPermissions, expiry time.Time, o *GetSASURLOptions) (string, error) {
|
||||
if b.sharedKey() == nil {
|
||||
return "", bloberror.MissingSharedKeyCredential
|
||||
}
|
||||
|
||||
urlParts, err := ParseURL(b.URL())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
t, err := time.Parse(SnapshotTimeFormat, urlParts.Snapshot)
|
||||
|
||||
if err != nil {
|
||||
t = time.Time{}
|
||||
}
|
||||
st := o.format()
|
||||
|
||||
qps, err := sas.BlobSignatureValues{
|
||||
ContainerName: urlParts.ContainerName,
|
||||
BlobName: urlParts.BlobName,
|
||||
SnapshotTime: t,
|
||||
Version: sas.Version,
|
||||
Permissions: permissions.String(),
|
||||
StartTime: st,
|
||||
ExpiryTime: expiry.UTC(),
|
||||
}.SignWithSharedKey(b.sharedKey())
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
endpoint := b.URL() + "?" + qps.Encode()
|
||||
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
// Concurrent Download Functions -----------------------------------------------------------------------------------------
|
||||
|
||||
// downloadBuffer downloads an Azure blob to a WriterAt in parallel.
|
||||
func (b *Client) downloadBuffer(ctx context.Context, writer io.WriterAt, o downloadOptions) (int64, error) {
|
||||
if o.BlockSize == 0 {
|
||||
o.BlockSize = DefaultDownloadBlockSize
|
||||
}
|
||||
|
||||
count := o.Range.Count
|
||||
if count == CountToEnd { // If size not specified, calculate it
|
||||
// If we don't have the length at all, get it
|
||||
gr, err := b.GetProperties(ctx, o.getBlobPropertiesOptions())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
count = *gr.ContentLength - o.Range.Offset
|
||||
}
|
||||
|
||||
if count <= 0 {
|
||||
// The file is empty, there is nothing to download.
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Prepare and do parallel download.
|
||||
progress := int64(0)
|
||||
progressLock := &sync.Mutex{}
|
||||
|
||||
err := shared.DoBatchTransfer(ctx, &shared.BatchTransferOptions{
|
||||
OperationName: "downloadBlobToWriterAt",
|
||||
TransferSize: count,
|
||||
ChunkSize: o.BlockSize,
|
||||
NumChunks: uint64(((count - 1) / o.BlockSize) + 1),
|
||||
Concurrency: o.Concurrency,
|
||||
Operation: func(ctx context.Context, chunkStart int64, count int64) error {
|
||||
downloadBlobOptions := o.getDownloadBlobOptions(HTTPRange{
|
||||
Offset: chunkStart + o.Range.Offset,
|
||||
Count: count,
|
||||
}, nil)
|
||||
dr, err := b.DownloadStream(ctx, downloadBlobOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var body io.ReadCloser = dr.NewRetryReader(ctx, &o.RetryReaderOptionsPerBlock)
|
||||
if o.Progress != nil {
|
||||
rangeProgress := int64(0)
|
||||
body = streaming.NewResponseProgress(
|
||||
body,
|
||||
func(bytesTransferred int64) {
|
||||
diff := bytesTransferred - rangeProgress
|
||||
rangeProgress = bytesTransferred
|
||||
progressLock.Lock()
|
||||
progress += diff
|
||||
o.Progress(progress)
|
||||
progressLock.Unlock()
|
||||
})
|
||||
}
|
||||
_, err = io.Copy(shared.NewSectionWriter(writer, chunkStart, count), body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = body.Close()
|
||||
return err
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// DownloadStream reads a range of bytes from a blob. The response also includes the blob's properties and metadata.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob.
|
||||
func (b *Client) DownloadStream(ctx context.Context, o *DownloadStreamOptions) (DownloadStreamResponse, error) {
|
||||
downloadOptions, leaseAccessConditions, cpkInfo, modifiedAccessConditions := o.format()
|
||||
if o == nil {
|
||||
o = &DownloadStreamOptions{}
|
||||
}
|
||||
|
||||
dr, err := b.generated().Download(ctx, downloadOptions, leaseAccessConditions, cpkInfo, modifiedAccessConditions)
|
||||
if err != nil {
|
||||
return DownloadStreamResponse{}, err
|
||||
}
|
||||
|
||||
return DownloadStreamResponse{
|
||||
client: b,
|
||||
DownloadResponse: dr,
|
||||
getInfo: httpGetterInfo{Range: o.Range, ETag: dr.ETag},
|
||||
ObjectReplicationRules: deserializeORSPolicies(dr.ObjectReplicationRules),
|
||||
cpkInfo: o.CPKInfo,
|
||||
cpkScope: o.CPKScopeInfo,
|
||||
}, err
|
||||
}
|
||||
|
||||
// DownloadBuffer downloads an Azure blob to a buffer with parallel.
|
||||
func (b *Client) DownloadBuffer(ctx context.Context, buffer []byte, o *DownloadBufferOptions) (int64, error) {
|
||||
if o == nil {
|
||||
o = &DownloadBufferOptions{}
|
||||
}
|
||||
return b.downloadBuffer(ctx, shared.NewBytesWriter(buffer), (downloadOptions)(*o))
|
||||
}
|
||||
|
||||
// DownloadFile downloads an Azure blob to a local file.
|
||||
// The file would be truncated if the size doesn't match.
|
||||
func (b *Client) DownloadFile(ctx context.Context, file *os.File, o *DownloadFileOptions) (int64, error) {
|
||||
if o == nil {
|
||||
o = &DownloadFileOptions{}
|
||||
}
|
||||
do := (*downloadOptions)(o)
|
||||
|
||||
// 1. Calculate the size of the destination file
|
||||
var size int64
|
||||
|
||||
count := do.Range.Count
|
||||
if count == CountToEnd {
|
||||
// Try to get Azure blob's size
|
||||
getBlobPropertiesOptions := do.getBlobPropertiesOptions()
|
||||
props, err := b.GetProperties(ctx, getBlobPropertiesOptions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
size = *props.ContentLength - do.Range.Offset
|
||||
do.Range.Count = size
|
||||
} else {
|
||||
size = count
|
||||
}
|
||||
|
||||
// 2. Compare and try to resize local file's size if it doesn't match Azure blob's size.
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if stat.Size() != size {
|
||||
if err = file.Truncate(size); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
if size > 0 {
|
||||
return b.downloadBuffer(ctx, file, *do)
|
||||
} else { // if the blob's size is 0, there is no need in downloading it
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
235
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/constants.go
generated
vendored
Normal file
235
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/constants.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blob
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
)
|
||||
|
||||
const (
|
||||
CountToEnd = 0
|
||||
|
||||
SnapshotTimeFormat = exported.SnapshotTimeFormat
|
||||
|
||||
// DefaultDownloadBlockSize is default block size
|
||||
DefaultDownloadBlockSize = int64(4 * 1024 * 1024) // 4MB
|
||||
|
||||
// DefaultConcurrency is the default number of blocks downloaded or uploaded in parallel
|
||||
DefaultConcurrency = shared.DefaultConcurrency
|
||||
)
|
||||
|
||||
// BlobType defines values for BlobType
|
||||
type BlobType = generated.BlobType
|
||||
|
||||
const (
|
||||
BlobTypeBlockBlob BlobType = generated.BlobTypeBlockBlob
|
||||
BlobTypePageBlob BlobType = generated.BlobTypePageBlob
|
||||
BlobTypeAppendBlob BlobType = generated.BlobTypeAppendBlob
|
||||
)
|
||||
|
||||
// PossibleBlobTypeValues returns the possible values for the BlobType const type.
|
||||
func PossibleBlobTypeValues() []BlobType {
|
||||
return generated.PossibleBlobTypeValues()
|
||||
}
|
||||
|
||||
// DeleteSnapshotsOptionType defines values for DeleteSnapshotsOptionType
|
||||
type DeleteSnapshotsOptionType = generated.DeleteSnapshotsOptionType
|
||||
|
||||
const (
|
||||
DeleteSnapshotsOptionTypeInclude DeleteSnapshotsOptionType = generated.DeleteSnapshotsOptionTypeInclude
|
||||
DeleteSnapshotsOptionTypeOnly DeleteSnapshotsOptionType = generated.DeleteSnapshotsOptionTypeOnly
|
||||
)
|
||||
|
||||
// PossibleDeleteSnapshotsOptionTypeValues returns the possible values for the DeleteSnapshotsOptionType const type.
|
||||
func PossibleDeleteSnapshotsOptionTypeValues() []DeleteSnapshotsOptionType {
|
||||
return generated.PossibleDeleteSnapshotsOptionTypeValues()
|
||||
}
|
||||
|
||||
// AccessTier defines values for Blob Access Tier.
|
||||
type AccessTier = generated.AccessTier
|
||||
|
||||
const (
|
||||
AccessTierArchive AccessTier = generated.AccessTierArchive
|
||||
AccessTierCool AccessTier = generated.AccessTierCool
|
||||
AccessTierCold AccessTier = generated.AccessTierCold
|
||||
AccessTierHot AccessTier = generated.AccessTierHot
|
||||
AccessTierP10 AccessTier = generated.AccessTierP10
|
||||
AccessTierP15 AccessTier = generated.AccessTierP15
|
||||
AccessTierP20 AccessTier = generated.AccessTierP20
|
||||
AccessTierP30 AccessTier = generated.AccessTierP30
|
||||
AccessTierP4 AccessTier = generated.AccessTierP4
|
||||
AccessTierP40 AccessTier = generated.AccessTierP40
|
||||
AccessTierP50 AccessTier = generated.AccessTierP50
|
||||
AccessTierP6 AccessTier = generated.AccessTierP6
|
||||
AccessTierP60 AccessTier = generated.AccessTierP60
|
||||
AccessTierP70 AccessTier = generated.AccessTierP70
|
||||
AccessTierP80 AccessTier = generated.AccessTierP80
|
||||
AccessTierPremium AccessTier = generated.AccessTierPremium
|
||||
)
|
||||
|
||||
// PossibleAccessTierValues returns the possible values for the AccessTier const type.
|
||||
func PossibleAccessTierValues() []AccessTier {
|
||||
return generated.PossibleAccessTierValues()
|
||||
}
|
||||
|
||||
// RehydratePriority - If an object is in rehydrate pending state then this header is returned with priority of rehydrate.
|
||||
// Valid values are High and Standard.
|
||||
type RehydratePriority = generated.RehydratePriority
|
||||
|
||||
const (
|
||||
RehydratePriorityHigh RehydratePriority = generated.RehydratePriorityHigh
|
||||
RehydratePriorityStandard RehydratePriority = generated.RehydratePriorityStandard
|
||||
)
|
||||
|
||||
// PossibleRehydratePriorityValues returns the possible values for the RehydratePriority const type.
|
||||
func PossibleRehydratePriorityValues() []RehydratePriority {
|
||||
return generated.PossibleRehydratePriorityValues()
|
||||
}
|
||||
|
||||
// ImmutabilityPolicyMode defines values for ImmutabilityPolicyMode
|
||||
type ImmutabilityPolicyMode = generated.ImmutabilityPolicyMode
|
||||
|
||||
const (
|
||||
ImmutabilityPolicyModeMutable ImmutabilityPolicyMode = generated.ImmutabilityPolicyModeMutable
|
||||
ImmutabilityPolicyModeUnlocked ImmutabilityPolicyMode = generated.ImmutabilityPolicyModeUnlocked
|
||||
ImmutabilityPolicyModeLocked ImmutabilityPolicyMode = generated.ImmutabilityPolicyModeLocked
|
||||
)
|
||||
|
||||
// PossibleImmutabilityPolicyModeValues returns the possible values for the ImmutabilityPolicyMode const type.
|
||||
func PossibleImmutabilityPolicyModeValues() []ImmutabilityPolicyMode {
|
||||
return generated.PossibleImmutabilityPolicyModeValues()
|
||||
}
|
||||
|
||||
// ImmutabilityPolicySetting returns the possible values for the ImmutabilityPolicySetting const type.
|
||||
type ImmutabilityPolicySetting = generated.ImmutabilityPolicySetting
|
||||
|
||||
const (
|
||||
ImmutabilityPolicySettingUnlocked ImmutabilityPolicySetting = generated.ImmutabilityPolicySettingUnlocked
|
||||
ImmutabilityPolicySettingLocked ImmutabilityPolicySetting = generated.ImmutabilityPolicySettingLocked
|
||||
)
|
||||
|
||||
// PossibleImmutabilityPolicySettingValues returns the possible values for the ImmutabilityPolicySetting const type.
|
||||
func PossibleImmutabilityPolicySettingValues() []ImmutabilityPolicySetting {
|
||||
return generated.PossibleImmutabilityPolicySettingValues()
|
||||
}
|
||||
|
||||
// CopyStatusType defines values for CopyStatusType
|
||||
type CopyStatusType = generated.CopyStatusType
|
||||
|
||||
const (
|
||||
CopyStatusTypePending CopyStatusType = generated.CopyStatusTypePending
|
||||
CopyStatusTypeSuccess CopyStatusType = generated.CopyStatusTypeSuccess
|
||||
CopyStatusTypeAborted CopyStatusType = generated.CopyStatusTypeAborted
|
||||
CopyStatusTypeFailed CopyStatusType = generated.CopyStatusTypeFailed
|
||||
)
|
||||
|
||||
// PossibleCopyStatusTypeValues returns the possible values for the CopyStatusType const type.
|
||||
func PossibleCopyStatusTypeValues() []CopyStatusType {
|
||||
return generated.PossibleCopyStatusTypeValues()
|
||||
}
|
||||
|
||||
// EncryptionAlgorithmType defines values for EncryptionAlgorithmType.
|
||||
type EncryptionAlgorithmType = generated.EncryptionAlgorithmType
|
||||
|
||||
const (
|
||||
EncryptionAlgorithmTypeNone EncryptionAlgorithmType = generated.EncryptionAlgorithmTypeNone
|
||||
EncryptionAlgorithmTypeAES256 EncryptionAlgorithmType = generated.EncryptionAlgorithmTypeAES256
|
||||
)
|
||||
|
||||
// PossibleEncryptionAlgorithmTypeValues returns the possible values for the EncryptionAlgorithmType const type.
|
||||
func PossibleEncryptionAlgorithmTypeValues() []EncryptionAlgorithmType {
|
||||
return generated.PossibleEncryptionAlgorithmTypeValues()
|
||||
}
|
||||
|
||||
// ArchiveStatus defines values for ArchiveStatus.
|
||||
type ArchiveStatus = generated.ArchiveStatus
|
||||
|
||||
const (
|
||||
ArchiveStatusRehydratePendingToCool ArchiveStatus = generated.ArchiveStatusRehydratePendingToCool
|
||||
ArchiveStatusRehydratePendingToHot ArchiveStatus = generated.ArchiveStatusRehydratePendingToHot
|
||||
ArchiveStatusRehydratePendingToCold ArchiveStatus = generated.ArchiveStatusRehydratePendingToCold
|
||||
)
|
||||
|
||||
// PossibleArchiveStatusValues returns the possible values for the ArchiveStatus const type.
|
||||
func PossibleArchiveStatusValues() []ArchiveStatus {
|
||||
return generated.PossibleArchiveStatusValues()
|
||||
}
|
||||
|
||||
// DeleteType defines values for DeleteType.
|
||||
type DeleteType = generated.DeleteType
|
||||
|
||||
const (
|
||||
DeleteTypeNone DeleteType = generated.DeleteTypeNone
|
||||
DeleteTypePermanent DeleteType = generated.DeleteTypePermanent
|
||||
)
|
||||
|
||||
// PossibleDeleteTypeValues returns the possible values for the DeleteType const type.
|
||||
func PossibleDeleteTypeValues() []DeleteType {
|
||||
return generated.PossibleDeleteTypeValues()
|
||||
}
|
||||
|
||||
// QueryFormatType - The quick query format type.
|
||||
type QueryFormatType = generated.QueryFormatType
|
||||
|
||||
const (
|
||||
QueryFormatTypeDelimited QueryFormatType = generated.QueryFormatTypeDelimited
|
||||
QueryFormatTypeJSON QueryFormatType = generated.QueryFormatTypeJSON
|
||||
QueryFormatTypeArrow QueryFormatType = generated.QueryFormatTypeArrow
|
||||
QueryFormatTypeParquet QueryFormatType = generated.QueryFormatTypeParquet
|
||||
)
|
||||
|
||||
// PossibleQueryFormatTypeValues returns the possible values for the QueryFormatType const type.
|
||||
func PossibleQueryFormatTypeValues() []QueryFormatType {
|
||||
return generated.PossibleQueryFormatTypeValues()
|
||||
}
|
||||
|
||||
// TransferValidationType abstracts the various mechanisms used to verify a transfer.
|
||||
type TransferValidationType = exported.TransferValidationType
|
||||
|
||||
// TransferValidationTypeCRC64 is a TransferValidationType used to provide a precomputed CRC64.
|
||||
type TransferValidationTypeCRC64 = exported.TransferValidationTypeCRC64
|
||||
|
||||
// TransferValidationTypeComputeCRC64 is a TransferValidationType that indicates a CRC64 should be computed during transfer.
|
||||
func TransferValidationTypeComputeCRC64() TransferValidationType {
|
||||
return exported.TransferValidationTypeComputeCRC64()
|
||||
}
|
||||
|
||||
// TransferValidationTypeMD5 is a TransferValidationType used to provide a precomputed MD5.
|
||||
type TransferValidationTypeMD5 = exported.TransferValidationTypeMD5
|
||||
|
||||
// SourceContentValidationType abstracts the various mechanisms used to validate source content.
|
||||
// This interface is not publicly implementable.
|
||||
type SourceContentValidationType interface {
|
||||
Apply(generated.SourceContentSetter)
|
||||
notPubliclyImplementable()
|
||||
}
|
||||
|
||||
// SourceContentValidationTypeCRC64 is a SourceContentValidationType used to provide a precomputed CRC64.
|
||||
type SourceContentValidationTypeCRC64 []byte
|
||||
|
||||
// Apply implements the SourceContentValidationType interface for type SourceContentValidationTypeCRC64.
|
||||
func (s SourceContentValidationTypeCRC64) Apply(src generated.SourceContentSetter) {
|
||||
src.SetSourceContentCRC64(s)
|
||||
}
|
||||
|
||||
func (SourceContentValidationTypeCRC64) notPubliclyImplementable() {}
|
||||
|
||||
var _ SourceContentValidationType = (SourceContentValidationTypeCRC64)(nil)
|
||||
|
||||
// SourceContentValidationTypeMD5 is a SourceContentValidationType used to provide a precomputed MD5.
|
||||
type SourceContentValidationTypeMD5 []byte
|
||||
|
||||
// Apply implements the SourceContentValidationType interface for type SourceContentValidationTypeMD5.
|
||||
func (s SourceContentValidationTypeMD5) Apply(src generated.SourceContentSetter) {
|
||||
src.SetSourceContentMD5(s)
|
||||
}
|
||||
|
||||
func (SourceContentValidationTypeMD5) notPubliclyImplementable() {}
|
||||
|
||||
var _ SourceContentValidationType = (SourceContentValidationTypeMD5)(nil)
|
||||
580
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/models.go
generated
vendored
Normal file
580
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/models.go
generated
vendored
Normal file
@@ -0,0 +1,580 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blob
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
)
|
||||
|
||||
// SharedKeyCredential contains an account's name and its primary or secondary key.
|
||||
type SharedKeyCredential = exported.SharedKeyCredential
|
||||
|
||||
// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the
|
||||
// storage account's name and either its primary or secondary key.
|
||||
func NewSharedKeyCredential(accountName, accountKey string) (*SharedKeyCredential, error) {
|
||||
return exported.NewSharedKeyCredential(accountName, accountKey)
|
||||
}
|
||||
|
||||
// Type Declarations ---------------------------------------------------------------------
|
||||
|
||||
// AccessConditions identifies blob-specific access conditions which you optionally set.
|
||||
type AccessConditions = exported.BlobAccessConditions
|
||||
|
||||
// LeaseAccessConditions contains optional parameters to access leased entity.
|
||||
type LeaseAccessConditions = exported.LeaseAccessConditions
|
||||
|
||||
// ModifiedAccessConditions contains a group of parameters for specifying access conditions.
|
||||
type ModifiedAccessConditions = exported.ModifiedAccessConditions
|
||||
|
||||
// CPKInfo contains a group of parameters for client provided encryption key.
|
||||
type CPKInfo = generated.CPKInfo
|
||||
|
||||
// CPKScopeInfo contains a group of parameters for client provided encryption scope.
|
||||
type CPKScopeInfo = generated.CPKScopeInfo
|
||||
|
||||
// HTTPHeaders contains a group of parameters for the BlobClient.SetHTTPHeaders method.
|
||||
type HTTPHeaders = generated.BlobHTTPHeaders
|
||||
|
||||
// SourceModifiedAccessConditions contains a group of parameters for the BlobClient.StartCopyFromURL method.
|
||||
type SourceModifiedAccessConditions = generated.SourceModifiedAccessConditions
|
||||
|
||||
// Tags represent map of blob index tags
|
||||
type Tags = generated.BlobTag
|
||||
|
||||
// HTTPRange defines a range of bytes within an HTTP resource, starting at offset and
|
||||
// ending at offset+count. A zero-value HTTPRange indicates the entire resource. An HTTPRange
|
||||
// which has an offset and zero value count indicates from the offset to the resource's end.
|
||||
type HTTPRange = exported.HTTPRange
|
||||
|
||||
// Request Model Declaration -------------------------------------------------------------------------------------------
|
||||
|
||||
// DownloadStreamOptions contains the optional parameters for the Client.Download method.
|
||||
type DownloadStreamOptions struct {
|
||||
// When set to true and specified together with the Range, the service returns the MD5 hash for the range, as long as the
|
||||
// range is less than or equal to 4 MB in size.
|
||||
RangeGetContentMD5 *bool
|
||||
|
||||
// Range specifies a range of bytes. The default value is all bytes.
|
||||
Range HTTPRange
|
||||
|
||||
AccessConditions *AccessConditions
|
||||
CPKInfo *CPKInfo
|
||||
CPKScopeInfo *CPKScopeInfo
|
||||
}
|
||||
|
||||
func (o *DownloadStreamOptions) format() (*generated.BlobClientDownloadOptions, *generated.LeaseAccessConditions, *generated.CPKInfo, *generated.ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
basics := generated.BlobClientDownloadOptions{
|
||||
RangeGetContentMD5: o.RangeGetContentMD5,
|
||||
Range: exported.FormatHTTPRange(o.Range),
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return &basics, leaseAccessConditions, o.CPKInfo, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// downloadOptions contains common options used by the DownloadBuffer and DownloadFile functions.
|
||||
type downloadOptions struct {
|
||||
// Range specifies a range of bytes. The default value is all bytes.
|
||||
Range HTTPRange
|
||||
|
||||
// BlockSize specifies the block size to use for each parallel download; the default size is DefaultDownloadBlockSize.
|
||||
BlockSize int64
|
||||
|
||||
// Progress is a function that is invoked periodically as bytes are received.
|
||||
Progress func(bytesTransferred int64)
|
||||
|
||||
// BlobAccessConditions indicates the access conditions used when making HTTP GET requests against the blob.
|
||||
AccessConditions *AccessConditions
|
||||
|
||||
// ClientProvidedKeyOptions indicates the client provided key by name and/or by value to encrypt/decrypt data.
|
||||
CPKInfo *CPKInfo
|
||||
CPKScopeInfo *CPKScopeInfo
|
||||
|
||||
// Concurrency indicates the maximum number of blocks to download in parallel (0=default).
|
||||
Concurrency uint16
|
||||
|
||||
// RetryReaderOptionsPerBlock is used when downloading each block.
|
||||
RetryReaderOptionsPerBlock RetryReaderOptions
|
||||
}
|
||||
|
||||
func (o *downloadOptions) getBlobPropertiesOptions() *GetPropertiesOptions {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
return &GetPropertiesOptions{
|
||||
AccessConditions: o.AccessConditions,
|
||||
CPKInfo: o.CPKInfo,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *downloadOptions) getDownloadBlobOptions(rnge HTTPRange, rangeGetContentMD5 *bool) *DownloadStreamOptions {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
return &DownloadStreamOptions{
|
||||
AccessConditions: o.AccessConditions,
|
||||
CPKInfo: o.CPKInfo,
|
||||
CPKScopeInfo: o.CPKScopeInfo,
|
||||
Range: rnge,
|
||||
RangeGetContentMD5: rangeGetContentMD5,
|
||||
}
|
||||
}
|
||||
|
||||
// DownloadBufferOptions contains the optional parameters for the DownloadBuffer method.
|
||||
type DownloadBufferOptions struct {
|
||||
// Range specifies a range of bytes. The default value is all bytes.
|
||||
Range HTTPRange
|
||||
|
||||
// BlockSize specifies the block size to use for each parallel download; the default size is DefaultDownloadBlockSize.
|
||||
BlockSize int64
|
||||
|
||||
// Progress is a function that is invoked periodically as bytes are received.
|
||||
Progress func(bytesTransferred int64)
|
||||
|
||||
// BlobAccessConditions indicates the access conditions used when making HTTP GET requests against the blob.
|
||||
AccessConditions *AccessConditions
|
||||
|
||||
// CPKInfo contains a group of parameters for client provided encryption key.
|
||||
CPKInfo *CPKInfo
|
||||
|
||||
// CPKScopeInfo contains a group of parameters for client provided encryption scope.
|
||||
CPKScopeInfo *CPKScopeInfo
|
||||
|
||||
// Concurrency indicates the maximum number of blocks to download in parallel (0=default).
|
||||
Concurrency uint16
|
||||
|
||||
// RetryReaderOptionsPerBlock is used when downloading each block.
|
||||
RetryReaderOptionsPerBlock RetryReaderOptions
|
||||
}
|
||||
|
||||
// DownloadFileOptions contains the optional parameters for the DownloadFile method.
|
||||
type DownloadFileOptions struct {
|
||||
// Range specifies a range of bytes. The default value is all bytes.
|
||||
Range HTTPRange
|
||||
|
||||
// BlockSize specifies the block size to use for each parallel download; the default size is DefaultDownloadBlockSize.
|
||||
BlockSize int64
|
||||
|
||||
// Progress is a function that is invoked periodically as bytes are received.
|
||||
Progress func(bytesTransferred int64)
|
||||
|
||||
// BlobAccessConditions indicates the access conditions used when making HTTP GET requests against the blob.
|
||||
AccessConditions *AccessConditions
|
||||
|
||||
// ClientProvidedKeyOptions indicates the client provided key by name and/or by value to encrypt/decrypt data.
|
||||
CPKInfo *CPKInfo
|
||||
CPKScopeInfo *CPKScopeInfo
|
||||
|
||||
// Concurrency indicates the maximum number of blocks to download in parallel. The default value is 5.
|
||||
Concurrency uint16
|
||||
|
||||
// RetryReaderOptionsPerBlock is used when downloading each block.
|
||||
RetryReaderOptionsPerBlock RetryReaderOptions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// DeleteOptions contains the optional parameters for the Client.Delete method.
|
||||
type DeleteOptions struct {
|
||||
// Required if the blob has associated snapshots. Specify one of the following two options: include: Delete the base blob
|
||||
// and all of its snapshots. only: Delete only the blob's snapshots and not the blob itself.
|
||||
DeleteSnapshots *DeleteSnapshotsOptionType
|
||||
AccessConditions *AccessConditions
|
||||
// Setting DeleteType to DeleteTypePermanent will permanently delete soft-delete snapshot and/or version blobs.
|
||||
// WARNING: This is a dangerous operation and should not be used unless you know the implications. Please proceed
|
||||
// with caution.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob
|
||||
BlobDeleteType *DeleteType
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) format() (*generated.BlobClientDeleteOptions, *generated.LeaseAccessConditions, *generated.ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
basics := generated.BlobClientDeleteOptions{
|
||||
DeleteSnapshots: o.DeleteSnapshots,
|
||||
DeleteType: o.BlobDeleteType, // None by default
|
||||
}
|
||||
|
||||
if o.AccessConditions == nil {
|
||||
return &basics, nil, nil
|
||||
}
|
||||
|
||||
return &basics, o.AccessConditions.LeaseAccessConditions, o.AccessConditions.ModifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// UndeleteOptions contains the optional parameters for the Client.Undelete method.
|
||||
type UndeleteOptions struct {
|
||||
// placeholder for future options
|
||||
}
|
||||
|
||||
func (o *UndeleteOptions) format() *generated.BlobClientUndeleteOptions {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// SetTierOptions contains the optional parameters for the Client.SetTier method.
|
||||
type SetTierOptions struct {
|
||||
// Optional: Indicates the priority with which to rehydrate an archived blob.
|
||||
RehydratePriority *RehydratePriority
|
||||
|
||||
AccessConditions *AccessConditions
|
||||
}
|
||||
|
||||
func (o *SetTierOptions) format() (*generated.BlobClientSetTierOptions, *generated.LeaseAccessConditions, *generated.ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return &generated.BlobClientSetTierOptions{RehydratePriority: o.RehydratePriority}, leaseAccessConditions, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// GetPropertiesOptions contains the optional parameters for the Client.GetProperties method
|
||||
type GetPropertiesOptions struct {
|
||||
AccessConditions *AccessConditions
|
||||
CPKInfo *CPKInfo
|
||||
}
|
||||
|
||||
func (o *GetPropertiesOptions) format() (*generated.BlobClientGetPropertiesOptions,
|
||||
*generated.LeaseAccessConditions, *generated.CPKInfo, *generated.ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return nil, leaseAccessConditions, o.CPKInfo, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// SetHTTPHeadersOptions contains the optional parameters for the Client.SetHTTPHeaders method.
|
||||
type SetHTTPHeadersOptions struct {
|
||||
AccessConditions *AccessConditions
|
||||
}
|
||||
|
||||
func (o *SetHTTPHeadersOptions) format() (*generated.BlobClientSetHTTPHeadersOptions, *generated.LeaseAccessConditions, *generated.ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return nil, leaseAccessConditions, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// SetMetadataOptions provides set of configurations for Set Metadata on blob operation
|
||||
type SetMetadataOptions struct {
|
||||
AccessConditions *AccessConditions
|
||||
CPKInfo *CPKInfo
|
||||
CPKScopeInfo *CPKScopeInfo
|
||||
}
|
||||
|
||||
func (o *SetMetadataOptions) format() (*generated.LeaseAccessConditions, *CPKInfo,
|
||||
*CPKScopeInfo, *ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return leaseAccessConditions, o.CPKInfo, o.CPKScopeInfo, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// CreateSnapshotOptions contains the optional parameters for the Client.CreateSnapshot method.
|
||||
type CreateSnapshotOptions struct {
|
||||
Metadata map[string]*string
|
||||
AccessConditions *AccessConditions
|
||||
CPKInfo *CPKInfo
|
||||
CPKScopeInfo *CPKScopeInfo
|
||||
}
|
||||
|
||||
func (o *CreateSnapshotOptions) format() (*generated.BlobClientCreateSnapshotOptions, *generated.CPKInfo,
|
||||
*generated.CPKScopeInfo, *generated.ModifiedAccessConditions, *generated.LeaseAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
|
||||
return &generated.BlobClientCreateSnapshotOptions{
|
||||
Metadata: o.Metadata,
|
||||
}, o.CPKInfo, o.CPKScopeInfo, modifiedAccessConditions, leaseAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// StartCopyFromURLOptions contains the optional parameters for the Client.StartCopyFromURL method.
|
||||
type StartCopyFromURLOptions struct {
|
||||
// Specifies the date time when the blobs immutability policy is set to expire.
|
||||
ImmutabilityPolicyExpiry *time.Time
|
||||
// Specifies the immutability policy mode to set on the blob.
|
||||
ImmutabilityPolicyMode *ImmutabilityPolicySetting
|
||||
// Specified if a legal hold should be set on the blob.
|
||||
LegalHold *bool
|
||||
// Optional. Used to set blob tags in various blob operations.
|
||||
BlobTags map[string]string
|
||||
// Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the
|
||||
// operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs
|
||||
// are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source
|
||||
// blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers.
|
||||
// See Naming and Referencing Containers, Blobs, and Metadata for more information.
|
||||
Metadata map[string]*string
|
||||
// Optional: Indicates the priority with which to rehydrate an archived blob.
|
||||
RehydratePriority *RehydratePriority
|
||||
// Overrides the sealed state of the destination blob. Service version 2019-12-12 and newer.
|
||||
SealBlob *bool
|
||||
// Optional. Indicates the tier to be set on the blob.
|
||||
Tier *AccessTier
|
||||
|
||||
SourceModifiedAccessConditions *SourceModifiedAccessConditions
|
||||
|
||||
AccessConditions *AccessConditions
|
||||
}
|
||||
|
||||
func (o *StartCopyFromURLOptions) format() (*generated.BlobClientStartCopyFromURLOptions,
|
||||
*generated.SourceModifiedAccessConditions, *generated.ModifiedAccessConditions, *generated.LeaseAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
basics := generated.BlobClientStartCopyFromURLOptions{
|
||||
BlobTagsString: shared.SerializeBlobTagsToStrPtr(o.BlobTags),
|
||||
Metadata: o.Metadata,
|
||||
RehydratePriority: o.RehydratePriority,
|
||||
SealBlob: o.SealBlob,
|
||||
Tier: o.Tier,
|
||||
ImmutabilityPolicyExpiry: o.ImmutabilityPolicyExpiry,
|
||||
ImmutabilityPolicyMode: o.ImmutabilityPolicyMode,
|
||||
LegalHold: o.LegalHold,
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return &basics, o.SourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// AbortCopyFromURLOptions contains the optional parameters for the Client.AbortCopyFromURL method.
|
||||
type AbortCopyFromURLOptions struct {
|
||||
LeaseAccessConditions *LeaseAccessConditions
|
||||
}
|
||||
|
||||
func (o *AbortCopyFromURLOptions) format() (*generated.BlobClientAbortCopyFromURLOptions, *generated.LeaseAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, o.LeaseAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// SetTagsOptions contains the optional parameters for the Client.SetTags method.
|
||||
type SetTagsOptions struct {
|
||||
// The version id parameter is an opaque DateTime value that, when present,
|
||||
// specifies the version of the blob to operate on. It's for service version 2019-10-10 and newer.
|
||||
VersionID *string
|
||||
// Optional header, Specifies the transactional crc64 for the body, to be validated by the service.
|
||||
TransactionalContentCRC64 []byte
|
||||
// Optional header, Specifies the transactional md5 for the body, to be validated by the service.
|
||||
TransactionalContentMD5 []byte
|
||||
|
||||
AccessConditions *AccessConditions
|
||||
}
|
||||
|
||||
func (o *SetTagsOptions) format() (*generated.BlobClientSetTagsOptions, *ModifiedAccessConditions, *generated.LeaseAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
options := &generated.BlobClientSetTagsOptions{
|
||||
TransactionalContentMD5: o.TransactionalContentMD5,
|
||||
TransactionalContentCRC64: o.TransactionalContentCRC64,
|
||||
VersionID: o.VersionID,
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return options, modifiedAccessConditions, leaseAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// GetTagsOptions contains the optional parameters for the Client.GetTags method.
|
||||
type GetTagsOptions struct {
|
||||
// The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve.
|
||||
Snapshot *string
|
||||
// The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on.
|
||||
// It's for service version 2019-10-10 and newer.
|
||||
VersionID *string
|
||||
|
||||
BlobAccessConditions *AccessConditions
|
||||
}
|
||||
|
||||
func (o *GetTagsOptions) format() (*generated.BlobClientGetTagsOptions, *generated.ModifiedAccessConditions, *generated.LeaseAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
options := &generated.BlobClientGetTagsOptions{
|
||||
Snapshot: o.Snapshot,
|
||||
VersionID: o.VersionID,
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.BlobAccessConditions)
|
||||
return options, modifiedAccessConditions, leaseAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// SetImmutabilityPolicyOptions contains the parameter for Client.SetImmutabilityPolicy
|
||||
type SetImmutabilityPolicyOptions struct {
|
||||
// Specifies the immutability policy mode to set on the blob. Possible values to set include: "Locked", "Unlocked".
|
||||
// "Mutable" can only be returned by service, don't set to "Mutable". If mode is not set - it will default to Unlocked.
|
||||
Mode *ImmutabilityPolicySetting
|
||||
ModifiedAccessConditions *ModifiedAccessConditions
|
||||
}
|
||||
|
||||
func (o *SetImmutabilityPolicyOptions) format() (*generated.BlobClientSetImmutabilityPolicyOptions, *ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return &generated.BlobClientSetImmutabilityPolicyOptions{}, nil
|
||||
}
|
||||
ac := &exported.BlobAccessConditions{
|
||||
ModifiedAccessConditions: o.ModifiedAccessConditions,
|
||||
}
|
||||
_, modifiedAccessConditions := exported.FormatBlobAccessConditions(ac)
|
||||
|
||||
options := &generated.BlobClientSetImmutabilityPolicyOptions{
|
||||
ImmutabilityPolicyMode: o.Mode,
|
||||
}
|
||||
|
||||
return options, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// DeleteImmutabilityPolicyOptions contains the optional parameters for the Client.DeleteImmutabilityPolicy method.
|
||||
type DeleteImmutabilityPolicyOptions struct {
|
||||
// placeholder for future options
|
||||
}
|
||||
|
||||
func (o *DeleteImmutabilityPolicyOptions) format() *generated.BlobClientDeleteImmutabilityPolicyOptions {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// SetLegalHoldOptions contains the optional parameters for the Client.SetLegalHold method.
|
||||
type SetLegalHoldOptions struct {
|
||||
// placeholder for future options
|
||||
}
|
||||
|
||||
func (o *SetLegalHoldOptions) format() *generated.BlobClientSetLegalHoldOptions {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// GetSASURLOptions contains the optional parameters for the Client.GetSASURL method.
|
||||
type GetSASURLOptions struct {
|
||||
StartTime *time.Time
|
||||
}
|
||||
|
||||
func (o *GetSASURLOptions) format() time.Time {
|
||||
if o == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
var st time.Time
|
||||
if o.StartTime != nil {
|
||||
st = o.StartTime.UTC()
|
||||
} else {
|
||||
st = time.Time{}
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// CopyFromURLOptions contains the optional parameters for the Client.CopyFromURL method.
|
||||
type CopyFromURLOptions struct {
|
||||
// Optional. Used to set blob tags in various blob operations.
|
||||
BlobTags map[string]string
|
||||
// Only Bearer type is supported. Credentials should be a valid OAuth access token to copy source.
|
||||
CopySourceAuthorization *string
|
||||
// Specifies the date time when the blobs immutability policy is set to expire.
|
||||
ImmutabilityPolicyExpiry *time.Time
|
||||
// Specifies the immutability policy mode to set on the blob.
|
||||
ImmutabilityPolicyMode *ImmutabilityPolicySetting
|
||||
// Specified if a legal hold should be set on the blob.
|
||||
LegalHold *bool
|
||||
// Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the
|
||||
// operation will copy the metadata from the source blob or file to the destination
|
||||
// blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata
|
||||
// is not copied from the source blob or file. Note that beginning with
|
||||
// version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers,
|
||||
// Blobs, and Metadata for more information.
|
||||
Metadata map[string]*string
|
||||
// Specify the md5 calculated for the range of bytes that must be read from the copy source.
|
||||
SourceContentMD5 []byte
|
||||
// Optional. Indicates the tier to be set on the blob.
|
||||
Tier *AccessTier
|
||||
|
||||
SourceModifiedAccessConditions *SourceModifiedAccessConditions
|
||||
|
||||
BlobAccessConditions *AccessConditions
|
||||
|
||||
CPKScopeInfo *CPKScopeInfo
|
||||
}
|
||||
|
||||
func (o *CopyFromURLOptions) format() (*generated.BlobClientCopyFromURLOptions, *generated.SourceModifiedAccessConditions, *generated.ModifiedAccessConditions, *generated.LeaseAccessConditions, *generated.CPKScopeInfo) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
options := &generated.BlobClientCopyFromURLOptions{
|
||||
BlobTagsString: shared.SerializeBlobTagsToStrPtr(o.BlobTags),
|
||||
CopySourceAuthorization: o.CopySourceAuthorization,
|
||||
ImmutabilityPolicyExpiry: o.ImmutabilityPolicyExpiry,
|
||||
ImmutabilityPolicyMode: o.ImmutabilityPolicyMode,
|
||||
LegalHold: o.LegalHold,
|
||||
Metadata: o.Metadata,
|
||||
SourceContentMD5: o.SourceContentMD5,
|
||||
Tier: o.Tier,
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.BlobAccessConditions)
|
||||
return options, o.SourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions, o.CPKScopeInfo
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// GetAccountInfoOptions provides set of options for Client.GetAccountInfo
|
||||
type GetAccountInfoOptions struct {
|
||||
// placeholder for future options
|
||||
}
|
||||
|
||||
func (o *GetAccountInfoOptions) format() *generated.BlobClientGetAccountInfoOptions {
|
||||
return nil
|
||||
}
|
||||
119
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/responses.go
generated
vendored
Normal file
119
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/responses.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blob
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
)
|
||||
|
||||
// DownloadResponse contains the response from method BlobClient.Download.
|
||||
type DownloadResponse = generated.BlobClientDownloadResponse
|
||||
|
||||
// DownloadStreamResponse contains the response from the DownloadStream method.
|
||||
// To read from the stream, read from the Body field, or call the NewRetryReader method.
|
||||
type DownloadStreamResponse struct {
|
||||
DownloadResponse
|
||||
ObjectReplicationRules []ObjectReplicationPolicy
|
||||
|
||||
client *Client
|
||||
getInfo httpGetterInfo
|
||||
cpkInfo *CPKInfo
|
||||
cpkScope *CPKScopeInfo
|
||||
}
|
||||
|
||||
// NewRetryReader constructs new RetryReader stream for reading data. If a connection fails while
|
||||
// reading, it will make additional requests to reestablish a connection and continue reading.
|
||||
// Pass nil for options to accept the default options.
|
||||
// Callers of this method should not access the DownloadStreamResponse.Body field.
|
||||
func (r *DownloadStreamResponse) NewRetryReader(ctx context.Context, options *RetryReaderOptions) *RetryReader {
|
||||
if options == nil {
|
||||
options = &RetryReaderOptions{}
|
||||
}
|
||||
|
||||
return newRetryReader(ctx, r.Body, r.getInfo, func(ctx context.Context, getInfo httpGetterInfo) (io.ReadCloser, error) {
|
||||
accessConditions := &AccessConditions{
|
||||
ModifiedAccessConditions: &ModifiedAccessConditions{IfMatch: getInfo.ETag},
|
||||
}
|
||||
options := DownloadStreamOptions{
|
||||
Range: getInfo.Range,
|
||||
AccessConditions: accessConditions,
|
||||
CPKInfo: r.cpkInfo,
|
||||
CPKScopeInfo: r.cpkScope,
|
||||
}
|
||||
resp, err := r.client.DownloadStream(ctx, &options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Body, err
|
||||
}, *options)
|
||||
}
|
||||
|
||||
// DeleteResponse contains the response from method BlobClient.Delete.
|
||||
type DeleteResponse = generated.BlobClientDeleteResponse
|
||||
|
||||
// UndeleteResponse contains the response from method BlobClient.Undelete.
|
||||
type UndeleteResponse = generated.BlobClientUndeleteResponse
|
||||
|
||||
// SetTierResponse contains the response from method BlobClient.SetTier.
|
||||
type SetTierResponse = generated.BlobClientSetTierResponse
|
||||
|
||||
// GetPropertiesResponse contains the response from method BlobClient.GetProperties.
|
||||
type GetPropertiesResponse = generated.BlobClientGetPropertiesResponse
|
||||
|
||||
// SetHTTPHeadersResponse contains the response from method BlobClient.SetHTTPHeaders.
|
||||
type SetHTTPHeadersResponse = generated.BlobClientSetHTTPHeadersResponse
|
||||
|
||||
// SetMetadataResponse contains the response from method BlobClient.SetMetadata.
|
||||
type SetMetadataResponse = generated.BlobClientSetMetadataResponse
|
||||
|
||||
// CreateSnapshotResponse contains the response from method BlobClient.CreateSnapshot.
|
||||
type CreateSnapshotResponse = generated.BlobClientCreateSnapshotResponse
|
||||
|
||||
// StartCopyFromURLResponse contains the response from method BlobClient.StartCopyFromURL.
|
||||
type StartCopyFromURLResponse = generated.BlobClientStartCopyFromURLResponse
|
||||
|
||||
// AbortCopyFromURLResponse contains the response from method BlobClient.AbortCopyFromURL.
|
||||
type AbortCopyFromURLResponse = generated.BlobClientAbortCopyFromURLResponse
|
||||
|
||||
// SetTagsResponse contains the response from method BlobClient.SetTags.
|
||||
type SetTagsResponse = generated.BlobClientSetTagsResponse
|
||||
|
||||
// GetTagsResponse contains the response from method BlobClient.GetTags.
|
||||
type GetTagsResponse = generated.BlobClientGetTagsResponse
|
||||
|
||||
// SetImmutabilityPolicyResponse contains the response from method BlobClient.SetImmutabilityPolicy.
|
||||
type SetImmutabilityPolicyResponse = generated.BlobClientSetImmutabilityPolicyResponse
|
||||
|
||||
// DeleteImmutabilityPolicyResponse contains the response from method BlobClient.DeleteImmutabilityPolicyResponse.
|
||||
type DeleteImmutabilityPolicyResponse = generated.BlobClientDeleteImmutabilityPolicyResponse
|
||||
|
||||
// SetLegalHoldResponse contains the response from method BlobClient.SetLegalHold.
|
||||
type SetLegalHoldResponse = generated.BlobClientSetLegalHoldResponse
|
||||
|
||||
// CopyFromURLResponse contains the response from method BlobClient.CopyFromURL.
|
||||
type CopyFromURLResponse = generated.BlobClientCopyFromURLResponse
|
||||
|
||||
// GetAccountInfoResponse contains the response from method BlobClient.GetAccountInfo.
|
||||
type GetAccountInfoResponse = generated.BlobClientGetAccountInfoResponse
|
||||
|
||||
// AcquireLeaseResponse contains the response from method BlobClient.AcquireLease.
|
||||
type AcquireLeaseResponse = generated.BlobClientAcquireLeaseResponse
|
||||
|
||||
// BreakLeaseResponse contains the response from method BlobClient.BreakLease.
|
||||
type BreakLeaseResponse = generated.BlobClientBreakLeaseResponse
|
||||
|
||||
// ChangeLeaseResponse contains the response from method BlobClient.ChangeLease.
|
||||
type ChangeLeaseResponse = generated.BlobClientChangeLeaseResponse
|
||||
|
||||
// ReleaseLeaseResponse contains the response from method BlobClient.ReleaseLease.
|
||||
type ReleaseLeaseResponse = generated.BlobClientReleaseLeaseResponse
|
||||
|
||||
// RenewLeaseResponse contains the response from method BlobClient.RenewLease.
|
||||
type RenewLeaseResponse = generated.BlobClientRenewLeaseResponse
|
||||
191
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/retry_reader.go
generated
vendored
Normal file
191
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/retry_reader.go
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blob
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
)
|
||||
|
||||
// HTTPGetter is a function type that refers to a method that performs an HTTP GET operation.
|
||||
type httpGetter func(ctx context.Context, i httpGetterInfo) (io.ReadCloser, error)
|
||||
|
||||
// HTTPGetterInfo is passed to an HTTPGetter function passing it parameters
|
||||
// that should be used to make an HTTP GET request.
|
||||
type httpGetterInfo struct {
|
||||
Range HTTPRange
|
||||
|
||||
// ETag specifies the resource's etag that should be used when creating
|
||||
// the HTTP GET request's If-Match header
|
||||
ETag *azcore.ETag
|
||||
}
|
||||
|
||||
// RetryReaderOptions configures the retry reader's behavior.
|
||||
// Zero-value fields will have their specified default values applied during use.
|
||||
// This allows for modification of a subset of fields.
|
||||
type RetryReaderOptions struct {
|
||||
// MaxRetries specifies the maximum number of attempts a failed read will be retried
|
||||
// before producing an error.
|
||||
// The default value is three.
|
||||
MaxRetries int32
|
||||
|
||||
// OnFailedRead, when non-nil, is called after any failure to read. Expected usage is diagnostic logging.
|
||||
OnFailedRead func(failureCount int32, lastError error, rnge HTTPRange, willRetry bool)
|
||||
|
||||
// EarlyCloseAsError can be set to true to prevent retries after "read on closed response body". By default,
|
||||
// retryReader has the following special behaviour: closing the response body before it is all read is treated as a
|
||||
// retryable error. This is to allow callers to force a retry by closing the body from another goroutine (e.g. if the =
|
||||
// read is too slow, caller may want to force a retry in the hope that the retry will be quicker). If
|
||||
// TreatEarlyCloseAsError is true, then retryReader's special behaviour is suppressed, and "read on closed body" is instead
|
||||
// treated as a fatal (non-retryable) error.
|
||||
// Note that setting TreatEarlyCloseAsError only guarantees that Closing will produce a fatal error if the Close happens
|
||||
// from the same "thread" (goroutine) as Read. Concurrent Close calls from other goroutines may instead produce network errors
|
||||
// which will be retried.
|
||||
// The default value is false.
|
||||
EarlyCloseAsError bool
|
||||
|
||||
doInjectError bool
|
||||
doInjectErrorRound int32
|
||||
injectedError error
|
||||
}
|
||||
|
||||
// RetryReader attempts to read from response, and if there is a retry-able network error
|
||||
// returned during reading, it will retry according to retry reader option through executing
|
||||
// user defined action with provided data to get a new response, and continue the overall reading process
|
||||
// through reading from the new response.
|
||||
// RetryReader implements the io.ReadCloser interface.
|
||||
type RetryReader struct {
|
||||
ctx context.Context
|
||||
info httpGetterInfo
|
||||
retryReaderOptions RetryReaderOptions
|
||||
getter httpGetter
|
||||
countWasBounded bool
|
||||
|
||||
// we support Close-ing during Reads (from other goroutines), so we protect the shared state, which is response
|
||||
responseMu *sync.Mutex
|
||||
response io.ReadCloser
|
||||
}
|
||||
|
||||
// newRetryReader creates a retry reader.
|
||||
func newRetryReader(ctx context.Context, initialResponse io.ReadCloser, info httpGetterInfo, getter httpGetter, o RetryReaderOptions) *RetryReader {
|
||||
if o.MaxRetries < 1 {
|
||||
o.MaxRetries = 3
|
||||
}
|
||||
return &RetryReader{
|
||||
ctx: ctx,
|
||||
getter: getter,
|
||||
info: info,
|
||||
countWasBounded: info.Range.Count != CountToEnd,
|
||||
response: initialResponse,
|
||||
responseMu: &sync.Mutex{},
|
||||
retryReaderOptions: o,
|
||||
}
|
||||
}
|
||||
|
||||
// setResponse function
|
||||
func (s *RetryReader) setResponse(r io.ReadCloser) {
|
||||
s.responseMu.Lock()
|
||||
defer s.responseMu.Unlock()
|
||||
s.response = r
|
||||
}
|
||||
|
||||
// Read from retry reader
|
||||
func (s *RetryReader) Read(p []byte) (n int, err error) {
|
||||
for try := int32(0); ; try++ {
|
||||
if s.countWasBounded && s.info.Range.Count == CountToEnd {
|
||||
// User specified an original count and the remaining bytes are 0, return 0, EOF
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
s.responseMu.Lock()
|
||||
resp := s.response
|
||||
s.responseMu.Unlock()
|
||||
if resp == nil { // We don't have a response stream to read from, try to get one.
|
||||
newResponse, err := s.getter(s.ctx, s.info)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Successful GET; this is the network stream we'll read from.
|
||||
s.setResponse(newResponse)
|
||||
resp = newResponse
|
||||
}
|
||||
n, err := resp.Read(p) // Read from the stream (this will return non-nil err if forceRetry is called, from another goroutine, while it is running)
|
||||
|
||||
// Injection mechanism for testing.
|
||||
if s.retryReaderOptions.doInjectError && try == s.retryReaderOptions.doInjectErrorRound {
|
||||
if s.retryReaderOptions.injectedError != nil {
|
||||
err = s.retryReaderOptions.injectedError
|
||||
} else {
|
||||
err = &net.DNSError{IsTemporary: true}
|
||||
}
|
||||
}
|
||||
|
||||
// We successfully read data or end EOF.
|
||||
if err == nil || err == io.EOF {
|
||||
s.info.Range.Offset += int64(n) // Increments the start offset in case we need to make a new HTTP request in the future
|
||||
if s.info.Range.Count != CountToEnd {
|
||||
s.info.Range.Count -= int64(n) // Decrement the count in case we need to make a new HTTP request in the future
|
||||
}
|
||||
return n, err // Return the return to the caller
|
||||
}
|
||||
_ = s.Close()
|
||||
|
||||
s.setResponse(nil) // Our stream is no longer good
|
||||
|
||||
// Check the retry count and error code, and decide whether to retry.
|
||||
retriesExhausted := try >= s.retryReaderOptions.MaxRetries
|
||||
_, isNetError := err.(net.Error)
|
||||
isUnexpectedEOF := err == io.ErrUnexpectedEOF
|
||||
willRetry := (isNetError || isUnexpectedEOF || s.wasRetryableEarlyClose(err)) && !retriesExhausted
|
||||
|
||||
// Notify, for logging purposes, of any failures
|
||||
if s.retryReaderOptions.OnFailedRead != nil {
|
||||
failureCount := try + 1 // because try is zero-based
|
||||
s.retryReaderOptions.OnFailedRead(failureCount, err, s.info.Range, willRetry)
|
||||
}
|
||||
|
||||
if willRetry {
|
||||
continue
|
||||
// Loop around and try to get and read from new stream.
|
||||
}
|
||||
return n, err // Not retryable, or retries exhausted, so just return
|
||||
}
|
||||
}
|
||||
|
||||
// By default, we allow early Closing, from another concurrent goroutine, to be used to force a retry
|
||||
// Is this safe, to close early from another goroutine? Early close ultimately ends up calling
|
||||
// net.Conn.Close, and that is documented as "Any blocked Read or Write operations will be unblocked and return errors"
|
||||
// which is exactly the behaviour we want.
|
||||
// NOTE: that if caller has forced an early Close from a separate goroutine (separate from the Read)
|
||||
// then there are two different types of error that may happen - either the one we check for here,
|
||||
// or a net.Error (due to closure of connection). Which one happens depends on timing. We only need this routine
|
||||
// to check for one, since the other is a net.Error, which our main Read retry loop is already handing.
|
||||
func (s *RetryReader) wasRetryableEarlyClose(err error) bool {
|
||||
if s.retryReaderOptions.EarlyCloseAsError {
|
||||
return false // user wants all early closes to be errors, and so not retryable
|
||||
}
|
||||
// unfortunately, http.errReadOnClosedResBody is private, so the best we can do here is to check for its text
|
||||
return strings.HasSuffix(err.Error(), ReadOnClosedBodyMessage)
|
||||
}
|
||||
|
||||
// ReadOnClosedBodyMessage of retry reader
|
||||
const ReadOnClosedBodyMessage = "read on closed response body"
|
||||
|
||||
// Close retry reader
|
||||
func (s *RetryReader) Close() error {
|
||||
s.responseMu.Lock()
|
||||
defer s.responseMu.Unlock()
|
||||
if s.response != nil {
|
||||
return s.response.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
79
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/utils.go
generated
vendored
Normal file
79
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob/utils.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blob
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
|
||||
)
|
||||
|
||||
// ObjectReplicationRules struct
|
||||
type ObjectReplicationRules struct {
|
||||
RuleID string
|
||||
Status string
|
||||
}
|
||||
|
||||
// ObjectReplicationPolicy are deserialized attributes.
|
||||
type ObjectReplicationPolicy struct {
|
||||
PolicyID *string
|
||||
Rules *[]ObjectReplicationRules
|
||||
}
|
||||
|
||||
// deserializeORSPolicies is utility function to deserialize ORS Policies.
|
||||
func deserializeORSPolicies(policies map[string]*string) (objectReplicationPolicies []ObjectReplicationPolicy) {
|
||||
if policies == nil {
|
||||
return nil
|
||||
}
|
||||
// For source blobs (blobs that have policy ids and rule ids applied to them),
|
||||
// the header will be formatted as "x-ms-or-<policy_id>_<rule_id>: {Complete, Failed}".
|
||||
// The value of this header is the status of the replication.
|
||||
orPolicyStatusHeader := make(map[string]*string)
|
||||
for key, value := range policies {
|
||||
if strings.Contains(key, "or-") && key != "x-ms-or-policy-id" {
|
||||
orPolicyStatusHeader[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
parsedResult := make(map[string][]ObjectReplicationRules)
|
||||
for key, value := range orPolicyStatusHeader {
|
||||
policyAndRuleIDs := strings.Split(strings.Split(key, "or-")[1], "_")
|
||||
policyId, ruleId := policyAndRuleIDs[0], policyAndRuleIDs[1]
|
||||
|
||||
parsedResult[policyId] = append(parsedResult[policyId], ObjectReplicationRules{RuleID: ruleId, Status: *value})
|
||||
}
|
||||
|
||||
for policyId, rules := range parsedResult {
|
||||
objectReplicationPolicies = append(objectReplicationPolicies, ObjectReplicationPolicy{
|
||||
PolicyID: &policyId,
|
||||
Rules: &rules,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ParseHTTPHeaders parses GetPropertiesResponse and returns HTTPHeaders.
|
||||
func ParseHTTPHeaders(resp GetPropertiesResponse) HTTPHeaders {
|
||||
return HTTPHeaders{
|
||||
BlobContentType: resp.ContentType,
|
||||
BlobContentEncoding: resp.ContentEncoding,
|
||||
BlobContentLanguage: resp.ContentLanguage,
|
||||
BlobContentDisposition: resp.ContentDisposition,
|
||||
BlobCacheControl: resp.CacheControl,
|
||||
BlobContentMD5: resp.ContentMD5,
|
||||
}
|
||||
}
|
||||
|
||||
// URLParts object represents the components that make up an Azure Storage Container/Blob URL.
|
||||
// NOTE: Changing any SAS-related field requires computing a new SAS signature.
|
||||
type URLParts = sas.URLParts
|
||||
|
||||
// ParseURL parses a URL initializing URLParts' fields including any SAS-related & snapshot query parameters. Any other
|
||||
// query parameters remain in the UnparsedParams field. This method overwrites all fields in the URLParts object.
|
||||
func ParseURL(u string) (URLParts, error) {
|
||||
return sas.ParseURL(u)
|
||||
}
|
||||
159
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror/error_codes.go
generated
vendored
Normal file
159
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror/error_codes.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package bloberror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
)
|
||||
|
||||
// HasCode returns true if the provided error is an *azcore.ResponseError
|
||||
// with its ErrorCode field equal to one of the specified Codes.
|
||||
func HasCode(err error, codes ...Code) bool {
|
||||
var respErr *azcore.ResponseError
|
||||
if !errors.As(err, &respErr) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, code := range codes {
|
||||
if respErr.ErrorCode == string(code) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Code - Error codes returned by the service
|
||||
type Code = generated.StorageErrorCode
|
||||
|
||||
const (
|
||||
AccountAlreadyExists Code = "AccountAlreadyExists"
|
||||
AccountBeingCreated Code = "AccountBeingCreated"
|
||||
AccountIsDisabled Code = "AccountIsDisabled"
|
||||
AppendPositionConditionNotMet Code = "AppendPositionConditionNotMet"
|
||||
AuthenticationFailed Code = "AuthenticationFailed"
|
||||
AuthorizationFailure Code = "AuthorizationFailure"
|
||||
AuthorizationPermissionMismatch Code = "AuthorizationPermissionMismatch"
|
||||
AuthorizationProtocolMismatch Code = "AuthorizationProtocolMismatch"
|
||||
AuthorizationResourceTypeMismatch Code = "AuthorizationResourceTypeMismatch"
|
||||
AuthorizationServiceMismatch Code = "AuthorizationServiceMismatch"
|
||||
AuthorizationSourceIPMismatch Code = "AuthorizationSourceIPMismatch"
|
||||
BlobAlreadyExists Code = "BlobAlreadyExists"
|
||||
BlobArchived Code = "BlobArchived"
|
||||
BlobBeingRehydrated Code = "BlobBeingRehydrated"
|
||||
BlobImmutableDueToPolicy Code = "BlobImmutableDueToPolicy"
|
||||
BlobNotArchived Code = "BlobNotArchived"
|
||||
BlobNotFound Code = "BlobNotFound"
|
||||
BlobOverwritten Code = "BlobOverwritten"
|
||||
BlobTierInadequateForContentLength Code = "BlobTierInadequateForContentLength"
|
||||
BlobUsesCustomerSpecifiedEncryption Code = "BlobUsesCustomerSpecifiedEncryption"
|
||||
BlockCountExceedsLimit Code = "BlockCountExceedsLimit"
|
||||
BlockListTooLong Code = "BlockListTooLong"
|
||||
CannotChangeToLowerTier Code = "CannotChangeToLowerTier"
|
||||
CannotVerifyCopySource Code = "CannotVerifyCopySource"
|
||||
ConditionHeadersNotSupported Code = "ConditionHeadersNotSupported"
|
||||
ConditionNotMet Code = "ConditionNotMet"
|
||||
ContainerAlreadyExists Code = "ContainerAlreadyExists"
|
||||
ContainerBeingDeleted Code = "ContainerBeingDeleted"
|
||||
ContainerDisabled Code = "ContainerDisabled"
|
||||
ContainerNotFound Code = "ContainerNotFound"
|
||||
ContentLengthLargerThanTierLimit Code = "ContentLengthLargerThanTierLimit"
|
||||
CopyAcrossAccountsNotSupported Code = "CopyAcrossAccountsNotSupported"
|
||||
CopyIDMismatch Code = "CopyIdMismatch"
|
||||
EmptyMetadataKey Code = "EmptyMetadataKey"
|
||||
FeatureVersionMismatch Code = "FeatureVersionMismatch"
|
||||
ImmutabilityPolicyDeleteOnLockedPolicy Code = "ImmutabilityPolicyDeleteOnLockedPolicy"
|
||||
IncrementalCopyBlobMismatch Code = "IncrementalCopyBlobMismatch"
|
||||
IncrementalCopyOfEralierVersionSnapshotNotAllowed Code = "IncrementalCopyOfEralierVersionSnapshotNotAllowed"
|
||||
IncrementalCopySourceMustBeSnapshot Code = "IncrementalCopySourceMustBeSnapshot"
|
||||
InfiniteLeaseDurationRequired Code = "InfiniteLeaseDurationRequired"
|
||||
InsufficientAccountPermissions Code = "InsufficientAccountPermissions"
|
||||
InternalError Code = "InternalError"
|
||||
InvalidAuthenticationInfo Code = "InvalidAuthenticationInfo"
|
||||
InvalidBlobOrBlock Code = "InvalidBlobOrBlock"
|
||||
InvalidBlobTier Code = "InvalidBlobTier"
|
||||
InvalidBlobType Code = "InvalidBlobType"
|
||||
InvalidBlockID Code = "InvalidBlockId"
|
||||
InvalidBlockList Code = "InvalidBlockList"
|
||||
InvalidHTTPVerb Code = "InvalidHttpVerb"
|
||||
InvalidHeaderValue Code = "InvalidHeaderValue"
|
||||
InvalidInput Code = "InvalidInput"
|
||||
InvalidMD5 Code = "InvalidMd5"
|
||||
InvalidMetadata Code = "InvalidMetadata"
|
||||
InvalidOperation Code = "InvalidOperation"
|
||||
InvalidPageRange Code = "InvalidPageRange"
|
||||
InvalidQueryParameterValue Code = "InvalidQueryParameterValue"
|
||||
InvalidRange Code = "InvalidRange"
|
||||
InvalidResourceName Code = "InvalidResourceName"
|
||||
InvalidSourceBlobType Code = "InvalidSourceBlobType"
|
||||
InvalidSourceBlobURL Code = "InvalidSourceBlobUrl"
|
||||
InvalidURI Code = "InvalidUri"
|
||||
InvalidVersionForPageBlobOperation Code = "InvalidVersionForPageBlobOperation"
|
||||
InvalidXMLDocument Code = "InvalidXmlDocument"
|
||||
InvalidXMLNodeValue Code = "InvalidXmlNodeValue"
|
||||
LeaseAlreadyBroken Code = "LeaseAlreadyBroken"
|
||||
LeaseAlreadyPresent Code = "LeaseAlreadyPresent"
|
||||
LeaseIDMismatchWithBlobOperation Code = "LeaseIdMismatchWithBlobOperation"
|
||||
LeaseIDMismatchWithContainerOperation Code = "LeaseIdMismatchWithContainerOperation"
|
||||
LeaseIDMismatchWithLeaseOperation Code = "LeaseIdMismatchWithLeaseOperation"
|
||||
LeaseIDMissing Code = "LeaseIdMissing"
|
||||
LeaseIsBreakingAndCannotBeAcquired Code = "LeaseIsBreakingAndCannotBeAcquired"
|
||||
LeaseIsBreakingAndCannotBeChanged Code = "LeaseIsBreakingAndCannotBeChanged"
|
||||
LeaseIsBrokenAndCannotBeRenewed Code = "LeaseIsBrokenAndCannotBeRenewed"
|
||||
LeaseLost Code = "LeaseLost"
|
||||
LeaseNotPresentWithBlobOperation Code = "LeaseNotPresentWithBlobOperation"
|
||||
LeaseNotPresentWithContainerOperation Code = "LeaseNotPresentWithContainerOperation"
|
||||
LeaseNotPresentWithLeaseOperation Code = "LeaseNotPresentWithLeaseOperation"
|
||||
MD5Mismatch Code = "Md5Mismatch"
|
||||
CRC64Mismatch Code = "Crc64Mismatch"
|
||||
MaxBlobSizeConditionNotMet Code = "MaxBlobSizeConditionNotMet"
|
||||
MetadataTooLarge Code = "MetadataTooLarge"
|
||||
MissingContentLengthHeader Code = "MissingContentLengthHeader"
|
||||
MissingRequiredHeader Code = "MissingRequiredHeader"
|
||||
MissingRequiredQueryParameter Code = "MissingRequiredQueryParameter"
|
||||
MissingRequiredXMLNode Code = "MissingRequiredXmlNode"
|
||||
MultipleConditionHeadersNotSupported Code = "MultipleConditionHeadersNotSupported"
|
||||
NoAuthenticationInformation Code = "NoAuthenticationInformation"
|
||||
NoPendingCopyOperation Code = "NoPendingCopyOperation"
|
||||
OperationNotAllowedOnIncrementalCopyBlob Code = "OperationNotAllowedOnIncrementalCopyBlob"
|
||||
OperationNotAllowedOnRootBlob Code = "OperationNotAllowedOnRootBlob"
|
||||
OperationTimedOut Code = "OperationTimedOut"
|
||||
OutOfRangeInput Code = "OutOfRangeInput"
|
||||
OutOfRangeQueryParameterValue Code = "OutOfRangeQueryParameterValue"
|
||||
PendingCopyOperation Code = "PendingCopyOperation"
|
||||
PreviousSnapshotCannotBeNewer Code = "PreviousSnapshotCannotBeNewer"
|
||||
PreviousSnapshotNotFound Code = "PreviousSnapshotNotFound"
|
||||
PreviousSnapshotOperationNotSupported Code = "PreviousSnapshotOperationNotSupported"
|
||||
RequestBodyTooLarge Code = "RequestBodyTooLarge"
|
||||
RequestURLFailedToParse Code = "RequestUrlFailedToParse"
|
||||
ResourceAlreadyExists Code = "ResourceAlreadyExists"
|
||||
ResourceNotFound Code = "ResourceNotFound"
|
||||
ResourceTypeMismatch Code = "ResourceTypeMismatch"
|
||||
SequenceNumberConditionNotMet Code = "SequenceNumberConditionNotMet"
|
||||
SequenceNumberIncrementTooLarge Code = "SequenceNumberIncrementTooLarge"
|
||||
ServerBusy Code = "ServerBusy"
|
||||
SnapshotCountExceeded Code = "SnapshotCountExceeded"
|
||||
SnapshotOperationRateExceeded Code = "SnapshotOperationRateExceeded"
|
||||
SnapshotsPresent Code = "SnapshotsPresent"
|
||||
SourceConditionNotMet Code = "SourceConditionNotMet"
|
||||
SystemInUse Code = "SystemInUse"
|
||||
TargetConditionNotMet Code = "TargetConditionNotMet"
|
||||
UnauthorizedBlobOverwrite Code = "UnauthorizedBlobOverwrite"
|
||||
UnsupportedHTTPVerb Code = "UnsupportedHttpVerb"
|
||||
UnsupportedHeader Code = "UnsupportedHeader"
|
||||
UnsupportedQueryParameter Code = "UnsupportedQueryParameter"
|
||||
UnsupportedXMLNode Code = "UnsupportedXmlNode"
|
||||
)
|
||||
|
||||
var (
|
||||
// MissingSharedKeyCredential - Error is returned when SAS URL is being created without SharedKeyCredential.
|
||||
MissingSharedKeyCredential = errors.New("SAS can only be signed with a SharedKeyCredential")
|
||||
UnsupportedChecksum = errors.New("for multi-part uploads, user generated checksums cannot be validated")
|
||||
)
|
||||
249
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/chunkwriting.go
generated
vendored
Normal file
249
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/chunkwriting.go
generated
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blockblob
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/uuid"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
)
|
||||
|
||||
// blockWriter provides methods to upload blocks that represent a file to a server and commit them.
|
||||
// This allows us to provide a local implementation that fakes the server for hermetic testing.
|
||||
type blockWriter interface {
|
||||
StageBlock(context.Context, string, io.ReadSeekCloser, *StageBlockOptions) (StageBlockResponse, error)
|
||||
Upload(context.Context, io.ReadSeekCloser, *UploadOptions) (UploadResponse, error)
|
||||
CommitBlockList(context.Context, []string, *CommitBlockListOptions) (CommitBlockListResponse, error)
|
||||
}
|
||||
|
||||
// copyFromReader copies a source io.Reader to blob storage using concurrent uploads.
|
||||
func copyFromReader[T ~[]byte](ctx context.Context, src io.Reader, dst blockWriter, options UploadStreamOptions, getBufferManager func(maxBuffers int, bufferSize int64) shared.BufferManager[T]) (CommitBlockListResponse, error) {
|
||||
options.setDefaults()
|
||||
|
||||
wg := sync.WaitGroup{} // Used to know when all outgoing blocks have finished processing
|
||||
errCh := make(chan error, 1) // contains the first error encountered during processing
|
||||
|
||||
buffers := getBufferManager(options.Concurrency, options.BlockSize)
|
||||
defer buffers.Free()
|
||||
|
||||
// this controls the lifetime of the uploading goroutines.
|
||||
// if an error is encountered, cancel() is called which will terminate all uploads.
|
||||
// NOTE: the ordering is important here. cancel MUST execute before
|
||||
// cleaning up the buffers so that any uploading goroutines exit first,
|
||||
// releasing their buffers back to the pool for cleanup.
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
// all blocks have IDs that start with a random UUID
|
||||
blockIDPrefix, err := uuid.New()
|
||||
if err != nil {
|
||||
return CommitBlockListResponse{}, err
|
||||
}
|
||||
tracker := blockTracker{
|
||||
blockIDPrefix: blockIDPrefix,
|
||||
options: options,
|
||||
}
|
||||
|
||||
// This goroutine grabs a buffer, reads from the stream into the buffer,
|
||||
// then creates a goroutine to upload/stage the block.
|
||||
for blockNum := uint32(0); true; blockNum++ {
|
||||
var buffer T
|
||||
select {
|
||||
case buffer = <-buffers.Acquire():
|
||||
// got a buffer
|
||||
default:
|
||||
// no buffer available; allocate a new buffer if possible
|
||||
if _, err := buffers.Grow(); err != nil {
|
||||
return CommitBlockListResponse{}, err
|
||||
}
|
||||
|
||||
// either grab the newly allocated buffer or wait for one to become available
|
||||
buffer = <-buffers.Acquire()
|
||||
}
|
||||
|
||||
var n int
|
||||
n, err = shared.ReadAtLeast(src, buffer, len(buffer))
|
||||
|
||||
if n > 0 {
|
||||
// some data was read, upload it
|
||||
wg.Add(1) // We're posting a buffer to be sent
|
||||
|
||||
// NOTE: we must pass blockNum as an arg to our goroutine else
|
||||
// it's captured by reference and can change underneath us!
|
||||
go func(blockNum uint32) {
|
||||
// Upload the outgoing block, matching the number of bytes read
|
||||
err := tracker.uploadBlock(ctx, dst, blockNum, buffer[:n])
|
||||
if err != nil {
|
||||
select {
|
||||
case errCh <- err:
|
||||
// error was set
|
||||
default:
|
||||
// some other error is already set
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
buffers.Release(buffer) // The goroutine reading from the stream can reuse this buffer now
|
||||
|
||||
// signal that the block has been staged.
|
||||
// we MUST do this after attempting to write to errCh
|
||||
// to avoid it racing with the reading goroutine.
|
||||
wg.Done()
|
||||
}(blockNum)
|
||||
} else {
|
||||
// nothing was read so the buffer is empty, send it back for reuse/clean-up.
|
||||
buffers.Release(buffer)
|
||||
}
|
||||
|
||||
if err != nil { // The reader is done, no more outgoing buffers
|
||||
if errors.Is(err, io.EOF) {
|
||||
// these are expected errors, we don't surface those
|
||||
err = nil
|
||||
} else {
|
||||
// some other error happened, terminate any outstanding uploads
|
||||
cancel()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait() // Wait for all outgoing blocks to complete
|
||||
|
||||
if err != nil {
|
||||
// there was an error reading from src, favor this error over any error during staging
|
||||
return CommitBlockListResponse{}, err
|
||||
}
|
||||
|
||||
select {
|
||||
case err = <-errCh:
|
||||
// there was an error during staging
|
||||
return CommitBlockListResponse{}, err
|
||||
default:
|
||||
// no error was encountered
|
||||
}
|
||||
|
||||
// If no error, after all blocks uploaded, commit them to the blob & return the result
|
||||
return tracker.commitBlocks(ctx, dst)
|
||||
}
|
||||
|
||||
// used to manage the uploading and committing of blocks
|
||||
type blockTracker struct {
|
||||
blockIDPrefix uuid.UUID // UUID used with all blockIDs
|
||||
maxBlockNum uint32 // defaults to 0
|
||||
firstBlock []byte // Used only if maxBlockNum is 0
|
||||
options UploadStreamOptions
|
||||
}
|
||||
|
||||
func (bt *blockTracker) uploadBlock(ctx context.Context, to blockWriter, num uint32, buffer []byte) error {
|
||||
if num == 0 {
|
||||
bt.firstBlock = buffer
|
||||
|
||||
// If whole payload fits in 1 block, don't stage it; End will upload it with 1 I/O operation
|
||||
// If the payload is exactly the same size as the buffer, there may be more content coming in.
|
||||
if len(buffer) < int(bt.options.BlockSize) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
// Else, upload a staged block...
|
||||
atomicMorphUint32(&bt.maxBlockNum, func(startVal uint32) (val uint32, morphResult uint32) {
|
||||
// Atomically remember (in t.numBlocks) the maximum block num we've ever seen
|
||||
if startVal < num {
|
||||
return num, 0
|
||||
}
|
||||
return startVal, 0
|
||||
})
|
||||
}
|
||||
|
||||
blockID := newUUIDBlockID(bt.blockIDPrefix).WithBlockNumber(num).ToBase64()
|
||||
_, err := to.StageBlock(ctx, blockID, streaming.NopCloser(bytes.NewReader(buffer)), bt.options.getStageBlockOptions())
|
||||
return err
|
||||
}
|
||||
|
||||
func (bt *blockTracker) commitBlocks(ctx context.Context, to blockWriter) (CommitBlockListResponse, error) {
|
||||
// If the first block had the exact same size as the buffer
|
||||
// we would have staged it as a block thinking that there might be more data coming
|
||||
if bt.maxBlockNum == 0 && len(bt.firstBlock) < int(bt.options.BlockSize) {
|
||||
// If whole payload fits in 1 block (block #0), upload it with 1 I/O operation
|
||||
up, err := to.Upload(ctx, streaming.NopCloser(bytes.NewReader(bt.firstBlock)), bt.options.getUploadOptions())
|
||||
if err != nil {
|
||||
return CommitBlockListResponse{}, err
|
||||
}
|
||||
|
||||
// convert UploadResponse to CommitBlockListResponse
|
||||
return CommitBlockListResponse{
|
||||
ClientRequestID: up.ClientRequestID,
|
||||
ContentMD5: up.ContentMD5,
|
||||
Date: up.Date,
|
||||
ETag: up.ETag,
|
||||
EncryptionKeySHA256: up.EncryptionKeySHA256,
|
||||
EncryptionScope: up.EncryptionScope,
|
||||
IsServerEncrypted: up.IsServerEncrypted,
|
||||
LastModified: up.LastModified,
|
||||
RequestID: up.RequestID,
|
||||
Version: up.Version,
|
||||
VersionID: up.VersionID,
|
||||
//ContentCRC64: up.ContentCRC64, doesn't exist on UploadResponse
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Multiple blocks staged, commit them all now
|
||||
blockID := newUUIDBlockID(bt.blockIDPrefix)
|
||||
blockIDs := make([]string, bt.maxBlockNum+1)
|
||||
for bn := uint32(0); bn < bt.maxBlockNum+1; bn++ {
|
||||
blockIDs[bn] = blockID.WithBlockNumber(bn).ToBase64()
|
||||
}
|
||||
|
||||
return to.CommitBlockList(ctx, blockIDs, bt.options.getCommitBlockListOptions())
|
||||
}
|
||||
|
||||
// AtomicMorpherUint32 identifies a method passed to and invoked by the AtomicMorph function.
|
||||
// The AtomicMorpher callback is passed a startValue and based on this value it returns
|
||||
// what the new value should be and the result that AtomicMorph should return to its caller.
|
||||
type atomicMorpherUint32 func(startVal uint32) (val uint32, morphResult uint32)
|
||||
|
||||
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
|
||||
func atomicMorphUint32(target *uint32, morpher atomicMorpherUint32) uint32 {
|
||||
for {
|
||||
currentVal := atomic.LoadUint32(target)
|
||||
desiredVal, morphResult := morpher(currentVal)
|
||||
if atomic.CompareAndSwapUint32(target, currentVal, desiredVal) {
|
||||
return morphResult
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type blockID [64]byte
|
||||
|
||||
func (blockID blockID) ToBase64() string {
|
||||
return base64.StdEncoding.EncodeToString(blockID[:])
|
||||
}
|
||||
|
||||
type uuidBlockID blockID
|
||||
|
||||
func newUUIDBlockID(u uuid.UUID) uuidBlockID {
|
||||
ubi := uuidBlockID{} // Create a new uuidBlockID
|
||||
copy(ubi[:len(u)], u[:]) // Copy the specified UUID into it
|
||||
// Block number defaults to 0
|
||||
return ubi
|
||||
}
|
||||
|
||||
func (ubi uuidBlockID) WithBlockNumber(blockNumber uint32) uuidBlockID {
|
||||
binary.BigEndian.PutUint32(ubi[len(uuid.UUID{}):], blockNumber) // Put block number after UUID
|
||||
return ubi // Return the passed-in copy
|
||||
}
|
||||
|
||||
func (ubi uuidBlockID) ToBase64() string {
|
||||
return blockID(ubi).ToBase64()
|
||||
}
|
||||
597
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/client.go
generated
vendored
Normal file
597
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/client.go
generated
vendored
Normal file
@@ -0,0 +1,597 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blockblob
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/uuid"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
|
||||
)
|
||||
|
||||
// ClientOptions contains the optional parameters when creating a Client.
|
||||
type ClientOptions base.ClientOptions
|
||||
|
||||
// Client defines a set of operations applicable to block blobs.
|
||||
type Client base.CompositeClient[generated.BlobClient, generated.BlockBlobClient]
|
||||
|
||||
// NewClient creates an instance of Client with the specified values.
|
||||
// - blobURL - the URL of the blob e.g. https://<account>.blob.core.windows.net/container/blob.txt
|
||||
// - cred - an Azure AD credential, typically obtained via the azidentity module
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
|
||||
audience := base.GetAudience((*base.ClientOptions)(options))
|
||||
conOptions := shared.GetClientOptions(options)
|
||||
authPolicy := shared.NewStorageChallengePolicy(cred, audience, conOptions.InsecureAllowCredentialWithHTTP)
|
||||
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
|
||||
|
||||
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*Client)(base.NewBlockBlobClient(blobURL, azClient, nil)), nil
|
||||
}
|
||||
|
||||
// NewClientWithNoCredential creates an instance of Client with the specified values.
|
||||
// This is used to anonymously access a blob or with a shared access signature (SAS) token.
|
||||
// - blobURL - the URL of the blob e.g. https://<account>.blob.core.windows.net/container/blob.txt?<sas token>
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClientWithNoCredential(blobURL string, options *ClientOptions) (*Client, error) {
|
||||
conOptions := shared.GetClientOptions(options)
|
||||
|
||||
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return (*Client)(base.NewBlockBlobClient(blobURL, azClient, nil)), nil
|
||||
}
|
||||
|
||||
// NewClientWithSharedKeyCredential creates an instance of Client with the specified values.
|
||||
// - blobURL - the URL of the blob e.g. https://<account>.blob.core.windows.net/container/blob.txt
|
||||
// - cred - a SharedKeyCredential created with the matching blob's storage account and access key
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClientWithSharedKeyCredential(blobURL string, cred *blob.SharedKeyCredential, options *ClientOptions) (*Client, error) {
|
||||
authPolicy := exported.NewSharedKeyCredPolicy(cred)
|
||||
conOptions := shared.GetClientOptions(options)
|
||||
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}
|
||||
|
||||
azClient, err := azcore.NewClient(exported.ModuleName, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return (*Client)(base.NewBlockBlobClient(blobURL, azClient, cred)), nil
|
||||
}
|
||||
|
||||
// NewClientFromConnectionString creates an instance of Client with the specified values.
|
||||
// - connectionString - a connection string for the desired storage account
|
||||
// - containerName - the name of the container within the storage account
|
||||
// - blobName - the name of the blob within the container
|
||||
// - options - client options; pass nil to accept the default values
|
||||
func NewClientFromConnectionString(connectionString, containerName, blobName string, options *ClientOptions) (*Client, error) {
|
||||
parsed, err := shared.ParseConnectionString(connectionString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsed.ServiceURL = runtime.JoinPaths(parsed.ServiceURL, containerName, blobName)
|
||||
|
||||
if parsed.AccountKey != "" && parsed.AccountName != "" {
|
||||
credential, err := exported.NewSharedKeyCredential(parsed.AccountName, parsed.AccountKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewClientWithSharedKeyCredential(parsed.ServiceURL, credential, options)
|
||||
}
|
||||
|
||||
return NewClientWithNoCredential(parsed.ServiceURL, options)
|
||||
}
|
||||
|
||||
func (bb *Client) sharedKey() *blob.SharedKeyCredential {
|
||||
return base.SharedKeyComposite((*base.CompositeClient[generated.BlobClient, generated.BlockBlobClient])(bb))
|
||||
}
|
||||
|
||||
func (bb *Client) generated() *generated.BlockBlobClient {
|
||||
_, blockBlob := base.InnerClients((*base.CompositeClient[generated.BlobClient, generated.BlockBlobClient])(bb))
|
||||
return blockBlob
|
||||
}
|
||||
|
||||
func (bb *Client) innerBlobGenerated() *generated.BlobClient {
|
||||
b := bb.BlobClient()
|
||||
return base.InnerClient((*base.Client[generated.BlobClient])(b))
|
||||
}
|
||||
|
||||
// URL returns the URL endpoint used by the Client object.
|
||||
func (bb *Client) URL() string {
|
||||
return bb.generated().Endpoint()
|
||||
}
|
||||
|
||||
// BlobClient returns the embedded blob client for this BlockBlob client.
|
||||
func (bb *Client) BlobClient() *blob.Client {
|
||||
blobClient, _ := base.InnerClients((*base.CompositeClient[generated.BlobClient, generated.BlockBlobClient])(bb))
|
||||
return (*blob.Client)(blobClient)
|
||||
}
|
||||
|
||||
// WithSnapshot creates a new Client object identical to the source but with the specified snapshot timestamp.
|
||||
// Pass "" to remove the snapshot returning a URL to the base blob.
|
||||
func (bb *Client) WithSnapshot(snapshot string) (*Client, error) {
|
||||
p, err := blob.ParseURL(bb.URL())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Snapshot = snapshot
|
||||
|
||||
return (*Client)(base.NewBlockBlobClient(p.String(), bb.generated().Internal(), bb.sharedKey())), nil
|
||||
}
|
||||
|
||||
// WithVersionID creates a new AppendBlobURL object identical to the source but with the specified version id.
|
||||
// Pass "" to remove the versionID returning a URL to the base blob.
|
||||
func (bb *Client) WithVersionID(versionID string) (*Client, error) {
|
||||
p, err := blob.ParseURL(bb.URL())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.VersionID = versionID
|
||||
|
||||
return (*Client)(base.NewBlockBlobClient(p.String(), bb.generated().Internal(), bb.sharedKey())), nil
|
||||
}
|
||||
|
||||
// Upload creates a new block blob or overwrites an existing block blob.
|
||||
// Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not
|
||||
// supported with Upload; the content of the existing blob is overwritten with the new content. To
|
||||
// perform a partial update of a block blob, use StageBlock and CommitBlockList.
|
||||
// This method panics if the stream is not at position 0.
|
||||
// Note that the http client closes the body stream after the request is sent to the service.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
|
||||
func (bb *Client) Upload(ctx context.Context, body io.ReadSeekCloser, options *UploadOptions) (UploadResponse, error) {
|
||||
count, err := shared.ValidateSeekableStreamAt0AndGetCount(body)
|
||||
if err != nil {
|
||||
return UploadResponse{}, err
|
||||
}
|
||||
|
||||
opts, httpHeaders, leaseInfo, cpkV, cpkN, accessConditions := options.format()
|
||||
|
||||
if options != nil && options.TransactionalValidation != nil {
|
||||
body, err = options.TransactionalValidation.Apply(body, opts)
|
||||
if err != nil {
|
||||
return UploadResponse{}, err
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := bb.generated().Upload(ctx, count, body, opts, httpHeaders, leaseInfo, cpkV, cpkN, accessConditions)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// UploadBlobFromURL - The Put Blob from URL operation creates a new Block Blob where the contents of the blob are read from
|
||||
// a given URL. Partial updates are not supported with Put Blob from URL; the content of an existing blob is overwritten
|
||||
// with the content of the new blob. To perform partial updates to a block blob’s contents using a source URL, use the Put
|
||||
// Block from URL API in conjunction with Put Block List.
|
||||
// For more information, see https://learn.microsoft.com/rest/api/storageservices/put-blob-from-url
|
||||
func (bb *Client) UploadBlobFromURL(ctx context.Context, copySource string, options *UploadBlobFromURLOptions) (UploadBlobFromURLResponse, error) {
|
||||
opts, httpHeaders, leaseAccessConditions, cpkInfo, cpkSourceInfo, modifiedAccessConditions, sourceModifiedConditions := options.format()
|
||||
|
||||
resp, err := bb.generated().PutBlobFromURL(ctx, int64(0), copySource, opts, httpHeaders, leaseAccessConditions, cpkInfo, cpkSourceInfo, modifiedAccessConditions, sourceModifiedConditions)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// StageBlock uploads the specified block to the block blob's "staging area" to be later committed by a call to CommitBlockList.
|
||||
// Note that the http client closes the body stream after the request is sent to the service.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block.
|
||||
func (bb *Client) StageBlock(ctx context.Context, base64BlockID string, body io.ReadSeekCloser, options *StageBlockOptions) (StageBlockResponse, error) {
|
||||
count, err := shared.ValidateSeekableStreamAt0AndGetCount(body)
|
||||
if err != nil {
|
||||
return StageBlockResponse{}, err
|
||||
}
|
||||
|
||||
opts, leaseAccessConditions, cpkInfo, cpkScopeInfo := options.format()
|
||||
|
||||
if options != nil && options.TransactionalValidation != nil {
|
||||
body, err = options.TransactionalValidation.Apply(body, opts)
|
||||
if err != nil {
|
||||
return StageBlockResponse{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := bb.generated().StageBlock(ctx, base64BlockID, count, body, opts, leaseAccessConditions, cpkInfo, cpkScopeInfo)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList.
|
||||
// If count is CountToEnd (0), then data is read from specified offset to the end.
|
||||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url.
|
||||
func (bb *Client) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL string, options *StageBlockFromURLOptions) (StageBlockFromURLResponse, error) {
|
||||
|
||||
stageBlockFromURLOptions, cpkInfo, cpkScopeInfo, leaseAccessConditions, sourceModifiedAccessConditions := options.format()
|
||||
|
||||
resp, err := bb.generated().StageBlockFromURL(ctx, base64BlockID, 0, sourceURL, stageBlockFromURLOptions,
|
||||
cpkInfo, cpkScopeInfo, leaseAccessConditions, sourceModifiedAccessConditions)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// CommitBlockList writes a blob by specifying the list of block IDs that make up the blob.
|
||||
// In order to be written as part of a blob, a block must have been successfully written
|
||||
// to the server in a prior PutBlock operation. You can call PutBlockList to update a blob
|
||||
// by uploading only those blocks that have changed, then committing the new and existing
|
||||
// blocks together. Any blocks not specified in the block list and permanently deleted.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block-list.
|
||||
func (bb *Client) CommitBlockList(ctx context.Context, base64BlockIDs []string, options *CommitBlockListOptions) (CommitBlockListResponse, error) {
|
||||
// this is a code smell in the generated code
|
||||
blockIds := make([]*string, len(base64BlockIDs))
|
||||
for k, v := range base64BlockIDs {
|
||||
blockIds[k] = to.Ptr(v)
|
||||
}
|
||||
|
||||
blockLookupList := generated.BlockLookupList{Latest: blockIds}
|
||||
|
||||
var commitOptions *generated.BlockBlobClientCommitBlockListOptions
|
||||
var headers *generated.BlobHTTPHeaders
|
||||
var leaseAccess *blob.LeaseAccessConditions
|
||||
var cpkInfo *generated.CPKInfo
|
||||
var cpkScope *generated.CPKScopeInfo
|
||||
var modifiedAccess *generated.ModifiedAccessConditions
|
||||
|
||||
if options != nil {
|
||||
commitOptions = &generated.BlockBlobClientCommitBlockListOptions{
|
||||
BlobTagsString: shared.SerializeBlobTagsToStrPtr(options.Tags),
|
||||
Metadata: options.Metadata,
|
||||
RequestID: options.RequestID,
|
||||
Tier: options.Tier,
|
||||
Timeout: options.Timeout,
|
||||
TransactionalContentCRC64: options.TransactionalContentCRC64,
|
||||
TransactionalContentMD5: options.TransactionalContentMD5,
|
||||
LegalHold: options.LegalHold,
|
||||
ImmutabilityPolicyMode: options.ImmutabilityPolicyMode,
|
||||
ImmutabilityPolicyExpiry: options.ImmutabilityPolicyExpiryTime,
|
||||
}
|
||||
|
||||
// If user attempts to pass in their own checksum, errors out.
|
||||
if options.TransactionalContentMD5 != nil || options.TransactionalContentCRC64 != nil {
|
||||
return CommitBlockListResponse{}, bloberror.UnsupportedChecksum
|
||||
}
|
||||
|
||||
headers = options.HTTPHeaders
|
||||
leaseAccess, modifiedAccess = exported.FormatBlobAccessConditions(options.AccessConditions)
|
||||
cpkInfo = options.CPKInfo
|
||||
cpkScope = options.CPKScopeInfo
|
||||
}
|
||||
|
||||
resp, err := bb.generated().CommitBlockList(ctx, blockLookupList, commitOptions, headers, leaseAccess, cpkInfo, cpkScope, modifiedAccess)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// GetBlockList returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-block-list.
|
||||
func (bb *Client) GetBlockList(ctx context.Context, listType BlockListType, options *GetBlockListOptions) (GetBlockListResponse, error) {
|
||||
o, lac, mac := options.format()
|
||||
|
||||
resp, err := bb.generated().GetBlockList(ctx, listType, o, lac, mac)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Redeclared APIs ----- Copy over to Append blob and Page blob as well.
|
||||
|
||||
// Delete marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection.
|
||||
// Note that deleting a blob also deletes all its snapshots.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob.
|
||||
func (bb *Client) Delete(ctx context.Context, o *blob.DeleteOptions) (blob.DeleteResponse, error) {
|
||||
return bb.BlobClient().Delete(ctx, o)
|
||||
}
|
||||
|
||||
// Undelete restores the contents and metadata of a soft-deleted blob and any associated soft-deleted snapshots.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/undelete-blob.
|
||||
func (bb *Client) Undelete(ctx context.Context, o *blob.UndeleteOptions) (blob.UndeleteResponse, error) {
|
||||
return bb.BlobClient().Undelete(ctx, o)
|
||||
}
|
||||
|
||||
// SetImmutabilityPolicy operation enables users to set the immutability policy on a blob.
|
||||
// https://learn.microsoft.com/en-us/azure/storage/blobs/immutable-storage-overview
|
||||
func (bb *Client) SetImmutabilityPolicy(ctx context.Context, expiryTime time.Time, options *blob.SetImmutabilityPolicyOptions) (blob.SetImmutabilityPolicyResponse, error) {
|
||||
return bb.BlobClient().SetImmutabilityPolicy(ctx, expiryTime, options)
|
||||
}
|
||||
|
||||
// DeleteImmutabilityPolicy operation enables users to delete the immutability policy on a blob.
|
||||
// https://learn.microsoft.com/en-us/azure/storage/blobs/immutable-storage-overview
|
||||
func (bb *Client) DeleteImmutabilityPolicy(ctx context.Context, options *blob.DeleteImmutabilityPolicyOptions) (blob.DeleteImmutabilityPolicyResponse, error) {
|
||||
return bb.BlobClient().DeleteImmutabilityPolicy(ctx, options)
|
||||
}
|
||||
|
||||
// SetLegalHold operation enables users to set legal hold on a blob.
|
||||
// https://learn.microsoft.com/en-us/azure/storage/blobs/immutable-storage-overview
|
||||
func (bb *Client) SetLegalHold(ctx context.Context, legalHold bool, options *blob.SetLegalHoldOptions) (blob.SetLegalHoldResponse, error) {
|
||||
return bb.BlobClient().SetLegalHold(ctx, legalHold, options)
|
||||
}
|
||||
|
||||
// SetTier operation sets the tier on a blob. The operation is allowed on a page
|
||||
// blob in a premium storage account and on a block blob in a blob storage account (locally
|
||||
// redundant storage only). A premium page blob's tier determines the allowed size, IOPs, and
|
||||
// bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation
|
||||
// does not update the blob's ETag.
|
||||
// For detailed information about block blob level tiering see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers.
|
||||
func (bb *Client) SetTier(ctx context.Context, tier blob.AccessTier, o *blob.SetTierOptions) (blob.SetTierResponse, error) {
|
||||
return bb.BlobClient().SetTier(ctx, tier, o)
|
||||
}
|
||||
|
||||
// SetExpiry operation sets an expiry time on an existing blob. This operation is only allowed on Hierarchical Namespace enabled accounts.
|
||||
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/set-blob-expiry
|
||||
func (bb *Client) SetExpiry(ctx context.Context, expiryType ExpiryType, o *SetExpiryOptions) (SetExpiryResponse, error) {
|
||||
if expiryType == nil {
|
||||
expiryType = ExpiryTypeNever{}
|
||||
}
|
||||
et, opts := expiryType.Format(o)
|
||||
resp, err := bb.innerBlobGenerated().SetExpiry(ctx, et, opts)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// GetProperties returns the blob's properties.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties.
|
||||
func (bb *Client) GetProperties(ctx context.Context, o *blob.GetPropertiesOptions) (blob.GetPropertiesResponse, error) {
|
||||
return bb.BlobClient().GetProperties(ctx, o)
|
||||
}
|
||||
|
||||
// GetAccountInfo provides account level information
|
||||
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/get-account-information?tabs=shared-access-signatures.
|
||||
func (bb *Client) GetAccountInfo(ctx context.Context, o *blob.GetAccountInfoOptions) (blob.GetAccountInfoResponse, error) {
|
||||
return bb.BlobClient().GetAccountInfo(ctx, o)
|
||||
}
|
||||
|
||||
// SetHTTPHeaders changes a blob's HTTP headers.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
|
||||
func (bb *Client) SetHTTPHeaders(ctx context.Context, httpHeaders blob.HTTPHeaders, o *blob.SetHTTPHeadersOptions) (blob.SetHTTPHeadersResponse, error) {
|
||||
return bb.BlobClient().SetHTTPHeaders(ctx, httpHeaders, o)
|
||||
}
|
||||
|
||||
// SetMetadata changes a blob's metadata.
|
||||
// https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata.
|
||||
func (bb *Client) SetMetadata(ctx context.Context, metadata map[string]*string, o *blob.SetMetadataOptions) (blob.SetMetadataResponse, error) {
|
||||
return bb.BlobClient().SetMetadata(ctx, metadata, o)
|
||||
}
|
||||
|
||||
// CreateSnapshot creates a read-only snapshot of a blob.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/snapshot-blob.
|
||||
func (bb *Client) CreateSnapshot(ctx context.Context, o *blob.CreateSnapshotOptions) (blob.CreateSnapshotResponse, error) {
|
||||
return bb.BlobClient().CreateSnapshot(ctx, o)
|
||||
}
|
||||
|
||||
// StartCopyFromURL copies the data at the source URL to a blob.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob.
|
||||
func (bb *Client) StartCopyFromURL(ctx context.Context, copySource string, o *blob.StartCopyFromURLOptions) (blob.StartCopyFromURLResponse, error) {
|
||||
return bb.BlobClient().StartCopyFromURL(ctx, copySource, o)
|
||||
}
|
||||
|
||||
// AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/abort-copy-blob.
|
||||
func (bb *Client) AbortCopyFromURL(ctx context.Context, copyID string, o *blob.AbortCopyFromURLOptions) (blob.AbortCopyFromURLResponse, error) {
|
||||
return bb.BlobClient().AbortCopyFromURL(ctx, copyID, o)
|
||||
}
|
||||
|
||||
// SetTags operation enables users to set tags on a blob or specific blob version, but not snapshot.
|
||||
// Each call to this operation replaces all existing tags attached to the blob.
|
||||
// To remove all tags from the blob, call this operation with no tags set.
|
||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags
|
||||
func (bb *Client) SetTags(ctx context.Context, tags map[string]string, o *blob.SetTagsOptions) (blob.SetTagsResponse, error) {
|
||||
return bb.BlobClient().SetTags(ctx, tags, o)
|
||||
}
|
||||
|
||||
// GetTags operation enables users to get tags on a blob or specific blob version, or snapshot.
|
||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags
|
||||
func (bb *Client) GetTags(ctx context.Context, o *blob.GetTagsOptions) (blob.GetTagsResponse, error) {
|
||||
return bb.BlobClient().GetTags(ctx, o)
|
||||
}
|
||||
|
||||
// CopyFromURL synchronously copies the data at the source URL to a block blob, with sizes up to 256 MB.
|
||||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url.
|
||||
func (bb *Client) CopyFromURL(ctx context.Context, copySource string, o *blob.CopyFromURLOptions) (blob.CopyFromURLResponse, error) {
|
||||
return bb.BlobClient().CopyFromURL(ctx, copySource, o)
|
||||
}
|
||||
|
||||
// GetSASURL is a convenience method for generating a SAS token for the currently pointed at block blob.
|
||||
// It can only be used if the credential supplied during creation was a SharedKeyCredential.
|
||||
func (bb *Client) GetSASURL(permissions sas.BlobPermissions, expiry time.Time, o *blob.GetSASURLOptions) (string, error) {
|
||||
return bb.BlobClient().GetSASURL(permissions, expiry, o)
|
||||
}
|
||||
|
||||
// Concurrent Upload Functions -----------------------------------------------------------------------------------------
|
||||
|
||||
// uploadFromReader uploads a buffer in blocks to a block blob.
|
||||
func (bb *Client) uploadFromReader(ctx context.Context, reader io.ReaderAt, actualSize int64, o *uploadFromReaderOptions) (uploadFromReaderResponse, error) {
|
||||
if o.BlockSize == 0 {
|
||||
// If bufferSize > (MaxStageBlockBytes * MaxBlocks), then error
|
||||
if actualSize > MaxStageBlockBytes*MaxBlocks {
|
||||
return uploadFromReaderResponse{}, errors.New("buffer is too large to upload to a block blob")
|
||||
}
|
||||
// If bufferSize <= MaxUploadBlobBytes, then Upload should be used with just 1 I/O request
|
||||
if actualSize <= MaxUploadBlobBytes {
|
||||
o.BlockSize = MaxUploadBlobBytes // Default if unspecified
|
||||
} else {
|
||||
o.BlockSize = int64(math.Ceil(float64(actualSize) / MaxBlocks)) // ceil(buffer / max blocks) = block size to use all 50,000 blocks
|
||||
if o.BlockSize < blob.DefaultDownloadBlockSize { // If the block size is smaller than 4MB, round up to 4MB
|
||||
o.BlockSize = blob.DefaultDownloadBlockSize
|
||||
}
|
||||
// StageBlock will be called with blockSize blocks and a Concurrency of (BufferSize / BlockSize).
|
||||
}
|
||||
}
|
||||
|
||||
if actualSize <= MaxUploadBlobBytes {
|
||||
// If the size can fit in 1 Upload call, do it this way
|
||||
var body io.ReadSeeker = io.NewSectionReader(reader, 0, actualSize)
|
||||
if o.Progress != nil {
|
||||
body = streaming.NewRequestProgress(shared.NopCloser(body), o.Progress)
|
||||
}
|
||||
|
||||
uploadBlockBlobOptions := o.getUploadBlockBlobOptions()
|
||||
resp, err := bb.Upload(ctx, shared.NopCloser(body), uploadBlockBlobOptions)
|
||||
|
||||
return toUploadReaderAtResponseFromUploadResponse(resp), err
|
||||
}
|
||||
|
||||
var numBlocks = uint16(((actualSize - 1) / o.BlockSize) + 1)
|
||||
if numBlocks > MaxBlocks {
|
||||
// prevent any math bugs from attempting to upload too many blocks which will always fail
|
||||
return uploadFromReaderResponse{}, errors.New("block limit exceeded")
|
||||
}
|
||||
|
||||
if log.Should(exported.EventUpload) {
|
||||
urlparts, err := blob.ParseURL(bb.generated().Endpoint())
|
||||
if err == nil {
|
||||
log.Writef(exported.EventUpload, "blob name %s actual size %v block-size %v block-count %v",
|
||||
urlparts.BlobName, actualSize, o.BlockSize, numBlocks)
|
||||
}
|
||||
}
|
||||
|
||||
blockIDList := make([]string, numBlocks) // Base-64 encoded block IDs
|
||||
progress := int64(0)
|
||||
progressLock := &sync.Mutex{}
|
||||
|
||||
err := shared.DoBatchTransfer(ctx, &shared.BatchTransferOptions{
|
||||
OperationName: "uploadFromReader",
|
||||
TransferSize: actualSize,
|
||||
ChunkSize: o.BlockSize,
|
||||
NumChunks: uint64(((actualSize - 1) / o.BlockSize) + 1),
|
||||
Concurrency: o.Concurrency,
|
||||
Operation: func(ctx context.Context, offset int64, chunkSize int64) error {
|
||||
// This function is called once per block.
|
||||
// It is passed this block's offset within the buffer and its count of bytes
|
||||
// Prepare to read the proper block/section of the buffer
|
||||
if chunkSize < o.BlockSize {
|
||||
// this is the last block. its actual size might be less
|
||||
// than the calculated size due to rounding up of the payload
|
||||
// size to fit in a whole number of blocks.
|
||||
chunkSize = (actualSize - offset)
|
||||
}
|
||||
var body io.ReadSeeker = io.NewSectionReader(reader, offset, chunkSize)
|
||||
blockNum := offset / o.BlockSize
|
||||
if o.Progress != nil {
|
||||
blockProgress := int64(0)
|
||||
body = streaming.NewRequestProgress(shared.NopCloser(body),
|
||||
func(bytesTransferred int64) {
|
||||
diff := bytesTransferred - blockProgress
|
||||
blockProgress = bytesTransferred
|
||||
progressLock.Lock() // 1 goroutine at a time gets progress report
|
||||
progress += diff
|
||||
o.Progress(progress)
|
||||
progressLock.Unlock()
|
||||
})
|
||||
}
|
||||
|
||||
// Block IDs are unique values to avoid issue if 2+ clients are uploading blocks
|
||||
// at the same time causing PutBlockList to get a mix of blocks from all the clients.
|
||||
generatedUuid, err := uuid.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blockIDList[blockNum] = base64.StdEncoding.EncodeToString([]byte(generatedUuid.String()))
|
||||
stageBlockOptions := o.getStageBlockOptions()
|
||||
_, err = bb.StageBlock(ctx, blockIDList[blockNum], shared.NopCloser(body), stageBlockOptions)
|
||||
return err
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return uploadFromReaderResponse{}, err
|
||||
}
|
||||
// All put blocks were successful, call Put Block List to finalize the blob
|
||||
commitBlockListOptions := o.getCommitBlockListOptions()
|
||||
resp, err := bb.CommitBlockList(ctx, blockIDList, commitBlockListOptions)
|
||||
|
||||
return toUploadReaderAtResponseFromCommitBlockListResponse(resp), err
|
||||
}
|
||||
|
||||
// UploadBuffer uploads a buffer in blocks to a block blob.
|
||||
func (bb *Client) UploadBuffer(ctx context.Context, buffer []byte, o *UploadBufferOptions) (UploadBufferResponse, error) {
|
||||
uploadOptions := uploadFromReaderOptions{}
|
||||
if o != nil {
|
||||
uploadOptions = *o
|
||||
}
|
||||
|
||||
// If user attempts to pass in their own checksum, errors out.
|
||||
if uploadOptions.TransactionalValidation != nil && reflect.TypeOf(uploadOptions.TransactionalValidation).Kind() != reflect.Func {
|
||||
return UploadBufferResponse{}, bloberror.UnsupportedChecksum
|
||||
}
|
||||
|
||||
return bb.uploadFromReader(ctx, bytes.NewReader(buffer), int64(len(buffer)), &uploadOptions)
|
||||
}
|
||||
|
||||
// UploadFile uploads a file in blocks to a block blob.
|
||||
func (bb *Client) UploadFile(ctx context.Context, file *os.File, o *UploadFileOptions) (UploadFileResponse, error) {
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return uploadFromReaderResponse{}, err
|
||||
}
|
||||
uploadOptions := uploadFromReaderOptions{}
|
||||
if o != nil {
|
||||
uploadOptions = *o
|
||||
}
|
||||
|
||||
// If user attempts to pass in their own checksum, errors out.
|
||||
if uploadOptions.TransactionalValidation != nil && reflect.TypeOf(uploadOptions.TransactionalValidation).Kind() != reflect.Func {
|
||||
return UploadFileResponse{}, bloberror.UnsupportedChecksum
|
||||
}
|
||||
|
||||
return bb.uploadFromReader(ctx, file, stat.Size(), &uploadOptions)
|
||||
}
|
||||
|
||||
// UploadStream copies the file held in io.Reader to the Blob at blockBlobClient.
|
||||
// A Context deadline or cancellation will cause this to error.
|
||||
func (bb *Client) UploadStream(ctx context.Context, body io.Reader, o *UploadStreamOptions) (UploadStreamResponse, error) {
|
||||
if o == nil {
|
||||
o = &UploadStreamOptions{}
|
||||
}
|
||||
|
||||
// If user attempts to pass in their own checksum, errors out.
|
||||
if o.TransactionalValidation != nil && reflect.TypeOf(o.TransactionalValidation).Kind() != reflect.Func {
|
||||
return UploadStreamResponse{}, bloberror.UnsupportedChecksum
|
||||
}
|
||||
|
||||
result, err := copyFromReader(ctx, body, bb, *o, shared.NewMMBPool)
|
||||
if err != nil {
|
||||
return CommitBlockListResponse{}, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Concurrent Download Functions -----------------------------------------------------------------------------------------
|
||||
|
||||
// DownloadStream reads a range of bytes from a blob. The response also includes the blob's properties and metadata.
|
||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob.
|
||||
func (bb *Client) DownloadStream(ctx context.Context, o *blob.DownloadStreamOptions) (blob.DownloadStreamResponse, error) {
|
||||
return bb.BlobClient().DownloadStream(ctx, o)
|
||||
}
|
||||
|
||||
// DownloadBuffer downloads an Azure blob to a buffer with parallel.
|
||||
func (bb *Client) DownloadBuffer(ctx context.Context, buffer []byte, o *blob.DownloadBufferOptions) (int64, error) {
|
||||
return bb.BlobClient().DownloadBuffer(ctx, shared.NewBytesWriter(buffer), o)
|
||||
}
|
||||
|
||||
// DownloadFile downloads an Azure blob to a local file.
|
||||
// The file would be truncated if the size doesn't match.
|
||||
func (bb *Client) DownloadFile(ctx context.Context, file *os.File, o *blob.DownloadFileOptions) (int64, error) {
|
||||
return bb.BlobClient().DownloadFile(ctx, file, o)
|
||||
}
|
||||
52
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/constants.go
generated
vendored
Normal file
52
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/constants.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blockblob
|
||||
|
||||
import "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
|
||||
const (
|
||||
// CountToEnd specifies the end of the file.
|
||||
CountToEnd = 0
|
||||
|
||||
_1MiB = 1024 * 1024
|
||||
|
||||
// MaxUploadBlobBytes indicates the maximum number of bytes that can be sent in a call to Upload.
|
||||
MaxUploadBlobBytes = 256 * 1024 * 1024 // 256MB
|
||||
|
||||
// MaxStageBlockBytes indicates the maximum number of bytes that can be sent in a call to StageBlock.
|
||||
MaxStageBlockBytes = 4000 * 1024 * 1024 // 4GB
|
||||
|
||||
// MaxBlocks indicates the maximum number of blocks allowed in a block blob.
|
||||
MaxBlocks = 50000
|
||||
)
|
||||
|
||||
// BlockListType defines values for BlockListType
|
||||
type BlockListType = generated.BlockListType
|
||||
|
||||
const (
|
||||
BlockListTypeCommitted BlockListType = generated.BlockListTypeCommitted
|
||||
BlockListTypeUncommitted BlockListType = generated.BlockListTypeUncommitted
|
||||
BlockListTypeAll BlockListType = generated.BlockListTypeAll
|
||||
)
|
||||
|
||||
// PossibleBlockListTypeValues returns the possible values for the BlockListType const type.
|
||||
func PossibleBlockListTypeValues() []BlockListType {
|
||||
return generated.PossibleBlockListTypeValues()
|
||||
}
|
||||
|
||||
// BlobCopySourceTags - can be 'COPY' or 'REPLACE'
|
||||
type BlobCopySourceTags = generated.BlobCopySourceTags
|
||||
|
||||
const (
|
||||
BlobCopySourceTagsCopy = generated.BlobCopySourceTagsCOPY
|
||||
BlobCopySourceTagsReplace = generated.BlobCopySourceTagsREPLACE
|
||||
)
|
||||
|
||||
// PossibleBlobCopySourceTagsValues returns the possible values for the BlobCopySourceTags const type.
|
||||
func PossibleBlobCopySourceTagsValues() []BlobCopySourceTags {
|
||||
return generated.PossibleBlobCopySourceTagsValues()
|
||||
}
|
||||
411
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/models.go
generated
vendored
Normal file
411
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/models.go
generated
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blockblob
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
)
|
||||
|
||||
// Type Declarations ---------------------------------------------------------------------
|
||||
|
||||
// Block - Represents a single block in a block blob. It describes the block's ID and size.
|
||||
type Block = generated.Block
|
||||
|
||||
// BlockList - can be uncommitted or committed blocks (committed/uncommitted)
|
||||
type BlockList = generated.BlockList
|
||||
|
||||
// Request Model Declaration -------------------------------------------------------------------------------------------
|
||||
|
||||
// UploadOptions contains the optional parameters for the Client.Upload method.
|
||||
type UploadOptions struct {
|
||||
// Optional. Used to set blob tags in various blob operations.
|
||||
Tags map[string]string
|
||||
|
||||
// Optional. Specifies a user-defined name-value pair associated with the blob.
|
||||
Metadata map[string]*string
|
||||
|
||||
// Optional. Indicates the tier to be set on the blob.
|
||||
Tier *blob.AccessTier
|
||||
|
||||
// TransactionalValidation specifies the transfer validation type to use.
|
||||
// The default is nil (no transfer validation).
|
||||
TransactionalValidation blob.TransferValidationType
|
||||
|
||||
HTTPHeaders *blob.HTTPHeaders
|
||||
CPKInfo *blob.CPKInfo
|
||||
CPKScopeInfo *blob.CPKScopeInfo
|
||||
AccessConditions *blob.AccessConditions
|
||||
LegalHold *bool
|
||||
ImmutabilityPolicyMode *blob.ImmutabilityPolicySetting
|
||||
ImmutabilityPolicyExpiryTime *time.Time
|
||||
|
||||
// Deprecated: TransactionalContentMD5 can be set by using TransactionalValidation instead
|
||||
TransactionalContentMD5 []byte
|
||||
}
|
||||
|
||||
func (o *UploadOptions) format() (*generated.BlockBlobClientUploadOptions, *generated.BlobHTTPHeaders, *generated.LeaseAccessConditions,
|
||||
*generated.CPKInfo, *generated.CPKScopeInfo, *generated.ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
basics := generated.BlockBlobClientUploadOptions{
|
||||
BlobTagsString: shared.SerializeBlobTagsToStrPtr(o.Tags),
|
||||
Metadata: o.Metadata,
|
||||
Tier: o.Tier,
|
||||
TransactionalContentMD5: o.TransactionalContentMD5,
|
||||
LegalHold: o.LegalHold,
|
||||
ImmutabilityPolicyMode: o.ImmutabilityPolicyMode,
|
||||
ImmutabilityPolicyExpiry: o.ImmutabilityPolicyExpiryTime,
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return &basics, o.HTTPHeaders, leaseAccessConditions, o.CPKInfo, o.CPKScopeInfo, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// UploadBlobFromURLOptions contains the optional parameters for the Client.UploadBlobFromURL method.
|
||||
type UploadBlobFromURLOptions struct {
|
||||
// Optional. Used to set blob tags in various blob operations.
|
||||
Tags map[string]string
|
||||
|
||||
// Only Bearer type is supported. Credentials should be a valid OAuth access token to copy source.
|
||||
CopySourceAuthorization *string
|
||||
|
||||
// Optional, default is true. Indicates if properties from the source blob should be copied.
|
||||
CopySourceBlobProperties *bool
|
||||
|
||||
// Optional, default 'replace'. Indicates if source tags should be copied or replaced with the tags specified by x-ms-tags.
|
||||
CopySourceTags *BlobCopySourceTags
|
||||
|
||||
// Optional. Specifies a user-defined name-value pair associated with the blob.
|
||||
Metadata map[string]*string
|
||||
|
||||
// Optional. Specifies the md5 calculated for the range of bytes that must be read from the copy source.
|
||||
SourceContentMD5 []byte
|
||||
|
||||
// Optional. Indicates the tier to be set on the blob.
|
||||
Tier *blob.AccessTier
|
||||
|
||||
// Additional optional headers
|
||||
HTTPHeaders *blob.HTTPHeaders
|
||||
AccessConditions *blob.AccessConditions
|
||||
CPKInfo *blob.CPKInfo
|
||||
CPKScopeInfo *blob.CPKScopeInfo
|
||||
SourceModifiedAccessConditions *blob.SourceModifiedAccessConditions
|
||||
}
|
||||
|
||||
func (o *UploadBlobFromURLOptions) format() (*generated.BlockBlobClientPutBlobFromURLOptions, *generated.BlobHTTPHeaders,
|
||||
*generated.LeaseAccessConditions, *generated.CPKInfo, *generated.CPKScopeInfo, *generated.ModifiedAccessConditions,
|
||||
*generated.SourceModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
options := generated.BlockBlobClientPutBlobFromURLOptions{
|
||||
BlobTagsString: shared.SerializeBlobTagsToStrPtr(o.Tags),
|
||||
CopySourceAuthorization: o.CopySourceAuthorization,
|
||||
CopySourceBlobProperties: o.CopySourceBlobProperties,
|
||||
CopySourceTags: o.CopySourceTags,
|
||||
Metadata: o.Metadata,
|
||||
SourceContentMD5: o.SourceContentMD5,
|
||||
Tier: o.Tier,
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return &options, o.HTTPHeaders, leaseAccessConditions, o.CPKInfo, o.CPKScopeInfo, modifiedAccessConditions, o.SourceModifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// StageBlockOptions contains the optional parameters for the Client.StageBlock method.
|
||||
type StageBlockOptions struct {
|
||||
CPKInfo *blob.CPKInfo
|
||||
|
||||
CPKScopeInfo *blob.CPKScopeInfo
|
||||
|
||||
LeaseAccessConditions *blob.LeaseAccessConditions
|
||||
|
||||
// TransactionalValidation specifies the transfer validation type to use.
|
||||
// The default is nil (no transfer validation).
|
||||
TransactionalValidation blob.TransferValidationType
|
||||
}
|
||||
|
||||
// StageBlockOptions contains the optional parameters for the Client.StageBlock method.
|
||||
func (o *StageBlockOptions) format() (*generated.BlockBlobClientStageBlockOptions, *generated.LeaseAccessConditions, *generated.CPKInfo, *generated.CPKScopeInfo) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
return &generated.BlockBlobClientStageBlockOptions{}, o.LeaseAccessConditions, o.CPKInfo, o.CPKScopeInfo
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// StageBlockFromURLOptions contains the optional parameters for the Client.StageBlockFromURL method.
|
||||
type StageBlockFromURLOptions struct {
|
||||
// Only Bearer type is supported. Credentials should be a valid OAuth access token to copy source.
|
||||
CopySourceAuthorization *string
|
||||
|
||||
LeaseAccessConditions *blob.LeaseAccessConditions
|
||||
|
||||
SourceModifiedAccessConditions *blob.SourceModifiedAccessConditions
|
||||
|
||||
// SourceContentValidation contains the validation mechanism used on the range of bytes read from the source.
|
||||
SourceContentValidation blob.SourceContentValidationType
|
||||
|
||||
// Range specifies a range of bytes. The default value is all bytes.
|
||||
Range blob.HTTPRange
|
||||
|
||||
CPKInfo *blob.CPKInfo
|
||||
|
||||
CPKScopeInfo *blob.CPKScopeInfo
|
||||
}
|
||||
|
||||
func (o *StageBlockFromURLOptions) format() (*generated.BlockBlobClientStageBlockFromURLOptions, *generated.CPKInfo, *generated.CPKScopeInfo, *generated.LeaseAccessConditions, *generated.SourceModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
options := &generated.BlockBlobClientStageBlockFromURLOptions{
|
||||
CopySourceAuthorization: o.CopySourceAuthorization,
|
||||
SourceRange: exported.FormatHTTPRange(o.Range),
|
||||
}
|
||||
|
||||
if o.SourceContentValidation != nil {
|
||||
o.SourceContentValidation.Apply(options)
|
||||
}
|
||||
|
||||
return options, o.CPKInfo, o.CPKScopeInfo, o.LeaseAccessConditions, o.SourceModifiedAccessConditions
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// CommitBlockListOptions contains the optional parameters for Client.CommitBlockList method.
|
||||
type CommitBlockListOptions struct {
|
||||
Tags map[string]string
|
||||
Metadata map[string]*string
|
||||
RequestID *string
|
||||
Tier *blob.AccessTier
|
||||
Timeout *int32
|
||||
HTTPHeaders *blob.HTTPHeaders
|
||||
CPKInfo *blob.CPKInfo
|
||||
CPKScopeInfo *blob.CPKScopeInfo
|
||||
AccessConditions *blob.AccessConditions
|
||||
LegalHold *bool
|
||||
ImmutabilityPolicyMode *blob.ImmutabilityPolicySetting
|
||||
ImmutabilityPolicyExpiryTime *time.Time
|
||||
|
||||
// Deprecated: TransactionalContentCRC64 cannot be generated
|
||||
TransactionalContentCRC64 []byte
|
||||
|
||||
// Deprecated: TransactionalContentMD5 cannot be generated
|
||||
TransactionalContentMD5 []byte
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// GetBlockListOptions contains the optional parameters for the Client.GetBlockList method.
|
||||
type GetBlockListOptions struct {
|
||||
Snapshot *string
|
||||
AccessConditions *blob.AccessConditions
|
||||
}
|
||||
|
||||
func (o *GetBlockListOptions) format() (*generated.BlockBlobClientGetBlockListOptions, *generated.LeaseAccessConditions, *generated.ModifiedAccessConditions) {
|
||||
if o == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return &generated.BlockBlobClientGetBlockListOptions{Snapshot: o.Snapshot}, leaseAccessConditions, modifiedAccessConditions
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// uploadFromReaderOptions identifies options used by the UploadBuffer and UploadFile functions.
|
||||
type uploadFromReaderOptions struct {
|
||||
// BlockSize specifies the block size to use; the default (and maximum size) is MaxStageBlockBytes.
|
||||
BlockSize int64
|
||||
|
||||
// Progress is a function that is invoked periodically as bytes are sent to the BlockBlobClient.
|
||||
// Note that the progress reporting is not always increasing; it can go down when retrying a request.
|
||||
Progress func(bytesTransferred int64)
|
||||
|
||||
// HTTPHeaders indicates the HTTP headers to be associated with the blob.
|
||||
HTTPHeaders *blob.HTTPHeaders
|
||||
|
||||
// Metadata indicates the metadata to be associated with the blob when PutBlockList is called.
|
||||
Metadata map[string]*string
|
||||
|
||||
// AccessConditions indicates the access conditions for the block blob.
|
||||
AccessConditions *blob.AccessConditions
|
||||
|
||||
// AccessTier indicates the tier of blob
|
||||
AccessTier *blob.AccessTier
|
||||
|
||||
// BlobTags
|
||||
Tags map[string]string
|
||||
|
||||
// ClientProvidedKeyOptions indicates the client provided key by name and/or by value to encrypt/decrypt data.
|
||||
CPKInfo *blob.CPKInfo
|
||||
CPKScopeInfo *blob.CPKScopeInfo
|
||||
|
||||
// Concurrency indicates the maximum number of blocks to upload in parallel (0=default)
|
||||
Concurrency uint16
|
||||
|
||||
TransactionalValidation blob.TransferValidationType
|
||||
|
||||
// Deprecated: TransactionalContentCRC64 cannot be generated at block level
|
||||
TransactionalContentCRC64 uint64
|
||||
|
||||
// Deprecated: TransactionalContentMD5 cannot be generated at block level
|
||||
TransactionalContentMD5 []byte
|
||||
}
|
||||
|
||||
// UploadBufferOptions provides set of configurations for UploadBuffer operation.
|
||||
type UploadBufferOptions = uploadFromReaderOptions
|
||||
|
||||
// UploadFileOptions provides set of configurations for UploadFile operation.
|
||||
type UploadFileOptions = uploadFromReaderOptions
|
||||
|
||||
func (o *uploadFromReaderOptions) getStageBlockOptions() *StageBlockOptions {
|
||||
leaseAccessConditions, _ := exported.FormatBlobAccessConditions(o.AccessConditions)
|
||||
return &StageBlockOptions{
|
||||
CPKInfo: o.CPKInfo,
|
||||
CPKScopeInfo: o.CPKScopeInfo,
|
||||
LeaseAccessConditions: leaseAccessConditions,
|
||||
|
||||
TransactionalValidation: o.TransactionalValidation,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *uploadFromReaderOptions) getUploadBlockBlobOptions() *UploadOptions {
|
||||
return &UploadOptions{
|
||||
Tags: o.Tags,
|
||||
Metadata: o.Metadata,
|
||||
Tier: o.AccessTier,
|
||||
HTTPHeaders: o.HTTPHeaders,
|
||||
AccessConditions: o.AccessConditions,
|
||||
CPKInfo: o.CPKInfo,
|
||||
CPKScopeInfo: o.CPKScopeInfo,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *uploadFromReaderOptions) getCommitBlockListOptions() *CommitBlockListOptions {
|
||||
return &CommitBlockListOptions{
|
||||
Tags: o.Tags,
|
||||
Metadata: o.Metadata,
|
||||
Tier: o.AccessTier,
|
||||
HTTPHeaders: o.HTTPHeaders,
|
||||
CPKInfo: o.CPKInfo,
|
||||
CPKScopeInfo: o.CPKScopeInfo,
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// UploadStreamOptions provides set of configurations for UploadStream operation.
|
||||
type UploadStreamOptions struct {
|
||||
// BlockSize defines the size of the buffer used during upload. The default and minimum value is 1 MiB.
|
||||
BlockSize int64
|
||||
|
||||
// Concurrency defines the max number of concurrent uploads to be performed to upload the file.
|
||||
// Each concurrent upload will create a buffer of size BlockSize. The default value is one.
|
||||
Concurrency int
|
||||
|
||||
TransactionalValidation blob.TransferValidationType
|
||||
|
||||
HTTPHeaders *blob.HTTPHeaders
|
||||
Metadata map[string]*string
|
||||
AccessConditions *blob.AccessConditions
|
||||
AccessTier *blob.AccessTier
|
||||
Tags map[string]string
|
||||
CPKInfo *blob.CPKInfo
|
||||
CPKScopeInfo *blob.CPKScopeInfo
|
||||
}
|
||||
|
||||
func (u *UploadStreamOptions) setDefaults() {
|
||||
if u.Concurrency == 0 {
|
||||
u.Concurrency = 1
|
||||
}
|
||||
|
||||
if u.BlockSize < _1MiB {
|
||||
u.BlockSize = _1MiB
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UploadStreamOptions) getStageBlockOptions() *StageBlockOptions {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
leaseAccessConditions, _ := exported.FormatBlobAccessConditions(u.AccessConditions)
|
||||
return &StageBlockOptions{
|
||||
TransactionalValidation: u.TransactionalValidation,
|
||||
CPKInfo: u.CPKInfo,
|
||||
CPKScopeInfo: u.CPKScopeInfo,
|
||||
LeaseAccessConditions: leaseAccessConditions,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UploadStreamOptions) getCommitBlockListOptions() *CommitBlockListOptions {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &CommitBlockListOptions{
|
||||
Tags: u.Tags,
|
||||
Metadata: u.Metadata,
|
||||
Tier: u.AccessTier,
|
||||
HTTPHeaders: u.HTTPHeaders,
|
||||
CPKInfo: u.CPKInfo,
|
||||
CPKScopeInfo: u.CPKScopeInfo,
|
||||
AccessConditions: u.AccessConditions,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UploadStreamOptions) getUploadOptions() *UploadOptions {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &UploadOptions{
|
||||
Tags: u.Tags,
|
||||
Metadata: u.Metadata,
|
||||
Tier: u.AccessTier,
|
||||
HTTPHeaders: u.HTTPHeaders,
|
||||
CPKInfo: u.CPKInfo,
|
||||
CPKScopeInfo: u.CPKScopeInfo,
|
||||
AccessConditions: u.AccessConditions,
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ExpiryType defines values for ExpiryType.
|
||||
type ExpiryType = exported.ExpiryType
|
||||
|
||||
// ExpiryTypeAbsolute defines the absolute time for the blob expiry.
|
||||
type ExpiryTypeAbsolute = exported.ExpiryTypeAbsolute
|
||||
|
||||
// ExpiryTypeRelativeToNow defines the duration relative to now for the blob expiry.
|
||||
type ExpiryTypeRelativeToNow = exported.ExpiryTypeRelativeToNow
|
||||
|
||||
// ExpiryTypeRelativeToCreation defines the duration relative to creation for the blob expiry.
|
||||
type ExpiryTypeRelativeToCreation = exported.ExpiryTypeRelativeToCreation
|
||||
|
||||
// ExpiryTypeNever defines that the blob will be set to never expire.
|
||||
type ExpiryTypeNever = exported.ExpiryTypeNever
|
||||
|
||||
// SetExpiryOptions contains the optional parameters for the Client.SetExpiry method.
|
||||
type SetExpiryOptions = exported.SetExpiryOptions
|
||||
117
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/responses.go
generated
vendored
Normal file
117
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob/responses.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package blockblob
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
)
|
||||
|
||||
// UploadResponse contains the response from method Client.Upload.
|
||||
type UploadResponse = generated.BlockBlobClientUploadResponse
|
||||
|
||||
// UploadBlobFromURLResponse contains the response from the method Client.UploadBlobFromURL
|
||||
type UploadBlobFromURLResponse = generated.BlockBlobClientPutBlobFromURLResponse
|
||||
|
||||
// StageBlockResponse contains the response from method Client.StageBlock.
|
||||
type StageBlockResponse = generated.BlockBlobClientStageBlockResponse
|
||||
|
||||
// CommitBlockListResponse contains the response from method Client.CommitBlockList.
|
||||
type CommitBlockListResponse = generated.BlockBlobClientCommitBlockListResponse
|
||||
|
||||
// StageBlockFromURLResponse contains the response from method Client.StageBlockFromURL.
|
||||
type StageBlockFromURLResponse = generated.BlockBlobClientStageBlockFromURLResponse
|
||||
|
||||
// GetBlockListResponse contains the response from method Client.GetBlockList.
|
||||
type GetBlockListResponse = generated.BlockBlobClientGetBlockListResponse
|
||||
|
||||
// uploadFromReaderResponse contains the response from method Client.UploadBuffer/Client.UploadFile.
|
||||
type uploadFromReaderResponse struct {
|
||||
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
|
||||
ClientRequestID *string
|
||||
|
||||
// ContentMD5 contains the information returned from the Content-MD5 header response.
|
||||
ContentMD5 []byte
|
||||
|
||||
// Date contains the information returned from the Date header response.
|
||||
Date *time.Time
|
||||
|
||||
// ETag contains the information returned from the ETag header response.
|
||||
ETag *azcore.ETag
|
||||
|
||||
// EncryptionKeySHA256 contains the information returned from the x-ms-encryption-key-sha256 header response.
|
||||
EncryptionKeySHA256 *string
|
||||
|
||||
// EncryptionScope contains the information returned from the x-ms-encryption-scope header response.
|
||||
EncryptionScope *string
|
||||
|
||||
// IsServerEncrypted contains the information returned from the x-ms-request-server-encrypted header response.
|
||||
IsServerEncrypted *bool
|
||||
|
||||
// LastModified contains the information returned from the Last-Modified header response.
|
||||
LastModified *time.Time
|
||||
|
||||
// RequestID contains the information returned from the x-ms-request-id header response.
|
||||
RequestID *string
|
||||
|
||||
// Version contains the information returned from the x-ms-version header response.
|
||||
Version *string
|
||||
|
||||
// VersionID contains the information returned from the x-ms-version-id header response.
|
||||
VersionID *string
|
||||
|
||||
// ContentCRC64 contains the information returned from the x-ms-content-crc64 header response.
|
||||
// Will be a part of response only if uploading data >= internal.MaxUploadBlobBytes (= 256 * 1024 * 1024 // 256MB)
|
||||
ContentCRC64 []byte
|
||||
}
|
||||
|
||||
func toUploadReaderAtResponseFromUploadResponse(resp UploadResponse) uploadFromReaderResponse {
|
||||
return uploadFromReaderResponse{
|
||||
ClientRequestID: resp.ClientRequestID,
|
||||
ContentMD5: resp.ContentMD5,
|
||||
Date: resp.Date,
|
||||
ETag: resp.ETag,
|
||||
EncryptionKeySHA256: resp.EncryptionKeySHA256,
|
||||
EncryptionScope: resp.EncryptionScope,
|
||||
IsServerEncrypted: resp.IsServerEncrypted,
|
||||
LastModified: resp.LastModified,
|
||||
RequestID: resp.RequestID,
|
||||
Version: resp.Version,
|
||||
VersionID: resp.VersionID,
|
||||
}
|
||||
}
|
||||
|
||||
func toUploadReaderAtResponseFromCommitBlockListResponse(resp CommitBlockListResponse) uploadFromReaderResponse {
|
||||
return uploadFromReaderResponse{
|
||||
ClientRequestID: resp.ClientRequestID,
|
||||
ContentMD5: resp.ContentMD5,
|
||||
Date: resp.Date,
|
||||
ETag: resp.ETag,
|
||||
EncryptionKeySHA256: resp.EncryptionKeySHA256,
|
||||
EncryptionScope: resp.EncryptionScope,
|
||||
IsServerEncrypted: resp.IsServerEncrypted,
|
||||
LastModified: resp.LastModified,
|
||||
RequestID: resp.RequestID,
|
||||
Version: resp.Version,
|
||||
VersionID: resp.VersionID,
|
||||
ContentCRC64: resp.ContentCRC64,
|
||||
}
|
||||
}
|
||||
|
||||
// UploadFileResponse contains the response from method Client.UploadBuffer/Client.UploadFile.
|
||||
type UploadFileResponse = uploadFromReaderResponse
|
||||
|
||||
// UploadBufferResponse contains the response from method Client.UploadBuffer/Client.UploadFile.
|
||||
type UploadBufferResponse = uploadFromReaderResponse
|
||||
|
||||
// UploadStreamResponse contains the response from method Client.CommitBlockList.
|
||||
type UploadStreamResponse = CommitBlockListResponse
|
||||
|
||||
// SetExpiryResponse contains the response from method Client.SetExpiry.
|
||||
type SetExpiryResponse = generated.BlobClientSetExpiryResponse
|
||||
129
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base/clients.go
generated
vendored
Normal file
129
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base/clients.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package base
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ClientOptions contains the optional parameters when creating a Client.
|
||||
type ClientOptions struct {
|
||||
azcore.ClientOptions
|
||||
|
||||
// Audience to use when requesting tokens for Azure Active Directory authentication.
|
||||
// Only has an effect when credential is of type TokenCredential. The value could be
|
||||
// https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net.
|
||||
Audience string
|
||||
}
|
||||
|
||||
type Client[T any] struct {
|
||||
inner *T
|
||||
credential any
|
||||
options *ClientOptions
|
||||
}
|
||||
|
||||
func InnerClient[T any](client *Client[T]) *T {
|
||||
return client.inner
|
||||
}
|
||||
|
||||
func SharedKey[T any](client *Client[T]) *exported.SharedKeyCredential {
|
||||
switch cred := client.credential.(type) {
|
||||
case *exported.SharedKeyCredential:
|
||||
return cred
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Credential[T any](client *Client[T]) any {
|
||||
return client.credential
|
||||
}
|
||||
|
||||
func GetClientOptions[T any](client *Client[T]) *ClientOptions {
|
||||
return client.options
|
||||
}
|
||||
|
||||
func GetAudience(clOpts *ClientOptions) string {
|
||||
if clOpts == nil || len(strings.TrimSpace(clOpts.Audience)) == 0 {
|
||||
return shared.TokenScope
|
||||
} else {
|
||||
return strings.TrimRight(clOpts.Audience, "/") + "/.default"
|
||||
}
|
||||
}
|
||||
|
||||
func NewClient[T any](inner *T) *Client[T] {
|
||||
return &Client[T]{inner: inner}
|
||||
}
|
||||
|
||||
func NewServiceClient(containerURL string, azClient *azcore.Client, credential any, options *ClientOptions) *Client[generated.ServiceClient] {
|
||||
return &Client[generated.ServiceClient]{
|
||||
inner: generated.NewServiceClient(containerURL, azClient),
|
||||
credential: credential,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func NewContainerClient(containerURL string, azClient *azcore.Client, credential any, options *ClientOptions) *Client[generated.ContainerClient] {
|
||||
return &Client[generated.ContainerClient]{
|
||||
inner: generated.NewContainerClient(containerURL, azClient),
|
||||
credential: credential,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBlobClient(blobURL string, azClient *azcore.Client, credential any, options *ClientOptions) *Client[generated.BlobClient] {
|
||||
return &Client[generated.BlobClient]{
|
||||
inner: generated.NewBlobClient(blobURL, azClient),
|
||||
credential: credential,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
type CompositeClient[T, U any] struct {
|
||||
innerT *T
|
||||
innerU *U
|
||||
sharedKey *exported.SharedKeyCredential
|
||||
}
|
||||
|
||||
func InnerClients[T, U any](client *CompositeClient[T, U]) (*Client[T], *U) {
|
||||
return &Client[T]{
|
||||
inner: client.innerT,
|
||||
credential: client.sharedKey,
|
||||
}, client.innerU
|
||||
}
|
||||
|
||||
func NewAppendBlobClient(blobURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.AppendBlobClient] {
|
||||
return &CompositeClient[generated.BlobClient, generated.AppendBlobClient]{
|
||||
innerT: generated.NewBlobClient(blobURL, azClient),
|
||||
innerU: generated.NewAppendBlobClient(blobURL, azClient),
|
||||
sharedKey: sharedKey,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBlockBlobClient(blobURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.BlockBlobClient] {
|
||||
return &CompositeClient[generated.BlobClient, generated.BlockBlobClient]{
|
||||
innerT: generated.NewBlobClient(blobURL, azClient),
|
||||
innerU: generated.NewBlockBlobClient(blobURL, azClient),
|
||||
sharedKey: sharedKey,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPageBlobClient(blobURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.PageBlobClient] {
|
||||
return &CompositeClient[generated.BlobClient, generated.PageBlobClient]{
|
||||
innerT: generated.NewBlobClient(blobURL, azClient),
|
||||
innerU: generated.NewPageBlobClient(blobURL, azClient),
|
||||
sharedKey: sharedKey,
|
||||
}
|
||||
}
|
||||
|
||||
func SharedKeyComposite[T, U any](client *CompositeClient[T, U]) *exported.SharedKeyCredential {
|
||||
return client.sharedKey
|
||||
}
|
||||
43
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/access_conditions.go
generated
vendored
Normal file
43
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/access_conditions.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
|
||||
const SnapshotTimeFormat = "2006-01-02T15:04:05.0000000Z07:00"
|
||||
|
||||
// ContainerAccessConditions identifies container-specific access conditions which you optionally set.
|
||||
type ContainerAccessConditions struct {
|
||||
ModifiedAccessConditions *ModifiedAccessConditions
|
||||
LeaseAccessConditions *LeaseAccessConditions
|
||||
}
|
||||
|
||||
func FormatContainerAccessConditions(b *ContainerAccessConditions) (*LeaseAccessConditions, *ModifiedAccessConditions) {
|
||||
if b == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return b.LeaseAccessConditions, b.ModifiedAccessConditions
|
||||
}
|
||||
|
||||
// BlobAccessConditions identifies blob-specific access conditions which you optionally set.
|
||||
type BlobAccessConditions struct {
|
||||
LeaseAccessConditions *LeaseAccessConditions
|
||||
ModifiedAccessConditions *ModifiedAccessConditions
|
||||
}
|
||||
|
||||
func FormatBlobAccessConditions(b *BlobAccessConditions) (*LeaseAccessConditions, *ModifiedAccessConditions) {
|
||||
if b == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return b.LeaseAccessConditions, b.ModifiedAccessConditions
|
||||
}
|
||||
|
||||
// LeaseAccessConditions contains optional parameters to access leased entity.
|
||||
type LeaseAccessConditions = generated.LeaseAccessConditions
|
||||
|
||||
// ModifiedAccessConditions contains a group of parameters for specifying access conditions.
|
||||
type ModifiedAccessConditions = generated.ModifiedAccessConditions
|
||||
67
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/access_policy.go
generated
vendored
Normal file
67
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/access_policy.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// AccessPolicyPermission type simplifies creating the permissions string for a container's access policy.
|
||||
// Initialize an instance of this type and then call its String method to set AccessPolicy's Permission field.
|
||||
type AccessPolicyPermission struct {
|
||||
Read, Add, Create, Write, Delete, List bool
|
||||
}
|
||||
|
||||
// String produces the access policy permission string for an Azure Storage container.
|
||||
// Call this method to set AccessPolicy's Permission field.
|
||||
func (p *AccessPolicyPermission) String() string {
|
||||
var b bytes.Buffer
|
||||
if p.Read {
|
||||
b.WriteRune('r')
|
||||
}
|
||||
if p.Add {
|
||||
b.WriteRune('a')
|
||||
}
|
||||
if p.Create {
|
||||
b.WriteRune('c')
|
||||
}
|
||||
if p.Write {
|
||||
b.WriteRune('w')
|
||||
}
|
||||
if p.Delete {
|
||||
b.WriteRune('d')
|
||||
}
|
||||
if p.List {
|
||||
b.WriteRune('l')
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Parse initializes the AccessPolicyPermission's fields from a string.
|
||||
func (p *AccessPolicyPermission) Parse(s string) error {
|
||||
*p = AccessPolicyPermission{} // Clear the flags
|
||||
for _, r := range s {
|
||||
switch r {
|
||||
case 'r':
|
||||
p.Read = true
|
||||
case 'a':
|
||||
p.Add = true
|
||||
case 'c':
|
||||
p.Create = true
|
||||
case 'w':
|
||||
p.Write = true
|
||||
case 'd':
|
||||
p.Delete = true
|
||||
case 'l':
|
||||
p.List = true
|
||||
default:
|
||||
return fmt.Errorf("invalid permission: '%v'", r)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
280
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/blob_batch.go
generated
vendored
Normal file
280
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/blob_batch.go
generated
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/uuid"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
)
|
||||
|
||||
const (
|
||||
batchIdPrefix = "batch_"
|
||||
httpVersion = "HTTP/1.1"
|
||||
httpNewline = "\r\n"
|
||||
)
|
||||
|
||||
// createBatchID is used for creating a new batch id which is used as batch boundary in the request body
|
||||
func createBatchID() (string, error) {
|
||||
batchID, err := uuid.New()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return batchIdPrefix + batchID.String(), nil
|
||||
}
|
||||
|
||||
// buildSubRequest is used for building the sub-request. Example:
|
||||
// DELETE /container0/blob0 HTTP/1.1
|
||||
// x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT
|
||||
// Authorization: SharedKey account:<redacted>
|
||||
// Content-Length: 0
|
||||
func buildSubRequest(req *policy.Request) []byte {
|
||||
var batchSubRequest strings.Builder
|
||||
blobPath := req.Raw().URL.EscapedPath()
|
||||
if len(req.Raw().URL.RawQuery) > 0 {
|
||||
blobPath += "?" + req.Raw().URL.RawQuery
|
||||
}
|
||||
|
||||
batchSubRequest.WriteString(fmt.Sprintf("%s %s %s%s", req.Raw().Method, blobPath, httpVersion, httpNewline))
|
||||
|
||||
for k, v := range req.Raw().Header {
|
||||
if strings.EqualFold(k, shared.HeaderXmsVersion) {
|
||||
continue
|
||||
}
|
||||
if len(v) > 0 {
|
||||
batchSubRequest.WriteString(fmt.Sprintf("%v: %v%v", k, v[0], httpNewline))
|
||||
}
|
||||
}
|
||||
|
||||
batchSubRequest.WriteString(httpNewline)
|
||||
return []byte(batchSubRequest.String())
|
||||
}
|
||||
|
||||
// CreateBatchRequest creates a new batch request using the sub-requests present in the BlobBatchBuilder.
|
||||
//
|
||||
// Example of a sub-request in the batch request body:
|
||||
//
|
||||
// --batch_357de4f7-6d0b-4e02-8cd2-6361411a9525
|
||||
// Content-Type: application/http
|
||||
// Content-Transfer-Encoding: binary
|
||||
// Content-ID: 0
|
||||
//
|
||||
// DELETE /container0/blob0 HTTP/1.1
|
||||
// x-ms-date: Thu, 14 Jun 2018 16:46:54 GMT
|
||||
// Authorization: SharedKey account:<redacted>
|
||||
// Content-Length: 0
|
||||
func CreateBatchRequest(bb *BlobBatchBuilder) ([]byte, string, error) {
|
||||
batchID, err := createBatchID()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Create a new multipart buffer
|
||||
reqBody := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(reqBody)
|
||||
|
||||
// Set the boundary
|
||||
err = writer.SetBoundary(batchID)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
partHeaders := make(textproto.MIMEHeader)
|
||||
partHeaders["Content-Type"] = []string{"application/http"}
|
||||
partHeaders["Content-Transfer-Encoding"] = []string{"binary"}
|
||||
var partWriter io.Writer
|
||||
|
||||
for i, req := range bb.SubRequests {
|
||||
if bb.AuthPolicy != nil {
|
||||
_, err := bb.AuthPolicy.Do(req)
|
||||
if err != nil && !strings.EqualFold(err.Error(), "no more policies") {
|
||||
if log.Should(EventSubmitBatch) {
|
||||
log.Writef(EventSubmitBatch, "failed to authorize sub-request for %v.\nError: %v", req.Raw().URL.Path, err.Error())
|
||||
}
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
partHeaders["Content-ID"] = []string{fmt.Sprintf("%v", i)}
|
||||
partWriter, err = writer.CreatePart(partHeaders)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
_, err = partWriter.Write(buildSubRequest(req))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
// Close the multipart writer
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return reqBody.Bytes(), batchID, nil
|
||||
}
|
||||
|
||||
// UpdateSubRequestHeaders updates the sub-request headers.
|
||||
// Removes x-ms-version header.
|
||||
func UpdateSubRequestHeaders(req *policy.Request) {
|
||||
// remove x-ms-version header from the request header
|
||||
for k := range req.Raw().Header {
|
||||
if strings.EqualFold(k, shared.HeaderXmsVersion) {
|
||||
delete(req.Raw().Header, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BatchResponseItem contains the response for the individual sub-requests.
|
||||
type BatchResponseItem struct {
|
||||
ContentID *int
|
||||
ContainerName *string
|
||||
BlobName *string
|
||||
RequestID *string
|
||||
Version *string
|
||||
Error error // nil error indicates that the batch sub-request operation is successful
|
||||
}
|
||||
|
||||
func getResponseBoundary(contentType *string) (string, error) {
|
||||
if contentType == nil {
|
||||
return "", fmt.Errorf("Content-Type returned in SubmitBatch response is nil")
|
||||
}
|
||||
|
||||
_, params, err := mime.ParseMediaType(*contentType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if val, ok := params["boundary"]; ok {
|
||||
return val, nil
|
||||
} else {
|
||||
return "", fmt.Errorf("batch boundary not present in Content-Type header of the SubmitBatch response.\nContent-Type: %v", *contentType)
|
||||
}
|
||||
}
|
||||
|
||||
func getContentID(part *multipart.Part) (*int, error) {
|
||||
contentID := part.Header.Get("Content-ID")
|
||||
if contentID == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
val, err := strconv.Atoi(strings.TrimSpace(contentID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &val, nil
|
||||
}
|
||||
|
||||
func getResponseHeader(key string, resp *http.Response) *string {
|
||||
val := resp.Header.Get(key)
|
||||
if val == "" {
|
||||
return nil
|
||||
}
|
||||
return &val
|
||||
}
|
||||
|
||||
// ParseBlobBatchResponse is used for parsing the batch response body into individual sub-responses for each item in the batch.
|
||||
func ParseBlobBatchResponse(respBody io.ReadCloser, contentType *string, subRequests []*policy.Request) ([]*BatchResponseItem, error) {
|
||||
boundary, err := getResponseBoundary(contentType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respReader := multipart.NewReader(respBody, boundary)
|
||||
var responses []*BatchResponseItem
|
||||
|
||||
for {
|
||||
part, err := respReader.NextPart()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
batchSubResponse := &BatchResponseItem{}
|
||||
batchSubResponse.ContentID, err = getContentID(part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if batchSubResponse.ContentID != nil {
|
||||
path := strings.Trim(subRequests[*batchSubResponse.ContentID].Raw().URL.Path, "/")
|
||||
p := strings.Split(path, "/")
|
||||
batchSubResponse.ContainerName = to.Ptr(p[0])
|
||||
batchSubResponse.BlobName = to.Ptr(strings.Join(p[1:], "/"))
|
||||
}
|
||||
|
||||
respBytes, err := io.ReadAll(part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
respBytes = append(respBytes, byte('\n'))
|
||||
buf := bytes.NewBuffer(respBytes)
|
||||
resp, err := http.ReadResponse(bufio.NewReader(buf), nil)
|
||||
// sub-response parsing error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
batchSubResponse.RequestID = getResponseHeader(shared.HeaderXmsRequestID, resp)
|
||||
batchSubResponse.Version = getResponseHeader(shared.HeaderXmsVersion, resp)
|
||||
|
||||
// sub-response failure
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
if len(responses) == 0 && batchSubResponse.ContentID == nil {
|
||||
// this case can happen when the parent request fails.
|
||||
// For example, batch request having more than 256 sub-requests.
|
||||
return nil, fmt.Errorf("%v", string(respBytes))
|
||||
}
|
||||
|
||||
resp.Request = subRequests[*batchSubResponse.ContentID].Raw()
|
||||
batchSubResponse.Error = runtime.NewResponseError(resp)
|
||||
}
|
||||
|
||||
responses = append(responses, batchSubResponse)
|
||||
}
|
||||
|
||||
if len(responses) != len(subRequests) {
|
||||
return nil, fmt.Errorf("expected %v responses, got %v for the batch ID: %v", len(subRequests), len(responses), boundary)
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
// not exported but used for batch request creation
|
||||
|
||||
// BlobBatchBuilder is used for creating the blob batch request
|
||||
type BlobBatchBuilder struct {
|
||||
AuthPolicy policy.Policy
|
||||
SubRequests []*policy.Request
|
||||
}
|
||||
|
||||
// BlobBatchOperationType defines the operation of the blob batch sub-requests.
|
||||
type BlobBatchOperationType string
|
||||
|
||||
const (
|
||||
BatchDeleteOperationType BlobBatchOperationType = "delete"
|
||||
BatchSetTierOperationType BlobBatchOperationType = "set tier"
|
||||
)
|
||||
33
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/exported.go
generated
vendored
Normal file
33
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/exported.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// HTTPRange defines a range of bytes within an HTTP resource, starting at offset and
|
||||
// ending at offset+count. A zero-value HTTPRange indicates the entire resource. An HTTPRange
|
||||
// which has an offset and zero value count indicates from the offset to the resource's end.
|
||||
type HTTPRange struct {
|
||||
Offset int64
|
||||
Count int64
|
||||
}
|
||||
|
||||
// FormatHTTPRange converts an HTTPRange to its string format.
|
||||
func FormatHTTPRange(r HTTPRange) *string {
|
||||
if r.Offset == 0 && r.Count == 0 {
|
||||
return nil // No specified range
|
||||
}
|
||||
endOffset := "" // if count == CountToEnd (0)
|
||||
if r.Count > 0 {
|
||||
endOffset = strconv.FormatInt((r.Offset+r.Count)-1, 10)
|
||||
}
|
||||
dataRange := fmt.Sprintf("bytes=%v-%s", r.Offset, endOffset)
|
||||
return &dataRange
|
||||
}
|
||||
20
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/log_events.go
generated
vendored
Normal file
20
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/log_events.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
)
|
||||
|
||||
// NOTE: these are publicly exported via type-aliasing in azblob/log.go
|
||||
const (
|
||||
// EventUpload is used when we compute number of blocks to upload and size of each block.
|
||||
EventUpload log.Event = "azblob.Upload"
|
||||
|
||||
// EventSubmitBatch is used for logging events related to submit blob batch operation.
|
||||
EventSubmitBatch log.Event = "azblob.SubmitBatch"
|
||||
)
|
||||
71
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/set_expiry.go
generated
vendored
Normal file
71
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/set_expiry.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
)
|
||||
|
||||
// ExpiryType defines values for ExpiryType
|
||||
type ExpiryType interface {
|
||||
Format(o *SetExpiryOptions) (generated.ExpiryOptions, *generated.BlobClientSetExpiryOptions)
|
||||
notPubliclyImplementable()
|
||||
}
|
||||
|
||||
// ExpiryTypeAbsolute defines the absolute time for the blob expiry
|
||||
type ExpiryTypeAbsolute time.Time
|
||||
|
||||
// ExpiryTypeRelativeToNow defines the duration relative to now for the blob expiry
|
||||
type ExpiryTypeRelativeToNow time.Duration
|
||||
|
||||
// ExpiryTypeRelativeToCreation defines the duration relative to creation for the blob expiry
|
||||
type ExpiryTypeRelativeToCreation time.Duration
|
||||
|
||||
// ExpiryTypeNever defines that the blob will be set to never expire
|
||||
type ExpiryTypeNever struct {
|
||||
// empty struct since NeverExpire expiry type does not require expiry time
|
||||
}
|
||||
|
||||
// SetExpiryOptions contains the optional parameters for the Client.SetExpiry method.
|
||||
type SetExpiryOptions struct {
|
||||
// placeholder for future options
|
||||
}
|
||||
|
||||
func (e ExpiryTypeAbsolute) Format(o *SetExpiryOptions) (generated.ExpiryOptions, *generated.BlobClientSetExpiryOptions) {
|
||||
return generated.ExpiryOptionsAbsolute, &generated.BlobClientSetExpiryOptions{
|
||||
ExpiresOn: to.Ptr(time.Time(e).UTC().Format(http.TimeFormat)),
|
||||
}
|
||||
}
|
||||
|
||||
func (e ExpiryTypeAbsolute) notPubliclyImplementable() {}
|
||||
|
||||
func (e ExpiryTypeRelativeToNow) Format(o *SetExpiryOptions) (generated.ExpiryOptions, *generated.BlobClientSetExpiryOptions) {
|
||||
return generated.ExpiryOptionsRelativeToNow, &generated.BlobClientSetExpiryOptions{
|
||||
ExpiresOn: to.Ptr(strconv.FormatInt(time.Duration(e).Milliseconds(), 10)),
|
||||
}
|
||||
}
|
||||
|
||||
func (e ExpiryTypeRelativeToNow) notPubliclyImplementable() {}
|
||||
|
||||
func (e ExpiryTypeRelativeToCreation) Format(o *SetExpiryOptions) (generated.ExpiryOptions, *generated.BlobClientSetExpiryOptions) {
|
||||
return generated.ExpiryOptionsRelativeToCreation, &generated.BlobClientSetExpiryOptions{
|
||||
ExpiresOn: to.Ptr(strconv.FormatInt(time.Duration(e).Milliseconds(), 10)),
|
||||
}
|
||||
}
|
||||
|
||||
func (e ExpiryTypeRelativeToCreation) notPubliclyImplementable() {}
|
||||
|
||||
func (e ExpiryTypeNever) Format(o *SetExpiryOptions) (generated.ExpiryOptions, *generated.BlobClientSetExpiryOptions) {
|
||||
return generated.ExpiryOptionsNeverExpire, nil
|
||||
}
|
||||
|
||||
func (e ExpiryTypeNever) notPubliclyImplementable() {}
|
||||
314
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/shared_key_credential.go
generated
vendored
Normal file
314
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/shared_key_credential.go
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
)
|
||||
|
||||
// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the
|
||||
// storage account's name and either its primary or secondary key.
|
||||
func NewSharedKeyCredential(accountName string, accountKey string) (*SharedKeyCredential, error) {
|
||||
c := SharedKeyCredential{accountName: accountName}
|
||||
if err := c.SetAccountKey(accountKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// SharedKeyCredential contains an account's name and its primary or secondary key.
|
||||
type SharedKeyCredential struct {
|
||||
// Only the NewSharedKeyCredential method should set these; all other methods should treat them as read-only
|
||||
accountName string
|
||||
accountKey atomic.Value // []byte
|
||||
}
|
||||
|
||||
// AccountName returns the Storage account's name.
|
||||
func (c *SharedKeyCredential) AccountName() string {
|
||||
return c.accountName
|
||||
}
|
||||
|
||||
// SetAccountKey replaces the existing account key with the specified account key.
|
||||
func (c *SharedKeyCredential) SetAccountKey(accountKey string) error {
|
||||
_bytes, err := base64.StdEncoding.DecodeString(accountKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode account key: %w", err)
|
||||
}
|
||||
c.accountKey.Store(_bytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ComputeHMACSHA256 generates a hash signature for an HTTP request or for a SAS.
|
||||
func (c *SharedKeyCredential) computeHMACSHA256(message string) (string, error) {
|
||||
h := hmac.New(sha256.New, c.accountKey.Load().([]byte))
|
||||
_, err := h.Write([]byte(message))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil)), err
|
||||
}
|
||||
|
||||
func (c *SharedKeyCredential) buildStringToSign(req *http.Request) (string, error) {
|
||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
|
||||
headers := req.Header
|
||||
contentLength := getHeader(shared.HeaderContentLength, headers)
|
||||
if contentLength == "0" {
|
||||
contentLength = ""
|
||||
}
|
||||
|
||||
canonicalizedResource, err := c.buildCanonicalizedResource(req.URL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
stringToSign := strings.Join([]string{
|
||||
req.Method,
|
||||
getHeader(shared.HeaderContentEncoding, headers),
|
||||
getHeader(shared.HeaderContentLanguage, headers),
|
||||
contentLength,
|
||||
getHeader(shared.HeaderContentMD5, headers),
|
||||
getHeader(shared.HeaderContentType, headers),
|
||||
"", // Empty date because x-ms-date is expected (as per web page above)
|
||||
getHeader(shared.HeaderIfModifiedSince, headers),
|
||||
getHeader(shared.HeaderIfMatch, headers),
|
||||
getHeader(shared.HeaderIfNoneMatch, headers),
|
||||
getHeader(shared.HeaderIfUnmodifiedSince, headers),
|
||||
getHeader(shared.HeaderRange, headers),
|
||||
c.buildCanonicalizedHeader(headers),
|
||||
canonicalizedResource,
|
||||
}, "\n")
|
||||
return stringToSign, nil
|
||||
}
|
||||
|
||||
func getHeader(key string, headers map[string][]string) string {
|
||||
if headers == nil {
|
||||
return ""
|
||||
}
|
||||
if v, ok := headers[key]; ok {
|
||||
if len(v) > 0 {
|
||||
return v[0]
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func getWeightTables() [][]int {
|
||||
tableLv0 := [...]int{
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71c, 0x0, 0x71f, 0x721, 0x723, 0x725,
|
||||
0x0, 0x0, 0x0, 0x72d, 0x803, 0x0, 0x0, 0x733, 0x0, 0xd03, 0xd1a, 0xd1c, 0xd1e,
|
||||
0xd20, 0xd22, 0xd24, 0xd26, 0xd28, 0xd2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xe02, 0xe09, 0xe0a, 0xe1a, 0xe21, 0xe23, 0xe25, 0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51,
|
||||
0xe70, 0xe7c, 0xe7e, 0xe89, 0xe8a, 0xe91, 0xe99, 0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9,
|
||||
0x0, 0x0, 0x0, 0x743, 0x744, 0x748, 0xe02, 0xe09, 0xe0a, 0xe1a, 0xe21, 0xe23, 0xe25,
|
||||
0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51, 0xe70, 0xe7c, 0xe7e, 0xe89, 0xe8a, 0xe91, 0xe99,
|
||||
0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9, 0x0, 0x74c, 0x0, 0x750, 0x0,
|
||||
}
|
||||
tableLv2 := [...]int{
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8212, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
}
|
||||
tables := [][]int{tableLv0[:], tableLv2[:]}
|
||||
return tables
|
||||
}
|
||||
|
||||
// NewHeaderStringComparer performs a multi-level, weight-based comparison of two strings
|
||||
func compareHeaders(lhs, rhs string, tables [][]int) int {
|
||||
currLevel, i, j := 0, 0, 0
|
||||
n := len(tables)
|
||||
lhsLen := len(lhs)
|
||||
rhsLen := len(rhs)
|
||||
|
||||
for currLevel < n {
|
||||
if currLevel == (n-1) && i != j {
|
||||
if i > j {
|
||||
return -1
|
||||
}
|
||||
if i < j {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var w1, w2 int
|
||||
|
||||
// Check bounds before accessing lhs[i]
|
||||
if i < lhsLen {
|
||||
w1 = tables[currLevel][lhs[i]]
|
||||
} else {
|
||||
w1 = 0x1
|
||||
}
|
||||
|
||||
// Check bounds before accessing rhs[j]
|
||||
if j < rhsLen {
|
||||
w2 = tables[currLevel][rhs[j]]
|
||||
} else {
|
||||
w2 = 0x1
|
||||
}
|
||||
|
||||
if w1 == 0x1 && w2 == 0x1 {
|
||||
i = 0
|
||||
j = 0
|
||||
currLevel++
|
||||
} else if w1 == w2 {
|
||||
i++
|
||||
j++
|
||||
} else if w1 == 0 {
|
||||
i++
|
||||
} else if w2 == 0 {
|
||||
j++
|
||||
} else {
|
||||
if w1 < w2 {
|
||||
return -1
|
||||
}
|
||||
if w1 > w2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *SharedKeyCredential) buildCanonicalizedHeader(headers http.Header) string {
|
||||
cm := map[string][]string{}
|
||||
for k, v := range headers {
|
||||
headerName := strings.TrimSpace(strings.ToLower(k))
|
||||
if strings.HasPrefix(headerName, "x-ms-") {
|
||||
cm[headerName] = v // NOTE: the value must not have any whitespace around it.
|
||||
}
|
||||
}
|
||||
if len(cm) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(cm))
|
||||
for key := range cm {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
tables := getWeightTables()
|
||||
// Sort the keys using the custom comparator
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return compareHeaders(keys[i], keys[j], tables) < 0
|
||||
})
|
||||
ch := bytes.NewBufferString("")
|
||||
for i, key := range keys {
|
||||
if i > 0 {
|
||||
ch.WriteRune('\n')
|
||||
}
|
||||
ch.WriteString(key)
|
||||
ch.WriteRune(':')
|
||||
ch.WriteString(strings.Join(cm[key], ","))
|
||||
}
|
||||
return ch.String()
|
||||
}
|
||||
|
||||
func (c *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) (string, error) {
|
||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
|
||||
cr := bytes.NewBufferString("/")
|
||||
cr.WriteString(c.accountName)
|
||||
|
||||
if len(u.Path) > 0 {
|
||||
// Any portion of the CanonicalizedResource string that is derived from
|
||||
// the resource's URI should be encoded exactly as it is in the URI.
|
||||
// -- https://msdn.microsoft.com/en-gb/library/azure/dd179428.aspx
|
||||
cr.WriteString(u.EscapedPath())
|
||||
} else {
|
||||
// a slash is required to indicate the root path
|
||||
cr.WriteString("/")
|
||||
}
|
||||
|
||||
// params is a map[string][]string; param name is key; params values is []string
|
||||
params, err := url.ParseQuery(u.RawQuery) // Returns URL decoded values
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse query params: %w", err)
|
||||
}
|
||||
|
||||
if len(params) > 0 { // There is at least 1 query parameter
|
||||
var paramNames []string // We use this to sort the parameter key names
|
||||
for paramName := range params {
|
||||
paramNames = append(paramNames, paramName) // paramNames must be lowercase
|
||||
}
|
||||
sort.Strings(paramNames)
|
||||
|
||||
for _, paramName := range paramNames {
|
||||
paramValues := params[paramName]
|
||||
sort.Strings(paramValues)
|
||||
|
||||
// Join the sorted key values separated by ','
|
||||
// Then prepend "keyName:"; then add this string to the buffer
|
||||
cr.WriteString("\n" + strings.ToLower(paramName) + ":" + strings.Join(paramValues, ","))
|
||||
}
|
||||
}
|
||||
return cr.String(), nil
|
||||
}
|
||||
|
||||
// ComputeHMACSHA256 is a helper for computing the signed string outside of this package.
|
||||
func ComputeHMACSHA256(cred *SharedKeyCredential, message string) (string, error) {
|
||||
return cred.computeHMACSHA256(message)
|
||||
}
|
||||
|
||||
// the following content isn't actually exported but must live
|
||||
// next to SharedKeyCredential as it uses its unexported methods
|
||||
|
||||
type SharedKeyCredPolicy struct {
|
||||
cred *SharedKeyCredential
|
||||
}
|
||||
|
||||
func NewSharedKeyCredPolicy(cred *SharedKeyCredential) *SharedKeyCredPolicy {
|
||||
return &SharedKeyCredPolicy{cred: cred}
|
||||
}
|
||||
|
||||
func (s *SharedKeyCredPolicy) Do(req *policy.Request) (*http.Response, error) {
|
||||
// skip adding the authorization header if no SharedKeyCredential was provided.
|
||||
// this prevents a panic that might be hard to diagnose and allows testing
|
||||
// against http endpoints that don't require authentication.
|
||||
if s.cred == nil {
|
||||
return req.Next()
|
||||
}
|
||||
|
||||
if d := getHeader(shared.HeaderXmsDate, req.Raw().Header); d == "" {
|
||||
req.Raw().Header.Set(shared.HeaderXmsDate, time.Now().UTC().Format(http.TimeFormat))
|
||||
}
|
||||
stringToSign, err := s.cred.buildStringToSign(req.Raw())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature, err := s.cred.computeHMACSHA256(stringToSign)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authHeader := strings.Join([]string{"SharedKey ", s.cred.AccountName(), ":", signature}, "")
|
||||
req.Raw().Header.Set(shared.HeaderAuthorization, authHeader)
|
||||
|
||||
response, err := req.Next()
|
||||
if err != nil && response != nil && response.StatusCode == http.StatusForbidden {
|
||||
// Service failed to authenticate request, log it
|
||||
log.Write(azlog.EventResponse, "===== HTTP Forbidden status, String-to-Sign:\n"+stringToSign+"\n===============================\n")
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
67
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/transfer_validation_option.go
generated
vendored
Normal file
67
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/transfer_validation_option.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"hash/crc64"
|
||||
"io"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
|
||||
)
|
||||
|
||||
// TransferValidationType abstracts the various mechanisms used to verify a transfer.
|
||||
type TransferValidationType interface {
|
||||
Apply(io.ReadSeekCloser, generated.TransactionalContentSetter) (io.ReadSeekCloser, error)
|
||||
notPubliclyImplementable()
|
||||
}
|
||||
|
||||
// TransferValidationTypeCRC64 is a TransferValidationType used to provide a precomputed CRC64.
|
||||
type TransferValidationTypeCRC64 uint64
|
||||
|
||||
func (c TransferValidationTypeCRC64) Apply(rsc io.ReadSeekCloser, cfg generated.TransactionalContentSetter) (io.ReadSeekCloser, error) {
|
||||
buf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(buf, uint64(c))
|
||||
cfg.SetCRC64(buf)
|
||||
return rsc, nil
|
||||
}
|
||||
|
||||
func (TransferValidationTypeCRC64) notPubliclyImplementable() {}
|
||||
|
||||
// TransferValidationTypeComputeCRC64 is a TransferValidationType that indicates a CRC64 should be computed during transfer.
|
||||
func TransferValidationTypeComputeCRC64() TransferValidationType {
|
||||
return transferValidationTypeFn(func(rsc io.ReadSeekCloser, cfg generated.TransactionalContentSetter) (io.ReadSeekCloser, error) {
|
||||
buf, err := io.ReadAll(rsc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
crc := crc64.Checksum(buf, shared.CRC64Table)
|
||||
return TransferValidationTypeCRC64(crc).Apply(streaming.NopCloser(bytes.NewReader(buf)), cfg)
|
||||
})
|
||||
}
|
||||
|
||||
// TransferValidationTypeMD5 is a TransferValidationType used to provide a precomputed MD5.
|
||||
type TransferValidationTypeMD5 []byte
|
||||
|
||||
func (c TransferValidationTypeMD5) Apply(rsc io.ReadSeekCloser, cfg generated.TransactionalContentSetter) (io.ReadSeekCloser, error) {
|
||||
cfg.SetMD5(c)
|
||||
return rsc, nil
|
||||
}
|
||||
|
||||
func (TransferValidationTypeMD5) notPubliclyImplementable() {}
|
||||
|
||||
type transferValidationTypeFn func(io.ReadSeekCloser, generated.TransactionalContentSetter) (io.ReadSeekCloser, error)
|
||||
|
||||
func (t transferValidationTypeFn) Apply(rsc io.ReadSeekCloser, cfg generated.TransactionalContentSetter) (io.ReadSeekCloser, error) {
|
||||
return t(rsc, cfg)
|
||||
}
|
||||
|
||||
func (transferValidationTypeFn) notPubliclyImplementable() {}
|
||||
64
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/user_delegation_credential.go
generated
vendored
Normal file
64
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/user_delegation_credential.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package exported
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
|
||||
)
|
||||
|
||||
// NewUserDelegationCredential creates a new UserDelegationCredential using a Storage account's Name and a user delegation Key from it
|
||||
func NewUserDelegationCredential(accountName string, udk UserDelegationKey) *UserDelegationCredential {
|
||||
return &UserDelegationCredential{
|
||||
accountName: accountName,
|
||||
userDelegationKey: udk,
|
||||
}
|
||||
}
|
||||
|
||||
// UserDelegationKey contains UserDelegationKey.
|
||||
type UserDelegationKey = generated.UserDelegationKey
|
||||
|
||||
// UserDelegationCredential contains an account's name and its user delegation key.
|
||||
type UserDelegationCredential struct {
|
||||
accountName string
|
||||
userDelegationKey UserDelegationKey
|
||||
}
|
||||
|
||||
// getAccountName returns the Storage account's Name
|
||||
func (f *UserDelegationCredential) getAccountName() string {
|
||||
return f.accountName
|
||||
}
|
||||
|
||||
// GetAccountName is a helper method for accessing the user delegation key parameters outside this package.
|
||||
func GetAccountName(udc *UserDelegationCredential) string {
|
||||
return udc.getAccountName()
|
||||
}
|
||||
|
||||
// computeHMACSHA256 generates a hash signature for an HTTP request or for a SAS.
|
||||
func (f *UserDelegationCredential) computeHMACSHA256(message string) (string, error) {
|
||||
bytes, _ := base64.StdEncoding.DecodeString(*f.userDelegationKey.Value)
|
||||
h := hmac.New(sha256.New, bytes)
|
||||
_, err := h.Write([]byte(message))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil)), err
|
||||
}
|
||||
|
||||
// ComputeUDCHMACSHA256 is a helper method for computing the signed string outside this package.
|
||||
func ComputeUDCHMACSHA256(udc *UserDelegationCredential, message string) (string, error) {
|
||||
return udc.computeHMACSHA256(message)
|
||||
}
|
||||
|
||||
// getUDKParams returns UserDelegationKey
|
||||
func (f *UserDelegationCredential) getUDKParams() *UserDelegationKey {
|
||||
return &f.userDelegationKey
|
||||
}
|
||||
|
||||
// GetUDKParams is a helper method for accessing the user delegation key parameters outside this package.
|
||||
func GetUDKParams(udc *UserDelegationCredential) *UserDelegationKey {
|
||||
return udc.getUDKParams()
|
||||
}
|
||||
12
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/version.go
generated
vendored
Normal file
12
vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported/version.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
package exported
|
||||
|
||||
const (
|
||||
ModuleName = "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
|
||||
ModuleVersion = "v1.5.0"
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user