зеркало из https://github.com/Azure/acs-engine.git
465 строки
17 KiB
Go
465 строки
17 KiB
Go
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT license.
|
|
|
|
package api
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"reflect"
|
|
|
|
"github.com/Azure/acs-engine/pkg/api/agentPoolOnlyApi/v20170831"
|
|
"github.com/Azure/acs-engine/pkg/api/agentPoolOnlyApi/v20180331"
|
|
apvlabs "github.com/Azure/acs-engine/pkg/api/agentPoolOnlyApi/vlabs"
|
|
"github.com/Azure/acs-engine/pkg/api/common"
|
|
"github.com/Azure/acs-engine/pkg/api/v20160330"
|
|
"github.com/Azure/acs-engine/pkg/api/v20160930"
|
|
"github.com/Azure/acs-engine/pkg/api/v20170131"
|
|
"github.com/Azure/acs-engine/pkg/api/v20170701"
|
|
"github.com/Azure/acs-engine/pkg/api/vlabs"
|
|
"github.com/Azure/acs-engine/pkg/helpers"
|
|
"github.com/Azure/acs-engine/pkg/i18n"
|
|
"github.com/pkg/errors"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Apiloader represents the object that loads api model
|
|
type Apiloader struct {
|
|
Translator *i18n.Translator
|
|
}
|
|
|
|
// LoadContainerServiceFromFile loads an ACS Cluster API Model from a JSON file
|
|
func (a *Apiloader) LoadContainerServiceFromFile(jsonFile string, validate, isUpdate bool, existingContainerService *ContainerService) (*ContainerService, string, error) {
|
|
contents, e := ioutil.ReadFile(jsonFile)
|
|
if e != nil {
|
|
return nil, "", a.Translator.Errorf("error reading file %s: %s", jsonFile, e.Error())
|
|
}
|
|
return a.DeserializeContainerService(contents, validate, isUpdate, existingContainerService)
|
|
}
|
|
|
|
// LoadDefaultContainerServiceProperties loads the default API model
|
|
func LoadDefaultContainerServiceProperties() (TypeMeta, *vlabs.Properties) {
|
|
return TypeMeta{APIVersion: vlabs.APIVersion}, &vlabs.Properties{
|
|
OrchestratorProfile: &vlabs.OrchestratorProfile{
|
|
OrchestratorType: "kubernetes",
|
|
},
|
|
MasterProfile: &vlabs.MasterProfile{
|
|
Count: 3,
|
|
VMSize: "Standard_DS2_v2",
|
|
OSDiskSizeGB: 200,
|
|
},
|
|
AgentPoolProfiles: []*vlabs.AgentPoolProfile{
|
|
{
|
|
Name: "agent",
|
|
Count: 3,
|
|
VMSize: "Standard_DS2_v2",
|
|
OSDiskSizeGB: 200,
|
|
},
|
|
},
|
|
LinuxProfile: &vlabs.LinuxProfile{AdminUsername: "azureuser"},
|
|
}
|
|
}
|
|
|
|
// DeserializeContainerService loads an ACS Cluster API Model, validates it, and returns the unversioned representation
|
|
func (a *Apiloader) DeserializeContainerService(contents []byte, validate, isUpdate bool, existingContainerService *ContainerService) (*ContainerService, string, error) {
|
|
m := &TypeMeta{}
|
|
if err := json.Unmarshal(contents, &m); err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
version := m.APIVersion
|
|
service, err := a.LoadContainerService(contents, version, validate, isUpdate, existingContainerService)
|
|
if service == nil || err != nil {
|
|
if isAgentPoolOnlyClusterJSON(contents) {
|
|
log.Info("No masterProfile: interpreting API model as agent pool only")
|
|
service, _, err := a.LoadContainerServiceForAgentPoolOnlyCluster(contents, version, validate, isUpdate, "", existingContainerService)
|
|
return service, version, err
|
|
}
|
|
}
|
|
return service, version, err
|
|
}
|
|
|
|
// LoadContainerService loads an ACS Cluster API Model, validates it, and returns the unversioned representation
|
|
func (a *Apiloader) LoadContainerService(
|
|
contents []byte,
|
|
version string,
|
|
validate, isUpdate bool,
|
|
existingContainerService *ContainerService) (*ContainerService, error) {
|
|
var curOrchVersion string
|
|
hasExistingCS := existingContainerService != nil
|
|
if hasExistingCS {
|
|
curOrchVersion = existingContainerService.Properties.OrchestratorProfile.OrchestratorVersion
|
|
}
|
|
switch version {
|
|
case v20160930.APIVersion:
|
|
containerService := &v20160930.ContainerService{}
|
|
if e := json.Unmarshal(contents, &containerService); e != nil {
|
|
return nil, e
|
|
}
|
|
if hasExistingCS {
|
|
vecs := ConvertContainerServiceToV20160930(existingContainerService)
|
|
if e := containerService.Merge(vecs); e != nil {
|
|
return nil, e
|
|
}
|
|
}
|
|
setContainerServiceDefaultsv20160930(containerService)
|
|
if containerService.Properties == nil {
|
|
return nil, errors.New("missing ContainerService Properties")
|
|
}
|
|
if e := containerService.Properties.Validate(); validate && e != nil {
|
|
return nil, e
|
|
}
|
|
unversioned := ConvertV20160930ContainerService(containerService)
|
|
if curOrchVersion != "" {
|
|
unversioned.Properties.OrchestratorProfile.OrchestratorVersion = curOrchVersion
|
|
}
|
|
return unversioned, nil
|
|
case v20160330.APIVersion:
|
|
containerService := &v20160330.ContainerService{}
|
|
if e := json.Unmarshal(contents, &containerService); e != nil {
|
|
return nil, e
|
|
}
|
|
if hasExistingCS {
|
|
vecs := ConvertContainerServiceToV20160330(existingContainerService)
|
|
if e := containerService.Merge(vecs); e != nil {
|
|
return nil, e
|
|
}
|
|
}
|
|
setContainerServiceDefaultsv20160330(containerService)
|
|
if containerService.Properties == nil {
|
|
return nil, errors.New("missing ContainerService Properties")
|
|
}
|
|
if e := containerService.Properties.Validate(); validate && e != nil {
|
|
return nil, e
|
|
}
|
|
unversioned := ConvertV20160330ContainerService(containerService)
|
|
if curOrchVersion != "" {
|
|
unversioned.Properties.OrchestratorProfile.OrchestratorVersion = curOrchVersion
|
|
}
|
|
return unversioned, nil
|
|
|
|
case v20170131.APIVersion:
|
|
containerService := &v20170131.ContainerService{}
|
|
if e := json.Unmarshal(contents, &containerService); e != nil {
|
|
return nil, e
|
|
}
|
|
if hasExistingCS {
|
|
vecs := ConvertContainerServiceToV20170131(existingContainerService)
|
|
if e := containerService.Merge(vecs); e != nil {
|
|
return nil, e
|
|
}
|
|
}
|
|
setContainerServiceDefaultsv20170131(containerService)
|
|
if containerService.Properties == nil {
|
|
return nil, errors.New("missing ContainerService Properties")
|
|
}
|
|
if e := containerService.Properties.Validate(); validate && e != nil {
|
|
return nil, e
|
|
}
|
|
unversioned := ConvertV20170131ContainerService(containerService)
|
|
if curOrchVersion != "" {
|
|
unversioned.Properties.OrchestratorProfile.OrchestratorVersion = curOrchVersion
|
|
}
|
|
return unversioned, nil
|
|
|
|
case v20170701.APIVersion:
|
|
containerService := &v20170701.ContainerService{}
|
|
if e := json.Unmarshal(contents, &containerService); e != nil {
|
|
return nil, e
|
|
}
|
|
if hasExistingCS {
|
|
vecs := ConvertContainerServiceToV20170701(existingContainerService)
|
|
if e := containerService.Merge(vecs); e != nil {
|
|
return nil, e
|
|
}
|
|
}
|
|
if containerService.Properties == nil {
|
|
return nil, errors.New("missing ContainerService Properties")
|
|
}
|
|
if e := containerService.Properties.Validate(isUpdate); validate && e != nil {
|
|
return nil, e
|
|
}
|
|
unversioned := ConvertV20170701ContainerService(containerService, isUpdate)
|
|
if curOrchVersion != "" &&
|
|
(containerService.Properties.OrchestratorProfile == nil ||
|
|
containerService.Properties.OrchestratorProfile.OrchestratorVersion == "") {
|
|
unversioned.Properties.OrchestratorProfile.OrchestratorVersion = curOrchVersion
|
|
}
|
|
return unversioned, nil
|
|
|
|
case vlabs.APIVersion:
|
|
containerService := &vlabs.ContainerService{}
|
|
if e := json.Unmarshal(contents, &containerService); e != nil {
|
|
return nil, e
|
|
}
|
|
if e := checkJSONKeys(contents, reflect.TypeOf(*containerService), reflect.TypeOf(TypeMeta{})); e != nil {
|
|
return nil, e
|
|
}
|
|
if hasExistingCS {
|
|
vecs := ConvertContainerServiceToVLabs(existingContainerService)
|
|
if e := containerService.Merge(vecs); e != nil {
|
|
return nil, e
|
|
}
|
|
}
|
|
if containerService.Properties == nil {
|
|
return nil, errors.New("missing ContainerService Properties")
|
|
}
|
|
if e := containerService.Properties.Validate(isUpdate); validate && e != nil {
|
|
return nil, e
|
|
}
|
|
unversioned := ConvertVLabsContainerService(containerService, isUpdate)
|
|
if curOrchVersion != "" &&
|
|
(containerService.Properties.OrchestratorProfile == nil ||
|
|
(containerService.Properties.OrchestratorProfile.OrchestratorVersion == "" &&
|
|
containerService.Properties.OrchestratorProfile.OrchestratorRelease == "")) {
|
|
unversioned.Properties.OrchestratorProfile.OrchestratorVersion = curOrchVersion
|
|
}
|
|
return unversioned, nil
|
|
|
|
default:
|
|
return nil, a.Translator.Errorf("unrecognized APIVersion '%s'", version)
|
|
}
|
|
}
|
|
|
|
// LoadContainerServiceForAgentPoolOnlyCluster loads an ACS Cluster API Model, validates it, and returns the unversioned representation
|
|
func (a *Apiloader) LoadContainerServiceForAgentPoolOnlyCluster(
|
|
contents []byte,
|
|
version string,
|
|
validate, isUpdate bool,
|
|
defaultKubernetesVersion string,
|
|
existingContainerService *ContainerService) (*ContainerService, bool, error) {
|
|
hasExistingCS := existingContainerService != nil
|
|
IsSSHAutoGenerated := false
|
|
hasWindows := false
|
|
switch version {
|
|
case v20170831.APIVersion:
|
|
managedCluster := &v20170831.ManagedCluster{}
|
|
if e := json.Unmarshal(contents, &managedCluster); e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
// verify managedCluster.Properties is not nil for creating case
|
|
if managedCluster.Properties == nil {
|
|
if !isUpdate {
|
|
return nil, false, a.Translator.Errorf("properties object in managed cluster should not be nil")
|
|
}
|
|
managedCluster.Properties = &v20170831.Properties{}
|
|
}
|
|
|
|
if hasExistingCS {
|
|
vemc := ConvertContainerServiceToV20170831AgentPoolOnly(existingContainerService)
|
|
if e := managedCluster.Merge(vemc); e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
}
|
|
|
|
// use defaultKubernetesVersion arg if no version was supplied in the request contents
|
|
if managedCluster.Properties.KubernetesVersion == "" && defaultKubernetesVersion != "" {
|
|
if !common.IsSupportedKubernetesVersion(defaultKubernetesVersion, isUpdate, hasWindows) {
|
|
return nil, IsSSHAutoGenerated, a.Translator.Errorf("The selected orchestrator version '%s' is not supported", defaultKubernetesVersion)
|
|
}
|
|
managedCluster.Properties.KubernetesVersion = defaultKubernetesVersion
|
|
}
|
|
|
|
// verify orchestrator version
|
|
if len(managedCluster.Properties.KubernetesVersion) > 0 && !common.IsSupportedKubernetesVersion(managedCluster.Properties.KubernetesVersion, isUpdate, hasWindows) {
|
|
return nil, IsSSHAutoGenerated, a.Translator.Errorf("The selected orchestrator version '%s' is not supported", managedCluster.Properties.KubernetesVersion)
|
|
}
|
|
|
|
if e := managedCluster.Properties.Validate(); validate && e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
|
|
return ConvertV20170831AgentPoolOnly(managedCluster), false, nil
|
|
case v20180331.APIVersion:
|
|
managedCluster := &v20180331.ManagedCluster{}
|
|
if e := json.Unmarshal(contents, &managedCluster); e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
// verify managedCluster.Properties is not nil for creating case
|
|
if managedCluster.Properties == nil {
|
|
if !isUpdate {
|
|
return nil, false, a.Translator.Errorf("properties object in managed cluster should not be nil")
|
|
}
|
|
managedCluster.Properties = &v20180331.Properties{}
|
|
}
|
|
|
|
if hasExistingCS {
|
|
vemc := ConvertContainerServiceToV20180331AgentPoolOnly(existingContainerService)
|
|
if e := managedCluster.Merge(vemc); e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
}
|
|
|
|
// use defaultKubernetesVersion arg if no version was supplied in the request contents
|
|
if managedCluster.Properties.KubernetesVersion == "" && defaultKubernetesVersion != "" {
|
|
if !common.IsSupportedKubernetesVersion(defaultKubernetesVersion, isUpdate, hasWindows) {
|
|
return nil, IsSSHAutoGenerated, a.Translator.Errorf("The selected orchestrator version '%s' is not supported", defaultKubernetesVersion)
|
|
}
|
|
if hasExistingCS {
|
|
managedCluster.Properties.KubernetesVersion = existingContainerService.Properties.OrchestratorProfile.OrchestratorVersion
|
|
} else {
|
|
managedCluster.Properties.KubernetesVersion = defaultKubernetesVersion
|
|
}
|
|
}
|
|
|
|
// verify orchestrator version
|
|
if len(managedCluster.Properties.KubernetesVersion) > 0 && !common.IsSupportedKubernetesVersion(managedCluster.Properties.KubernetesVersion, isUpdate, hasWindows) {
|
|
return nil, IsSSHAutoGenerated, a.Translator.Errorf("The selected orchestrator version '%s' is not supported", managedCluster.Properties.KubernetesVersion)
|
|
}
|
|
|
|
if e := managedCluster.Properties.Validate(); validate && e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
|
|
// only generate ssh key on new cluster
|
|
if !hasExistingCS && managedCluster.Properties.LinuxProfile == nil {
|
|
linuxProfile := &v20180331.LinuxProfile{}
|
|
linuxProfile.AdminUsername = "azureuser"
|
|
_, publicKey, err := helpers.CreateSSH(rand.Reader, a.Translator)
|
|
if err != nil {
|
|
return nil, IsSSHAutoGenerated, err
|
|
}
|
|
linuxProfile.SSH.PublicKeys = []v20180331.PublicKey{{KeyData: publicKey}}
|
|
managedCluster.Properties.LinuxProfile = linuxProfile
|
|
IsSSHAutoGenerated = true
|
|
}
|
|
return ConvertV20180331AgentPoolOnly(managedCluster), IsSSHAutoGenerated, nil
|
|
case apvlabs.APIVersion:
|
|
managedCluster := &apvlabs.ManagedCluster{}
|
|
if e := json.Unmarshal(contents, &managedCluster); e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
if e := managedCluster.Properties.Validate(); validate && e != nil {
|
|
return nil, IsSSHAutoGenerated, e
|
|
}
|
|
return ConvertVLabsAgentPoolOnly(managedCluster), IsSSHAutoGenerated, nil
|
|
default:
|
|
return nil, IsSSHAutoGenerated, a.Translator.Errorf("unrecognized APIVersion in LoadContainerServiceForAgentPoolOnlyCluster '%s'", version)
|
|
}
|
|
}
|
|
|
|
// SerializeContainerService takes an unversioned container service and returns the bytes
|
|
func (a *Apiloader) SerializeContainerService(containerService *ContainerService, version string) ([]byte, error) {
|
|
if containerService.Properties != nil && containerService.Properties.HostedMasterProfile != nil {
|
|
b, err := a.serializeHostedContainerService(containerService, version)
|
|
if err == nil && b != nil {
|
|
return b, nil
|
|
}
|
|
}
|
|
|
|
switch version {
|
|
case v20160930.APIVersion:
|
|
v20160930ContainerService := ConvertContainerServiceToV20160930(containerService)
|
|
armContainerService := &V20160930ARMContainerService{}
|
|
armContainerService.ContainerService = v20160930ContainerService
|
|
armContainerService.APIVersion = version
|
|
b, err := helpers.JSONMarshalIndent(armContainerService, "", " ", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
|
|
case v20160330.APIVersion:
|
|
v20160330ContainerService := ConvertContainerServiceToV20160330(containerService)
|
|
armContainerService := &V20160330ARMContainerService{}
|
|
armContainerService.ContainerService = v20160330ContainerService
|
|
armContainerService.APIVersion = version
|
|
b, err := helpers.JSONMarshalIndent(armContainerService, "", " ", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
|
|
case v20170131.APIVersion:
|
|
v20170131ContainerService := ConvertContainerServiceToV20170131(containerService)
|
|
armContainerService := &V20170131ARMContainerService{}
|
|
armContainerService.ContainerService = v20170131ContainerService
|
|
armContainerService.APIVersion = version
|
|
b, err := helpers.JSONMarshalIndent(armContainerService, "", " ", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
|
|
case v20170701.APIVersion:
|
|
v20170701ContainerService := ConvertContainerServiceToV20170701(containerService)
|
|
armContainerService := &V20170701ARMContainerService{}
|
|
armContainerService.ContainerService = v20170701ContainerService
|
|
armContainerService.APIVersion = version
|
|
b, err := helpers.JSONMarshalIndent(armContainerService, "", " ", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
|
|
case vlabs.APIVersion:
|
|
vlabsContainerService := ConvertContainerServiceToVLabs(containerService)
|
|
armContainerService := &VlabsARMContainerService{}
|
|
armContainerService.ContainerService = vlabsContainerService
|
|
armContainerService.APIVersion = version
|
|
b, err := helpers.JSONMarshalIndent(armContainerService, "", " ", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
|
|
default:
|
|
return nil, a.Translator.Errorf("invalid version %s for conversion back from unversioned object", version)
|
|
}
|
|
}
|
|
|
|
func (a *Apiloader) serializeHostedContainerService(containerService *ContainerService, version string) ([]byte, error) {
|
|
switch version {
|
|
case v20170831.APIVersion:
|
|
v20170831ContainerService := ConvertContainerServiceToV20170831AgentPoolOnly(containerService)
|
|
armContainerService := &V20170831ARMManagedContainerService{}
|
|
armContainerService.ManagedCluster = v20170831ContainerService
|
|
armContainerService.APIVersion = version
|
|
b, err := helpers.JSONMarshalIndent(armContainerService, "", " ", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
case v20180331.APIVersion:
|
|
v20180331ContainerService := ConvertContainerServiceToV20180331AgentPoolOnly(containerService)
|
|
armContainerService := &V20180331ARMManagedContainerService{}
|
|
armContainerService.ManagedCluster = v20180331ContainerService
|
|
armContainerService.APIVersion = version
|
|
b, err := helpers.JSONMarshalIndent(armContainerService, "", " ", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
default:
|
|
return nil, a.Translator.Errorf("invalid version %s for conversion back from unversioned object", version)
|
|
}
|
|
}
|
|
|
|
// Sets default container service property values for any appropriate zero values
|
|
func setContainerServiceDefaultsv20160930(c *v20160930.ContainerService) {
|
|
if c.Properties.OrchestratorProfile == nil {
|
|
c.Properties.OrchestratorProfile = &v20160930.OrchestratorProfile{
|
|
OrchestratorType: v20160930.DCOS,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sets default container service property values for any appropriate zero values
|
|
func setContainerServiceDefaultsv20160330(c *v20160330.ContainerService) {
|
|
if c.Properties.OrchestratorProfile == nil {
|
|
c.Properties.OrchestratorProfile = &v20160330.OrchestratorProfile{
|
|
OrchestratorType: v20160330.DCOS,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sets default container service property values for any appropriate zero values
|
|
func setContainerServiceDefaultsv20170131(c *v20170131.ContainerService) {
|
|
if c.Properties.OrchestratorProfile == nil {
|
|
c.Properties.OrchestratorProfile = &v20170131.OrchestratorProfile{
|
|
OrchestratorType: v20170131.DCOS,
|
|
}
|
|
}
|
|
}
|