forked from Azure/aks-engine-azurestack
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: "aks-engine get-skus" command (#2772)
* refactor: expose Azure VM SKUs data structure * feat: "aks-engine get-skus" command * refactor: separate skus into constants and funcs * style: remove extra newline * fix: validate before making Azure API call * test: add cmd unit test * test: add azurestack UTs * ci: update code generation script and Makefile target * chore: add new SKUs found by "get-skus" * fix: leave unimplemented on Azure Stack * chore: add new SKUs found by "get-skus" * refactor: share a string * chore: backfill some old SKUs
- Loading branch information
Showing
22 changed files
with
7,384 additions
and
1,547 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
// 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/pkg/errors" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
const ( | ||
developersOnly = "\n\nThis command is unsupported and intended to be used only by AKS Engine developers." | ||
skusName = "get-skus" | ||
skusShortDescription = "Show Azure VM SKUs that can be used to deploy an AKS Engine cluster" | ||
skusLongDescription = skusShortDescription + developersOnly | ||
) | ||
|
||
var skusOutputFormatOptions = append(outputFormatOptions, "code") | ||
|
||
type SkusCmd struct { | ||
authProvider | ||
|
||
// user input | ||
output string | ||
|
||
// derived | ||
client armhelpers.AKSEngineClient | ||
} | ||
|
||
func newGetSkusCmd() *cobra.Command { | ||
vmc := SkusCmd{ | ||
authProvider: &authArgs{}, | ||
} | ||
|
||
command := &cobra.Command{ | ||
Use: skusName, | ||
Short: skusShortDescription, | ||
Long: skusLongDescription, | ||
Hidden: true, | ||
RunE: vmc.run, | ||
} | ||
|
||
f := command.Flags() | ||
outputFlagDescription := fmt.Sprintf("Output format. Allowed values: %s", | ||
strings.Join(skusOutputFormatOptions, ", ")) | ||
f.StringVarP(&vmc.output, "output", "o", "human", outputFlagDescription) | ||
addAuthFlags(vmc.getAuthArgs(), f) | ||
|
||
return command | ||
} | ||
|
||
func (vmc *SkusCmd) run(cmd *cobra.Command, args []string) error { | ||
log.Debugf("Start listing VM SKUs") | ||
|
||
var err error | ||
|
||
// validate --output flag value before making API call | ||
outputFlagValid := false | ||
for _, opt := range skusOutputFormatOptions { | ||
if vmc.output == opt { | ||
outputFlagValid = true | ||
break | ||
} | ||
} | ||
if !outputFlagValid { | ||
return errors.New(fmt.Sprintf("invalid output format: \"%s\". Allowed values: %s.\n", | ||
vmc.output, strings.Join(skusOutputFormatOptions, ", "))) | ||
} | ||
|
||
if err = vmc.getAuthArgs().validateAuthArgs(); err != nil { | ||
return err | ||
} | ||
|
||
if vmc.client, err = vmc.authProvider.getClient(); err != nil { | ||
return errors.Wrap(err, "failed to get client") | ||
} | ||
|
||
// List Resource SKUs | ||
ctx, cancel := context.WithTimeout(context.Background(), armhelpers.DefaultARMOperationTimeout) | ||
defer cancel() | ||
page, err := vmc.client.ListResourceSkus(ctx, "") | ||
if err != nil { | ||
return errors.Wrap(err, "failed to list resource SKUs") | ||
} | ||
skus := helpers.VMSkus | ||
if page != nil { | ||
for _, r := range page.Values() { | ||
name := *r.Name | ||
if !strings.HasPrefix(name, "Standard_") || strings.HasSuffix(name, "_Promo") { | ||
continue | ||
} | ||
// Add to the list if the SKU isn't already present | ||
found := false | ||
for _, s := range skus { | ||
if name == s.Name { | ||
found = true | ||
break | ||
} | ||
} | ||
if !found { | ||
acceleratedNetworking := false | ||
if r.Capabilities != nil { | ||
for _, c := range *r.Capabilities { | ||
if c.Name != nil && *c.Name == "AcceleratedNetworkingEnabled" { | ||
if c.Value != nil && strings.EqualFold(*c.Value, "True") { | ||
acceleratedNetworking = true | ||
} | ||
} | ||
} | ||
} | ||
skus = append(skus, helpers.VMSku{ | ||
Name: name, | ||
AcceleratedNetworking: acceleratedNetworking, | ||
StorageAccountType: storageAccountType(name), | ||
}) | ||
} | ||
} | ||
} | ||
|
||
// Sort the SKUs by name | ||
sort.Slice(skus, func(i, j int) bool { | ||
return skus[i].Name < skus[j].Name | ||
}) | ||
|
||
switch vmc.output { | ||
case "json": | ||
data, jsonErr := helpers.JSONMarshalIndent(skus, "", " ", 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 | ||
// GetKubernetesAllowedVMSKUs provides the allowed sizes for Kubernetes agent VMs. | ||
// | ||
// Code generated for package helpers by aks-engine DO NOT EDIT. (@generated) | ||
// | ||
// To generate this code, run the command: | ||
// aks-engine get-skus --output=code | ||
type VMSku struct { | ||
Name string | ||
StorageAccountType string | ||
AcceleratedNetworking bool | ||
} | ||
var VMSkus = []VMSku{ | ||
`) | ||
formatStr := "\t{\n\t\tName: \"%s\",\n\t\tStorageAccountType: \"%s\",\n\t\tAcceleratedNetworking: %t,\n\t},\n" | ||
for _, s := range skus { | ||
b.WriteString(fmt.Sprintf(formatStr, s.Name, s.StorageAccountType, s.AcceleratedNetworking)) | ||
} | ||
b.WriteString("}") | ||
fmt.Println(b.String()) | ||
case "human": | ||
w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', tabwriter.FilterHTML) | ||
fmt.Fprintln(w, "Name\tStorage Account Type\tAccelerated Networking Support") | ||
for _, sku := range skus { | ||
fmt.Fprintf(w, "%s\t%s\t%t\n", sku.Name, sku.StorageAccountType, sku.AcceleratedNetworking) | ||
} | ||
w.Flush() | ||
} | ||
|
||
log.Debugf("Done listing VM SKUs") | ||
|
||
return err | ||
} | ||
|
||
func storageAccountType(skuName string) string { | ||
parts := strings.Split(skuName, "_") | ||
if len(parts) > 1 { | ||
if strings.Contains(strings.ToUpper(parts[1]), "S") { | ||
return "Premium_LRS" | ||
} | ||
} | ||
return "Standard_LRS" | ||
} |
Oops, something went wrong.