acs-engine/cmd/upgrade.go

189 строки
5.5 KiB
Go

package cmd
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"github.com/Azure/acs-engine/pkg/acsengine"
"github.com/Azure/acs-engine/pkg/api"
"github.com/Azure/acs-engine/pkg/api/vlabs"
"github.com/Azure/acs-engine/pkg/armhelpers"
"github.com/Azure/acs-engine/pkg/i18n"
"github.com/Azure/acs-engine/pkg/operations/kubernetesupgrade"
"github.com/leonelquinteros/gotext"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
const (
upgradeName = "upgrade"
upgradeShortDescription = "upgrades an existing Kubernetes cluster"
upgradeLongDescription = "upgrades an existing Kubernetes cluster, first replacing masters, then nodes"
)
type upgradeCmd struct {
authArgs
// user input
resourceGroupName string
deploymentDirectory string
upgradeModelFile string
containerService *api.ContainerService
apiVersion string
location string
// derived
client armhelpers.ACSEngineClient
locale *gotext.Locale
nameSuffix string
agentPoolsToUpgrade []string
}
// NewUpgradeCmd run a command to upgrade a Kubernetes cluster
func newUpgradeCmd() *cobra.Command {
uc := upgradeCmd{}
upgradeCmd := &cobra.Command{
Use: upgradeName,
Short: upgradeShortDescription,
Long: upgradeLongDescription,
RunE: func(cmd *cobra.Command, args []string) error {
return uc.run(cmd, args)
},
}
f := upgradeCmd.Flags()
f.StringVar(&uc.location, "location", "", "location the cluster is deployed in")
f.StringVar(&uc.resourceGroupName, "resource-group", "", "the resource group where the cluster is deployed")
f.StringVar(&uc.deploymentDirectory, "deployment-dir", "", "the location of the output from `generate`")
f.StringVar(&uc.upgradeModelFile, "upgrademodel-file", "", "file path to upgrade API model")
addAuthFlags(&uc.authArgs, f)
return upgradeCmd
}
func (uc *upgradeCmd) validate(cmd *cobra.Command, args []string) {
log.Infoln("validating...")
var err error
uc.locale, err = i18n.LoadTranslations()
if err != nil {
log.Fatalf("error loading translation files: %s", err.Error())
}
if uc.resourceGroupName == "" {
cmd.Usage()
log.Fatal("--resource-group must be specified")
}
if uc.location == "" {
cmd.Usage()
log.Fatal("--location must be specified")
}
// TODO(colemick): add in the cmd annotation to help enable autocompletion
if uc.upgradeModelFile == "" {
cmd.Usage()
log.Fatal("--upgrademodel-file must be specified")
}
if uc.client, err = uc.authArgs.getClient(); err != nil {
log.Error("Failed to get client:", err)
}
if uc.deploymentDirectory == "" {
cmd.Usage()
log.Fatal("--deployment-dir must be specified")
}
_, err = uc.client.EnsureResourceGroup(uc.resourceGroupName, uc.location)
if err != nil {
log.Fatalln(err)
}
// load apimodel from the deployment directory
apiModelPath := path.Join(uc.deploymentDirectory, "apimodel.json")
if _, err = os.Stat(apiModelPath); os.IsNotExist(err) {
log.Fatalf("specified api model does not exist (%s)", apiModelPath)
}
apiloader := &api.Apiloader{
Translator: &i18n.Translator{
Locale: uc.locale,
},
}
uc.containerService, uc.apiVersion, err = apiloader.LoadContainerServiceFromFile(apiModelPath, true, nil)
if err != nil {
log.Fatalf("error parsing the api model: %s", err.Error())
}
if _, err = os.Stat(uc.upgradeModelFile); os.IsNotExist(err) {
log.Fatalf("specified upgrade model file does not exist (%s)", uc.upgradeModelFile)
}
// validate upgrade and set the Goal State
contents, err := ioutil.ReadFile(uc.upgradeModelFile)
if err != nil {
log.Fatalf("error reading file %s: %s", uc.upgradeModelFile, err.Error())
}
if err = apiloader.UpdateContainerServiceForUpgrade(contents, vlabs.APIVersion, uc.containerService, true); err != nil {
log.Fatalf("error loading ContainerService: %s", err.Error())
}
uc.client, err = uc.authArgs.getClient()
if err != nil {
log.Fatalf("failed to get client") // TODO: cleanup
}
// Read name suffix to identify nodes in the resource group that belong
// to this cluster.
// TODO: Also update to read namesuffix from the parameters file as
// user could have specified a name suffix instead of using the default
// value generated by ACS Engine
templatePath := path.Join(uc.deploymentDirectory, "azuredeploy.json")
contents, _ = ioutil.ReadFile(templatePath)
var template interface{}
json.Unmarshal(contents, &template)
templateMap := template.(map[string]interface{})
templateParameters := templateMap["parameters"].(map[string]interface{})
nameSuffixParam := templateParameters["nameSuffix"].(map[string]interface{})
uc.nameSuffix = nameSuffixParam["defaultValue"].(string)
log.Infoln(fmt.Sprintf("Name suffix: %s", uc.nameSuffix))
uc.agentPoolsToUpgrade = []string{}
log.Infoln(fmt.Sprintf("Gathering agent pool names..."))
for _, agentPool := range uc.containerService.Properties.AgentPoolProfiles {
uc.agentPoolsToUpgrade = append(uc.agentPoolsToUpgrade, agentPool.Name)
}
}
func (uc *upgradeCmd) run(cmd *cobra.Command, args []string) error {
uc.validate(cmd, args)
upgradeCluster := kubernetesupgrade.UpgradeCluster{
Translator: &i18n.Translator{
Locale: uc.locale,
},
Client: uc.client,
}
kubeConfig, err := acsengine.GenerateKubeConfig(uc.containerService.Properties, uc.location)
if err != nil {
log.Fatalf("failed to generate kube config") // TODO: cleanup
}
if err = upgradeCluster.UpgradeCluster(uc.authArgs.SubscriptionID, kubeConfig, uc.resourceGroupName,
uc.containerService, uc.nameSuffix, uc.agentPoolsToUpgrade); err != nil {
log.Fatalf("Error upgrading cluster: %s \n", err.Error())
}
return nil
}