1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
18 "git.curoverse.com/arvados.git/sdk/go/arvados"
19 "git.curoverse.com/arvados.git/sdk/go/config"
20 "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-06-01/compute"
21 "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
22 "github.com/Azure/go-autorest/autorest"
23 "github.com/Azure/go-autorest/autorest/azure"
24 "github.com/Azure/go-autorest/autorest/to"
25 "golang.org/x/crypto/ssh"
26 check "gopkg.in/check.v1"
29 type AzureProviderSuite struct{}
31 var _ = check.Suite(&AzureProviderSuite{})
33 type VirtualMachinesClientStub struct{}
35 func (*VirtualMachinesClientStub) CreateOrUpdate(ctx context.Context,
36 resourceGroupName string,
38 parameters compute.VirtualMachine) (result compute.VirtualMachine, err error) {
39 parameters.ID = &VMName
40 parameters.Name = &VMName
41 return parameters, nil
44 func (*VirtualMachinesClientStub) Delete(ctx context.Context, resourceGroupName string, VMName string) (result *http.Response, err error) {
48 func (*VirtualMachinesClientStub) ListComplete(ctx context.Context, resourceGroupName string) (result compute.VirtualMachineListResultIterator, err error) {
49 return compute.VirtualMachineListResultIterator{}, nil
52 type InterfacesClientStub struct{}
54 func (*InterfacesClientStub) CreateOrUpdate(ctx context.Context,
55 resourceGroupName string,
57 parameters network.Interface) (result network.Interface, err error) {
58 parameters.ID = to.StringPtr(nicName)
59 (*parameters.IPConfigurations)[0].PrivateIPAddress = to.StringPtr("192.168.5.5")
60 return parameters, nil
63 func (*InterfacesClientStub) Delete(ctx context.Context, resourceGroupName string, VMName string) (result *http.Response, err error) {
67 func (*InterfacesClientStub) ListComplete(ctx context.Context, resourceGroupName string) (result network.InterfaceListResultIterator, err error) {
68 return network.InterfaceListResultIterator{}, nil
71 var live = flag.String("live-azure-cfg", "", "Test with real azure API, provide config file")
73 func GetProvider() (InstanceProvider, ImageID, arvados.Cluster, error) {
74 cluster := arvados.Cluster{
75 InstanceTypes: arvados.InstanceTypeMap(map[string]arvados.InstanceType{
76 "tiny": arvados.InstanceType{
78 ProviderType: "Standard_D1_v2",
87 cfg := AzureProviderConfig{}
88 err := config.LoadFile(&cfg, *live)
90 return nil, ImageID(""), cluster, err
92 ap, err := NewAzureProvider(cfg, "test123")
93 return ap, ImageID(cfg.Image), cluster, err
96 azconfig: AzureProviderConfig{
97 BlobContainer: "vhds",
99 dispatcherID: "test123",
100 namePrefix: "compute-test123-",
102 ap.vmClient = &VirtualMachinesClientStub{}
103 ap.netClient = &InterfacesClientStub{}
104 return &ap, ImageID("blob"), cluster, nil
108 func (*AzureProviderSuite) TestCreate(c *check.C) {
109 ap, img, cluster, err := GetProvider()
111 c.Fatal("Error making provider", err)
114 f, err := os.Open("azconfig_sshkey.pub")
115 c.Assert(err, check.IsNil)
117 keybytes, err := ioutil.ReadAll(f)
118 c.Assert(err, check.IsNil)
120 pk, _, _, _, err := ssh.ParseAuthorizedKey(keybytes)
121 c.Assert(err, check.IsNil)
123 inst, err := ap.Create(context.Background(),
124 cluster.InstanceTypes["tiny"],
125 img, map[string]string{"tag1": "bleep"},
128 c.Assert(err, check.IsNil)
130 log.Printf("Result %v %v", inst.String(), inst.Address())
134 func (*AzureProviderSuite) TestListInstances(c *check.C) {
135 ap, _, _, err := GetProvider()
137 c.Fatal("Error making provider", err)
140 l, err := ap.Instances(context.Background())
142 c.Assert(err, check.IsNil)
144 for _, i := range l {
145 tg, _ := i.Tags(context.Background())
146 log.Printf("%v %v %v", i.String(), i.Address(), tg)
150 func (*AzureProviderSuite) TestManageNics(c *check.C) {
151 ap, _, _, err := GetProvider()
153 c.Fatal("Error making provider", err)
156 ap.(*AzureProvider).ManageNics(context.Background())
159 func (*AzureProviderSuite) TestManageBlobs(c *check.C) {
160 ap, _, _, err := GetProvider()
162 c.Fatal("Error making provider", err)
165 ap.(*AzureProvider).ManageBlobs(context.Background())
168 func (*AzureProviderSuite) TestDestroyInstances(c *check.C) {
169 ap, _, _, err := GetProvider()
171 c.Fatal("Error making provider", err)
174 l, err := ap.Instances(context.Background())
175 c.Assert(err, check.IsNil)
177 for _, i := range l {
178 c.Check(i.Destroy(context.Background()), check.IsNil)
182 func (*AzureProviderSuite) TestDeleteFake(c *check.C) {
183 ap, _, _, err := GetProvider()
185 c.Fatal("Error making provider", err)
188 _, err = ap.(*AzureProvider).netClient.Delete(context.Background(), "fakefakefake", "fakefakefake")
190 de, ok := err.(autorest.DetailedError)
192 rq := de.Original.(*azure.RequestError)
194 log.Printf("%v %q %q", rq.Response.StatusCode, rq.ServiceError.Code, rq.ServiceError.Message)
198 func (*AzureProviderSuite) TestWrapError(c *check.C) {
199 retryError := autorest.DetailedError{
200 Original: &azure.RequestError{
201 DetailedError: autorest.DetailedError{
202 Response: &http.Response{
204 Header: map[string][]string{"Retry-After": []string{"123"}},
207 ServiceError: &azure.ServiceError{},
210 wrapped := WrapAzureError(retryError)
211 _, ok := wrapped.(RateLimitError)
212 c.Check(ok, check.Equals, true)
214 quotaError := autorest.DetailedError{
215 Original: &azure.RequestError{
216 DetailedError: autorest.DetailedError{
217 Response: &http.Response{
221 ServiceError: &azure.ServiceError{
222 Message: "No more quota",
226 wrapped = WrapAzureError(quotaError)
227 _, ok = wrapped.(QuotaError)
228 c.Check(ok, check.Equals, true)
231 func (*AzureProviderSuite) TestSetTags(c *check.C) {
232 ap, _, _, err := GetProvider()
234 c.Fatal("Error making provider", err)
236 l, err := ap.Instances(context.Background())
237 c.Assert(err, check.IsNil)
240 err = l[0].SetTags(context.Background(), map[string]string{"foo": "bar"})
242 c.Fatal("Error setting tags", err)
245 l, err = ap.Instances(context.Background())
246 c.Assert(err, check.IsNil)
249 tg, _ := l[0].Tags(context.Background())
250 log.Printf("tags are %v", tg)
254 func (*AzureProviderSuite) TestSSH(c *check.C) {
255 ap, _, _, err := GetProvider()
257 c.Fatal("Error making provider", err)
259 l, err := ap.Instances(context.Background())
260 c.Assert(err, check.IsNil)
264 sshclient, err := SetupSSHClient(c, l[0].Address()+":2222")
265 c.Assert(err, check.IsNil)
267 sess, err := sshclient.NewSession()
268 c.Assert(err, check.IsNil)
270 out, err := sess.Output("ls /")
271 c.Assert(err, check.IsNil)
273 log.Printf("%v", out)
275 sshclient.Conn.Close()
279 func SetupSSHClient(c *check.C, addr string) (*ssh.Client, error) {
281 return nil, errors.New("instance has no address")
284 f, err := os.Open("azconfig_sshkey")
285 c.Assert(err, check.IsNil)
287 keybytes, err := ioutil.ReadAll(f)
288 c.Assert(err, check.IsNil)
290 priv, err := ssh.ParsePrivateKey(keybytes)
291 c.Assert(err, check.IsNil)
293 var receivedKey ssh.PublicKey
294 client, err := ssh.Dial("tcp", addr, &ssh.ClientConfig{
296 Auth: []ssh.AuthMethod{
297 ssh.PublicKeys(priv),
299 HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
303 Timeout: time.Minute,
308 } else if receivedKey == nil {
309 return nil, errors.New("BUG: key was never provided to HostKeyCallback")
312 /*if wkr.publicKey == nil || !bytes.Equal(wkr.publicKey.Marshal(), receivedKey.Marshal()) {
313 err = wkr.instance.VerifyPublicKey(receivedKey, client)
317 wkr.publicKey = receivedKey