Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 21 additions & 82 deletions pkg/provider/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"strings"
"time"

"github.com/AlecAivazis/survey/v2"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
Expand All @@ -35,39 +34,12 @@ import (
pluralerr "github.com/pluralsh/plural-cli/pkg/utils/errors"
)

// ResourceGroupClient is the subset of functions we need from armresources.VirtualResourceGroupsClient;
// this interface is purely here for allowing unit tests.
type ResourceGroupClient interface {
CreateOrUpdate(ctx context.Context, resourceGroupName string, parameters armresources.ResourceGroup, options *armresources.ResourceGroupsClientCreateOrUpdateOptions) (armresources.ResourceGroupsClientCreateOrUpdateResponse, error)
Get(ctx context.Context, resourceGroupName string, options *armresources.ResourceGroupsClientGetOptions) (armresources.ResourceGroupsClientGetResponse, error)
}

type AccountsClient interface {
GetProperties(ctx context.Context, resourceGroupName string, accountName string, options *armstorage.AccountsClientGetPropertiesOptions) (armstorage.AccountsClientGetPropertiesResponse, error)
BeginCreate(ctx context.Context, resourceGroupName string, accountName string, parameters armstorage.AccountCreateParameters, options *armstorage.AccountsClientBeginCreateOptions) (*runtime.Poller[armstorage.AccountsClientCreateResponse], error)
NewListPager(options *armstorage.AccountsClientListOptions) *runtime.Pager[armstorage.AccountsClientListResponse]
ListKeys(ctx context.Context, resourceGroupName string, accountName string, options *armstorage.AccountsClientListKeysOptions) (armstorage.AccountsClientListKeysResponse, error)
}

type ContainerClient interface {
GetProperties(ctx context.Context, ac azblob.LeaseAccessConditions) (*azblob.ContainerGetPropertiesResponse, error)
Create(ctx context.Context, metadata azblob.Metadata, publicAccessType azblob.PublicAccessType) (*azblob.ContainerCreateResponse, error)
}

type SubscriptionClient interface {
NewListLocationsPager(subscriptionID string, options *armsubscription.SubscriptionsClientListLocationsOptions) *runtime.Pager[armsubscription.SubscriptionsClientListLocationsResponse]
}

type ZonesClient interface {
NewListByResourceGroupPager(resourceGroupName string, options *armdns.ZonesClientListByResourceGroupOptions) *runtime.Pager[armdns.ZonesClientListByResourceGroupResponse]
}

type ClientSet struct {
Subscriptions SubscriptionClient
Groups ResourceGroupClient
Accounts AccountsClient
Containers ContainerClient
Zones ZonesClient
Subscriptions *armsubscription.SubscriptionsClient
Groups *armresources.ResourceGroupsClient
Accounts *armstorage.AccountsClient
Zones *armdns.ZonesClient
Containers *azblob.ContainerURL
}

func GetClientSet(subscriptionId string) (*ClientSet, error) {
Expand Down Expand Up @@ -126,65 +98,32 @@ func mkAzure(conf config.Config) (prov *AzureProvider, err error) {
}

ctx := context.Background()
locations := []string{}
locationsPager := clients.Subscriptions.NewListLocationsPager(subId, nil)
for locationsPager.More() {
page, err := locationsPager.NextPage(ctx)
if err != nil {
return nil, err
}

for _, v := range page.Value {
if v != nil {
locations = append(locations, *v.Name)
}
}
cluster, err := askCluster()
if err != nil {
return
}

var resp struct {
Cluster string
Storage string
Region string
Resource string
location, err := askAzureLocation(ctx, clients.Subscriptions, subId)
if err != nil {
return
}
var azureSurvey = []*survey.Question{
{
Name: "cluster",
Prompt: &survey.Input{Message: "Enter the name of your cluster:", Default: clusterFlag},
Validate: validCluster,
},
{
Name: "storage",
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:"},
Validate: utils.ValidateStorageAccountName,
},
{
Name: "region",
Prompt: &survey.Select{Message: "Enter the region you want to deploy to:", Default: "eastus", Options: locations},
Validate: survey.Required,
},
{
Name: "resource",
Prompt: &survey.Input{Message: "Enter the name of the resource group to use:"},
Validate: utils.ValidateResourceGroupName,
},

resourceGroup, err := askAzureResourceGroup(ctx, clients.Groups)
if err != nil {
return
}

err = survey.Ask(azureSurvey, &resp)
storageAccount, err := askAzureStorageAccount(ctx, clients.Accounts)
if err != nil {
return
}

prov = &AzureProvider{
resp.Cluster,
resp.Resource,
prov = &AzureProvider{cluster,
resourceGroup,
"",
resp.Region,
map[string]interface{}{
"SubscriptionId": subId,
"TenantId": tenID,
"StorageAccount": resp.Storage,
},
location,
map[string]any{"SubscriptionId": subId, "TenantId": tenID, "StorageAccount": storageAccount},
nil,
clients,
}
Expand Down Expand Up @@ -443,7 +382,7 @@ func (az *AzureProvider) upsertStorageContainer(acc armstorage.Account, name str
u, _ := url.Parse(fmt.Sprintf(`https://%s.blob.core.windows.net`, accountName))
service := azblob.NewServiceURL(*u, p)
containerClient := service.NewContainerURL(name)
az.clients.Containers = containerClient
az.clients.Containers = &containerClient
}

_, err = az.clients.Containers.GetProperties(ctx, azblob.LeaseAccessConditions{})
Expand Down
147 changes: 147 additions & 0 deletions pkg/provider/azure_survey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package provider

import (
"context"

"github.com/AlecAivazis/survey/v2"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription"
"github.com/pluralsh/plural-cli/pkg/utils"
)

const createNewOption = "Create new..."

func askCluster() (string, error) {
cluster := ""
if err := survey.AskOne(
&survey.Input{Message: "Enter the name of your cluster:"},
&cluster, survey.WithValidator(validCluster),
); err != nil {
return "", err
}

return cluster, nil
}

func azureLocations(ctx context.Context, client *armsubscription.SubscriptionsClient, subscriptionID string) ([]string, error) {
locations := make([]string, 0)
pager := client.NewListLocationsPager(subscriptionID, nil)
for pager.More() {
page, err := pager.NextPage(ctx)
if err != nil {
return nil, err
}

for _, v := range page.Value {
if v != nil {
locations = append(locations, *v.Name)
}
}
}

return locations, nil
}

func askAzureLocation(ctx context.Context, client *armsubscription.SubscriptionsClient, subscriptionID string) (string, error) {
options, err := azureLocations(ctx, client, subscriptionID)
if err != nil {
return "", err
}

location := ""
if err = survey.AskOne(
&survey.Select{Message: "Select the location you want to deploy to:", Options: options, Default: "eastus"},
&location, survey.WithValidator(survey.Required),
); err != nil {
return "", err
}

return location, nil
}

func azureResourceGroups(ctx context.Context, client *armresources.ResourceGroupsClient) ([]string, error) {
groups := make([]string, 0)
pager := client.NewListPager(nil)
for pager.More() {
page, err := pager.NextPage(ctx)
if err != nil {
return nil, err
}

for _, v := range page.Value {
if v != nil {
groups = append(groups, *v.Name)
}
}
}

return groups, nil
}

func askAzureResourceGroup(ctx context.Context, client *armresources.ResourceGroupsClient) (string, error) {
options, err := azureResourceGroups(ctx, client)
if err != nil {
return "", err
}
options = append(options, createNewOption)

group := ""
if err = survey.AskOne(
&survey.Select{Message: "Select the resource group to use:", Options: options},
&group, survey.WithValidator(survey.Required),
); err != nil {
return "", err
}

if group == createNewOption {
if err = survey.AskOne(&survey.Input{Message: "Enter resource group name:"}, &group, survey.WithValidator(utils.ValidateResourceGroupName)); err != nil {
return "", err
}
}

return group, nil
}

func azureStorageAccounts(ctx context.Context, client *armstorage.AccountsClient) ([]string, error) {
accounts := make([]string, 0)
pager := client.NewListPager(nil)
for pager.More() {
page, err := pager.NextPage(ctx)
if err != nil {
return nil, err
}

for _, v := range page.Value {
if v != nil {
accounts = append(accounts, *v.Name)
}
}
}

return accounts, nil
}

func askAzureStorageAccount(ctx context.Context, client *armstorage.AccountsClient) (string, error) {
options, err := azureStorageAccounts(ctx, client)
if err != nil {
return "", err
}
options = append(options, createNewOption)

account := ""
if err = survey.AskOne(
&survey.Select{Message: "Select the storage account to use:", Options: options},
&account, survey.WithValidator(survey.Required),
); err != nil {
return "", err
}

if account == createNewOption {
if err = survey.AskOne(&survey.Input{Message: "Enter globally unique storage account name:"}, &account, survey.WithValidator(utils.ValidateStorageAccountName)); err != nil {
return "", err
}
}

return account, nil
}
Loading
Loading