forked from Azure/azure-sdk-for-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
278 lines (243 loc) · 12.7 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
//go:build go1.18
// +build go1.18
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
package service
import (
"context"
"errors"
"net/http"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/base"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
)
// ClientOptions contains the optional parameters when creating a Client.
type ClientOptions struct {
azcore.ClientOptions
}
// Client represents a URL to the Azure Blob Storage service allowing you to manipulate blob containers.
type Client base.Client[generated.ServiceClient]
// NewClient creates a Client object using the specified URL, Azure AD credential, and options.
// Example of serviceURL: https://<your_storage_account>.blob.core.windows.net
func NewClient(serviceURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
authPolicy := runtime.NewBearerTokenPolicy(cred, []string{shared.TokenScope}, nil)
conOptions := shared.GetClientOptions(options)
conOptions.PerRetryPolicies = append(conOptions.PerRetryPolicies, authPolicy)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
return (*Client)(base.NewServiceClient(serviceURL, pl, nil)), nil
}
// NewClientWithNoCredential creates a Client object using the specified URL and options.
// Example of serviceURL: https://<your_storage_account>.blob.core.windows.net?<SAS token>
func NewClientWithNoCredential(serviceURL string, options *ClientOptions) (*Client, error) {
conOptions := shared.GetClientOptions(options)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
return (*Client)(base.NewServiceClient(serviceURL, pl, nil)), nil
}
// NewClientWithSharedKeyCredential creates a Client object using the specified URL, shared key, and options.
// Example of serviceURL: https://<your_storage_account>.blob.core.windows.net
func NewClientWithSharedKeyCredential(serviceURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) {
authPolicy := exported.NewSharedKeyCredPolicy(cred)
conOptions := shared.GetClientOptions(options)
conOptions.PerRetryPolicies = append(conOptions.PerRetryPolicies, authPolicy)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
return (*Client)(base.NewServiceClient(serviceURL, pl, cred)), nil
}
// NewClientFromConnectionString creates a service client from the given connection string.
// nolint
func NewClientFromConnectionString(connectionString string, options *ClientOptions) (*Client, error) {
parsed, err := shared.ParseConnectionString(connectionString)
if err != nil {
return nil, err
}
if parsed.AccountKey != "" && parsed.AccountName != "" {
credential, err := exported.NewSharedKeyCredential(parsed.AccountName, parsed.AccountKey)
if err != nil {
return nil, err
}
return NewClientWithSharedKeyCredential(parsed.ServiceURL, credential, options)
}
return NewClientWithNoCredential(parsed.ServiceURL, options)
}
// NewClientWithUserDelegationCredential obtains a UserDelegationKey object using the base ServiceURL object.
// OAuth is required for this call, as well as any role that can delegate access to the storage account.
func NewClientWithUserDelegationCredential(serviceURL string, ctx context.Context, info generated.KeyInfo, timeout *int32, requestID *string) (*Client, error) {
url, err := exported.ParseURL(serviceURL)
if err != nil {
return nil, err
}
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, nil)
sc := generated.NewServiceClient(serviceURL, pl)
opts := GetUserDelegationKeyOptions{
RequestID: requestID,
Timeout: timeout,
}
udk, err := sc.GetUserDelegationKey(ctx, info, &opts)
if err != nil {
return nil, err
}
return (*Client)(base.NewServiceClientUDK(url.Host, pl, nil, &udk.UserDelegationKey)), nil
}
func (s Client) GetUserDelegationKey(ctx context.Context, keyInfo generated.KeyInfo, options *GetUserDelegationKeyOptions) GetUserDelegationKeyResponse {
resp, _ := s.generated().GetUserDelegationKey(ctx, keyInfo, options)
return resp
}
func (s *Client) generated() *generated.ServiceClient {
return base.InnerClient((*base.Client[generated.ServiceClient])(s))
}
func (s *Client) sharedKey() *SharedKeyCredential {
return base.SharedKey((*base.Client[generated.ServiceClient])(s))
}
// URL returns the URL endpoint used by the Client object.
func (s *Client) URL() string {
return s.generated().Endpoint()
}
// NewContainerClient creates a new ContainerClient object by concatenating containerName to the end of
// Client's URL. The new ContainerClient uses the same request policy pipeline as the Client.
// To change the pipeline, create the ContainerClient and then call its WithPipeline method passing in the
// desired pipeline object. Or, call this package's NewContainerClient instead of calling this object's
// NewContainerClient method.
func (s *Client) NewContainerClient(containerName string) *container.Client {
containerURL := runtime.JoinPaths(s.generated().Endpoint(), containerName)
return (*container.Client)(base.NewContainerClient(containerURL, s.generated().Pipeline(), s.sharedKey()))
}
// CreateContainer is a lifecycle method to creates a new container under the specified account.
// If the container with the same name already exists, a ResourceExistsError will be raised.
// This method returns a client with which to interact with the newly created container.
func (s *Client) CreateContainer(ctx context.Context, containerName string, options *CreateContainerOptions) (CreateContainerResponse, error) {
containerClient := s.NewContainerClient(containerName)
containerCreateResp, err := containerClient.Create(ctx, options)
return containerCreateResp, err
}
// DeleteContainer is a lifecycle method that marks the specified container for deletion.
// The container and any blobs contained within it are later deleted during garbage collection.
// If the container is not found, a ResourceNotFoundError will be raised.
func (s *Client) DeleteContainer(ctx context.Context, containerName string, options *DeleteContainerOptions) (DeleteContainerResponse, error) {
containerClient := s.NewContainerClient(containerName)
containerDeleteResp, err := containerClient.Delete(ctx, options)
return containerDeleteResp, err
}
// GetAccountInfo provides account level information
func (s *Client) GetAccountInfo(ctx context.Context, o *GetAccountInfoOptions) (GetAccountInfoResponse, error) {
getAccountInfoOptions := o.format()
resp, err := s.generated().GetAccountInfo(ctx, getAccountInfoOptions)
return resp, err
}
// NewListContainersPager operation returns a pager of the containers under the specified account.
// Use an empty Marker to start enumeration from the beginning. Container names are returned in lexicographic order.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/list-containers2.
func (s *Client) NewListContainersPager(o *ListContainersOptions) *runtime.Pager[ListContainersResponse] {
listOptions := generated.ServiceClientListContainersSegmentOptions{}
if o != nil {
if o.Include.Deleted {
listOptions.Include = append(listOptions.Include, generated.ListContainersIncludeTypeDeleted)
}
if o.Include.Metadata {
listOptions.Include = append(listOptions.Include, generated.ListContainersIncludeTypeMetadata)
}
listOptions.Marker = o.Marker
listOptions.Maxresults = o.MaxResults
listOptions.Prefix = o.Prefix
}
return runtime.NewPager(runtime.PagingHandler[ListContainersResponse]{
More: func(page ListContainersResponse) bool {
return page.NextMarker != nil && len(*page.NextMarker) > 0
},
Fetcher: func(ctx context.Context, page *ListContainersResponse) (ListContainersResponse, error) {
var req *policy.Request
var err error
if page == nil {
req, err = s.generated().ListContainersSegmentCreateRequest(ctx, &listOptions)
} else {
listOptions.Marker = page.Marker
req, err = s.generated().ListContainersSegmentCreateRequest(ctx, &listOptions)
}
if err != nil {
return ListContainersResponse{}, err
}
resp, err := s.generated().Pipeline().Do(req)
if err != nil {
return ListContainersResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return ListContainersResponse{}, runtime.NewResponseError(resp)
}
return s.generated().ListContainersSegmentHandleResponse(resp)
},
})
}
// GetProperties - gets the properties of a storage account's Blob service, including properties for Storage Analytics
// and CORS (Cross-Origin Resource Sharing) rules.
func (s *Client) GetProperties(ctx context.Context, o *GetPropertiesOptions) (GetPropertiesResponse, error) {
getPropertiesOptions := o.format()
resp, err := s.generated().GetProperties(ctx, getPropertiesOptions)
return resp, err
}
// SetProperties Sets the properties of a storage account's Blob service, including Azure Storage Analytics.
// If an element (e.g. analytics_logging) is left as None, the existing settings on the service for that functionality are preserved.
func (s *Client) SetProperties(ctx context.Context, o *SetPropertiesOptions) (SetPropertiesResponse, error) {
properties, setPropertiesOptions := o.format()
resp, err := s.generated().SetProperties(ctx, properties, setPropertiesOptions)
return resp, err
}
// GetStatistics Retrieves statistics related to replication for the Blob service.
// It is only available when read-access geo-redundant replication is enabled for the storage account.
// With geo-redundant replication, Azure Storage maintains your data durable
// in two locations. In both locations, Azure Storage constantly maintains
// multiple healthy replicas of your data. The location where you read,
// create, update, or delete data is the primary storage account location.
// The primary location exists in the region you choose at the time you
// create an account via the Azure Management Azure classic portal, for
// example, North Central US. The location to which your data is replicated
// is the secondary location. The secondary location is automatically
// determined based on the location of the primary; it is in a second data
// center that resides in the same region as the primary location. Read-only
// access is available from the secondary location, if read-access geo-redundant
// replication is enabled for your storage account.
func (s *Client) GetStatistics(ctx context.Context, o *GetStatisticsOptions) (GetStatisticsResponse, error) {
getStatisticsOptions := o.format()
resp, err := s.generated().GetStatistics(ctx, getStatisticsOptions)
return resp, err
}
// GetSASURL is a convenience method for generating a SAS token for the currently pointed at account.
// It can only be used if the credential supplied during creation was a SharedKeyCredential.
// This validity can be checked with CanGetAccountSASToken().
func (s *Client) GetSASURL(resources SASResourceTypes, permissions SASPermissions, services SASServices, start time.Time, expiry time.Time) (string, error) {
if s.sharedKey() == nil {
return "", errors.New("SAS can only be signed with a SharedKeyCredential")
}
qps, err := SASSignatureValues{
Version: exported.SASVersion,
Protocol: exported.SASProtocolHTTPS,
Permissions: permissions.String(),
Services: services.String(),
ResourceTypes: resources.String(),
StartTime: start.UTC(),
ExpiryTime: expiry.UTC(),
}.Sign(s.sharedKey())
if err != nil {
return "", err
}
endpoint := s.URL()
if !strings.HasSuffix(endpoint, "/") {
endpoint += "/"
}
endpoint += "?" + qps.Encode()
return endpoint, nil
}
// FilterBlobs operation finds all blobs in the storage account whose tags match a given search expression.
// Filter blobs searches across all containers within a storage account but can be scoped within the expression to a single container.
// https://docs.microsoft.com/en-us/rest/api/storageservices/find-blobs-by-tags
// eg. "dog='germanshepherd' and penguin='emperorpenguin'"
// To specify a container, eg. "@container=’containerName’ and Name = ‘C’"
func (s *Client) FilterBlobs(ctx context.Context, o *FilterBlobsOptions) (FilterBlobsResponse, error) {
serviceFilterBlobsOptions := o.format()
resp, err := s.generated().FilterBlobs(ctx, serviceFilterBlobsOptions)
return resp, err
}