2020-02-28 22:51:14 +03:00
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"text/tabwriter"
|
|
|
|
|
|
|
|
"github.com/Azure/aks-engine/pkg/armhelpers"
|
|
|
|
"github.com/Azure/aks-engine/pkg/helpers"
|
|
|
|
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-06-01/subscriptions"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
locationsName = "get-locations"
|
|
|
|
locationsShortDescription = "Show Azure locations where an AKS Engine cluster can be deployed"
|
2020-04-07 04:00:50 +03:00
|
|
|
locationsLongDescription = locationsShortDescription + developersOnly
|
2020-02-28 22:51:14 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
chinaEast2DisplayName = "China East 2"
|
|
|
|
chinaEast2Name = "chinaeast2"
|
|
|
|
chinaEastDisplayName = "China East"
|
|
|
|
chinaEastName = "chinaeast"
|
|
|
|
chinaNorth2DisplayName = "China North 2"
|
|
|
|
chinaNorth2Name = "chinanorth2"
|
|
|
|
chinaNorthDisplayName = "China North"
|
|
|
|
chinaNorthName = "chinanorth"
|
|
|
|
centralUsEuapDisplayName = "Central US EUAP (Canary)"
|
|
|
|
centralUsEuapName = "centraluseuap"
|
|
|
|
eastUs2EuapDisplayName = "East US 2 EUAP (Canary)"
|
|
|
|
eastUs2EuapName = "eastus2euap"
|
|
|
|
germanyCentralDisplayName = "Germany Central"
|
|
|
|
germanyCentralName = "germanycentral"
|
|
|
|
germanyNortheastDisplayName = "Germany Northeast"
|
|
|
|
germanyNortheastName = "germanynortheast"
|
|
|
|
usDodCentralDisplayName = "US DoD Central"
|
|
|
|
usDodCentralName = "usdodcentral"
|
|
|
|
usDodEastDisplayName = "US Dod East"
|
|
|
|
usDodEastName = "usdodeast"
|
|
|
|
usGovArizonaDisplayName = "US Gov Arizona"
|
|
|
|
usGovArizonaName = "usgovarizona"
|
|
|
|
usGovIowaDisplayName = "US Gov Iowa"
|
|
|
|
usGovIowaName = "usgoviowa"
|
|
|
|
usGovTexasDisplayName = "US Gov Texas"
|
|
|
|
usGovTexasName = "usgovtexas"
|
|
|
|
usGovVirginiaDisplayName = "US Gov Virginia"
|
|
|
|
usGovVirginiaName = "usgovvirginia"
|
|
|
|
notAvailable = "N/A"
|
|
|
|
)
|
|
|
|
|
|
|
|
var locationsOutputFormatOptions = append(outputFormatOptions, "code")
|
|
|
|
|
|
|
|
type LocationsCmd struct {
|
|
|
|
authProvider
|
|
|
|
|
|
|
|
// user input
|
|
|
|
output string
|
|
|
|
|
|
|
|
// derived
|
|
|
|
client armhelpers.AKSEngineClient
|
|
|
|
}
|
|
|
|
|
|
|
|
func newGetLocationsCmd() *cobra.Command {
|
|
|
|
glc := LocationsCmd{
|
|
|
|
authProvider: &authArgs{},
|
|
|
|
}
|
|
|
|
|
|
|
|
command := &cobra.Command{
|
|
|
|
Use: locationsName,
|
|
|
|
Short: locationsShortDescription,
|
|
|
|
Long: locationsLongDescription,
|
|
|
|
Hidden: true,
|
|
|
|
RunE: glc.run,
|
|
|
|
}
|
|
|
|
|
|
|
|
f := command.Flags()
|
|
|
|
getVersionsCmdDescription := fmt.Sprintf("Output format. Allowed values: %s",
|
|
|
|
strings.Join(locationsOutputFormatOptions, ", "))
|
|
|
|
f.StringVarP(&glc.output, "output", "o", "human", getVersionsCmdDescription)
|
|
|
|
addAuthFlags(glc.getAuthArgs(), f)
|
|
|
|
|
|
|
|
return command
|
|
|
|
}
|
|
|
|
|
|
|
|
func (glc *LocationsCmd) run(cmd *cobra.Command, args []string) error {
|
|
|
|
log.Debugf("Start listing Azure locations")
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// validate --output flag value before making API call
|
|
|
|
outputFlagValid := false
|
|
|
|
for _, opt := range locationsOutputFormatOptions {
|
|
|
|
if glc.output == opt {
|
|
|
|
outputFlagValid = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !outputFlagValid {
|
|
|
|
return errors.New(fmt.Sprintf("invalid output format: \"%s\". Allowed values: %s.\n",
|
|
|
|
glc.output, strings.Join(locationsOutputFormatOptions, ", ")))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = glc.getAuthArgs().validateAuthArgs(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if glc.client, err = glc.authProvider.getClient(); err != nil {
|
|
|
|
return errors.Wrap(err, "failed to get client")
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), armhelpers.DefaultARMOperationTimeout)
|
|
|
|
defer cancel()
|
|
|
|
list, err := glc.client.ListLocations(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to list locations")
|
|
|
|
}
|
|
|
|
locations := *list
|
|
|
|
|
|
|
|
specialLocations := []subscriptions.Location{
|
|
|
|
// Azure China Cloud locations
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &chinaEastName,
|
|
|
|
DisplayName: &chinaEastDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &chinaEast2Name,
|
|
|
|
DisplayName: &chinaEast2DisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &chinaNorthName,
|
|
|
|
DisplayName: &chinaNorthDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &chinaNorth2Name,
|
|
|
|
DisplayName: &chinaNorth2DisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
// Canary locations
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: ¢ralUsEuapName,
|
|
|
|
DisplayName: ¢ralUsEuapDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &eastUs2EuapName,
|
|
|
|
DisplayName: &eastUs2EuapDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
// US DoD locations
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &usDodCentralName,
|
|
|
|
DisplayName: &usDodCentralDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &usDodEastName,
|
|
|
|
DisplayName: &usDodEastDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
// US Gov locations
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &usGovArizonaName,
|
|
|
|
DisplayName: &usGovArizonaDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &usGovIowaName,
|
|
|
|
DisplayName: &usGovIowaDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &usGovTexasName,
|
|
|
|
DisplayName: &usGovTexasDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &usGovVirginiaName,
|
|
|
|
DisplayName: &usGovVirginiaDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
// Germany locations
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &germanyCentralName,
|
|
|
|
DisplayName: &germanyCentralDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: ¬Available,
|
|
|
|
Name: &germanyNortheastName,
|
|
|
|
DisplayName: &germanyNortheastDisplayName,
|
|
|
|
Latitude: ¬Available,
|
|
|
|
Longitude: ¬Available,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
// Add special locations if they aren't already in the list
|
|
|
|
for _, s := range specialLocations {
|
|
|
|
found := false
|
|
|
|
for _, l := range locations {
|
|
|
|
if l.Name == s.Name {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
locations = append(locations, s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort the locations by name
|
|
|
|
sort.Slice(locations, func(i, j int) bool {
|
|
|
|
return *locations[i].Name < *locations[j].Name
|
|
|
|
})
|
|
|
|
|
|
|
|
switch glc.output {
|
|
|
|
case "json":
|
|
|
|
data, jsonErr := helpers.JSONMarshalIndent(locations, "", " ", false)
|
|
|
|
if jsonErr != nil {
|
|
|
|
return jsonErr
|
|
|
|
}
|
|
|
|
fmt.Println(string(data))
|
|
|
|
case "code":
|
|
|
|
b := strings.Builder{}
|
|
|
|
b.WriteString(`// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
package helpers
|
|
|
|
|
|
|
|
// GetAzureLocations provides all available Azure cloud locations.
|
|
|
|
//
|
|
|
|
// Code generated for package helpers by aks-engine DO NOT EDIT. (@generated)
|
|
|
|
//
|
|
|
|
// To generate this code, run the command:
|
|
|
|
// aks-engine get-locations --output=code
|
|
|
|
func GetAzureLocations() []string {
|
|
|
|
return []string{
|
|
|
|
`)
|
|
|
|
for _, l := range locations {
|
|
|
|
b.WriteString(fmt.Sprintf("\t\t\"%s\",\n", *l.Name))
|
|
|
|
}
|
|
|
|
b.WriteString("\t}\n}")
|
|
|
|
fmt.Println(b.String())
|
|
|
|
case "human":
|
|
|
|
w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', tabwriter.FilterHTML)
|
|
|
|
fmt.Fprintln(w, "Location\tName\tLatitude\tLongitude")
|
|
|
|
for _, location := range locations {
|
|
|
|
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
|
|
|
|
*location.Name, *location.DisplayName, *location.Latitude, *location.Longitude)
|
|
|
|
}
|
|
|
|
w.Flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("Done listing Azure locations")
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|