github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/azure/internal/azurecli/az_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package azurecli_test
     5  
     6  import (
     7  	"os/exec"
     8  	"strings"
     9  
    10  	"github.com/Azure/go-autorest/autorest/adal"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/juju/provider/azure/internal/azurecli"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  )
    16  
    17  type azSuite struct{}
    18  
    19  var _ = gc.Suite(&azSuite{})
    20  
    21  func (s *azSuite) TestGetAccessToken(c *gc.C) {
    22  	azcli := azurecli.AzureCLI{
    23  		Exec: testExecutor{
    24  			commands: map[string]result{
    25  				"az account get-access-token -o json": {
    26  					stdout: []byte(`
    27  {
    28    "accessToken": "ACCESSTOKEN",
    29    "expiresOn": "2017-06-07 09:27:58.063743",
    30    "subscription": "5544b9a5-0000-0000-0000-fedceb5d3696",
    31    "tenant": "a52afd7f-0000-0000-0000-e47a54b982da",
    32    "tokenType": "Bearer"
    33  }
    34  `[1:]),
    35  				},
    36  			},
    37  		}.Exec,
    38  	}
    39  	tok, err := azcli.GetAccessToken("", "")
    40  	c.Assert(err, jc.ErrorIsNil)
    41  	c.Assert(tok, jc.DeepEquals, &azurecli.AccessToken{
    42  		AccessToken:  "ACCESSTOKEN",
    43  		ExpiresOn:    "2017-06-07 09:27:58.063743",
    44  		Subscription: "5544b9a5-0000-0000-0000-fedceb5d3696",
    45  		Tenant:       "a52afd7f-0000-0000-0000-e47a54b982da",
    46  		TokenType:    "Bearer",
    47  	})
    48  }
    49  
    50  func (s *azSuite) TestGetAccessTokenWithSubscriptionAndResource(c *gc.C) {
    51  	azcli := azurecli.AzureCLI{
    52  		Exec: testExecutor{
    53  			commands: map[string]result{
    54  				"az account get-access-token --subscription 5544b9a5-0000-0000-0000-fedceb5d3696 --resource resid -o json": {
    55  					stdout: []byte(`
    56  {
    57    "accessToken": "ACCESSTOKEN",
    58    "expiresOn": "2017-06-07 09:27:58.063743",
    59    "subscription": "5544b9a5-0000-0000-0000-fedceb5d3696",
    60    "tenant": "a52afd7f-0000-0000-0000-e47a54b982da",
    61    "tokenType": "Bearer"
    62  }
    63  `[1:]),
    64  				},
    65  			},
    66  		}.Exec,
    67  	}
    68  	tok, err := azcli.GetAccessToken("5544b9a5-0000-0000-0000-fedceb5d3696", "resid")
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	c.Assert(tok, jc.DeepEquals, &azurecli.AccessToken{
    71  		AccessToken:  "ACCESSTOKEN",
    72  		ExpiresOn:    "2017-06-07 09:27:58.063743",
    73  		Subscription: "5544b9a5-0000-0000-0000-fedceb5d3696",
    74  		Tenant:       "a52afd7f-0000-0000-0000-e47a54b982da",
    75  		TokenType:    "Bearer",
    76  	})
    77  }
    78  
    79  func (s *azSuite) TestGetAccessTokenError(c *gc.C) {
    80  	azcli := azurecli.AzureCLI{
    81  		Exec: testExecutor{
    82  			commands: map[string]result{
    83  				"az account get-access-token -o json": {
    84  					error: &exec.ExitError{Stderr: []byte("test error")},
    85  				},
    86  			},
    87  		}.Exec,
    88  	}
    89  	tok, err := azcli.GetAccessToken("", "")
    90  	c.Assert(err, gc.ErrorMatches, `execution failure: test error`)
    91  	c.Assert(tok, gc.IsNil)
    92  }
    93  
    94  func (s *azSuite) TestGetAccessTokenJSONError(c *gc.C) {
    95  	azcli := azurecli.AzureCLI{
    96  		Exec: testExecutor{
    97  			commands: map[string]result{
    98  				"az account get-access-token -o json": {
    99  					stdout: []byte(`}`),
   100  				},
   101  			},
   102  		}.Exec,
   103  	}
   104  	tok, err := azcli.GetAccessToken("", "")
   105  	c.Assert(err, gc.ErrorMatches, `cannot unmarshal output: invalid character '}' looking for beginning of value`)
   106  	c.Assert(tok, gc.IsNil)
   107  }
   108  
   109  func (s *azSuite) TestAzureTokenFromAccessToken(c *gc.C) {
   110  	tok := azurecli.AccessToken{
   111  		AccessToken:  "0123456789",
   112  		ExpiresOn:    "2017-06-05 10:20:43.752534",
   113  		Subscription: "00000000-0000-0000-0000-00000001",
   114  		Tenant:       "00000000-0000-0000-0000-00000002",
   115  		TokenType:    "Bearer",
   116  	}
   117  	tok1 := tok.Token()
   118  	c.Assert(tok1, jc.DeepEquals, &adal.Token{
   119  		AccessToken: "0123456789",
   120  		Type:        "Bearer",
   121  	})
   122  }
   123  
   124  func (s *azSuite) TestShowAccount(c *gc.C) {
   125  	azcli := azurecli.AzureCLI{
   126  		Exec: testExecutor{
   127  			commands: map[string]result{
   128  				"az account show -o json": {
   129  					stdout: []byte(`
   130  {
   131    "environmentName": "AzureCloud",
   132    "id": "5544b9a5-0000-0000-0000-fedceb5d3696",
   133    "isDefault": true,
   134    "name": "AccountName",
   135    "state": "Enabled",
   136    "tenantId": "a52afd7f-0000-0000-0000-e47a54b982da",
   137    "user": {
   138      "name": "user@example.com",
   139      "type": "user"
   140    }
   141  }
   142  
   143  `[1:]),
   144  				},
   145  			},
   146  		}.Exec,
   147  	}
   148  	acc, err := azcli.ShowAccount("")
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	c.Assert(acc, jc.DeepEquals, &azurecli.Account{
   151  		CloudName: "AzureCloud",
   152  		ID:        "5544b9a5-0000-0000-0000-fedceb5d3696",
   153  		IsDefault: true,
   154  		Name:      "AccountName",
   155  		State:     "Enabled",
   156  		TenantId:  "a52afd7f-0000-0000-0000-e47a54b982da",
   157  	})
   158  }
   159  
   160  func (s *azSuite) TestShowAccountWithSubscription(c *gc.C) {
   161  	azcli := azurecli.AzureCLI{
   162  		Exec: testExecutor{
   163  			commands: map[string]result{
   164  				"az account show --subscription 5544b9a5-0000-0000-0000-fedceb5d3696 -o json": {
   165  					stdout: []byte(`
   166  {
   167    "environmentName": "AzureCloud",
   168    "id": "5544b9a5-0000-0000-0000-fedceb5d3696",
   169    "isDefault": true,
   170    "name": "AccountName",
   171    "state": "Enabled",
   172    "tenantId": "a52afd7f-0000-0000-0000-e47a54b982da",
   173    "user": {
   174      "name": "user@example.com",
   175      "type": "user"
   176    }
   177  }
   178  
   179  `[1:]),
   180  				},
   181  			},
   182  		}.Exec,
   183  	}
   184  	acc, err := azcli.ShowAccount("5544b9a5-0000-0000-0000-fedceb5d3696")
   185  	c.Assert(err, jc.ErrorIsNil)
   186  	c.Assert(acc, jc.DeepEquals, &azurecli.Account{
   187  		CloudName: "AzureCloud",
   188  		ID:        "5544b9a5-0000-0000-0000-fedceb5d3696",
   189  		IsDefault: true,
   190  		Name:      "AccountName",
   191  		State:     "Enabled",
   192  		TenantId:  "a52afd7f-0000-0000-0000-e47a54b982da",
   193  	})
   194  }
   195  
   196  func (s *azSuite) TestShowAccountError(c *gc.C) {
   197  	azcli := azurecli.AzureCLI{
   198  		Exec: testExecutor{
   199  			commands: map[string]result{
   200  				"az account show -o json": {
   201  					error: &exec.ExitError{Stderr: []byte("test error\nusage ...")},
   202  				},
   203  			},
   204  		}.Exec,
   205  	}
   206  	acc, err := azcli.ShowAccount("")
   207  	c.Assert(err, gc.ErrorMatches, `execution failure: test error`)
   208  	c.Assert(acc, gc.IsNil)
   209  }
   210  
   211  func (s *azSuite) TestListAccounts(c *gc.C) {
   212  	azcli := azurecli.AzureCLI{
   213  		Exec: testExecutor{
   214  			commands: map[string]result{
   215  				"az account list -o json": {
   216  					stdout: []byte(`
   217  [
   218    {
   219      "cloudName": "AzureCloud",
   220      "id": "d7ad3057-0000-0000-0000-513d7136eec5",
   221      "isDefault": false,
   222      "name": "Free Trial",
   223      "state": "Enabled",
   224      "tenantId": "b7bb0664-0000-0000-0000-4d5f1481ef22",
   225      "user": {
   226        "name": "user@example.com",
   227        "type": "user"
   228      }
   229    },
   230    {
   231      "cloudName": "AzureCloud",
   232      "id": "5af17b7d-0000-0000-0000-5cd99887fdf7",
   233      "isDefault": true,
   234      "name": "Pay-As-You-Go",
   235      "state": "Enabled",
   236      "tenantId": "2da419a9-0000-0000-0000-ac7c24bbe2e7",
   237      "user": {
   238        "name": "user@example.com",
   239        "type": "user"
   240      }
   241    }
   242  ]
   243  `[1:]),
   244  				},
   245  			},
   246  		}.Exec,
   247  	}
   248  	accs, err := azcli.ListAccounts()
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	c.Assert(accs, jc.DeepEquals, []azurecli.Account{{
   251  		CloudName: "AzureCloud",
   252  		ID:        "d7ad3057-0000-0000-0000-513d7136eec5",
   253  		IsDefault: false,
   254  		Name:      "Free Trial",
   255  		State:     "Enabled",
   256  		TenantId:  "b7bb0664-0000-0000-0000-4d5f1481ef22",
   257  	}, {
   258  		CloudName: "AzureCloud",
   259  		ID:        "5af17b7d-0000-0000-0000-5cd99887fdf7",
   260  		IsDefault: true,
   261  		Name:      "Pay-As-You-Go",
   262  		State:     "Enabled",
   263  		TenantId:  "2da419a9-0000-0000-0000-ac7c24bbe2e7",
   264  	}})
   265  }
   266  
   267  func (s *azSuite) TestListAccountsError(c *gc.C) {
   268  	azcli := azurecli.AzureCLI{
   269  		Exec: testExecutor{
   270  			commands: map[string]result{
   271  				"az account list -o json": {
   272  					error: errors.New("test error"),
   273  				},
   274  			},
   275  		}.Exec,
   276  	}
   277  	accs, err := azcli.ListAccounts()
   278  	c.Assert(err, gc.ErrorMatches, `execution failure: test error`)
   279  	c.Assert(accs, gc.IsNil)
   280  }
   281  
   282  func (s *azSuite) TestFindAccountsWithCloudName(c *gc.C) {
   283  	azcli := azurecli.AzureCLI{
   284  		Exec: testExecutor{
   285  			commands: map[string]result{
   286  				"az account list --query [?cloudName=='AzureCloud'] -o json": {
   287  					stdout: []byte(`
   288  [
   289    {
   290      "cloudName": "AzureCloud",
   291      "id": "d7ad3057-0000-0000-0000-513d7136eec5",
   292      "isDefault": false,
   293      "name": "Free Trial",
   294      "state": "Enabled",
   295      "tenantId": "b7bb0664-0000-0000-0000-4d5f1481ef22",
   296      "user": {
   297        "name": "user@example.com",
   298        "type": "user"
   299      }
   300    },
   301    {
   302      "cloudName": "AzureCloud",
   303      "id": "5af17b7d-0000-0000-0000-5cd99887fdf7",
   304      "isDefault": true,
   305      "name": "Pay-As-You-Go",
   306      "state": "Enabled",
   307      "tenantId": "2da419a9-0000-0000-0000-ac7c24bbe2e7",
   308      "user": {
   309        "name": "user@example.com",
   310        "type": "user"
   311      }
   312    }
   313  ]
   314  `[1:]),
   315  				},
   316  			},
   317  		}.Exec,
   318  	}
   319  	accs, err := azcli.FindAccountsWithCloudName("AzureCloud")
   320  	c.Assert(err, jc.ErrorIsNil)
   321  	c.Assert(accs, jc.DeepEquals, []azurecli.Account{{
   322  		CloudName: "AzureCloud",
   323  		ID:        "d7ad3057-0000-0000-0000-513d7136eec5",
   324  		IsDefault: false,
   325  		Name:      "Free Trial",
   326  		State:     "Enabled",
   327  		TenantId:  "b7bb0664-0000-0000-0000-4d5f1481ef22",
   328  	}, {
   329  		CloudName: "AzureCloud",
   330  		ID:        "5af17b7d-0000-0000-0000-5cd99887fdf7",
   331  		IsDefault: true,
   332  		Name:      "Pay-As-You-Go",
   333  		State:     "Enabled",
   334  		TenantId:  "2da419a9-0000-0000-0000-ac7c24bbe2e7",
   335  	}})
   336  }
   337  
   338  func (s *azSuite) TestFindAccountsWithCloudNameError(c *gc.C) {
   339  	azcli := azurecli.AzureCLI{
   340  		Exec: testExecutor{
   341  			commands: map[string]result{
   342  				"az account list --query [?cloudName=='AzureCloud'] -o json": {
   343  					error: errors.New("test error"),
   344  				},
   345  			},
   346  		}.Exec,
   347  	}
   348  	accs, err := azcli.FindAccountsWithCloudName("AzureCloud")
   349  	c.Assert(err, gc.ErrorMatches, `execution failure: test error`)
   350  	c.Assert(accs, gc.IsNil)
   351  }
   352  
   353  func (s *azSuite) TestShowCloud(c *gc.C) {
   354  	azcli := azurecli.AzureCLI{
   355  		Exec: testExecutor{
   356  			commands: map[string]result{
   357  				"az cloud show -o json": {
   358  					stdout: []byte(`
   359  {
   360    "endpoints": {
   361      "activeDirectory": "https://login.microsoftonline.com",
   362      "activeDirectoryGraphResourceId": "https://graph.windows.net/",
   363      "activeDirectoryResourceId": "https://management.core.windows.net/",
   364      "batchResourceId": "https://batch.core.windows.net/",
   365      "gallery": "https://gallery.azure.com/",
   366      "management": "https://management.core.windows.net/",
   367      "resourceManager": "https://management.azure.com/",
   368      "sqlManagement": "https://management.core.windows.net:8443/"
   369    },
   370    "isActive": true,
   371    "name": "AzureCloud",
   372    "profile": "latest",
   373    "suffixes": {
   374      "azureDatalakeAnalyticsCatalogAndJobEndpoint": "azuredatalakeanalytics.net",
   375      "azureDatalakeStoreFileSystemEndpoint": "azuredatalakestore.net",
   376      "keyvaultDns": ".vault.azure.net",
   377      "sqlServerHostname": ".database.windows.net",
   378      "storageEndpoint": "core.windows.net"
   379    }
   380  }
   381  `[1:]),
   382  				},
   383  			},
   384  		}.Exec,
   385  	}
   386  	cloud, err := azcli.ShowCloud("")
   387  	c.Assert(err, jc.ErrorIsNil)
   388  	c.Assert(cloud, jc.DeepEquals, &azurecli.Cloud{
   389  		Endpoints: azurecli.CloudEndpoints{
   390  			ActiveDirectory:                "https://login.microsoftonline.com",
   391  			ActiveDirectoryGraphResourceID: "https://graph.windows.net/",
   392  			ActiveDirectoryResourceID:      "https://management.core.windows.net/",
   393  			BatchResourceID:                "https://batch.core.windows.net/",
   394  			Management:                     "https://management.core.windows.net/",
   395  			ResourceManager:                "https://management.azure.com/",
   396  			SQLManagement:                  "https://management.core.windows.net:8443/",
   397  		},
   398  		IsActive: true,
   399  		Name:     "AzureCloud",
   400  		Profile:  "latest",
   401  		Suffixes: azurecli.CloudSuffixes{
   402  			AzureDatalakeAnalyticsCatalogAndJobEndpoint: "azuredatalakeanalytics.net",
   403  			AzureDatalakeStoreFileSystemEndpoint:        "azuredatalakestore.net",
   404  			KeyvaultDNS:                                 ".vault.azure.net",
   405  			SQLServerHostname:                           ".database.windows.net",
   406  			StorageEndpoint:                             "core.windows.net",
   407  		},
   408  	})
   409  }
   410  
   411  func (s *azSuite) TestShowCloudWithName(c *gc.C) {
   412  	azcli := azurecli.AzureCLI{
   413  		Exec: testExecutor{
   414  			commands: map[string]result{
   415  				"az cloud show --name AzureUSGovernment -o json": {
   416  					stdout: []byte(`
   417  {
   418    "endpoints": {
   419      "activeDirectory": "https://login.microsoftonline.com",
   420      "activeDirectoryGraphResourceId": "https://graph.windows.net/",
   421      "activeDirectoryResourceId": "https://management.core.usgovcloudapi.net/",
   422      "batchResourceId": "https://batch.core.usgovcloudapi.net/",
   423      "gallery": "https://gallery.usgovcloudapi.net/",
   424      "management": "https://management.core.usgovcloudapi.net/",
   425      "resourceManager": "https://management.usgovcloudapi.net/",
   426      "sqlManagement": "https://management.core.usgovcloudapi.net:8443/"
   427    },
   428    "isActive": false,
   429    "name": "AzureUSGovernment",
   430    "profile": "latest",
   431    "suffixes": {
   432      "azureDatalakeAnalyticsCatalogAndJobEndpoint": null,
   433      "azureDatalakeStoreFileSystemEndpoint": null,
   434      "keyvaultDns": ".vault.usgovcloudapi.net",
   435      "sqlServerHostname": ".database.usgovcloudapi.net",
   436      "storageEndpoint": "core.usgovcloudapi.net"
   437    }
   438  }
   439  `[1:]),
   440  				},
   441  			},
   442  		}.Exec,
   443  	}
   444  	cloud, err := azcli.ShowCloud("AzureUSGovernment")
   445  	c.Assert(err, jc.ErrorIsNil)
   446  	c.Assert(cloud, jc.DeepEquals, &azurecli.Cloud{
   447  		Endpoints: azurecli.CloudEndpoints{
   448  			ActiveDirectory:                "https://login.microsoftonline.com",
   449  			ActiveDirectoryGraphResourceID: "https://graph.windows.net/",
   450  			ActiveDirectoryResourceID:      "https://management.core.usgovcloudapi.net/",
   451  			BatchResourceID:                "https://batch.core.usgovcloudapi.net/",
   452  			Management:                     "https://management.core.usgovcloudapi.net/",
   453  			ResourceManager:                "https://management.usgovcloudapi.net/",
   454  			SQLManagement:                  "https://management.core.usgovcloudapi.net:8443/",
   455  		},
   456  		IsActive: false,
   457  		Name:     "AzureUSGovernment",
   458  		Profile:  "latest",
   459  		Suffixes: azurecli.CloudSuffixes{
   460  			KeyvaultDNS:       ".vault.usgovcloudapi.net",
   461  			SQLServerHostname: ".database.usgovcloudapi.net",
   462  			StorageEndpoint:   "core.usgovcloudapi.net",
   463  		},
   464  	})
   465  }
   466  
   467  func (s *azSuite) TestShowCloudError(c *gc.C) {
   468  	azcli := azurecli.AzureCLI{
   469  		Exec: testExecutor{
   470  			commands: map[string]result{
   471  				"az cloud show -o json": {
   472  					error: errors.New("test error"),
   473  				},
   474  			},
   475  		}.Exec,
   476  	}
   477  	cloud, err := azcli.ShowCloud("")
   478  	c.Assert(err, gc.ErrorMatches, `execution failure: test error`)
   479  	c.Assert(cloud, gc.IsNil)
   480  }
   481  
   482  func (s *azSuite) TestFindCloudsWithResourceManagerEndpoint(c *gc.C) {
   483  	azcli := azurecli.AzureCLI{
   484  		Exec: testExecutor{
   485  			commands: map[string]result{
   486  				"az cloud list --query [?endpoints.resourceManager=='https://management.azure.com/'] -o json": {
   487  					stdout: []byte(`
   488  [
   489    {
   490      "endpoints": {
   491        "activeDirectory": "https://login.microsoftonline.com",
   492        "activeDirectoryGraphResourceId": "https://graph.windows.net/",
   493        "activeDirectoryResourceId": "https://management.core.windows.net/",
   494        "batchResourceId": "https://batch.core.windows.net/",
   495        "gallery": "https://gallery.azure.com/",
   496        "management": "https://management.core.windows.net/",
   497        "resourceManager": "https://management.azure.com/",
   498        "sqlManagement": "https://management.core.windows.net:8443/"
   499      },
   500      "isActive": true,
   501      "name": "AzureCloud",
   502      "profile": "latest",
   503      "suffixes": {
   504        "azureDatalakeAnalyticsCatalogAndJobEndpoint": "azuredatalakeanalytics.net",
   505        "azureDatalakeStoreFileSystemEndpoint": "azuredatalakestore.net",
   506        "keyvaultDns": ".vault.azure.net",
   507        "sqlServerHostname": ".database.windows.net",
   508        "storageEndpoint": "core.windows.net"
   509      }
   510    }
   511  ]
   512  `[1:]),
   513  				},
   514  			},
   515  		}.Exec,
   516  	}
   517  	cloud, err := azcli.FindCloudsWithResourceManagerEndpoint("https://management.azure.com/")
   518  	c.Assert(err, jc.ErrorIsNil)
   519  	c.Assert(cloud, jc.DeepEquals, []azurecli.Cloud{{
   520  		Endpoints: azurecli.CloudEndpoints{
   521  			ActiveDirectory:                "https://login.microsoftonline.com",
   522  			ActiveDirectoryGraphResourceID: "https://graph.windows.net/",
   523  			ActiveDirectoryResourceID:      "https://management.core.windows.net/",
   524  			BatchResourceID:                "https://batch.core.windows.net/",
   525  			Management:                     "https://management.core.windows.net/",
   526  			ResourceManager:                "https://management.azure.com/",
   527  			SQLManagement:                  "https://management.core.windows.net:8443/",
   528  		},
   529  		IsActive: true,
   530  		Name:     "AzureCloud",
   531  		Profile:  "latest",
   532  		Suffixes: azurecli.CloudSuffixes{
   533  			AzureDatalakeAnalyticsCatalogAndJobEndpoint: "azuredatalakeanalytics.net",
   534  			AzureDatalakeStoreFileSystemEndpoint:        "azuredatalakestore.net",
   535  			KeyvaultDNS:                                 ".vault.azure.net",
   536  			SQLServerHostname:                           ".database.windows.net",
   537  			StorageEndpoint:                             "core.windows.net",
   538  		},
   539  	}})
   540  }
   541  
   542  func (s *azSuite) TestFindCloudsWithResourceManagerEndpointError(c *gc.C) {
   543  	azcli := azurecli.AzureCLI{
   544  		Exec: testExecutor{
   545  			commands: map[string]result{
   546  				"az cloud list --query [?endpoints.resourceManager=='https://management.azure.com/'] -o json": {
   547  					error: errors.New("test error"),
   548  				},
   549  			},
   550  		}.Exec,
   551  	}
   552  	cloud, err := azcli.FindCloudsWithResourceManagerEndpoint("https://management.azure.com/")
   553  	c.Assert(err, gc.ErrorMatches, `execution failure: test error`)
   554  	c.Assert(cloud, gc.IsNil)
   555  }
   556  
   557  func (s *azSuite) TestListClouds(c *gc.C) {
   558  	azcli := azurecli.AzureCLI{
   559  		Exec: testExecutor{
   560  			commands: map[string]result{
   561  				"az cloud list -o json": {
   562  					stdout: []byte(`
   563  [
   564    {
   565      "endpoints": {
   566        "activeDirectory": "https://login.microsoftonline.com",
   567        "activeDirectoryGraphResourceId": "https://graph.windows.net/",
   568        "activeDirectoryResourceId": "https://management.core.windows.net/",
   569        "batchResourceId": "https://batch.core.windows.net/",
   570        "gallery": "https://gallery.azure.com/",
   571        "management": "https://management.core.windows.net/",
   572        "resourceManager": "https://management.azure.com/",
   573        "sqlManagement": "https://management.core.windows.net:8443/"
   574      },
   575      "isActive": true,
   576      "name": "AzureCloud",
   577      "profile": "latest",
   578      "suffixes": {
   579        "azureDatalakeAnalyticsCatalogAndJobEndpoint": "azuredatalakeanalytics.net",
   580        "azureDatalakeStoreFileSystemEndpoint": "azuredatalakestore.net",
   581        "keyvaultDns": ".vault.azure.net",
   582        "sqlServerHostname": ".database.windows.net",
   583        "storageEndpoint": "core.windows.net"
   584      }
   585    },
   586    {
   587      "endpoints": {
   588        "activeDirectory": "https://login.chinacloudapi.cn",
   589        "activeDirectoryGraphResourceId": "https://graph.chinacloudapi.cn/",
   590        "activeDirectoryResourceId": "https://management.core.chinacloudapi.cn/",
   591        "batchResourceId": "https://batch.chinacloudapi.cn/",
   592        "gallery": "https://gallery.chinacloudapi.cn/",
   593        "management": "https://management.core.chinacloudapi.cn/",
   594        "resourceManager": "https://management.chinacloudapi.cn",
   595        "sqlManagement": "https://management.core.chinacloudapi.cn:8443/"
   596      },
   597      "isActive": false,
   598      "name": "AzureChinaCloud",
   599      "profile": "latest",
   600      "suffixes": {
   601        "azureDatalakeAnalyticsCatalogAndJobEndpoint": null,
   602        "azureDatalakeStoreFileSystemEndpoint": null,
   603        "keyvaultDns": ".vault.azure.cn",
   604        "sqlServerHostname": ".database.chinacloudapi.cn",
   605        "storageEndpoint": "core.chinacloudapi.cn"
   606      }
   607    },
   608    {
   609      "endpoints": {
   610        "activeDirectory": "https://login.microsoftonline.com",
   611        "activeDirectoryGraphResourceId": "https://graph.windows.net/",
   612        "activeDirectoryResourceId": "https://management.core.usgovcloudapi.net/",
   613        "batchResourceId": "https://batch.core.usgovcloudapi.net/",
   614        "gallery": "https://gallery.usgovcloudapi.net/",
   615        "management": "https://management.core.usgovcloudapi.net/",
   616        "resourceManager": "https://management.usgovcloudapi.net/",
   617        "sqlManagement": "https://management.core.usgovcloudapi.net:8443/"
   618      },
   619      "isActive": false,
   620      "name": "AzureUSGovernment",
   621      "profile": "latest",
   622      "suffixes": {
   623        "azureDatalakeAnalyticsCatalogAndJobEndpoint": null,
   624        "azureDatalakeStoreFileSystemEndpoint": null,
   625        "keyvaultDns": ".vault.usgovcloudapi.net",
   626        "sqlServerHostname": ".database.usgovcloudapi.net",
   627        "storageEndpoint": "core.usgovcloudapi.net"
   628      }
   629    },
   630    {
   631      "endpoints": {
   632        "activeDirectory": "https://login.microsoftonline.de",
   633        "activeDirectoryGraphResourceId": "https://graph.cloudapi.de/",
   634        "activeDirectoryResourceId": "https://management.core.cloudapi.de/",
   635        "batchResourceId": "https://batch.cloudapi.de/",
   636        "gallery": "https://gallery.cloudapi.de/",
   637        "management": "https://management.core.cloudapi.de/",
   638        "resourceManager": "https://management.microsoftazure.de",
   639        "sqlManagement": "https://management.core.cloudapi.de:8443/"
   640      },
   641      "isActive": false,
   642      "name": "AzureGermanCloud",
   643      "profile": "latest",
   644      "suffixes": {
   645        "azureDatalakeAnalyticsCatalogAndJobEndpoint": null,
   646        "azureDatalakeStoreFileSystemEndpoint": null,
   647        "keyvaultDns": ".vault.microsoftazure.de",
   648        "sqlServerHostname": ".database.cloudapi.de",
   649        "storageEndpoint": "core.cloudapi.de"
   650      }
   651    }
   652  ]
   653  
   654  `[1:]),
   655  				},
   656  			},
   657  		}.Exec,
   658  	}
   659  	clouds, err := azcli.ListClouds()
   660  	c.Assert(err, jc.ErrorIsNil)
   661  	c.Assert(clouds, jc.DeepEquals, []azurecli.Cloud{{
   662  		Endpoints: azurecli.CloudEndpoints{
   663  			ActiveDirectory:                "https://login.microsoftonline.com",
   664  			ActiveDirectoryGraphResourceID: "https://graph.windows.net/",
   665  			ActiveDirectoryResourceID:      "https://management.core.windows.net/",
   666  			BatchResourceID:                "https://batch.core.windows.net/",
   667  			Management:                     "https://management.core.windows.net/",
   668  			ResourceManager:                "https://management.azure.com/",
   669  			SQLManagement:                  "https://management.core.windows.net:8443/",
   670  		},
   671  		IsActive: true,
   672  		Name:     "AzureCloud",
   673  		Profile:  "latest",
   674  		Suffixes: azurecli.CloudSuffixes{
   675  			AzureDatalakeAnalyticsCatalogAndJobEndpoint: "azuredatalakeanalytics.net",
   676  			AzureDatalakeStoreFileSystemEndpoint:        "azuredatalakestore.net",
   677  			KeyvaultDNS:                                 ".vault.azure.net",
   678  			SQLServerHostname:                           ".database.windows.net",
   679  			StorageEndpoint:                             "core.windows.net",
   680  		},
   681  	}, {
   682  		Endpoints: azurecli.CloudEndpoints{
   683  			ActiveDirectory:                "https://login.chinacloudapi.cn",
   684  			ActiveDirectoryGraphResourceID: "https://graph.chinacloudapi.cn/",
   685  			ActiveDirectoryResourceID:      "https://management.core.chinacloudapi.cn/",
   686  			BatchResourceID:                "https://batch.chinacloudapi.cn/",
   687  			Management:                     "https://management.core.chinacloudapi.cn/",
   688  			ResourceManager:                "https://management.chinacloudapi.cn",
   689  			SQLManagement:                  "https://management.core.chinacloudapi.cn:8443/",
   690  		},
   691  		IsActive: false,
   692  		Name:     "AzureChinaCloud",
   693  		Profile:  "latest",
   694  		Suffixes: azurecli.CloudSuffixes{
   695  			KeyvaultDNS:       ".vault.azure.cn",
   696  			SQLServerHostname: ".database.chinacloudapi.cn",
   697  			StorageEndpoint:   "core.chinacloudapi.cn",
   698  		},
   699  	}, {
   700  		Endpoints: azurecli.CloudEndpoints{
   701  			ActiveDirectory:                "https://login.microsoftonline.com",
   702  			ActiveDirectoryGraphResourceID: "https://graph.windows.net/",
   703  			ActiveDirectoryResourceID:      "https://management.core.usgovcloudapi.net/",
   704  			BatchResourceID:                "https://batch.core.usgovcloudapi.net/",
   705  			Management:                     "https://management.core.usgovcloudapi.net/",
   706  			ResourceManager:                "https://management.usgovcloudapi.net/",
   707  			SQLManagement:                  "https://management.core.usgovcloudapi.net:8443/",
   708  		},
   709  		IsActive: false,
   710  		Name:     "AzureUSGovernment",
   711  		Profile:  "latest",
   712  		Suffixes: azurecli.CloudSuffixes{
   713  			KeyvaultDNS:       ".vault.usgovcloudapi.net",
   714  			SQLServerHostname: ".database.usgovcloudapi.net",
   715  			StorageEndpoint:   "core.usgovcloudapi.net",
   716  		},
   717  	}, {
   718  		Endpoints: azurecli.CloudEndpoints{
   719  			ActiveDirectory:                "https://login.microsoftonline.de",
   720  			ActiveDirectoryGraphResourceID: "https://graph.cloudapi.de/",
   721  			ActiveDirectoryResourceID:      "https://management.core.cloudapi.de/",
   722  			BatchResourceID:                "https://batch.cloudapi.de/",
   723  			Management:                     "https://management.core.cloudapi.de/",
   724  			ResourceManager:                "https://management.microsoftazure.de",
   725  			SQLManagement:                  "https://management.core.cloudapi.de:8443/",
   726  		},
   727  		IsActive: false,
   728  		Name:     "AzureGermanCloud",
   729  		Profile:  "latest",
   730  		Suffixes: azurecli.CloudSuffixes{
   731  			KeyvaultDNS:       ".vault.microsoftazure.de",
   732  			SQLServerHostname: ".database.cloudapi.de",
   733  			StorageEndpoint:   "core.cloudapi.de",
   734  		},
   735  	}})
   736  }
   737  
   738  func (s *azSuite) TestListCloudsError(c *gc.C) {
   739  	azcli := azurecli.AzureCLI{
   740  		Exec: testExecutor{
   741  			commands: map[string]result{
   742  				"az cloud list -o json": {
   743  					error: errors.New("test error"),
   744  				},
   745  			},
   746  		}.Exec,
   747  	}
   748  	cloud, err := azcli.ListClouds()
   749  	c.Assert(err, gc.ErrorMatches, `execution failure: test error`)
   750  	c.Assert(cloud, gc.IsNil)
   751  }
   752  
   753  type result struct {
   754  	stdout []byte
   755  	error  error
   756  }
   757  
   758  type testExecutor struct {
   759  	commands map[string]result
   760  }
   761  
   762  func (e testExecutor) Exec(cmd string, args []string) ([]byte, error) {
   763  	c := strings.Join(append([]string{cmd}, args...), " ")
   764  	r, ok := e.commands[c]
   765  	if !ok {
   766  		return nil, errors.Errorf("unexpected command '%s'", c)
   767  	}
   768  	return r.stdout, r.error
   769  }