mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-17 15:50:10 +00:00
Addd Azure ARM client with backoff retries
This commit is contained in:
parent
09cb73a554
commit
9d67227fb4
@ -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"],
|
||||
)
|
@ -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))
|
||||
}
|
@ -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)
|
||||
}
|
@ -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"
|
@ -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)
|
||||
}
|
@ -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"],
|
||||
)
|
@ -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"
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user