Addd Azure ARM client with backoff retries

This commit is contained in:
Pengfei Ni 2019-12-31 11:02:47 +08:00
parent 09cb73a554
commit 9d67227fb4
8 changed files with 1329 additions and 0 deletions

View File

@ -0,0 +1,48 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"azure_armclient.go",
"doc.go",
"interface.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/legacy-cloud-providers/azure/clients/armclient",
importpath = "k8s.io/legacy-cloud-providers/azure/clients/armclient",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/client-go/pkg/version:go_default_library",
"//staging/src/k8s.io/legacy-cloud-providers/azure/retry: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_armclient_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/legacy-cloud-providers/azure/retry:go_default_library",
"//vendor/github.com/Azure/go-autorest/autorest: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/armclient/mockarmclient:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,543 @@
// +build !providerless
/*
Copyright 2019 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 armclient
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"unicode"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
"k8s.io/client-go/pkg/version"
"k8s.io/klog"
"k8s.io/legacy-cloud-providers/azure/retry"
)
var _ Interface = &Client{}
// Client implements ARM client Interface.
type Client struct {
client autorest.Client
backoff *retry.Backoff
baseURI string
apiVersion string
clientRegion string
}
// New creates a ARM client
func New(authorizer autorest.Authorizer, baseURI, userAgent, apiVersion, clientRegion string, clientBackoff *retry.Backoff) *Client {
restClient := autorest.NewClientWithUserAgent(userAgent)
restClient.PollingDelay = 5 * time.Second
restClient.RetryAttempts = 3
restClient.RetryDuration = time.Second * 1
restClient.Authorizer = authorizer
if userAgent == "" {
restClient.UserAgent = GetUserAgent(restClient)
}
backoff := clientBackoff
if backoff == nil {
// 1 steps means no retry.
backoff = &retry.Backoff{
Steps: 1,
}
}
return &Client{
client: restClient,
baseURI: baseURI,
backoff: backoff,
apiVersion: apiVersion,
clientRegion: NormalizeAzureRegion(clientRegion),
}
}
// GetUserAgent gets 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 arm-network/2016-09-01; kubernetes-cloudprovider/v1.17.0;
func GetUserAgent(client autorest.Client) string {
k8sVersion := version.Get().GitVersion
return fmt.Sprintf("%s; kubernetes-cloudprovider/%s", client.UserAgent, k8sVersion)
}
// NormalizeAzureRegion returns a normalized Azure region with white spaces removed and converted to lower case
func NormalizeAzureRegion(name string) string {
region := ""
for _, runeValue := range name {
if !unicode.IsSpace(runeValue) {
region += string(runeValue)
}
}
return strings.ToLower(region)
}
// sendRequest sends a http request to ARM service.
// Although Azure SDK supports retries per https://github.com/azure/azure-sdk-for-go#request-retry-policy, we
// disable it since we want to fully control the retry policies.
func (c *Client) sendRequest(ctx context.Context, request *http.Request) (*http.Response, *retry.Error) {
sendBackoff := *c.backoff
response, err := autorest.SendWithSender(
c.client,
request,
retry.DoExponentialBackoffRetry(&sendBackoff),
)
return response, retry.GetError(response, err)
}
// Send sends a http request to ARM service with possible retry to regional ARM endpoint.
func (c *Client) Send(ctx context.Context, request *http.Request) (*http.Response, *retry.Error) {
response, rerr := c.sendRequest(ctx, request)
if rerr != nil {
return response, rerr
}
if response.StatusCode != http.StatusNotFound || c.clientRegion == "" {
return response, rerr
}
bodyBytes, _ := ioutil.ReadAll(response.Body)
defer func() {
response.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
}()
bodyString := string(bodyBytes)
klog.V(5).Infof("Send.sendRequest original error message: %s", bodyString)
// Hack: retry the regional ARM endpoint in case of ARM traffic split and arm resource group replication is too slow
var body map[string]interface{}
if e := json.Unmarshal(bodyBytes, &body); e != nil {
klog.V(5).Infof("Send.sendRequest: error in parsing response body string: %s, Skip retrying regional host", e)
return response, rerr
}
if err, ok := body["error"].(map[string]interface{}); !ok ||
err["code"] == nil ||
!strings.EqualFold(err["code"].(string), "ResourceGroupNotFound") {
klog.V(5).Infof("Send.sendRequest: response body does not contain ResourceGroupNotFound error code. Skip retrying regional host")
return response, rerr
}
currentHost := request.URL.Host
if request.Host != "" {
currentHost = request.Host
}
if strings.HasPrefix(strings.ToLower(currentHost), c.clientRegion) {
klog.V(5).Infof("Send.sendRequest: current host %s is regional host. Skip retrying regional host.", currentHost)
return response, rerr
}
request.Host = fmt.Sprintf("%s.%s", c.clientRegion, strings.ToLower(currentHost))
klog.V(5).Infof("Send.sendRegionalRequest on ResourceGroupNotFound error. Retrying regional host: %s", request.Host)
regionalResponse, regionalError := c.sendRequest(ctx, request)
// only use the result if the regional request actually goes through and returns 2xx status code, for two reasons:
// 1. the retry on regional ARM host approach is a hack.
// 2. the concatted regional uri could be wrong as the rule is not officially declared by ARM.
if regionalResponse == nil || regionalResponse.StatusCode > 299 {
regionalErrStr := ""
if regionalError != nil {
regionalErrStr = regionalError.Error().Error()
}
klog.V(5).Infof("Send.sendRegionalRequest failed to get response from regional host, error: '%s'. Ignoring the result.", regionalErrStr)
return response, rerr
}
return regionalResponse, regionalError
}
// PreparePutRequest prepares put request
func (c *Client) PreparePutRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
decorators = append(
[]autorest.PrepareDecorator{
autorest.AsContentType("application/json; charset=utf-8"),
autorest.AsPut(),
autorest.WithBaseURL(c.baseURI)},
decorators...)
return c.prepareRequest(ctx, decorators...)
}
// PreparePostRequest prepares post request
func (c *Client) PreparePostRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
decorators = append(
[]autorest.PrepareDecorator{
autorest.AsContentType("application/json; charset=utf-8"),
autorest.AsPost(),
autorest.WithBaseURL(c.baseURI)},
decorators...)
return c.prepareRequest(ctx, decorators...)
}
// PrepareGetRequest prepares get request
func (c *Client) PrepareGetRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
decorators = append(
[]autorest.PrepareDecorator{
autorest.AsGet(),
autorest.WithBaseURL(c.baseURI)},
decorators...)
return c.prepareRequest(ctx, decorators...)
}
// PrepareDeleteRequest preparse delete request
func (c *Client) PrepareDeleteRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
decorators = append(
[]autorest.PrepareDecorator{
autorest.AsDelete(),
autorest.WithBaseURL(c.baseURI)},
decorators...)
return c.prepareRequest(ctx, decorators...)
}
// PrepareHeadRequest prepares head request
func (c *Client) PrepareHeadRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
decorators = append(
[]autorest.PrepareDecorator{
autorest.AsHead(),
autorest.WithBaseURL(c.baseURI)},
decorators...)
return c.prepareRequest(ctx, decorators...)
}
// WaitForAsyncOperationCompletion waits for an operation completion
func (c *Client) WaitForAsyncOperationCompletion(ctx context.Context, future *azure.Future, asyncOperationName string) error {
err := future.WaitForCompletionRef(ctx, c.client)
if err != nil {
klog.V(5).Infof("Received error in WaitForCompletionRef: '%v'", err)
return err
}
var done bool
done, err = future.DoneWithContext(ctx, c.client)
if err != nil {
klog.V(5).Infof("Received error in DoneWithContext: '%v'", err)
return autorest.NewErrorWithError(err, asyncOperationName, "Result", future.Response(), "Polling failure")
}
if !done {
return azure.NewAsyncOpIncompleteError(asyncOperationName)
}
return nil
}
// WaitForAsyncOperationResult waits for an operation result.
func (c *Client) WaitForAsyncOperationResult(ctx context.Context, future *azure.Future, asyncOperationName string) (*http.Response, error) {
err := c.WaitForAsyncOperationCompletion(ctx, future, asyncOperationName)
if err != nil {
klog.V(5).Infof("Received error in WaitForAsyncOperationCompletion: '%v'", err)
return nil, err
}
sendBackoff := *c.backoff
sender := autorest.DecorateSender(
c.client,
retry.DoExponentialBackoffRetry(&sendBackoff),
)
return future.GetResult(sender)
}
// SendAsync send a request and return a future object representing the async result as well as the origin http response
func (c *Client) SendAsync(ctx context.Context, request *http.Request) (*azure.Future, *http.Response, *retry.Error) {
asyncResponse, rerr := c.Send(ctx, request)
if rerr != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "sendAsync.send", request.URL.String(), rerr.Error())
return nil, nil, rerr
}
future, err := azure.NewFutureFromResponse(asyncResponse)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "sendAsync.responed", request.URL.String(), err)
return nil, asyncResponse, retry.GetError(asyncResponse, err)
}
return &future, asyncResponse, nil
}
// GetResource get a resource by resource ID
func (c *Client) GetResource(ctx context.Context, resourceID, expand string) (*http.Response, *retry.Error) {
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters("{resourceID}", map[string]interface{}{"resourceID": resourceID}),
}
if expand != "" {
queryParameters := map[string]interface{}{
"$expand": autorest.Encode("query", expand),
}
decorators = append(decorators, autorest.WithQueryParameters(queryParameters))
}
request, err := c.PrepareGetRequest(ctx, decorators...)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "get.prepare", resourceID, err)
return nil, retry.NewError(false, err)
}
return c.Send(ctx, request)
}
// PutResource puts a resource by resource ID
func (c *Client) PutResource(ctx context.Context, resourceID string, parameters interface{}) (*http.Response, *retry.Error) {
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters("{resourceID}", map[string]interface{}{"resourceID": resourceID}),
autorest.WithJSON(parameters),
}
request, err := c.PreparePutRequest(ctx, decorators...)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "put.prepare", resourceID, err)
return nil, retry.NewError(false, err)
}
future, resp, clientErr := c.SendAsync(ctx, request)
defer c.CloseResponse(ctx, resp)
if clientErr != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "put.send", resourceID, clientErr.Error())
return nil, clientErr
}
response, err := c.WaitForAsyncOperationResult(ctx, future, "armclient.PutResource")
if err != nil {
if response != nil {
klog.V(5).Infof("Received error in WaitForAsyncOperationResult: '%s', response code %d", err.Error(), response.StatusCode)
} else {
klog.V(5).Infof("Received error in WaitForAsyncOperationResult: '%s', no response", err.Error())
}
retriableErr := retry.GetError(response, err)
if !retriableErr.Retriable &&
strings.Contains(strings.ToUpper(err.Error()), strings.ToUpper("InternalServerError")) {
klog.V(5).Infof("Received InternalServerError in WaitForAsyncOperationResult: '%s', setting error retriable", err.Error())
retriableErr.Retriable = true
}
return nil, retriableErr
}
return response, nil
}
// PutResourceAsync puts a resource by resource ID in async mode
func (c *Client) PutResourceAsync(ctx context.Context, resourceID string, parameters interface{}) (*azure.Future, *retry.Error) {
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters("{resourceID}", map[string]interface{}{"resourceID": resourceID}),
autorest.WithJSON(parameters),
}
request, err := c.PreparePutRequest(ctx, decorators...)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "put.prepare", resourceID, err)
return nil, retry.NewError(false, err)
}
future, resp, rErr := c.SendAsync(ctx, request)
defer c.CloseResponse(ctx, resp)
if rErr != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "put.send", resourceID, err)
return nil, rErr
}
return future, nil
}
// PostResource posts a resource by resource ID
func (c *Client) PostResource(ctx context.Context, resourceID, action string, parameters interface{}) (*http.Response, *retry.Error) {
pathParameters := map[string]interface{}{
"resourceID": resourceID,
"action": action,
}
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters("{resourceID}/{action}", pathParameters),
autorest.WithJSON(parameters),
}
request, err := c.PreparePostRequest(ctx, decorators...)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "post.prepare", resourceID, err)
return nil, retry.NewError(false, err)
}
return c.sendRequest(ctx, request)
}
// DeleteResource deletes a resource by resource ID
func (c *Client) DeleteResource(ctx context.Context, resourceID, ifMatch string) *retry.Error {
future, clientErr := c.DeleteResourceAsync(ctx, resourceID, ifMatch)
if clientErr != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "delete.request", resourceID, clientErr.Error())
return clientErr
}
if future == nil {
return nil
}
if err := c.WaitForAsyncOperationCompletion(ctx, future, "armclient.DeleteResource"); err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "delete.wait", resourceID, clientErr.Error())
return retry.NewError(true, err)
}
return nil
}
// HeadResource heads a resource by resource ID
func (c *Client) HeadResource(ctx context.Context, resourceID string) (*http.Response, *retry.Error) {
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters("{resourceID}", map[string]interface{}{"resourceID": resourceID}),
}
request, err := c.PrepareHeadRequest(ctx, decorators...)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "head.prepare", resourceID, err)
return nil, retry.NewError(false, err)
}
return c.sendRequest(ctx, request)
}
// DeleteResourceAsync delete a resource by resource ID and returns a future representing the async result
func (c *Client) DeleteResourceAsync(ctx context.Context, resourceID, ifMatch string) (*azure.Future, *retry.Error) {
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters("{resourceID}", map[string]interface{}{"resourceID": resourceID}),
}
if len(ifMatch) > 0 {
decorators = append(decorators, autorest.WithHeader("If-Match", autorest.String(ifMatch)))
}
deleteRequest, err := c.PrepareDeleteRequest(ctx, decorators...)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "deleteAsync.prepare", resourceID, err)
return nil, retry.NewError(false, err)
}
resp, rerr := c.sendRequest(ctx, deleteRequest)
defer c.CloseResponse(ctx, resp)
if rerr != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "deleteAsync.send", resourceID, rerr.Error())
return nil, rerr
}
err = autorest.Respond(
resp,
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusNotFound))
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "deleteAsync.respond", resourceID, err)
return nil, retry.GetError(resp, err)
}
if resp.StatusCode == http.StatusNotFound {
return nil, nil
}
future, err := azure.NewFutureFromResponse(resp)
if err != nil {
klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "deleteAsync.future", resourceID, err)
return nil, retry.GetError(resp, err)
}
return &future, nil
}
// CloseResponse closes a response
func (c *Client) CloseResponse(ctx context.Context, response *http.Response) {
if response != nil && response.Body != nil {
if err := response.Body.Close(); err != nil {
klog.Errorf("Error closing the response body: %v", err)
}
}
}
func (c *Client) prepareRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
decorators = append(
decorators,
withAPIVersion(c.apiVersion))
preparer := autorest.CreatePreparer(decorators...)
return preparer.Prepare((&http.Request{}).WithContext(ctx))
}
func withAPIVersion(apiVersion string) autorest.PrepareDecorator {
const apiVersionKey = "api-version"
return func(p autorest.Preparer) autorest.Preparer {
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
r, err := p.Prepare(r)
if err == nil {
if r.URL == nil {
return r, fmt.Errorf("Error in withAPIVersion: Invoked with a nil URL")
}
v := r.URL.Query()
if len(v.Get(apiVersionKey)) > 0 {
return r, nil
}
v.Add(apiVersionKey, apiVersion)
r.URL.RawQuery = v.Encode()
}
return r, err
})
}
}
// GetResourceID gets Azure resource ID
func GetResourceID(subscriptionID, resourceGroupName, resourceType, resourceName string) string {
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s",
autorest.Encode("path", subscriptionID),
autorest.Encode("path", resourceGroupName),
resourceType,
autorest.Encode("path", resourceName))
}
// GetChildResourceID gets Azure child resource ID
func GetChildResourceID(subscriptionID, resourceGroupName, resourceType, resourceName, childResourceType, childResourceName string) string {
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s/%s/%s",
autorest.Encode("path", subscriptionID),
autorest.Encode("path", resourceGroupName),
resourceType,
autorest.Encode("path", resourceName),
childResourceType,
autorest.Encode("path", childResourceName))
}
// GetChildResourcesListID gets Azure child resources list ID
func GetChildResourcesListID(subscriptionID, resourceGroupName, resourceType, resourceName, childResourceType string) string {
return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s/%s",
autorest.Encode("path", subscriptionID),
autorest.Encode("path", resourceGroupName),
resourceType,
autorest.Encode("path", resourceName),
childResourceType)
}
// GetProviderResourceID gets Azure RP resource ID
func GetProviderResourceID(subscriptionID, providerNamespace string) string {
return fmt.Sprintf("/subscriptions/%s/providers/%s",
autorest.Encode("path", subscriptionID),
providerNamespace)
}
// GetProviderResourcesListID gets Azure RP resources list ID
func GetProviderResourcesListID(subscriptionID string) string {
return fmt.Sprintf("/subscriptions/%s/providers", autorest.Encode("path", subscriptionID))
}

View File

@ -0,0 +1,253 @@
// +build !providerless
/*
Copyright 2019 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 armclient
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/Azure/go-autorest/autorest"
"github.com/stretchr/testify/assert"
"k8s.io/legacy-cloud-providers/azure/retry"
)
func TestSend(t *testing.T) {
count := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if count <= 1 {
http.Error(w, "failed", http.StatusInternalServerError)
count++
}
}))
backoff := &retry.Backoff{Steps: 3}
armClient := New(nil, server.URL, "test", "2019-01-01", "eastus", backoff)
pathParameters := map[string]interface{}{
"resourceGroupName": autorest.Encode("path", "testgroup"),
"subscriptionId": autorest.Encode("path", "testid"),
"resourceName": autorest.Encode("path", "testname"),
}
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters(
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/vNets/{resourceName}", pathParameters),
}
ctx := context.Background()
request, err := armClient.PrepareGetRequest(ctx, decorators...)
assert.NoError(t, err)
response, rerr := armClient.Send(ctx, request)
assert.Nil(t, rerr)
assert.Equal(t, 2, count)
assert.Equal(t, http.StatusOK, response.StatusCode)
}
func TestSendFailure(t *testing.T) {
count := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "failed", http.StatusInternalServerError)
count++
}))
backoff := &retry.Backoff{Steps: 3}
armClient := New(nil, server.URL, "test", "2019-01-01", "eastus", backoff)
pathParameters := map[string]interface{}{
"resourceGroupName": autorest.Encode("path", "testgroup"),
"subscriptionId": autorest.Encode("path", "testid"),
"resourceName": autorest.Encode("path", "testname"),
}
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters(
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/vNets/{resourceName}", pathParameters),
}
ctx := context.Background()
request, err := armClient.PrepareGetRequest(ctx, decorators...)
assert.NoError(t, err)
response, rerr := armClient.Send(ctx, request)
assert.NotNil(t, rerr)
assert.Equal(t, 3, count)
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
}
func TestSendThrottled(t *testing.T) {
count := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(retry.RetryAfterHeaderKey, "30")
http.Error(w, "failed", http.StatusTooManyRequests)
count++
}))
backoff := &retry.Backoff{Steps: 3}
armClient := New(nil, server.URL, "test", "2019-01-01", "eastus", backoff)
pathParameters := map[string]interface{}{
"resourceGroupName": autorest.Encode("path", "testgroup"),
"subscriptionId": autorest.Encode("path", "testid"),
"resourceName": autorest.Encode("path", "testname"),
}
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters(
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/vNets/{resourceName}", pathParameters),
}
ctx := context.Background()
request, err := armClient.PrepareGetRequest(ctx, decorators...)
assert.NoError(t, err)
response, rerr := armClient.Send(ctx, request)
assert.NotNil(t, rerr)
assert.Equal(t, 1, count)
assert.Equal(t, http.StatusTooManyRequests, response.StatusCode)
}
func TestSendAsync(t *testing.T) {
count := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
http.Error(w, "failed", http.StatusForbidden)
}))
backoff := &retry.Backoff{Steps: 1}
armClient := New(nil, server.URL, "test", "2019-01-01", "eastus", backoff)
armClient.client.RetryDuration = time.Millisecond * 1
pathParameters := map[string]interface{}{
"resourceGroupName": autorest.Encode("path", "testgroup"),
"subscriptionId": autorest.Encode("path", "testid"),
"resourceName": autorest.Encode("path", "testname"),
}
decorators := []autorest.PrepareDecorator{
autorest.WithPathParameters(
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/vNets/{resourceName}", pathParameters),
}
ctx := context.Background()
request, err := armClient.PreparePutRequest(ctx, decorators...)
assert.NoError(t, err)
future, response, rerr := armClient.SendAsync(ctx, request)
assert.Nil(t, future)
assert.Nil(t, response)
assert.Equal(t, 1, count)
assert.NotNil(t, rerr)
assert.Equal(t, true, rerr.Retriable)
}
func TestNormalizeAzureRegion(t *testing.T) {
tests := []struct {
region string
expected string
}{
{
region: "eastus",
expected: "eastus",
},
{
region: " eastus ",
expected: "eastus",
},
{
region: " eastus\t",
expected: "eastus",
},
{
region: " eastus\v",
expected: "eastus",
},
{
region: " eastus\v\r\f\n",
expected: "eastus",
},
}
for i, test := range tests {
real := NormalizeAzureRegion(test.region)
assert.Equal(t, test.expected, real, "test[%d]: NormalizeAzureRegion(%q) != %q", i, test.region, test.expected)
}
}
func TestPutResource(t *testing.T) {
expectedURI := "/subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/testPIP?api-version=2019-01-01"
operationURI := "/subscriptions/subscription/providers/Microsoft.Network/locations/eastus/operations/op?api-version=2019-01-01"
handlers := []func(http.ResponseWriter, *http.Request){
func(rw http.ResponseWriter, req *http.Request) {
assert.Equal(t, "PUT", req.Method)
assert.Equal(t, expectedURI, req.URL.String())
rw.Header().Set(http.CanonicalHeaderKey("Azure-AsyncOperation"),
fmt.Sprintf("http://%s%s", req.Host, operationURI))
rw.WriteHeader(http.StatusCreated)
},
func(rw http.ResponseWriter, req *http.Request) {
assert.Equal(t, "GET", req.Method)
assert.Equal(t, operationURI, req.URL.String())
rw.WriteHeader(http.StatusOK)
rw.Write([]byte(`{"error":{"code":"InternalServerError"},"status":"Failed"}`))
},
}
count := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handlers[count](w, r)
count++
if count > 1 {
count = 1
}
}))
backoff := &retry.Backoff{Steps: 1}
armClient := New(nil, server.URL, "test", "2019-01-01", "eastus", backoff)
armClient.client.RetryDuration = time.Millisecond * 1
ctx := context.Background()
response, rerr := armClient.PutResource(ctx, "/subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/testPIP", nil)
assert.Equal(t, 1, count)
assert.Nil(t, response)
assert.NotNil(t, rerr)
assert.Equal(t, true, rerr.Retriable)
}
func TestDeleteResourceAsync(t *testing.T) {
count := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
http.Error(w, "failed", http.StatusForbidden)
}))
backoff := &retry.Backoff{Steps: 3}
armClient := New(nil, server.URL, "test", "2019-01-01", "eastus", backoff)
armClient.client.RetryDuration = time.Millisecond * 1
ctx := context.Background()
resourceID := "/subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/testPIP"
future, rerr := armClient.DeleteResourceAsync(ctx, resourceID, "")
assert.Equal(t, 3, count)
assert.Nil(t, future)
assert.NotNil(t, rerr)
assert.Equal(t, true, rerr.Retriable)
}

View File

@ -0,0 +1,20 @@
// +build !providerless
/*
Copyright 2019 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 armclient implements the client for ARM.
package armclient // import "k8s.io/legacy-cloud-providers/azure/clients/armclient"

View File

@ -0,0 +1,84 @@
// +build !providerless
/*
Copyright 2019 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 armclient
import (
"context"
"net/http"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
"k8s.io/legacy-cloud-providers/azure/retry"
)
// Interface is the client interface for ARM.
// 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/armclient/interface.go -package=mockarmclient Interface > $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient/interface.go
type Interface interface {
// Send sends a http request to ARM service with possible retry to regional ARM endpoint.
Send(ctx context.Context, request *http.Request) (*http.Response, *retry.Error)
// PreparePutRequest prepares put request
PreparePutRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error)
// PreparePostRequest prepares post request
PreparePostRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error)
// PrepareGetRequest prepares get request
PrepareGetRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error)
// PrepareDeleteRequest preparse delete request
PrepareDeleteRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error)
// PrepareHeadRequest prepares head request
PrepareHeadRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error)
// WaitForAsyncOperationCompletion waits for an operation completion
WaitForAsyncOperationCompletion(ctx context.Context, future *azure.Future, asyncOperationName string) error
// WaitForAsyncOperationResult waits for an operation result.
WaitForAsyncOperationResult(ctx context.Context, future *azure.Future, asyncOperationName string) (*http.Response, error)
// SendAsync send a request and return a future object representing the async result as well as the origin http response
SendAsync(ctx context.Context, request *http.Request) (*azure.Future, *http.Response, *retry.Error)
// PutResource puts a resource by resource ID
PutResource(ctx context.Context, resourceID string, parameters interface{}) (*http.Response, *retry.Error)
// PutResourceAsync puts a resource by resource ID in async mode
PutResourceAsync(ctx context.Context, resourceID string, parameters interface{}) (*azure.Future, *retry.Error)
// HeadResource heads a resource by resource ID
HeadResource(ctx context.Context, resourceID string) (*http.Response, *retry.Error)
// GetResource get a resource by resource ID
GetResource(ctx context.Context, resourceID, expand string) (*http.Response, *retry.Error)
// PostResource posts a resource by resource ID
PostResource(ctx context.Context, resourceID, action string, parameters interface{}) (*http.Response, *retry.Error)
// DeleteResource deletes a resource by resource ID
DeleteResource(ctx context.Context, resourceID, ifMatch string) *retry.Error
// DeleteResourceAsync delete a resource by resource ID and returns a future representing the async result
DeleteResourceAsync(ctx context.Context, resourceID, ifMatch string) (*azure.Future, *retry.Error)
// CloseResponse closes a response
CloseResponse(ctx context.Context, response *http.Response)
}

View File

@ -0,0 +1,32 @@
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/armclient/mockarmclient",
importpath = "k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/legacy-cloud-providers/azure/retry: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/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"],
)

View File

@ -0,0 +1,20 @@
// +build !providerless
/*
Copyright 2019 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 mockarmclient implements the mock client for ARM.
package mockarmclient // import "k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient"

View File

@ -0,0 +1,329 @@
// +build !providerless
/*
Copyright 2019 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 mockarmclient
import (
context "context"
http "net/http"
reflect "reflect"
autorest "github.com/Azure/go-autorest/autorest"
azure "github.com/Azure/go-autorest/autorest/azure"
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
}
// Send mocks base method
func (m *MockInterface) Send(ctx context.Context, request *http.Request) (*http.Response, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Send", ctx, request)
ret0, _ := ret[0].(*http.Response)
ret1, _ := ret[1].(*retry.Error)
return ret0, ret1
}
// Send indicates an expected call of Send
func (mr *MockInterfaceMockRecorder) Send(ctx, request interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockInterface)(nil).Send), ctx, request)
}
// PreparePutRequest mocks base method
func (m *MockInterface) PreparePutRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
m.ctrl.T.Helper()
varargs := []interface{}{ctx}
for _, a := range decorators {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "PreparePutRequest", varargs...)
ret0, _ := ret[0].(*http.Request)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PreparePutRequest indicates an expected call of PreparePutRequest
func (mr *MockInterfaceMockRecorder) PreparePutRequest(ctx interface{}, decorators ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx}, decorators...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreparePutRequest", reflect.TypeOf((*MockInterface)(nil).PreparePutRequest), varargs...)
}
// PreparePostRequest mocks base method
func (m *MockInterface) PreparePostRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
m.ctrl.T.Helper()
varargs := []interface{}{ctx}
for _, a := range decorators {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "PreparePostRequest", varargs...)
ret0, _ := ret[0].(*http.Request)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PreparePostRequest indicates an expected call of PreparePostRequest
func (mr *MockInterfaceMockRecorder) PreparePostRequest(ctx interface{}, decorators ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx}, decorators...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreparePostRequest", reflect.TypeOf((*MockInterface)(nil).PreparePostRequest), varargs...)
}
// PrepareGetRequest mocks base method
func (m *MockInterface) PrepareGetRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
m.ctrl.T.Helper()
varargs := []interface{}{ctx}
for _, a := range decorators {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "PrepareGetRequest", varargs...)
ret0, _ := ret[0].(*http.Request)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PrepareGetRequest indicates an expected call of PrepareGetRequest
func (mr *MockInterfaceMockRecorder) PrepareGetRequest(ctx interface{}, decorators ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx}, decorators...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareGetRequest", reflect.TypeOf((*MockInterface)(nil).PrepareGetRequest), varargs...)
}
// PrepareDeleteRequest mocks base method
func (m *MockInterface) PrepareDeleteRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
m.ctrl.T.Helper()
varargs := []interface{}{ctx}
for _, a := range decorators {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "PrepareDeleteRequest", varargs...)
ret0, _ := ret[0].(*http.Request)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PrepareDeleteRequest indicates an expected call of PrepareDeleteRequest
func (mr *MockInterfaceMockRecorder) PrepareDeleteRequest(ctx interface{}, decorators ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx}, decorators...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareDeleteRequest", reflect.TypeOf((*MockInterface)(nil).PrepareDeleteRequest), varargs...)
}
// PrepareHeadRequest mocks base method
func (m *MockInterface) PrepareHeadRequest(ctx context.Context, decorators ...autorest.PrepareDecorator) (*http.Request, error) {
m.ctrl.T.Helper()
varargs := []interface{}{ctx}
for _, a := range decorators {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "PrepareHeadRequest", varargs...)
ret0, _ := ret[0].(*http.Request)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PrepareHeadRequest indicates an expected call of PrepareHeadRequest
func (mr *MockInterfaceMockRecorder) PrepareHeadRequest(ctx interface{}, decorators ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx}, decorators...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareHeadRequest", reflect.TypeOf((*MockInterface)(nil).PrepareHeadRequest), varargs...)
}
// WaitForAsyncOperationCompletion mocks base method
func (m *MockInterface) WaitForAsyncOperationCompletion(ctx context.Context, future *azure.Future, asyncOperationName string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "WaitForAsyncOperationCompletion", ctx, future, asyncOperationName)
ret0, _ := ret[0].(error)
return ret0
}
// WaitForAsyncOperationCompletion indicates an expected call of WaitForAsyncOperationCompletion
func (mr *MockInterfaceMockRecorder) WaitForAsyncOperationCompletion(ctx, future, asyncOperationName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForAsyncOperationCompletion", reflect.TypeOf((*MockInterface)(nil).WaitForAsyncOperationCompletion), ctx, future, asyncOperationName)
}
// WaitForAsyncOperationResult mocks base method
func (m *MockInterface) WaitForAsyncOperationResult(ctx context.Context, future *azure.Future, asyncOperationName string) (*http.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "WaitForAsyncOperationResult", ctx, future, asyncOperationName)
ret0, _ := ret[0].(*http.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// WaitForAsyncOperationResult indicates an expected call of WaitForAsyncOperationResult
func (mr *MockInterfaceMockRecorder) WaitForAsyncOperationResult(ctx, future, asyncOperationName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForAsyncOperationResult", reflect.TypeOf((*MockInterface)(nil).WaitForAsyncOperationResult), ctx, future, asyncOperationName)
}
// SendAsync mocks base method
func (m *MockInterface) SendAsync(ctx context.Context, request *http.Request) (*azure.Future, *http.Response, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendAsync", ctx, request)
ret0, _ := ret[0].(*azure.Future)
ret1, _ := ret[1].(*http.Response)
ret2, _ := ret[2].(*retry.Error)
return ret0, ret1, ret2
}
// SendAsync indicates an expected call of SendAsync
func (mr *MockInterfaceMockRecorder) SendAsync(ctx, request interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockInterface)(nil).SendAsync), ctx, request)
}
// PutResource mocks base method
func (m *MockInterface) PutResource(ctx context.Context, resourceID string, parameters interface{}) (*http.Response, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PutResource", ctx, resourceID, parameters)
ret0, _ := ret[0].(*http.Response)
ret1, _ := ret[1].(*retry.Error)
return ret0, ret1
}
// PutResource indicates an expected call of PutResource
func (mr *MockInterfaceMockRecorder) PutResource(ctx, resourceID, parameters interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutResource", reflect.TypeOf((*MockInterface)(nil).PutResource), ctx, resourceID, parameters)
}
// PutResourceAsync mocks base method
func (m *MockInterface) PutResourceAsync(ctx context.Context, resourceID string, parameters interface{}) (*azure.Future, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PutResourceAsync", ctx, resourceID, parameters)
ret0, _ := ret[0].(*azure.Future)
ret1, _ := ret[1].(*retry.Error)
return ret0, ret1
}
// PutResourceAsync indicates an expected call of PutResourceAsync
func (mr *MockInterfaceMockRecorder) PutResourceAsync(ctx, resourceID, parameters interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutResourceAsync", reflect.TypeOf((*MockInterface)(nil).PutResourceAsync), ctx, resourceID, parameters)
}
// HeadResource mocks base method
func (m *MockInterface) HeadResource(ctx context.Context, resourceID string) (*http.Response, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HeadResource", ctx, resourceID)
ret0, _ := ret[0].(*http.Response)
ret1, _ := ret[1].(*retry.Error)
return ret0, ret1
}
// HeadResource indicates an expected call of HeadResource
func (mr *MockInterfaceMockRecorder) HeadResource(ctx, resourceID interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadResource", reflect.TypeOf((*MockInterface)(nil).HeadResource), ctx, resourceID)
}
// GetResource mocks base method
func (m *MockInterface) GetResource(ctx context.Context, resourceID, expand string) (*http.Response, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetResource", ctx, resourceID, expand)
ret0, _ := ret[0].(*http.Response)
ret1, _ := ret[1].(*retry.Error)
return ret0, ret1
}
// GetResource indicates an expected call of GetResource
func (mr *MockInterfaceMockRecorder) GetResource(ctx, resourceID, expand interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResource", reflect.TypeOf((*MockInterface)(nil).GetResource), ctx, resourceID, expand)
}
// PostResource mocks base method
func (m *MockInterface) PostResource(ctx context.Context, resourceID, action string, parameters interface{}) (*http.Response, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PostResource", ctx, resourceID, action, parameters)
ret0, _ := ret[0].(*http.Response)
ret1, _ := ret[1].(*retry.Error)
return ret0, ret1
}
// PostResource indicates an expected call of PostResource
func (mr *MockInterfaceMockRecorder) PostResource(ctx, resourceID, action, parameters interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostResource", reflect.TypeOf((*MockInterface)(nil).PostResource), ctx, resourceID, action, parameters)
}
// DeleteResource mocks base method
func (m *MockInterface) DeleteResource(ctx context.Context, resourceID, ifMatch string) *retry.Error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteResource", ctx, resourceID, ifMatch)
ret0, _ := ret[0].(*retry.Error)
return ret0
}
// DeleteResource indicates an expected call of DeleteResource
func (mr *MockInterfaceMockRecorder) DeleteResource(ctx, resourceID, ifMatch interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteResource", reflect.TypeOf((*MockInterface)(nil).DeleteResource), ctx, resourceID, ifMatch)
}
// DeleteResourceAsync mocks base method
func (m *MockInterface) DeleteResourceAsync(ctx context.Context, resourceID, ifMatch string) (*azure.Future, *retry.Error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteResourceAsync", ctx, resourceID, ifMatch)
ret0, _ := ret[0].(*azure.Future)
ret1, _ := ret[1].(*retry.Error)
return ret0, ret1
}
// DeleteResourceAsync indicates an expected call of DeleteResourceAsync
func (mr *MockInterfaceMockRecorder) DeleteResourceAsync(ctx, resourceID, ifMatch interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteResourceAsync", reflect.TypeOf((*MockInterface)(nil).DeleteResourceAsync), ctx, resourceID, ifMatch)
}
// CloseResponse mocks base method
func (m *MockInterface) CloseResponse(ctx context.Context, response *http.Response) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "CloseResponse", ctx, response)
}
// CloseResponse indicates an expected call of CloseResponse
func (mr *MockInterfaceMockRecorder) CloseResponse(ctx, response interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseResponse", reflect.TypeOf((*MockInterface)(nil).CloseResponse), ctx, response)
}