go.mod: bump images to v0.26.0

This is mainly needed in order to get the RHEL 9 SAP Azure images.
This commit is contained in:
Ondřej Budai 2023-12-21 19:47:16 +01:00 committed by Tom Gundersen
parent d5483ccfb0
commit 807f249146
232 changed files with 32705 additions and 3663 deletions

View file

@ -1,17 +1,129 @@
# Release History
## 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

View file

@ -22,6 +22,24 @@ 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]interface{} = map[reflect.Type]interface{}{}
@ -66,7 +84,9 @@ func IsNullValue[T any](v T) bool {
return false
}
// ClientOptions contains configuration settings for a client's pipeline.
// 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.
@ -75,22 +95,17 @@ type Client struct {
tr tracing.Tracer
// cached on the client to support shallow copying with new values
tp tracing.Provider
modVer string
tp tracing.Provider
modVer string
namespace string
}
// NewClient creates a new Client instance with the provided values.
// - clientName - the fully qualified name of the client ("module/package.Client"); this is used by the telemetry policy and tracing provider.
// if module and package are the same value, the "module/" prefix can be omitted.
// - moduleVersion - the semantic version of the containing module; used by the telemetry policy
// - 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(clientName, moduleVersion string, plOpts runtime.PipelineOptions, options *ClientOptions) (*Client, error) {
mod, client, err := shared.ExtractModuleName(clientName)
if err != nil {
return nil, err
}
func NewClient(moduleName, moduleVersion string, plOpts runtime.PipelineOptions, options *ClientOptions) (*Client, error) {
if options == nil {
options = &ClientOptions{}
}
@ -101,15 +116,19 @@ func NewClient(clientName, moduleVersion string, plOpts runtime.PipelineOptions,
}
}
pl := runtime.NewPipeline(mod, moduleVersion, plOpts, options)
pl := runtime.NewPipeline(moduleName, moduleVersion, plOpts, options)
tr := options.TracingProvider.NewTracer(client, moduleVersion)
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,
pl: pl,
tr: tr,
tp: options.TracingProvider,
modVer: moduleVersion,
namespace: plOpts.Tracing.Namespace,
}, nil
}
@ -128,5 +147,8 @@ func (c *Client) Tracer() tracing.Tracer {
// - 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)
return &Client{pl: c.pl, tr: tr, tp: c.tp, modVer: 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}
}

View file

@ -253,5 +253,12 @@ When resuming a poller, no IO is performed, and zero-value arguments can be used
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

View file

@ -8,8 +8,11 @@ package exported
import (
"context"
"encoding/base64"
"fmt"
"io"
"net/http"
"sync/atomic"
"time"
)
@ -51,6 +54,17 @@ type AccessToken struct {
// 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
@ -65,3 +79,97 @@ 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)
}

View file

@ -8,10 +8,7 @@ package exported
import (
"errors"
"fmt"
"net/http"
"golang.org/x/net/http/httpguts"
)
// Policy represents an extensibility point for the Pipeline that can mutate the specified
@ -75,23 +72,6 @@ func (p Pipeline) Do(req *Request) (*http.Response, error) {
if req == nil {
return nil, errors.New("request cannot be nil")
}
// check copied from Transport.roundTrip()
for k, vv := range req.Raw().Header {
if !httpguts.ValidHeaderFieldName(k) {
if req.Raw().Body != nil {
req.Raw().Body.Close()
}
return nil, fmt.Errorf("invalid header field name %q", k)
}
for _, v := range vv {
if !httpguts.ValidHeaderFieldValue(v) {
if req.Raw().Body != nil {
req.Raw().Body.Close()
}
return nil, fmt.Errorf("invalid header field value %q for key %v", v, k)
}
}
}
req.policies = p.policies
return req.Next()
}

View file

@ -8,6 +8,7 @@ package exported
import (
"context"
"encoding/base64"
"errors"
"fmt"
"io"
@ -18,6 +19,28 @@ import (
"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.
@ -170,6 +193,14 @@ func (req *Request) Clone(ctx context.Context) *Request {
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.

View file

@ -13,6 +13,7 @@ import (
"net/http"
"regexp"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
"github.com/Azure/azure-sdk-for-go/sdk/internal/exported"
)
@ -25,7 +26,7 @@ func NewResponseError(resp *http.Response) error {
}
// prefer the error code in the response header
if ec := resp.Header.Get("x-ms-error-code"); ec != "" {
if ec := resp.Header.Get(shared.HeaderXMSErrorCode); ec != "" {
respErr.ErrorCode = ec
return respErr
}
@ -112,33 +113,45 @@ type ResponseError struct {
// 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 {
const separator = "--------------------------------------------------------------------------------"
// write the request method and URL with response status code
msg := &bytes.Buffer{}
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)
fmt.Fprintln(msg, "--------------------------------------------------------------------------------")
fmt.Fprintf(msg, "RESPONSE %d: %s\n", e.RawResponse.StatusCode, e.RawResponse.Status)
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")
}
fmt.Fprintln(msg, "--------------------------------------------------------------------------------")
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))
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")
}
// 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, "--------------------------------------------------------------------------------")
fmt.Fprintln(msg, separator)
return msg.String()
}

View 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]interface{}) 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)
}

View file

@ -7,8 +7,9 @@
package shared
const (
ContentTypeAppJSON = "application/json"
ContentTypeAppXML = "application/xml"
ContentTypeAppJSON = "application/json"
ContentTypeAppXML = "application/xml"
ContentTypeTextPlain = "text/plain"
)
const (
@ -17,20 +18,27 @@ const (
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.7.2"
Version = "v1.9.1"
)

View file

@ -16,14 +16,23 @@ import (
"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{}
// CtxIncludeResponseKey is used as a context key for retrieving the raw response.
type CtxIncludeResponseKey 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 {
@ -35,22 +44,64 @@ func Delay(ctx context.Context, delay time.Duration) error {
}
}
// RetryAfter returns non-zero if the response contains a Retry-After header value.
// 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
}
ra := resp.Header.Get(HeaderRetryAfter)
if ra == "" {
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
}
// retry-after values are expressed in either number of
// seconds or an HTTP-date indicating when to try again
if retryAfter, _ := strconv.Atoi(ra); retryAfter > 0 {
return time.Duration(retryAfter) * time.Second
} else if t, err := time.Parse(time.RFC1123, ra); err == nil {
return time.Until(t)
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
}
@ -78,26 +129,21 @@ func ValidateModVer(moduleVersion string) error {
return nil
}
// ExtractModuleName returns "module", "package.Client" from "module/package.Client" or
// "package", "package.Client" from "package.Client" when there's no "module/" prefix.
// If clientName is malformed, an error is returned.
func ExtractModuleName(clientName string) (string, string, error) {
// uses unnamed capturing for "module", "package.Client", and "package"
regex, err := regexp.Compile(`^(?:([a-z0-9]+)/)?(([a-z0-9]+)\.(?:[A-Za-z0-9]+))$`)
if err != nil {
return "", "", err
}
matches := regex.FindStringSubmatch(clientName)
if len(matches) < 4 {
return "", "", fmt.Errorf("malformed clientName %s", clientName)
}
// the first match is the entire string, the second is "module", the third is
// "package.Client" and the fourth is "package".
// if there was no "module/" prefix, the second match will be the empty string
if matches[1] != "" {
return matches[1], matches[2], nil
}
return matches[3], matches[2], 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)
}
}

View file

@ -7,11 +7,13 @@
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"
)
@ -27,9 +29,11 @@ type Transporter = exported.Transporter
type Request = exported.Request
// ClientOptions contains optional settings for a client's pipeline.
// All zero-value fields will be initialized with default values.
// 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 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.
@ -162,3 +166,22 @@ type AuthorizationHandler struct {
// the policy will return any 401 response to the client.
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)
}

View file

@ -10,6 +10,12 @@ 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.
@ -20,12 +26,16 @@ type PagingHandler[T any] struct {
// 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
}
@ -34,6 +44,7 @@ type Pager[T any] struct {
func NewPager[T any](handler PagingHandler[T]) *Pager[T] {
return &Pager[T]{
handler: handler,
tracer: handler.Tracer,
firstPage: true,
}
}
@ -48,8 +59,6 @@ func (p *Pager[T]) More() bool {
// NextPage advances the pager to the next page.
func (p *Pager[T]) NextPage(ctx context.Context) (T, error) {
var resp T
var err error
if p.current != nil {
if p.firstPage {
// we get here if it's an LRO-pager, we already have the first page
@ -58,12 +67,16 @@ func (p *Pager[T]) NextPage(ctx context.Context) (T, error) {
} else if !p.handler.More(*p.current) {
return *new(T), errors.New("no more pages")
}
resp, err = p.handler.Fetcher(ctx, p.current)
} else {
// non-LRO case, first page
p.firstPage = false
resp, err = p.handler.Fetcher(ctx, nil)
}
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
}
@ -75,3 +88,41 @@ func (p *Pager[T]) NextPage(ctx context.Context) (T, error) {
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)
}
// 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 nextLink == "" {
req, err = firstReq(ctx)
} else if nextLink, err = EncodeQueryParams(nextLink); err == nil {
if options != nil && 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
}
if !HasStatusCode(resp, http.StatusOK) {
return nil, NewResponseError(resp)
}
return resp, nil
}

View file

@ -13,9 +13,35 @@ import (
// PipelineOptions contains Pipeline options for SDK developers
type PipelineOptions struct {
AllowedHeaders, AllowedQueryParameters []string
APIVersion APIVersionOptions
PerCall, PerRetry []policy.Policy
// 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.
@ -56,8 +82,10 @@ func NewPipeline(module, version string, plOpts PipelineOptions, options *policy
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(httpHeaderPolicy), exported.PolicyFunc(bodyDownloadPolicy))
policies = append(policies, exported.PolicyFunc(bodyDownloadPolicy))
transport := cp.Transport
if transport == nil {
transport = defaultHTTPClient

View file

@ -6,6 +6,7 @@ package runtime
import (
"errors"
"net/http"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
@ -34,7 +35,7 @@ type acquiringResourceState struct {
// 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(state.req.Raw().Context(), state.tro)
tk, err := state.p.cred.GetToken(&shared.ContextWithDeniedValues{Context: state.req.Raw().Context()}, state.tro)
if err != nil {
return exported.AccessToken{}, time.Time{}, err
}
@ -72,6 +73,17 @@ func (b *BearerTokenPolicy) authenticateAndAuthorize(req *policy.Request) func(p
// 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); err != nil {
return nil, err
}
var err error
if b.authzHandler.OnRequest != nil {
err = b.authzHandler.OnRequest(req, b.authenticateAndAuthorize(req))
@ -79,7 +91,7 @@ func (b *BearerTokenPolicy) Do(req *policy.Request) (*http.Response, error) {
err = b.authenticateAndAuthorize(req)(policy.TokenRequestOptions{Scopes: b.scopes})
}
if err != nil {
return nil, ensureNonRetriable(err)
return nil, errorinfo.NonRetriableError(err)
}
res, err := req.Next()
@ -95,22 +107,15 @@ func (b *BearerTokenPolicy) Do(req *policy.Request) (*http.Response, error) {
}
}
}
return res, ensureNonRetriable(err)
}
func ensureNonRetriable(err error) error {
var nre errorinfo.NonRetriable
if err != nil && !errors.As(err, &nre) {
err = btpError{err}
if err != nil {
err = errorinfo.NonRetriableError(err)
}
return err
return res, err
}
// btpError is a wrapper that ensures RetryPolicy doesn't retry requests BearerTokenPolicy couldn't authorize
type btpError struct {
error
func checkHTTPSForAuth(req *policy.Request) error {
if strings.ToLower(req.Raw().URL.Scheme) != "https" {
return errorinfo.NonRetriableError(errors.New("authenticated requests are not permitted for non TLS protected (https) endpoints"))
}
return nil
}
func (btpError) NonRetriable() {}
var _ errorinfo.NonRetriable = (*btpError)(nil)

View file

@ -34,6 +34,7 @@ func httpHeaderPolicy(req *policy.Request) (*http.Response, error) {
// 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 context.WithValue(parent, shared.CtxWithHTTPHeaderKey{}, header)
return policy.WithHTTPHeader(parent, header)
}

View file

@ -0,0 +1,143 @@
//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 {
// for future expansion
}
// 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)
const newSpanKind = tracing.SpanKindInternal
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) {}
}
}
ctx, span := tracer.Start(ctx, name, &tracing.SpanOptions{
Kind: newSpanKind,
})
ctx = context.WithValue(ctx, ctxActiveSpan{}, newSpanKind)
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{}

View file

@ -20,7 +20,7 @@ func includeResponsePolicy(req *policy.Request) (*http.Response, error) {
if resp == nil {
return resp, err
}
if httpOutRaw := req.Raw().Context().Value(shared.CtxIncludeResponseKey{}); httpOutRaw != nil {
if httpOutRaw := req.Raw().Context().Value(shared.CtxWithCaptureResponse{}); httpOutRaw != nil {
httpOut := httpOutRaw.(**http.Response)
*httpOut = resp
}
@ -29,6 +29,7 @@ func includeResponsePolicy(req *policy.Request) (*http.Response, 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.
// Deprecated: use [policy.WithCaptureResponse] instead.
func WithCaptureResponse(parent context.Context, resp **http.Response) context.Context {
return context.WithValue(parent, shared.CtxIncludeResponseKey{}, resp)
return policy.WithCaptureResponse(parent, resp)
}

View file

@ -0,0 +1,57 @@
// 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
}
// KeyCredentialPolicyOptions contains the optional values configuring [KeyCredentialPolicy].
type KeyCredentialPolicyOptions struct {
// 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,
}
}
// 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); 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()
}

View file

@ -191,7 +191,8 @@ func (p *logPolicy) writeHeader(b *bytes.Buffer, header http.Header) {
}
sort.Strings(keys)
for _, k := range keys {
value := header.Get(k)
// 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

View file

@ -59,15 +59,7 @@ func setDefaults(o *policy.RetryOptions) {
}
func calcDelay(o policy.RetryOptions, try int32) time.Duration { // try is >=1; never 0
pow := func(number int64, exponent int32) int64 { // pow is nested helper function
var result int64 = 1
for n := int32(0); n < exponent; n++ {
result *= number
}
return result
}
delay := time.Duration(pow(2, try)-1) * o.RetryDelay
delay := time.Duration((1<<try)-1) * o.RetryDelay
// Introduce some jitter: [0.0, 1.0) / 2 = [0.0, 0.5) + 0.8 = [0.8, 1.3)
delay = time.Duration(delay.Seconds() * (rand.Float64()/2 + 0.8) * float64(time.Second)) // NOTE: We want math/rand; not crypto/rand
@ -209,8 +201,9 @@ func (p *retryPolicy) Do(req *policy.Request) (resp *http.Response, err error) {
// 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 context.WithValue(parent, shared.CtxWithRetryOptionsKey{}, options)
return policy.WithRetryOptions(parent, options)
}
// ********** The following type/methods implement the retryableRequestBody (a ReadSeekCloser)

View file

@ -0,0 +1,47 @@
// 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
}
// SASCredentialPolicyOptions contains the optional values configuring [SASCredentialPolicy].
type SASCredentialPolicyOptions struct {
// placeholder for future optional values
}
// 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 {
return &SASCredentialPolicy{
cred: cred,
header: header,
}
}
// 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); err != nil {
return nil, err
}
req.Raw().Header.Add(k.header, exported.SASCredentialGet(k.cred))
}
return req.Next()
}

View file

@ -43,6 +43,10 @@ func NewTelemetryPolicy(mod, ver string, o *policy.TelemetryOptions) policy.Poli
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)

View file

@ -13,6 +13,8 @@ import (
"flag"
"fmt"
"net/http"
"reflect"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
@ -20,9 +22,11 @@ import (
"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"
)
@ -54,6 +58,9 @@ type NewPollerOptions[T any] struct {
// 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.
@ -70,6 +77,7 @@ func NewPoller[T any](resp *http.Response, pl exported.Pipeline, options *NewPol
op: options.Handler,
resp: resp,
result: result,
tracer: options.Tracer,
}, nil
}
@ -83,7 +91,9 @@ func NewPoller[T any](resp *http.Response, pl exported.Pipeline, options *NewPol
// determine the polling method
var opr PollingHandler[T]
var err error
if async.Applicable(resp) {
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) {
@ -110,6 +120,7 @@ func NewPoller[T any](resp *http.Response, pl exported.Pipeline, options *NewPol
op: opr,
resp: resp,
result: result,
tracer: options.Tracer,
}, nil
}
@ -121,6 +132,9 @@ type NewPollerFromResumeTokenOptions[T any] struct {
// 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.
@ -147,7 +161,9 @@ func NewPollerFromResumeToken[T any](token string, pl exported.Pipeline, options
opr := options.Handler
// now rehydrate the poller based on the encoded poller type
if opr != nil {
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, "")
@ -166,6 +182,7 @@ func NewPollerFromResumeToken[T any](token string, pl exported.Pipeline, options
return &Poller[T]{
op: opr,
result: result,
tracer: options.Tracer,
}, nil
}
@ -188,6 +205,7 @@ type Poller[T any] struct {
resp *http.Response
err error
result *T
tracer tracing.Tracer
done bool
}
@ -203,7 +221,7 @@ type PollUntilDoneOptions struct {
// 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) (T, error) {
func (p *Poller[T]) PollUntilDone(ctx context.Context, options *PollUntilDoneOptions) (res T, err error) {
if options == nil {
options = &PollUntilDoneOptions{}
}
@ -212,9 +230,13 @@ func (p *Poller[T]) PollUntilDone(ctx context.Context, options *PollUntilDoneOpt
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 {
return *new(T), errors.New("polling frequency minimum is one second")
err = errors.New("polling frequency minimum is one second")
return
}
start := time.Now()
@ -226,22 +248,24 @@ func (p *Poller[T]) PollUntilDone(ctx context.Context, options *PollUntilDoneOpt
// 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 {
if err = shared.Delay(ctx, retryAfter); err != nil {
logPollUntilDoneExit(err)
return *new(T), err
return
}
}
}
// begin polling the endpoint until a terminal state is reached
for {
resp, err := p.Poll(ctx)
var resp *http.Response
resp, err = p.Poll(ctx)
if err != nil {
logPollUntilDoneExit(err)
return *new(T), err
return
}
if p.Done() {
logPollUntilDoneExit("succeeded")
return p.Result(ctx)
res, err = p.Result(ctx)
return
}
d := cp.Frequency
if retryAfter := shared.RetryAfter(resp); retryAfter > 0 {
@ -252,7 +276,7 @@ func (p *Poller[T]) PollUntilDone(ctx context.Context, options *PollUntilDoneOpt
}
if err = shared.Delay(ctx, d); err != nil {
logPollUntilDoneExit(err)
return *new(T), err
return
}
}
}
@ -261,17 +285,22 @@ func (p *Poller[T]) PollUntilDone(ctx context.Context, options *PollUntilDoneOpt
// 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) (*http.Response, error) {
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
return p.resp, nil
resp = p.resp
return
}
resp, err := p.op.Poll(ctx)
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 nil, err
return
}
p.resp = resp
return p.resp, nil
return
}
// Done returns true if the LRO has reached a terminal state.
@ -284,31 +313,40 @@ func (p *Poller[T]) Done() bool {
// 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) (T, error) {
func (p *Poller[T]) Result(ctx context.Context) (res T, err error) {
if !p.Done() {
return *new(T), errors.New("poller is in a non-terminal state")
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 {
return *new(T), p.err
err = p.err
return
}
return *p.result, nil
res = *p.result
return
}
err := p.op.Result(ctx, p.result)
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) {
// 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 *new(T), err
return
}
p.done = true
if p.err != nil {
return *new(T), p.err
err = p.err
return
}
return *p.result, nil
res = *p.result
return
}
// ResumeToken returns a value representing the poller that can be used to resume
@ -325,3 +363,22 @@ func (p *Poller[T]) ResumeToken() (string, error) {
}
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:]
}

View file

@ -9,17 +9,14 @@ package runtime
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"mime/multipart"
"os"
"net/url"
"path"
"reflect"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
@ -28,14 +25,14 @@ import (
// 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 int
type Base64Encoding = exported.Base64Encoding
const (
// Base64StdFormat uses base64.StdEncoding for encoding and decoding payloads.
Base64StdFormat Base64Encoding = 0
Base64StdFormat Base64Encoding = exported.Base64StdFormat
// Base64URLFormat uses base64.RawURLEncoding for encoding and decoding payloads.
Base64URLFormat Base64Encoding = 1
Base64URLFormat Base64Encoding = exported.Base64URLFormat
)
// NewRequest creates a new policy.Request with the specified input.
@ -44,6 +41,19 @@ func NewRequest(ctx context.Context, httpMethod string, endpoint string) (*polic
return exported.NewRequest(ctx, httpMethod, endpoint)
}
// EncodeQueryParams will parse and encode any query parameters in the specified URL.
func EncodeQueryParams(u string) (string, error) {
before, after, found := strings.Cut(u, "?")
if !found {
return u, nil
}
qp, err := url.ParseQuery(after)
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
@ -79,10 +89,7 @@ func JoinPaths(root string, paths ...string) string {
// EncodeByteArray will base-64 encode the byte slice v.
func EncodeByteArray(v []byte, format Base64Encoding) string {
if format == Base64URLFormat {
return base64.RawURLEncoding.EncodeToString(v)
}
return base64.StdEncoding.EncodeToString(v)
return exported.EncodeByteArray(v, format)
}
// MarshalAsByteArray will base-64 encode the byte slice v, then calls SetBody.
@ -95,9 +102,6 @@ func MarshalAsByteArray(req *policy.Request, v []byte, format Base64Encoding) er
// MarshalAsJSON calls json.Marshal() to get the JSON encoding of v then calls SetBody.
func MarshalAsJSON(req *policy.Request, v interface{}) error {
if omit := os.Getenv("AZURE_SDK_GO_OMIT_READONLY"); omit == "true" {
v = cloneWithoutReadOnlyFields(v)
}
b, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("error marshalling type %T: %s", v, err)
@ -169,80 +173,5 @@ func SkipBodyDownload(req *policy.Request) {
req.SetOperationValue(bodyDownloadPolicyOpValues{Skip: true})
}
// returns a clone of the object graph pointed to by v, omitting values of all read-only
// fields. if there are no read-only fields in the object graph, no clone is created.
func cloneWithoutReadOnlyFields(v interface{}) interface{} {
val := reflect.Indirect(reflect.ValueOf(v))
if val.Kind() != reflect.Struct {
// not a struct, skip
return v
}
// first walk the graph to find any R/O fields.
// if there aren't any, skip cloning the graph.
if !recursiveFindReadOnlyField(val) {
return v
}
return recursiveCloneWithoutReadOnlyFields(val)
}
// returns true if any field in the object graph of val contains the `azure:"ro"` tag value
func recursiveFindReadOnlyField(val reflect.Value) bool {
t := val.Type()
// iterate over the fields, looking for the "azure" tag.
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
aztag := field.Tag.Get("azure")
if azureTagIsReadOnly(aztag) {
return true
} else if reflect.Indirect(val.Field(i)).Kind() == reflect.Struct && recursiveFindReadOnlyField(reflect.Indirect(val.Field(i))) {
return true
}
}
return false
}
// clones the object graph of val. all non-R/O properties are copied to the clone
func recursiveCloneWithoutReadOnlyFields(val reflect.Value) interface{} {
t := val.Type()
clone := reflect.New(t)
// iterate over the fields, looking for the "azure" tag.
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
aztag := field.Tag.Get("azure")
if azureTagIsReadOnly(aztag) {
// omit from payload
continue
}
// clone field will receive the same value as the source field...
value := val.Field(i)
v := reflect.Indirect(value)
if v.IsValid() && v.Type() != reflect.TypeOf(time.Time{}) && v.Kind() == reflect.Struct {
// ...unless the source value is a struct, in which case we recurse to clone that struct.
// (We can't recursively clone time.Time because it contains unexported fields.)
c := recursiveCloneWithoutReadOnlyFields(v)
if field.Anonymous {
// NOTE: this does not handle the case of embedded fields of unexported struct types.
// this should be ok as we don't generate any code like this at present
value = reflect.Indirect(reflect.ValueOf(c))
} else {
value = reflect.ValueOf(c)
}
}
reflect.Indirect(clone).Field(i).Set(value)
}
return clone.Interface()
}
// returns true if the "azure" tag contains the option "ro"
func azureTagIsReadOnly(tag string) bool {
if tag == "" {
return false
}
parts := strings.Split(tag, ",")
for _, part := range parts {
if part == "ro" {
return true
}
}
return false
}
// CtxAPINameKey is used as a context key for adding/retrieving the API name.
type CtxAPINameKey = shared.CtxAPINameKey

View file

@ -8,13 +8,13 @@ package runtime
import (
"bytes"
"encoding/base64"
"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"
)
@ -105,31 +105,5 @@ func removeBOM(resp *http.Response) error {
// DecodeByteArray will base-64 decode the provided string into v.
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)
}
return azexported.DecodeByteArray(s, v, format)
}

View file

@ -11,6 +11,8 @@ import (
"net"
"net/http"
"time"
"golang.org/x/net/http2"
)
var defaultHTTPClient *http.Client
@ -24,6 +26,7 @@ func init() {
}),
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
@ -32,6 +35,13 @@ func init() {
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,
}

View file

@ -31,12 +31,12 @@ type Provider struct {
newTracerFn func(name, version string) Tracer
}
// NewTracer creates a new Tracer for the specified name and version.
// - name - the name of the tracer object, typically the fully qualified name of the service client
// - version - the version of the module in which the service client resides
func (p Provider) NewTracer(name, version string) (tracer 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(name, version)
tracer = p.newTracerFn(module, version)
}
return
}
@ -45,21 +45,28 @@ func (p Provider) NewTracer(name, version string) (tracer Tracer) {
// TracerOptions contains the optional values when creating a Tracer.
type TracerOptions struct {
// for future expansion
// 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,
newSpanFn: newSpanFn,
spanFromContextFn: options.SpanFromContext,
}
}
// Tracer is the factory that creates Span instances.
type Tracer struct {
newSpanFn func(ctx context.Context, spanName string, options *SpanOptions) (context.Context, Span)
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.
@ -68,11 +75,37 @@ type Tracer struct {
// - 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 {
return t.newSpanFn(ctx, spanName, options)
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.
@ -97,9 +130,6 @@ type SpanImpl struct {
// AddEvent contains the implementation for the Span.AddEvent method.
AddEvent func(string, ...Attribute)
// AddError contains the implementation for the Span.AddError method.
AddError func(err error)
// SetStatus contains the implementation for the Span.SetStatus method.
SetStatus func(SpanStatus, string)
}
@ -140,13 +170,6 @@ func (s Span) AddEvent(name string, attrs ...Attribute) {
}
}
// AddError adds the specified error event to the span.
func (s Span) AddError(err error) {
if s.impl.AddError != nil {
s.impl.AddError(err)
}
}
// SetStatus sets the status on the span along with a description.
func (s Span) SetStatus(code SpanStatus, desc string) {
if s.impl.SetStatus != nil {

View file

@ -14,3 +14,33 @@ 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
}

View file

@ -1,5 +1,24 @@
# Release History
## 1.2.1 (2023-12-13)
### Features Added
* Exposed GetSASURL from specialized clients
### Bugs Fixed
* Fixed case in Blob Batch API when blob path has / in it. Fixes [#21649](https://github.com/Azure/azure-sdk-for-go/issues/21649).
* Fixed SharedKeyMissingError when using client.BlobClient().GetSASURL() method
* Fixed an issue that would cause metadata keys with empty values to be omitted when enumerating blobs.
* Fixed an issue where passing empty map to set blob tags API was causing panic. Fixes [#21869](https://github.com/Azure/azure-sdk-for-go/issues/21869).
* Fixed an issue where downloaded file has incorrect size when not a multiple of block size. Fixes [#21995](https://github.com/Azure/azure-sdk-for-go/issues/21995).
* Fixed case where `io.ErrUnexpectedEOF` was treated as expected error in `UploadStream`. Fixes [#21837](https://github.com/Azure/azure-sdk-for-go/issues/21837).
### Other Changes
* Updated the version of `azcore` to `1.9.1` and `azidentity` to `1.4.0`.
## 1.2.0 (2023-10-11)
### Bugs Fixed

View file

@ -10,6 +10,7 @@ import (
"context"
"errors"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
"io"
"os"
"time"
@ -338,6 +339,12 @@ func (ab *Client) CopyFromURL(ctx context.Context, copySource string, o *blob.Co
return blob.CopyFromURLResponse{}, errors.New("operation will not work on this blob type. CopyFromURL works only with block blob")
}
// GetSASURL is a convenience method for generating a SAS token for the currently pointed at append blob.
// It can only be used if the credential supplied during creation was a SharedKeyCredential.
func (ab *Client) GetSASURL(permissions sas.BlobPermissions, expiry time.Time, o *blob.GetSASURLOptions) (string, error) {
return ab.BlobClient().GetSASURL(permissions, expiry, o)
}
// Concurrent Download Functions -----------------------------------------------------------------------------------------
// DownloadStream reads a range of bytes from a blob. The response also includes the blob's properties and metadata.

View file

@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "go",
"TagPrefix": "go/storage/azblob",
"Tag": "go/storage/azblob_818d8addd0"
"Tag": "go/storage/azblob_0040e8284c"
}

View file

@ -464,7 +464,7 @@ func (b *Client) downloadFile(ctx context.Context, writer io.Writer, o downloadO
buffers := shared.NewMMBPool(int(o.Concurrency), o.BlockSize)
defer buffers.Free()
aquireBuffer := func() ([]byte, error) {
acquireBuffer := func() ([]byte, error) {
select {
case b := <-buffers.Acquire():
// got a buffer
@ -489,21 +489,23 @@ func (b *Client) downloadFile(ctx context.Context, writer io.Writer, o downloadO
/*
* We have created as many channels as the number of chunks we have.
* Each downloaded block will be sent to the channel matching its
* sequece number, i.e. 0th block is sent to 0th channel, 1st block
* sequence number, i.e. 0th block is sent to 0th channel, 1st block
* to 1st channel and likewise. The blocks are then read and written
* to the file serially by below goroutine. Do note that the blocks
* blocks are still downloaded parallelly from n/w, only serailized
* are still downloaded parallelly from n/w, only serialized
* and written to file here.
*/
writerError := make(chan error)
writeSize := int64(0)
go func(ch chan error) {
for _, block := range blocks {
select {
case <-ctx.Done():
return
case block := <-block:
_, err := writer.Write(block)
buffers.Release(block)
n, err := writer.Write(block)
writeSize += int64(n)
buffers.Release(block[:cap(block)])
if err != nil {
ch <- err
return
@ -521,7 +523,7 @@ func (b *Client) downloadFile(ctx context.Context, writer io.Writer, o downloadO
NumChunks: numChunks,
Concurrency: o.Concurrency,
Operation: func(ctx context.Context, chunkStart int64, count int64) error {
buff, err := aquireBuffer()
buff, err := acquireBuffer()
if err != nil {
return err
}
@ -538,8 +540,8 @@ func (b *Client) downloadFile(ctx context.Context, writer io.Writer, o downloadO
return err
}
blockIndex := (chunkStart / o.BlockSize)
blocks[blockIndex] <- buff
blockIndex := chunkStart / o.BlockSize
blocks[blockIndex] <- buff[:count]
return nil
},
})
@ -551,7 +553,7 @@ func (b *Client) downloadFile(ctx context.Context, writer io.Writer, o downloadO
if err = <-writerError; err != nil {
return 0, err
}
return count, nil
return writeSize, nil
}
// DownloadStream reads a range of bytes from a blob. The response also includes the blob's properties and metadata.

View file

@ -51,7 +51,7 @@ 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 but no zero value count indicates from the offset to the resource's end.
// which has an offset and zero value count indicates from the offset to the resource's end.
type HTTPRange = exported.HTTPRange
// Request Model Declaration -------------------------------------------------------------------------------------------

View file

@ -69,6 +69,7 @@ const (
CopyIDMismatch Code = "CopyIdMismatch"
EmptyMetadataKey Code = "EmptyMetadataKey"
FeatureVersionMismatch Code = "FeatureVersionMismatch"
ImmutabilityPolicyDeleteOnLockedPolicy Code = "ImmutabilityPolicyDeleteOnLockedPolicy"
IncrementalCopyBlobMismatch Code = "IncrementalCopyBlobMismatch"
IncrementalCopyOfEralierVersionSnapshotNotAllowed Code = "IncrementalCopyOfEralierVersionSnapshotNotAllowed"
IncrementalCopySourceMustBeSnapshot Code = "IncrementalCopySourceMustBeSnapshot"
@ -122,6 +123,7 @@ const (
NoAuthenticationInformation Code = "NoAuthenticationInformation"
NoPendingCopyOperation Code = "NoPendingCopyOperation"
OperationNotAllowedOnIncrementalCopyBlob Code = "OperationNotAllowedOnIncrementalCopyBlob"
OperationNotAllowedOnRootBlob Code = "OperationNotAllowedOnRootBlob"
OperationTimedOut Code = "OperationTimedOut"
OutOfRangeInput Code = "OutOfRangeInput"
OutOfRangeQueryParameterValue Code = "OutOfRangeQueryParameterValue"

View file

@ -75,7 +75,7 @@ func copyFromReader[T ~[]byte](ctx context.Context, src io.Reader, dst blockWrit
}
var n int
n, err = io.ReadFull(src, buffer)
n, err = shared.ReadAtLeast(src, buffer, len(buffer))
if n > 0 {
// some data was read, upload it
@ -108,7 +108,7 @@ func copyFromReader[T ~[]byte](ctx context.Context, src io.Reader, dst blockWrit
}
if err != nil { // The reader is done, no more outgoing buffers
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
if errors.Is(err, io.EOF) {
// these are expected errors, we don't surface those
err = nil
} else {

View file

@ -13,6 +13,7 @@ import (
"errors"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
"io"
"math"
"os"
@ -129,7 +130,7 @@ func (bb *Client) URL() string {
return bb.generated().Endpoint()
}
// BlobClient returns the embedded blob client for this AppendBlob client.
// 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)
@ -410,6 +411,12 @@ func (bb *Client) CopyFromURL(ctx context.Context, copySource string, o *blob.Co
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.

View file

@ -26,6 +26,7 @@ stages:
parameters:
ServiceDirectory: 'storage/azblob'
RunLiveTests: true
UsePipelineProxy: false
EnvVars:
AZURE_CLIENT_ID: $(AZBLOB_CLIENT_ID)
AZURE_TENANT_ID: $(AZBLOB_TENANT_ID)

View file

@ -32,5 +32,5 @@ func ParseURL(u string) (URLParts, error) {
// 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 but no zero value count indicates from the offset to the resource's end.
// which has an offset and zero value count indicates from the offset to the resource's end.
type HTTPRange = exported.HTTPRange

View file

@ -71,7 +71,10 @@ type CompositeClient[T, U any] struct {
}
func InnerClients[T, U any](client *CompositeClient[T, U]) (*Client[T], *U) {
return &Client[T]{inner: client.innerT}, client.innerU
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] {

View file

@ -49,7 +49,7 @@ func createBatchID() (string, error) {
// Content-Length: 0
func buildSubRequest(req *policy.Request) []byte {
var batchSubRequest strings.Builder
blobPath := req.Raw().URL.Path
blobPath := req.Raw().URL.EscapedPath()
if len(req.Raw().URL.RawQuery) > 0 {
blobPath += "?" + req.Raw().URL.RawQuery
}

View file

@ -13,7 +13,7 @@ import (
// 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 but no zero value count indicates from the offset to the resource's end.
// which has an offset and zero value count indicates from the offset to the resource's end.
type HTTPRange struct {
Offset int64
Count int64

View file

@ -8,5 +8,5 @@ package exported
const (
ModuleName = "azblob"
ModuleVersion = "v1.2.0"
ModuleVersion = "v1.2.1"
)

View file

@ -19,7 +19,7 @@ modelerfour:
seal-single-value-enum-by-default: true
lenient-model-deduplication: true
export-clients: true
use: "@autorest/go@4.0.0-preview.49"
use: "@autorest/go@4.0.0-preview.61"
```
### Updating service version to 2023-08-03
@ -280,7 +280,9 @@ directive:
``` yaml
directive:
- from: zz_models.go
- from:
- zz_models.go
- zz_options.go
where: $
transform: >-
return $.
@ -443,8 +445,8 @@ directive:
where: $
transform: >-
return $.
replace(/if\s+!runtime\.HasStatusCode\(resp,\s+http\.StatusOK\)\s+\{\s*\n\t\treturn\s+ServiceClientSubmitBatchResponse\{\}\,\s+runtime\.NewResponseError\(resp\)\s*\n\t\}/g,
`if !runtime.HasStatusCode(resp, http.StatusAccepted) {\n\t\treturn ServiceClientSubmitBatchResponse{}, runtime.NewResponseError(resp)\n\t}`);
replace(/if\s+!runtime\.HasStatusCode\(httpResp,\s+http\.StatusOK\)\s+\{\s+err\s+=\s+runtime\.NewResponseError\(httpResp\)\s+return ServiceClientSubmitBatchResponse\{\}\,\s+err\s+}/g,
`if !runtime.HasStatusCode(httpResp, http.StatusAccepted) {\n\t\terr = runtime.NewResponseError(httpResp)\n\t\treturn ServiceClientSubmitBatchResponse{}, err\n\t}`);
```
### Convert time to GMT for If-Modified-Since and If-Unmodified-Since request headers

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -44,18 +43,21 @@ type AppendBlobClient struct {
// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *AppendBlobClient) AppendBlock(ctx context.Context, contentLength int64, body io.ReadSeekCloser, options *AppendBlobClientAppendBlockOptions, leaseAccessConditions *LeaseAccessConditions, appendPositionAccessConditions *AppendPositionAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, modifiedAccessConditions *ModifiedAccessConditions) (AppendBlobClientAppendBlockResponse, error) {
var err error
req, err := client.appendBlockCreateRequest(ctx, contentLength, body, options, leaseAccessConditions, appendPositionAccessConditions, cpkInfo, cpkScopeInfo, modifiedAccessConditions)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return AppendBlobClientAppendBlockResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return AppendBlobClientAppendBlockResponse{}, err
}
return client.appendBlockHandleResponse(resp)
resp, err := client.appendBlockHandleResponse(httpResp)
return resp, err
}
// appendBlockCreateRequest creates the AppendBlock request.
@ -127,46 +129,6 @@ func (client *AppendBlobClient) appendBlockCreateRequest(ctx context.Context, co
// appendBlockHandleResponse handles the AppendBlock response.
func (client *AppendBlobClient) appendBlockHandleResponse(resp *http.Response) (AppendBlobClientAppendBlockResponse, error) {
result := AppendBlobClientAppendBlockResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-blob-append-offset"); val != "" {
result.BlobAppendOffset = &val
}
@ -178,6 +140,39 @@ func (client *AppendBlobClient) appendBlockHandleResponse(resp *http.Response) (
}
result.BlobCommittedBlockCount = &blobCommittedBlockCount
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
@ -185,11 +180,18 @@ func (client *AppendBlobClient) appendBlockHandleResponse(resp *http.Response) (
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -213,18 +215,21 @@ func (client *AppendBlobClient) appendBlockHandleResponse(resp *http.Response) (
// - SourceModifiedAccessConditions - SourceModifiedAccessConditions contains a group of parameters for the BlobClient.StartCopyFromURL
// method.
func (client *AppendBlobClient) AppendBlockFromURL(ctx context.Context, sourceURL string, contentLength int64, options *AppendBlobClientAppendBlockFromURLOptions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, leaseAccessConditions *LeaseAccessConditions, appendPositionAccessConditions *AppendPositionAccessConditions, modifiedAccessConditions *ModifiedAccessConditions, sourceModifiedAccessConditions *SourceModifiedAccessConditions) (AppendBlobClientAppendBlockFromURLResponse, error) {
var err error
req, err := client.appendBlockFromURLCreateRequest(ctx, sourceURL, contentLength, options, cpkInfo, cpkScopeInfo, leaseAccessConditions, appendPositionAccessConditions, modifiedAccessConditions, sourceModifiedAccessConditions)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return AppendBlobClientAppendBlockFromURLResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
return client.appendBlockFromURLHandleResponse(resp)
resp, err := client.appendBlockFromURLHandleResponse(httpResp)
return resp, err
}
// appendBlockFromURLCreateRequest creates the AppendBlockFromURL request.
@ -315,43 +320,6 @@ func (client *AppendBlobClient) appendBlockFromURLCreateRequest(ctx context.Cont
// appendBlockFromURLHandleResponse handles the AppendBlockFromURL response.
func (client *AppendBlobClient) appendBlockFromURLHandleResponse(resp *http.Response) (AppendBlobClientAppendBlockFromURLResponse, error) {
result := AppendBlobClientAppendBlockFromURLResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-blob-append-offset"); val != "" {
result.BlobAppendOffset = &val
}
@ -363,6 +331,30 @@ func (client *AppendBlobClient) appendBlockFromURLHandleResponse(resp *http.Resp
}
result.BlobCommittedBlockCount = &blobCommittedBlockCount
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
@ -376,6 +368,19 @@ func (client *AppendBlobClient) appendBlockFromURLHandleResponse(resp *http.Resp
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientAppendBlockFromURLResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -391,18 +396,21 @@ func (client *AppendBlobClient) appendBlockFromURLHandleResponse(resp *http.Resp
// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *AppendBlobClient) Create(ctx context.Context, contentLength int64, options *AppendBlobClientCreateOptions, blobHTTPHeaders *BlobHTTPHeaders, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, modifiedAccessConditions *ModifiedAccessConditions) (AppendBlobClientCreateResponse, error) {
var err error
req, err := client.createCreateRequest(ctx, contentLength, options, blobHTTPHeaders, leaseAccessConditions, cpkInfo, cpkScopeInfo, modifiedAccessConditions)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return AppendBlobClientCreateResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return AppendBlobClientCreateResponse{}, err
}
return client.createHandleResponse(resp)
resp, err := client.createHandleResponse(httpResp)
return resp, err
}
// createCreateRequest creates the Create request.
@ -496,15 +504,8 @@ func (client *AppendBlobClient) createCreateRequest(ctx context.Context, content
// createHandleResponse handles the Create response.
func (client *AppendBlobClient) createHandleResponse(resp *http.Response) (AppendBlobClientCreateResponse, error) {
result := AppendBlobClientCreateResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
result.LastModified = &lastModified
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
@ -513,8 +514,35 @@ func (client *AppendBlobClient) createHandleResponse(resp *http.Response) (Appen
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
@ -525,26 +553,6 @@ func (client *AppendBlobClient) createHandleResponse(resp *http.Response) (Appen
if val := resp.Header.Get("x-ms-version-id"); val != "" {
result.VersionID = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return AppendBlobClientCreateResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
return result, nil
}
@ -559,18 +567,21 @@ func (client *AppendBlobClient) createHandleResponse(resp *http.Response) (Appen
// - AppendPositionAccessConditions - AppendPositionAccessConditions contains a group of parameters for the AppendBlobClient.AppendBlock
// method.
func (client *AppendBlobClient) Seal(ctx context.Context, options *AppendBlobClientSealOptions, leaseAccessConditions *LeaseAccessConditions, modifiedAccessConditions *ModifiedAccessConditions, appendPositionAccessConditions *AppendPositionAccessConditions) (AppendBlobClientSealResponse, error) {
var err error
req, err := client.sealCreateRequest(ctx, options, leaseAccessConditions, modifiedAccessConditions, appendPositionAccessConditions)
if err != nil {
return AppendBlobClientSealResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return AppendBlobClientSealResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return AppendBlobClientSealResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return AppendBlobClientSealResponse{}, err
}
return client.sealHandleResponse(resp)
resp, err := client.sealHandleResponse(httpResp)
return resp, err
}
// sealCreateRequest creates the Seal request.
@ -614,25 +625,9 @@ func (client *AppendBlobClient) sealCreateRequest(ctx context.Context, options *
// sealHandleResponse handles the Seal response.
func (client *AppendBlobClient) sealHandleResponse(resp *http.Response) (AppendBlobClientSealResponse, error) {
result := AppendBlobClientSealResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientSealResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -640,6 +635,9 @@ func (client *AppendBlobClient) sealHandleResponse(resp *http.Response) (AppendB
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-blob-sealed"); val != "" {
isSealed, err := strconv.ParseBool(val)
if err != nil {
@ -647,5 +645,18 @@ func (client *AppendBlobClient) sealHandleResponse(resp *http.Response) (AppendB
}
result.IsSealed = &isSealed
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return AppendBlobClientSealResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -47,18 +46,21 @@ type BlockBlobClient struct {
// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *BlockBlobClient) CommitBlockList(ctx context.Context, blocks BlockLookupList, options *BlockBlobClientCommitBlockListOptions, blobHTTPHeaders *BlobHTTPHeaders, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, modifiedAccessConditions *ModifiedAccessConditions) (BlockBlobClientCommitBlockListResponse, error) {
var err error
req, err := client.commitBlockListCreateRequest(ctx, blocks, options, blobHTTPHeaders, leaseAccessConditions, cpkInfo, cpkScopeInfo, modifiedAccessConditions)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return BlockBlobClientCommitBlockListResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return BlockBlobClientCommitBlockListResponse{}, err
}
return client.commitBlockListHandleResponse(resp)
resp, err := client.commitBlockListHandleResponse(httpResp)
return resp, err
}
// commitBlockListCreateRequest creates the CommitBlockList request.
@ -163,22 +165,8 @@ func (client *BlockBlobClient) commitBlockListCreateRequest(ctx context.Context,
// commitBlockListHandleResponse handles the CommitBlockList response.
func (client *BlockBlobClient) commitBlockListHandleResponse(resp *http.Response) (BlockBlobClientCommitBlockListResponse, error) {
result := BlockBlobClientCommitBlockListResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.ContentMD5 = contentMD5
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
@ -187,8 +175,42 @@ func (client *BlockBlobClient) commitBlockListHandleResponse(resp *http.Response
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
@ -199,26 +221,6 @@ func (client *BlockBlobClient) commitBlockListHandleResponse(resp *http.Response
if val := resp.Header.Get("x-ms-version-id"); val != "" {
result.VersionID = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return BlockBlobClientCommitBlockListResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
return result, nil
}
@ -231,18 +233,21 @@ func (client *BlockBlobClient) commitBlockListHandleResponse(resp *http.Response
// - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *BlockBlobClient) GetBlockList(ctx context.Context, listType BlockListType, options *BlockBlobClientGetBlockListOptions, leaseAccessConditions *LeaseAccessConditions, modifiedAccessConditions *ModifiedAccessConditions) (BlockBlobClientGetBlockListResponse, error) {
var err error
req, err := client.getBlockListCreateRequest(ctx, listType, options, leaseAccessConditions, modifiedAccessConditions)
if err != nil {
return BlockBlobClientGetBlockListResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return BlockBlobClientGetBlockListResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return BlockBlobClientGetBlockListResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return BlockBlobClientGetBlockListResponse{}, err
}
return client.getBlockListHandleResponse(resp)
resp, err := client.getBlockListHandleResponse(httpResp)
return resp, err
}
// getBlockListCreateRequest creates the GetBlockList request.
@ -278,19 +283,6 @@ func (client *BlockBlobClient) getBlockListCreateRequest(ctx context.Context, li
// getBlockListHandleResponse handles the GetBlockList response.
func (client *BlockBlobClient) getBlockListHandleResponse(resp *http.Response) (BlockBlobClientGetBlockListResponse, error) {
result := BlockBlobClientGetBlockListResponse{}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientGetBlockListResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Content-Type"); val != "" {
result.ContentType = &val
}
if val := resp.Header.Get("x-ms-blob-content-length"); val != "" {
blobContentLength, err := strconv.ParseInt(val, 10, 64)
if err != nil {
@ -301,11 +293,8 @@ func (client *BlockBlobClient) getBlockListHandleResponse(resp *http.Response) (
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
if val := resp.Header.Get("Content-Type"); val != "" {
result.ContentType = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
@ -314,6 +303,22 @@ func (client *BlockBlobClient) getBlockListHandleResponse(resp *http.Response) (
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientGetBlockListResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if err := runtime.UnmarshalAsXML(resp, &result.BlockList); err != nil {
return BlockBlobClientGetBlockListResponse{}, err
}
@ -342,18 +347,21 @@ func (client *BlockBlobClient) getBlockListHandleResponse(resp *http.Response) (
// - SourceModifiedAccessConditions - SourceModifiedAccessConditions contains a group of parameters for the BlobClient.StartCopyFromURL
// method.
func (client *BlockBlobClient) PutBlobFromURL(ctx context.Context, contentLength int64, copySource string, options *BlockBlobClientPutBlobFromURLOptions, blobHTTPHeaders *BlobHTTPHeaders, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, modifiedAccessConditions *ModifiedAccessConditions, sourceModifiedAccessConditions *SourceModifiedAccessConditions) (BlockBlobClientPutBlobFromURLResponse, error) {
var err error
req, err := client.putBlobFromURLCreateRequest(ctx, contentLength, copySource, options, blobHTTPHeaders, leaseAccessConditions, cpkInfo, cpkScopeInfo, modifiedAccessConditions, sourceModifiedAccessConditions)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return BlockBlobClientPutBlobFromURLResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return BlockBlobClientPutBlobFromURLResponse{}, err
}
return client.putBlobFromURLHandleResponse(resp)
resp, err := client.putBlobFromURLHandleResponse(httpResp)
return resp, err
}
// putBlobFromURLCreateRequest creates the PutBlobFromURL request.
@ -472,15 +480,8 @@ func (client *BlockBlobClient) putBlobFromURLCreateRequest(ctx context.Context,
// putBlobFromURLHandleResponse handles the PutBlobFromURL response.
func (client *BlockBlobClient) putBlobFromURLHandleResponse(resp *http.Response) (BlockBlobClientPutBlobFromURLResponse, error) {
result := BlockBlobClientPutBlobFromURLResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
result.LastModified = &lastModified
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
@ -489,8 +490,35 @@ func (client *BlockBlobClient) putBlobFromURLHandleResponse(resp *http.Response)
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
@ -501,26 +529,6 @@ func (client *BlockBlobClient) putBlobFromURLHandleResponse(resp *http.Response)
if val := resp.Header.Get("x-ms-version-id"); val != "" {
result.VersionID = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return BlockBlobClientPutBlobFromURLResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
return result, nil
}
@ -538,18 +546,21 @@ func (client *BlockBlobClient) putBlobFromURLHandleResponse(resp *http.Response)
// - CPKInfo - CPKInfo contains a group of parameters for the BlobClient.Download method.
// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method.
func (client *BlockBlobClient) StageBlock(ctx context.Context, blockID string, contentLength int64, body io.ReadSeekCloser, options *BlockBlobClientStageBlockOptions, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo) (BlockBlobClientStageBlockResponse, error) {
var err error
req, err := client.stageBlockCreateRequest(ctx, blockID, contentLength, body, options, leaseAccessConditions, cpkInfo, cpkScopeInfo)
if err != nil {
return BlockBlobClientStageBlockResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return BlockBlobClientStageBlockResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return BlockBlobClientStageBlockResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return BlockBlobClientStageBlockResponse{}, err
}
return client.stageBlockHandleResponse(resp)
resp, err := client.stageBlockHandleResponse(httpResp)
return resp, err
}
// stageBlockCreateRequest creates the StageBlock request.
@ -601,29 +612,9 @@ func (client *BlockBlobClient) stageBlockCreateRequest(ctx context.Context, bloc
// stageBlockHandleResponse handles the StageBlock response.
func (client *BlockBlobClient) stageBlockHandleResponse(resp *http.Response) (BlockBlobClientStageBlockResponse, error) {
result := BlockBlobClientStageBlockResponse{}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return BlockBlobClientStageBlockResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientStageBlockResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
@ -631,6 +622,26 @@ func (client *BlockBlobClient) stageBlockHandleResponse(resp *http.Response) (Bl
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return BlockBlobClientStageBlockResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientStageBlockResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
@ -638,11 +649,11 @@ func (client *BlockBlobClient) stageBlockHandleResponse(resp *http.Response) (Bl
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -665,18 +676,21 @@ func (client *BlockBlobClient) stageBlockHandleResponse(resp *http.Response) (Bl
// - SourceModifiedAccessConditions - SourceModifiedAccessConditions contains a group of parameters for the BlobClient.StartCopyFromURL
// method.
func (client *BlockBlobClient) StageBlockFromURL(ctx context.Context, blockID string, contentLength int64, sourceURL string, options *BlockBlobClientStageBlockFromURLOptions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, leaseAccessConditions *LeaseAccessConditions, sourceModifiedAccessConditions *SourceModifiedAccessConditions) (BlockBlobClientStageBlockFromURLResponse, error) {
var err error
req, err := client.stageBlockFromURLCreateRequest(ctx, blockID, contentLength, sourceURL, options, cpkInfo, cpkScopeInfo, leaseAccessConditions, sourceModifiedAccessConditions)
if err != nil {
return BlockBlobClientStageBlockFromURLResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return BlockBlobClientStageBlockFromURLResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return BlockBlobClientStageBlockFromURLResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return BlockBlobClientStageBlockFromURLResponse{}, err
}
return client.stageBlockFromURLHandleResponse(resp)
resp, err := client.stageBlockFromURLHandleResponse(httpResp)
return resp, err
}
// stageBlockFromURLCreateRequest creates the StageBlockFromURL request.
@ -744,12 +758,8 @@ func (client *BlockBlobClient) stageBlockFromURLCreateRequest(ctx context.Contex
// stageBlockFromURLHandleResponse handles the StageBlockFromURL response.
func (client *BlockBlobClient) stageBlockFromURLHandleResponse(resp *http.Response) (BlockBlobClientStageBlockFromURLResponse, error) {
result := BlockBlobClientStageBlockFromURLResponse{}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return BlockBlobClientStageBlockFromURLResponse{}, err
}
result.ContentMD5 = contentMD5
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
@ -758,14 +768,12 @@ func (client *BlockBlobClient) stageBlockFromURLHandleResponse(resp *http.Respon
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return BlockBlobClientStageBlockFromURLResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
@ -774,6 +782,12 @@ func (client *BlockBlobClient) stageBlockFromURLHandleResponse(resp *http.Respon
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
@ -781,11 +795,11 @@ func (client *BlockBlobClient) stageBlockFromURLHandleResponse(resp *http.Respon
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -806,18 +820,21 @@ func (client *BlockBlobClient) stageBlockFromURLHandleResponse(resp *http.Respon
// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *BlockBlobClient) Upload(ctx context.Context, contentLength int64, body io.ReadSeekCloser, options *BlockBlobClientUploadOptions, blobHTTPHeaders *BlobHTTPHeaders, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, modifiedAccessConditions *ModifiedAccessConditions) (BlockBlobClientUploadResponse, error) {
var err error
req, err := client.uploadCreateRequest(ctx, contentLength, body, options, blobHTTPHeaders, leaseAccessConditions, cpkInfo, cpkScopeInfo, modifiedAccessConditions)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return BlockBlobClientUploadResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return BlockBlobClientUploadResponse{}, err
}
return client.uploadHandleResponse(resp)
resp, err := client.uploadHandleResponse(httpResp)
return resp, err
}
// uploadCreateRequest creates the Upload request.
@ -923,15 +940,8 @@ func (client *BlockBlobClient) uploadCreateRequest(ctx context.Context, contentL
// uploadHandleResponse handles the Upload response.
func (client *BlockBlobClient) uploadHandleResponse(resp *http.Response) (BlockBlobClientUploadResponse, error) {
result := BlockBlobClientUploadResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
result.LastModified = &lastModified
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
@ -940,8 +950,35 @@ func (client *BlockBlobClient) uploadHandleResponse(resp *http.Response) (BlockB
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
@ -952,25 +989,5 @@ func (client *BlockBlobClient) uploadHandleResponse(resp *http.Response) (BlockB
if val := resp.Header.Get("x-ms-version-id"); val != "" {
result.VersionID = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return BlockBlobClientUploadResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
return result, nil
}

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated

File diff suppressed because it is too large Load diff

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -24,12 +23,12 @@ func (a AccessPolicy) MarshalXML(enc *xml.Encoder, start xml.StartElement) error
type alias AccessPolicy
aux := &struct {
*alias
Expiry *timeRFC3339 `xml:"Expiry"`
Start *timeRFC3339 `xml:"Start"`
Expiry *dateTimeRFC3339 `xml:"Expiry"`
Start *dateTimeRFC3339 `xml:"Start"`
}{
alias: (*alias)(&a),
Expiry: (*timeRFC3339)(a.Expiry),
Start: (*timeRFC3339)(a.Start),
Expiry: (*dateTimeRFC3339)(a.Expiry),
Start: (*dateTimeRFC3339)(a.Start),
}
return enc.EncodeElement(aux, start)
}
@ -39,8 +38,8 @@ func (a *AccessPolicy) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) er
type alias AccessPolicy
aux := &struct {
*alias
Expiry *timeRFC3339 `xml:"Expiry"`
Start *timeRFC3339 `xml:"Start"`
Expiry *dateTimeRFC3339 `xml:"Expiry"`
Start *dateTimeRFC3339 `xml:"Start"`
}{
alias: (*alias)(a),
}
@ -106,25 +105,25 @@ func (b BlobProperties) MarshalXML(enc *xml.Encoder, start xml.StartElement) err
type alias BlobProperties
aux := &struct {
*alias
AccessTierChangeTime *timeRFC1123 `xml:"AccessTierChangeTime"`
ContentMD5 *string `xml:"Content-MD5"`
CopyCompletionTime *timeRFC1123 `xml:"CopyCompletionTime"`
CreationTime *timeRFC1123 `xml:"Creation-Time"`
DeletedTime *timeRFC1123 `xml:"DeletedTime"`
ExpiresOn *timeRFC1123 `xml:"Expiry-Time"`
ImmutabilityPolicyExpiresOn *timeRFC1123 `xml:"ImmutabilityPolicyUntilDate"`
LastAccessedOn *timeRFC1123 `xml:"LastAccessTime"`
LastModified *timeRFC1123 `xml:"Last-Modified"`
AccessTierChangeTime *dateTimeRFC1123 `xml:"AccessTierChangeTime"`
ContentMD5 *string `xml:"Content-MD5"`
CopyCompletionTime *dateTimeRFC1123 `xml:"CopyCompletionTime"`
CreationTime *dateTimeRFC1123 `xml:"Creation-Time"`
DeletedTime *dateTimeRFC1123 `xml:"DeletedTime"`
ExpiresOn *dateTimeRFC1123 `xml:"Expiry-Time"`
ImmutabilityPolicyExpiresOn *dateTimeRFC1123 `xml:"ImmutabilityPolicyUntilDate"`
LastAccessedOn *dateTimeRFC1123 `xml:"LastAccessTime"`
LastModified *dateTimeRFC1123 `xml:"Last-Modified"`
}{
alias: (*alias)(&b),
AccessTierChangeTime: (*timeRFC1123)(b.AccessTierChangeTime),
CopyCompletionTime: (*timeRFC1123)(b.CopyCompletionTime),
CreationTime: (*timeRFC1123)(b.CreationTime),
DeletedTime: (*timeRFC1123)(b.DeletedTime),
ExpiresOn: (*timeRFC1123)(b.ExpiresOn),
ImmutabilityPolicyExpiresOn: (*timeRFC1123)(b.ImmutabilityPolicyExpiresOn),
LastAccessedOn: (*timeRFC1123)(b.LastAccessedOn),
LastModified: (*timeRFC1123)(b.LastModified),
AccessTierChangeTime: (*dateTimeRFC1123)(b.AccessTierChangeTime),
CopyCompletionTime: (*dateTimeRFC1123)(b.CopyCompletionTime),
CreationTime: (*dateTimeRFC1123)(b.CreationTime),
DeletedTime: (*dateTimeRFC1123)(b.DeletedTime),
ExpiresOn: (*dateTimeRFC1123)(b.ExpiresOn),
ImmutabilityPolicyExpiresOn: (*dateTimeRFC1123)(b.ImmutabilityPolicyExpiresOn),
LastAccessedOn: (*dateTimeRFC1123)(b.LastAccessedOn),
LastModified: (*dateTimeRFC1123)(b.LastModified),
}
if b.ContentMD5 != nil {
encodedContentMD5 := runtime.EncodeByteArray(b.ContentMD5, runtime.Base64StdFormat)
@ -138,15 +137,15 @@ func (b *BlobProperties) UnmarshalXML(dec *xml.Decoder, start xml.StartElement)
type alias BlobProperties
aux := &struct {
*alias
AccessTierChangeTime *timeRFC1123 `xml:"AccessTierChangeTime"`
ContentMD5 *string `xml:"Content-MD5"`
CopyCompletionTime *timeRFC1123 `xml:"CopyCompletionTime"`
CreationTime *timeRFC1123 `xml:"Creation-Time"`
DeletedTime *timeRFC1123 `xml:"DeletedTime"`
ExpiresOn *timeRFC1123 `xml:"Expiry-Time"`
ImmutabilityPolicyExpiresOn *timeRFC1123 `xml:"ImmutabilityPolicyUntilDate"`
LastAccessedOn *timeRFC1123 `xml:"LastAccessTime"`
LastModified *timeRFC1123 `xml:"Last-Modified"`
AccessTierChangeTime *dateTimeRFC1123 `xml:"AccessTierChangeTime"`
ContentMD5 *string `xml:"Content-MD5"`
CopyCompletionTime *dateTimeRFC1123 `xml:"CopyCompletionTime"`
CreationTime *dateTimeRFC1123 `xml:"Creation-Time"`
DeletedTime *dateTimeRFC1123 `xml:"DeletedTime"`
ExpiresOn *dateTimeRFC1123 `xml:"Expiry-Time"`
ImmutabilityPolicyExpiresOn *dateTimeRFC1123 `xml:"ImmutabilityPolicyUntilDate"`
LastAccessedOn *dateTimeRFC1123 `xml:"LastAccessTime"`
LastModified *dateTimeRFC1123 `xml:"Last-Modified"`
}{
alias: (*alias)(b),
}
@ -249,12 +248,12 @@ func (c ContainerProperties) MarshalXML(enc *xml.Encoder, start xml.StartElement
type alias ContainerProperties
aux := &struct {
*alias
DeletedTime *timeRFC1123 `xml:"DeletedTime"`
LastModified *timeRFC1123 `xml:"Last-Modified"`
DeletedTime *dateTimeRFC1123 `xml:"DeletedTime"`
LastModified *dateTimeRFC1123 `xml:"Last-Modified"`
}{
alias: (*alias)(&c),
DeletedTime: (*timeRFC1123)(c.DeletedTime),
LastModified: (*timeRFC1123)(c.LastModified),
DeletedTime: (*dateTimeRFC1123)(c.DeletedTime),
LastModified: (*dateTimeRFC1123)(c.LastModified),
}
return enc.EncodeElement(aux, start)
}
@ -264,8 +263,8 @@ func (c *ContainerProperties) UnmarshalXML(dec *xml.Decoder, start xml.StartElem
type alias ContainerProperties
aux := &struct {
*alias
DeletedTime *timeRFC1123 `xml:"DeletedTime"`
LastModified *timeRFC1123 `xml:"Last-Modified"`
DeletedTime *dateTimeRFC1123 `xml:"DeletedTime"`
LastModified *dateTimeRFC1123 `xml:"Last-Modified"`
}{
alias: (*alias)(c),
}
@ -297,10 +296,10 @@ func (g GeoReplication) MarshalXML(enc *xml.Encoder, start xml.StartElement) err
type alias GeoReplication
aux := &struct {
*alias
LastSyncTime *timeRFC1123 `xml:"LastSyncTime"`
LastSyncTime *dateTimeRFC1123 `xml:"LastSyncTime"`
}{
alias: (*alias)(&g),
LastSyncTime: (*timeRFC1123)(g.LastSyncTime),
LastSyncTime: (*dateTimeRFC1123)(g.LastSyncTime),
}
return enc.EncodeElement(aux, start)
}
@ -310,7 +309,7 @@ func (g *GeoReplication) UnmarshalXML(dec *xml.Decoder, start xml.StartElement)
type alias GeoReplication
aux := &struct {
*alias
LastSyncTime *timeRFC1123 `xml:"LastSyncTime"`
LastSyncTime *dateTimeRFC1123 `xml:"LastSyncTime"`
}{
alias: (*alias)(g),
}
@ -414,12 +413,12 @@ func (u UserDelegationKey) MarshalXML(enc *xml.Encoder, start xml.StartElement)
type alias UserDelegationKey
aux := &struct {
*alias
SignedExpiry *timeRFC3339 `xml:"SignedExpiry"`
SignedStart *timeRFC3339 `xml:"SignedStart"`
SignedExpiry *dateTimeRFC3339 `xml:"SignedExpiry"`
SignedStart *dateTimeRFC3339 `xml:"SignedStart"`
}{
alias: (*alias)(&u),
SignedExpiry: (*timeRFC3339)(u.SignedExpiry),
SignedStart: (*timeRFC3339)(u.SignedStart),
SignedExpiry: (*dateTimeRFC3339)(u.SignedExpiry),
SignedStart: (*dateTimeRFC3339)(u.SignedStart),
}
return enc.EncodeElement(aux, start)
}
@ -429,8 +428,8 @@ func (u *UserDelegationKey) UnmarshalXML(dec *xml.Decoder, start xml.StartElemen
type alias UserDelegationKey
aux := &struct {
*alias
SignedExpiry *timeRFC3339 `xml:"SignedExpiry"`
SignedStart *timeRFC3339 `xml:"SignedStart"`
SignedExpiry *dateTimeRFC3339 `xml:"SignedExpiry"`
SignedStart *dateTimeRFC3339 `xml:"SignedStart"`
}{
alias: (*alias)(u),
}

File diff suppressed because it is too large Load diff

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -41,18 +40,21 @@ type PageBlobClient struct {
// method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *PageBlobClient) ClearPages(ctx context.Context, contentLength int64, options *PageBlobClientClearPagesOptions, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, sequenceNumberAccessConditions *SequenceNumberAccessConditions, modifiedAccessConditions *ModifiedAccessConditions) (PageBlobClientClearPagesResponse, error) {
var err error
req, err := client.clearPagesCreateRequest(ctx, contentLength, options, leaseAccessConditions, cpkInfo, cpkScopeInfo, sequenceNumberAccessConditions, modifiedAccessConditions)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return PageBlobClientClearPagesResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return PageBlobClientClearPagesResponse{}, err
}
return client.clearPagesHandleResponse(resp)
resp, err := client.clearPagesHandleResponse(httpResp)
return resp, err
}
// clearPagesCreateRequest creates the ClearPages request.
@ -122,30 +124,6 @@ func (client *PageBlobClient) clearPagesCreateRequest(ctx context.Context, conte
// clearPagesHandleResponse handles the ClearPages response.
func (client *PageBlobClient) clearPagesHandleResponse(resp *http.Response) (PageBlobClientClearPagesResponse, error) {
result := PageBlobClientClearPagesResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-blob-sequence-number"); val != "" {
blobSequenceNumber, err := strconv.ParseInt(val, 10, 64)
if err != nil {
@ -156,11 +134,19 @@ func (client *PageBlobClient) clearPagesHandleResponse(resp *http.Response) (Pag
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
@ -169,6 +155,22 @@ func (client *PageBlobClient) clearPagesHandleResponse(resp *http.Response) (Pag
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientClearPagesResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -187,18 +189,21 @@ func (client *PageBlobClient) clearPagesHandleResponse(resp *http.Response) (Pag
// method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *PageBlobClient) CopyIncremental(ctx context.Context, copySource string, options *PageBlobClientCopyIncrementalOptions, modifiedAccessConditions *ModifiedAccessConditions) (PageBlobClientCopyIncrementalResponse, error) {
var err error
req, err := client.copyIncrementalCreateRequest(ctx, copySource, options, modifiedAccessConditions)
if err != nil {
return PageBlobClientCopyIncrementalResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientCopyIncrementalResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusAccepted) {
return PageBlobClientCopyIncrementalResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusAccepted) {
err = runtime.NewResponseError(httpResp)
return PageBlobClientCopyIncrementalResponse{}, err
}
return client.copyIncrementalHandleResponse(resp)
resp, err := client.copyIncrementalHandleResponse(httpResp)
return resp, err
}
// copyIncrementalCreateRequest creates the CopyIncremental request.
@ -240,6 +245,22 @@ func (client *PageBlobClient) copyIncrementalCreateRequest(ctx context.Context,
// copyIncrementalHandleResponse handles the CopyIncremental response.
func (client *PageBlobClient) copyIncrementalHandleResponse(resp *http.Response) (PageBlobClientCopyIncrementalResponse, error) {
result := PageBlobClientCopyIncrementalResponse{}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-copy-id"); val != "" {
result.CopyID = &val
}
if val := resp.Header.Get("x-ms-copy-status"); val != "" {
result.CopyStatus = (*CopyStatusType)(&val)
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientCopyIncrementalResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
@ -250,28 +271,12 @@ func (client *PageBlobClient) copyIncrementalHandleResponse(resp *http.Response)
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientCopyIncrementalResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-copy-id"); val != "" {
result.CopyID = &val
}
if val := resp.Header.Get("x-ms-copy-status"); val != "" {
result.CopyStatus = (*CopyStatusType)(&val)
}
return result, nil
}
@ -289,18 +294,21 @@ func (client *PageBlobClient) copyIncrementalHandleResponse(resp *http.Response)
// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *PageBlobClient) Create(ctx context.Context, contentLength int64, blobContentLength int64, options *PageBlobClientCreateOptions, blobHTTPHeaders *BlobHTTPHeaders, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, modifiedAccessConditions *ModifiedAccessConditions) (PageBlobClientCreateResponse, error) {
var err error
req, err := client.createCreateRequest(ctx, contentLength, blobContentLength, options, blobHTTPHeaders, leaseAccessConditions, cpkInfo, cpkScopeInfo, modifiedAccessConditions)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return PageBlobClientCreateResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return PageBlobClientCreateResponse{}, err
}
return client.createHandleResponse(resp)
resp, err := client.createHandleResponse(httpResp)
return resp, err
}
// createCreateRequest creates the Create request.
@ -401,15 +409,8 @@ func (client *PageBlobClient) createCreateRequest(ctx context.Context, contentLe
// createHandleResponse handles the Create response.
func (client *PageBlobClient) createHandleResponse(resp *http.Response) (PageBlobClientCreateResponse, error) {
result := PageBlobClientCreateResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
result.LastModified = &lastModified
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
@ -418,8 +419,35 @@ func (client *PageBlobClient) createHandleResponse(resp *http.Response) (PageBlo
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
@ -430,26 +458,6 @@ func (client *PageBlobClient) createHandleResponse(resp *http.Response) (PageBlo
if val := resp.Header.Get("x-ms-version-id"); val != "" {
result.VersionID = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return PageBlobClientCreateResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
return result, nil
}
@ -467,23 +475,16 @@ func (client *PageBlobClient) NewGetPageRangesPager(options *PageBlobClientGetPa
return page.NextMarker != nil && len(*page.NextMarker) > 0
},
Fetcher: func(ctx context.Context, page *PageBlobClientGetPageRangesResponse) (PageBlobClientGetPageRangesResponse, error) {
var req *policy.Request
var err error
if page == nil {
req, err = client.GetPageRangesCreateRequest(ctx, options, leaseAccessConditions, modifiedAccessConditions)
} else {
req, err = runtime.NewRequest(ctx, http.MethodGet, *page.NextMarker)
nextLink := ""
if page != nil {
nextLink = *page.NextMarker
}
resp, err := runtime.FetcherForNextLink(ctx, client.internal.Pipeline(), nextLink, func(ctx context.Context) (*policy.Request, error) {
return client.GetPageRangesCreateRequest(ctx, options, leaseAccessConditions, modifiedAccessConditions)
}, nil)
if err != nil {
return PageBlobClientGetPageRangesResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientGetPageRangesResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return PageBlobClientGetPageRangesResponse{}, runtime.NewResponseError(resp)
}
return client.GetPageRangesHandleResponse(resp)
},
})
@ -542,16 +543,6 @@ func (client *PageBlobClient) GetPageRangesCreateRequest(ctx context.Context, op
// GetPageRangesHandleResponse handles the GetPageRanges response.
func (client *PageBlobClient) GetPageRangesHandleResponse(resp *http.Response) (PageBlobClientGetPageRangesResponse, error) {
result := PageBlobClientGetPageRangesResponse{}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientGetPageRangesResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-blob-content-length"); val != "" {
blobContentLength, err := strconv.ParseInt(val, 10, 64)
if err != nil {
@ -562,12 +553,6 @@ func (client *PageBlobClient) GetPageRangesHandleResponse(resp *http.Response) (
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -575,6 +560,22 @@ func (client *PageBlobClient) GetPageRangesHandleResponse(resp *http.Response) (
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientGetPageRangesResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if err := runtime.UnmarshalAsXML(resp, &result.PageList); err != nil {
return PageBlobClientGetPageRangesResponse{}, err
}
@ -595,23 +596,16 @@ func (client *PageBlobClient) NewGetPageRangesDiffPager(options *PageBlobClientG
return page.NextMarker != nil && len(*page.NextMarker) > 0
},
Fetcher: func(ctx context.Context, page *PageBlobClientGetPageRangesDiffResponse) (PageBlobClientGetPageRangesDiffResponse, error) {
var req *policy.Request
var err error
if page == nil {
req, err = client.GetPageRangesDiffCreateRequest(ctx, options, leaseAccessConditions, modifiedAccessConditions)
} else {
req, err = runtime.NewRequest(ctx, http.MethodGet, *page.NextMarker)
nextLink := ""
if page != nil {
nextLink = *page.NextMarker
}
resp, err := runtime.FetcherForNextLink(ctx, client.internal.Pipeline(), nextLink, func(ctx context.Context) (*policy.Request, error) {
return client.GetPageRangesDiffCreateRequest(ctx, options, leaseAccessConditions, modifiedAccessConditions)
}, nil)
if err != nil {
return PageBlobClientGetPageRangesDiffResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientGetPageRangesDiffResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return PageBlobClientGetPageRangesDiffResponse{}, runtime.NewResponseError(resp)
}
return client.GetPageRangesDiffHandleResponse(resp)
},
})
@ -676,16 +670,6 @@ func (client *PageBlobClient) GetPageRangesDiffCreateRequest(ctx context.Context
// GetPageRangesDiffHandleResponse handles the GetPageRangesDiff response.
func (client *PageBlobClient) GetPageRangesDiffHandleResponse(resp *http.Response) (PageBlobClientGetPageRangesDiffResponse, error) {
result := PageBlobClientGetPageRangesDiffResponse{}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientGetPageRangesDiffResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-blob-content-length"); val != "" {
blobContentLength, err := strconv.ParseInt(val, 10, 64)
if err != nil {
@ -696,12 +680,6 @@ func (client *PageBlobClient) GetPageRangesDiffHandleResponse(resp *http.Respons
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -709,6 +687,22 @@ func (client *PageBlobClient) GetPageRangesDiffHandleResponse(resp *http.Respons
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientGetPageRangesDiffResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if err := runtime.UnmarshalAsXML(resp, &result.PageList); err != nil {
return PageBlobClientGetPageRangesDiffResponse{}, err
}
@ -727,18 +721,21 @@ func (client *PageBlobClient) GetPageRangesDiffHandleResponse(resp *http.Respons
// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *PageBlobClient) Resize(ctx context.Context, blobContentLength int64, options *PageBlobClientResizeOptions, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, modifiedAccessConditions *ModifiedAccessConditions) (PageBlobClientResizeResponse, error) {
var err error
req, err := client.resizeCreateRequest(ctx, blobContentLength, options, leaseAccessConditions, cpkInfo, cpkScopeInfo, modifiedAccessConditions)
if err != nil {
return PageBlobClientResizeResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientResizeResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return PageBlobClientResizeResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return PageBlobClientResizeResponse{}, err
}
return client.resizeHandleResponse(resp)
resp, err := client.resizeHandleResponse(httpResp)
return resp, err
}
// resizeCreateRequest creates the Resize request.
@ -795,16 +792,6 @@ func (client *PageBlobClient) resizeCreateRequest(ctx context.Context, blobConte
// resizeHandleResponse handles the Resize response.
func (client *PageBlobClient) resizeHandleResponse(resp *http.Response) (PageBlobClientResizeResponse, error) {
result := PageBlobClientResizeResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientResizeResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-blob-sequence-number"); val != "" {
blobSequenceNumber, err := strconv.ParseInt(val, 10, 64)
if err != nil {
@ -815,12 +802,6 @@ func (client *PageBlobClient) resizeHandleResponse(resp *http.Response) (PageBlo
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -828,6 +809,22 @@ func (client *PageBlobClient) resizeHandleResponse(resp *http.Response) (PageBlo
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientResizeResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -842,18 +839,21 @@ func (client *PageBlobClient) resizeHandleResponse(resp *http.Response) (PageBlo
// - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *PageBlobClient) UpdateSequenceNumber(ctx context.Context, sequenceNumberAction SequenceNumberActionType, options *PageBlobClientUpdateSequenceNumberOptions, leaseAccessConditions *LeaseAccessConditions, modifiedAccessConditions *ModifiedAccessConditions) (PageBlobClientUpdateSequenceNumberResponse, error) {
var err error
req, err := client.updateSequenceNumberCreateRequest(ctx, sequenceNumberAction, options, leaseAccessConditions, modifiedAccessConditions)
if err != nil {
return PageBlobClientUpdateSequenceNumberResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientUpdateSequenceNumberResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return PageBlobClientUpdateSequenceNumberResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return PageBlobClientUpdateSequenceNumberResponse{}, err
}
return client.updateSequenceNumberHandleResponse(resp)
resp, err := client.updateSequenceNumberHandleResponse(httpResp)
return resp, err
}
// updateSequenceNumberCreateRequest creates the UpdateSequenceNumber request.
@ -901,16 +901,6 @@ func (client *PageBlobClient) updateSequenceNumberCreateRequest(ctx context.Cont
// updateSequenceNumberHandleResponse handles the UpdateSequenceNumber response.
func (client *PageBlobClient) updateSequenceNumberHandleResponse(resp *http.Response) (PageBlobClientUpdateSequenceNumberResponse, error) {
result := PageBlobClientUpdateSequenceNumberResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientUpdateSequenceNumberResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-blob-sequence-number"); val != "" {
blobSequenceNumber, err := strconv.ParseInt(val, 10, 64)
if err != nil {
@ -921,12 +911,6 @@ func (client *PageBlobClient) updateSequenceNumberHandleResponse(resp *http.Resp
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -934,6 +918,22 @@ func (client *PageBlobClient) updateSequenceNumberHandleResponse(resp *http.Resp
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientUpdateSequenceNumberResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -951,18 +951,21 @@ func (client *PageBlobClient) updateSequenceNumberHandleResponse(resp *http.Resp
// method.
// - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method.
func (client *PageBlobClient) UploadPages(ctx context.Context, contentLength int64, body io.ReadSeekCloser, options *PageBlobClientUploadPagesOptions, leaseAccessConditions *LeaseAccessConditions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, sequenceNumberAccessConditions *SequenceNumberAccessConditions, modifiedAccessConditions *ModifiedAccessConditions) (PageBlobClientUploadPagesResponse, error) {
var err error
req, err := client.uploadPagesCreateRequest(ctx, contentLength, body, options, leaseAccessConditions, cpkInfo, cpkScopeInfo, sequenceNumberAccessConditions, modifiedAccessConditions)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return PageBlobClientUploadPagesResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return PageBlobClientUploadPagesResponse{}, err
}
return client.uploadPagesHandleResponse(resp)
resp, err := client.uploadPagesHandleResponse(httpResp)
return resp, err
}
// uploadPagesCreateRequest creates the UploadPages request.
@ -1041,30 +1044,6 @@ func (client *PageBlobClient) uploadPagesCreateRequest(ctx context.Context, cont
// uploadPagesHandleResponse handles the UploadPages response.
func (client *PageBlobClient) uploadPagesHandleResponse(resp *http.Response) (PageBlobClientUploadPagesResponse, error) {
result := PageBlobClientUploadPagesResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-blob-sequence-number"); val != "" {
blobSequenceNumber, err := strconv.ParseInt(val, 10, 64)
if err != nil {
@ -1075,11 +1054,19 @@ func (client *PageBlobClient) uploadPagesHandleResponse(resp *http.Response) (Pa
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
@ -1088,6 +1075,15 @@ func (client *PageBlobClient) uploadPagesHandleResponse(resp *http.Response) (Pa
}
result.Date = &date
}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
@ -1095,11 +1091,18 @@ func (client *PageBlobClient) uploadPagesHandleResponse(resp *http.Response) (Pa
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientUploadPagesResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -1126,18 +1129,21 @@ func (client *PageBlobClient) uploadPagesHandleResponse(resp *http.Response) (Pa
// - SourceModifiedAccessConditions - SourceModifiedAccessConditions contains a group of parameters for the BlobClient.StartCopyFromURL
// method.
func (client *PageBlobClient) UploadPagesFromURL(ctx context.Context, sourceURL string, sourceRange string, contentLength int64, rangeParam string, options *PageBlobClientUploadPagesFromURLOptions, cpkInfo *CPKInfo, cpkScopeInfo *CPKScopeInfo, leaseAccessConditions *LeaseAccessConditions, sequenceNumberAccessConditions *SequenceNumberAccessConditions, modifiedAccessConditions *ModifiedAccessConditions, sourceModifiedAccessConditions *SourceModifiedAccessConditions) (PageBlobClientUploadPagesFromURLResponse, error) {
var err error
req, err := client.uploadPagesFromURLCreateRequest(ctx, sourceURL, sourceRange, contentLength, rangeParam, options, cpkInfo, cpkScopeInfo, leaseAccessConditions, sequenceNumberAccessConditions, modifiedAccessConditions, sourceModifiedAccessConditions)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusCreated) {
return PageBlobClientUploadPagesFromURLResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusCreated) {
err = runtime.NewResponseError(httpResp)
return PageBlobClientUploadPagesFromURLResponse{}, err
}
return client.uploadPagesFromURLHandleResponse(resp)
resp, err := client.uploadPagesFromURLHandleResponse(httpResp)
return resp, err
}
// uploadPagesFromURLCreateRequest creates the UploadPagesFromURL request.
@ -1228,22 +1234,12 @@ func (client *PageBlobClient) uploadPagesFromURLCreateRequest(ctx context.Contex
// uploadPagesFromURLHandleResponse handles the UploadPagesFromURL response.
func (client *PageBlobClient) uploadPagesFromURLHandleResponse(resp *http.Response) (PageBlobClientUploadPagesFromURLResponse, error) {
result := PageBlobClientUploadPagesFromURLResponse{}
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if val := resp.Header.Get("x-ms-blob-sequence-number"); val != "" {
blobSequenceNumber, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
result.ContentMD5 = contentMD5
result.BlobSequenceNumber = &blobSequenceNumber
}
if val := resp.Header.Get("x-ms-content-crc64"); val != "" {
contentCRC64, err := base64.StdEncoding.DecodeString(val)
@ -1252,18 +1248,12 @@ func (client *PageBlobClient) uploadPagesFromURLHandleResponse(resp *http.Respon
}
result.ContentCRC64 = contentCRC64
}
if val := resp.Header.Get("x-ms-blob-sequence-number"); val != "" {
blobSequenceNumber, err := strconv.ParseInt(val, 10, 64)
if val := resp.Header.Get("Content-MD5"); val != "" {
contentMD5, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
result.BlobSequenceNumber = &blobSequenceNumber
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
result.ContentMD5 = contentMD5
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
@ -1272,12 +1262,8 @@ func (client *PageBlobClient) uploadPagesFromURLHandleResponse(resp *http.Respon
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
if val := resp.Header.Get("ETag"); val != "" {
result.ETag = (*azcore.ETag)(&val)
}
if val := resp.Header.Get("x-ms-encryption-key-sha256"); val != "" {
result.EncryptionKeySHA256 = &val
@ -1285,5 +1271,25 @@ func (client *PageBlobClient) uploadPagesFromURLHandleResponse(resp *http.Respon
if val := resp.Header.Get("x-ms-encryption-scope"); val != "" {
result.EncryptionScope = &val
}
if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" {
isServerEncrypted, err := strconv.ParseBool(val)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
result.IsServerEncrypted = &isServerEncrypted
}
if val := resp.Header.Get("Last-Modified"); val != "" {
lastModified, err := time.Parse(time.RFC1123, val)
if err != nil {
return PageBlobClientUploadPagesFromURLResponse{}, err
}
result.LastModified = &lastModified
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -656,18 +655,20 @@ type BlobClientGetPropertiesResponse struct {
// BlobClientGetTagsResponse contains the response from method BlobClient.GetTags.
type BlobClientGetTagsResponse struct {
// Blob tags
BlobTags
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// BlobClientQueryResponse contains the response from method BlobClient.Query.
@ -1051,29 +1052,30 @@ type BlockBlobClientCommitBlockListResponse struct {
// BlockBlobClientGetBlockListResponse contains the response from method BlockBlobClient.GetBlockList.
type BlockBlobClientGetBlockListResponse struct {
BlockList
// BlobContentLength contains the information returned from the x-ms-blob-content-length header response.
BlobContentLength *int64 `xml:"BlobContentLength"`
BlobContentLength *int64
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// ContentType contains the information returned from the Content-Type header response.
ContentType *string `xml:"ContentType"`
ContentType *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// ETag contains the information returned from the ETag header response.
ETag *azcore.ETag `xml:"ETag"`
ETag *azcore.ETag
// LastModified contains the information returned from the Last-Modified header response.
LastModified *time.Time `xml:"LastModified"`
LastModified *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// BlockBlobClientPutBlobFromURLResponse contains the response from method BlockBlobClient.PutBlobFromURL.
@ -1318,45 +1320,47 @@ type ContainerClientDeleteResponse struct {
// ContainerClientFilterBlobsResponse contains the response from method ContainerClient.FilterBlobs.
type ContainerClientFilterBlobsResponse struct {
// The result of a Filter Blobs API call
FilterBlobSegment
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ContainerClientGetAccessPolicyResponse contains the response from method ContainerClient.GetAccessPolicy.
type ContainerClientGetAccessPolicyResponse struct {
// BlobPublicAccess contains the information returned from the x-ms-blob-public-access header response.
BlobPublicAccess *PublicAccessType `xml:"BlobPublicAccess"`
BlobPublicAccess *PublicAccessType
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// ETag contains the information returned from the ETag header response.
ETag *azcore.ETag `xml:"ETag"`
ETag *azcore.ETag
// LastModified contains the information returned from the Last-Modified header response.
LastModified *time.Time `xml:"LastModified"`
LastModified *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// a collection of signed identifiers
SignedIdentifiers []*SignedIdentifier `xml:"SignedIdentifier"`
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ContainerClientGetAccountInfoResponse contains the response from method ContainerClient.GetAccountInfo.
@ -1434,40 +1438,44 @@ type ContainerClientGetPropertiesResponse struct {
// ContainerClientListBlobFlatSegmentResponse contains the response from method ContainerClient.NewListBlobFlatSegmentPager.
type ContainerClientListBlobFlatSegmentResponse struct {
// An enumeration of blobs
ListBlobsFlatSegmentResponse
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// ContentType contains the information returned from the Content-Type header response.
ContentType *string `xml:"ContentType"`
ContentType *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ContainerClientListBlobHierarchySegmentResponse contains the response from method ContainerClient.NewListBlobHierarchySegmentPager.
type ContainerClientListBlobHierarchySegmentResponse struct {
// An enumeration of blobs
ListBlobsHierarchySegmentResponse
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// ContentType contains the information returned from the Content-Type header response.
ContentType *string `xml:"ContentType"`
ContentType *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ContainerClientReleaseLeaseResponse contains the response from method ContainerClient.ReleaseLease.
@ -1697,52 +1705,56 @@ type PageBlobClientCreateResponse struct {
// PageBlobClientGetPageRangesDiffResponse contains the response from method PageBlobClient.NewGetPageRangesDiffPager.
type PageBlobClientGetPageRangesDiffResponse struct {
// the list of pages
PageList
// BlobContentLength contains the information returned from the x-ms-blob-content-length header response.
BlobContentLength *int64 `xml:"BlobContentLength"`
BlobContentLength *int64
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// ETag contains the information returned from the ETag header response.
ETag *azcore.ETag `xml:"ETag"`
ETag *azcore.ETag
// LastModified contains the information returned from the Last-Modified header response.
LastModified *time.Time `xml:"LastModified"`
LastModified *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// PageBlobClientGetPageRangesResponse contains the response from method PageBlobClient.NewGetPageRangesPager.
type PageBlobClientGetPageRangesResponse struct {
// the list of pages
PageList
// BlobContentLength contains the information returned from the x-ms-blob-content-length header response.
BlobContentLength *int64 `xml:"BlobContentLength"`
BlobContentLength *int64
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// ETag contains the information returned from the ETag header response.
ETag *azcore.ETag `xml:"ETag"`
ETag *azcore.ETag
// LastModified contains the information returned from the Last-Modified header response.
LastModified *time.Time `xml:"LastModified"`
LastModified *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// PageBlobClientResizeResponse contains the response from method PageBlobClient.Resize.
@ -1870,18 +1882,20 @@ type PageBlobClientUploadPagesResponse struct {
// ServiceClientFilterBlobsResponse contains the response from method ServiceClient.FilterBlobs.
type ServiceClientFilterBlobsResponse struct {
// The result of a Filter Blobs API call
FilterBlobSegment
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ServiceClientGetAccountInfoResponse contains the response from method ServiceClient.GetAccountInfo.
@ -1910,60 +1924,68 @@ type ServiceClientGetAccountInfoResponse struct {
// ServiceClientGetPropertiesResponse contains the response from method ServiceClient.GetProperties.
type ServiceClientGetPropertiesResponse struct {
// Storage Service Properties.
StorageServiceProperties
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ServiceClientGetStatisticsResponse contains the response from method ServiceClient.GetStatistics.
type ServiceClientGetStatisticsResponse struct {
// Stats for the storage service.
StorageServiceStats
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ServiceClientGetUserDelegationKeyResponse contains the response from method ServiceClient.GetUserDelegationKey.
type ServiceClientGetUserDelegationKeyResponse struct {
// A user delegation key
UserDelegationKey
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// Date contains the information returned from the Date header response.
Date *time.Time `xml:"Date"`
Date *time.Time
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ServiceClientListContainersSegmentResponse contains the response from method ServiceClient.NewListContainersSegmentPager.
type ServiceClientListContainersSegmentResponse struct {
// An enumeration of containers
ListContainersSegmentResponse
// ClientRequestID contains the information returned from the x-ms-client-request-id header response.
ClientRequestID *string `xml:"ClientRequestID"`
ClientRequestID *string
// RequestID contains the information returned from the x-ms-request-id header response.
RequestID *string `xml:"RequestID"`
RequestID *string
// Version contains the information returned from the x-ms-version header response.
Version *string `xml:"Version"`
Version *string
}
// ServiceClientSetPropertiesResponse contains the response from method ServiceClient.SetProperties.

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -38,18 +37,21 @@ type ServiceClient struct {
// - where - Filters the results to return only to return only blobs whose tags match the specified expression.
// - options - ServiceClientFilterBlobsOptions contains the optional parameters for the ServiceClient.FilterBlobs method.
func (client *ServiceClient) FilterBlobs(ctx context.Context, where string, options *ServiceClientFilterBlobsOptions) (ServiceClientFilterBlobsResponse, error) {
var err error
req, err := client.filterBlobsCreateRequest(ctx, where, options)
if err != nil {
return ServiceClientFilterBlobsResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return ServiceClientFilterBlobsResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return ServiceClientFilterBlobsResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return ServiceClientFilterBlobsResponse{}, err
}
return client.filterBlobsHandleResponse(resp)
resp, err := client.filterBlobsHandleResponse(httpResp)
return resp, err
}
// filterBlobsCreateRequest creates the FilterBlobs request.
@ -88,12 +90,6 @@ func (client *ServiceClient) filterBlobsHandleResponse(resp *http.Response) (Ser
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -101,6 +97,12 @@ func (client *ServiceClient) filterBlobsHandleResponse(resp *http.Response) (Ser
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if err := runtime.UnmarshalAsXML(resp, &result.FilterBlobSegment); err != nil {
return ServiceClientFilterBlobsResponse{}, err
}
@ -113,18 +115,21 @@ func (client *ServiceClient) filterBlobsHandleResponse(resp *http.Response) (Ser
// Generated from API version 2023-08-03
// - options - ServiceClientGetAccountInfoOptions contains the optional parameters for the ServiceClient.GetAccountInfo method.
func (client *ServiceClient) GetAccountInfo(ctx context.Context, options *ServiceClientGetAccountInfoOptions) (ServiceClientGetAccountInfoResponse, error) {
var err error
req, err := client.getAccountInfoCreateRequest(ctx, options)
if err != nil {
return ServiceClientGetAccountInfoResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return ServiceClientGetAccountInfoResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return ServiceClientGetAccountInfoResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return ServiceClientGetAccountInfoResponse{}, err
}
return client.getAccountInfoHandleResponse(resp)
resp, err := client.getAccountInfoHandleResponse(httpResp)
return resp, err
}
// getAccountInfoCreateRequest creates the GetAccountInfo request.
@ -145,15 +150,12 @@ func (client *ServiceClient) getAccountInfoCreateRequest(ctx context.Context, op
// getAccountInfoHandleResponse handles the GetAccountInfo response.
func (client *ServiceClient) getAccountInfoHandleResponse(resp *http.Response) (ServiceClientGetAccountInfoResponse, error) {
result := ServiceClientGetAccountInfoResponse{}
if val := resp.Header.Get("x-ms-account-kind"); val != "" {
result.AccountKind = (*AccountKind)(&val)
}
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -161,12 +163,6 @@ func (client *ServiceClient) getAccountInfoHandleResponse(resp *http.Response) (
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-sku-name"); val != "" {
result.SKUName = (*SKUName)(&val)
}
if val := resp.Header.Get("x-ms-account-kind"); val != "" {
result.AccountKind = (*AccountKind)(&val)
}
if val := resp.Header.Get("x-ms-is-hns-enabled"); val != "" {
isHierarchicalNamespaceEnabled, err := strconv.ParseBool(val)
if err != nil {
@ -174,6 +170,15 @@ func (client *ServiceClient) getAccountInfoHandleResponse(resp *http.Response) (
}
result.IsHierarchicalNamespaceEnabled = &isHierarchicalNamespaceEnabled
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-sku-name"); val != "" {
result.SKUName = (*SKUName)(&val)
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
return result, nil
}
@ -184,18 +189,21 @@ func (client *ServiceClient) getAccountInfoHandleResponse(resp *http.Response) (
// Generated from API version 2023-08-03
// - options - ServiceClientGetPropertiesOptions contains the optional parameters for the ServiceClient.GetProperties method.
func (client *ServiceClient) GetProperties(ctx context.Context, options *ServiceClientGetPropertiesOptions) (ServiceClientGetPropertiesResponse, error) {
var err error
req, err := client.getPropertiesCreateRequest(ctx, options)
if err != nil {
return ServiceClientGetPropertiesResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return ServiceClientGetPropertiesResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return ServiceClientGetPropertiesResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return ServiceClientGetPropertiesResponse{}, err
}
return client.getPropertiesHandleResponse(resp)
resp, err := client.getPropertiesHandleResponse(httpResp)
return resp, err
}
// getPropertiesCreateRequest creates the GetProperties request.
@ -244,18 +252,21 @@ func (client *ServiceClient) getPropertiesHandleResponse(resp *http.Response) (S
// Generated from API version 2023-08-03
// - options - ServiceClientGetStatisticsOptions contains the optional parameters for the ServiceClient.GetStatistics method.
func (client *ServiceClient) GetStatistics(ctx context.Context, options *ServiceClientGetStatisticsOptions) (ServiceClientGetStatisticsResponse, error) {
var err error
req, err := client.getStatisticsCreateRequest(ctx, options)
if err != nil {
return ServiceClientGetStatisticsResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return ServiceClientGetStatisticsResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return ServiceClientGetStatisticsResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return ServiceClientGetStatisticsResponse{}, err
}
return client.getStatisticsHandleResponse(resp)
resp, err := client.getStatisticsHandleResponse(httpResp)
return resp, err
}
// getStatisticsCreateRequest creates the GetStatistics request.
@ -285,12 +296,6 @@ func (client *ServiceClient) getStatisticsHandleResponse(resp *http.Response) (S
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -298,6 +303,12 @@ func (client *ServiceClient) getStatisticsHandleResponse(resp *http.Response) (S
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if err := runtime.UnmarshalAsXML(resp, &result.StorageServiceStats); err != nil {
return ServiceClientGetStatisticsResponse{}, err
}
@ -313,18 +324,21 @@ func (client *ServiceClient) getStatisticsHandleResponse(resp *http.Response) (S
// - options - ServiceClientGetUserDelegationKeyOptions contains the optional parameters for the ServiceClient.GetUserDelegationKey
// method.
func (client *ServiceClient) GetUserDelegationKey(ctx context.Context, keyInfo KeyInfo, options *ServiceClientGetUserDelegationKeyOptions) (ServiceClientGetUserDelegationKeyResponse, error) {
var err error
req, err := client.getUserDelegationKeyCreateRequest(ctx, keyInfo, options)
if err != nil {
return ServiceClientGetUserDelegationKeyResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return ServiceClientGetUserDelegationKeyResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return ServiceClientGetUserDelegationKeyResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusOK) {
err = runtime.NewResponseError(httpResp)
return ServiceClientGetUserDelegationKeyResponse{}, err
}
return client.getUserDelegationKeyHandleResponse(resp)
resp, err := client.getUserDelegationKeyHandleResponse(httpResp)
return resp, err
}
// getUserDelegationKeyCreateRequest creates the GetUserDelegationKey request.
@ -357,12 +371,6 @@ func (client *ServiceClient) getUserDelegationKeyHandleResponse(resp *http.Respo
if val := resp.Header.Get("x-ms-client-request-id"); val != "" {
result.ClientRequestID = &val
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if val := resp.Header.Get("Date"); val != "" {
date, err := time.Parse(time.RFC1123, val)
if err != nil {
@ -370,6 +378,12 @@ func (client *ServiceClient) getUserDelegationKeyHandleResponse(resp *http.Respo
}
result.Date = &date
}
if val := resp.Header.Get("x-ms-request-id"); val != "" {
result.RequestID = &val
}
if val := resp.Header.Get("x-ms-version"); val != "" {
result.Version = &val
}
if err := runtime.UnmarshalAsXML(resp, &result.UserDelegationKey); err != nil {
return ServiceClientGetUserDelegationKeyResponse{}, err
}
@ -441,18 +455,21 @@ func (client *ServiceClient) ListContainersSegmentHandleResponse(resp *http.Resp
// - storageServiceProperties - The StorageService properties.
// - options - ServiceClientSetPropertiesOptions contains the optional parameters for the ServiceClient.SetProperties method.
func (client *ServiceClient) SetProperties(ctx context.Context, storageServiceProperties StorageServiceProperties, options *ServiceClientSetPropertiesOptions) (ServiceClientSetPropertiesResponse, error) {
var err error
req, err := client.setPropertiesCreateRequest(ctx, storageServiceProperties, options)
if err != nil {
return ServiceClientSetPropertiesResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return ServiceClientSetPropertiesResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusAccepted) {
return ServiceClientSetPropertiesResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusAccepted) {
err = runtime.NewResponseError(httpResp)
return ServiceClientSetPropertiesResponse{}, err
}
return client.setPropertiesHandleResponse(resp)
resp, err := client.setPropertiesHandleResponse(httpResp)
return resp, err
}
// setPropertiesCreateRequest creates the SetProperties request.
@ -504,18 +521,21 @@ func (client *ServiceClient) setPropertiesHandleResponse(resp *http.Response) (S
// - body - Initial data
// - options - ServiceClientSubmitBatchOptions contains the optional parameters for the ServiceClient.SubmitBatch method.
func (client *ServiceClient) SubmitBatch(ctx context.Context, contentLength int64, multipartContentType string, body io.ReadSeekCloser, options *ServiceClientSubmitBatchOptions) (ServiceClientSubmitBatchResponse, error) {
var err error
req, err := client.submitBatchCreateRequest(ctx, contentLength, multipartContentType, body, options)
if err != nil {
return ServiceClientSubmitBatchResponse{}, err
}
resp, err := client.internal.Pipeline().Do(req)
httpResp, err := client.internal.Pipeline().Do(req)
if err != nil {
return ServiceClientSubmitBatchResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusAccepted) {
return ServiceClientSubmitBatchResponse{}, runtime.NewResponseError(resp)
if !runtime.HasStatusCode(httpResp, http.StatusAccepted) {
err = runtime.NewResponseError(httpResp)
return ServiceClientSubmitBatchResponse{}, err
}
return client.submitBatchHandleResponse(resp)
resp, err := client.submitBatchHandleResponse(httpResp)
return resp, err
}
// submitBatchCreateRequest creates the SubmitBatch request.

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -15,29 +14,29 @@ import (
)
const (
rfc1123JSON = `"` + time.RFC1123 + `"`
dateTimeRFC1123JSON = `"` + time.RFC1123 + `"`
)
type timeRFC1123 time.Time
type dateTimeRFC1123 time.Time
func (t timeRFC1123) MarshalJSON() ([]byte, error) {
b := []byte(time.Time(t).Format(rfc1123JSON))
func (t dateTimeRFC1123) MarshalJSON() ([]byte, error) {
b := []byte(time.Time(t).Format(dateTimeRFC1123JSON))
return b, nil
}
func (t timeRFC1123) MarshalText() ([]byte, error) {
func (t dateTimeRFC1123) MarshalText() ([]byte, error) {
b := []byte(time.Time(t).Format(time.RFC1123))
return b, nil
}
func (t *timeRFC1123) UnmarshalJSON(data []byte) error {
p, err := time.Parse(rfc1123JSON, strings.ToUpper(string(data)))
*t = timeRFC1123(p)
func (t *dateTimeRFC1123) UnmarshalJSON(data []byte) error {
p, err := time.Parse(dateTimeRFC1123JSON, strings.ToUpper(string(data)))
*t = dateTimeRFC1123(p)
return err
}
func (t *timeRFC1123) UnmarshalText(data []byte) error {
func (t *dateTimeRFC1123) UnmarshalText(data []byte) error {
p, err := time.Parse(time.RFC1123, string(data))
*t = timeRFC1123(p)
*t = dateTimeRFC1123(p)
return err
}

View file

@ -3,9 +3,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
@ -15,45 +14,45 @@ import (
"time"
)
const (
utcLayoutJSON = `"2006-01-02T15:04:05.999999999"`
utcLayout = "2006-01-02T15:04:05.999999999"
rfc3339JSON = `"` + time.RFC3339Nano + `"`
)
// Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases.
var tzOffsetRegex = regexp.MustCompile(`(Z|z|\+|-)(\d+:\d+)*"*$`)
type timeRFC3339 time.Time
const (
utcDateTimeJSON = `"2006-01-02T15:04:05.999999999"`
utcDateTime = "2006-01-02T15:04:05.999999999"
dateTimeJSON = `"` + time.RFC3339Nano + `"`
)
func (t timeRFC3339) MarshalJSON() (json []byte, err error) {
type dateTimeRFC3339 time.Time
func (t dateTimeRFC3339) MarshalJSON() ([]byte, error) {
tt := time.Time(t)
return tt.MarshalJSON()
}
func (t timeRFC3339) MarshalText() (text []byte, err error) {
func (t dateTimeRFC3339) MarshalText() ([]byte, error) {
tt := time.Time(t)
return tt.MarshalText()
}
func (t *timeRFC3339) UnmarshalJSON(data []byte) error {
layout := utcLayoutJSON
func (t *dateTimeRFC3339) UnmarshalJSON(data []byte) error {
layout := utcDateTimeJSON
if tzOffsetRegex.Match(data) {
layout = rfc3339JSON
layout = dateTimeJSON
}
return t.Parse(layout, string(data))
}
func (t *timeRFC3339) UnmarshalText(data []byte) (err error) {
layout := utcLayout
func (t *dateTimeRFC3339) UnmarshalText(data []byte) error {
layout := utcDateTime
if tzOffsetRegex.Match(data) {
layout = time.RFC3339Nano
}
return t.Parse(layout, string(data))
}
func (t *timeRFC3339) Parse(layout, value string) error {
func (t *dateTimeRFC3339) Parse(layout, value string) error {
p, err := time.Parse(layout, strings.ToUpper(value))
*t = timeRFC3339(p)
*t = dateTimeRFC3339(p)
return err
}

View file

@ -3,14 +3,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// Code generated by Microsoft (R) AutoRest Code Generator.
// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// DO NOT EDIT.
package generated
import (
"encoding/xml"
"errors"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"io"
"strings"
)
@ -19,22 +21,32 @@ type additionalProperties map[string]*string
// UnmarshalXML implements the xml.Unmarshaler interface for additionalProperties.
func (ap *additionalProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
tokName := ""
for t, err := d.Token(); err == nil; t, err = d.Token() {
tokValue := ""
for {
t, err := d.Token()
if errors.Is(err, io.EOF) {
break
} else if err != nil {
return err
}
switch tt := t.(type) {
case xml.StartElement:
tokName = strings.ToLower(tt.Name.Local)
break
tokValue = ""
case xml.CharData:
if tokName == "" {
continue
}
tokValue = string(tt)
case xml.EndElement:
if tokName == "" {
continue
}
if *ap == nil {
*ap = additionalProperties{}
}
s := string(tt)
(*ap)[tokName] = &s
(*ap)[tokName] = to.Ptr(tokValue)
tokName = ""
break
}
}
return nil

View file

@ -144,9 +144,6 @@ func ParseConnectionString(connectionString string) (ParsedConnectionString, err
// SerializeBlobTags converts tags to generated.BlobTags
func SerializeBlobTags(tagsMap map[string]string) *generated.BlobTags {
if len(tagsMap) == 0 {
return nil
}
blobTagSet := make([]*generated.BlobTag, 0)
for key, val := range tagsMap {
newKey, newVal := key, val
@ -257,3 +254,27 @@ func IsIPEndpointStyle(host string) bool {
}
return net.ParseIP(host) != nil
}
// ReadAtLeast reads from r into buf until it has read at least min bytes.
// It returns the number of bytes copied and an error.
// The EOF error is returned if no bytes were read or
// EOF happened after reading fewer than min bytes.
// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
// On return, n >= min if and only if err == nil.
// If r returns an error having read at least min bytes, the error is dropped.
// This method is same as io.ReadAtLeast except that it does not
// return io.ErrUnexpectedEOF when fewer than min bytes are read.
func ReadAtLeast(r io.Reader, buf []byte, min int) (n int, err error) {
if len(buf) < min {
return 0, io.ErrShortBuffer
}
for n < min && err == nil {
var nn int
nn, err = r.Read(buf[n:])
n += nn
}
if n >= min {
err = nil
}
return
}

View file

@ -8,6 +8,7 @@ package pageblob
import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
"io"
"net/http"
"net/url"
@ -426,6 +427,12 @@ func (pb *Client) CopyFromURL(ctx context.Context, copySource string, o *blob.Co
return pb.BlobClient().CopyFromURL(ctx, copySource, o)
}
// GetSASURL is a convenience method for generating a SAS token for the currently pointed at Page blob.
// It can only be used if the credential supplied during creation was a SharedKeyCredential.
func (pb *Client) GetSASURL(permissions sas.BlobPermissions, expiry time.Time, o *blob.GetSASURLOptions) (string, error) {
return pb.BlobClient().GetSASURL(permissions, expiry, o)
}
// Concurrent Download Functions -----------------------------------------------------------------------------------------
// DownloadStream reads a range of bytes from a blob. The response also includes the blob's properties and metadata.

File diff suppressed because it is too large Load diff

View file

@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
const SDKVersion = "1.49.0"
const SDKVersion = "1.49.7"

View file

@ -58035,6 +58035,25 @@ type AdvertiseByoipCidrInput struct {
// the required permissions, the error response is DryRunOperation. Otherwise,
// it is UnauthorizedOperation.
DryRun *bool `type:"boolean"`
// If you have Local Zones (https://docs.aws.amazon.com/local-zones/latest/ug/how-local-zones-work.html)
// enabled, you can choose a network border group for Local Zones when you provision
// and advertise a BYOIPv4 CIDR. Choose the network border group carefully as
// the EIP and the Amazon Web Services resource it is associated with must reside
// in the same network border group.
//
// You can provision BYOIP address ranges to and advertise them in the following
// Local Zone network border groups:
//
// * us-east-1-dfw-2
//
// * us-west-2-lax-1
//
// * us-west-2-phx-2
//
// You cannot provision or advertise BYOIPv6 address ranges in Local Zones at
// this time.
NetworkBorderGroup *string `type:"string"`
}
// String returns the string representation.
@ -58086,6 +58105,12 @@ func (s *AdvertiseByoipCidrInput) SetDryRun(v bool) *AdvertiseByoipCidrInput {
return s
}
// SetNetworkBorderGroup sets the NetworkBorderGroup field's value.
func (s *AdvertiseByoipCidrInput) SetNetworkBorderGroup(v string) *AdvertiseByoipCidrInput {
s.NetworkBorderGroup = &v
return s
}
type AdvertiseByoipCidrOutput struct {
_ struct{} `type:"structure"`
@ -64318,6 +64343,25 @@ type ByoipCidr struct {
// The description of the address range.
Description *string `locationName:"description" type:"string"`
// If you have Local Zones (https://docs.aws.amazon.com/local-zones/latest/ug/how-local-zones-work.html)
// enabled, you can choose a network border group for Local Zones when you provision
// and advertise a BYOIPv4 CIDR. Choose the network border group carefully as
// the EIP and the Amazon Web Services resource it is associated with must reside
// in the same network border group.
//
// You can provision BYOIP address ranges to and advertise them in the following
// Local Zone network border groups:
//
// * us-east-1-dfw-2
//
// * us-west-2-lax-1
//
// * us-west-2-phx-2
//
// You cannot provision or advertise BYOIPv6 address ranges in Local Zones at
// this time.
NetworkBorderGroup *string `locationName:"networkBorderGroup" type:"string"`
// The state of the address pool.
State *string `locationName:"state" type:"string" enum:"ByoipCidrState"`
@ -64362,6 +64406,12 @@ func (s *ByoipCidr) SetDescription(v string) *ByoipCidr {
return s
}
// SetNetworkBorderGroup sets the NetworkBorderGroup field's value.
func (s *ByoipCidr) SetNetworkBorderGroup(v string) *ByoipCidr {
s.NetworkBorderGroup = &v
return s
}
// SetState sets the State field's value.
func (s *ByoipCidr) SetState(v string) *ByoipCidr {
s.State = &v
@ -135752,6 +135802,11 @@ type InstanceNetworkInterfaceSpecification struct {
// for eth0, and can only be assigned to a new network interface, not an existing
// one. You cannot specify more than one network interface in the request. If
// launching into a default subnet, the default value is true.
//
// Starting on February 1, 2024, Amazon Web Services will charge for all public
// IPv4 addresses, including public IPv4 addresses associated with running instances
// and Elastic IP addresses. For more information, see the Public IPv4 Address
// tab on the Amazon VPC pricing page (http://aws.amazon.com/vpc/pricing/).
AssociatePublicIpAddress *bool `locationName:"associatePublicIpAddress" type:"boolean"`
// A security group connection tracking specification that enables you to set
@ -142771,20 +142826,18 @@ type LaunchTemplateInstanceMetadataOptions struct {
// Possible values: Integers from 1 to 64
HttpPutResponseHopLimit *int64 `locationName:"httpPutResponseHopLimit" type:"integer"`
// Indicates whether IMDSv2 is optional or required.
// Indicates whether IMDSv2 is required.
//
// optional - When IMDSv2 is optional, you can choose to retrieve instance metadata
// with or without a session token in your request. If you retrieve the IAM
// role credentials without a token, the IMDSv1 role credentials are returned.
// If you retrieve the IAM role credentials using a valid session token, the
// IMDSv2 role credentials are returned.
// * optional - IMDSv2 is optional. You can choose whether to send a session
// token in your instance metadata retrieval requests. If you retrieve IAM
// role credentials without a session token, you receive the IMDSv1 role
// credentials. If you retrieve IAM role credentials using a valid session
// token, you receive the IMDSv2 role credentials.
//
// required - When IMDSv2 is required, you must send a session token with any
// instance metadata retrieval requests. In this state, retrieving the IAM role
// credentials always returns IMDSv2 credentials; IMDSv1 credentials are not
// available.
//
// Default: optional
// * required - IMDSv2 is required. You must send a session token in your
// instance metadata retrieval requests. With this option, retrieving the
// IAM role credentials always returns IMDSv2 credentials; IMDSv1 credentials
// are not available.
HttpTokens *string `locationName:"httpTokens" type:"string" enum:"LaunchTemplateHttpTokensState"`
// Set to enabled to allow access to instance tags from the instance metadata.
@ -142884,22 +142937,21 @@ type LaunchTemplateInstanceMetadataOptionsRequest struct {
// Possible values: Integers from 1 to 64
HttpPutResponseHopLimit *int64 `type:"integer"`
// IMDSv2 uses token-backed sessions. Set the use of HTTP tokens to optional
// (in other words, set the use of IMDSv2 to optional) or required (in other
// words, set the use of IMDSv2 to required).
// Indicates whether IMDSv2 is required.
//
// * optional - When IMDSv2 is optional, you can choose to retrieve instance
// metadata with or without a session token in your request. If you retrieve
// the IAM role credentials without a token, the IMDSv1 role credentials
// are returned. If you retrieve the IAM role credentials using a valid session
// token, the IMDSv2 role credentials are returned.
// * optional - IMDSv2 is optional. You can choose whether to send a session
// token in your instance metadata retrieval requests. If you retrieve IAM
// role credentials without a session token, you receive the IMDSv1 role
// credentials. If you retrieve IAM role credentials using a valid session
// token, you receive the IMDSv2 role credentials.
//
// * required - When IMDSv2 is required, you must send a session token with
// any instance metadata retrieval requests. In this state, retrieving the
// * required - IMDSv2 is required. You must send a session token in your
// instance metadata retrieval requests. With this option, retrieving the
// IAM role credentials always returns IMDSv2 credentials; IMDSv1 credentials
// are not available.
//
// Default: optional
// Default: If the value of ImdsSupport for the Amazon Machine Image (AMI) for
// your instance is v2.0, the default is required.
HttpTokens *string `type:"string" enum:"LaunchTemplateHttpTokensState"`
// Set to enabled to allow access to instance tags from the instance metadata.
@ -142974,6 +143026,11 @@ type LaunchTemplateInstanceNetworkInterfaceSpecification struct {
// Indicates whether to associate a public IPv4 address with eth0 for a new
// network interface.
//
// Starting on February 1, 2024, Amazon Web Services will charge for all public
// IPv4 addresses, including public IPv4 addresses associated with running instances
// and Elastic IP addresses. For more information, see the Public IPv4 Address
// tab on the Amazon VPC pricing page (http://aws.amazon.com/vpc/pricing/).
AssociatePublicIpAddress *bool `locationName:"associatePublicIpAddress" type:"boolean"`
// A security group connection tracking specification that enables you to set
@ -143210,6 +143267,11 @@ type LaunchTemplateInstanceNetworkInterfaceSpecificationRequest struct {
AssociateCarrierIpAddress *bool `type:"boolean"`
// Associates a public IPv4 address with eth0 for a new network interface.
//
// Starting on February 1, 2024, Amazon Web Services will charge for all public
// IPv4 addresses, including public IPv4 addresses associated with running instances
// and Elastic IP addresses. For more information, see the Public IPv4 Address
// tab on the Amazon VPC pricing page (http://aws.amazon.com/vpc/pricing/).
AssociatePublicIpAddress *bool `type:"boolean"`
// A security group connection tracking specification that enables you to set
@ -161174,6 +161236,25 @@ type ProvisionByoipCidrInput struct {
// Reserved.
MultiRegion *bool `type:"boolean"`
// If you have Local Zones (https://docs.aws.amazon.com/local-zones/latest/ug/how-local-zones-work.html)
// enabled, you can choose a network border group for Local Zones when you provision
// and advertise a BYOIPv4 CIDR. Choose the network border group carefully as
// the EIP and the Amazon Web Services resource it is associated with must reside
// in the same network border group.
//
// You can provision BYOIP address ranges to and advertise them in the following
// Local Zone network border groups:
//
// * us-east-1-dfw-2
//
// * us-west-2-lax-1
//
// * us-west-2-phx-2
//
// You cannot provision or advertise BYOIPv6 address ranges in Local Zones at
// this time.
NetworkBorderGroup *string `type:"string"`
// The tags to apply to the address pool.
PoolTagSpecifications []*TagSpecification `locationName:"PoolTagSpecification" locationNameList:"item" type:"list"`
@ -161250,6 +161331,12 @@ func (s *ProvisionByoipCidrInput) SetMultiRegion(v bool) *ProvisionByoipCidrInpu
return s
}
// SetNetworkBorderGroup sets the NetworkBorderGroup field's value.
func (s *ProvisionByoipCidrInput) SetNetworkBorderGroup(v string) *ProvisionByoipCidrInput {
s.NetworkBorderGroup = &v
return s
}
// SetPoolTagSpecifications sets the PoolTagSpecifications field's value.
func (s *ProvisionByoipCidrInput) SetPoolTagSpecifications(v []*TagSpecification) *ProvisionByoipCidrInput {
s.PoolTagSpecifications = v
@ -165874,23 +165961,7 @@ type RequestLaunchTemplateData struct {
SecurityGroups []*string `locationName:"SecurityGroup" locationNameList:"SecurityGroup" type:"list"`
// The tags to apply to the resources that are created during instance launch.
//
// You can specify tags for the following resources only:
//
// * Instances
//
// * Volumes
//
// * Elastic graphics
//
// * Spot Instance requests
//
// * Network interfaces
//
// To tag a resource after it has been created, see CreateTags (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateTags.html).
//
// To tag the launch template itself, you must use the TagSpecification (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateLaunchTemplate.html)
// parameter.
// These tags are not applied to the launch template.
TagSpecifications []*LaunchTemplateTagSpecificationRequest `locationName:"TagSpecification" locationNameList:"LaunchTemplateTagSpecificationRequest" type:"list"`
// The user data to make available to the instance. You must provide base64-encoded

0
vendor/github.com/felixge/httpsnoop/.gitignore generated vendored Normal file
View file

19
vendor/github.com/felixge/httpsnoop/LICENSE.txt generated vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2016 Felix Geisendörfer (felix@debuggable.com)
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.

10
vendor/github.com/felixge/httpsnoop/Makefile generated vendored Normal file
View file

@ -0,0 +1,10 @@
.PHONY: ci generate clean
ci: clean generate
go test -race -v ./...
generate:
go generate .
clean:
rm -rf *_generated*.go

95
vendor/github.com/felixge/httpsnoop/README.md generated vendored Normal file
View file

@ -0,0 +1,95 @@
# httpsnoop
Package httpsnoop provides an easy way to capture http related metrics (i.e.
response time, bytes written, and http status code) from your application's
http.Handlers.
Doing this requires non-trivial wrapping of the http.ResponseWriter interface,
which is also exposed for users interested in a more low-level API.
[![Go Reference](https://pkg.go.dev/badge/github.com/felixge/httpsnoop.svg)](https://pkg.go.dev/github.com/felixge/httpsnoop)
[![Build Status](https://github.com/felixge/httpsnoop/actions/workflows/main.yaml/badge.svg)](https://github.com/felixge/httpsnoop/actions/workflows/main.yaml)
## Usage Example
```go
// myH is your app's http handler, perhaps a http.ServeMux or similar.
var myH http.Handler
// wrappedH wraps myH in order to log every request.
wrappedH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
m := httpsnoop.CaptureMetrics(myH, w, r)
log.Printf(
"%s %s (code=%d dt=%s written=%d)",
r.Method,
r.URL,
m.Code,
m.Duration,
m.Written,
)
})
http.ListenAndServe(":8080", wrappedH)
```
## Why this package exists
Instrumenting an application's http.Handler is surprisingly difficult.
However if you google for e.g. "capture ResponseWriter status code" you'll find
lots of advise and code examples that suggest it to be a fairly trivial
undertaking. Unfortunately everything I've seen so far has a high chance of
breaking your application.
The main problem is that a `http.ResponseWriter` often implements additional
interfaces such as `http.Flusher`, `http.CloseNotifier`, `http.Hijacker`, `http.Pusher`, and
`io.ReaderFrom`. So the naive approach of just wrapping `http.ResponseWriter`
in your own struct that also implements the `http.ResponseWriter` interface
will hide the additional interfaces mentioned above. This has a high change of
introducing subtle bugs into any non-trivial application.
Another approach I've seen people take is to return a struct that implements
all of the interfaces above. However, that's also problematic, because it's
difficult to fake some of these interfaces behaviors when the underlying
`http.ResponseWriter` doesn't have an implementation. It's also dangerous,
because an application may choose to operate differently, merely because it
detects the presence of these additional interfaces.
This package solves this problem by checking which additional interfaces a
`http.ResponseWriter` implements, returning a wrapped version implementing the
exact same set of interfaces.
Additionally this package properly handles edge cases such as `WriteHeader` not
being called, or called more than once, as well as concurrent calls to
`http.ResponseWriter` methods, and even calls happening after the wrapped
`ServeHTTP` has already returned.
Unfortunately this package is not perfect either. It's possible that it is
still missing some interfaces provided by the go core (let me know if you find
one), and it won't work for applications adding their own interfaces into the
mix. You can however use `httpsnoop.Unwrap(w)` to access the underlying
`http.ResponseWriter` and type-assert the result to its other interfaces.
However, hopefully the explanation above has sufficiently scared you of rolling
your own solution to this problem. httpsnoop may still break your application,
but at least it tries to avoid it as much as possible.
Anyway, the real problem here is that smuggling additional interfaces inside
`http.ResponseWriter` is a problematic design choice, but it probably goes as
deep as the Go language specification itself. But that's okay, I still prefer
Go over the alternatives ;).
## Performance
```
BenchmarkBaseline-8 20000 94912 ns/op
BenchmarkCaptureMetrics-8 20000 95461 ns/op
```
As you can see, using `CaptureMetrics` on a vanilla http.Handler introduces an
overhead of ~500 ns per http request on my machine. However, the margin of
error appears to be larger than that, therefor it should be reasonable to
assume that the overhead introduced by `CaptureMetrics` is absolutely
negligible.
## License
MIT

86
vendor/github.com/felixge/httpsnoop/capture_metrics.go generated vendored Normal file
View file

@ -0,0 +1,86 @@
package httpsnoop
import (
"io"
"net/http"
"time"
)
// Metrics holds metrics captured from CaptureMetrics.
type Metrics struct {
// Code is the first http response code passed to the WriteHeader func of
// the ResponseWriter. If no such call is made, a default code of 200 is
// assumed instead.
Code int
// Duration is the time it took to execute the handler.
Duration time.Duration
// Written is the number of bytes successfully written by the Write or
// ReadFrom function of the ResponseWriter. ResponseWriters may also write
// data to their underlaying connection directly (e.g. headers), but those
// are not tracked. Therefor the number of Written bytes will usually match
// the size of the response body.
Written int64
}
// CaptureMetrics wraps the given hnd, executes it with the given w and r, and
// returns the metrics it captured from it.
func CaptureMetrics(hnd http.Handler, w http.ResponseWriter, r *http.Request) Metrics {
return CaptureMetricsFn(w, func(ww http.ResponseWriter) {
hnd.ServeHTTP(ww, r)
})
}
// CaptureMetricsFn wraps w and calls fn with the wrapped w and returns the
// resulting metrics. This is very similar to CaptureMetrics (which is just
// sugar on top of this func), but is a more usable interface if your
// application doesn't use the Go http.Handler interface.
func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metrics {
m := Metrics{Code: http.StatusOK}
m.CaptureMetrics(w, fn)
return m
}
// CaptureMetrics wraps w and calls fn with the wrapped w and updates
// Metrics m with the resulting metrics. This is similar to CaptureMetricsFn,
// but allows one to customize starting Metrics object.
func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWriter)) {
var (
start = time.Now()
headerWritten bool
hooks = Hooks{
WriteHeader: func(next WriteHeaderFunc) WriteHeaderFunc {
return func(code int) {
next(code)
if !(code >= 100 && code <= 199) && !headerWritten {
m.Code = code
headerWritten = true
}
}
},
Write: func(next WriteFunc) WriteFunc {
return func(p []byte) (int, error) {
n, err := next(p)
m.Written += int64(n)
headerWritten = true
return n, err
}
},
ReadFrom: func(next ReadFromFunc) ReadFromFunc {
return func(src io.Reader) (int64, error) {
n, err := next(src)
headerWritten = true
m.Written += n
return n, err
}
},
}
)
fn(Wrap(w, hooks))
m.Duration += time.Since(start)
}

10
vendor/github.com/felixge/httpsnoop/docs.go generated vendored Normal file
View file

@ -0,0 +1,10 @@
// Package httpsnoop provides an easy way to capture http related metrics (i.e.
// response time, bytes written, and http status code) from your application's
// http.Handlers.
//
// Doing this requires non-trivial wrapping of the http.ResponseWriter
// interface, which is also exposed for users interested in a more low-level
// API.
package httpsnoop
//go:generate go run codegen/main.go

View file

@ -0,0 +1,436 @@
// +build go1.8
// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
package httpsnoop
import (
"bufio"
"io"
"net"
"net/http"
)
// HeaderFunc is part of the http.ResponseWriter interface.
type HeaderFunc func() http.Header
// WriteHeaderFunc is part of the http.ResponseWriter interface.
type WriteHeaderFunc func(code int)
// WriteFunc is part of the http.ResponseWriter interface.
type WriteFunc func(b []byte) (int, error)
// FlushFunc is part of the http.Flusher interface.
type FlushFunc func()
// CloseNotifyFunc is part of the http.CloseNotifier interface.
type CloseNotifyFunc func() <-chan bool
// HijackFunc is part of the http.Hijacker interface.
type HijackFunc func() (net.Conn, *bufio.ReadWriter, error)
// ReadFromFunc is part of the io.ReaderFrom interface.
type ReadFromFunc func(src io.Reader) (int64, error)
// PushFunc is part of the http.Pusher interface.
type PushFunc func(target string, opts *http.PushOptions) error
// Hooks defines a set of method interceptors for methods included in
// http.ResponseWriter as well as some others. You can think of them as
// middleware for the function calls they target. See Wrap for more details.
type Hooks struct {
Header func(HeaderFunc) HeaderFunc
WriteHeader func(WriteHeaderFunc) WriteHeaderFunc
Write func(WriteFunc) WriteFunc
Flush func(FlushFunc) FlushFunc
CloseNotify func(CloseNotifyFunc) CloseNotifyFunc
Hijack func(HijackFunc) HijackFunc
ReadFrom func(ReadFromFunc) ReadFromFunc
Push func(PushFunc) PushFunc
}
// Wrap returns a wrapped version of w that provides the exact same interface
// as w. Specifically if w implements any combination of:
//
// - http.Flusher
// - http.CloseNotifier
// - http.Hijacker
// - io.ReaderFrom
// - http.Pusher
//
// The wrapped version will implement the exact same combination. If no hooks
// are set, the wrapped version also behaves exactly as w. Hooks targeting
// methods not supported by w are ignored. Any other hooks will intercept the
// method they target and may modify the call's arguments and/or return values.
// The CaptureMetrics implementation serves as a working example for how the
// hooks can be used.
func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {
rw := &rw{w: w, h: hooks}
_, i0 := w.(http.Flusher)
_, i1 := w.(http.CloseNotifier)
_, i2 := w.(http.Hijacker)
_, i3 := w.(io.ReaderFrom)
_, i4 := w.(http.Pusher)
switch {
// combination 1/32
case !i0 && !i1 && !i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
}{rw, rw}
// combination 2/32
case !i0 && !i1 && !i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Pusher
}{rw, rw, rw}
// combination 3/32
case !i0 && !i1 && !i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
io.ReaderFrom
}{rw, rw, rw}
// combination 4/32
case !i0 && !i1 && !i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw}
// combination 5/32
case !i0 && !i1 && i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Hijacker
}{rw, rw, rw}
// combination 6/32
case !i0 && !i1 && i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Hijacker
http.Pusher
}{rw, rw, rw, rw}
// combination 7/32
case !i0 && !i1 && i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw}
// combination 8/32
case !i0 && !i1 && i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Hijacker
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw, rw}
// combination 9/32
case !i0 && i1 && !i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
}{rw, rw, rw}
// combination 10/32
case !i0 && i1 && !i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
http.Pusher
}{rw, rw, rw, rw}
// combination 11/32
case !i0 && i1 && !i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
io.ReaderFrom
}{rw, rw, rw, rw}
// combination 12/32
case !i0 && i1 && !i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw, rw}
// combination 13/32
case !i0 && i1 && i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
http.Hijacker
}{rw, rw, rw, rw}
// combination 14/32
case !i0 && i1 && i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
http.Hijacker
http.Pusher
}{rw, rw, rw, rw, rw}
// combination 15/32
case !i0 && i1 && i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw, rw}
// combination 16/32
case !i0 && i1 && i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
http.Hijacker
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw, rw, rw}
// combination 17/32
case i0 && !i1 && !i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
}{rw, rw, rw}
// combination 18/32
case i0 && !i1 && !i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.Pusher
}{rw, rw, rw, rw}
// combination 19/32
case i0 && !i1 && !i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
io.ReaderFrom
}{rw, rw, rw, rw}
// combination 20/32
case i0 && !i1 && !i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw, rw}
// combination 21/32
case i0 && !i1 && i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.Hijacker
}{rw, rw, rw, rw}
// combination 22/32
case i0 && !i1 && i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.Hijacker
http.Pusher
}{rw, rw, rw, rw, rw}
// combination 23/32
case i0 && !i1 && i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw, rw}
// combination 24/32
case i0 && !i1 && i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.Hijacker
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw, rw, rw}
// combination 25/32
case i0 && i1 && !i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
}{rw, rw, rw, rw}
// combination 26/32
case i0 && i1 && !i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
http.Pusher
}{rw, rw, rw, rw, rw}
// combination 27/32
case i0 && i1 && !i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
io.ReaderFrom
}{rw, rw, rw, rw, rw}
// combination 28/32
case i0 && i1 && !i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw, rw, rw}
// combination 29/32
case i0 && i1 && i2 && !i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
http.Hijacker
}{rw, rw, rw, rw, rw}
// combination 30/32
case i0 && i1 && i2 && !i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
http.Hijacker
http.Pusher
}{rw, rw, rw, rw, rw, rw}
// combination 31/32
case i0 && i1 && i2 && i3 && !i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw, rw, rw}
// combination 32/32
case i0 && i1 && i2 && i3 && i4:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
http.Hijacker
io.ReaderFrom
http.Pusher
}{rw, rw, rw, rw, rw, rw, rw}
}
panic("unreachable")
}
type rw struct {
w http.ResponseWriter
h Hooks
}
func (w *rw) Unwrap() http.ResponseWriter {
return w.w
}
func (w *rw) Header() http.Header {
f := w.w.(http.ResponseWriter).Header
if w.h.Header != nil {
f = w.h.Header(f)
}
return f()
}
func (w *rw) WriteHeader(code int) {
f := w.w.(http.ResponseWriter).WriteHeader
if w.h.WriteHeader != nil {
f = w.h.WriteHeader(f)
}
f(code)
}
func (w *rw) Write(b []byte) (int, error) {
f := w.w.(http.ResponseWriter).Write
if w.h.Write != nil {
f = w.h.Write(f)
}
return f(b)
}
func (w *rw) Flush() {
f := w.w.(http.Flusher).Flush
if w.h.Flush != nil {
f = w.h.Flush(f)
}
f()
}
func (w *rw) CloseNotify() <-chan bool {
f := w.w.(http.CloseNotifier).CloseNotify
if w.h.CloseNotify != nil {
f = w.h.CloseNotify(f)
}
return f()
}
func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) {
f := w.w.(http.Hijacker).Hijack
if w.h.Hijack != nil {
f = w.h.Hijack(f)
}
return f()
}
func (w *rw) ReadFrom(src io.Reader) (int64, error) {
f := w.w.(io.ReaderFrom).ReadFrom
if w.h.ReadFrom != nil {
f = w.h.ReadFrom(f)
}
return f(src)
}
func (w *rw) Push(target string, opts *http.PushOptions) error {
f := w.w.(http.Pusher).Push
if w.h.Push != nil {
f = w.h.Push(f)
}
return f(target, opts)
}
type Unwrapper interface {
Unwrap() http.ResponseWriter
}
// Unwrap returns the underlying http.ResponseWriter from within zero or more
// layers of httpsnoop wrappers.
func Unwrap(w http.ResponseWriter) http.ResponseWriter {
if rw, ok := w.(Unwrapper); ok {
// recurse until rw.Unwrap() returns a non-Unwrapper
return Unwrap(rw.Unwrap())
} else {
return w
}
}

View file

@ -0,0 +1,278 @@
// +build !go1.8
// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
package httpsnoop
import (
"bufio"
"io"
"net"
"net/http"
)
// HeaderFunc is part of the http.ResponseWriter interface.
type HeaderFunc func() http.Header
// WriteHeaderFunc is part of the http.ResponseWriter interface.
type WriteHeaderFunc func(code int)
// WriteFunc is part of the http.ResponseWriter interface.
type WriteFunc func(b []byte) (int, error)
// FlushFunc is part of the http.Flusher interface.
type FlushFunc func()
// CloseNotifyFunc is part of the http.CloseNotifier interface.
type CloseNotifyFunc func() <-chan bool
// HijackFunc is part of the http.Hijacker interface.
type HijackFunc func() (net.Conn, *bufio.ReadWriter, error)
// ReadFromFunc is part of the io.ReaderFrom interface.
type ReadFromFunc func(src io.Reader) (int64, error)
// Hooks defines a set of method interceptors for methods included in
// http.ResponseWriter as well as some others. You can think of them as
// middleware for the function calls they target. See Wrap for more details.
type Hooks struct {
Header func(HeaderFunc) HeaderFunc
WriteHeader func(WriteHeaderFunc) WriteHeaderFunc
Write func(WriteFunc) WriteFunc
Flush func(FlushFunc) FlushFunc
CloseNotify func(CloseNotifyFunc) CloseNotifyFunc
Hijack func(HijackFunc) HijackFunc
ReadFrom func(ReadFromFunc) ReadFromFunc
}
// Wrap returns a wrapped version of w that provides the exact same interface
// as w. Specifically if w implements any combination of:
//
// - http.Flusher
// - http.CloseNotifier
// - http.Hijacker
// - io.ReaderFrom
//
// The wrapped version will implement the exact same combination. If no hooks
// are set, the wrapped version also behaves exactly as w. Hooks targeting
// methods not supported by w are ignored. Any other hooks will intercept the
// method they target and may modify the call's arguments and/or return values.
// The CaptureMetrics implementation serves as a working example for how the
// hooks can be used.
func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {
rw := &rw{w: w, h: hooks}
_, i0 := w.(http.Flusher)
_, i1 := w.(http.CloseNotifier)
_, i2 := w.(http.Hijacker)
_, i3 := w.(io.ReaderFrom)
switch {
// combination 1/16
case !i0 && !i1 && !i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
}{rw, rw}
// combination 2/16
case !i0 && !i1 && !i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
io.ReaderFrom
}{rw, rw, rw}
// combination 3/16
case !i0 && !i1 && i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
http.Hijacker
}{rw, rw, rw}
// combination 4/16
case !i0 && !i1 && i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw}
// combination 5/16
case !i0 && i1 && !i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
}{rw, rw, rw}
// combination 6/16
case !i0 && i1 && !i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
io.ReaderFrom
}{rw, rw, rw, rw}
// combination 7/16
case !i0 && i1 && i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
http.Hijacker
}{rw, rw, rw, rw}
// combination 8/16
case !i0 && i1 && i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
http.CloseNotifier
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw, rw}
// combination 9/16
case i0 && !i1 && !i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
}{rw, rw, rw}
// combination 10/16
case i0 && !i1 && !i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
io.ReaderFrom
}{rw, rw, rw, rw}
// combination 11/16
case i0 && !i1 && i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.Hijacker
}{rw, rw, rw, rw}
// combination 12/16
case i0 && !i1 && i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw, rw}
// combination 13/16
case i0 && i1 && !i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
}{rw, rw, rw, rw}
// combination 14/16
case i0 && i1 && !i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
io.ReaderFrom
}{rw, rw, rw, rw, rw}
// combination 15/16
case i0 && i1 && i2 && !i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
http.Hijacker
}{rw, rw, rw, rw, rw}
// combination 16/16
case i0 && i1 && i2 && i3:
return struct {
Unwrapper
http.ResponseWriter
http.Flusher
http.CloseNotifier
http.Hijacker
io.ReaderFrom
}{rw, rw, rw, rw, rw, rw}
}
panic("unreachable")
}
type rw struct {
w http.ResponseWriter
h Hooks
}
func (w *rw) Unwrap() http.ResponseWriter {
return w.w
}
func (w *rw) Header() http.Header {
f := w.w.(http.ResponseWriter).Header
if w.h.Header != nil {
f = w.h.Header(f)
}
return f()
}
func (w *rw) WriteHeader(code int) {
f := w.w.(http.ResponseWriter).WriteHeader
if w.h.WriteHeader != nil {
f = w.h.WriteHeader(f)
}
f(code)
}
func (w *rw) Write(b []byte) (int, error) {
f := w.w.(http.ResponseWriter).Write
if w.h.Write != nil {
f = w.h.Write(f)
}
return f(b)
}
func (w *rw) Flush() {
f := w.w.(http.Flusher).Flush
if w.h.Flush != nil {
f = w.h.Flush(f)
}
f()
}
func (w *rw) CloseNotify() <-chan bool {
f := w.w.(http.CloseNotifier).CloseNotify
if w.h.CloseNotify != nil {
f = w.h.CloseNotify(f)
}
return f()
}
func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) {
f := w.w.(http.Hijacker).Hijack
if w.h.Hijack != nil {
f = w.h.Hijack(f)
}
return f()
}
func (w *rw) ReadFrom(src io.Reader) (int64, error) {
f := w.w.(io.ReaderFrom).ReadFrom
if w.h.ReadFrom != nil {
f = w.h.ReadFrom(f)
}
return f(src)
}
type Unwrapper interface {
Unwrap() http.ResponseWriter
}
// Unwrap returns the underlying http.ResponseWriter from within zero or more
// layers of httpsnoop wrappers.
func Unwrap(w http.ResponseWriter) http.ResponseWriter {
if rw, ok := w.(Unwrapper); ok {
// recurse until rw.Unwrap() returns a non-Unwrapper
return Unwrap(rw.Unwrap())
} else {
return w
}
}

26
vendor/github.com/go-logr/logr/.golangci.yaml generated vendored Normal file
View file

@ -0,0 +1,26 @@
run:
timeout: 1m
tests: true
linters:
disable-all: true
enable:
- asciicheck
- errcheck
- forcetypeassert
- gocritic
- gofmt
- goimports
- gosimple
- govet
- ineffassign
- misspell
- revive
- staticcheck
- typecheck
- unused
issues:
exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 10

6
vendor/github.com/go-logr/logr/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,6 @@
# CHANGELOG
## v1.0.0-rc1
This is the first logged release. Major changes (including breaking changes)
have occurred since earlier tags.

17
vendor/github.com/go-logr/logr/CONTRIBUTING.md generated vendored Normal file
View file

@ -0,0 +1,17 @@
# Contributing
Logr is open to pull-requests, provided they fit within the intended scope of
the project. Specifically, this library aims to be VERY small and minimalist,
with no external dependencies.
## Compatibility
This project intends to follow [semantic versioning](http://semver.org) and
is very strict about compatibility. Any proposed changes MUST follow those
rules.
## Performance
As a logging library, logr must be as light-weight as possible. Any proposed
code change must include results of running the [benchmark](./benchmark)
before and after the change.

201
vendor/github.com/go-logr/logr/LICENSE generated vendored Normal file
View file

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

393
vendor/github.com/go-logr/logr/README.md generated vendored Normal file
View file

@ -0,0 +1,393 @@
# A minimal logging API for Go
[![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-logr/logr/badge)](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr)
logr offers an(other) opinion on how Go programs and libraries can do logging
without becoming coupled to a particular logging implementation. This is not
an implementation of logging - it is an API. In fact it is two APIs with two
different sets of users.
The `Logger` type is intended for application and library authors. It provides
a relatively small API which can be used everywhere you want to emit logs. It
defers the actual act of writing logs (to files, to stdout, or whatever) to the
`LogSink` interface.
The `LogSink` interface is intended for logging library implementers. It is a
pure interface which can be implemented by logging frameworks to provide the actual logging
functionality.
This decoupling allows application and library developers to write code in
terms of `logr.Logger` (which has very low dependency fan-out) while the
implementation of logging is managed "up stack" (e.g. in or near `main()`.)
Application developers can then switch out implementations as necessary.
Many people assert that libraries should not be logging, and as such efforts
like this are pointless. Those people are welcome to convince the authors of
the tens-of-thousands of libraries that *DO* write logs that they are all
wrong. In the meantime, logr takes a more practical approach.
## Typical usage
Somewhere, early in an application's life, it will make a decision about which
logging library (implementation) it actually wants to use. Something like:
```
func main() {
// ... other setup code ...
// Create the "root" logger. We have chosen the "logimpl" implementation,
// which takes some initial parameters and returns a logr.Logger.
logger := logimpl.New(param1, param2)
// ... other setup code ...
```
Most apps will call into other libraries, create structures to govern the flow,
etc. The `logr.Logger` object can be passed to these other libraries, stored
in structs, or even used as a package-global variable, if needed. For example:
```
app := createTheAppObject(logger)
app.Run()
```
Outside of this early setup, no other packages need to know about the choice of
implementation. They write logs in terms of the `logr.Logger` that they
received:
```
type appObject struct {
// ... other fields ...
logger logr.Logger
// ... other fields ...
}
func (app *appObject) Run() {
app.logger.Info("starting up", "timestamp", time.Now())
// ... app code ...
```
## Background
If the Go standard library had defined an interface for logging, this project
probably would not be needed. Alas, here we are.
When the Go developers started developing such an interface with
[slog](https://github.com/golang/go/issues/56345), they adopted some of the
logr design but also left out some parts and changed others:
| Feature | logr | slog |
|---------|------|------|
| High-level API | `Logger` (passed by value) | `Logger` (passed by [pointer](https://github.com/golang/go/issues/59126)) |
| Low-level API | `LogSink` | `Handler` |
| Stack unwinding | done by `LogSink` | done by `Logger` |
| Skipping helper functions | `WithCallDepth`, `WithCallStackHelper` | [not supported by Logger](https://github.com/golang/go/issues/59145) |
| Generating a value for logging on demand | `Marshaler` | `LogValuer` |
| Log levels | >= 0, higher meaning "less important" | positive and negative, with 0 for "info" and higher meaning "more important" |
| Error log entries | always logged, don't have a verbosity level | normal log entries with level >= `LevelError` |
| Passing logger via context | `NewContext`, `FromContext` | no API |
| Adding a name to a logger | `WithName` | no API |
| Modify verbosity of log entries in a call chain | `V` | no API |
| Grouping of key/value pairs | not supported | `WithGroup`, `GroupValue` |
The high-level slog API is explicitly meant to be one of many different APIs
that can be layered on top of a shared `slog.Handler`. logr is one such
alternative API, with [interoperability](#slog-interoperability) provided by the [`slogr`](slogr)
package.
### Inspiration
Before you consider this package, please read [this blog post by the
inimitable Dave Cheney][warning-makes-no-sense]. We really appreciate what
he has to say, and it largely aligns with our own experiences.
### Differences from Dave's ideas
The main differences are:
1. Dave basically proposes doing away with the notion of a logging API in favor
of `fmt.Printf()`. We disagree, especially when you consider things like output
locations, timestamps, file and line decorations, and structured logging. This
package restricts the logging API to just 2 types of logs: info and error.
Info logs are things you want to tell the user which are not errors. Error
logs are, well, errors. If your code receives an `error` from a subordinate
function call and is logging that `error` *and not returning it*, use error
logs.
2. Verbosity-levels on info logs. This gives developers a chance to indicate
arbitrary grades of importance for info logs, without assigning names with
semantic meaning such as "warning", "trace", and "debug." Superficially this
may feel very similar, but the primary difference is the lack of semantics.
Because verbosity is a numerical value, it's safe to assume that an app running
with higher verbosity means more (and less important) logs will be generated.
## Implementations (non-exhaustive)
There are implementations for the following logging libraries:
- **a function** (can bridge to non-structured libraries): [funcr](https://github.com/go-logr/logr/tree/master/funcr)
- **a testing.T** (for use in Go tests, with JSON-like output): [testr](https://github.com/go-logr/logr/tree/master/testr)
- **github.com/google/glog**: [glogr](https://github.com/go-logr/glogr)
- **k8s.io/klog** (for Kubernetes): [klogr](https://git.k8s.io/klog/klogr)
- **a testing.T** (with klog-like text output): [ktesting](https://git.k8s.io/klog/ktesting)
- **go.uber.org/zap**: [zapr](https://github.com/go-logr/zapr)
- **log** (the Go standard library logger): [stdr](https://github.com/go-logr/stdr)
- **github.com/sirupsen/logrus**: [logrusr](https://github.com/bombsimon/logrusr)
- **github.com/wojas/genericr**: [genericr](https://github.com/wojas/genericr) (makes it easy to implement your own backend)
- **logfmt** (Heroku style [logging](https://www.brandur.org/logfmt)): [logfmtr](https://github.com/iand/logfmtr)
- **github.com/rs/zerolog**: [zerologr](https://github.com/go-logr/zerologr)
- **github.com/go-kit/log**: [gokitlogr](https://github.com/tonglil/gokitlogr) (also compatible with github.com/go-kit/kit/log since v0.12.0)
- **bytes.Buffer** (writing to a buffer): [bufrlogr](https://github.com/tonglil/buflogr) (useful for ensuring values were logged, like during testing)
## slog interoperability
Interoperability goes both ways, using the `logr.Logger` API with a `slog.Handler`
and using the `slog.Logger` API with a `logr.LogSink`. [slogr](./slogr) provides `NewLogr` and
`NewSlogHandler` API calls to convert between a `logr.Logger` and a `slog.Handler`.
As usual, `slog.New` can be used to wrap such a `slog.Handler` in the high-level
slog API. `slogr` itself leaves that to the caller.
## Using a `logr.Sink` as backend for slog
Ideally, a logr sink implementation should support both logr and slog by
implementing both the normal logr interface(s) and `slogr.SlogSink`. Because
of a conflict in the parameters of the common `Enabled` method, it is [not
possible to implement both slog.Handler and logr.Sink in the same
type](https://github.com/golang/go/issues/59110).
If both are supported, log calls can go from the high-level APIs to the backend
without the need to convert parameters. `NewLogr` and `NewSlogHandler` can
convert back and forth without adding additional wrappers, with one exception:
when `Logger.V` was used to adjust the verbosity for a `slog.Handler`, then
`NewSlogHandler` has to use a wrapper which adjusts the verbosity for future
log calls.
Such an implementation should also support values that implement specific
interfaces from both packages for logging (`logr.Marshaler`, `slog.LogValuer`,
`slog.GroupValue`). logr does not convert those.
Not supporting slog has several drawbacks:
- Recording source code locations works correctly if the handler gets called
through `slog.Logger`, but may be wrong in other cases. That's because a
`logr.Sink` does its own stack unwinding instead of using the program counter
provided by the high-level API.
- slog levels <= 0 can be mapped to logr levels by negating the level without a
loss of information. But all slog levels > 0 (e.g. `slog.LevelWarning` as
used by `slog.Logger.Warn`) must be mapped to 0 before calling the sink
because logr does not support "more important than info" levels.
- The slog group concept is supported by prefixing each key in a key/value
pair with the group names, separated by a dot. For structured output like
JSON it would be better to group the key/value pairs inside an object.
- Special slog values and interfaces don't work as expected.
- The overhead is likely to be higher.
These drawbacks are severe enough that applications using a mixture of slog and
logr should switch to a different backend.
## Using a `slog.Handler` as backend for logr
Using a plain `slog.Handler` without support for logr works better than the
other direction:
- All logr verbosity levels can be mapped 1:1 to their corresponding slog level
by negating them.
- Stack unwinding is done by the `slogr.SlogSink` and the resulting program
counter is passed to the `slog.Handler`.
- Names added via `Logger.WithName` are gathered and recorded in an additional
attribute with `logger` as key and the names separated by slash as value.
- `Logger.Error` is turned into a log record with `slog.LevelError` as level
and an additional attribute with `err` as key, if an error was provided.
The main drawback is that `logr.Marshaler` will not be supported. Types should
ideally support both `logr.Marshaler` and `slog.Valuer`. If compatibility
with logr implementations without slog support is not important, then
`slog.Valuer` is sufficient.
## Context support for slog
Storing a logger in a `context.Context` is not supported by
slog. `logr.NewContext` and `logr.FromContext` can be used with slog like this
to fill this gap:
func HandlerFromContext(ctx context.Context) slog.Handler {
logger, err := logr.FromContext(ctx)
if err == nil {
return slogr.NewSlogHandler(logger)
}
return slog.Default().Handler()
}
func ContextWithHandler(ctx context.Context, handler slog.Handler) context.Context {
return logr.NewContext(ctx, slogr.NewLogr(handler))
}
The downside is that storing and retrieving a `slog.Handler` needs more
allocations compared to using a `logr.Logger`. Therefore the recommendation is
to use the `logr.Logger` API in code which uses contextual logging.
## FAQ
### Conceptual
#### Why structured logging?
- **Structured logs are more easily queryable**: Since you've got
key-value pairs, it's much easier to query your structured logs for
particular values by filtering on the contents of a particular key --
think searching request logs for error codes, Kubernetes reconcilers for
the name and namespace of the reconciled object, etc.
- **Structured logging makes it easier to have cross-referenceable logs**:
Similarly to searchability, if you maintain conventions around your
keys, it becomes easy to gather all log lines related to a particular
concept.
- **Structured logs allow better dimensions of filtering**: if you have
structure to your logs, you've got more precise control over how much
information is logged -- you might choose in a particular configuration
to log certain keys but not others, only log lines where a certain key
matches a certain value, etc., instead of just having v-levels and names
to key off of.
- **Structured logs better represent structured data**: sometimes, the
data that you want to log is inherently structured (think tuple-link
objects.) Structured logs allow you to preserve that structure when
outputting.
#### Why V-levels?
**V-levels give operators an easy way to control the chattiness of log
operations**. V-levels provide a way for a given package to distinguish
the relative importance or verbosity of a given log message. Then, if
a particular logger or package is logging too many messages, the user
of the package can simply change the v-levels for that library.
#### Why not named levels, like Info/Warning/Error?
Read [Dave Cheney's post][warning-makes-no-sense]. Then read [Differences
from Dave's ideas](#differences-from-daves-ideas).
#### Why not allow format strings, too?
**Format strings negate many of the benefits of structured logs**:
- They're not easily searchable without resorting to fuzzy searching,
regular expressions, etc.
- They don't store structured data well, since contents are flattened into
a string.
- They're not cross-referenceable.
- They don't compress easily, since the message is not constant.
(Unless you turn positional parameters into key-value pairs with numerical
keys, at which point you've gotten key-value logging with meaningless
keys.)
### Practical
#### Why key-value pairs, and not a map?
Key-value pairs are *much* easier to optimize, especially around
allocations. Zap (a structured logger that inspired logr's interface) has
[performance measurements](https://github.com/uber-go/zap#performance)
that show this quite nicely.
While the interface ends up being a little less obvious, you get
potentially better performance, plus avoid making users type
`map[string]string{}` every time they want to log.
#### What if my V-levels differ between libraries?
That's fine. Control your V-levels on a per-logger basis, and use the
`WithName` method to pass different loggers to different libraries.
Generally, you should take care to ensure that you have relatively
consistent V-levels within a given logger, however, as this makes deciding
on what verbosity of logs to request easier.
#### But I really want to use a format string!
That's not actually a question. Assuming your question is "how do
I convert my mental model of logging with format strings to logging with
constant messages":
1. Figure out what the error actually is, as you'd write in a TL;DR style,
and use that as a message.
2. For every place you'd write a format specifier, look to the word before
it, and add that as a key value pair.
For instance, consider the following examples (all taken from spots in the
Kubernetes codebase):
- `klog.V(4).Infof("Client is returning errors: code %v, error %v",
responseCode, err)` becomes `logger.Error(err, "client returned an
error", "code", responseCode)`
- `klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v",
seconds, retries, url)` becomes `logger.V(4).Info("got a retry-after
response when requesting url", "attempt", retries, "after
seconds", seconds, "url", url)`
If you *really* must use a format string, use it in a key's value, and
call `fmt.Sprintf` yourself. For instance: `log.Printf("unable to
reflect over type %T")` becomes `logger.Info("unable to reflect over
type", "type", fmt.Sprintf("%T"))`. In general though, the cases where
this is necessary should be few and far between.
#### How do I choose my V-levels?
This is basically the only hard constraint: increase V-levels to denote
more verbose or more debug-y logs.
Otherwise, you can start out with `0` as "you always want to see this",
`1` as "common logging that you might *possibly* want to turn off", and
`10` as "I would like to performance-test your log collection stack."
Then gradually choose levels in between as you need them, working your way
down from 10 (for debug and trace style logs) and up from 1 (for chattier
info-type logs). For reference, slog pre-defines -4 for debug logs
(corresponds to 4 in logr), which matches what is
[recommended for Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md#what-method-to-use).
#### How do I choose my keys?
Keys are fairly flexible, and can hold more or less any string
value. For best compatibility with implementations and consistency
with existing code in other projects, there are a few conventions you
should consider.
- Make your keys human-readable.
- Constant keys are generally a good idea.
- Be consistent across your codebase.
- Keys should naturally match parts of the message string.
- Use lower case for simple keys and
[lowerCamelCase](https://en.wiktionary.org/wiki/lowerCamelCase) for
more complex ones. Kubernetes is one example of a project that has
[adopted that
convention](https://github.com/kubernetes/community/blob/HEAD/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments).
While key names are mostly unrestricted (and spaces are acceptable),
it's generally a good idea to stick to printable ascii characters, or at
least match the general character set of your log lines.
#### Why should keys be constant values?
The point of structured logging is to make later log processing easier. Your
keys are, effectively, the schema of each log message. If you use different
keys across instances of the same log line, you will make your structured logs
much harder to use. `Sprintf()` is for values, not for keys!
#### Why is this not a pure interface?
The Logger type is implemented as a struct in order to allow the Go compiler to
optimize things like high-V `Info` logs that are not triggered. Not all of
these implementations are implemented yet, but this structure was suggested as
a way to ensure they *can* be implemented. All of the real work is behind the
`LogSink` interface.
[warning-makes-no-sense]: http://dave.cheney.net/2015/11/05/lets-talk-about-logging

18
vendor/github.com/go-logr/logr/SECURITY.md generated vendored Normal file
View file

@ -0,0 +1,18 @@
# Security Policy
If you have discovered a security vulnerability in this project, please report it
privately. **Do not disclose it as a public issue.** This gives us time to work with you
to fix the issue before public exposure, reducing the chance that the exploit will be
used before a patch is released.
You may submit the report in the following ways:
- send an email to go-logr-security@googlegroups.com
- send us a [private vulnerability report](https://github.com/go-logr/logr/security/advisories/new)
Please provide the following information in your report:
- A description of the vulnerability and its impact
- How to reproduce the issue
We ask that you give us 90 days to work on a fix before public exposure.

24
vendor/github.com/go-logr/logr/discard.go generated vendored Normal file
View file

@ -0,0 +1,24 @@
/*
Copyright 2020 The logr Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package logr
// Discard returns a Logger that discards all messages logged to it. It can be
// used whenever the caller is not interested in the logs. Logger instances
// produced by this function always compare as equal.
func Discard() Logger {
return New(nil)
}

804
vendor/github.com/go-logr/logr/funcr/funcr.go generated vendored Normal file
View file

@ -0,0 +1,804 @@
/*
Copyright 2021 The logr Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package funcr implements formatting of structured log messages and
// optionally captures the call site and timestamp.
//
// The simplest way to use it is via its implementation of a
// github.com/go-logr/logr.LogSink with output through an arbitrary
// "write" function. See New and NewJSON for details.
//
// # Custom LogSinks
//
// For users who need more control, a funcr.Formatter can be embedded inside
// your own custom LogSink implementation. This is useful when the LogSink
// needs to implement additional methods, for example.
//
// # Formatting
//
// This will respect logr.Marshaler, fmt.Stringer, and error interfaces for
// values which are being logged. When rendering a struct, funcr will use Go's
// standard JSON tags (all except "string").
package funcr
import (
"bytes"
"encoding"
"encoding/json"
"fmt"
"path/filepath"
"reflect"
"runtime"
"strconv"
"strings"
"time"
"github.com/go-logr/logr"
)
// New returns a logr.Logger which is implemented by an arbitrary function.
func New(fn func(prefix, args string), opts Options) logr.Logger {
return logr.New(newSink(fn, NewFormatter(opts)))
}
// NewJSON returns a logr.Logger which is implemented by an arbitrary function
// and produces JSON output.
func NewJSON(fn func(obj string), opts Options) logr.Logger {
fnWrapper := func(_, obj string) {
fn(obj)
}
return logr.New(newSink(fnWrapper, NewFormatterJSON(opts)))
}
// Underlier exposes access to the underlying logging function. Since
// callers only have a logr.Logger, they have to know which
// implementation is in use, so this interface is less of an
// abstraction and more of a way to test type conversion.
type Underlier interface {
GetUnderlying() func(prefix, args string)
}
func newSink(fn func(prefix, args string), formatter Formatter) logr.LogSink {
l := &fnlogger{
Formatter: formatter,
write: fn,
}
// For skipping fnlogger.Info and fnlogger.Error.
l.Formatter.AddCallDepth(1)
return l
}
// Options carries parameters which influence the way logs are generated.
type Options struct {
// LogCaller tells funcr to add a "caller" key to some or all log lines.
// This has some overhead, so some users might not want it.
LogCaller MessageClass
// LogCallerFunc tells funcr to also log the calling function name. This
// has no effect if caller logging is not enabled (see Options.LogCaller).
LogCallerFunc bool
// LogTimestamp tells funcr to add a "ts" key to log lines. This has some
// overhead, so some users might not want it.
LogTimestamp bool
// TimestampFormat tells funcr how to render timestamps when LogTimestamp
// is enabled. If not specified, a default format will be used. For more
// details, see docs for Go's time.Layout.
TimestampFormat string
// Verbosity tells funcr which V logs to produce. Higher values enable
// more logs. Info logs at or below this level will be written, while logs
// above this level will be discarded.
Verbosity int
// RenderBuiltinsHook allows users to mutate the list of key-value pairs
// while a log line is being rendered. The kvList argument follows logr
// conventions - each pair of slice elements is comprised of a string key
// and an arbitrary value (verified and sanitized before calling this
// hook). The value returned must follow the same conventions. This hook
// can be used to audit or modify logged data. For example, you might want
// to prefix all of funcr's built-in keys with some string. This hook is
// only called for built-in (provided by funcr itself) key-value pairs.
// Equivalent hooks are offered for key-value pairs saved via
// logr.Logger.WithValues or Formatter.AddValues (see RenderValuesHook) and
// for user-provided pairs (see RenderArgsHook).
RenderBuiltinsHook func(kvList []any) []any
// RenderValuesHook is the same as RenderBuiltinsHook, except that it is
// only called for key-value pairs saved via logr.Logger.WithValues. See
// RenderBuiltinsHook for more details.
RenderValuesHook func(kvList []any) []any
// RenderArgsHook is the same as RenderBuiltinsHook, except that it is only
// called for key-value pairs passed directly to Info and Error. See
// RenderBuiltinsHook for more details.
RenderArgsHook func(kvList []any) []any
// MaxLogDepth tells funcr how many levels of nested fields (e.g. a struct
// that contains a struct, etc.) it may log. Every time it finds a struct,
// slice, array, or map the depth is increased by one. When the maximum is
// reached, the value will be converted to a string indicating that the max
// depth has been exceeded. If this field is not specified, a default
// value will be used.
MaxLogDepth int
}
// MessageClass indicates which category or categories of messages to consider.
type MessageClass int
const (
// None ignores all message classes.
None MessageClass = iota
// All considers all message classes.
All
// Info only considers info messages.
Info
// Error only considers error messages.
Error
)
// fnlogger inherits some of its LogSink implementation from Formatter
// and just needs to add some glue code.
type fnlogger struct {
Formatter
write func(prefix, args string)
}
func (l fnlogger) WithName(name string) logr.LogSink {
l.Formatter.AddName(name)
return &l
}
func (l fnlogger) WithValues(kvList ...any) logr.LogSink {
l.Formatter.AddValues(kvList)
return &l
}
func (l fnlogger) WithCallDepth(depth int) logr.LogSink {
l.Formatter.AddCallDepth(depth)
return &l
}
func (l fnlogger) Info(level int, msg string, kvList ...any) {
prefix, args := l.FormatInfo(level, msg, kvList)
l.write(prefix, args)
}
func (l fnlogger) Error(err error, msg string, kvList ...any) {
prefix, args := l.FormatError(err, msg, kvList)
l.write(prefix, args)
}
func (l fnlogger) GetUnderlying() func(prefix, args string) {
return l.write
}
// Assert conformance to the interfaces.
var _ logr.LogSink = &fnlogger{}
var _ logr.CallDepthLogSink = &fnlogger{}
var _ Underlier = &fnlogger{}
// NewFormatter constructs a Formatter which emits a JSON-like key=value format.
func NewFormatter(opts Options) Formatter {
return newFormatter(opts, outputKeyValue)
}
// NewFormatterJSON constructs a Formatter which emits strict JSON.
func NewFormatterJSON(opts Options) Formatter {
return newFormatter(opts, outputJSON)
}
// Defaults for Options.
const defaultTimestampFormat = "2006-01-02 15:04:05.000000"
const defaultMaxLogDepth = 16
func newFormatter(opts Options, outfmt outputFormat) Formatter {
if opts.TimestampFormat == "" {
opts.TimestampFormat = defaultTimestampFormat
}
if opts.MaxLogDepth == 0 {
opts.MaxLogDepth = defaultMaxLogDepth
}
f := Formatter{
outputFormat: outfmt,
prefix: "",
values: nil,
depth: 0,
opts: &opts,
}
return f
}
// Formatter is an opaque struct which can be embedded in a LogSink
// implementation. It should be constructed with NewFormatter. Some of
// its methods directly implement logr.LogSink.
type Formatter struct {
outputFormat outputFormat
prefix string
values []any
valuesStr string
depth int
opts *Options
}
// outputFormat indicates which outputFormat to use.
type outputFormat int
const (
// outputKeyValue emits a JSON-like key=value format, but not strict JSON.
outputKeyValue outputFormat = iota
// outputJSON emits strict JSON.
outputJSON
)
// PseudoStruct is a list of key-value pairs that gets logged as a struct.
type PseudoStruct []any
// render produces a log line, ready to use.
func (f Formatter) render(builtins, args []any) string {
// Empirically bytes.Buffer is faster than strings.Builder for this.
buf := bytes.NewBuffer(make([]byte, 0, 1024))
if f.outputFormat == outputJSON {
buf.WriteByte('{')
}
vals := builtins
if hook := f.opts.RenderBuiltinsHook; hook != nil {
vals = hook(f.sanitize(vals))
}
f.flatten(buf, vals, false, false) // keys are ours, no need to escape
continuing := len(builtins) > 0
if len(f.valuesStr) > 0 {
if continuing {
if f.outputFormat == outputJSON {
buf.WriteByte(',')
} else {
buf.WriteByte(' ')
}
}
continuing = true
buf.WriteString(f.valuesStr)
}
vals = args
if hook := f.opts.RenderArgsHook; hook != nil {
vals = hook(f.sanitize(vals))
}
f.flatten(buf, vals, continuing, true) // escape user-provided keys
if f.outputFormat == outputJSON {
buf.WriteByte('}')
}
return buf.String()
}
// flatten renders a list of key-value pairs into a buffer. If continuing is
// true, it assumes that the buffer has previous values and will emit a
// separator (which depends on the output format) before the first pair it
// writes. If escapeKeys is true, the keys are assumed to have
// non-JSON-compatible characters in them and must be evaluated for escapes.
//
// This function returns a potentially modified version of kvList, which
// ensures that there is a value for every key (adding a value if needed) and
// that each key is a string (substituting a key if needed).
func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, continuing bool, escapeKeys bool) []any {
// This logic overlaps with sanitize() but saves one type-cast per key,
// which can be measurable.
if len(kvList)%2 != 0 {
kvList = append(kvList, noValue)
}
for i := 0; i < len(kvList); i += 2 {
k, ok := kvList[i].(string)
if !ok {
k = f.nonStringKey(kvList[i])
kvList[i] = k
}
v := kvList[i+1]
if i > 0 || continuing {
if f.outputFormat == outputJSON {
buf.WriteByte(',')
} else {
// In theory the format could be something we don't understand. In
// practice, we control it, so it won't be.
buf.WriteByte(' ')
}
}
if escapeKeys {
buf.WriteString(prettyString(k))
} else {
// this is faster
buf.WriteByte('"')
buf.WriteString(k)
buf.WriteByte('"')
}
if f.outputFormat == outputJSON {
buf.WriteByte(':')
} else {
buf.WriteByte('=')
}
buf.WriteString(f.pretty(v))
}
return kvList
}
func (f Formatter) pretty(value any) string {
return f.prettyWithFlags(value, 0, 0)
}
const (
flagRawStruct = 0x1 // do not print braces on structs
)
// TODO: This is not fast. Most of the overhead goes here.
func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string {
if depth > f.opts.MaxLogDepth {
return `"<max-log-depth-exceeded>"`
}
// Handle types that take full control of logging.
if v, ok := value.(logr.Marshaler); ok {
// Replace the value with what the type wants to get logged.
// That then gets handled below via reflection.
value = invokeMarshaler(v)
}
// Handle types that want to format themselves.
switch v := value.(type) {
case fmt.Stringer:
value = invokeStringer(v)
case error:
value = invokeError(v)
}
// Handling the most common types without reflect is a small perf win.
switch v := value.(type) {
case bool:
return strconv.FormatBool(v)
case string:
return prettyString(v)
case int:
return strconv.FormatInt(int64(v), 10)
case int8:
return strconv.FormatInt(int64(v), 10)
case int16:
return strconv.FormatInt(int64(v), 10)
case int32:
return strconv.FormatInt(int64(v), 10)
case int64:
return strconv.FormatInt(int64(v), 10)
case uint:
return strconv.FormatUint(uint64(v), 10)
case uint8:
return strconv.FormatUint(uint64(v), 10)
case uint16:
return strconv.FormatUint(uint64(v), 10)
case uint32:
return strconv.FormatUint(uint64(v), 10)
case uint64:
return strconv.FormatUint(v, 10)
case uintptr:
return strconv.FormatUint(uint64(v), 10)
case float32:
return strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case complex64:
return `"` + strconv.FormatComplex(complex128(v), 'f', -1, 64) + `"`
case complex128:
return `"` + strconv.FormatComplex(v, 'f', -1, 128) + `"`
case PseudoStruct:
buf := bytes.NewBuffer(make([]byte, 0, 1024))
v = f.sanitize(v)
if flags&flagRawStruct == 0 {
buf.WriteByte('{')
}
for i := 0; i < len(v); i += 2 {
if i > 0 {
buf.WriteByte(',')
}
k, _ := v[i].(string) // sanitize() above means no need to check success
// arbitrary keys might need escaping
buf.WriteString(prettyString(k))
buf.WriteByte(':')
buf.WriteString(f.prettyWithFlags(v[i+1], 0, depth+1))
}
if flags&flagRawStruct == 0 {
buf.WriteByte('}')
}
return buf.String()
}
buf := bytes.NewBuffer(make([]byte, 0, 256))
t := reflect.TypeOf(value)
if t == nil {
return "null"
}
v := reflect.ValueOf(value)
switch t.Kind() {
case reflect.Bool:
return strconv.FormatBool(v.Bool())
case reflect.String:
return prettyString(v.String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(int64(v.Int()), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return strconv.FormatUint(uint64(v.Uint()), 10)
case reflect.Float32:
return strconv.FormatFloat(float64(v.Float()), 'f', -1, 32)
case reflect.Float64:
return strconv.FormatFloat(v.Float(), 'f', -1, 64)
case reflect.Complex64:
return `"` + strconv.FormatComplex(complex128(v.Complex()), 'f', -1, 64) + `"`
case reflect.Complex128:
return `"` + strconv.FormatComplex(v.Complex(), 'f', -1, 128) + `"`
case reflect.Struct:
if flags&flagRawStruct == 0 {
buf.WriteByte('{')
}
printComma := false // testing i>0 is not enough because of JSON omitted fields
for i := 0; i < t.NumField(); i++ {
fld := t.Field(i)
if fld.PkgPath != "" {
// reflect says this field is only defined for non-exported fields.
continue
}
if !v.Field(i).CanInterface() {
// reflect isn't clear exactly what this means, but we can't use it.
continue
}
name := ""
omitempty := false
if tag, found := fld.Tag.Lookup("json"); found {
if tag == "-" {
continue
}
if comma := strings.Index(tag, ","); comma != -1 {
if n := tag[:comma]; n != "" {
name = n
}
rest := tag[comma:]
if strings.Contains(rest, ",omitempty,") || strings.HasSuffix(rest, ",omitempty") {
omitempty = true
}
} else {
name = tag
}
}
if omitempty && isEmpty(v.Field(i)) {
continue
}
if printComma {
buf.WriteByte(',')
}
printComma = true // if we got here, we are rendering a field
if fld.Anonymous && fld.Type.Kind() == reflect.Struct && name == "" {
buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), flags|flagRawStruct, depth+1))
continue
}
if name == "" {
name = fld.Name
}
// field names can't contain characters which need escaping
buf.WriteByte('"')
buf.WriteString(name)
buf.WriteByte('"')
buf.WriteByte(':')
buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), 0, depth+1))
}
if flags&flagRawStruct == 0 {
buf.WriteByte('}')
}
return buf.String()
case reflect.Slice, reflect.Array:
// If this is outputing as JSON make sure this isn't really a json.RawMessage.
// If so just emit "as-is" and don't pretty it as that will just print
// it as [X,Y,Z,...] which isn't terribly useful vs the string form you really want.
if f.outputFormat == outputJSON {
if rm, ok := value.(json.RawMessage); ok {
// If it's empty make sure we emit an empty value as the array style would below.
if len(rm) > 0 {
buf.Write(rm)
} else {
buf.WriteString("null")
}
return buf.String()
}
}
buf.WriteByte('[')
for i := 0; i < v.Len(); i++ {
if i > 0 {
buf.WriteByte(',')
}
e := v.Index(i)
buf.WriteString(f.prettyWithFlags(e.Interface(), 0, depth+1))
}
buf.WriteByte(']')
return buf.String()
case reflect.Map:
buf.WriteByte('{')
// This does not sort the map keys, for best perf.
it := v.MapRange()
i := 0
for it.Next() {
if i > 0 {
buf.WriteByte(',')
}
// If a map key supports TextMarshaler, use it.
keystr := ""
if m, ok := it.Key().Interface().(encoding.TextMarshaler); ok {
txt, err := m.MarshalText()
if err != nil {
keystr = fmt.Sprintf("<error-MarshalText: %s>", err.Error())
} else {
keystr = string(txt)
}
keystr = prettyString(keystr)
} else {
// prettyWithFlags will produce already-escaped values
keystr = f.prettyWithFlags(it.Key().Interface(), 0, depth+1)
if t.Key().Kind() != reflect.String {
// JSON only does string keys. Unlike Go's standard JSON, we'll
// convert just about anything to a string.
keystr = prettyString(keystr)
}
}
buf.WriteString(keystr)
buf.WriteByte(':')
buf.WriteString(f.prettyWithFlags(it.Value().Interface(), 0, depth+1))
i++
}
buf.WriteByte('}')
return buf.String()
case reflect.Ptr, reflect.Interface:
if v.IsNil() {
return "null"
}
return f.prettyWithFlags(v.Elem().Interface(), 0, depth)
}
return fmt.Sprintf(`"<unhandled-%s>"`, t.Kind().String())
}
func prettyString(s string) string {
// Avoid escaping (which does allocations) if we can.
if needsEscape(s) {
return strconv.Quote(s)
}
b := bytes.NewBuffer(make([]byte, 0, 1024))
b.WriteByte('"')
b.WriteString(s)
b.WriteByte('"')
return b.String()
}
// needsEscape determines whether the input string needs to be escaped or not,
// without doing any allocations.
func needsEscape(s string) bool {
for _, r := range s {
if !strconv.IsPrint(r) || r == '\\' || r == '"' {
return true
}
}
return false
}
func isEmpty(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Complex64, reflect.Complex128:
return v.Complex() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
func invokeMarshaler(m logr.Marshaler) (ret any) {
defer func() {
if r := recover(); r != nil {
ret = fmt.Sprintf("<panic: %s>", r)
}
}()
return m.MarshalLog()
}
func invokeStringer(s fmt.Stringer) (ret string) {
defer func() {
if r := recover(); r != nil {
ret = fmt.Sprintf("<panic: %s>", r)
}
}()
return s.String()
}
func invokeError(e error) (ret string) {
defer func() {
if r := recover(); r != nil {
ret = fmt.Sprintf("<panic: %s>", r)
}
}()
return e.Error()
}
// Caller represents the original call site for a log line, after considering
// logr.Logger.WithCallDepth and logr.Logger.WithCallStackHelper. The File and
// Line fields will always be provided, while the Func field is optional.
// Users can set the render hook fields in Options to examine logged key-value
// pairs, one of which will be {"caller", Caller} if the Options.LogCaller
// field is enabled for the given MessageClass.
type Caller struct {
// File is the basename of the file for this call site.
File string `json:"file"`
// Line is the line number in the file for this call site.
Line int `json:"line"`
// Func is the function name for this call site, or empty if
// Options.LogCallerFunc is not enabled.
Func string `json:"function,omitempty"`
}
func (f Formatter) caller() Caller {
// +1 for this frame, +1 for Info/Error.
pc, file, line, ok := runtime.Caller(f.depth + 2)
if !ok {
return Caller{"<unknown>", 0, ""}
}
fn := ""
if f.opts.LogCallerFunc {
if fp := runtime.FuncForPC(pc); fp != nil {
fn = fp.Name()
}
}
return Caller{filepath.Base(file), line, fn}
}
const noValue = "<no-value>"
func (f Formatter) nonStringKey(v any) string {
return fmt.Sprintf("<non-string-key: %s>", f.snippet(v))
}
// snippet produces a short snippet string of an arbitrary value.
func (f Formatter) snippet(v any) string {
const snipLen = 16
snip := f.pretty(v)
if len(snip) > snipLen {
snip = snip[:snipLen]
}
return snip
}
// sanitize ensures that a list of key-value pairs has a value for every key
// (adding a value if needed) and that each key is a string (substituting a key
// if needed).
func (f Formatter) sanitize(kvList []any) []any {
if len(kvList)%2 != 0 {
kvList = append(kvList, noValue)
}
for i := 0; i < len(kvList); i += 2 {
_, ok := kvList[i].(string)
if !ok {
kvList[i] = f.nonStringKey(kvList[i])
}
}
return kvList
}
// Init configures this Formatter from runtime info, such as the call depth
// imposed by logr itself.
// Note that this receiver is a pointer, so depth can be saved.
func (f *Formatter) Init(info logr.RuntimeInfo) {
f.depth += info.CallDepth
}
// Enabled checks whether an info message at the given level should be logged.
func (f Formatter) Enabled(level int) bool {
return level <= f.opts.Verbosity
}
// GetDepth returns the current depth of this Formatter. This is useful for
// implementations which do their own caller attribution.
func (f Formatter) GetDepth() int {
return f.depth
}
// FormatInfo renders an Info log message into strings. The prefix will be
// empty when no names were set (via AddNames), or when the output is
// configured for JSON.
func (f Formatter) FormatInfo(level int, msg string, kvList []any) (prefix, argsStr string) {
args := make([]any, 0, 64) // using a constant here impacts perf
prefix = f.prefix
if f.outputFormat == outputJSON {
args = append(args, "logger", prefix)
prefix = ""
}
if f.opts.LogTimestamp {
args = append(args, "ts", time.Now().Format(f.opts.TimestampFormat))
}
if policy := f.opts.LogCaller; policy == All || policy == Info {
args = append(args, "caller", f.caller())
}
args = append(args, "level", level, "msg", msg)
return prefix, f.render(args, kvList)
}
// FormatError renders an Error log message into strings. The prefix will be
// empty when no names were set (via AddNames), or when the output is
// configured for JSON.
func (f Formatter) FormatError(err error, msg string, kvList []any) (prefix, argsStr string) {
args := make([]any, 0, 64) // using a constant here impacts perf
prefix = f.prefix
if f.outputFormat == outputJSON {
args = append(args, "logger", prefix)
prefix = ""
}
if f.opts.LogTimestamp {
args = append(args, "ts", time.Now().Format(f.opts.TimestampFormat))
}
if policy := f.opts.LogCaller; policy == All || policy == Error {
args = append(args, "caller", f.caller())
}
args = append(args, "msg", msg)
var loggableErr any
if err != nil {
loggableErr = err.Error()
}
args = append(args, "error", loggableErr)
return prefix, f.render(args, kvList)
}
// AddName appends the specified name. funcr uses '/' characters to separate
// name elements. Callers should not pass '/' in the provided name string, but
// this library does not actually enforce that.
func (f *Formatter) AddName(name string) {
if len(f.prefix) > 0 {
f.prefix += "/"
}
f.prefix += name
}
// AddValues adds key-value pairs to the set of saved values to be logged with
// each log line.
func (f *Formatter) AddValues(kvList []any) {
// Three slice args forces a copy.
n := len(f.values)
f.values = append(f.values[:n:n], kvList...)
vals := f.values
if hook := f.opts.RenderValuesHook; hook != nil {
vals = hook(f.sanitize(vals))
}
// Pre-render values, so we don't have to do it on each Info/Error call.
buf := bytes.NewBuffer(make([]byte, 0, 1024))
f.flatten(buf, vals, false, true) // escape user-provided keys
f.valuesStr = buf.String()
}
// AddCallDepth increases the number of stack-frames to skip when attributing
// the log line to a file and line.
func (f *Formatter) AddCallDepth(depth int) {
f.depth += depth
}

563
vendor/github.com/go-logr/logr/logr.go generated vendored Normal file
View file

@ -0,0 +1,563 @@
/*
Copyright 2019 The logr Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This design derives from Dave Cheney's blog:
// http://dave.cheney.net/2015/11/05/lets-talk-about-logging
// Package logr defines a general-purpose logging API and abstract interfaces
// to back that API. Packages in the Go ecosystem can depend on this package,
// while callers can implement logging with whatever backend is appropriate.
//
// # Usage
//
// Logging is done using a Logger instance. Logger is a concrete type with
// methods, which defers the actual logging to a LogSink interface. The main
// methods of Logger are Info() and Error(). Arguments to Info() and Error()
// are key/value pairs rather than printf-style formatted strings, emphasizing
// "structured logging".
//
// With Go's standard log package, we might write:
//
// log.Printf("setting target value %s", targetValue)
//
// With logr's structured logging, we'd write:
//
// logger.Info("setting target", "value", targetValue)
//
// Errors are much the same. Instead of:
//
// log.Printf("failed to open the pod bay door for user %s: %v", user, err)
//
// We'd write:
//
// logger.Error(err, "failed to open the pod bay door", "user", user)
//
// Info() and Error() are very similar, but they are separate methods so that
// LogSink implementations can choose to do things like attach additional
// information (such as stack traces) on calls to Error(). Error() messages are
// always logged, regardless of the current verbosity. If there is no error
// instance available, passing nil is valid.
//
// # Verbosity
//
// Often we want to log information only when the application in "verbose
// mode". To write log lines that are more verbose, Logger has a V() method.
// The higher the V-level of a log line, the less critical it is considered.
// Log-lines with V-levels that are not enabled (as per the LogSink) will not
// be written. Level V(0) is the default, and logger.V(0).Info() has the same
// meaning as logger.Info(). Negative V-levels have the same meaning as V(0).
// Error messages do not have a verbosity level and are always logged.
//
// Where we might have written:
//
// if flVerbose >= 2 {
// log.Printf("an unusual thing happened")
// }
//
// We can write:
//
// logger.V(2).Info("an unusual thing happened")
//
// # Logger Names
//
// Logger instances can have name strings so that all messages logged through
// that instance have additional context. For example, you might want to add
// a subsystem name:
//
// logger.WithName("compactor").Info("started", "time", time.Now())
//
// The WithName() method returns a new Logger, which can be passed to
// constructors or other functions for further use. Repeated use of WithName()
// will accumulate name "segments". These name segments will be joined in some
// way by the LogSink implementation. It is strongly recommended that name
// segments contain simple identifiers (letters, digits, and hyphen), and do
// not contain characters that could muddle the log output or confuse the
// joining operation (e.g. whitespace, commas, periods, slashes, brackets,
// quotes, etc).
//
// # Saved Values
//
// Logger instances can store any number of key/value pairs, which will be
// logged alongside all messages logged through that instance. For example,
// you might want to create a Logger instance per managed object:
//
// With the standard log package, we might write:
//
// log.Printf("decided to set field foo to value %q for object %s/%s",
// targetValue, object.Namespace, object.Name)
//
// With logr we'd write:
//
// // Elsewhere: set up the logger to log the object name.
// obj.logger = mainLogger.WithValues(
// "name", obj.name, "namespace", obj.namespace)
//
// // later on...
// obj.logger.Info("setting foo", "value", targetValue)
//
// # Best Practices
//
// Logger has very few hard rules, with the goal that LogSink implementations
// might have a lot of freedom to differentiate. There are, however, some
// things to consider.
//
// The log message consists of a constant message attached to the log line.
// This should generally be a simple description of what's occurring, and should
// never be a format string. Variable information can then be attached using
// named values.
//
// Keys are arbitrary strings, but should generally be constant values. Values
// may be any Go value, but how the value is formatted is determined by the
// LogSink implementation.
//
// Logger instances are meant to be passed around by value. Code that receives
// such a value can call its methods without having to check whether the
// instance is ready for use.
//
// The zero logger (= Logger{}) is identical to Discard() and discards all log
// entries. Code that receives a Logger by value can simply call it, the methods
// will never crash. For cases where passing a logger is optional, a pointer to Logger
// should be used.
//
// # Key Naming Conventions
//
// Keys are not strictly required to conform to any specification or regex, but
// it is recommended that they:
// - be human-readable and meaningful (not auto-generated or simple ordinals)
// - be constant (not dependent on input data)
// - contain only printable characters
// - not contain whitespace or punctuation
// - use lower case for simple keys and lowerCamelCase for more complex ones
//
// These guidelines help ensure that log data is processed properly regardless
// of the log implementation. For example, log implementations will try to
// output JSON data or will store data for later database (e.g. SQL) queries.
//
// While users are generally free to use key names of their choice, it's
// generally best to avoid using the following keys, as they're frequently used
// by implementations:
// - "caller": the calling information (file/line) of a particular log line
// - "error": the underlying error value in the `Error` method
// - "level": the log level
// - "logger": the name of the associated logger
// - "msg": the log message
// - "stacktrace": the stack trace associated with a particular log line or
// error (often from the `Error` message)
// - "ts": the timestamp for a log line
//
// Implementations are encouraged to make use of these keys to represent the
// above concepts, when necessary (for example, in a pure-JSON output form, it
// would be necessary to represent at least message and timestamp as ordinary
// named values).
//
// # Break Glass
//
// Implementations may choose to give callers access to the underlying
// logging implementation. The recommended pattern for this is:
//
// // Underlier exposes access to the underlying logging implementation.
// // Since callers only have a logr.Logger, they have to know which
// // implementation is in use, so this interface is less of an abstraction
// // and more of way to test type conversion.
// type Underlier interface {
// GetUnderlying() <underlying-type>
// }
//
// Logger grants access to the sink to enable type assertions like this:
//
// func DoSomethingWithImpl(log logr.Logger) {
// if underlier, ok := log.GetSink().(impl.Underlier); ok {
// implLogger := underlier.GetUnderlying()
// ...
// }
// }
//
// Custom `With*` functions can be implemented by copying the complete
// Logger struct and replacing the sink in the copy:
//
// // WithFooBar changes the foobar parameter in the log sink and returns a
// // new logger with that modified sink. It does nothing for loggers where
// // the sink doesn't support that parameter.
// func WithFoobar(log logr.Logger, foobar int) logr.Logger {
// if foobarLogSink, ok := log.GetSink().(FoobarSink); ok {
// log = log.WithSink(foobarLogSink.WithFooBar(foobar))
// }
// return log
// }
//
// Don't use New to construct a new Logger with a LogSink retrieved from an
// existing Logger. Source code attribution might not work correctly and
// unexported fields in Logger get lost.
//
// Beware that the same LogSink instance may be shared by different logger
// instances. Calling functions that modify the LogSink will affect all of
// those.
package logr
import (
"context"
)
// New returns a new Logger instance. This is primarily used by libraries
// implementing LogSink, rather than end users. Passing a nil sink will create
// a Logger which discards all log lines.
func New(sink LogSink) Logger {
logger := Logger{}
logger.setSink(sink)
if sink != nil {
sink.Init(runtimeInfo)
}
return logger
}
// setSink stores the sink and updates any related fields. It mutates the
// logger and thus is only safe to use for loggers that are not currently being
// used concurrently.
func (l *Logger) setSink(sink LogSink) {
l.sink = sink
}
// GetSink returns the stored sink.
func (l Logger) GetSink() LogSink {
return l.sink
}
// WithSink returns a copy of the logger with the new sink.
func (l Logger) WithSink(sink LogSink) Logger {
l.setSink(sink)
return l
}
// Logger is an interface to an abstract logging implementation. This is a
// concrete type for performance reasons, but all the real work is passed on to
// a LogSink. Implementations of LogSink should provide their own constructors
// that return Logger, not LogSink.
//
// The underlying sink can be accessed through GetSink and be modified through
// WithSink. This enables the implementation of custom extensions (see "Break
// Glass" in the package documentation). Normally the sink should be used only
// indirectly.
type Logger struct {
sink LogSink
level int
}
// Enabled tests whether this Logger is enabled. For example, commandline
// flags might be used to set the logging verbosity and disable some info logs.
func (l Logger) Enabled() bool {
// Some implementations of LogSink look at the caller in Enabled (e.g.
// different verbosity levels per package or file), but we only pass one
// CallDepth in (via Init). This means that all calls from Logger to the
// LogSink's Enabled, Info, and Error methods must have the same number of
// frames. In other words, Logger methods can't call other Logger methods
// which call these LogSink methods unless we do it the same in all paths.
return l.sink != nil && l.sink.Enabled(l.level)
}
// Info logs a non-error message with the given key/value pairs as context.
//
// The msg argument should be used to add some constant description to the log
// line. The key/value pairs can then be used to add additional variable
// information. The key/value pairs must alternate string keys and arbitrary
// values.
func (l Logger) Info(msg string, keysAndValues ...any) {
if l.sink == nil {
return
}
if l.sink.Enabled(l.level) { // see comment in Enabled
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
withHelper.GetCallStackHelper()()
}
l.sink.Info(l.level, msg, keysAndValues...)
}
}
// Error logs an error, with the given message and key/value pairs as context.
// It functions similarly to Info, but may have unique behavior, and should be
// preferred for logging errors (see the package documentations for more
// information). The log message will always be emitted, regardless of
// verbosity level.
//
// The msg argument should be used to add context to any underlying error,
// while the err argument should be used to attach the actual error that
// triggered this log line, if present. The err parameter is optional
// and nil may be passed instead of an error instance.
func (l Logger) Error(err error, msg string, keysAndValues ...any) {
if l.sink == nil {
return
}
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
withHelper.GetCallStackHelper()()
}
l.sink.Error(err, msg, keysAndValues...)
}
// V returns a new Logger instance for a specific verbosity level, relative to
// this Logger. In other words, V-levels are additive. A higher verbosity
// level means a log message is less important. Negative V-levels are treated
// as 0.
func (l Logger) V(level int) Logger {
if l.sink == nil {
return l
}
if level < 0 {
level = 0
}
l.level += level
return l
}
// GetV returns the verbosity level of the logger. If the logger's LogSink is
// nil as in the Discard logger, this will always return 0.
func (l Logger) GetV() int {
// 0 if l.sink nil because of the if check in V above.
return l.level
}
// WithValues returns a new Logger instance with additional key/value pairs.
// See Info for documentation on how key/value pairs work.
func (l Logger) WithValues(keysAndValues ...any) Logger {
if l.sink == nil {
return l
}
l.setSink(l.sink.WithValues(keysAndValues...))
return l
}
// WithName returns a new Logger instance with the specified name element added
// to the Logger's name. Successive calls with WithName append additional
// suffixes to the Logger's name. It's strongly recommended that name segments
// contain only letters, digits, and hyphens (see the package documentation for
// more information).
func (l Logger) WithName(name string) Logger {
if l.sink == nil {
return l
}
l.setSink(l.sink.WithName(name))
return l
}
// WithCallDepth returns a Logger instance that offsets the call stack by the
// specified number of frames when logging call site information, if possible.
// This is useful for users who have helper functions between the "real" call
// site and the actual calls to Logger methods. If depth is 0 the attribution
// should be to the direct caller of this function. If depth is 1 the
// attribution should skip 1 call frame, and so on. Successive calls to this
// are additive.
//
// If the underlying log implementation supports a WithCallDepth(int) method,
// it will be called and the result returned. If the implementation does not
// support CallDepthLogSink, the original Logger will be returned.
//
// To skip one level, WithCallStackHelper() should be used instead of
// WithCallDepth(1) because it works with implementions that support the
// CallDepthLogSink and/or CallStackHelperLogSink interfaces.
func (l Logger) WithCallDepth(depth int) Logger {
if l.sink == nil {
return l
}
if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
l.setSink(withCallDepth.WithCallDepth(depth))
}
return l
}
// WithCallStackHelper returns a new Logger instance that skips the direct
// caller when logging call site information, if possible. This is useful for
// users who have helper functions between the "real" call site and the actual
// calls to Logger methods and want to support loggers which depend on marking
// each individual helper function, like loggers based on testing.T.
//
// In addition to using that new logger instance, callers also must call the
// returned function.
//
// If the underlying log implementation supports a WithCallDepth(int) method,
// WithCallDepth(1) will be called to produce a new logger. If it supports a
// WithCallStackHelper() method, that will be also called. If the
// implementation does not support either of these, the original Logger will be
// returned.
func (l Logger) WithCallStackHelper() (func(), Logger) {
if l.sink == nil {
return func() {}, l
}
var helper func()
if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
l.setSink(withCallDepth.WithCallDepth(1))
}
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
helper = withHelper.GetCallStackHelper()
} else {
helper = func() {}
}
return helper, l
}
// IsZero returns true if this logger is an uninitialized zero value
func (l Logger) IsZero() bool {
return l.sink == nil
}
// contextKey is how we find Loggers in a context.Context.
type contextKey struct{}
// FromContext returns a Logger from ctx or an error if no Logger is found.
func FromContext(ctx context.Context) (Logger, error) {
if v, ok := ctx.Value(contextKey{}).(Logger); ok {
return v, nil
}
return Logger{}, notFoundError{}
}
// notFoundError exists to carry an IsNotFound method.
type notFoundError struct{}
func (notFoundError) Error() string {
return "no logr.Logger was present"
}
func (notFoundError) IsNotFound() bool {
return true
}
// FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this
// returns a Logger that discards all log messages.
func FromContextOrDiscard(ctx context.Context) Logger {
if v, ok := ctx.Value(contextKey{}).(Logger); ok {
return v
}
return Discard()
}
// NewContext returns a new Context, derived from ctx, which carries the
// provided Logger.
func NewContext(ctx context.Context, logger Logger) context.Context {
return context.WithValue(ctx, contextKey{}, logger)
}
// RuntimeInfo holds information that the logr "core" library knows which
// LogSinks might want to know.
type RuntimeInfo struct {
// CallDepth is the number of call frames the logr library adds between the
// end-user and the LogSink. LogSink implementations which choose to print
// the original logging site (e.g. file & line) should climb this many
// additional frames to find it.
CallDepth int
}
// runtimeInfo is a static global. It must not be changed at run time.
var runtimeInfo = RuntimeInfo{
CallDepth: 1,
}
// LogSink represents a logging implementation. End-users will generally not
// interact with this type.
type LogSink interface {
// Init receives optional information about the logr library for LogSink
// implementations that need it.
Init(info RuntimeInfo)
// Enabled tests whether this LogSink is enabled at the specified V-level.
// For example, commandline flags might be used to set the logging
// verbosity and disable some info logs.
Enabled(level int) bool
// Info logs a non-error message with the given key/value pairs as context.
// The level argument is provided for optional logging. This method will
// only be called when Enabled(level) is true. See Logger.Info for more
// details.
Info(level int, msg string, keysAndValues ...any)
// Error logs an error, with the given message and key/value pairs as
// context. See Logger.Error for more details.
Error(err error, msg string, keysAndValues ...any)
// WithValues returns a new LogSink with additional key/value pairs. See
// Logger.WithValues for more details.
WithValues(keysAndValues ...any) LogSink
// WithName returns a new LogSink with the specified name appended. See
// Logger.WithName for more details.
WithName(name string) LogSink
}
// CallDepthLogSink represents a LogSink that knows how to climb the call stack
// to identify the original call site and can offset the depth by a specified
// number of frames. This is useful for users who have helper functions
// between the "real" call site and the actual calls to Logger methods.
// Implementations that log information about the call site (such as file,
// function, or line) would otherwise log information about the intermediate
// helper functions.
//
// This is an optional interface and implementations are not required to
// support it.
type CallDepthLogSink interface {
// WithCallDepth returns a LogSink that will offset the call
// stack by the specified number of frames when logging call
// site information.
//
// If depth is 0, the LogSink should skip exactly the number
// of call frames defined in RuntimeInfo.CallDepth when Info
// or Error are called, i.e. the attribution should be to the
// direct caller of Logger.Info or Logger.Error.
//
// If depth is 1 the attribution should skip 1 call frame, and so on.
// Successive calls to this are additive.
WithCallDepth(depth int) LogSink
}
// CallStackHelperLogSink represents a LogSink that knows how to climb
// the call stack to identify the original call site and can skip
// intermediate helper functions if they mark themselves as
// helper. Go's testing package uses that approach.
//
// This is useful for users who have helper functions between the
// "real" call site and the actual calls to Logger methods.
// Implementations that log information about the call site (such as
// file, function, or line) would otherwise log information about the
// intermediate helper functions.
//
// This is an optional interface and implementations are not required
// to support it. Implementations that choose to support this must not
// simply implement it as WithCallDepth(1), because
// Logger.WithCallStackHelper will call both methods if they are
// present. This should only be implemented for LogSinks that actually
// need it, as with testing.T.
type CallStackHelperLogSink interface {
// GetCallStackHelper returns a function that must be called
// to mark the direct caller as helper function when logging
// call site information.
GetCallStackHelper() func()
}
// Marshaler is an optional interface that logged values may choose to
// implement. Loggers with structured output, such as JSON, should
// log the object return by the MarshalLog method instead of the
// original value.
type Marshaler interface {
// MarshalLog can be used to:
// - ensure that structs are not logged as strings when the original
// value has a String method: return a different type without a
// String method
// - select which fields of a complex type should get logged:
// return a simpler struct with fewer fields
// - log unexported fields: return a different struct
// with exported fields
//
// It may return any value of any type.
MarshalLog() any
}

201
vendor/github.com/go-logr/stdr/LICENSE generated vendored Normal file
View file

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

6
vendor/github.com/go-logr/stdr/README.md generated vendored Normal file
View file

@ -0,0 +1,6 @@
# Minimal Go logging using logr and Go's standard library
[![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/stdr.svg)](https://pkg.go.dev/github.com/go-logr/stdr)
This package implements the [logr interface](https://github.com/go-logr/logr)
in terms of Go's standard log package(https://pkg.go.dev/log).

170
vendor/github.com/go-logr/stdr/stdr.go generated vendored Normal file
View file

@ -0,0 +1,170 @@
/*
Copyright 2019 The logr Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package stdr implements github.com/go-logr/logr.Logger in terms of
// Go's standard log package.
package stdr
import (
"log"
"os"
"github.com/go-logr/logr"
"github.com/go-logr/logr/funcr"
)
// The global verbosity level. See SetVerbosity().
var globalVerbosity int
// SetVerbosity sets the global level against which all info logs will be
// compared. If this is greater than or equal to the "V" of the logger, the
// message will be logged. A higher value here means more logs will be written.
// The previous verbosity value is returned. This is not concurrent-safe -
// callers must be sure to call it from only one goroutine.
func SetVerbosity(v int) int {
old := globalVerbosity
globalVerbosity = v
return old
}
// New returns a logr.Logger which is implemented by Go's standard log package,
// or something like it. If std is nil, this will use a default logger
// instead.
//
// Example: stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile)))
func New(std StdLogger) logr.Logger {
return NewWithOptions(std, Options{})
}
// NewWithOptions returns a logr.Logger which is implemented by Go's standard
// log package, or something like it. See New for details.
func NewWithOptions(std StdLogger, opts Options) logr.Logger {
if std == nil {
// Go's log.Default() is only available in 1.16 and higher.
std = log.New(os.Stderr, "", log.LstdFlags)
}
if opts.Depth < 0 {
opts.Depth = 0
}
fopts := funcr.Options{
LogCaller: funcr.MessageClass(opts.LogCaller),
}
sl := &logger{
Formatter: funcr.NewFormatter(fopts),
std: std,
}
// For skipping our own logger.Info/Error.
sl.Formatter.AddCallDepth(1 + opts.Depth)
return logr.New(sl)
}
// Options carries parameters which influence the way logs are generated.
type Options struct {
// Depth biases the assumed number of call frames to the "true" caller.
// This is useful when the calling code calls a function which then calls
// stdr (e.g. a logging shim to another API). Values less than zero will
// be treated as zero.
Depth int
// LogCaller tells stdr to add a "caller" key to some or all log lines.
// Go's log package has options to log this natively, too.
LogCaller MessageClass
// TODO: add an option to log the date/time
}
// MessageClass indicates which category or categories of messages to consider.
type MessageClass int
const (
// None ignores all message classes.
None MessageClass = iota
// All considers all message classes.
All
// Info only considers info messages.
Info
// Error only considers error messages.
Error
)
// StdLogger is the subset of the Go stdlib log.Logger API that is needed for
// this adapter.
type StdLogger interface {
// Output is the same as log.Output and log.Logger.Output.
Output(calldepth int, logline string) error
}
type logger struct {
funcr.Formatter
std StdLogger
}
var _ logr.LogSink = &logger{}
var _ logr.CallDepthLogSink = &logger{}
func (l logger) Enabled(level int) bool {
return globalVerbosity >= level
}
func (l logger) Info(level int, msg string, kvList ...interface{}) {
prefix, args := l.FormatInfo(level, msg, kvList)
if prefix != "" {
args = prefix + ": " + args
}
_ = l.std.Output(l.Formatter.GetDepth()+1, args)
}
func (l logger) Error(err error, msg string, kvList ...interface{}) {
prefix, args := l.FormatError(err, msg, kvList)
if prefix != "" {
args = prefix + ": " + args
}
_ = l.std.Output(l.Formatter.GetDepth()+1, args)
}
func (l logger) WithName(name string) logr.LogSink {
l.Formatter.AddName(name)
return &l
}
func (l logger) WithValues(kvList ...interface{}) logr.LogSink {
l.Formatter.AddValues(kvList)
return &l
}
func (l logger) WithCallDepth(depth int) logr.LogSink {
l.Formatter.AddCallDepth(depth)
return &l
}
// Underlier exposes access to the underlying logging implementation. Since
// callers only have a logr.Logger, they have to know which implementation is
// in use, so this interface is less of an abstraction and more of way to test
// type conversion.
type Underlier interface {
GetUnderlying() StdLogger
}
// GetUnderlying returns the StdLogger underneath this logger. Since StdLogger
// is itself an interface, the result may or may not be a Go log.Logger.
func (l logger) GetUnderlying() StdLogger {
return l.std
}

View file

@ -1,5 +1,12 @@
# Changelog
## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12)
### Features
* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29))
## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26)

View file

@ -108,12 +108,23 @@ func setClockSequence(seq int) {
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. The time is only defined for version 1 and 2 UUIDs.
// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs.
func (uuid UUID) Time() Time {
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
return Time(time)
var t Time
switch uuid.Version() {
case 6:
time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110
t = Time(time)
case 7:
time := binary.BigEndian.Uint64(uuid[:8])
t = Time((time>>16)*10000 + g1582ns100)
default: // forward compatible
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
t = Time(time)
}
return t
}
// ClockSequence returns the clock sequence encoded in uuid.

View file

@ -186,6 +186,59 @@ func Must(uuid UUID, err error) UUID {
return uuid
}
// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
// It returns an error if the format is invalid, otherwise nil.
func Validate(s string) error {
switch len(s) {
// Standard UUID format
case 36:
// UUID with "urn:uuid:" prefix
case 36 + 9:
if !strings.EqualFold(s[:9], "urn:uuid:") {
return fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
// UUID enclosed in braces
case 36 + 2:
if s[0] != '{' || s[len(s)-1] != '}' {
return fmt.Errorf("invalid bracketed UUID format")
}
s = s[1 : len(s)-1]
// UUID without hyphens
case 32:
for i := 0; i < len(s); i += 2 {
_, ok := xtob(s[i], s[i+1])
if !ok {
return errors.New("invalid UUID format")
}
}
default:
return invalidLengthError{len(s)}
}
// Check for standard UUID format
if len(s) == 36 {
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return errors.New("invalid UUID format")
}
for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
if _, ok := xtob(s[x], s[x+1]); !ok {
return errors.New("invalid UUID format")
}
}
}
return nil
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {

56
vendor/github.com/google/uuid/version6.go generated vendored Normal file
View file

@ -0,0 +1,56 @@
// Copyright 2023 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "encoding/binary"
// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality.
// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs.
// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.
//
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6
//
// NewV6 returns a Version 6 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewV6 returns Nil and an error.
func NewV6() (UUID, error) {
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
binary.BigEndian.PutUint64(uuid[0:], uint64(now))
binary.BigEndian.PutUint16(uuid[8:], seq)
uuid[6] = 0x60 | (uuid[6] & 0x0F)
uuid[8] = 0x80 | (uuid[8] & 0x3F)
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
copy(uuid[10:], nodeID[:])
nodeMu.Unlock()
return uuid, nil
}

75
vendor/github.com/google/uuid/version7.go generated vendored Normal file
View file

@ -0,0 +1,75 @@
// Copyright 2023 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// UUID version 7 features a time-ordered value field derived from the widely
// implemented and well known Unix Epoch timestamp source,
// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded.
// As well as improved entropy characteristics over versions 1 or 6.
//
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7
//
// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.
//
// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch).
// Uses the randomness pool if it was enabled with EnableRandPool.
// On error, NewV7 returns Nil and an error
func NewV7() (UUID, error) {
uuid, err := NewRandom()
if err != nil {
return uuid, err
}
makeV7(uuid[:])
return uuid, nil
}
// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch).
// it use NewRandomFromReader fill random bits.
// On error, NewV7FromReader returns Nil and an error.
func NewV7FromReader(r io.Reader) (UUID, error) {
uuid, err := NewRandomFromReader(r)
if err != nil {
return uuid, err
}
makeV7(uuid[:])
return uuid, nil
}
// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6])
// uuid[8] already has the right version number (Variant is 10)
// see function NewV7 and NewV7FromReader
func makeV7(uuid []byte) {
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
_ = uuid[15] // bounds check
t := timeNow().UnixMilli()
uuid[0] = byte(t >> 40)
uuid[1] = byte(t >> 32)
uuid[2] = byte(t >> 24)
uuid[3] = byte(t >> 16)
uuid[4] = byte(t >> 8)
uuid[5] = byte(t)
uuid[6] = 0x70 | (uuid[6] & 0x0F)
// uuid[8] has already has right version
}

View file

@ -46,3 +46,16 @@ var CustomFilesPolicies = NewPathPolicies(map[string]PathPolicy{
"/etc/passwd": {Deny: true},
"/etc/group": {Deny: true},
})
// MountpointPolicies for ostree
var OstreeMountpointPolicies = NewPathPolicies(map[string]PathPolicy{
"/": {},
"/ostree": {Deny: true},
"/home": {Deny: true},
"/var/home": {Deny: true},
"/var/opt": {Deny: true},
"/var/srv": {Deny: true},
"/var/roothome": {Deny: true},
"/var/usrlocal": {Deny: true},
"/var/mnt": {Deny: true},
})

View file

@ -122,6 +122,7 @@ var (
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: iotServices,
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
},
rpmOstree: true,
image: iotCommitImage,
@ -143,6 +144,7 @@ var (
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: iotServices,
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
},
rpmOstree: true,
bootISO: false,

View file

@ -47,6 +47,8 @@ func osCustomizations(
osc.KernelOptionsAppend = kernelOptions
}
osc.FIPS = c.GetFIPS()
osc.ExtraBasePackages = osPackageSet.Include
osc.ExcludeBasePackages = osPackageSet.Exclude
osc.ExtraBaseRepos = osPackageSet.Repositories
@ -467,6 +469,7 @@ func iotInstallerImage(workload workload.Workload,
img := image.NewAnacondaOSTreeInstaller(commit)
customizations := bp.Customizations
img.FIPS = customizations.GetFIPS()
img.Platform = t.platform
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
@ -508,6 +511,7 @@ func iotImage(workload workload.Workload,
distro := t.Arch().Distro()
customizations := bp.Customizations
img.FIPS = customizations.GetFIPS()
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
@ -581,6 +585,7 @@ func iotSimplifiedInstallerImage(workload workload.Workload,
rawImg := image.NewOSTreeDiskImageFromCommit(commit)
customizations := bp.Customizations
rawImg.FIPS = customizations.GetFIPS()
rawImg.Users = users.UsersFromBP(customizations.GetUsers())
rawImg.Groups = users.GroupsFromBP(customizations.GetGroups())

View file

@ -270,7 +270,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
if t.name == "iot-raw-image" || t.name == "iot-qcow2-image" {
allowed := []string{"User", "Group", "Directories", "Files", "Services"}
allowed := []string{"User", "Group", "Directories", "Files", "Services", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return nil, fmt.Errorf("unsupported blueprint customizations found for image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}
@ -281,7 +281,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
// TODO: Support kernel name selection for image-installer
if t.bootISO {
if t.name == "iot-simplified-installer" {
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group"}
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return nil, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}
@ -319,7 +319,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
}
} else if t.name == "iot-installer" || t.name == "image-installer" {
allowed := []string{"User", "Group"}
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return nil, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}

View file

@ -7,6 +7,7 @@ import (
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/fsnode"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
@ -21,6 +22,7 @@ func edgeCommitImgType(rd distribution) imageType {
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices(rd),
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
},
rpmOstree: true,
image: edgeCommitImage,
@ -47,6 +49,7 @@ func edgeOCIImgType(rd distribution) imageType {
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices(rd),
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
},
rpmOstree: true,
bootISO: false,

View file

@ -49,6 +49,8 @@ func osCustomizations(
}
}
osc.FIPS = c.GetFIPS()
osc.ExtraBasePackages = osPackageSet.Include
osc.ExcludeBasePackages = osPackageSet.Exclude
osc.ExtraBaseRepos = osPackageSet.Repositories
@ -436,6 +438,7 @@ func edgeInstallerImage(workload workload.Workload,
img.OSName = "rhel"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)
img.FIPS = customizations.GetFIPS()
img.Filename = t.Filename()
@ -459,6 +462,7 @@ func edgeRawImage(workload workload.Workload,
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
img.FIPS = customizations.GetFIPS()
img.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
// TODO: move to image config
@ -505,6 +509,7 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
rawImg.Users = users.UsersFromBP(customizations.GetUsers())
rawImg.Groups = users.GroupsFromBP(customizations.GetGroups())
rawImg.FIPS = customizations.GetFIPS()
rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
rawImg.Keyboard = "us"

View file

@ -303,7 +303,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
if t.name == "edge-simplified-installer" {
allowed := []string{"InstallationDevice", "FDO", "User", "Group"}
allowed := []string{"InstallationDevice", "FDO", "User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}
@ -330,7 +330,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
}
} else if t.name == "edge-installer" {
allowed := []string{"User", "Group"}
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}
@ -343,7 +343,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, fmt.Errorf("%q images require specifying a URL from which to retrieve the OSTree commit", t.name)
}
allowed := []string{"User", "Group"}
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}

View file

@ -402,6 +402,11 @@ func rhelEc2SapPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rh-amazon-rhui-client-sap-bundle-e4s",
"libcanberra-gtk2",
},
Exclude: []string{
// COMPOSER-1829
"firewalld",
},
}.Append(rhelEc2CommonPackageSet(t)).Append(SapPackageSet(t))
}

View file

@ -70,6 +70,27 @@ var (
}
)
func azureSapRhuiImgType(rd distribution) imageType {
return imageType{
name: "azure-sap-rhui",
filename: "disk.vhd.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: azureSapPackageSet,
},
defaultImageConfig: defaultAzureRhuiImageConfig.InheritFrom(sapAzureImageConfig(rd)),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 64 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc", "xz"},
exports: []string{"xz"},
basePartitionTables: azureRhuiBasePartitionTables,
}
}
// PACKAGE SETS
// Common Azure image package set
@ -598,3 +619,18 @@ var defaultAzureRhuiImageConfig = &distro.ImageConfig{
},
},
}
// Azure SAP image package set
// Includes the common azure package set, the common SAP packages, and
// the azure rhui sap package.
func azureSapPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rhui-azure-rhel9-sap-ha",
},
}.Append(azureCommonPackageSet(t)).Append(SapPackageSet(t))
}
func sapAzureImageConfig(rd distribution) *distro.ImageConfig {
return sapImageConfig(rd.osVersion).InheritFrom(defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig))
}

View file

@ -460,6 +460,8 @@ func newDistro(name string, minor int) *distribution {
x86_64.addImageTypes(azureX64Platform, azureRhuiImgType, azureByosImgType)
aarch64.addImageTypes(azureAarch64Platform, azureRhuiImgType, azureByosImgType)
x86_64.addImageTypes(azureX64Platform, azureSapRhuiImgType(rd))
// keep the RHEL EC2 x86_64 images before 9.3 BIOS-only for backward compatibility
if common.VersionLessThan(rd.osVersion, "9.3") {
ec2X86Platform = &platform.X86{

View file

@ -46,6 +46,8 @@ func osCustomizations(
osc.KernelOptionsAppend = kernelOptions
}
osc.FIPS = c.GetFIPS()
osc.ExtraBasePackages = osPackageSet.Include
osc.ExcludeBasePackages = osPackageSet.Exclude
osc.ExtraBaseRepos = osPackageSet.Repositories

View file

@ -167,12 +167,7 @@ func (t *imageType) getPartitionTable(
partitioningMode := options.PartitioningMode
if t.rpmOstree {
// Edge supports only LVM, force it.
// Raw is not supported, return an error if it is requested
// TODO Need a central location for logic like this
if partitioningMode == disk.RawPartitioningMode {
return nil, fmt.Errorf("partitioning mode raw not supported for %s on %s", t.Name(), t.arch.Name())
}
partitioningMode = disk.LVMPartitioningMode
}
@ -308,7 +303,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
if t.name == "edge-simplified-installer" {
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS"}
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}
@ -358,8 +353,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if options.OSTree == nil || options.OSTree.URL == "" {
return warnings, fmt.Errorf("%q images require specifying a URL from which to retrieve the OSTree commit", t.name)
}
allowed := []string{"Ignition", "Kernel", "User", "Group", "FIPS"}
allowed := []string{"Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
}
@ -386,9 +380,14 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
mountpoints := customizations.GetFilesystems()
if mountpoints != nil && t.rpmOstree {
return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types")
if mountpoints != nil && t.rpmOstree && (t.name == "edge-container" || t.name == "edge-commit") {
return warnings, fmt.Errorf("Custom mountpoints are not supported for edge-container and edge-commit")
} else if mountpoints != nil && t.rpmOstree && !(t.name == "edge-container" || t.name == "edge-commit") {
//customization allowed for edge-raw-image,edge-ami,edge-vsphere,edge-simplified-installer
err := blueprint.CheckMountpointsPolicy(mountpoints, pathpolicy.OstreeMountpointPolicies)
if err != nil {
return warnings, err
}
}
err := blueprint.CheckMountpointsPolicy(mountpoints, pathpolicy.MountpointPolicies)

View file

@ -142,7 +142,6 @@ func SapPackageSet(t *imageType) rpmmd.PackageSet {
"krb5-workstation",
"libaio",
"libatomic",
"libcanberra-gtk2",
"libicu",
"libtool-ltdl",
"lm_sensors",
@ -156,8 +155,6 @@ func SapPackageSet(t *imageType) rpmmd.PackageSet {
"libnsl",
},
Exclude: []string{
// COMPOSER-1829
"firewalld",
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",

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