From 43554c80a61f088f7ee788af55e7da13993c9da9 Mon Sep 17 00:00:00 2001 From: Pengfei Ni Date: Wed, 15 Jan 2020 09:23:46 +0000 Subject: [PATCH 1/5] Add disk clients based on armclient --- .../azure/clients/diskclient/BUILD | 57 ++++ .../clients/diskclient/azure_diskclient.go | 248 ++++++++++++++++++ .../diskclient/azure_diskclient_test.go | 129 +++++++++ .../azure/clients/diskclient/doc.go | 20 ++ .../azure/clients/diskclient/interface.go | 45 ++++ .../clients/diskclient/mockdiskclient/BUILD | 31 +++ .../clients/diskclient/mockdiskclient/doc.go | 20 ++ .../diskclient/mockdiskclient/interface.go | 94 +++++++ 8 files changed, 644 insertions(+) create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient_test.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD new file mode 100644 index 00000000000..47a714646cd --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD @@ -0,0 +1,57 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "azure_diskclient.go", + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/diskclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/metrics:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["azure_diskclient_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go new file mode 100644 index 00000000000..9a95ff6f8ae --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go @@ -0,0 +1,248 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 diskclient + +import ( + "context" + "net/http" + "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + + "k8s.io/client-go/util/flowcontrol" + "k8s.io/klog" + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/metrics" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +var _ Interface = &Client{} + +// Client implements Disk client Interface. +type Client struct { + armClient armclient.Interface + subscriptionID string + + // Rate limiting configures. + rateLimiterReader flowcontrol.RateLimiter + rateLimiterWriter flowcontrol.RateLimiter + + // ARM throttling configures. + RetryAfterReader time.Time + RetryAfterWriter time.Time +} + +// New creates a new Disk client with ratelimiting. +func New(config *azclients.ClientConfig) *Client { + baseURI := config.ResourceManagerEndpoint + authorizer := autorest.NewBearerAuthorizer(config.ServicePrincipalToken) + armClient := armclient.New(authorizer, baseURI, "", APIVersion, config.Location, config.Backoff) + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig) + + klog.V(2).Infof("Azure DisksClient (read ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPS, + config.RateLimitConfig.CloudProviderRateLimitBucket) + klog.V(2).Infof("Azure DisksClient (write ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPSWrite, + config.RateLimitConfig.CloudProviderRateLimitBucketWrite) + + client := &Client{ + armClient: armClient, + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + subscriptionID: config.SubscriptionID, + } + + return client +} + +// Get gets a Disk. +func (c *Client) Get(ctx context.Context, resourceGroupName string, diskName string) (compute.Disk, *retry.Error) { + mc := metrics.NewMetricContext("disks", "get", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterReader.TryAccept() { + mc.RateLimitedCount() + return compute.Disk{}, retry.GetRateLimitError(false, "GetDisk") + } + + // Report errors if the client is throttled. + if c.RetryAfterReader.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("GetDisk", "client throttled", c.RetryAfterReader) + return compute.Disk{}, rerr + } + + result, rerr := c.getDisk(ctx, resourceGroupName, diskName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterReader = rerr.RetryAfter + } + + return result, rerr + } + + return result, nil +} + +// getDisk gets a Disk. +func (c *Client) getDisk(ctx context.Context, resourceGroupName string, diskName string) (compute.Disk, *retry.Error) { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Compute/disks", + diskName, + ) + result := compute.Disk{} + + response, rerr := c.armClient.GetResource(ctx, resourceID, "") + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.get.request", resourceID, rerr.Error()) + return result, rerr + } + + err := autorest.Respond( + response, + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result)) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.get.respond", resourceID, err) + return result, retry.GetError(response, err) + } + + result.Response = autorest.Response{Response: response} + return result, nil +} + +// CreateOrUpdate creates or updates a Disk. +func (c *Client) CreateOrUpdate(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.Disk) *retry.Error { + mc := metrics.NewMetricContext("disks", "create_or_update", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterWriter.TryAccept() { + mc.RateLimitedCount() + return retry.GetRateLimitError(true, "DiskCreateOrUpdate") + } + + // Report errors if the client is throttled. + if c.RetryAfterWriter.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("DiskCreateOrUpdate", "client throttled", c.RetryAfterWriter) + return rerr + } + + rerr := c.createOrUpdateDisk(ctx, resourceGroupName, diskName, diskParameter) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterWriter = rerr.RetryAfter + } + + return rerr + } + + return nil +} + +// createOrUpdateDisk creates or updates a Disk. +func (c *Client) createOrUpdateDisk(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.Disk) *retry.Error { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Compute/disks", + diskName, + ) + + response, rerr := c.armClient.PutResource(ctx, resourceID, diskParameter) + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.put.request", resourceID, rerr.Error()) + return rerr + } + + if response != nil && response.StatusCode != http.StatusNoContent { + _, rerr = c.createOrUpdateResponder(response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.put.respond", resourceID, rerr.Error()) + return rerr + } + } + + return nil +} + +func (c *Client) createOrUpdateResponder(resp *http.Response) (*compute.Disk, *retry.Error) { + result := &compute.Disk{} + err := autorest.Respond( + resp, + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), + autorest.ByUnmarshallingJSON(&result)) + result.Response = autorest.Response{Response: resp} + return result, retry.GetError(resp, err) +} + +// Delete deletes a Disk by name. +func (c *Client) Delete(ctx context.Context, resourceGroupName string, diskName string) *retry.Error { + mc := metrics.NewMetricContext("disks", "delete", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterWriter.TryAccept() { + mc.RateLimitedCount() + return retry.GetRateLimitError(true, "DiskDelete") + } + + // Report errors if the client is throttled. + if c.RetryAfterWriter.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("DiskDelete", "client throttled", c.RetryAfterWriter) + return rerr + } + + rerr := c.deleteDisk(ctx, resourceGroupName, diskName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterWriter = rerr.RetryAfter + } + + return rerr + } + + return nil +} + +// deleteDisk deletes a PublicIPAddress by name. +func (c *Client) deleteDisk(ctx context.Context, resourceGroupName string, diskName string) *retry.Error { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Compute/disks", + diskName, + ) + + return c.armClient.DeleteResource(ctx, resourceID, "") +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient_test.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient_test.go new file mode 100644 index 00000000000..afd5bf2e828 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient_test.go @@ -0,0 +1,129 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 diskclient + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient" +) + +func TestGetNotFound(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/disks/disk1" + response := &http.Response{ + StatusCode: http.StatusNotFound, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + diskClient := getTestDiskClient(armClient) + expected := compute.Disk{Response: autorest.Response{}} + result, rerr := diskClient.Get(context.TODO(), "rg", "disk1") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode) +} + +func TestGetInternalError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/disks/disk1" + response := &http.Response{ + StatusCode: http.StatusInternalServerError, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + diskClient := getTestDiskClient(armClient) + expected := compute.Disk{Response: autorest.Response{}} + result, rerr := diskClient.Get(context.TODO(), "rg", "disk1") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode) +} + +func TestCreateOrUpdate(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + disk := getTestDisk("disk1") + armClient := mockarmclient.NewMockInterface(ctrl) + response := &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + } + armClient.EXPECT().PutResource(gomock.Any(), to.String(disk.ID), disk).Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + diskClient := getTestDiskClient(armClient) + rerr := diskClient.CreateOrUpdate(context.TODO(), "rg", "disk1", disk) + assert.Nil(t, rerr) +} + +func TestDelete(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := getTestDisk("disk1") + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().DeleteResource(gomock.Any(), to.String(r.ID), "").Return(nil).Times(1) + + diskClient := getTestDiskClient(armClient) + rerr := diskClient.Delete(context.TODO(), "rg", "disk1") + assert.Nil(t, rerr) +} + +func getTestDisk(name string) compute.Disk { + return compute.Disk{ + ID: to.StringPtr(fmt.Sprintf("/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/disks/%s", name)), + Name: to.StringPtr(name), + Location: to.StringPtr("eastus"), + } +} + +func getTestDiskClient(armClient armclient.Interface) *Client { + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{}) + return &Client{ + armClient: armClient, + subscriptionID: "subscriptionID", + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + } +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/doc.go new file mode 100644 index 00000000000..de825dd7382 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 diskclient implements the client for Disks. +package diskclient // import "k8s.io/legacy-cloud-providers/azure/clients/diskclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go new file mode 100644 index 00000000000..004fe1e09df --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go @@ -0,0 +1,45 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 diskclient + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +const ( + // APIVersion is the API version for compute. + APIVersion = "2019-07-01" +) + +// Interface is the client interface for Disks. +// Don't forget to run the following command to generate the mock client: +// mockgen -source=$GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go -package=mockdiskclient Interface > $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go +type Interface interface { + // Get gets a Disk. + Get(ctx context.Context, resourceGroupName string, diskName string) (result compute.Disk, rerr *retry.Error) + + // CreateOrUpdate creates or updates a Disk. + CreateOrUpdate(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.Disk) *retry.Error + + // Delete deletes a Disk by name. + Delete(ctx context.Context, resourceGroupName string, diskName string) *retry.Error +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/BUILD new file mode 100644 index 00000000000..055dc4c1c8a --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/BUILD @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/doc.go new file mode 100644 index 00000000000..440b3b8a985 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mockdiskclient implements the mock client for Disks. +package mockdiskclient // import "k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go new file mode 100644 index 00000000000..098cdfb8701 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go @@ -0,0 +1,94 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mockdiskclient + +import ( + context "context" + reflect "reflect" + + compute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + gomock "github.com/golang/mock/gomock" + retry "k8s.io/legacy-cloud-providers/azure/retry" +) + +// MockInterface is a mock of Interface interface +type MockInterface struct { + ctrl *gomock.Controller + recorder *MockInterfaceMockRecorder +} + +// MockInterfaceMockRecorder is the mock recorder for MockInterface +type MockInterfaceMockRecorder struct { + mock *MockInterface +} + +// NewMockInterface creates a new mock instance +func NewMockInterface(ctrl *gomock.Controller) *MockInterface { + mock := &MockInterface{ctrl: ctrl} + mock.recorder = &MockInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { + return m.recorder +} + +// Get mocks base method +func (m *MockInterface) Get(ctx context.Context, resourceGroupName, diskName string) (compute.Disk, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, diskName) + ret0, _ := ret[0].(compute.Disk) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// Get indicates an expected call of Get +func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, diskName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, diskName) +} + +// CreateOrUpdate mocks base method +func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, diskName string, diskParameter compute.Disk) *retry.Error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, diskName, diskParameter) + ret0, _ := ret[0].(*retry.Error) + return ret0 +} + +// CreateOrUpdate indicates an expected call of CreateOrUpdate +func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, diskName, diskParameter interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, diskName, diskParameter) +} + +// Delete mocks base method +func (m *MockInterface) Delete(ctx context.Context, resourceGroupName, diskName string) *retry.Error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, resourceGroupName, diskName) + ret0, _ := ret[0].(*retry.Error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockInterfaceMockRecorder) Delete(ctx, resourceGroupName, diskName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName, diskName) +} From c86d1ec0e9dbc8d2d9a142b2a6fdf00425935379 Mon Sep 17 00:00:00 2001 From: Pengfei Ni Date: Wed, 15 Jan 2020 11:34:29 +0000 Subject: [PATCH 2/5] Add storageaccount clients based on armclient --- .../azure/clients/storageaccountclient/BUILD | 57 +++ .../azure_storageaccountclient.go | 466 ++++++++++++++++++ .../azure_storageaccountclient_test.go | 175 +++++++ .../azure/clients/storageaccountclient/doc.go | 20 + .../clients/storageaccountclient/interface.go | 51 ++ .../mockstorageaccountclient/BUILD | 31 ++ .../mockstorageaccountclient/doc.go | 20 + .../mockstorageaccountclient/interface.go | 123 +++++ 8 files changed, 943 insertions(+) create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient_test.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/interface.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/interface.go diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD new file mode 100644 index 00000000000..3148f992bcd --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD @@ -0,0 +1,57 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "azure_storageaccountclient.go", + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/metrics:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["azure_storageaccountclient_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient.go new file mode 100644 index 00000000000..84c0c8af1ae --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient.go @@ -0,0 +1,466 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 storageaccountclient + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/to" + + "k8s.io/client-go/util/flowcontrol" + "k8s.io/klog" + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/metrics" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +var _ Interface = &Client{} + +// Client implements StorageAccount client Interface. +type Client struct { + armClient armclient.Interface + subscriptionID string + + // Rate limiting configures. + rateLimiterReader flowcontrol.RateLimiter + rateLimiterWriter flowcontrol.RateLimiter + + // ARM throttling configures. + RetryAfterReader time.Time + RetryAfterWriter time.Time +} + +// New creates a new StorageAccount client with ratelimiting. +func New(config *azclients.ClientConfig) *Client { + baseURI := config.ResourceManagerEndpoint + authorizer := autorest.NewBearerAuthorizer(config.ServicePrincipalToken) + armClient := armclient.New(authorizer, baseURI, "", APIVersion, config.Location, config.Backoff) + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig) + + klog.V(2).Infof("Azure StorageAccountClient (read ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPS, + config.RateLimitConfig.CloudProviderRateLimitBucket) + klog.V(2).Infof("Azure StorageAccountClient (write ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPSWrite, + config.RateLimitConfig.CloudProviderRateLimitBucketWrite) + + client := &Client{ + armClient: armClient, + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + subscriptionID: config.SubscriptionID, + } + + return client +} + +// GetProperties gets properties of the StorageAccount. +func (c *Client) GetProperties(ctx context.Context, resourceGroupName string, accountName string) (storage.Account, *retry.Error) { + mc := metrics.NewMetricContext("storage_account", "get", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterReader.TryAccept() { + mc.RateLimitedCount() + return storage.Account{}, retry.GetRateLimitError(false, "StorageAccountGet") + } + + // Report errors if the client is throttled. + if c.RetryAfterReader.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("StorageAccountGet", "client throttled", c.RetryAfterReader) + return storage.Account{}, rerr + } + + result, rerr := c.getStorageAccount(ctx, resourceGroupName, accountName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterReader = rerr.RetryAfter + } + + return result, rerr + } + + return result, nil +} + +// getStorageAccount gets properties of the StorageAccount. +func (c *Client) getStorageAccount(ctx context.Context, resourceGroupName string, accountName string) (storage.Account, *retry.Error) { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Storage/storageAccounts", + accountName, + ) + result := storage.Account{} + + response, rerr := c.armClient.GetResource(ctx, resourceID, "") + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageaccount.get.request", resourceID, rerr.Error()) + return result, rerr + } + + err := autorest.Respond( + response, + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result)) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageaccount.get.respond", resourceID, err) + return result, retry.GetError(response, err) + } + + result.Response = autorest.Response{Response: response} + return result, nil +} + +// ListKeys get a list of storage account keys. +func (c *Client) ListKeys(ctx context.Context, resourceGroupName string, accountName string) (storage.AccountListKeysResult, *retry.Error) { + mc := metrics.NewMetricContext("storage_account", "list_keys", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterReader.TryAccept() { + mc.RateLimitedCount() + return storage.AccountListKeysResult{}, retry.GetRateLimitError(false, "StorageAccountListKeys") + } + + // Report errors if the client is throttled. + if c.RetryAfterReader.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("StorageAccountListKeys", "client throttled", c.RetryAfterReader) + return storage.AccountListKeysResult{}, rerr + } + + result, rerr := c.listStorageAccountKeys(ctx, resourceGroupName, accountName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterReader = rerr.RetryAfter + } + + return result, rerr + } + + return result, nil +} + +// listStorageAccountKeys get a list of storage account keys. +func (c *Client) listStorageAccountKeys(ctx context.Context, resourceGroupName string, accountName string) (storage.AccountListKeysResult, *retry.Error) { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Storage/storageAccounts", + accountName, + ) + + result := storage.AccountListKeysResult{} + response, rerr := c.armClient.PostResource(ctx, resourceID, "listKeys", struct{}{}) + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageaccount.listkeys.request", resourceID, rerr.Error()) + return result, rerr + } + + err := autorest.Respond( + response, + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result)) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageaccount.listkeys.respond", resourceID, err) + return result, retry.GetError(response, err) + } + + result.Response = autorest.Response{Response: response} + return result, nil +} + +// Create creates a StorageAccount. +func (c *Client) Create(ctx context.Context, resourceGroupName string, accountName string, parameters storage.AccountCreateParameters) *retry.Error { + mc := metrics.NewMetricContext("storage_account", "create", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterWriter.TryAccept() { + mc.RateLimitedCount() + return retry.GetRateLimitError(true, "StorageAccountCreate") + } + + // Report errors if the client is throttled. + if c.RetryAfterWriter.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("StorageAccountCreate", "client throttled", c.RetryAfterWriter) + return rerr + } + + rerr := c.createStorageAccount(ctx, resourceGroupName, accountName, parameters) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterWriter = rerr.RetryAfter + } + + return rerr + } + + return nil +} + +// createStorageAccount creates or updates a StorageAccount. +func (c *Client) createStorageAccount(ctx context.Context, resourceGroupName string, accountName string, parameters storage.AccountCreateParameters) *retry.Error { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Storage/storageAccounts", + accountName, + ) + + response, rerr := c.armClient.PutResource(ctx, resourceID, parameters) + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageAccount.put.request", resourceID, rerr.Error()) + return rerr + } + + if response != nil && response.StatusCode != http.StatusNoContent { + _, rerr = c.createResponder(response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageAccount.put.respond", resourceID, rerr.Error()) + return rerr + } + } + + return nil +} + +func (c *Client) createResponder(resp *http.Response) (*storage.Account, *retry.Error) { + result := &storage.Account{} + err := autorest.Respond( + resp, + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), + autorest.ByUnmarshallingJSON(&result)) + result.Response = autorest.Response{Response: resp} + return result, retry.GetError(resp, err) +} + +// Delete deletes a StorageAccount by name. +func (c *Client) Delete(ctx context.Context, resourceGroupName string, accountName string) *retry.Error { + mc := metrics.NewMetricContext("storage_account", "delete", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterWriter.TryAccept() { + mc.RateLimitedCount() + return retry.GetRateLimitError(true, "StorageAccountDelete") + } + + // Report errors if the client is throttled. + if c.RetryAfterWriter.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("StorageAccountDelete", "client throttled", c.RetryAfterWriter) + return rerr + } + + rerr := c.deleteStorageAccount(ctx, resourceGroupName, accountName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterWriter = rerr.RetryAfter + } + + return rerr + } + + return nil +} + +// deleteStorageAccount deletes a PublicIPAddress by name. +func (c *Client) deleteStorageAccount(ctx context.Context, resourceGroupName string, accountName string) *retry.Error { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Storage/storageAccounts", + accountName, + ) + + return c.armClient.DeleteResource(ctx, resourceID, "") +} + +// ListByResourceGroup get a list storage accounts by resourceGroup. +func (c *Client) ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]storage.Account, *retry.Error) { + mc := metrics.NewMetricContext("storage_account", "list_by_resource_group", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterReader.TryAccept() { + mc.RateLimitedCount() + return nil, retry.GetRateLimitError(false, "StorageAccountListByResourceGroup") + } + + // Report errors if the client is throttled. + if c.RetryAfterReader.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("StorageAccountListByResourceGroup", "client throttled", c.RetryAfterReader) + return nil, rerr + } + + result, rerr := c.ListStorageAccountByResourceGroup(ctx, resourceGroupName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterReader = rerr.RetryAfter + } + + return result, rerr + } + + return result, nil +} + +// ListStorageAccountByResourceGroup get a list storage accounts by resourceGroup. +func (c *Client) ListStorageAccountByResourceGroup(ctx context.Context, resourceGroupName string) ([]storage.Account, *retry.Error) { + resourceID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts", + autorest.Encode("path", c.subscriptionID), + autorest.Encode("path", resourceGroupName)) + result := make([]storage.Account, 0) + page := &AccountListResultPage{} + page.fn = c.listNextResults + + resp, rerr := c.armClient.GetResource(ctx, resourceID, "") + defer c.armClient.CloseResponse(ctx, resp) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageAccount.list.request", resourceID, rerr.Error()) + return result, rerr + } + + var err error + page.alr, err = c.listResponder(resp) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageAccount.list.respond", resourceID, err) + return result, retry.GetError(resp, err) + } + + for page.NotDone() { + result = append(result, *page.Response().Value...) + if err = page.NextWithContext(ctx); err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "storageAccount.list.next", resourceID, err) + return result, retry.GetError(page.Response().Response.Response, err) + } + } + + return result, nil +} + +func (c *Client) listResponder(resp *http.Response) (result storage.AccountListResult, err error) { + err = autorest.Respond( + resp, + autorest.ByIgnoring(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result)) + result.Response = autorest.Response{Response: resp} + return +} + +// StorageAccountResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (c *Client) StorageAccountResultPreparer(ctx context.Context, lr storage.AccountListResult) (*http.Request, error) { + if lr.NextLink == nil || len(to.String(lr.NextLink)) < 1 { + return nil, nil + } + + decorators := []autorest.PrepareDecorator{ + autorest.WithBaseURL(to.String(lr.NextLink)), + } + return c.armClient.PrepareGetRequest(ctx, decorators...) +} + +// listNextResults retrieves the next set of results, if any. +func (c *Client) listNextResults(ctx context.Context, lastResults storage.AccountListResult) (result storage.AccountListResult, err error) { + req, err := c.StorageAccountResultPreparer(ctx, lastResults) + if err != nil { + return result, autorest.NewErrorWithError(err, "storageaccount", "listNextResults", nil, "Failure preparing next results request") + } + if req == nil { + return + } + + resp, rerr := c.armClient.Send(ctx, req) + defer c.armClient.CloseResponse(ctx, resp) + if rerr != nil { + result.Response = autorest.Response{Response: resp} + return result, autorest.NewErrorWithError(rerr.Error(), "storageaccount", "listNextResults", resp, "Failure sending next results request") + } + + result, err = c.listResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "storageaccount", "listNextResults", resp, "Failure responding to next results request") + } + + return +} + +// AccountListResultPage contains a page of Account values. +type AccountListResultPage struct { + fn func(context.Context, storage.AccountListResult) (storage.AccountListResult, error) + alr storage.AccountListResult +} + +// NextWithContext advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +func (page *AccountListResultPage) NextWithContext(ctx context.Context) (err error) { + next, err := page.fn(ctx, page.alr) + if err != nil { + return err + } + page.alr = next + return nil +} + +// Next advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +// Deprecated: Use NextWithContext() instead. +func (page *AccountListResultPage) Next() error { + return page.NextWithContext(context.Background()) +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page AccountListResultPage) NotDone() bool { + return !page.alr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page AccountListResultPage) Response() storage.AccountListResult { + return page.alr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page AccountListResultPage) Values() []storage.Account { + if page.alr.IsEmpty() { + return nil + } + return *page.alr.Value +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient_test.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient_test.go new file mode 100644 index 00000000000..f1fb0031533 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/azure_storageaccountclient_test.go @@ -0,0 +1,175 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 storageaccountclient + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient" +) + +func TestGetPropertiesNotFound(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/sa1" + response := &http.Response{ + StatusCode: http.StatusNotFound, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + saClient := getTestStorageAccountClient(armClient) + expected := storage.Account{Response: autorest.Response{}} + result, rerr := saClient.GetProperties(context.TODO(), "rg", "sa1") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode) +} + +func TestGetPropertiesInternalError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/sa1" + response := &http.Response{ + StatusCode: http.StatusInternalServerError, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + saClient := getTestStorageAccountClient(armClient) + expected := storage.Account{Response: autorest.Response{}} + result, rerr := saClient.GetProperties(context.TODO(), "rg", "sa1") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode) +} + +func TestListKeys(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/sa1" + response := &http.Response{ + StatusCode: http.StatusNotFound, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().PostResource(gomock.Any(), resourceID, "listKeys", struct{}{}).Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + saClient := getTestStorageAccountClient(armClient) + expected := storage.AccountListKeysResult{Response: autorest.Response{}} + result, rerr := saClient.ListKeys(context.TODO(), "rg", "sa1") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode) +} + +func TestListByResourceGroup(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts" + armClient := mockarmclient.NewMockInterface(ctrl) + snList := []storage.Account{getTestStorageAccount("sn1"), getTestStorageAccount("pip2"), getTestStorageAccount("pip3")} + responseBody, err := json.Marshal(storage.AccountListResult{Value: &snList}) + assert.Nil(t, err) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return( + &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(responseBody)), + }, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + saClient := getTestStorageAccountClient(armClient) + result, rerr := saClient.ListByResourceGroup(context.TODO(), "rg") + assert.Nil(t, rerr) + assert.Equal(t, 3, len(result)) +} + +func TestCreate(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/sa1" + sa := storage.AccountCreateParameters{ + Location: to.StringPtr("eastus"), + } + armClient := mockarmclient.NewMockInterface(ctrl) + response := &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + } + armClient.EXPECT().PutResource(gomock.Any(), resourceID, sa).Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + saClient := getTestStorageAccountClient(armClient) + rerr := saClient.Create(context.TODO(), "rg", "sa1", sa) + assert.Nil(t, rerr) +} + +func TestDelete(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := getTestStorageAccount("sa1") + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().DeleteResource(gomock.Any(), to.String(r.ID), "").Return(nil).Times(1) + + rtClient := getTestStorageAccountClient(armClient) + rerr := rtClient.Delete(context.TODO(), "rg", "sa1") + assert.Nil(t, rerr) +} + +func getTestStorageAccount(name string) storage.Account { + return storage.Account{ + ID: to.StringPtr(fmt.Sprintf("/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/%s", name)), + Name: to.StringPtr(name), + Location: to.StringPtr("eastus"), + } +} + +func getTestStorageAccountClient(armClient armclient.Interface) *Client { + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{}) + return &Client{ + armClient: armClient, + subscriptionID: "subscriptionID", + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + } +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/doc.go new file mode 100644 index 00000000000..93b2b4dd2bd --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 storageaccountclient implements the client for StorageAccounts. +package storageaccountclient // import "k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/interface.go new file mode 100644 index 00000000000..5a0112c2397 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/interface.go @@ -0,0 +1,51 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 storageaccountclient + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +const ( + // APIVersion is the API version for network. + APIVersion = "2019-06-01" +) + +// Interface is the client interface for StorageAccounts. +// Don't forget to run the following command to generate the mock client: +// mockgen -source=$GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/interface.go -package=mockstorageaccountclient Interface > $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/interface.go +type Interface interface { + // Create creates a StorageAccount. + Create(ctx context.Context, resourceGroupName string, accountName string, parameters storage.AccountCreateParameters) *retry.Error + + // Delete deletes a StorageAccount by name. + Delete(ctx context.Context, resourceGroupName string, accountName string) *retry.Error + + // ListKeys get a list of storage account keys. + ListKeys(ctx context.Context, resourceGroupName string, accountName string) (storage.AccountListKeysResult, *retry.Error) + + // ListByResourceGroup get a list storage accounts by resourceGroup. + ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]storage.Account, *retry.Error) + + // GetProperties gets properties of the StorageAccount. + GetProperties(ctx context.Context, resourceGroupName string, accountName string) (result storage.Account, rerr *retry.Error) +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/BUILD new file mode 100644 index 00000000000..a1c7eb60815 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/BUILD @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/doc.go new file mode 100644 index 00000000000..907a8e77bd1 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mockstorageaccountclient implements the mock client for StorageAccounts. +package mockstorageaccountclient // import "k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/interface.go new file mode 100644 index 00000000000..45e8654cac2 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient/interface.go @@ -0,0 +1,123 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mockstorageaccountclient + +import ( + context "context" + storage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" + gomock "github.com/golang/mock/gomock" + retry "k8s.io/legacy-cloud-providers/azure/retry" + reflect "reflect" +) + +// MockInterface is a mock of Interface interface +type MockInterface struct { + ctrl *gomock.Controller + recorder *MockInterfaceMockRecorder +} + +// MockInterfaceMockRecorder is the mock recorder for MockInterface +type MockInterfaceMockRecorder struct { + mock *MockInterface +} + +// NewMockInterface creates a new mock instance +func NewMockInterface(ctrl *gomock.Controller) *MockInterface { + mock := &MockInterface{ctrl: ctrl} + mock.recorder = &MockInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { + return m.recorder +} + +// Create mocks base method +func (m *MockInterface) Create(ctx context.Context, resourceGroupName, accountName string, parameters storage.AccountCreateParameters) *retry.Error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, resourceGroupName, accountName, parameters) + ret0, _ := ret[0].(*retry.Error) + return ret0 +} + +// Create indicates an expected call of Create +func (mr *MockInterfaceMockRecorder) Create(ctx, resourceGroupName, accountName, parameters interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockInterface)(nil).Create), ctx, resourceGroupName, accountName, parameters) +} + +// Delete mocks base method +func (m *MockInterface) Delete(ctx context.Context, resourceGroupName, accountName string) *retry.Error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, resourceGroupName, accountName) + ret0, _ := ret[0].(*retry.Error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockInterfaceMockRecorder) Delete(ctx, resourceGroupName, accountName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName, accountName) +} + +// ListKeys mocks base method +func (m *MockInterface) ListKeys(ctx context.Context, resourceGroupName, accountName string) (storage.AccountListKeysResult, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListKeys", ctx, resourceGroupName, accountName) + ret0, _ := ret[0].(storage.AccountListKeysResult) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// ListKeys indicates an expected call of ListKeys +func (mr *MockInterfaceMockRecorder) ListKeys(ctx, resourceGroupName, accountName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListKeys", reflect.TypeOf((*MockInterface)(nil).ListKeys), ctx, resourceGroupName, accountName) +} + +// ListByResourceGroup mocks base method +func (m *MockInterface) ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]storage.Account, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListByResourceGroup", ctx, resourceGroupName) + ret0, _ := ret[0].([]storage.Account) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// ListByResourceGroup indicates an expected call of ListByResourceGroup +func (mr *MockInterfaceMockRecorder) ListByResourceGroup(ctx, resourceGroupName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListByResourceGroup", reflect.TypeOf((*MockInterface)(nil).ListByResourceGroup), ctx, resourceGroupName) +} + +// GetProperties mocks base method +func (m *MockInterface) GetProperties(ctx context.Context, resourceGroupName, accountName string) (storage.Account, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProperties", ctx, resourceGroupName, accountName) + ret0, _ := ret[0].(storage.Account) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// GetProperties indicates an expected call of GetProperties +func (mr *MockInterfaceMockRecorder) GetProperties(ctx, resourceGroupName, accountName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProperties", reflect.TypeOf((*MockInterface)(nil).GetProperties), ctx, resourceGroupName, accountName) +} From 4ea5509b31aef3c5a490f2621b4ac7567aa02f79 Mon Sep 17 00:00:00 2001 From: Pengfei Ni Date: Thu, 16 Jan 2020 14:33:29 +0000 Subject: [PATCH 3/5] Add vmsize clients based on armclient --- .../azure/clients/vmsizeclient/BUILD | 58 ++++++++ .../vmsizeclient/azure_vmsizeclient.go | 136 ++++++++++++++++++ .../vmsizeclient/azure_vmsizeclient_test.go | 88 ++++++++++++ .../azure/clients/vmsizeclient/doc.go | 20 +++ .../azure/clients/vmsizeclient/interface.go | 39 +++++ .../vmsizeclient/mockvmsizeclient/BUILD | 31 ++++ .../vmsizeclient/mockvmsizeclient/doc.go | 20 +++ .../mockvmsizeclient/interface.go | 65 +++++++++ 8 files changed, 457 insertions(+) create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient_test.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/interface.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/interface.go diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD new file mode 100644 index 00000000000..eb4267faa2a --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD @@ -0,0 +1,58 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "azure_virtualmachinesizeclient.go", + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/metrics:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["azure_virtualmachinesizeclient_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient/mockvirtualmachinesizeclient:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient.go new file mode 100644 index 00000000000..d54d487cd76 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient.go @@ -0,0 +1,136 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 vmsizeclient + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + + "k8s.io/client-go/util/flowcontrol" + "k8s.io/klog" + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/metrics" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +var _ Interface = &Client{} + +// Client implements VirtualMachineSize client Interface. +type Client struct { + armClient armclient.Interface + subscriptionID string + + // Rate limiting configures. + rateLimiterReader flowcontrol.RateLimiter + rateLimiterWriter flowcontrol.RateLimiter + + // ARM throttling configures. + RetryAfterReader time.Time + RetryAfterWriter time.Time +} + +// New creates a new VirtualMachineSize client with ratelimiting. +func New(config *azclients.ClientConfig) *Client { + baseURI := config.ResourceManagerEndpoint + authorizer := autorest.NewBearerAuthorizer(config.ServicePrincipalToken) + armClient := armclient.New(authorizer, baseURI, "", APIVersion, config.Location, config.Backoff) + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig) + + klog.V(2).Infof("Azure VirtualMachineSizesClient (read ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPS, + config.RateLimitConfig.CloudProviderRateLimitBucket) + klog.V(2).Infof("Azure VirtualMachineSizesClient (write ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPSWrite, + config.RateLimitConfig.CloudProviderRateLimitBucketWrite) + + client := &Client{ + armClient: armClient, + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + subscriptionID: config.SubscriptionID, + } + + return client +} + +// List gets compute.VirtualMachineSizeListResult. +func (c *Client) List(ctx context.Context, location string) (compute.VirtualMachineSizeListResult, *retry.Error) { + mc := metrics.NewMetricContext("vmsizes", "list", "", c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterReader.TryAccept() { + mc.RateLimitedCount() + return compute.VirtualMachineSizeListResult{}, retry.GetRateLimitError(false, "VMSizesList") + } + + // Report errors if the client is throttled. + if c.RetryAfterReader.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("VMSizesList", "client throttled", c.RetryAfterReader) + return compute.VirtualMachineSizeListResult{}, rerr + } + + result, rerr := c.listVirtualMachineSizes(ctx, location) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterReader = rerr.RetryAfter + } + + return result, rerr + } + + return result, nil +} + +// listVirtualMachineSizes gets compute.VirtualMachineSizeListResult. +func (c *Client) listVirtualMachineSizes(ctx context.Context, location string) (compute.VirtualMachineSizeListResult, *retry.Error) { + resourceID := fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/locations/%s/vmSizes", + autorest.Encode("path", c.subscriptionID), + autorest.Encode("path", location), + ) + + result := compute.VirtualMachineSizeListResult{} + response, rerr := c.armClient.GetResource(ctx, resourceID, "") + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "vmsize.list.request", resourceID, rerr.Error()) + return result, rerr + } + + err := autorest.Respond( + response, + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result)) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "vmsize.list.respond", resourceID, err) + return result, retry.GetError(response, err) + } + + result.Response = autorest.Response{Response: response} + return result, nil +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient_test.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient_test.go new file mode 100644 index 00000000000..08420a7457b --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/azure_vmsizeclient_test.go @@ -0,0 +1,88 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 vmsizeclient + +import ( + "bytes" + "context" + "io/ioutil" + "net/http" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient" +) + +func TestListNotFound(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/providers/Microsoft.Compute/locations/eastus/vmSizes" + response := &http.Response{ + StatusCode: http.StatusNotFound, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + vmsizeClient := getTestVMSizeClient(armClient) + expected := compute.VirtualMachineSizeListResult{Response: autorest.Response{}} + result, rerr := vmsizeClient.List(context.TODO(), "eastus") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode) +} + +func TestListInternalError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/providers/Microsoft.Compute/locations/eastus/vmSizes" + response := &http.Response{ + StatusCode: http.StatusInternalServerError, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + vmsizeClient := getTestVMSizeClient(armClient) + expected := compute.VirtualMachineSizeListResult{Response: autorest.Response{}} + result, rerr := vmsizeClient.List(context.TODO(), "eastus") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode) +} + +func getTestVMSizeClient(armClient armclient.Interface) *Client { + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{}) + return &Client{ + armClient: armClient, + subscriptionID: "subscriptionID", + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + } +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/doc.go new file mode 100644 index 00000000000..ea6323460d8 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 vmsizeclient implements the client for VirtualMachineSizes. +package vmsizeclient // import "k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/interface.go new file mode 100644 index 00000000000..604c08cd1e0 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/interface.go @@ -0,0 +1,39 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 vmsizeclient + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +const ( + // APIVersion is the API version for compute. + APIVersion = "2019-07-01" +) + +// Interface is the client interface for VirtualMachineSizes. +// Don't forget to run the following command to generate the mock client: +// mockgen -source=$GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/interface.go -package=mockvmsizeclient Interface > $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/interface.go +type Interface interface { + // List gets compute.VirtualMachineSizeListResult. + List(ctx context.Context, location string) (result compute.VirtualMachineSizeListResult, rerr *retry.Error) +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD new file mode 100644 index 00000000000..ff5ae99e4e5 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient/mockvirtualmachinesizeclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient/mockvirtualmachinesizeclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/doc.go new file mode 100644 index 00000000000..1a4253009d9 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mockvmsizeclient implements the mock client for VirtualMachineSizes. +package mockvmsizeclient // import "k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient/mockvmsizeclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/interface.go new file mode 100644 index 00000000000..36b2742358e --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/interface.go @@ -0,0 +1,65 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mockvmsizeclient + +import ( + context "context" + compute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + gomock "github.com/golang/mock/gomock" + retry "k8s.io/legacy-cloud-providers/azure/retry" + reflect "reflect" +) + +// MockInterface is a mock of Interface interface +type MockInterface struct { + ctrl *gomock.Controller + recorder *MockInterfaceMockRecorder +} + +// MockInterfaceMockRecorder is the mock recorder for MockInterface +type MockInterfaceMockRecorder struct { + mock *MockInterface +} + +// NewMockInterface creates a new mock instance +func NewMockInterface(ctrl *gomock.Controller) *MockInterface { + mock := &MockInterface{ctrl: ctrl} + mock.recorder = &MockInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { + return m.recorder +} + +// List mocks base method +func (m *MockInterface) List(ctx context.Context, location string) (compute.VirtualMachineSizeListResult, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List", ctx, location) + ret0, _ := ret[0].(compute.VirtualMachineSizeListResult) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// List indicates an expected call of List +func (mr *MockInterfaceMockRecorder) List(ctx, location interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockInterface)(nil).List), ctx, location) +} From c6429e3726f3e3066903708794c6ee481b6fb218 Mon Sep 17 00:00:00 2001 From: Pengfei Ni Date: Thu, 16 Jan 2020 15:21:27 +0000 Subject: [PATCH 4/5] Add snapshot clients based on armclient --- .../azure/clients/snapshotclient/BUILD | 57 +++ .../snapshotclient/azure_snapshotclient.go | 405 ++++++++++++++++++ .../azure_snapshotclient_test.go | 151 +++++++ .../azure/clients/snapshotclient/doc.go | 20 + .../azure/clients/snapshotclient/interface.go | 48 +++ .../snapshotclient/mocksnapshotclient/BUILD | 31 ++ .../snapshotclient/mocksnapshotclient/doc.go | 20 + .../mocksnapshotclient/interface.go | 108 +++++ 8 files changed, 840 insertions(+) create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient_test.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/interface.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/doc.go create mode 100644 staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/interface.go diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD new file mode 100644 index 00000000000..cb561aa3dcc --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD @@ -0,0 +1,57 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "azure_snapshotclient.go", + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/snapshotclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/metrics:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["azure_snapshotclient_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient.go new file mode 100644 index 00000000000..d0e15c2adc7 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient.go @@ -0,0 +1,405 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 snapshotclient + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/to" + + "k8s.io/client-go/util/flowcontrol" + "k8s.io/klog" + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/metrics" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +var _ Interface = &Client{} + +// Client implements Snapshot client Interface. +type Client struct { + armClient armclient.Interface + subscriptionID string + + // Rate limiting configures. + rateLimiterReader flowcontrol.RateLimiter + rateLimiterWriter flowcontrol.RateLimiter + + // ARM throttling configures. + RetryAfterReader time.Time + RetryAfterWriter time.Time +} + +// New creates a new Snapshot client with ratelimiting. +func New(config *azclients.ClientConfig) *Client { + baseURI := config.ResourceManagerEndpoint + authorizer := autorest.NewBearerAuthorizer(config.ServicePrincipalToken) + armClient := armclient.New(authorizer, baseURI, "", APIVersion, config.Location, config.Backoff) + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig) + + klog.V(2).Infof("Azure SnapshotClient (read ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPS, + config.RateLimitConfig.CloudProviderRateLimitBucket) + klog.V(2).Infof("Azure SnapshotClient (write ops) using rate limit config: QPS=%g, bucket=%d", + config.RateLimitConfig.CloudProviderRateLimitQPSWrite, + config.RateLimitConfig.CloudProviderRateLimitBucketWrite) + + client := &Client{ + armClient: armClient, + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + subscriptionID: config.SubscriptionID, + } + + return client +} + +// Get gets a Snapshot. +func (c *Client) Get(ctx context.Context, resourceGroupName string, snapshotName string) (compute.Snapshot, *retry.Error) { + mc := metrics.NewMetricContext("snapshot", "get", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterReader.TryAccept() { + mc.RateLimitedCount() + return compute.Snapshot{}, retry.GetRateLimitError(false, "SnapshotGet") + } + + // Report errors if the client is throttled. + if c.RetryAfterReader.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("SnapshotGet", "client throttled", c.RetryAfterReader) + return compute.Snapshot{}, rerr + } + + result, rerr := c.getSnapshot(ctx, resourceGroupName, snapshotName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterReader = rerr.RetryAfter + } + + return result, rerr + } + + return result, nil +} + +// getSnapshot gets a Snapshot. +func (c *Client) getSnapshot(ctx context.Context, resourceGroupName string, snapshotName string) (compute.Snapshot, *retry.Error) { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Compute/snapshots", + snapshotName, + ) + result := compute.Snapshot{} + + response, rerr := c.armClient.GetResource(ctx, resourceID, "") + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "snapshot.get.request", resourceID, rerr.Error()) + return result, rerr + } + + err := autorest.Respond( + response, + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result)) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "snapshot.get.respond", resourceID, err) + return result, retry.GetError(response, err) + } + + result.Response = autorest.Response{Response: response} + return result, nil +} + +// Delete deletes a Snapshot by name. +func (c *Client) Delete(ctx context.Context, resourceGroupName string, snapshotName string) *retry.Error { + mc := metrics.NewMetricContext("snapshot", "delete", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterWriter.TryAccept() { + mc.RateLimitedCount() + return retry.GetRateLimitError(true, "SnapshotDelete") + } + + // Report errors if the client is throttled. + if c.RetryAfterWriter.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("SnapshotDelete", "client throttled", c.RetryAfterWriter) + return rerr + } + + rerr := c.deleteSnapshot(ctx, resourceGroupName, snapshotName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterWriter = rerr.RetryAfter + } + + return rerr + } + + return nil +} + +// deleteSnapshot deletes a PublicIPAddress by name. +func (c *Client) deleteSnapshot(ctx context.Context, resourceGroupName string, snapshotName string) *retry.Error { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Compute/snapshots", + snapshotName, + ) + + return c.armClient.DeleteResource(ctx, resourceID, "") +} + +// CreateOrUpdate creates or updates a Snapshot. +func (c *Client) CreateOrUpdate(ctx context.Context, resourceGroupName string, snapshotName string, snapshot compute.Snapshot) *retry.Error { + mc := metrics.NewMetricContext("snapshot", "create_or_update", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterWriter.TryAccept() { + mc.RateLimitedCount() + return retry.GetRateLimitError(true, "SnapshotCreateOrUpdate") + } + + // Report errors if the client is throttled. + if c.RetryAfterWriter.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("SnapshotCreateOrUpdate", "client throttled", c.RetryAfterWriter) + return rerr + } + + rerr := c.createOrUpdateSnapshot(ctx, resourceGroupName, snapshotName, snapshot) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterWriter = rerr.RetryAfter + } + + return rerr + } + + return nil +} + +// createOrUpdateSnapshot creates or updates a Snapshot. +func (c *Client) createOrUpdateSnapshot(ctx context.Context, resourceGroupName string, snapshotName string, snapshot compute.Snapshot) *retry.Error { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Compute/snapshots", + snapshotName, + ) + + response, rerr := c.armClient.PutResource(ctx, resourceID, snapshot) + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "snapshot.put.request", resourceID, rerr.Error()) + return rerr + } + + if response != nil && response.StatusCode != http.StatusNoContent { + _, rerr = c.createOrUpdateResponder(response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "snapshot.put.respond", resourceID, rerr.Error()) + return rerr + } + } + + return nil +} + +func (c *Client) createOrUpdateResponder(resp *http.Response) (*compute.Snapshot, *retry.Error) { + result := &compute.Snapshot{} + err := autorest.Respond( + resp, + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), + autorest.ByUnmarshallingJSON(&result)) + result.Response = autorest.Response{Response: resp} + return result, retry.GetError(resp, err) +} + +// ListByResourceGroup get a list snapshots by resourceGroup. +func (c *Client) ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Snapshot, *retry.Error) { + mc := metrics.NewMetricContext("snapshot", "list_by_resource_group", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterReader.TryAccept() { + mc.RateLimitedCount() + return nil, retry.GetRateLimitError(false, "SnapshotListByResourceGroup") + } + + // Report errors if the client is throttled. + if c.RetryAfterReader.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("SnapshotListByResourceGroup", "client throttled", c.RetryAfterReader) + return nil, rerr + } + + result, rerr := c.listSnapshotsByResourceGroup(ctx, resourceGroupName) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterReader = rerr.RetryAfter + } + + return result, rerr + } + + return result, nil +} + +// listSnapshotsByResourceGroup gets a list of snapshots in the resource group. +func (c *Client) listSnapshotsByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Snapshot, *retry.Error) { + resourceID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/snapshots", + autorest.Encode("path", c.subscriptionID), + autorest.Encode("path", resourceGroupName)) + result := make([]compute.Snapshot, 0) + page := &SnapshotListPage{} + page.fn = c.listNextResults + + resp, rerr := c.armClient.GetResource(ctx, resourceID, "") + defer c.armClient.CloseResponse(ctx, resp) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "snapshot.list.request", resourceID, rerr.Error()) + return result, rerr + } + + var err error + page.sl, err = c.listResponder(resp) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "snapshot.list.respond", resourceID, err) + return result, retry.GetError(resp, err) + } + + for page.NotDone() { + result = append(result, *page.Response().Value...) + if err = page.NextWithContext(ctx); err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "snapshot.list.next", resourceID, err) + return result, retry.GetError(page.Response().Response.Response, err) + } + } + + return result, nil +} + +func (c *Client) listResponder(resp *http.Response) (result compute.SnapshotList, err error) { + err = autorest.Respond( + resp, + autorest.ByIgnoring(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result)) + result.Response = autorest.Response{Response: resp} + return +} + +// SnapshotListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (c *Client) SnapshotListResultPreparer(ctx context.Context, lr compute.SnapshotList) (*http.Request, error) { + if lr.NextLink == nil || len(to.String(lr.NextLink)) < 1 { + return nil, nil + } + + decorators := []autorest.PrepareDecorator{ + autorest.WithBaseURL(to.String(lr.NextLink)), + } + return c.armClient.PrepareGetRequest(ctx, decorators...) +} + +// listNextResults retrieves the next set of results, if any. +func (c *Client) listNextResults(ctx context.Context, lastResults compute.SnapshotList) (result compute.SnapshotList, err error) { + req, err := c.SnapshotListResultPreparer(ctx, lastResults) + if err != nil { + return result, autorest.NewErrorWithError(err, "snapshotclient", "listNextResults", nil, "Failure preparing next results request") + } + if req == nil { + return + } + + resp, rerr := c.armClient.Send(ctx, req) + defer c.armClient.CloseResponse(ctx, resp) + if rerr != nil { + result.Response = autorest.Response{Response: resp} + return result, autorest.NewErrorWithError(rerr.Error(), "snapshotclient", "listNextResults", resp, "Failure sending next results request") + } + + result, err = c.listResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "snapshotclient", "listNextResults", resp, "Failure responding to next results request") + } + + return +} + +// SnapshotListPage contains a page of Snapshot values. +type SnapshotListPage struct { + fn func(context.Context, compute.SnapshotList) (compute.SnapshotList, error) + sl compute.SnapshotList +} + +// NextWithContext advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +func (page *SnapshotListPage) NextWithContext(ctx context.Context) (err error) { + next, err := page.fn(ctx, page.sl) + if err != nil { + return err + } + page.sl = next + return nil +} + +// Next advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +// Deprecated: Use NextWithContext() instead. +func (page *SnapshotListPage) Next() error { + return page.NextWithContext(context.Background()) +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page SnapshotListPage) NotDone() bool { + return !page.sl.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page SnapshotListPage) Response() compute.SnapshotList { + return page.sl +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page SnapshotListPage) Values() []compute.Snapshot { + if page.sl.IsEmpty() { + return nil + } + return *page.sl.Value +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient_test.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient_test.go new file mode 100644 index 00000000000..611f968ad0b --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/azure_snapshotclient_test.go @@ -0,0 +1,151 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 snapshotclient + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/armclient" + "k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient" +) + +func TestGetNotFound(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/snapshots/sn1" + response := &http.Response{ + StatusCode: http.StatusNotFound, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + snClient := getTestSnapshotClient(armClient) + expected := compute.Snapshot{Response: autorest.Response{}} + result, rerr := snClient.Get(context.TODO(), "rg", "sn1") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusNotFound, rerr.HTTPStatusCode) +} + +func TestGetInternalError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/snapshots/sn1" + response := &http.Response{ + StatusCode: http.StatusInternalServerError, + Body: ioutil.NopCloser(bytes.NewReader([]byte("{}"))), + } + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + snClient := getTestSnapshotClient(armClient) + expected := compute.Snapshot{Response: autorest.Response{}} + result, rerr := snClient.Get(context.TODO(), "rg", "sn1") + assert.Equal(t, expected, result) + assert.NotNil(t, rerr) + assert.Equal(t, http.StatusInternalServerError, rerr.HTTPStatusCode) +} + +func TestListByResourceGroup(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resourceID := "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/snapshots" + armClient := mockarmclient.NewMockInterface(ctrl) + snList := []compute.Snapshot{getTestSnapshot("sn1"), getTestSnapshot("pip2"), getTestSnapshot("pip3")} + responseBody, err := json.Marshal(compute.SnapshotList{Value: &snList}) + assert.Nil(t, err) + armClient.EXPECT().GetResource(gomock.Any(), resourceID, "").Return( + &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(responseBody)), + }, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + snClient := getTestSnapshotClient(armClient) + result, rerr := snClient.ListByResourceGroup(context.TODO(), "rg") + assert.Nil(t, rerr) + assert.Equal(t, 3, len(result)) +} + +func TestCreateOrUpdate(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + sn := getTestSnapshot("sn1") + armClient := mockarmclient.NewMockInterface(ctrl) + response := &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + } + armClient.EXPECT().PutResource(gomock.Any(), to.String(sn.ID), sn).Return(response, nil).Times(1) + armClient.EXPECT().CloseResponse(gomock.Any(), gomock.Any()).Times(1) + + snClient := getTestSnapshotClient(armClient) + rerr := snClient.CreateOrUpdate(context.TODO(), "rg", "sn1", sn) + assert.Nil(t, rerr) +} + +func TestDelete(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := getTestSnapshot("sn1") + armClient := mockarmclient.NewMockInterface(ctrl) + armClient.EXPECT().DeleteResource(gomock.Any(), to.String(r.ID), "").Return(nil).Times(1) + + rtClient := getTestSnapshotClient(armClient) + rerr := rtClient.Delete(context.TODO(), "rg", "sn1") + assert.Nil(t, rerr) +} + +func getTestSnapshot(name string) compute.Snapshot { + return compute.Snapshot{ + ID: to.StringPtr(fmt.Sprintf("/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/snapshots/%s", name)), + Name: to.StringPtr(name), + Location: to.StringPtr("eastus"), + } +} + +func getTestSnapshotClient(armClient armclient.Interface) *Client { + rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(&azclients.RateLimitConfig{}) + return &Client{ + armClient: armClient, + subscriptionID: "subscriptionID", + rateLimiterReader: rateLimiterReader, + rateLimiterWriter: rateLimiterWriter, + } +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/doc.go new file mode 100644 index 00000000000..b499f31b0cf --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 snapshotclient implements the client for Snapshots. +package snapshotclient // import "k8s.io/legacy-cloud-providers/azure/clients/snapshotclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/interface.go new file mode 100644 index 00000000000..e98bd1d1c27 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/interface.go @@ -0,0 +1,48 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 snapshotclient + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "k8s.io/legacy-cloud-providers/azure/retry" +) + +const ( + // APIVersion is the API version for compute. + APIVersion = "2019-07-01" +) + +// Interface is the client interface for Snapshots. +// Don't forget to run the following command to generate the mock client: +// mockgen -source=$GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/interface.go -package=mocksnapshotclient Interface > $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/interface.go +type Interface interface { + // Get gets a Snapshot. + Get(ctx context.Context, resourceGroupName string, snapshotName string) (compute.Snapshot, *retry.Error) + + // Delete deletes a Snapshot by name. + Delete(ctx context.Context, resourceGroupName string, snapshotName string) *retry.Error + + // ListByResourceGroup get a list snapshots by resourceGroup. + ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Snapshot, *retry.Error) + + // CreateOrUpdate creates or updates a Snapshot. + CreateOrUpdate(ctx context.Context, resourceGroupName string, snapshotName string, snapshot compute.Snapshot) *retry.Error +} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD new file mode 100644 index 00000000000..1af72524452 --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "interface.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/golang/mock/gomock:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/doc.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/doc.go new file mode 100644 index 00000000000..c9d0943615b --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/doc.go @@ -0,0 +1,20 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mocksnapshotclient implements the mock client for Snapshots. +package mocksnapshotclient // import "k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient" diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/interface.go b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/interface.go new file mode 100644 index 00000000000..980454a849a --- /dev/null +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/interface.go @@ -0,0 +1,108 @@ +// +build !providerless + +/* +Copyright 2020 The Kubernetes 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 mocksnapshotclient + +import ( + context "context" + compute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + gomock "github.com/golang/mock/gomock" + retry "k8s.io/legacy-cloud-providers/azure/retry" + reflect "reflect" +) + +// MockInterface is a mock of Interface interface +type MockInterface struct { + ctrl *gomock.Controller + recorder *MockInterfaceMockRecorder +} + +// MockInterfaceMockRecorder is the mock recorder for MockInterface +type MockInterfaceMockRecorder struct { + mock *MockInterface +} + +// NewMockInterface creates a new mock instance +func NewMockInterface(ctrl *gomock.Controller) *MockInterface { + mock := &MockInterface{ctrl: ctrl} + mock.recorder = &MockInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { + return m.recorder +} + +// Get mocks base method +func (m *MockInterface) Get(ctx context.Context, resourceGroupName, snapshotName string) (compute.Snapshot, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, resourceGroupName, snapshotName) + ret0, _ := ret[0].(compute.Snapshot) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// Get indicates an expected call of Get +func (mr *MockInterfaceMockRecorder) Get(ctx, resourceGroupName, snapshotName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), ctx, resourceGroupName, snapshotName) +} + +// Delete mocks base method +func (m *MockInterface) Delete(ctx context.Context, resourceGroupName, snapshotName string) *retry.Error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, resourceGroupName, snapshotName) + ret0, _ := ret[0].(*retry.Error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockInterfaceMockRecorder) Delete(ctx, resourceGroupName, snapshotName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName, snapshotName) +} + +// ListByResourceGroup mocks base method +func (m *MockInterface) ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Snapshot, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListByResourceGroup", ctx, resourceGroupName) + ret0, _ := ret[0].([]compute.Snapshot) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// ListByResourceGroup indicates an expected call of ListByResourceGroup +func (mr *MockInterfaceMockRecorder) ListByResourceGroup(ctx, resourceGroupName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListByResourceGroup", reflect.TypeOf((*MockInterface)(nil).ListByResourceGroup), ctx, resourceGroupName) +} + +// CreateOrUpdate mocks base method +func (m *MockInterface) CreateOrUpdate(ctx context.Context, resourceGroupName, snapshotName string, snapshot compute.Snapshot) *retry.Error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, resourceGroupName, snapshotName, snapshot) + ret0, _ := ret[0].(*retry.Error) + return ret0 +} + +// CreateOrUpdate indicates an expected call of CreateOrUpdate +func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, snapshotName, snapshot interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, snapshotName, snapshot) +} From b0a6e597feeeb1b50a064ea34d130c4f57b816a8 Mon Sep 17 00:00:00 2001 From: Pengfei Ni Date: Fri, 17 Jan 2020 03:55:14 +0000 Subject: [PATCH 5/5] Use new storage clients in Azure cloud provider --- .../k8s.io/legacy-cloud-providers/azure/BUILD | 7 +- .../legacy-cloud-providers/azure/azure.go | 27 +- .../azure/azure_blobDiskController.go | 7 +- .../azure/azure_client.go | 311 +----------------- .../azure/azure_fakes.go | 4 +- .../azure/azure_storage_test.go | 20 +- .../azure/azure_storageaccount.go | 5 +- .../azure/clients/BUILD | 4 + .../azure/clients/snapshotclient/BUILD | 5 +- .../snapshotclient/mocksnapshotclient/BUILD | 2 +- .../azure/clients/storageaccountclient/BUILD | 1 + .../azure/clients/vmsizeclient/BUILD | 16 +- .../vmsizeclient/mockvmsizeclient/BUILD | 6 +- vendor/modules.txt | 4 + 14 files changed, 57 insertions(+), 362 deletions(-) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/BUILD index d65a4af2a1f..d37f3e462df 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/BUILD +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/BUILD @@ -54,10 +54,8 @@ go_library( "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", - "//staging/src/k8s.io/client-go/pkg/version:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", "//staging/src/k8s.io/client-go/tools/record:go_default_library", - "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/cloud-provider/service/helpers:go_default_library", "//staging/src/k8s.io/cloud-provider/volume:go_default_library", @@ -66,17 +64,20 @@ go_library( "//staging/src/k8s.io/component-base/featuregate:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/auth:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/interfaceclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/loadbalancerclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/publicipclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/routeclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/routetableclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/securitygroupclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/subnetclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmclient:go_default_library", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmssclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmssvmclient:go_default_library", - "//staging/src/k8s.io/legacy-cloud-providers/azure/metrics:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network:go_default_library", diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/azure.go b/staging/src/k8s.io/legacy-cloud-providers/azure/azure.go index 9caece8c230..9f046960ebf 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/azure.go +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/azure.go @@ -27,7 +27,6 @@ import ( "sync" "time" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" @@ -39,21 +38,24 @@ import ( clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" v1core "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/client-go/pkg/version" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" cloudprovider "k8s.io/cloud-provider" "k8s.io/klog" "k8s.io/legacy-cloud-providers/azure/auth" azclients "k8s.io/legacy-cloud-providers/azure/clients" + "k8s.io/legacy-cloud-providers/azure/clients/diskclient" "k8s.io/legacy-cloud-providers/azure/clients/interfaceclient" "k8s.io/legacy-cloud-providers/azure/clients/loadbalancerclient" "k8s.io/legacy-cloud-providers/azure/clients/publicipclient" "k8s.io/legacy-cloud-providers/azure/clients/routeclient" "k8s.io/legacy-cloud-providers/azure/clients/routetableclient" "k8s.io/legacy-cloud-providers/azure/clients/securitygroupclient" + "k8s.io/legacy-cloud-providers/azure/clients/snapshotclient" + "k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient" "k8s.io/legacy-cloud-providers/azure/clients/subnetclient" "k8s.io/legacy-cloud-providers/azure/clients/vmclient" + "k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient" "k8s.io/legacy-cloud-providers/azure/clients/vmssclient" "k8s.io/legacy-cloud-providers/azure/clients/vmssvmclient" "k8s.io/legacy-cloud-providers/azure/retry" @@ -235,7 +237,7 @@ type Cloud struct { VirtualMachinesClient VirtualMachinesClient StorageAccountClient StorageAccountClient DisksClient DisksClient - SnapshotsClient *compute.SnapshotsClient + SnapshotsClient SnapshotsClient FileClient FileClient VirtualMachineScaleSetsClient VirtualMachineScaleSetsClient VirtualMachineScaleSetVMsClient VirtualMachineScaleSetVMsClient @@ -493,18 +495,16 @@ func (az *Cloud) InitializeCloudFromConfig(config *Config, fromSecret bool) erro az.VirtualMachinesClient = vmclient.New(azClientConfig.WithRateLimiter(config.VirtualMachineRateLimit)) az.PublicIPAddressesClient = publicipclient.New(azClientConfig.WithRateLimiter(config.PublicIPAddressRateLimit)) az.VirtualMachineScaleSetsClient = vmssclient.New(azClientConfig.WithRateLimiter(config.VirtualMachineScaleSetRateLimit)) + az.DisksClient = diskclient.New(azClientConfig.WithRateLimiter(config.DiskRateLimit)) + az.VirtualMachineSizesClient = vmsizeclient.New(azClientConfig.WithRateLimiter(config.VirtualMachineSizeRateLimit)) + az.SnapshotsClient = snapshotclient.New(azClientConfig.WithRateLimiter(config.SnapshotRateLimit)) + az.StorageAccountClient = storageaccountclient.New(azClientConfig.WithRateLimiter(config.StorageAccountRateLimit)) // Error "not an active Virtual Machine Scale Set VM" is not retriable for VMSS VM. vmssVMClientConfig := azClientConfig.WithRateLimiter(config.VirtualMachineScaleSetRateLimit) vmssVMClientConfig.Backoff = vmssVMClientConfig.Backoff.WithNonRetriableErrors([]string{vmssVMNotActiveErrorMessage}) az.VirtualMachineScaleSetVMsClient = vmssvmclient.New(vmssVMClientConfig) - // TODO(feiskyer): refactor the following clients to use armclient - az.DisksClient = newAzDisksClient(azClientConfig.WithRateLimiter(config.DiskRateLimit)) - az.SnapshotsClient = newSnapshotsClient(azClientConfig.WithRateLimiter(config.SnapshotRateLimit)) - az.StorageAccountClient = newAzStorageAccountClient(azClientConfig.WithRateLimiter(config.StorageAccountRateLimit)) - az.VirtualMachineSizesClient = newAzVirtualMachineSizesClient(azClientConfig.WithRateLimiter(config.VirtualMachineSizeRateLimit)) - // TODO(feiskyer): refactor azureFileClient to Interface. az.FileClient = &azureFileClient{env: *env} @@ -615,15 +615,6 @@ func (az *Cloud) ProviderName() string { return CloudProviderName } -// configureUserAgent configures the autorest client with a user agent that -// includes "kubernetes" and the full kubernetes git version string -// example: -// Azure-SDK-for-Go/7.0.1-beta arm-network/2016-09-01; kubernetes-cloudprovider/v1.7.0-alpha.2.711+a2fadef8170bb0-dirty; -func configureUserAgent(client *autorest.Client) { - k8sVersion := version.Get().GitVersion - client.UserAgent = fmt.Sprintf("%s; kubernetes-cloudprovider/%s", client.UserAgent, k8sVersion) -} - func initDiskControllers(az *Cloud) error { // Common controller contains the function // needed by both blob disk and managed disk controllers diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_blobDiskController.go b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_blobDiskController.go index 0fd742de916..9dc6c458af4 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_blobDiskController.go +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_blobDiskController.go @@ -443,16 +443,13 @@ func (c *BlobDiskController) getDiskCount(SAName string) (int, error) { func (c *BlobDiskController) getAllStorageAccounts() (map[string]*storageAccountState, error) { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - accountListResult, rerr := c.common.cloud.StorageAccountClient.ListByResourceGroup(ctx, c.common.resourceGroup) + accountList, rerr := c.common.cloud.StorageAccountClient.ListByResourceGroup(ctx, c.common.resourceGroup) if rerr != nil { return nil, rerr.Error() } - if accountListResult.Value == nil { - return nil, fmt.Errorf("azureDisk - empty accountListResult") - } accounts := make(map[string]*storageAccountState) - for _, v := range *accountListResult.Value { + for _, v := range accountList { if v.Name == nil || v.Sku == nil { klog.Info("azureDisk - accountListResult Name or Sku is nil") continue diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_client.go b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_client.go index 87323dbc5be..cb5211a5399 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_client.go +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_client.go @@ -20,18 +20,11 @@ package azure import ( "context" - "fmt" - "time" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network" "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" - "github.com/Azure/go-autorest/autorest" - "k8s.io/client-go/util/flowcontrol" - "k8s.io/klog" - azclients "k8s.io/legacy-cloud-providers/azure/clients" - "k8s.io/legacy-cloud-providers/azure/metrics" "k8s.io/legacy-cloud-providers/azure/retry" ) @@ -41,15 +34,6 @@ const ( virtualMachineScaleSetsDeallocating = "Deallocating" ) -// Helpers for rate limiting error/error channel creation -func createRateLimitErr(isWrite bool, opName string) *retry.Error { - opType := "read" - if isWrite { - opType = "write" - } - return retry.GetRetriableError(fmt.Errorf("azure - cloud provider rate limited(%s) for operation:%s", opType, opName)) -} - // VirtualMachinesClient defines needed functions for azure compute.VirtualMachinesClient type VirtualMachinesClient interface { CreateOrUpdate(ctx context.Context, resourceGroupName string, VMName string, parameters compute.VirtualMachine, source string) *retry.Error @@ -129,10 +113,18 @@ type StorageAccountClient interface { Create(ctx context.Context, resourceGroupName string, accountName string, parameters storage.AccountCreateParameters) *retry.Error Delete(ctx context.Context, resourceGroupName string, accountName string) *retry.Error ListKeys(ctx context.Context, resourceGroupName string, accountName string) (result storage.AccountListKeysResult, rerr *retry.Error) - ListByResourceGroup(ctx context.Context, resourceGroupName string) (result storage.AccountListResult, rerr *retry.Error) + ListByResourceGroup(ctx context.Context, resourceGroupName string) (result []storage.Account, rerr *retry.Error) GetProperties(ctx context.Context, resourceGroupName string, accountName string) (result storage.Account, rerr *retry.Error) } +// SnapshotsClient defines needed functions for azure compute.SnapshotsClient +type SnapshotsClient interface { + Get(ctx context.Context, resourceGroupName string, snapshotName string) (compute.Snapshot, *retry.Error) + Delete(ctx context.Context, resourceGroupName string, snapshotName string) *retry.Error + ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Snapshot, *retry.Error) + CreateOrUpdate(ctx context.Context, resourceGroupName string, snapshotName string, snapshot compute.Snapshot) *retry.Error +} + // DisksClient defines needed functions for azure compute.DisksClient type DisksClient interface { CreateOrUpdate(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.Disk) *retry.Error @@ -148,288 +140,3 @@ type VirtualMachineSizesClient interface { func getContextWithCancel() (context.Context, context.CancelFunc) { return context.WithCancel(context.Background()) } - -// azStorageAccountClient implements StorageAccountClient. -type azStorageAccountClient struct { - client storage.AccountsClient - rateLimiterReader flowcontrol.RateLimiter - rateLimiterWriter flowcontrol.RateLimiter -} - -func newAzStorageAccountClient(config *azclients.ClientConfig) *azStorageAccountClient { - storageAccountClient := storage.NewAccountsClientWithBaseURI(config.ResourceManagerEndpoint, config.SubscriptionID) - storageAccountClient.Authorizer = autorest.NewBearerAuthorizer(config.ServicePrincipalToken) - storageAccountClient.PollingDelay = 5 * time.Second - if config.ShouldOmitCloudProviderBackoff { - storageAccountClient.RetryAttempts = config.CloudProviderBackoffRetries - storageAccountClient.RetryDuration = time.Duration(config.CloudProviderBackoffDuration) * time.Second - } - configureUserAgent(&storageAccountClient.Client) - - klog.V(2).Infof("Azure StorageAccountClient (read ops) using rate limit config: QPS=%g, bucket=%d", - config.RateLimitConfig.CloudProviderRateLimitQPS, - config.RateLimitConfig.CloudProviderRateLimitBucket) - klog.V(2).Infof("Azure StorageAccountClient (write ops) using rate limit config: QPS=%g, bucket=%d", - config.RateLimitConfig.CloudProviderRateLimitQPSWrite, - config.RateLimitConfig.CloudProviderRateLimitBucketWrite) - rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig) - return &azStorageAccountClient{ - client: storageAccountClient, - rateLimiterReader: rateLimiterReader, - rateLimiterWriter: rateLimiterWriter, - } -} - -func (az *azStorageAccountClient) Create(ctx context.Context, resourceGroupName string, accountName string, parameters storage.AccountCreateParameters) *retry.Error { - mc := metrics.NewMetricContext("storage_account", "create", resourceGroupName, az.client.SubscriptionID, "") - /* Write rate limiting */ - if !az.rateLimiterWriter.TryAccept() { - mc.RateLimitedCount() - return createRateLimitErr(true, "StorageAccountCreate") - } - - klog.V(10).Infof("azStorageAccountClient.Create(%q,%q): start", resourceGroupName, accountName) - defer func() { - klog.V(10).Infof("azStorageAccountClient.Create(%q,%q): end", resourceGroupName, accountName) - }() - - future, err := az.client.Create(ctx, resourceGroupName, accountName, parameters) - if err != nil { - return retry.GetError(future.Response(), err) - } - - err = future.WaitForCompletionRef(ctx, az.client.Client) - mc.Observe(err) - return retry.GetError(future.Response(), err) -} - -func (az *azStorageAccountClient) Delete(ctx context.Context, resourceGroupName string, accountName string) *retry.Error { - mc := metrics.NewMetricContext("storage_account", "delete", resourceGroupName, az.client.SubscriptionID, "") - if !az.rateLimiterReader.TryAccept() { - mc.RateLimitedCount() - return createRateLimitErr(false, "DeleteStorageAccount") - } - - klog.V(10).Infof("azStorageAccountClient.Delete(%q,%q): start", resourceGroupName, accountName) - defer func() { - klog.V(10).Infof("azStorageAccountClient.Delete(%q,%q): end", resourceGroupName, accountName) - }() - - result, err := az.client.Delete(ctx, resourceGroupName, accountName) - mc.Observe(err) - return retry.GetStatusNotFoundAndForbiddenIgnoredError(result.Response, err) -} - -func (az *azStorageAccountClient) ListKeys(ctx context.Context, resourceGroupName string, accountName string) (result storage.AccountListKeysResult, rerr *retry.Error) { - mc := metrics.NewMetricContext("storage_account", "list_keys", resourceGroupName, az.client.SubscriptionID, "") - if !az.rateLimiterReader.TryAccept() { - mc.RateLimitedCount() - rerr = createRateLimitErr(false, "ListStorageAccountKeys") - return - } - - klog.V(10).Infof("azStorageAccountClient.ListKeys(%q,%q): start", resourceGroupName, accountName) - defer func() { - klog.V(10).Infof("azStorageAccountClient.ListKeys(%q,%q): end", resourceGroupName, accountName) - }() - - var err error - result, err = az.client.ListKeys(ctx, resourceGroupName, accountName, storage.Kerb) - mc.Observe(err) - return result, retry.GetError(result.Response.Response, err) -} - -func (az *azStorageAccountClient) ListByResourceGroup(ctx context.Context, resourceGroupName string) (result storage.AccountListResult, rerr *retry.Error) { - mc := metrics.NewMetricContext("storage_account", "list_by_resource_group", resourceGroupName, az.client.SubscriptionID, "") - if !az.rateLimiterReader.TryAccept() { - mc.RateLimitedCount() - rerr = createRateLimitErr(false, "ListStorageAccountsByResourceGroup") - return - } - - klog.V(10).Infof("azStorageAccountClient.ListByResourceGroup(%q): start", resourceGroupName) - defer func() { - klog.V(10).Infof("azStorageAccountClient.ListByResourceGroup(%q): end", resourceGroupName) - }() - - var err error - result, err = az.client.ListByResourceGroup(ctx, resourceGroupName) - mc.Observe(err) - return result, retry.GetError(result.Response.Response, err) -} - -func (az *azStorageAccountClient) GetProperties(ctx context.Context, resourceGroupName string, accountName string) (result storage.Account, rerr *retry.Error) { - mc := metrics.NewMetricContext("storage_account", "get_properties", resourceGroupName, az.client.SubscriptionID, "") - if !az.rateLimiterReader.TryAccept() { - mc.RateLimitedCount() - rerr = createRateLimitErr(false, "GetStorageAccount/Properties") - return - } - - klog.V(10).Infof("azStorageAccountClient.GetProperties(%q,%q): start", resourceGroupName, accountName) - defer func() { - klog.V(10).Infof("azStorageAccountClient.GetProperties(%q,%q): end", resourceGroupName, accountName) - }() - - var err error - result, err = az.client.GetProperties(ctx, resourceGroupName, accountName, "") - mc.Observe(err) - return result, retry.GetError(result.Response.Response, err) -} - -// azDisksClient implements DisksClient. -type azDisksClient struct { - client compute.DisksClient - rateLimiterReader flowcontrol.RateLimiter - rateLimiterWriter flowcontrol.RateLimiter -} - -func newAzDisksClient(config *azclients.ClientConfig) *azDisksClient { - disksClient := compute.NewDisksClientWithBaseURI(config.ResourceManagerEndpoint, config.SubscriptionID) - disksClient.Authorizer = autorest.NewBearerAuthorizer(config.ServicePrincipalToken) - disksClient.PollingDelay = 5 * time.Second - if config.ShouldOmitCloudProviderBackoff { - disksClient.RetryAttempts = config.CloudProviderBackoffRetries - disksClient.RetryDuration = time.Duration(config.CloudProviderBackoffDuration) * time.Second - } - configureUserAgent(&disksClient.Client) - - klog.V(2).Infof("Azure DisksClient (read ops) using rate limit config: QPS=%g, bucket=%d", - config.RateLimitConfig.CloudProviderRateLimitQPS, - config.RateLimitConfig.CloudProviderRateLimitBucket) - klog.V(2).Infof("Azure DisksClient (write ops) using rate limit config: QPS=%g, bucket=%d", - config.RateLimitConfig.CloudProviderRateLimitQPSWrite, - config.RateLimitConfig.CloudProviderRateLimitBucketWrite) - rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig) - return &azDisksClient{ - client: disksClient, - rateLimiterReader: rateLimiterReader, - rateLimiterWriter: rateLimiterWriter, - } -} - -func (az *azDisksClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.Disk) *retry.Error { - mc := metrics.NewMetricContext("disks", "create_or_update", resourceGroupName, az.client.SubscriptionID, "") - /* Write rate limiting */ - if !az.rateLimiterWriter.TryAccept() { - mc.RateLimitedCount() - return createRateLimitErr(true, "DiskCreateOrUpdate") - } - - klog.V(10).Infof("azDisksClient.CreateOrUpdate(%q,%q): start", resourceGroupName, diskName) - defer func() { - klog.V(10).Infof("azDisksClient.CreateOrUpdate(%q,%q): end", resourceGroupName, diskName) - }() - - future, err := az.client.CreateOrUpdate(ctx, resourceGroupName, diskName, diskParameter) - if err != nil { - return retry.GetError(future.Response(), mc.Observe(err)) - } - - err = future.WaitForCompletionRef(ctx, az.client.Client) - return retry.GetError(future.Response(), mc.Observe(err)) -} - -func (az *azDisksClient) Delete(ctx context.Context, resourceGroupName string, diskName string) *retry.Error { - mc := metrics.NewMetricContext("disks", "delete", resourceGroupName, az.client.SubscriptionID, "") - /* Write rate limiting */ - if !az.rateLimiterWriter.TryAccept() { - mc.RateLimitedCount() - return createRateLimitErr(true, "DiskDelete") - } - - klog.V(10).Infof("azDisksClient.Delete(%q,%q): start", resourceGroupName, diskName) - defer func() { - klog.V(10).Infof("azDisksClient.Delete(%q,%q): end", resourceGroupName, diskName) - }() - - future, err := az.client.Delete(ctx, resourceGroupName, diskName) - if err != nil { - return retry.GetStatusNotFoundAndForbiddenIgnoredError(future.Response(), mc.Observe(err)) - } - err = future.WaitForCompletionRef(ctx, az.client.Client) - return retry.GetStatusNotFoundAndForbiddenIgnoredError(future.Response(), mc.Observe(err)) -} - -func (az *azDisksClient) Get(ctx context.Context, resourceGroupName string, diskName string) (result compute.Disk, rerr *retry.Error) { - mc := metrics.NewMetricContext("disks", "get", resourceGroupName, az.client.SubscriptionID, "") - if !az.rateLimiterReader.TryAccept() { - mc.RateLimitedCount() - rerr = createRateLimitErr(false, "GetDisk") - return - } - - klog.V(10).Infof("azDisksClient.Get(%q,%q): start", resourceGroupName, diskName) - defer func() { - klog.V(10).Infof("azDisksClient.Get(%q,%q): end", resourceGroupName, diskName) - }() - - var err error - result, err = az.client.Get(ctx, resourceGroupName, diskName) - mc.Observe(err) - return result, retry.GetError(result.Response.Response, err) -} - -// TODO(feiskyer): refactor compute.SnapshotsClient to Interface. -func newSnapshotsClient(config *azclients.ClientConfig) *compute.SnapshotsClient { - snapshotsClient := compute.NewSnapshotsClientWithBaseURI(config.ResourceManagerEndpoint, config.SubscriptionID) - snapshotsClient.Authorizer = autorest.NewBearerAuthorizer(config.ServicePrincipalToken) - snapshotsClient.PollingDelay = 5 * time.Second - if config.ShouldOmitCloudProviderBackoff { - snapshotsClient.RetryAttempts = config.CloudProviderBackoffRetries - snapshotsClient.RetryDuration = time.Duration(config.CloudProviderBackoffDuration) * time.Second - } - configureUserAgent(&snapshotsClient.Client) - return &snapshotsClient -} - -// azVirtualMachineSizesClient implements VirtualMachineSizesClient. -type azVirtualMachineSizesClient struct { - client compute.VirtualMachineSizesClient - rateLimiterReader flowcontrol.RateLimiter - rateLimiterWriter flowcontrol.RateLimiter -} - -func newAzVirtualMachineSizesClient(config *azclients.ClientConfig) *azVirtualMachineSizesClient { - VirtualMachineSizesClient := compute.NewVirtualMachineSizesClient(config.SubscriptionID) - VirtualMachineSizesClient.BaseURI = config.ResourceManagerEndpoint - VirtualMachineSizesClient.Authorizer = autorest.NewBearerAuthorizer(config.ServicePrincipalToken) - VirtualMachineSizesClient.PollingDelay = 5 * time.Second - if config.ShouldOmitCloudProviderBackoff { - VirtualMachineSizesClient.RetryAttempts = config.CloudProviderBackoffRetries - VirtualMachineSizesClient.RetryDuration = time.Duration(config.CloudProviderBackoffDuration) * time.Second - } - configureUserAgent(&VirtualMachineSizesClient.Client) - - klog.V(2).Infof("Azure VirtualMachineSizesClient (read ops) using rate limit config: QPS=%g, bucket=%d", - config.RateLimitConfig.CloudProviderRateLimitQPS, - config.RateLimitConfig.CloudProviderRateLimitBucket) - klog.V(2).Infof("Azure VirtualMachineSizesClient (write ops) using rate limit config: QPS=%g, bucket=%d", - config.RateLimitConfig.CloudProviderRateLimitQPSWrite, - config.RateLimitConfig.CloudProviderRateLimitBucketWrite) - rateLimiterReader, rateLimiterWriter := azclients.NewRateLimiter(config.RateLimitConfig) - return &azVirtualMachineSizesClient{ - rateLimiterReader: rateLimiterReader, - rateLimiterWriter: rateLimiterWriter, - client: VirtualMachineSizesClient, - } -} - -func (az *azVirtualMachineSizesClient) List(ctx context.Context, location string) (result compute.VirtualMachineSizeListResult, rerr *retry.Error) { - mc := metrics.NewMetricContext("vmsizes", "list", "", az.client.SubscriptionID, "") - if !az.rateLimiterReader.TryAccept() { - mc.RateLimitedCount() - rerr = createRateLimitErr(false, "VMSizesList") - return - } - - klog.V(10).Infof("azVirtualMachineSizesClient.List(%q): start", location) - defer func() { - klog.V(10).Infof("azVirtualMachineSizesClient.List(%q): end", location) - }() - - var err error - result, err = az.client.List(ctx, location) - mc.Observe(err) - return result, retry.GetError(result.Response.Response, err) -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_fakes.go b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_fakes.go index 95849cdec7f..7464d20408c 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_fakes.go +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_fakes.go @@ -772,7 +772,7 @@ type fakeStorageAccountClient struct { mutex *sync.Mutex FakeStore map[string]map[string]storage.Account Keys storage.AccountListKeysResult - Accounts storage.AccountListResult + Accounts []storage.Account Err error } @@ -825,7 +825,7 @@ func (fSAC *fakeStorageAccountClient) ListKeys(ctx context.Context, resourceGrou return fSAC.Keys, nil } -func (fSAC *fakeStorageAccountClient) ListByResourceGroup(ctx context.Context, resourceGroupName string) (result storage.AccountListResult, err *retry.Error) { +func (fSAC *fakeStorageAccountClient) ListByResourceGroup(ctx context.Context, resourceGroupName string) (result []storage.Account, err *retry.Error) { return fSAC.Accounts, nil } diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storage_test.go b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storage_test.go index 778e5441c81..631c4dab82a 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storage_test.go +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storage_test.go @@ -44,7 +44,7 @@ func TestCreateFileShare(t *testing.T) { acctKind string loc string gb int - accounts storage.AccountListResult + accounts []storage.Account keys storage.AccountListKeysResult err error @@ -77,10 +77,8 @@ func TestCreateFileShare(t *testing.T) { acctKind: kind, loc: location, gb: 10, - accounts: storage.AccountListResult{ - Value: &[]storage.Account{ - {Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Kind: storage.Kind(kind), Location: &location}, - }, + accounts: []storage.Account{ + {Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Kind: storage.Kind(kind), Location: &location}, }, keys: storage.AccountListKeysResult{ Keys: &[]storage.AccountKey{ @@ -97,10 +95,8 @@ func TestCreateFileShare(t *testing.T) { acctKind: kind, loc: location, gb: 10, - accounts: storage.AccountListResult{ - Value: &[]storage.Account{ - {Name: &bogus, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &location}, - }, + accounts: []storage.Account{ + {Name: &bogus, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &location}, }, expectErr: true, }, @@ -111,10 +107,8 @@ func TestCreateFileShare(t *testing.T) { acctKind: kind, loc: location, gb: 10, - accounts: storage.AccountListResult{ - Value: &[]storage.Account{ - {Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &bogus}, - }, + accounts: []storage.Account{ + {Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &bogus}, }, expectErr: true, }, diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storageaccount.go b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storageaccount.go index 5145b711f8e..c1abf1b26c1 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storageaccount.go +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/azure_storageaccount.go @@ -40,12 +40,9 @@ func (az *Cloud) getStorageAccounts(matchingAccountType, matchingAccountKind, re if rerr != nil { return nil, rerr.Error() } - if result.Value == nil { - return nil, fmt.Errorf("unexpected error when listing storage accounts from resource group %s", resourceGroup) - } accounts := []accountWithLocation{} - for _, acct := range *result.Value { + for _, acct := range result { if acct.Name != nil && acct.Location != nil && acct.Sku != nil { storageType := string((*acct.Sku).Name) if matchingAccountType != "" && !strings.EqualFold(matchingAccountType, storageType) { diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/BUILD index 64ce9fa06f2..0e93d59499d 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/BUILD +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/BUILD @@ -28,14 +28,18 @@ filegroup( srcs = [ ":package-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:all-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/interfaceclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/loadbalancerclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/publicipclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/routeclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/routetableclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/securitygroupclient:all-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient:all-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/subnetclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmclient:all-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmssclient:all-srcs", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmssvmclient:all-srcs", ], diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD index cb561aa3dcc..f495e83f632 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/BUILD @@ -16,9 +16,10 @@ go_library( "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/metrics:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", - "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) @@ -31,7 +32,7 @@ go_test( "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient:go_default_library", - "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", "//vendor/github.com/golang/mock/gomock:go_default_library", diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD index 1af72524452..920a884ec31 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/snapshotclient/mocksnapshotclient/BUILD @@ -11,7 +11,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", - "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", "//vendor/github.com/golang/mock/gomock:go_default_library", ], ) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD index 3148f992bcd..710c4c9c85b 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/BUILD @@ -19,6 +19,7 @@ go_library( "//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD index eb4267faa2a..588fb5ad3a9 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/BUILD @@ -3,12 +3,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ - "azure_virtualmachinesizeclient.go", + "azure_vmsizeclient.go", "doc.go", "interface.go", ], - importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient", - importpath = "k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient", + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient", visibility = ["//visibility:public"], deps = [ "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", @@ -16,25 +16,23 @@ go_library( "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/metrics:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", - "//vendor/github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", - "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) go_test( name = "go_default_test", - srcs = ["azure_virtualmachinesizeclient_test.go"], + srcs = ["azure_vmsizeclient_test.go"], embed = [":go_default_library"], deps = [ "//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient:go_default_library", "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient:go_default_library", - "//vendor/github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", - "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", "//vendor/github.com/golang/mock/gomock:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", ], @@ -51,7 +49,7 @@ filegroup( name = "all-srcs", srcs = [ ":package-srcs", - "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient/mockvirtualmachinesizeclient:all-srcs", + "//staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient:all-srcs", ], tags = ["automanaged"], visibility = ["//visibility:public"], diff --git a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD index ff5ae99e4e5..9256d86f420 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD +++ b/staging/src/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient/BUILD @@ -6,12 +6,12 @@ go_library( "doc.go", "interface.go", ], - importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient/mockvirtualmachinesizeclient", - importpath = "k8s.io/legacy-cloud-providers/azure/clients/virtualmachinesizeclient/mockvirtualmachinesizeclient", + importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient", + importpath = "k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient/mockvmsizeclient", visibility = ["//visibility:public"], deps = [ "//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library", - "//vendor/github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library", "//vendor/github.com/golang/mock/gomock:go_default_library", ], ) diff --git a/vendor/modules.txt b/vendor/modules.txt index 3b8f8bc950a..edfc37e579f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1838,14 +1838,18 @@ k8s.io/legacy-cloud-providers/azure k8s.io/legacy-cloud-providers/azure/auth k8s.io/legacy-cloud-providers/azure/clients k8s.io/legacy-cloud-providers/azure/clients/armclient +k8s.io/legacy-cloud-providers/azure/clients/diskclient k8s.io/legacy-cloud-providers/azure/clients/interfaceclient k8s.io/legacy-cloud-providers/azure/clients/loadbalancerclient k8s.io/legacy-cloud-providers/azure/clients/publicipclient k8s.io/legacy-cloud-providers/azure/clients/routeclient k8s.io/legacy-cloud-providers/azure/clients/routetableclient k8s.io/legacy-cloud-providers/azure/clients/securitygroupclient +k8s.io/legacy-cloud-providers/azure/clients/snapshotclient +k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient k8s.io/legacy-cloud-providers/azure/clients/subnetclient k8s.io/legacy-cloud-providers/azure/clients/vmclient +k8s.io/legacy-cloud-providers/azure/clients/vmsizeclient k8s.io/legacy-cloud-providers/azure/clients/vmssclient k8s.io/legacy-cloud-providers/azure/clients/vmssvmclient k8s.io/legacy-cloud-providers/azure/metrics