Skip to content

Commit 82d1e16

Browse files
authored
feat: Query resource groups and storage accounts and display select instead of input in the survey (#673)
* query resource groups and storage accounts * allow creating new group and account * add validation
1 parent 5daff86 commit 82d1e16

File tree

5 files changed

+168
-371
lines changed

5 files changed

+168
-371
lines changed

pkg/provider/azure.go

Lines changed: 21 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"strings"
1313
"time"
1414

15-
"github.com/AlecAivazis/survey/v2"
1615
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
1716
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
1817
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
@@ -35,39 +34,12 @@ import (
3534
pluralerr "github.com/pluralsh/plural-cli/pkg/utils/errors"
3635
)
3736

38-
// ResourceGroupClient is the subset of functions we need from armresources.VirtualResourceGroupsClient;
39-
// this interface is purely here for allowing unit tests.
40-
type ResourceGroupClient interface {
41-
CreateOrUpdate(ctx context.Context, resourceGroupName string, parameters armresources.ResourceGroup, options *armresources.ResourceGroupsClientCreateOrUpdateOptions) (armresources.ResourceGroupsClientCreateOrUpdateResponse, error)
42-
Get(ctx context.Context, resourceGroupName string, options *armresources.ResourceGroupsClientGetOptions) (armresources.ResourceGroupsClientGetResponse, error)
43-
}
44-
45-
type AccountsClient interface {
46-
GetProperties(ctx context.Context, resourceGroupName string, accountName string, options *armstorage.AccountsClientGetPropertiesOptions) (armstorage.AccountsClientGetPropertiesResponse, error)
47-
BeginCreate(ctx context.Context, resourceGroupName string, accountName string, parameters armstorage.AccountCreateParameters, options *armstorage.AccountsClientBeginCreateOptions) (*runtime.Poller[armstorage.AccountsClientCreateResponse], error)
48-
NewListPager(options *armstorage.AccountsClientListOptions) *runtime.Pager[armstorage.AccountsClientListResponse]
49-
ListKeys(ctx context.Context, resourceGroupName string, accountName string, options *armstorage.AccountsClientListKeysOptions) (armstorage.AccountsClientListKeysResponse, error)
50-
}
51-
52-
type ContainerClient interface {
53-
GetProperties(ctx context.Context, ac azblob.LeaseAccessConditions) (*azblob.ContainerGetPropertiesResponse, error)
54-
Create(ctx context.Context, metadata azblob.Metadata, publicAccessType azblob.PublicAccessType) (*azblob.ContainerCreateResponse, error)
55-
}
56-
57-
type SubscriptionClient interface {
58-
NewListLocationsPager(subscriptionID string, options *armsubscription.SubscriptionsClientListLocationsOptions) *runtime.Pager[armsubscription.SubscriptionsClientListLocationsResponse]
59-
}
60-
61-
type ZonesClient interface {
62-
NewListByResourceGroupPager(resourceGroupName string, options *armdns.ZonesClientListByResourceGroupOptions) *runtime.Pager[armdns.ZonesClientListByResourceGroupResponse]
63-
}
64-
6537
type ClientSet struct {
66-
Subscriptions SubscriptionClient
67-
Groups ResourceGroupClient
68-
Accounts AccountsClient
69-
Containers ContainerClient
70-
Zones ZonesClient
38+
Subscriptions *armsubscription.SubscriptionsClient
39+
Groups *armresources.ResourceGroupsClient
40+
Accounts *armstorage.AccountsClient
41+
Zones *armdns.ZonesClient
42+
Containers *azblob.ContainerURL
7143
}
7244

7345
func GetClientSet(subscriptionId string) (*ClientSet, error) {
@@ -135,65 +107,32 @@ func mkAzure(conf config.Config) (prov *AzureProvider, err error) {
135107
}
136108

137109
ctx := context.Background()
138-
locations := []string{}
139-
locationsPager := clients.Subscriptions.NewListLocationsPager(subId, nil)
140-
for locationsPager.More() {
141-
page, err := locationsPager.NextPage(ctx)
142-
if err != nil {
143-
return nil, err
144-
}
145110

146-
for _, v := range page.Value {
147-
if v != nil {
148-
locations = append(locations, *v.Name)
149-
}
150-
}
111+
cluster, err := askCluster()
112+
if err != nil {
113+
return
151114
}
152115

153-
var resp struct {
154-
Cluster string
155-
Storage string
156-
Region string
157-
Resource string
116+
location, err := askAzureLocation(ctx, clients.Subscriptions, subId)
117+
if err != nil {
118+
return
158119
}
159-
var azureSurvey = []*survey.Question{
160-
{
161-
Name: "cluster",
162-
Prompt: &survey.Input{Message: "Enter the name of your cluster:", Default: clusterFlag},
163-
Validate: validCluster,
164-
},
165-
{
166-
Name: "storage",
167-
Prompt: &survey.Input{Message: "Enter the name of the storage account to use for your stage, must be globally unique or already owned by your subscription:"},
168-
Validate: utils.ValidateStorageAccountName,
169-
},
170-
{
171-
Name: "region",
172-
Prompt: &survey.Select{Message: "Enter the region you want to deploy to:", Default: "eastus", Options: locations},
173-
Validate: survey.Required,
174-
},
175-
{
176-
Name: "resource",
177-
Prompt: &survey.Input{Message: "Enter the name of the resource group to use:"},
178-
Validate: utils.ValidateResourceGroupName,
179-
},
120+
121+
resourceGroup, err := askAzureResourceGroup(ctx, clients.Groups)
122+
if err != nil {
123+
return
180124
}
181125

182-
err = survey.Ask(azureSurvey, &resp)
126+
storageAccount, err := askAzureStorageAccount(ctx, clients.Accounts)
183127
if err != nil {
184128
return
185129
}
186130

187-
prov = &AzureProvider{
188-
resp.Cluster,
189-
resp.Resource,
131+
prov = &AzureProvider{cluster,
132+
resourceGroup,
190133
"",
191-
resp.Region,
192-
map[string]interface{}{
193-
"SubscriptionId": subId,
194-
"TenantId": tenID,
195-
"StorageAccount": resp.Storage,
196-
},
134+
location,
135+
map[string]any{"SubscriptionId": subId, "TenantId": tenID, "StorageAccount": storageAccount},
197136
nil,
198137
clients,
199138
}
@@ -452,7 +391,7 @@ func (az *AzureProvider) upsertStorageContainer(acc armstorage.Account, name str
452391
u, _ := url.Parse(fmt.Sprintf(`https://%s.blob.core.windows.net`, accountName))
453392
service := azblob.NewServiceURL(*u, p)
454393
containerClient := service.NewContainerURL(name)
455-
az.clients.Containers = containerClient
394+
az.clients.Containers = &containerClient
456395
}
457396

458397
_, err = az.clients.Containers.GetProperties(ctx, azblob.LeaseAccessConditions{})

pkg/provider/azure_survey.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
6+
"github.com/AlecAivazis/survey/v2"
7+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
8+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
9+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription"
10+
"github.com/pluralsh/plural-cli/pkg/utils"
11+
)
12+
13+
const createNewOption = "Create new..."
14+
15+
func askCluster() (string, error) {
16+
cluster := ""
17+
if err := survey.AskOne(
18+
&survey.Input{Message: "Enter the name of your cluster:"},
19+
&cluster, survey.WithValidator(validCluster),
20+
); err != nil {
21+
return "", err
22+
}
23+
24+
return cluster, nil
25+
}
26+
27+
func azureLocations(ctx context.Context, client *armsubscription.SubscriptionsClient, subscriptionID string) ([]string, error) {
28+
locations := make([]string, 0)
29+
pager := client.NewListLocationsPager(subscriptionID, nil)
30+
for pager.More() {
31+
page, err := pager.NextPage(ctx)
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
for _, v := range page.Value {
37+
if v != nil {
38+
locations = append(locations, *v.Name)
39+
}
40+
}
41+
}
42+
43+
return locations, nil
44+
}
45+
46+
func askAzureLocation(ctx context.Context, client *armsubscription.SubscriptionsClient, subscriptionID string) (string, error) {
47+
options, err := azureLocations(ctx, client, subscriptionID)
48+
if err != nil {
49+
return "", err
50+
}
51+
52+
location := ""
53+
if err = survey.AskOne(
54+
&survey.Select{Message: "Select the location you want to deploy to:", Options: options, Default: "eastus"},
55+
&location, survey.WithValidator(survey.Required),
56+
); err != nil {
57+
return "", err
58+
}
59+
60+
return location, nil
61+
}
62+
63+
func azureResourceGroups(ctx context.Context, client *armresources.ResourceGroupsClient) ([]string, error) {
64+
groups := make([]string, 0)
65+
pager := client.NewListPager(nil)
66+
for pager.More() {
67+
page, err := pager.NextPage(ctx)
68+
if err != nil {
69+
return nil, err
70+
}
71+
72+
for _, v := range page.Value {
73+
if v != nil {
74+
groups = append(groups, *v.Name)
75+
}
76+
}
77+
}
78+
79+
return groups, nil
80+
}
81+
82+
func askAzureResourceGroup(ctx context.Context, client *armresources.ResourceGroupsClient) (string, error) {
83+
options, err := azureResourceGroups(ctx, client)
84+
if err != nil {
85+
return "", err
86+
}
87+
options = append(options, createNewOption)
88+
89+
group := ""
90+
if err = survey.AskOne(
91+
&survey.Select{Message: "Select the resource group to use:", Options: options},
92+
&group, survey.WithValidator(survey.Required),
93+
); err != nil {
94+
return "", err
95+
}
96+
97+
if group == createNewOption {
98+
if err = survey.AskOne(&survey.Input{Message: "Enter resource group name:"}, &group, survey.WithValidator(utils.ValidateResourceGroupName)); err != nil {
99+
return "", err
100+
}
101+
}
102+
103+
return group, nil
104+
}
105+
106+
func azureStorageAccounts(ctx context.Context, client *armstorage.AccountsClient) ([]string, error) {
107+
accounts := make([]string, 0)
108+
pager := client.NewListPager(nil)
109+
for pager.More() {
110+
page, err := pager.NextPage(ctx)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
for _, v := range page.Value {
116+
if v != nil {
117+
accounts = append(accounts, *v.Name)
118+
}
119+
}
120+
}
121+
122+
return accounts, nil
123+
}
124+
125+
func askAzureStorageAccount(ctx context.Context, client *armstorage.AccountsClient) (string, error) {
126+
options, err := azureStorageAccounts(ctx, client)
127+
if err != nil {
128+
return "", err
129+
}
130+
options = append(options, createNewOption)
131+
132+
account := ""
133+
if err = survey.AskOne(
134+
&survey.Select{Message: "Select the storage account to use:", Options: options},
135+
&account, survey.WithValidator(survey.Required),
136+
); err != nil {
137+
return "", err
138+
}
139+
140+
if account == createNewOption {
141+
if err = survey.AskOne(&survey.Input{Message: "Enter globally unique storage account name:"}, &account, survey.WithValidator(utils.ValidateStorageAccountName)); err != nil {
142+
return "", err
143+
}
144+
}
145+
146+
return account, nil
147+
}

0 commit comments

Comments
 (0)