13964: Detect and report rate limit and quota exceeded errors
[arvados.git] / lib / dispatchcloud / azure_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package dispatchcloud
6
7 import (
8         "context"
9         "flag"
10         "log"
11         "net/http"
12
13         "git.curoverse.com/arvados.git/sdk/go/arvados"
14         "git.curoverse.com/arvados.git/sdk/go/config"
15         "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-06-01/compute"
16         "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
17         "github.com/Azure/go-autorest/autorest"
18         "github.com/Azure/go-autorest/autorest/azure"
19         "github.com/Azure/go-autorest/autorest/to"
20         check "gopkg.in/check.v1"
21 )
22
23 type AzureProviderSuite struct{}
24
25 var _ = check.Suite(&AzureProviderSuite{})
26
27 type VirtualMachinesClientStub struct{}
28
29 func (*VirtualMachinesClientStub) CreateOrUpdate(ctx context.Context,
30         resourceGroupName string,
31         VMName string,
32         parameters compute.VirtualMachine) (result compute.VirtualMachine, err error) {
33         parameters.ID = &VMName
34         return parameters, nil
35 }
36
37 func (*VirtualMachinesClientStub) Delete(ctx context.Context, resourceGroupName string, VMName string) (result *http.Response, err error) {
38         return nil, nil
39 }
40
41 func (*VirtualMachinesClientStub) ListComplete(ctx context.Context, resourceGroupName string) (result compute.VirtualMachineListResultIterator, err error) {
42         return compute.VirtualMachineListResultIterator{}, nil
43 }
44
45 type InterfacesClientStub struct{}
46
47 func (*InterfacesClientStub) CreateOrUpdate(ctx context.Context,
48         resourceGroupName string,
49         nicName string,
50         parameters network.Interface) (result network.Interface, err error) {
51         parameters.ID = to.StringPtr(nicName)
52         (*parameters.IPConfigurations)[0].PrivateIPAddress = to.StringPtr("192.168.5.5")
53         return parameters, nil
54 }
55
56 func (*InterfacesClientStub) Delete(ctx context.Context, resourceGroupName string, VMName string) (result *http.Response, err error) {
57         return nil, nil
58 }
59
60 func (*InterfacesClientStub) ListComplete(ctx context.Context, resourceGroupName string) (result network.InterfaceListResultIterator, err error) {
61         return network.InterfaceListResultIterator{}, nil
62 }
63
64 var live = flag.String("live-azure-cfg", "", "Test with real azure API, provide config file")
65
66 func GetProvider() (Provider, ImageID, arvados.Cluster, error) {
67         cluster := arvados.Cluster{
68                 InstanceTypes: arvados.InstanceTypeMap(map[string]arvados.InstanceType{
69                         "tiny": arvados.InstanceType{
70                                 Name:         "tiny",
71                                 ProviderType: "Standard_D1_v2",
72                                 VCPUs:        1,
73                                 RAM:          4000000000,
74                                 Scratch:      10000000000,
75                                 Price:        .02,
76                                 Preemptible:  false,
77                         },
78                 })}
79         if *live != "" {
80                 cfg := AzureProviderConfig{}
81                 err := config.LoadFile(&cfg, *live)
82                 if err != nil {
83                         return nil, ImageID(""), cluster, err
84                 }
85                 ap, err := NewAzureProvider(cfg, cluster)
86                 return ap, ImageID(cfg.Image), cluster, err
87         } else {
88                 ap := AzureProvider{
89                         azconfig: AzureProviderConfig{
90                                 BlobContainer: "vhds",
91                         },
92                         arvconfig: cluster,
93                 }
94                 ap.vmClient = &VirtualMachinesClientStub{}
95                 ap.netClient = &InterfacesClientStub{}
96                 return &ap, ImageID("blob"), cluster, nil
97         }
98 }
99
100 func (*AzureProviderSuite) TestCreate(c *check.C) {
101         ap, img, cluster, err := GetProvider()
102         if err != nil {
103                 c.Fatal("Error making provider", err)
104         }
105
106         inst, err := ap.Create(context.Background(),
107                 cluster.InstanceTypes["tiny"],
108                 img, []InstanceTag{"tag1"})
109
110         c.Assert(err, check.IsNil)
111
112         log.Printf("Result %v %v", inst.String(), inst.Address())
113 }
114
115 func (*AzureProviderSuite) TestListInstances(c *check.C) {
116         ap, _, _, err := GetProvider()
117         if err != nil {
118                 c.Fatal("Error making provider", err)
119         }
120
121         l, err := ap.Instances(context.Background())
122
123         c.Assert(err, check.IsNil)
124
125         for _, i := range l {
126                 log.Printf("%v %v %v", i.String(), i.Address(), i.InstanceType())
127         }
128 }
129
130 func (*AzureProviderSuite) TestManageNics(c *check.C) {
131         ap, _, _, err := GetProvider()
132         if err != nil {
133                 c.Fatal("Error making provider", err)
134         }
135
136         ap.(*AzureProvider).ManageNics(context.Background())
137 }
138
139 func (*AzureProviderSuite) TestManageBlobs(c *check.C) {
140         ap, _, _, err := GetProvider()
141         if err != nil {
142                 c.Fatal("Error making provider", err)
143         }
144
145         ap.(*AzureProvider).ManageBlobs(context.Background())
146 }
147
148 func (*AzureProviderSuite) TestDestroyInstances(c *check.C) {
149         ap, _, _, err := GetProvider()
150         if err != nil {
151                 c.Fatal("Error making provider", err)
152         }
153
154         l, err := ap.Instances(context.Background())
155         c.Assert(err, check.IsNil)
156
157         for _, i := range l {
158                 c.Check(i.Destroy(context.Background()), check.IsNil)
159         }
160 }
161
162 func (*AzureProviderSuite) TestDeleteFake(c *check.C) {
163         ap, _, _, err := GetProvider()
164         if err != nil {
165                 c.Fatal("Error making provider", err)
166         }
167
168         _, err = ap.(*AzureProvider).netClient.Delete(context.Background(), "fakefakefake", "fakefakefake")
169
170         rq := err.(autorest.DetailedError).Original.(*azure.RequestError)
171
172         log.Printf("%v %q %q", rq.Response.StatusCode, rq.ServiceError.Code, rq.ServiceError.Message)
173 }
174
175 func (*AzureProviderSuite) TestWrapError(c *check.C) {
176         retryError := autorest.DetailedError{
177                 Original: &azure.RequestError{
178                         DetailedError: autorest.DetailedError{
179                                 Response: &http.Response{
180                                         StatusCode: 429,
181                                         Header:     map[string][]string{"Retry-After": []string{"123"}},
182                                 },
183                         },
184                         ServiceError: &azure.ServiceError{},
185                 },
186         }
187         wrapped := WrapAzureError(retryError)
188         _, ok := wrapped.(RateLimitError)
189         c.Check(ok, check.Equals, true)
190
191         quotaError := autorest.DetailedError{
192                 Original: &azure.RequestError{
193                         DetailedError: autorest.DetailedError{
194                                 Response: &http.Response{
195                                         StatusCode: 503,
196                                 },
197                         },
198                         ServiceError: &azure.ServiceError{
199                                 Message: "No more quota",
200                         },
201                 },
202         }
203         wrapped = WrapAzureError(quotaError)
204         _, ok = wrapped.(QuotaError)
205         c.Check(ok, check.Equals, true)
206 }