зеркало из https://github.com/Azure/aks-engine.git
Merge pull request #4 from Azure/anhowe-kubernetes
Add Kubernetes, VNET support for all orchestrators, volume support for all orchestrators, windows support in swarm
This commit is contained in:
Коммит
a210a4f714
|
@ -0,0 +1,5 @@
|
|||
*.anthony.json
|
||||
deployVM0.ps1
|
||||
noparams.json
|
||||
output*
|
||||
acstgen.exe
|
|
@ -6,10 +6,11 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"./api/vlabs"
|
||||
"./clustertemplate"
|
||||
"./tgen"
|
||||
)
|
||||
|
||||
// loadAcsCluster loads an ACS Cluster API Model from a JSON file
|
||||
|
@ -23,7 +24,7 @@ func loadAcsCluster(jsonFile string) (*vlabs.AcsCluster, error) {
|
|||
if e := json.Unmarshal(contents, &acsCluster); e != nil {
|
||||
return nil, fmt.Errorf("error unmarshalling file %s: %s", jsonFile, e.Error())
|
||||
}
|
||||
acsCluster.SetDefaults()
|
||||
|
||||
if e := acsCluster.Validate(); e != nil {
|
||||
return nil, fmt.Errorf("error validating acs cluster from file %s: %s", jsonFile, e.Error())
|
||||
}
|
||||
|
@ -61,10 +62,14 @@ func prettyPrintJSON(content string) (string, error) {
|
|||
|
||||
func prettyPrintArmTemplate(template string) (string, error) {
|
||||
translateParams := [][]string{
|
||||
{"parameters", "dparameters"},
|
||||
{"variables", "evariables"},
|
||||
{"resources", "fresources"},
|
||||
{"outputs", "zoutputs"},
|
||||
{"\"parameters\"", "\"dparameters\""},
|
||||
{"\"variables\"", "\"evariables\""},
|
||||
{"\"resources\"", "\"fresources\""},
|
||||
{"\"outputs\"", "\"zoutputs\""},
|
||||
// there is a bug in ARM where it doesn't correctly translate back '\u003e' (>)
|
||||
{">", "GREATERTHAN"},
|
||||
{"<", "LESSTHAN"},
|
||||
{"&", "AMPERSAND"},
|
||||
}
|
||||
|
||||
template = translateJSON(template, translateParams, false)
|
||||
|
@ -77,11 +82,98 @@ func prettyPrintArmTemplate(template string) (string, error) {
|
|||
return template, nil
|
||||
}
|
||||
|
||||
func writeArtifacts(acsCluster *vlabs.AcsCluster, template string, parameters, artifactsDir string, templateDirectory string, certsGenerated bool) error {
|
||||
if len(artifactsDir) == 0 {
|
||||
artifactsDir = fmt.Sprintf("%s-%s", acsCluster.OrchestratorProfile.OrchestratorType, tgen.GenerateClusterID(acsCluster))
|
||||
artifactsDir = path.Join("output", artifactsDir)
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(acsCluster, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if e := saveFile(artifactsDir, "apimodel.json", b); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if e := saveFileString(artifactsDir, "azuredeploy.json", template); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if e := saveFileString(artifactsDir, "azuredeploy.parameters.json", parameters); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if certsGenerated {
|
||||
if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
directory := path.Join(artifactsDir, "kubeconfig")
|
||||
for _, location := range tgen.AzureLocations {
|
||||
b, gkcerr := tgen.GenerateKubeConfig(acsCluster, templateDirectory, location)
|
||||
if gkcerr != nil {
|
||||
return gkcerr
|
||||
}
|
||||
if e := saveFileString(directory, fmt.Sprintf("kubeconfig.%s.json", location), b); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if e := saveFileString(artifactsDir, "ca.key", acsCluster.CertificateProfile.GetCAPrivateKey()); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "ca.crt", acsCluster.CertificateProfile.CaCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "apiserver.key", acsCluster.CertificateProfile.APIServerPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "apiserver.crt", acsCluster.CertificateProfile.APIServerCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "client.key", acsCluster.CertificateProfile.ClientPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "client.crt", acsCluster.CertificateProfile.ClientCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "kubectlClient.key", acsCluster.CertificateProfile.KubeConfigPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "kubectlClient.crt", acsCluster.CertificateProfile.KubeConfigCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveFileString(dir string, file string, data string) error {
|
||||
return saveFile(dir, file, []byte(data))
|
||||
}
|
||||
|
||||
func saveFile(dir string, file string, data []byte) error {
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
if e := os.MkdirAll(dir, 0700); e != nil {
|
||||
return fmt.Errorf("error creating directory '%s': %s", dir, e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
path := path.Join(dir, file)
|
||||
if err := ioutil.WriteFile(path, []byte(data), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "wrote %s\n", path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func usage(errs ...error) {
|
||||
for _, err := range errs {
|
||||
fmt.Fprintf(os.Stderr, "error: %s\n\n", err.Error())
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "usage: %s ClusterDefinitionFile\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, "usage: %s [OPTIONS] ClusterDefinitionFile\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, " read the ClusterDefinitionFile and output an arm template")
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
fmt.Fprintf(os.Stderr, "options:\n")
|
||||
|
@ -90,10 +182,13 @@ func usage(errs ...error) {
|
|||
|
||||
var templateDirectory = flag.String("templateDirectory", "./parts", "directory containing base template files")
|
||||
var noPrettyPrint = flag.Bool("noPrettyPrint", false, "do not pretty print output")
|
||||
var artifactsDir = flag.String("artifacts", "", "directory where artifacts will be written")
|
||||
var classicMode = flag.Bool("classicMode", false, "enable classic parameters and outputs")
|
||||
|
||||
func main() {
|
||||
var acsCluster *vlabs.AcsCluster
|
||||
var template string
|
||||
var parameters string
|
||||
var err error
|
||||
|
||||
flag.Parse()
|
||||
|
@ -114,7 +209,7 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err = clustertemplate.VerifyFiles(*templateDirectory); err != nil {
|
||||
if err = tgen.VerifyFiles(*templateDirectory); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "verification failed: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -124,7 +219,17 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
if template, err = clustertemplate.GenerateTemplate(acsCluster, *templateDirectory); err != nil {
|
||||
certsGenerated := false
|
||||
if certsGenerated, err = tgen.SetAcsClusterDefaults(acsCluster); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error while setting defaults %s: %s", jsonFile, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *classicMode {
|
||||
acsCluster.SetClassicMode(true)
|
||||
}
|
||||
|
||||
if template, parameters, err = tgen.GenerateTemplate(acsCluster, *templateDirectory); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error generating template %s: %s", jsonFile, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -134,6 +239,14 @@ func main() {
|
|||
fmt.Fprintf(os.Stderr, "error pretty printing template %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
if parameters, err = prettyPrintArmTemplate(parameters); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error pretty printing template %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if err = writeArtifacts(acsCluster, template, parameters, *artifactsDir, *templateDirectory, certsGenerated); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error writing artifacts %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Print(template)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ const (
|
|||
DCOS173 = "DCOS173"
|
||||
// Swarm is the string constant for the Swarm orchestrator type
|
||||
Swarm = "Swarm"
|
||||
// Kubernetes is the string constant for the Kubernetes orchestrator type
|
||||
Kubernetes = "Kubernetes"
|
||||
// MinAgentCount are the minimum number of agents
|
||||
MinAgentCount = 1
|
||||
// MaxAgentCount are the maximum number of agents
|
||||
|
@ -17,14 +19,16 @@ const (
|
|||
MinPort = 1
|
||||
// MaxPort specifies the maximum tcp port to open
|
||||
MaxPort = 65535
|
||||
// BaseLBPriority specifies the base lb priority.
|
||||
BaseLBPriority = 200
|
||||
// DefaultMasterSubnet specifies the default master subnet
|
||||
DefaultMasterSubnet = "172.16.0.0/24"
|
||||
// DefaultFirstConsecutiveStaticIP specifies the static IP address on master 0
|
||||
DefaultFirstConsecutiveStaticIP = "172.16.0.5"
|
||||
// DefaultAgentSubnetTemplate specifies a default agent subnet
|
||||
DefaultAgentSubnetTemplate = "10.%d.0.0/24"
|
||||
// MaxDisks specifies the maximum attached disks to add to the cluster
|
||||
MaxDisks = 4
|
||||
// StorageExternal equates to VMSS where attached disks are unsupported (Default)
|
||||
StorageExternal = "External"
|
||||
// StorageVolumes equates to AS where attached disks are supported
|
||||
StorageVolumes = "Volumes"
|
||||
// StorageHAVolumes are managed disks that provide fault domain coverage for volumes.
|
||||
StorageHAVolumes = "HAVolumes"
|
||||
// OSTypeWindows specifies the Windows OS
|
||||
OSTypeWindows = "Windows"
|
||||
// OSTypeLinux specifies the Linux OS
|
||||
OSTypeLinux = "Linux"
|
||||
)
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
package vlabs
|
||||
|
||||
import "fmt"
|
||||
|
||||
// SetDefaults implements APIObject
|
||||
func (o *OrchestratorProfile) SetDefaults() {
|
||||
}
|
||||
|
||||
// SetDefaults implements APIObject
|
||||
func (m *MasterProfile) SetDefaults() {
|
||||
if !m.IsCustomVNET() {
|
||||
m.subnet = DefaultMasterSubnet
|
||||
m.FirstConsecutiveStaticIP = DefaultFirstConsecutiveStaticIP
|
||||
}
|
||||
}
|
||||
|
||||
// SetDefaults implements APIObject
|
||||
func (a *AgentPoolProfile) SetDefaults() {
|
||||
}
|
||||
|
||||
// SetDefaults implements APIObject
|
||||
func (l *LinuxProfile) SetDefaults() {
|
||||
}
|
||||
|
||||
// SetDefaults implements APIObject
|
||||
func (a *AcsCluster) SetDefaults() {
|
||||
a.OrchestratorProfile.SetDefaults()
|
||||
a.MasterProfile.SetDefaults()
|
||||
|
||||
// assign subnets if VNET not specified
|
||||
subnetCounter := 0
|
||||
for i := range a.AgentPoolProfiles {
|
||||
profile := &a.AgentPoolProfiles[i]
|
||||
profile.SetDefaults()
|
||||
if !profile.IsCustomVNET() {
|
||||
profile.subnet = fmt.Sprintf(DefaultAgentSubnetTemplate, subnetCounter)
|
||||
subnetCounter++
|
||||
}
|
||||
}
|
||||
a.LinuxProfile.SetDefaults()
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
// Package vlabs stores an experimental api model for acs
|
||||
package vlabs // import "./api/vlabs"
|
||||
package vlabs
|
||||
|
|
|
@ -2,10 +2,15 @@ package vlabs
|
|||
|
||||
// AcsCluster represents the ACS cluster definition
|
||||
type AcsCluster struct {
|
||||
OrchestratorProfile OrchestratorProfile `json:"orchestratorProfile"`
|
||||
MasterProfile MasterProfile `json:"masterProfile"`
|
||||
AgentPoolProfiles []AgentPoolProfile `json:"agentPoolProfiles"`
|
||||
LinuxProfile LinuxProfile `json:"linuxProfile"`
|
||||
OrchestratorProfile OrchestratorProfile `json:"orchestratorProfile"`
|
||||
MasterProfile MasterProfile `json:"masterProfile"`
|
||||
AgentPoolProfiles []AgentPoolProfile `json:"agentPoolProfiles"`
|
||||
WindowsProfile WindowsProfile `json:"windowsProfile"`
|
||||
LinuxProfile LinuxProfile `json:"linuxProfile"`
|
||||
ServicePrincipalProfile ServicePrincipalProfile `json:"servicePrincipalProfile"`
|
||||
CertificateProfile CertificateProfile `json:"certificateProfile"`
|
||||
// classic mode is used to output parameters and outputs
|
||||
classicMode bool
|
||||
}
|
||||
|
||||
// OrchestratorProfile represents the type of orchestrator
|
||||
|
@ -13,6 +18,32 @@ type OrchestratorProfile struct {
|
|||
OrchestratorType string `json:"orchestratorType"`
|
||||
}
|
||||
|
||||
// ServicePrincipalProfile contains the client and secret used by the cluster for Azure Resource CRUD
|
||||
type ServicePrincipalProfile struct {
|
||||
ClientID string `json:"servicePrincipalClientID,omitempty"`
|
||||
Secret string `json:"servicePrincipalClientSecret,omitempty"`
|
||||
}
|
||||
|
||||
// CertificateProfile represents the definition of the master cluster
|
||||
type CertificateProfile struct {
|
||||
// CaCertificate is the certificate authority certificate.
|
||||
CaCertificate string `json:"caCertificate,omitempty"`
|
||||
// ApiServerCertificate is the rest api server certificate, and signed by the CA
|
||||
APIServerCertificate string `json:"apiServerCertificate,omitempty"`
|
||||
// ApiServerPrivateKey is the rest api server private key, and signed by the CA
|
||||
APIServerPrivateKey string `json:"apiServerPrivateKey,omitempty"`
|
||||
// ClientCertificate is the certificate used by the client kubelet services and signed by the CA
|
||||
ClientCertificate string `json:"clientCertificate,omitempty"`
|
||||
// ClientPrivateKey is the private key used by the client kubelet services and signed by the CA
|
||||
ClientPrivateKey string `json:"clientPrivateKey,omitempty"`
|
||||
// KubeConfigCertificate is the client certificate used for kubectl cli and signed by the CA
|
||||
KubeConfigCertificate string `json:"kubeConfigCertificate,omitempty"`
|
||||
// KubeConfigPrivateKey is the client private key used for kubectl cli and signed by the CA
|
||||
KubeConfigPrivateKey string `json:"kubeConfigPrivateKey,omitempty"`
|
||||
// caPrivateKey is an internal field only set if generation required
|
||||
caPrivateKey string
|
||||
}
|
||||
|
||||
// MasterProfile represents the definition of the master cluster
|
||||
type MasterProfile struct {
|
||||
Count int `json:"count"`
|
||||
|
@ -30,8 +61,9 @@ type AgentPoolProfile struct {
|
|||
Count int `json:"count"`
|
||||
VMSize string `json:"vmSize"`
|
||||
DNSPrefix string `json:"dnsPrefix,omitempty"`
|
||||
OSType string `json:"osType,omitempty"`
|
||||
Ports []int `json:"ports,omitempty"`
|
||||
IsStateful bool `json:"isStateful,omitempty"`
|
||||
StorageType string `json:"storageType,omitempty"`
|
||||
DiskSizesGB []int `json:"diskSizesGB,omitempty"`
|
||||
VnetSubnetID string `json:"vnetSubnetID,omitempty"`
|
||||
// subnet is internal
|
||||
|
@ -48,12 +80,47 @@ type LinuxProfile struct {
|
|||
} `json:"ssh"`
|
||||
}
|
||||
|
||||
// WindowsProfile represents the windows parameters passed to the cluster
|
||||
type WindowsProfile struct {
|
||||
AdminUsername string `json:"adminUsername"`
|
||||
AdminPassword string `json:"adminPassword"`
|
||||
}
|
||||
|
||||
// APIObject defines the required functionality of an api object
|
||||
type APIObject interface {
|
||||
SetDefaults()
|
||||
Validate() error
|
||||
}
|
||||
|
||||
// GetClassicMode gets the classic mode for deciding to output classic parameters
|
||||
func (a *AcsCluster) GetClassicMode() bool {
|
||||
return a.classicMode
|
||||
}
|
||||
|
||||
// SetClassicMode toggles classic parameters and outputs
|
||||
func (a *AcsCluster) SetClassicMode(isClassicMode bool) {
|
||||
a.classicMode = isClassicMode
|
||||
}
|
||||
|
||||
// HasWindows returns true if the cluster contains windows
|
||||
func (a *AcsCluster) HasWindows() bool {
|
||||
for _, agentPoolProfile := range a.AgentPoolProfiles {
|
||||
if agentPoolProfile.OSType == OSTypeWindows {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetCAPrivateKey returns the ca private key
|
||||
func (c *CertificateProfile) GetCAPrivateKey() string {
|
||||
return c.caPrivateKey
|
||||
}
|
||||
|
||||
// SetCAPrivateKey sets the ca private key
|
||||
func (c *CertificateProfile) SetCAPrivateKey(caPrivateKey string) {
|
||||
c.caPrivateKey = caPrivateKey
|
||||
}
|
||||
|
||||
// IsCustomVNET returns true if the customer brought their own VNET
|
||||
func (m *MasterProfile) IsCustomVNET() bool {
|
||||
return len(m.VnetSubnetID) > 0
|
||||
|
@ -64,11 +131,26 @@ func (m *MasterProfile) GetSubnet() string {
|
|||
return m.subnet
|
||||
}
|
||||
|
||||
// SetSubnet sets the read-only subnet for the master
|
||||
func (m *MasterProfile) SetSubnet(subnet string) {
|
||||
m.subnet = subnet
|
||||
}
|
||||
|
||||
// IsCustomVNET returns true if the customer brought their own VNET
|
||||
func (a *AgentPoolProfile) IsCustomVNET() bool {
|
||||
return len(a.VnetSubnetID) > 0
|
||||
}
|
||||
|
||||
// IsWindows returns true if the agent pool is windows
|
||||
func (a *AgentPoolProfile) IsWindows() bool {
|
||||
return a.OSType == OSTypeWindows
|
||||
}
|
||||
|
||||
// IsVolumeBasedStorage returns true if the customer specified disks
|
||||
func (a *AgentPoolProfile) IsVolumeBasedStorage() bool {
|
||||
return a.StorageType == StorageVolumes
|
||||
}
|
||||
|
||||
// HasDisks returns true if the customer specified disks
|
||||
func (a *AgentPoolProfile) HasDisks() bool {
|
||||
return len(a.DiskSizesGB) > 0
|
||||
|
@ -78,3 +160,8 @@ func (a *AgentPoolProfile) HasDisks() bool {
|
|||
func (a *AgentPoolProfile) GetSubnet() string {
|
||||
return a.subnet
|
||||
}
|
||||
|
||||
// SetSubnet sets the read-only subnet for the agent pool
|
||||
func (a *AgentPoolProfile) SetSubnet(subnet string) {
|
||||
a.subnet = subnet
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package vlabs
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Validate implements APIObject
|
||||
|
@ -14,9 +14,11 @@ func (o *OrchestratorProfile) Validate() error {
|
|||
case DCOS184:
|
||||
case DCOS173:
|
||||
case Swarm:
|
||||
case Kubernetes:
|
||||
default:
|
||||
return fmt.Errorf("OrchestratorProfile has unknown orchestrator: %s", o.OrchestratorType)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -67,8 +69,8 @@ func (a *AgentPoolProfile) Validate() error {
|
|||
return e
|
||||
}
|
||||
}
|
||||
if len(a.DiskSizesGB) > 0 && !a.IsStateful {
|
||||
return fmt.Errorf("Disks were specified on a non stateful cluster named '%s'. Ensure you add '\"isStateful\": true' to the model", a.Name)
|
||||
if len(a.DiskSizesGB) > 0 && (a.StorageType != StorageVolumes && a.StorageType != StorageHAVolumes) {
|
||||
return fmt.Errorf("Storage Type %s does not support attached disks for cluster named '%s'. Specify storage as either %s or %s", a.StorageType, a.Name, StorageVolumes, StorageHAVolumes)
|
||||
}
|
||||
if len(a.DiskSizesGB) > MaxDisks {
|
||||
return fmt.Errorf("A maximum of %d disks may be specified. %d disks were specified for cluster named '%s'", MaxDisks, len(a.DiskSizesGB), a.Name)
|
||||
|
@ -104,12 +106,49 @@ func (a *AcsCluster) Validate() error {
|
|||
if e := validateUniqueProfileNames(a.AgentPoolProfiles); e != nil {
|
||||
return e
|
||||
}
|
||||
if a.OrchestratorProfile.OrchestratorType == Kubernetes && len(a.ServicePrincipalProfile.ClientID) == 0 {
|
||||
return fmt.Errorf("the service principal client ID must be specified with Orchestrator %s", a.OrchestratorProfile.OrchestratorType)
|
||||
}
|
||||
|
||||
if a.OrchestratorProfile.OrchestratorType == Kubernetes && len(a.ServicePrincipalProfile.Secret) == 0 {
|
||||
return fmt.Errorf("the service principal client secrect must be specified with Orchestrator %s", a.OrchestratorProfile.OrchestratorType)
|
||||
}
|
||||
|
||||
for _, agentPoolProfile := range a.AgentPoolProfiles {
|
||||
if e := agentPoolProfile.Validate(); e != nil {
|
||||
return e
|
||||
}
|
||||
if a.OrchestratorProfile.OrchestratorType == Swarm && agentPoolProfile.IsStateful {
|
||||
return errors.New("stateful deployments are not supported with Swarm, please let us know if you want this feature")
|
||||
switch agentPoolProfile.StorageType {
|
||||
case StorageVolumes:
|
||||
case StorageHAVolumes:
|
||||
case StorageExternal:
|
||||
case "":
|
||||
default:
|
||||
{
|
||||
return fmt.Errorf("unknown storage type '%s' for agent pool '%s'. Specify one of %s, %s, or %s", agentPoolProfile.StorageType, agentPoolProfile.Name, StorageExternal, StorageVolumes, StorageHAVolumes)
|
||||
}
|
||||
}
|
||||
if agentPoolProfile.StorageType == StorageHAVolumes {
|
||||
return errors.New("HA volumes are currently unsupported")
|
||||
}
|
||||
if a.OrchestratorProfile.OrchestratorType == Kubernetes && (agentPoolProfile.StorageType == StorageExternal || len(agentPoolProfile.StorageType) == 0) {
|
||||
return fmt.Errorf("External storage deployments (VMSS) are not supported with Kubernetes since Kubernetes requires the ability to attach/detach disks. To fix specify \"StorageType\":\"%s\"", StorageVolumes)
|
||||
}
|
||||
if a.OrchestratorProfile.OrchestratorType == Kubernetes && len(agentPoolProfile.DNSPrefix) > 0 {
|
||||
return errors.New("DNSPrefix not support for agent pools in Kubernetes - Kubernetes marks its own clusters public")
|
||||
}
|
||||
if agentPoolProfile.OSType == OSTypeWindows {
|
||||
switch a.OrchestratorProfile.OrchestratorType {
|
||||
case Swarm:
|
||||
default:
|
||||
return fmt.Errorf("Orchestrator %s does not support Windows", a.OrchestratorProfile.OrchestratorType)
|
||||
}
|
||||
if len(a.WindowsProfile.AdminUsername) == 0 {
|
||||
return fmt.Errorf("WindowsProfile.AdminUsername must not be empty since agent pool '%s' specifies windows", agentPoolProfile.Name)
|
||||
}
|
||||
if len(a.WindowsProfile.AdminPassword) == 0 {
|
||||
return fmt.Errorf("WindowsProfile.AdminPassword must not be empty since agent pool '%s' specifies windows", agentPoolProfile.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if e := a.LinuxProfile.Validate(); e != nil {
|
||||
|
@ -128,36 +167,6 @@ func validateName(name string, label string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func parseCIDR(cidr string) (octet1 int, octet2 int, octet3 int, octet4 int, subnet int, err error) {
|
||||
// verify cidr format and a /24 subnet
|
||||
// regular expression inspired by http://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/
|
||||
cidrRegex := `^((?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.((?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.((?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/((?:[0-9]|[1-2][0-9]|3[0-2]))$`
|
||||
var re *regexp.Regexp
|
||||
if re, err = regexp.Compile(cidrRegex); err != nil {
|
||||
return 0, 0, 0, 0, 0, err
|
||||
}
|
||||
submatches := re.FindStringSubmatch(cidr)
|
||||
if len(submatches) != 6 {
|
||||
return 0, 0, 0, 0, 0, fmt.Errorf("address %s is not specified as valid cidr", cidr)
|
||||
}
|
||||
if octet1, err = strconv.Atoi(submatches[1]); err != nil {
|
||||
return 0, 0, 0, 0, 0, err
|
||||
}
|
||||
if octet2, err = strconv.Atoi(submatches[2]); err != nil {
|
||||
return 0, 0, 0, 0, 0, err
|
||||
}
|
||||
if octet3, err = strconv.Atoi(submatches[3]); err != nil {
|
||||
return 0, 0, 0, 0, 0, err
|
||||
}
|
||||
if octet4, err = strconv.Atoi(submatches[4]); err != nil {
|
||||
return 0, 0, 0, 0, 0, err
|
||||
}
|
||||
if subnet, err = strconv.Atoi(submatches[5]); err != nil {
|
||||
return 0, 0, 0, 0, 0, err
|
||||
}
|
||||
return octet1, octet2, octet3, octet4, subnet, nil
|
||||
}
|
||||
|
||||
func validatePoolName(poolName string) error {
|
||||
// we will cap at length of 12 and all lowercase letters since this makes up the VMName
|
||||
poolNameRegex := `^([a-z][a-z0-9]{0,11})$`
|
||||
|
@ -185,33 +194,6 @@ func validateDNSName(dnsName string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func parseIP(ipaddress string) (octet1 int, octet2 int, octet3 int, octet4 int, err error) {
|
||||
// verify cidr format and a /24 subnet
|
||||
// regular expression inspired by http://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/
|
||||
ipRegex := `^((?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.((?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.((?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
|
||||
var re *regexp.Regexp
|
||||
if re, err = regexp.Compile(ipRegex); err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
}
|
||||
submatches := re.FindStringSubmatch(ipaddress)
|
||||
if len(submatches) != 5 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("address %s is not specified as a valid ip address", ipaddress)
|
||||
}
|
||||
if octet1, err = strconv.Atoi(submatches[1]); err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
}
|
||||
if octet2, err = strconv.Atoi(submatches[2]); err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
}
|
||||
if octet3, err = strconv.Atoi(submatches[3]); err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
}
|
||||
if octet4, err = strconv.Atoi(submatches[4]); err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
}
|
||||
return octet1, octet2, octet3, octet4, nil
|
||||
}
|
||||
|
||||
func validateUniqueProfileNames(profiles []AgentPoolProfile) error {
|
||||
profileNames := make(map[string]bool)
|
||||
for _, profile := range profiles {
|
||||
|
@ -242,9 +224,6 @@ func validateVNET(a *AcsCluster) error {
|
|||
}
|
||||
}
|
||||
if isCustomVNET {
|
||||
if a.OrchestratorProfile.OrchestratorType == Swarm {
|
||||
return errors.New("bring your own VNET is not supported with Swarm, please let us know if you want this feature")
|
||||
}
|
||||
subscription, resourcegroup, vnetname, _, e := GetVNETSubnetIDComponents(a.MasterProfile.VnetSubnetID)
|
||||
if e != nil {
|
||||
return e
|
||||
|
@ -262,9 +241,9 @@ func validateVNET(a *AcsCluster) error {
|
|||
}
|
||||
}
|
||||
|
||||
// validate that the first master IP address has been set
|
||||
if e = validateName(a.MasterProfile.FirstConsecutiveStaticIP, "MasterProfile.FirstConsecutiveStaticIP (with VNET Subnet specification)"); e != nil {
|
||||
return e
|
||||
masterFirstIP := net.ParseIP(a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
if masterFirstIP == nil {
|
||||
return fmt.Errorf("MasterProfile.FirstConsecutiveStaticIP (with VNET Subnet specification) '%s' is an invalid IP address", a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
},
|
||||
"masterProfile": {
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe0927i",
|
||||
"dnsPrefix": "mgmtanhowe1009i",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
|
@ -17,7 +17,7 @@
|
|||
"name": "agentpublic",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe0927i",
|
||||
"dnsPrefix": "appanhowe1009i",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
|
@ -4,7 +4,7 @@
|
|||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe0926i",
|
||||
"dnsPrefix": "mgmtanhowe1009g",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
|
@ -17,7 +17,7 @@
|
|||
"name": "agentpool2",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe0926i",
|
||||
"dnsPrefix": "appanhowe1009g",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "DCOS"
|
||||
"orchestratorType": "DCOS184"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 5,
|
||||
"dnsPrefix": "mgmtanhowe0926i",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe1009h",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
|
@ -17,7 +17,7 @@
|
|||
"name": "agentpublic",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe0926i",
|
||||
"dnsPrefix": "appanhowe1009h",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
|
@ -1,70 +0,0 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "DCOS"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe0928g",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agtnodisks1",
|
||||
"count": 1,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true
|
||||
},
|
||||
{
|
||||
"name": "agent128",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true,
|
||||
"diskSizesGB": [10, 10, 10, 10]
|
||||
},
|
||||
{
|
||||
"name": "agent1public",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe0928g",
|
||||
"isStateful": true,
|
||||
"diskSizesGB": [1],
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "agtnodisks2",
|
||||
"count": 1,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true
|
||||
},
|
||||
{
|
||||
"name": "agtnodisks3",
|
||||
"count": 1,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true
|
||||
},
|
||||
{
|
||||
"name": "astateless1",
|
||||
"count": 2,
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
{
|
||||
"name": "astateless2",
|
||||
"count": 2,
|
||||
"vmSize": "Standard_D2_v2"
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Kubernetes"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe1004f",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agentpool1",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes"
|
||||
},
|
||||
{
|
||||
"name": "agentpool2",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes"
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"servicePrincipalProfile": {
|
||||
"servicePrincipalClientID": "[REPLACE-WITH-ServicePrincipalClientID",
|
||||
"servicePrincipalClientSecret": "[REPLACE-WITH-myServicePrincipalClientSecret"
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe0927c",
|
||||
"dnsPrefix": "mgmtanhowe1009r",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
|
@ -12,7 +12,7 @@
|
|||
"name": "agentpool1",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe0927c",
|
||||
"dnsPrefix": "appanhowe1009r",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": { },
|
||||
"variables": { },
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2016-03-30",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "KubernetesCustomVNET",
|
||||
"properties": {
|
||||
"addressSpace": {
|
||||
"addressPrefixes": [
|
||||
"10.239.0.0/16"
|
||||
]
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"name": "KubernetesSubnet",
|
||||
"properties": {
|
||||
"addressPrefix": "10.239.0.0/16"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": { },
|
||||
"variables": { },
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2016-03-30",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "ExampleCustomVNET",
|
||||
"properties": {
|
||||
"addressSpace": {
|
||||
"addressPrefixes": [
|
||||
"10.100.0.0/24",
|
||||
"10.200.0.0/24"
|
||||
]
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"name": "ExampleMasterSubnet",
|
||||
"properties": {
|
||||
"addressPrefix": "10.100.0.0/24"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ExampleAgentSubnet",
|
||||
"properties": {
|
||||
"addressPrefix": "10.200.0.0/24"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -3,24 +3,25 @@
|
|||
"orchestratorType": "DCOS"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 5,
|
||||
"dnsPrefix": "mgmtanhowe0927h",
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe1009f",
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweExampleRG/providers/Microsoft.Network/virtualNetworks/ExampleCustomVNET/subnets/ExampleMasterSubnet",
|
||||
"firstConsecutiveStaticIP": "10.100.0.5"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agentPrivate",
|
||||
"name": "agentprivate",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweExampleRG/providers/Microsoft.Network/virtualNetworks/ExampleCustomVNET/subnets/ExampleAgentSubnet"
|
||||
},
|
||||
{
|
||||
"name": "agentPublic",
|
||||
"name": "agentpublic",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe0927h",
|
||||
"dnsPrefix": "appanhowe1009f",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweExampleRG/providers/Microsoft.Network/virtualNetworks/ExampleCustomVNET/subnets/ExampleAgentSubnet",
|
||||
"ports": [
|
||||
80,
|
|
@ -1,9 +1,11 @@
|
|||
$VerbosePreference="Continue"
|
||||
$deployName="anhoweExampleRG"
|
||||
$deployName="anhoweKubeVnet"
|
||||
$RGName=$deployName
|
||||
$SubscriptionId="b52fce95-de5f-4b37-afca-db203a5d0b6a"
|
||||
Set-AzureRmContext -SubscriptionId $SubscriptionId
|
||||
$locName="West US"
|
||||
$templateFile = "azuredeploy.json"
|
||||
#$templateFile = "azuredeploy.dcos.json"
|
||||
#$templateFile = "azuredeploy.swarm.json"
|
||||
$templateFile = "azuredeploy.kubernetes.json"
|
||||
New-AzureRmResourceGroup -Name $RGName -Location $locName -Force
|
||||
New-AzureRmResourceGroupDeployment -Name $deployName -ResourceGroupName $RGName -TemplateFile $templateFile
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Kubernetes"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "anhowe1009d",
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweKubeVnet/providers/Microsoft.Network/virtualNetworks/KubernetesCustomVNET/subnets/KubernetesSubnet",
|
||||
"firstConsecutiveStaticIP": "10.239.255.245"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agentpri",
|
||||
"count": 2,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweKubeVnet/providers/Microsoft.Network/virtualNetworks/KubernetesCustomVNET/subnets/KubernetesSubnet",
|
||||
"StorageType": "Volumes"
|
||||
},
|
||||
{
|
||||
"name": "agentpri2",
|
||||
"count": 2,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweKubeVnet/providers/Microsoft.Network/virtualNetworks/KubernetesCustomVNET/subnets/KubernetesSubnet",
|
||||
"StorageType": "Volumes"
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"servicePrincipalProfile": {
|
||||
"servicePrincipalClientID": "[REPLACE-WITH-ServicePrincipalClientID",
|
||||
"servicePrincipalClientSecret": "[REPLACE-WITH-myServicePrincipalClientSecret"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Swarm"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe1009j",
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweExampleRG/providers/Microsoft.Network/virtualNetworks/ExampleCustomVNET/subnets/ExampleMasterSubnet",
|
||||
"firstConsecutiveStaticIP": "10.100.0.5"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agentprivate",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweExampleRG/providers/Microsoft.Network/virtualNetworks/ExampleCustomVNET/subnets/ExampleAgentSubnet"
|
||||
},
|
||||
{
|
||||
"name": "agentpublic",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe1009j",
|
||||
"vnetSubnetId": "/subscriptions/b52fce95-de5f-4b37-afca-db203a5d0b6a/resourceGroups/anhoweExampleRG/providers/Microsoft.Network/virtualNetworks/ExampleCustomVNET/subnets/ExampleAgentSubnet",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "DCOS"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe1009o",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agent128",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes",
|
||||
"diskSizesGB": [128, 128, 128, 128]
|
||||
},
|
||||
{
|
||||
"name": "agent1public",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe1009o",
|
||||
"StorageType": "Volumes",
|
||||
"diskSizesGB": [1],
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,21 +4,27 @@
|
|||
},
|
||||
"masterProfile": {
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe0928d",
|
||||
"dnsPrefix": "mgmtanhowe1009n",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agtnodisks1",
|
||||
"count": 1,
|
||||
"name": "agent128",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true
|
||||
"StorageType": "Volumes"
|
||||
},
|
||||
{
|
||||
"name": "agtnodisks2",
|
||||
"count": 1,
|
||||
"name": "agent1public",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true
|
||||
"dnsPrefix": "appanhowe1009n",
|
||||
"StorageType": "Volumes",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Kubernetes"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe1004f",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agentpool1",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes",
|
||||
"diskSizesGB": [128, 128, 128, 128]
|
||||
},
|
||||
{
|
||||
"name": "agentpool2",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes",
|
||||
"diskSizesGB": [10, 10, 10, 10]
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"servicePrincipalProfile": {
|
||||
"servicePrincipalClientID": "[REPLACE-WITH-ServicePrincipalClientID",
|
||||
"servicePrincipalClientSecret": "[REPLACE-WITH-myServicePrincipalClientSecret"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Swarm"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe1009q",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agent128",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes",
|
||||
"diskSizesGB": [128, 128, 128, 128]
|
||||
},
|
||||
{
|
||||
"name": "agent1public",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe1009q",
|
||||
"StorageType": "Volumes",
|
||||
"diskSizesGB": [1],
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Swarm"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 3,
|
||||
"dnsPrefix": "mgmtanhowe1009p",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agent128",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes"
|
||||
},
|
||||
{
|
||||
"name": "agent1public",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe1009p",
|
||||
"StorageType": "Volumes",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Swarm"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe1009d",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "publicwin1",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe1009d",
|
||||
"osType": "Windows",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "privatewin",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"osType": "Windows"
|
||||
}
|
||||
],
|
||||
"windowsProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"adminPassword": "replacepassword1234$"
|
||||
},
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Swarm"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe1009f",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "publicwin1",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe1009f",
|
||||
"osType": "Windows",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "privatewin",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"osType": "Windows"
|
||||
},
|
||||
{
|
||||
"name": "privatelinux",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"osType": "Linux"
|
||||
}
|
||||
],
|
||||
"windowsProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"adminPassword": "replacepassword1234$"
|
||||
},
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Swarm"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe1009e",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "publicwin1",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"dnsPrefix": "appanhowe1009e",
|
||||
"osType": "Windows",
|
||||
"StorageType": "Volumes",
|
||||
"ports": [
|
||||
80,
|
||||
443,
|
||||
8080
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "privatewin",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"StorageType": "Volumes",
|
||||
"osType": "Windows"
|
||||
}
|
||||
],
|
||||
"windowsProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"adminPassword": "replacepassword1234$"
|
||||
},
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
// Package clustertemplate stores an experimental api model for acs
|
||||
package clustertemplate // import "./clustertemplate"
|
|
@ -1,392 +0,0 @@
|
|||
package clustertemplate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"text/template"
|
||||
|
||||
"./../api/vlabs"
|
||||
)
|
||||
|
||||
const (
|
||||
agentOutputs = "agentoutputs.t"
|
||||
agentParams = "agentparams.t"
|
||||
dcosAgentResources = "dcosagentresources.t"
|
||||
dcosAgentResourcesDisks = "dcosagentresourcesdisks.t"
|
||||
dcosAgentVars = "dcosagentvars.t"
|
||||
dcosBaseFile = "dcosbase.t"
|
||||
dcosCustomData173 = "dcoscustomdata173.t"
|
||||
dcosCustomData184 = "dcoscustomdata184.t"
|
||||
dcosMasterResources = "dcosmasterresources.t"
|
||||
dcosMasterVars = "dcosmastervars.t"
|
||||
masterOutputs = "masteroutputs.t"
|
||||
masterParams = "masterparams.t"
|
||||
swarmBaseFile = "swarmbase.t"
|
||||
swarmAgentCustomData = "swarmagentcustomdata.t"
|
||||
swarmAgentResources = "swarmagentresources.t"
|
||||
swarmAgentVars = "swarmagentvars.t"
|
||||
swarmMasterCustomData = "swarmmastercustomdata.t"
|
||||
swarmMasterResources = "swarmmasterresources.t"
|
||||
swarmMasterVars = "swarmmastervars.t"
|
||||
)
|
||||
|
||||
var dcosTemplateFiles = []string{agentOutputs, agentParams, dcosAgentResources, dcosAgentResourcesDisks, dcosAgentVars, dcosBaseFile, dcosCustomData173, dcosCustomData184, dcosMasterResources, dcosMasterVars, masterOutputs, masterParams}
|
||||
var swarmTemplateFiles = []string{agentOutputs, agentParams, masterParams, swarmBaseFile, swarmAgentCustomData, swarmAgentResources, swarmAgentVars, swarmBaseFile, masterOutputs, swarmMasterCustomData, swarmMasterResources, swarmMasterVars}
|
||||
|
||||
// VerifyFiles verifies that the required template files exist
|
||||
func VerifyFiles(partsDirectory string) error {
|
||||
for _, file := range append(dcosTemplateFiles, swarmTemplateFiles...) {
|
||||
templateFile := path.Join(partsDirectory, file)
|
||||
if _, err := os.Stat(templateFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("template file %s does not exist, did you specify the correct template directory?", templateFile)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateTemplate generates the template from the API Model
|
||||
func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (string, error) {
|
||||
var err error
|
||||
var templ *template.Template
|
||||
|
||||
templateMap := template.FuncMap{
|
||||
"IsDCOS173": func() bool {
|
||||
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS173
|
||||
},
|
||||
"IsDCOS184": func() bool {
|
||||
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS184 ||
|
||||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS
|
||||
},
|
||||
"IsPublic": func(ports []int) bool {
|
||||
return len(ports) > 0
|
||||
},
|
||||
"GetVNETSubnetDependencies": func() string {
|
||||
return getVNETSubnetDependencies(acsCluster)
|
||||
},
|
||||
"GetLBRules": func(name string, ports []int) string {
|
||||
return getLBRules(name, ports)
|
||||
},
|
||||
"GetProbes": func(ports []int) string {
|
||||
return getProbes(ports)
|
||||
},
|
||||
"GetSecurityRules": func(ports []int) string {
|
||||
return getSecurityRules(ports)
|
||||
},
|
||||
"GetMasterRolesFileContents": func() string {
|
||||
return getMasterRolesFileContents()
|
||||
},
|
||||
"GetAgentRolesFileContents": func(ports []int) string {
|
||||
return getAgentRolesFileContents(ports)
|
||||
},
|
||||
"GetDCOSCustomDataPublicIPStr": func() string {
|
||||
return getDCOSCustomDataPublicIPStr(acsCluster.OrchestratorProfile.OrchestratorType, acsCluster.MasterProfile.Count)
|
||||
},
|
||||
"GetDCOSGUID": func() string {
|
||||
return getPackageGUID(acsCluster.OrchestratorProfile.OrchestratorType, acsCluster.MasterProfile.Count)
|
||||
},
|
||||
"GetLinuxProfileFirstSSHPublicKey": func() string {
|
||||
return acsCluster.LinuxProfile.SSH.PublicKeys[0].KeyData
|
||||
},
|
||||
"GetUniqueNameSuffix": func() string {
|
||||
return generateUniqueNameSuffix(acsCluster)
|
||||
},
|
||||
"GetVNETAddressPrefixes": func() string {
|
||||
return getVNETAddressPrefixes(acsCluster)
|
||||
},
|
||||
"GetVNETSubnets": func(addNSG bool) string {
|
||||
return getVNETSubnets(acsCluster, addNSG)
|
||||
},
|
||||
"GetDataDisks": func(profile *vlabs.AgentPoolProfile) string {
|
||||
return getDataDisks(profile)
|
||||
},
|
||||
// inspired by http://stackoverflow.com/questions/18276173/calling-a-template-with-several-pipeline-parameters/18276968#18276968
|
||||
"dict": func(values ...interface{}) (map[string]interface{}, error) {
|
||||
if len(values)%2 != 0 {
|
||||
return nil, errors.New("invalid dict call")
|
||||
}
|
||||
dict := make(map[string]interface{}, len(values)/2)
|
||||
for i := 0; i < len(values); i += 2 {
|
||||
key, ok := values[i].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("dict keys must be strings")
|
||||
}
|
||||
dict[key] = values[i+1]
|
||||
}
|
||||
return dict, nil
|
||||
},
|
||||
}
|
||||
templ = template.New("acs template").Funcs(templateMap)
|
||||
|
||||
var files []string
|
||||
var baseFile string
|
||||
if isDCOS(acsCluster) {
|
||||
files = dcosTemplateFiles
|
||||
baseFile = dcosBaseFile
|
||||
} else if isSwarm(acsCluster) {
|
||||
files = swarmTemplateFiles
|
||||
baseFile = swarmBaseFile
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
templateFile := path.Join(partsDirectory, file)
|
||||
bytes, e := ioutil.ReadFile(templateFile)
|
||||
if e != nil {
|
||||
return "", fmt.Errorf("Error reading file %s: %s", templateFile, e.Error())
|
||||
}
|
||||
if _, err = templ.New(file).Parse(string(bytes)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
if err = templ.ExecuteTemplate(&b, baseFile, acsCluster); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
func generateUniqueNameSuffix(acsCluster *vlabs.AcsCluster) string {
|
||||
uniqueNameSuffixSize := 8
|
||||
// the name suffix uniquely identifies the cluster and is generated off a hash
|
||||
// from the master dns name
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(acsCluster.MasterProfile.DNSPrefix))
|
||||
rand.Seed(int64(h.Sum64()))
|
||||
return fmt.Sprintf("%08d", rand.Uint32())[:uniqueNameSuffixSize]
|
||||
}
|
||||
|
||||
func getPackageGUID(orchestratorType string, masterCount int) string {
|
||||
if orchestratorType == vlabs.DCOS || orchestratorType == vlabs.DCOS184 {
|
||||
switch masterCount {
|
||||
case 1:
|
||||
return "5ac6a7d060584c58c704e1f625627a591ecbde4e"
|
||||
case 3:
|
||||
return "42bd1d74e9a2b23836bd78919c716c20b98d5a0e"
|
||||
case 5:
|
||||
return "97947a91e2c024ed4f043bfcdad49da9418d3095"
|
||||
}
|
||||
} else if orchestratorType == vlabs.DCOS173 {
|
||||
switch masterCount {
|
||||
case 1:
|
||||
return "6b604c1331c2b8b52bb23d1ea8a8d17e0f2b7428"
|
||||
case 3:
|
||||
return "6af5097e7956962a3d4318d28fbf280a47305485"
|
||||
case 5:
|
||||
return "376e07e0dbad2af3da2c03bc92bb07e84b3dafd5"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getDCOSCustomDataPublicIPStr(orchestratorType string, masterCount int) string {
|
||||
if orchestratorType == vlabs.DCOS ||
|
||||
orchestratorType == vlabs.DCOS173 ||
|
||||
orchestratorType == vlabs.DCOS184 {
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < masterCount; i++ {
|
||||
buf.WriteString(fmt.Sprintf("reference(variables('masterVMNic')[%d]).ipConfigurations[0].properties.privateIPAddress,", i))
|
||||
if i < (masterCount - 1) {
|
||||
buf.WriteString(`'\\\", \\\"', `)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getVNETAddressPrefixes(acsCluster *vlabs.AcsCluster) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(`"[variables('masterSubnet')]"`)
|
||||
for _, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
buf.WriteString(fmt.Sprintf(",\n \"[variables('%sSubnet')]\"", agentProfile.Name))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getVNETSubnetDependencies(acsCluster *vlabs.AcsCluster) string {
|
||||
agentString := ` "[concat('Microsoft.Network/networkSecurityGroups/', variables('%sNSGName'))]"`
|
||||
var buf bytes.Buffer
|
||||
for index, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(agentString, agentProfile.Name))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getVNETSubnets(acsCluster *vlabs.AcsCluster, addNSG bool) string {
|
||||
masterString := `{
|
||||
"name": "[variables('masterSubnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('masterSubnet')]"
|
||||
}
|
||||
}`
|
||||
agentString := ` {
|
||||
"name": "[variables('%sSubnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('%sSubnet')]"
|
||||
}
|
||||
}`
|
||||
agentStringNSG := ` {
|
||||
"name": "[variables('%sSubnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('%sSubnet')]",
|
||||
"networkSecurityGroup": {
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('%sNSGName'))]"
|
||||
}
|
||||
}
|
||||
}`
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(masterString)
|
||||
for _, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
buf.WriteString(",\n")
|
||||
if addNSG {
|
||||
buf.WriteString(fmt.Sprintf(agentStringNSG, agentProfile.Name, agentProfile.Name, agentProfile.Name))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf(agentString, agentProfile.Name, agentProfile.Name))
|
||||
}
|
||||
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getLBRule(name string, port int) string {
|
||||
return fmt.Sprintf(` {
|
||||
"name": "LBRule%d",
|
||||
"properties": {
|
||||
"backendAddressPool": {
|
||||
"id": "[concat(variables('%sLbID'), '/backendAddressPools/', variables('%sLbBackendPoolName'))]"
|
||||
},
|
||||
"backendPort": %d,
|
||||
"enableFloatingIP": false,
|
||||
"frontendIPConfiguration": {
|
||||
"id": "[variables('%sLbIPConfigID')]"
|
||||
},
|
||||
"frontendPort": %d,
|
||||
"idleTimeoutInMinutes": 5,
|
||||
"loadDistribution": "Default",
|
||||
"probe": {
|
||||
"id": "[concat(variables('%sLbID'),'/probes/tcp%dProbe')]"
|
||||
},
|
||||
"protocol": "tcp"
|
||||
}
|
||||
}`, port, name, name, port, name, port, name, port)
|
||||
}
|
||||
|
||||
func getLBRules(name string, ports []int) string {
|
||||
var buf bytes.Buffer
|
||||
for index, port := range ports {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(getLBRule(name, port))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getProbe(port int) string {
|
||||
return fmt.Sprintf(` {
|
||||
"name": "tcp%dProbe",
|
||||
"properties": {
|
||||
"intervalInSeconds": "5",
|
||||
"numberOfProbes": "2",
|
||||
"port": %d,
|
||||
"protocol": "tcp"
|
||||
}
|
||||
}`, port, port)
|
||||
}
|
||||
|
||||
func getProbes(ports []int) string {
|
||||
var buf bytes.Buffer
|
||||
for index, port := range ports {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(getProbe(port))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getSecurityRule(port int, portIndex int) string {
|
||||
return fmt.Sprintf(` {
|
||||
"name": "Allow_%d",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "Allow traffic from the Internet to port %d",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationPortRange": "%d",
|
||||
"direction": "Inbound",
|
||||
"priority": %d,
|
||||
"protocol": "*",
|
||||
"sourceAddressPrefix": "Internet",
|
||||
"sourcePortRange": "*"
|
||||
}
|
||||
}`, port, port, port, vlabs.BaseLBPriority+portIndex)
|
||||
}
|
||||
|
||||
func getDataDisks(a *vlabs.AgentPoolProfile) string {
|
||||
if !a.HasDisks() {
|
||||
return ""
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("\"dataDisks\": [\n")
|
||||
dataDisks := ` {
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": "%d",
|
||||
"lun": %d,
|
||||
"name": "[concat(variables('%sVMNamePrefix'), copyIndex(),'-datadisk%d')]",
|
||||
"vhd": {
|
||||
"uri": "[concat('http://',variables('storageAccountPrefixes')[mod(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('%sStorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('%sStorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('%sDataAccountName'),'.blob.core.windows.net/vhds/',variables('%sVMNamePrefix'),copyIndex(), '--datadisk%d.vhd')]"
|
||||
}
|
||||
}`
|
||||
for i, diskSize := range a.DiskSizesGB {
|
||||
if i > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(dataDisks, diskSize, i, a.Name, i, a.Name, a.Name, a.Name, a.Name, i))
|
||||
}
|
||||
buf.WriteString("\n ],")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getSecurityRules(ports []int) string {
|
||||
var buf bytes.Buffer
|
||||
for index, port := range ports {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(getSecurityRule(port, index))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getMasterRolesFileContents() string {
|
||||
return `{\"content\": \"\", \"path\": \"/etc/mesosphere/roles/master\"}, {\"content\": \"\", \"path\": \"/etc/mesosphere/roles/azure_master\"},`
|
||||
}
|
||||
|
||||
func getAgentRolesFileContents(ports []int) string {
|
||||
if len(ports) > 0 {
|
||||
// public agents
|
||||
return `{\"content\": \"\", \"path\": \"/etc/mesosphere/roles/slave_public\"},`
|
||||
} else {
|
||||
// private agents
|
||||
return `{\"content\": \"\", \"path\": \"/etc/mesosphere/roles/slave\"},`
|
||||
}
|
||||
}
|
||||
|
||||
func isDCOS(acsCluster *vlabs.AcsCluster) bool {
|
||||
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS184 ||
|
||||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS ||
|
||||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS173
|
||||
}
|
||||
|
||||
func isSwarm(acsCluster *vlabs.AcsCluster) bool {
|
||||
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Swarm
|
||||
}
|
|
@ -1,163 +1,12 @@
|
|||
"{{.Name}}Count": {
|
||||
"allowedValues": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
41,
|
||||
42,
|
||||
43,
|
||||
44,
|
||||
45,
|
||||
46,
|
||||
47,
|
||||
48,
|
||||
49,
|
||||
50,
|
||||
51,
|
||||
52,
|
||||
53,
|
||||
54,
|
||||
55,
|
||||
56,
|
||||
57,
|
||||
58,
|
||||
59,
|
||||
60,
|
||||
61,
|
||||
62,
|
||||
63,
|
||||
64,
|
||||
65,
|
||||
66,
|
||||
67,
|
||||
68,
|
||||
69,
|
||||
70,
|
||||
71,
|
||||
72,
|
||||
73,
|
||||
74,
|
||||
75,
|
||||
76,
|
||||
77,
|
||||
78,
|
||||
79,
|
||||
80,
|
||||
81,
|
||||
82,
|
||||
83,
|
||||
84,
|
||||
85,
|
||||
86,
|
||||
87,
|
||||
88,
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
92,
|
||||
93,
|
||||
94,
|
||||
95,
|
||||
96,
|
||||
97,
|
||||
98,
|
||||
99,
|
||||
100
|
||||
],
|
||||
"defaultValue": {{.Count}},
|
||||
"allowedValues": [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100],
|
||||
"metadata": {
|
||||
"description": "The number of Mesos agents for the cluster. This value can be from 1 to 100"
|
||||
},
|
||||
"type": "int"
|
||||
},
|
||||
"{{.Name}}VMSize": {
|
||||
"allowedValues": [
|
||||
"Standard_A0",
|
||||
"Standard_A1",
|
||||
"Standard_A2",
|
||||
"Standard_A3",
|
||||
"Standard_A4",
|
||||
"Standard_A5",
|
||||
"Standard_A6",
|
||||
"Standard_A7",
|
||||
"Standard_A8",
|
||||
"Standard_A9",
|
||||
"Standard_A10",
|
||||
"Standard_A11",
|
||||
"Standard_D1",
|
||||
"Standard_D2",
|
||||
"Standard_D3",
|
||||
"Standard_D4",
|
||||
"Standard_D11",
|
||||
"Standard_D12",
|
||||
"Standard_D13",
|
||||
"Standard_D14",
|
||||
"Standard_D1_v2",
|
||||
"Standard_D2_v2",
|
||||
"Standard_D3_v2",
|
||||
"Standard_D4_v2",
|
||||
"Standard_D5_v2",
|
||||
"Standard_D11_v2",
|
||||
"Standard_D12_v2",
|
||||
"Standard_D13_v2",
|
||||
"Standard_D14_v2",
|
||||
"Standard_G1",
|
||||
"Standard_G2",
|
||||
"Standard_G3",
|
||||
"Standard_G4",
|
||||
"Standard_G5",
|
||||
"Standard_DS1",
|
||||
"Standard_DS2",
|
||||
"Standard_DS3",
|
||||
"Standard_DS4",
|
||||
"Standard_DS11",
|
||||
"Standard_DS12",
|
||||
"Standard_DS13",
|
||||
"Standard_DS14",
|
||||
"Standard_GS1",
|
||||
"Standard_GS2",
|
||||
"Standard_GS3",
|
||||
"Standard_GS4",
|
||||
"Standard_GS5"
|
||||
],
|
||||
"defaultValue": "{{.VMSize}}",
|
||||
{{GetAgentAllowedSizes}}
|
||||
"metadata": {
|
||||
"description": "The size of the Virtual Machine."
|
||||
},
|
||||
|
@ -165,7 +14,6 @@
|
|||
},
|
||||
{{if .IsCustomVNET}}
|
||||
"{{.Name}}VnetSubnetID": {
|
||||
"defaultValue": "{{.VnetSubnetID}}",
|
||||
"metadata": {
|
||||
"description": "Sets the vnet subnet of agent pool '{{.Name}}'."
|
||||
},
|
||||
|
@ -182,7 +30,6 @@
|
|||
{{end}}
|
||||
{{if IsPublic .Ports}}
|
||||
,"{{.Name}}EndpointDNSNamePrefix": {
|
||||
"defaultValue": "{{.DNSPrefix}}",
|
||||
"metadata": {
|
||||
"description": "Sets the Domain name label for the agent pool IP Address. The concatenation of the domain name label and the regional DNS zone make up the fully qualified domain name associated with the public IP address."
|
||||
},
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
"agentEndpointDNSNamePrefix": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "Sets the Domain name label for the agent pool IP Address. The concatenation of the domain name label and the regional DNS zone make up the fully qualified domain name associated with the public IP address."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"disablePasswordAuthentication": {
|
||||
"defaultValue": true,
|
||||
"metadata": {
|
||||
"description": "This setting controls whether password auth is disabled for Linux VMs provisioned by this template. Default is true which disables password and makes SSH key required."
|
||||
},
|
||||
"type": "bool"
|
||||
},
|
||||
"enableNewStorageAccountNaming": {
|
||||
"defaultValue": true,
|
||||
"metadata": {
|
||||
"description": "If true: uses DNS name prefix + Orchestrator name + Region to create storage account name to reduce name collision probability. If false: uses DNS name prefix + Orchestrator name to create storage account name to maintain template idempotency."
|
||||
},
|
||||
"type": "bool"
|
||||
},
|
||||
"enableVMDiagnostics": {
|
||||
"defaultValue": true,
|
||||
"metadata": {
|
||||
"description": "Allows user to enable/disable boot & vm diagnostics."
|
||||
},
|
||||
"type": "bool"
|
||||
},
|
||||
"isValidation": {
|
||||
"allowedValues": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"defaultValue": 0,
|
||||
"metadata": {
|
||||
"description": "This is testing in the validation region"
|
||||
},
|
||||
"type": "int"
|
||||
},
|
||||
"jumpboxEndpointDNSNamePrefix": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "Sets the Domain name label for the jumpbox. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"linuxAdminPassword": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "Password for the Linux Virtual Machine. Not Required. If not set, you must provide a SSH key."
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"linuxOffer": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "This is the offer of the image used by the linux cluster"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"linuxPublisher": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "This is the publisher of the image used by the linux cluster"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"linuxSku": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "This is the linux sku used by the linux cluster"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"linuxVersion": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "This is the linux version used by the linux cluster"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"masterCount": {
|
||||
"allowedValues": [
|
||||
1,
|
||||
3,
|
||||
5
|
||||
],
|
||||
"defaultValue": 1,
|
||||
"metadata": {
|
||||
"description": "The number of Mesos masters for the cluster."
|
||||
},
|
||||
"type": "int"
|
||||
},
|
||||
"oauthEnabled": {
|
||||
"allowedValues": [
|
||||
"true",
|
||||
"false"
|
||||
],
|
||||
"defaultValue": "false",
|
||||
"metadata": {
|
||||
"description": "Enable OAuth authentication"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"postInstallScriptURI": {
|
||||
"defaultValue": "disabled",
|
||||
"metadata": {
|
||||
"description": "After installation, this specifies a script to download and install. To disabled, set value to 'disabled'."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"setLinuxConfigurationForVMCreate": {
|
||||
"allowedValues": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"defaultValue": 1,
|
||||
"metadata": {
|
||||
"description": "This setting controls whether Linux configuration with SSH Key is passed in VM PUT Payload. Defaults to 1. If SSH Key is blank, this must be set to 0."
|
||||
},
|
||||
"type": "int"
|
||||
},
|
||||
"vmsPerStorageAccount": {
|
||||
"defaultValue": 5,
|
||||
"metadata": {
|
||||
"description": "This specifies the number of VMs per storage accounts"
|
||||
},
|
||||
"type": "int"
|
||||
},
|
||||
{{if not .HasWindows}}
|
||||
"windowsAdminPassword": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "Password for the Windows Virtual Machine."
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"windowsAdminUsername": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "User name for the Windows Virtual Machine (Password Only Supported)."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
{{end}}
|
||||
"windowsJumpboxOffer": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "This is the windows offer used by the windows"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"windowsJumpboxPublisher": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "This is the windows publisher used by the windows"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"windowsJumpboxSku": {
|
||||
"defaultValue": "UNUSED",
|
||||
"metadata": {
|
||||
"description": "This is the windows sku used by the windows"
|
||||
},
|
||||
"type": "string"
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('storageLocation')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('storageAccountPrefixes')[mod(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('{{.Name}}VMSize')].storageAccountType]"
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('storageLocation')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('storageAccountPrefixes')[mod(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('{{.Name}}VMSize')].storageAccountType]"
|
||||
|
@ -80,7 +80,7 @@
|
|||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('storageLocation')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('storageAccountPrefixes')[mod(add(copyIndex(variables('dataStorageAccountPrefixSeed')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(copyIndex(variables('dataStorageAccountPrefixSeed')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}DataAccountName'))]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('{{.Name}}VMSize')].storageAccountType]"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"{{.Name}}StorageAccountOffset": "[mul(variables('maxStorageAccountsPerAgent'),variables('{{.Name}}Index'))]",
|
||||
"{{.Name}}Count": "[parameters('{{.Name}}Count')]",
|
||||
{{if .IsStateful}}
|
||||
{{if .IsVolumeBasedStorage}}
|
||||
"{{.Name}}AvailabilitySet": "[concat('{{.Name}}-availabilitySet-', variables('nameSuffix'))]",
|
||||
"{{.Name}}StorageAccountsCount": "[add(div(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')), mod(add(mod(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')),2), add(mod(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')),1)))]",
|
||||
{{else}}
|
||||
|
|
|
@ -8,18 +8,20 @@
|
|||
"variables": {
|
||||
{{range $index, $agent := .AgentPoolProfiles}}
|
||||
{{template "dcosagentvars.t" .}}
|
||||
{{if .IsStateful}}
|
||||
{{if .IsVolumeBasedStorage}}
|
||||
"{{.Name}}DataAccountName": "[concat(variables('storageAccountBaseName'), 'data{{$index}}')]",
|
||||
{{end}}
|
||||
"{{.Name}}Index": {{$index}},
|
||||
"{{.Name}}AccountName": "[concat(variables('storageAccountBaseName'), 'agnt{{$index}}')]",
|
||||
{{end}}
|
||||
|
||||
{{template "dcosmastervars.t" .}}
|
||||
{{template "dcosmastervars.t" .}},
|
||||
|
||||
{{GetSizeMap}}
|
||||
},
|
||||
"resources": [
|
||||
{{range .AgentPoolProfiles}}
|
||||
{{if .IsStateful}}
|
||||
{{if .IsVolumeBasedStorage}}
|
||||
{{template "dcosagentresourcesdisks.t" .}},
|
||||
{{else}}
|
||||
{{template "dcosagentresources.t" .}},
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('storageLocation')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('masterStorageAccountName')]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('masterVMSize')].storageAccountType]"
|
||||
|
@ -15,7 +15,7 @@
|
|||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('storageLocation')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('masterStorageAccountExhibitorName')]",
|
||||
"properties": {
|
||||
"accountType": "Standard_LRS"
|
||||
|
@ -141,12 +141,13 @@
|
|||
"name": "nicLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
{{if not .MasterProfile.IsCustomVNET}}
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
"[variables('masterNSGID')]",
|
||||
{{else}}
|
||||
"[variables('vnetID')]",
|
||||
{{end}}
|
||||
"[variables('masterLbID')]",
|
||||
"[concat(variables('masterLbID'),'/inboundNatRules/SSH-',variables('masterVMNamePrefix'),copyIndex())]",
|
||||
"[variables('masterNSGID')]"
|
||||
"[concat(variables('masterLbID'),'/inboundNatRules/SSH-',variables('masterVMNamePrefix'),copyIndex())]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('masterVMNamePrefix'), 'nic-', copyIndex())]",
|
||||
|
@ -172,10 +173,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"networkSecurityGroup": {
|
||||
]
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
,"networkSecurityGroup": {
|
||||
"id": "[variables('masterNSGID')]"
|
||||
}
|
||||
{{end}}
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
|
|
|
@ -41,197 +41,16 @@
|
|||
"[concat(variables('masterVMNamePrefix'), 'nic-6')]"
|
||||
],
|
||||
"masterVMSize": "[parameters('masterVMSize')]",
|
||||
"nameSuffix": "{{GetUniqueNameSuffix}}",
|
||||
"nameSuffix": "[parameters('nameSuffix')]",
|
||||
"oauthEnabled": "false",
|
||||
"orchestratorName": "dcos",
|
||||
"osImageOffer": "UbuntuServer",
|
||||
"osImagePublisher": "Canonical",
|
||||
"osImageSKU": "16.04.0-LTS",
|
||||
"osImageVersion": "16.04.201606270",
|
||||
"osImageVersion": "16.04.201606270",
|
||||
"sshKeyPath": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]",
|
||||
"sshRSAPublicKey": "[parameters('sshRSAPublicKey')]",
|
||||
"storageAccountBaseName": "[uniqueString(concat(variables('masterEndpointDNSNamePrefix'),resourceGroup().location, variables('orchestratorName')))]",
|
||||
"storageAccountPrefixes": [
|
||||
"0",
|
||||
"6",
|
||||
"c",
|
||||
"i",
|
||||
"o",
|
||||
"u",
|
||||
"1",
|
||||
"7",
|
||||
"d",
|
||||
"j",
|
||||
"p",
|
||||
"v",
|
||||
"2",
|
||||
"8",
|
||||
"e",
|
||||
"k",
|
||||
"q",
|
||||
"w",
|
||||
"3",
|
||||
"9",
|
||||
"f",
|
||||
"l",
|
||||
"r",
|
||||
"x",
|
||||
"4",
|
||||
"a",
|
||||
"g",
|
||||
"m",
|
||||
"s",
|
||||
"y",
|
||||
"5",
|
||||
"b",
|
||||
"h",
|
||||
"n",
|
||||
"t",
|
||||
"z"
|
||||
],
|
||||
"storageAccountPrefixes": [ "0", "6", "c", "i", "o", "u", "1", "7", "d", "j", "p", "v", "2", "8", "e", "k", "q", "w", "3", "9", "f", "l", "r", "x", "4", "a", "g", "m", "s", "y", "5", "b", "h", "n", "t", "z" ],
|
||||
"storageAccountPrefixesCount": "[length(variables('storageAccountPrefixes'))]",
|
||||
"storageAccountType": "Standard_LRS",
|
||||
"storageLocation": "[resourceGroup().location]",
|
||||
"vmSizesMap": {
|
||||
"Standard_A0": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A1": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A10": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A11": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A5": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A6": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A7": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A8": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A9": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D1": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D11": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D11_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D12": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D12_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D13": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D13_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D14": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D14_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D1_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D2_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D3_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D4_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D5_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_DS1": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS11": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS12": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS13": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS14": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS3": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS4": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_G1": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G5": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_GS1": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS3": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS4": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS5": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
}
|
||||
}
|
||||
"storageAccountType": "Standard_LRS"
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"apiVersion": "v1",
|
||||
"clusters": [
|
||||
{
|
||||
"cluster": {
|
||||
"certificate-authority-data": "<<<variables('caCertificate')>>>",
|
||||
"server": "https://<<<reference(concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))).dnsSettings.fqdn>>>"
|
||||
},
|
||||
"name": "{{{resourceGroup}}}"
|
||||
}
|
||||
],
|
||||
"contexts": [
|
||||
{
|
||||
"context": {
|
||||
"cluster": "{{{resourceGroup}}}",
|
||||
"user": "{{{resourceGroup}}}-admin"
|
||||
},
|
||||
"name": "{{{resourceGroup}}}"
|
||||
}
|
||||
],
|
||||
"current-context": "{{{resourceGroup}}}",
|
||||
"kind": "Config",
|
||||
"users": [
|
||||
{
|
||||
"name": "{{{resourceGroup}}}-admin",
|
||||
"user": {
|
||||
"client-certificate-data": "<<<variables('kubeConfigCertificate')>>>",
|
||||
"client-key-data": "<<<variables('kubeConfigPrivateKey')>>>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
#cloud-config
|
||||
|
||||
# { { { variable } } }
|
||||
|
||||
runcmd:
|
||||
- /usr/bin/curl -sSL --retry 12 --retry-delay 10 https://get.docker.com/ > /tmp/install-docker
|
||||
- /bin/bash -c "/bin/bash /tmp/install-docker"
|
||||
|
||||
write_files:
|
||||
- path: "/etc/systemd/system/docker.service.d/clear_mount_propagation_flags.conf"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
[Service]
|
||||
MountFlags=shared
|
||||
|
||||
- path: "/etc/systemd/system/docker.service.d/overlay.conf"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/usr/bin/docker daemon -H fd:// --storage-driver=overlay
|
||||
|
||||
- path: "/etc/kubernetes/certs/ca.crt"
|
||||
permissions: "0644"
|
||||
encoding: "base64"
|
||||
owner: "root"
|
||||
content: |
|
||||
{{{caCertificate}}}
|
||||
|
||||
- path: "/etc/kubernetes/certs/apiserver.crt"
|
||||
permissions: "0644"
|
||||
encoding: "base64"
|
||||
owner: "root"
|
||||
content: |
|
||||
{{{apiserverCertificate}}}
|
||||
|
||||
- path: "/etc/kubernetes/certs/client.crt"
|
||||
permissions: "0644"
|
||||
encoding: "base64"
|
||||
owner: "root"
|
||||
content: |
|
||||
{{{clientCertificate}}}
|
||||
|
||||
- path: "/var/lib/kubelet/kubeconfig"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- name: localcluster
|
||||
cluster:
|
||||
certificate-authority: /etc/kubernetes/certs/ca.crt
|
||||
server: https://{{{masterPrivateIp}}}:443
|
||||
users:
|
||||
- name: client
|
||||
user:
|
||||
client-certificate: /etc/kubernetes/certs/client.crt
|
||||
client-key: /etc/kubernetes/certs/client.key
|
||||
contexts:
|
||||
- context:
|
||||
cluster: localcluster
|
||||
user: client
|
||||
name: localclustercontext
|
||||
current-context: localclustercontext
|
||||
|
||||
- path: /etc/kubernetes/manifests/node.yaml
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata:
|
||||
name: "k8s-node"
|
||||
namespace: "kube-system"
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: "kube-proxy"
|
||||
image: "{{{kubernetesHyperkubeSpec}}}"
|
||||
command:
|
||||
- "/hyperkube"
|
||||
- "proxy"
|
||||
- "--kubeconfig=/var/lib/kubelet/kubeconfig"
|
||||
- "--proxy-mode=iptables"
|
||||
- "--v=2"
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: "etc-kubernetes"
|
||||
mountPath: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
mountPath: "/var/lib/kubelet"
|
||||
volumes:
|
||||
- name: "etc-kubernetes"
|
||||
hostPath:
|
||||
path: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
hostPath:
|
||||
path: "/var/lib/kubelet"
|
||||
|
||||
- path: "/etc/systemd/system/kubelet.service"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubelet
|
||||
Requires=docker.service
|
||||
After=docker.service
|
||||
[Service]
|
||||
Restart=always
|
||||
ExecStartPre=/bin/mkdir -p /var/lib/kubelet
|
||||
ExecStartPre=/bin/mount --bind /var/lib/kubelet /var/lib/kubelet
|
||||
ExecStartPre=/bin/mount --make-shared /var/lib/kubelet
|
||||
ExecStart=/usr/bin/docker run \
|
||||
--net=host \
|
||||
--pid=host \
|
||||
--privileged \
|
||||
--volume=/:/rootfs:ro \
|
||||
--volume=/sys:/sys:ro \
|
||||
--volume=/var/run:/var/run:rw \
|
||||
--volume=/var/lib/docker/:/var/lib/docker:rw \
|
||||
--volume=/var/lib/kubelet/:/var/lib/kubelet:shared \
|
||||
--volume=/var/log/containers/:/var/log/containers:rw \
|
||||
--volume=/etc/kubernetes/:/etc/kubernetes/:rw \
|
||||
{{{kubernetesHyperkubeSpec}}} \
|
||||
/hyperkube kubelet \
|
||||
--api-servers="https://{{{masterPrivateIp}}}:443" \
|
||||
--kubeconfig=/var/lib/kubelet/kubeconfig \
|
||||
--address=0.0.0.0 \
|
||||
--allow-privileged=true \
|
||||
--enable-server \
|
||||
--enable-debugging-handlers \
|
||||
--config=/etc/kubernetes/manifests \
|
||||
--cluster-dns={{{kubeDnsServiceIP}}} \
|
||||
--cluster-domain=cluster.local \
|
||||
--cloud-provider=azure \
|
||||
--cloud-config=/etc/kubernetes/azure.json \
|
||||
--hairpin-mode=promiscuous-bridge \
|
||||
--network-plugin=kubenet \
|
||||
--reconcile-cidr \
|
||||
--v=2
|
||||
ExecStop=/usr/bin/docker stop -t 2 kubelet
|
||||
|
||||
- path: "/opt/azure/containers/provision.sh"
|
||||
permissions: "0744"
|
||||
encoding: gzip
|
||||
owner: "root"
|
||||
content: !!binary |
|
||||
AGENT_PROVISION_B64_GZIP_STR
|
|
@ -0,0 +1,123 @@
|
|||
#!/bin/bash
|
||||
|
||||
###########################################################
|
||||
# START SECRET DATA - ECHO DISABLED
|
||||
###########################################################
|
||||
|
||||
TID=$1
|
||||
SID=$2
|
||||
RGP=$3
|
||||
LOC=$4
|
||||
SUB=$5
|
||||
NSG=$6
|
||||
VNT=$7
|
||||
RTB=$8
|
||||
SVCPrincipalClientId=$9
|
||||
SVCPrincipalClientSecret=${10}
|
||||
CLIENTPRIVATEKEY=${11}
|
||||
|
||||
CLIENTKEY=/etc/kubernetes/certs/client.key
|
||||
touch $CLIENTKEY
|
||||
chmod 0644 $CLIENTKEY
|
||||
chown root:root $CLIENTKEY
|
||||
echo $CLIENTPRIVATEKEY | /usr/bin/base64 --decode > $CLIENTKEY
|
||||
|
||||
AZUREJSON=/etc/kubernetes/azure.json
|
||||
touch $AZUREJSON
|
||||
chmod 0644 $AZUREJSON
|
||||
chown root:root $AZUREJSON
|
||||
AZURECONTENT=$(cat <<EOF
|
||||
{
|
||||
"tenantId": "$TID",
|
||||
"subscriptionId": "$SID",
|
||||
"aadClientId": "$SVCPrincipalClientId",
|
||||
"aadClientSecret": "$SVCPrincipalClientSecret",
|
||||
"resourceGroup": "$RGP",
|
||||
"location": "$LOC",
|
||||
"subnetName": "$SUB",
|
||||
"securityGroupName": "$NSG",
|
||||
"vnetName": "$VNT",
|
||||
"routeTableName": "$RTB"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
echo "$AZURECONTENT" > $AZUREJSON
|
||||
|
||||
###########################################################
|
||||
# END OF SECRET DATA
|
||||
###########################################################
|
||||
|
||||
set -x
|
||||
|
||||
# wait for docker to be available
|
||||
ensuredockerbinary()
|
||||
{
|
||||
dockerfound=1
|
||||
for i in {1..600}; do
|
||||
if [ -e /usr/bin/docker ]
|
||||
then
|
||||
dockerfound=0
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ $dockerfound -ne 0 ]
|
||||
then
|
||||
echo "kubectl nor docker did not install successfully"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
ensuredockerbinary
|
||||
|
||||
# start all the services
|
||||
/bin/systemctl restart docker
|
||||
ensureDocker()
|
||||
{
|
||||
dockerStarted=1
|
||||
for i in {1..600}; do
|
||||
/usr/bin/docker ps 2>&1 | grep "daemon running"
|
||||
if [ "$?" = "0" ]
|
||||
then
|
||||
echo "status $?"
|
||||
/bin/systemctl restart docker
|
||||
else
|
||||
echo "docker started"
|
||||
dockerStarted=0
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ $dockerStarted -ne 0 ]
|
||||
then
|
||||
echo "docker did not start"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
ensureDocker
|
||||
|
||||
/bin/systemctl restart kubelet
|
||||
|
||||
ensureKubernetes()
|
||||
{
|
||||
kubernetesStarted=1
|
||||
for i in {1..600}; do
|
||||
/usr/bin/docker ps | grep kubelet
|
||||
if [ "$?" = "0" ]
|
||||
then
|
||||
echo "kubernetes started"
|
||||
kubernetesStarted=0
|
||||
break
|
||||
else
|
||||
echo "kubernetes status $?"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ $kubernetesStarted -ne 0 ]
|
||||
then
|
||||
echo "kubernetes did not start"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
ensureKubernetes
|
||||
|
||||
echo "Install complete successfully"
|
|
@ -0,0 +1,166 @@
|
|||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}Count')]",
|
||||
"name": "loop"
|
||||
},
|
||||
"dependsOn": [
|
||||
{{if .IsCustomVNET}}
|
||||
"[variables('nsgID')]"
|
||||
{{else}}
|
||||
"[variables('vnetID')]"
|
||||
{{end}}
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[concat(variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex())]",
|
||||
"properties": {
|
||||
{{if .IsCustomVNET}}
|
||||
"networkSecurityGroup": {
|
||||
"id": "[variables('nsgID')]"
|
||||
},
|
||||
{{end}}
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"name": "ipconfig1",
|
||||
"properties": {
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"subnet": {
|
||||
"id": "[variables('{{.Name}}VnetSubnetID')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"enableIPForwarding": true
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionStorage')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}StorageAccountsCount')]",
|
||||
"name": "loop"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[concat(variables('storageAccountPrefixes')[mod(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('{{.Name}}VMSize')].storageAccountType]"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
{{if .HasDisks}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionStorage')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}StorageAccountsCount')]",
|
||||
"name": "datadiskLoop"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[concat(variables('storageAccountPrefixes')[mod(add(copyIndex(variables('dataStorageAccountPrefixSeed')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(copyIndex(variables('dataStorageAccountPrefixSeed')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}DataAccountName'))]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('{{.Name}}VMSize')].storageAccountType]"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
{{end}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('{{.Name}}AvailabilitySet')]",
|
||||
"properties": {},
|
||||
"type": "Microsoft.Compute/availabilitySets"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}Count')]",
|
||||
"name": "vmLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
{{if .HasDisks}}
|
||||
"[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}DataAccountName'))]",
|
||||
{{end}}
|
||||
"[concat('Microsoft.Network/networkInterfaces/', variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex())]",
|
||||
"[concat('Microsoft.Compute/availabilitySets/', variables('{{.Name}}AvailabilitySet'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex())]",
|
||||
"properties": {
|
||||
"availabilitySet": {
|
||||
"id": "[resourceId('Microsoft.Compute/availabilitySets',variables('{{.Name}}AvailabilitySet'))]"
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "[variables('{{.Name}}VMSize')]"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex()))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminUsername": "[variables('username')]",
|
||||
"computername": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex())]",
|
||||
{{GetKubernetesAgentCustomData .}}
|
||||
"linuxConfiguration": {
|
||||
"disablePasswordAuthentication": "true",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "[parameters('sshRSAPublicKey')]",
|
||||
"path": "[variables('sshKeyPath')]"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
{{GetDataDisks .}}
|
||||
"imageReference": {
|
||||
"offer": "[variables('osImageOffer')]",
|
||||
"publisher": "[variables('osImagePublisher')]",
|
||||
"sku": "[variables('osImageSKU')]",
|
||||
"version": "[variables('osImageVersion')]"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(),'-osdisk')]",
|
||||
"vhd": {
|
||||
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')),variables('apiVersionStorage')).primaryEndpoints.blob,'osdisk/', variables('{{.Name}}VMNamePrefix'), copyIndex(), '-osdisk.vhd')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}Count')]",
|
||||
"name": "vmLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Compute/virtualMachines/', variables('{{.Name}}VMNamePrefix'), copyIndex())]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"type": "Microsoft.Compute/virtualMachines/extensions",
|
||||
"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(),'/cse', copyIndex())]",
|
||||
"properties": {
|
||||
"publisher": "Microsoft.OSTCExtensions",
|
||||
"type": "CustomScriptForLinux",
|
||||
"typeHandlerVersion": "1.5",
|
||||
"autoUpgradeMinorVersion": true,
|
||||
"settings": {},
|
||||
"protectedSettings": {
|
||||
"commandToExecute": "[concat('/usr/bin/nohup /bin/bash -c \"/bin/bash /opt/azure/containers/provision.sh ',variables('tenantID'),' ',variables('subscriptionId'),' ',variables('resourceGroup'),' ',variables('location'),' ',variables('subnetName'),' ',variables('nsgName'),' ',variables('virtualNetworkName'),' ',variables('routeTableName'),' {{GetAgentSecrets}} >> /var/log/azure/cluster-provision.log 2>&1 &\" &')]"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
"{{.Name}}StorageAccountOffset": "[mul(variables('maxStorageAccountsPerAgent'),variables('{{.Name}}Index'))]",
|
||||
"{{.Name}}Count": "[parameters('{{.Name}}Count')]",
|
||||
"{{.Name}}AvailabilitySet": "[concat('{{.Name}}-availabilitySet-', variables('nameSuffix'))]",
|
||||
"{{.Name}}StorageAccountsCount": "[add(div(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')), mod(add(mod(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')),2), add(mod(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')),1)))]",
|
||||
"{{.Name}}VMNamePrefix": "[concat(variables('orchestratorName'), '-{{.Name}}-', variables('nameSuffix'), '-')]",
|
||||
"{{.Name}}VMSize": "[parameters('{{.Name}}VMSize')]",
|
||||
{{if .IsCustomVNET}}
|
||||
"{{.Name}}VnetSubnetID": "[parameters('{{.Name}}VnetSubnetID')]",
|
||||
"{{.Name}}SubnetName": "[parameters('{{.Name}}VnetSubnetID')]",
|
||||
"{{.Name}}VnetParts": "[split(parameters('{{.Name}}VnetSubnetID'),'/subnets/')]",
|
||||
{{else}}
|
||||
"{{.Name}}VnetSubnetID": "[variables('vnetSubnetID')]",
|
||||
"{{.Name}}SubnetName": "[variables('subnetName')]",
|
||||
{{end}}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
{{range .AgentPoolProfiles}}{{template "agentparams.t" .}},{{end}}
|
||||
{{template "masterparams.t" .}},
|
||||
{{template "kubernetesparams.t" .}}
|
||||
},
|
||||
"variables": {
|
||||
{{range $index, $agent := .AgentPoolProfiles}}
|
||||
{{template "kubernetesagentvars.t" .}}
|
||||
{{if .HasDisks}}
|
||||
"{{.Name}}DataAccountName": "[concat(variables('storageAccountBaseName'), 'data{{$index}}')]",
|
||||
{{end}}
|
||||
"{{.Name}}Index": {{$index}},
|
||||
"{{.Name}}AccountName": "[concat(variables('storageAccountBaseName'), 'agnt{{$index}}')]",
|
||||
{{end}}
|
||||
{{template "kubernetesmastervars.t" .}},
|
||||
|
||||
{{GetSizeMap}}
|
||||
},
|
||||
"resources": [
|
||||
{{range .AgentPoolProfiles}}
|
||||
{{template "kubernetesagentresources.t" .}},
|
||||
{{end}}
|
||||
{{template "kubernetesmasterresources.t" .}}
|
||||
],
|
||||
"outputs": {
|
||||
{{template "masteroutputs.t" .}}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
#cloud-config
|
||||
|
||||
# { { { variable } } }
|
||||
|
||||
packages:
|
||||
- etcd
|
||||
- jq
|
||||
- traceroute
|
||||
|
||||
runcmd:
|
||||
- /bin/bash -c "/bin/echo DAEMON_ARGS=--advertise-client-urls ""http://127.0.0.1:2379,http://{{{masterPrivateIp}}}:2379"" --listen-client-urls ""http://0.0.0.0:2379,http://0.0.0.0:4001"" | tee -a /etc/default/etcd"
|
||||
- /usr/bin/curl -sSL --retry 12 --retry-delay 10 https://get.docker.com/ > /tmp/install-docker
|
||||
- /bin/bash -c "/bin/bash /tmp/install-docker"
|
||||
- /usr/bin/curl -sSL --retry 12 --retry-delay 10 https://storage.googleapis.com/kubernetes-release/release/v1.4.1/bin/linux/amd64/kubectl > /usr/local/bin/kubectl
|
||||
- chmod +x /usr/local/bin/kubectl
|
||||
|
||||
write_files:
|
||||
- path: "/etc/systemd/system/docker.service.d/clear_mount_propagation_flags.conf"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
[Service]
|
||||
MountFlags=shared
|
||||
|
||||
- path: "/etc/systemd/system/docker.service.d/overlay.conf"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/usr/bin/docker daemon -H fd:// --storage-driver=overlay
|
||||
|
||||
- path: "/etc/kubernetes/certs/ca.crt"
|
||||
permissions: "0644"
|
||||
encoding: "base64"
|
||||
owner: "root"
|
||||
content: |
|
||||
{{{caCertificate}}}
|
||||
|
||||
- path: "/etc/kubernetes/certs/apiserver.crt"
|
||||
permissions: "0644"
|
||||
encoding: "base64"
|
||||
owner: "root"
|
||||
content: |
|
||||
{{{apiServerCertificate}}}
|
||||
|
||||
- path: "/etc/kubernetes/certs/client.crt"
|
||||
permissions: "0644"
|
||||
encoding: "base64"
|
||||
owner: "root"
|
||||
content: |
|
||||
{{{clientCertificate}}}
|
||||
|
||||
- path: "/var/lib/kubelet/kubeconfig"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- name: localcluster
|
||||
cluster:
|
||||
certificate-authority: /etc/kubernetes/certs/ca.crt
|
||||
server: https://{{{masterPrivateIp}}}:443
|
||||
users:
|
||||
- name: client
|
||||
user:
|
||||
client-certificate: /etc/kubernetes/certs/client.crt
|
||||
client-key: /etc/kubernetes/certs/client.key
|
||||
contexts:
|
||||
- context:
|
||||
cluster: localcluster
|
||||
user: client
|
||||
name: localclustercontext
|
||||
current-context: localclustercontext
|
||||
|
||||
- path: /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata:
|
||||
name: "kube-apiserver"
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
tier: control-plane
|
||||
component: kube-apiserver
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: "kube-apiserver"
|
||||
image: "{{{kubernetesHyperkubeSpec}}}"
|
||||
command:
|
||||
- "/hyperkube"
|
||||
- "apiserver"
|
||||
- "--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota"
|
||||
- "--address=0.0.0.0"
|
||||
- "--allow-privileged"
|
||||
- "--insecure-port=8080"
|
||||
- "--secure-port=443"
|
||||
- "--cloud-provider=azure"
|
||||
- "--cloud-config=/etc/kubernetes/azure.json"
|
||||
- "--service-cluster-ip-range={{{kubeServiceCidr}}}"
|
||||
- "--etcd-servers=http://127.0.0.1:4001"
|
||||
- "--tls-cert-file=/etc/kubernetes/certs/apiserver.crt"
|
||||
- "--tls-private-key-file=/etc/kubernetes/certs/apiserver.key"
|
||||
- "--client-ca-file=/etc/kubernetes/certs/ca.crt"
|
||||
- "--service-account-key-file=/etc/kubernetes/certs/apiserver.key"
|
||||
- "--v=4"
|
||||
volumeMounts:
|
||||
- name: "etc-kubernetes"
|
||||
mountPath: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
mountPath: "/var/lib/kubelet"
|
||||
volumes:
|
||||
- name: "etc-kubernetes"
|
||||
hostPath:
|
||||
path: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
hostPath:
|
||||
path: "/var/lib/kubelet"
|
||||
|
||||
- path: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata:
|
||||
name: "kube-controller-manager"
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
tier: control-plane
|
||||
component: kube-controller-manager
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: "kube-controller-manager"
|
||||
image: "{{{kubernetesHyperkubeSpec}}}"
|
||||
command:
|
||||
- "/hyperkube"
|
||||
- "controller-manager"
|
||||
- "--master=127.0.0.1:8080"
|
||||
- "--kubeconfig=/var/lib/kubelet/kubeconfig"
|
||||
- "--allocate-node-cidrs=true"
|
||||
- "--cluster-cidr=10.244.0.0/16"
|
||||
- "--cluster-name={{{masterFqdnPrefix}}}"
|
||||
- "--cloud-provider=azure"
|
||||
- "--cloud-config=/etc/kubernetes/azure.json"
|
||||
- "--root-ca-file=/etc/kubernetes/certs/ca.crt"
|
||||
- "--service-account-private-key-file=/etc/kubernetes/certs/apiserver.key"
|
||||
- "--v=2"
|
||||
volumeMounts:
|
||||
- name: "etc-kubernetes"
|
||||
mountPath: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
mountPath: "/var/lib/kubelet"
|
||||
volumes:
|
||||
- name: "etc-kubernetes"
|
||||
hostPath:
|
||||
path: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
hostPath:
|
||||
path: "/var/lib/kubelet"
|
||||
|
||||
- path: /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata:
|
||||
name: "kube-scheduler"
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
tier: control-plane
|
||||
component: kube-scheduler
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: "kube-scheduler"
|
||||
image: "{{{kubernetesHyperkubeSpec}}}"
|
||||
command:
|
||||
- "/hyperkube"
|
||||
- "scheduler"
|
||||
- "--master=127.0.0.1:8080"
|
||||
- "--kubeconfig=/var/lib/kubelet/kubeconfig"
|
||||
- "--v=2"
|
||||
volumeMounts:
|
||||
- name: "etc-kubernetes"
|
||||
mountPath: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
mountPath: "/var/lib/kubelet"
|
||||
volumes:
|
||||
- name: "etc-kubernetes"
|
||||
hostPath:
|
||||
path: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
hostPath:
|
||||
path: "/var/lib/kubelet"
|
||||
|
||||
- path: /etc/kubernetes/manifests/kube-proxy.yaml
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata:
|
||||
name: "kube-proxy"
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
tier: control-plane
|
||||
component: kube-proxy
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: "kube-proxy"
|
||||
image: "{{{kubernetesHyperkubeSpec}}}"
|
||||
command:
|
||||
- "/hyperkube"
|
||||
- "proxy"
|
||||
- "--kubeconfig=/var/lib/kubelet/kubeconfig"
|
||||
- "--proxy-mode=iptables"
|
||||
- "--v=2"
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: "etc-kubernetes"
|
||||
mountPath: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
mountPath: "/var/lib/kubelet"
|
||||
volumes:
|
||||
- name: "etc-kubernetes"
|
||||
hostPath:
|
||||
path: "/etc/kubernetes"
|
||||
- name: "var-lib-kubelet"
|
||||
hostPath:
|
||||
path: "/var/lib/kubelet"
|
||||
|
||||
- path: "/etc/systemd/system/kubelet.service"
|
||||
permissions: "0644"
|
||||
owner: "root"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubelet
|
||||
Requires=docker.service
|
||||
After=docker.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
ExecStartPre=/bin/mkdir -p /var/lib/kubelet
|
||||
ExecStartPre=/bin/mount --bind /var/lib/kubelet /var/lib/kubelet
|
||||
ExecStartPre=/bin/mount --make-shared /var/lib/kubelet
|
||||
ExecStart=/usr/bin/docker run \
|
||||
--net=host \
|
||||
--pid=host \
|
||||
--privileged \
|
||||
--volume=/:/rootfs:ro \
|
||||
--volume=/sys:/sys:ro \
|
||||
--volume=/var/run:/var/run:rw \
|
||||
--volume=/var/lib/docker/:/var/lib/docker:rw \
|
||||
--volume=/var/lib/kubelet/:/var/lib/kubelet:shared \
|
||||
--volume=/var/log/containers/:/var/log/containers:rw \
|
||||
--volume=/etc/kubernetes/:/etc/kubernetes:rw \
|
||||
{{{kubernetesHyperkubeSpec}}} \
|
||||
/hyperkube kubelet \
|
||||
--api-servers="https://{{{masterPrivateIp}}}:443" \
|
||||
--kubeconfig=/var/lib/kubelet/kubeconfig \
|
||||
--address=0.0.0.0 \
|
||||
--allow-privileged=true \
|
||||
--enable-server \
|
||||
--enable-debugging-handlers \
|
||||
--config=/etc/kubernetes/manifests \
|
||||
--cluster-dns={{{kubeDnsServiceIP}}} \
|
||||
--cluster-domain=cluster.local \
|
||||
--register-schedulable=false \
|
||||
--cloud-provider=azure \
|
||||
--cloud-config=/etc/kubernetes/azure.json \
|
||||
--v=2
|
||||
ExecStop=/usr/bin/docker stop -t 2 kubelet
|
||||
|
||||
- path: "/opt/azure/containers/provision.sh"
|
||||
permissions: "0744"
|
||||
encoding: gzip
|
||||
owner: "root"
|
||||
content: !!binary |
|
||||
MASTER_PROVISION_B64_GZIP_STR
|
|
@ -0,0 +1,143 @@
|
|||
#!/bin/bash
|
||||
|
||||
###########################################################
|
||||
# START SECRET DATA - ECHO DISABLED
|
||||
###########################################################
|
||||
TID=$1
|
||||
SID=$2
|
||||
RGP=$3
|
||||
LOC=$4
|
||||
SUB=$5
|
||||
NSG=$6
|
||||
VNT=$7
|
||||
RTB=$8
|
||||
SVCPrincipalClientId=$9
|
||||
SVCPrincipalClientSecret=${10}
|
||||
CLIENTPRIVATEKEY=${11}
|
||||
SERVERPRIVATEKEY=${12}
|
||||
|
||||
APISERVERKEY=/etc/kubernetes/certs/apiserver.key
|
||||
touch $APISERVERKEY
|
||||
chmod 0644 $APISERVERKEY
|
||||
chown root:root $APISERVERKEY
|
||||
echo $SERVERPRIVATEKEY | /usr/bin/base64 --decode > $APISERVERKEY
|
||||
|
||||
CLIENTKEY=/etc/kubernetes/certs/client.key
|
||||
touch $CLIENTKEY
|
||||
chmod 0644 $CLIENTKEY
|
||||
chown root:root $CLIENTKEY
|
||||
echo $CLIENTPRIVATEKEY | /usr/bin/base64 --decode > $CLIENTKEY
|
||||
|
||||
AZUREJSON=/etc/kubernetes/azure.json
|
||||
touch $AZUREJSON
|
||||
chmod 0644 $AZUREJSON
|
||||
chown root:root $AZUREJSON
|
||||
AZURECONTENT=$(cat <<EOF
|
||||
{
|
||||
"tenantId": "$TID",
|
||||
"subscriptionId": "$SID",
|
||||
"aadClientId": "$SVCPrincipalClientId",
|
||||
"aadClientSecret": "$SVCPrincipalClientSecret",
|
||||
"resourceGroup": "$RGP",
|
||||
"location": "$LOC",
|
||||
"subnetName": "$SUB",
|
||||
"securityGroupName": "$NSG",
|
||||
"vnetName": "$VNT",
|
||||
"routeTableName": "$RTB"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
echo "$AZURECONTENT" > $AZUREJSON
|
||||
|
||||
###########################################################
|
||||
# END OF SECRET DATA
|
||||
###########################################################
|
||||
|
||||
set -x
|
||||
|
||||
# wait for kubectl to report successful cluster health
|
||||
ensurekubectl()
|
||||
{
|
||||
kubectlfound=1
|
||||
for i in {1..600}; do
|
||||
if [ -e /usr/local/bin/kubectl ]
|
||||
then
|
||||
kubectlfound=0
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ $kubectlfound -ne 0 ]
|
||||
then
|
||||
if [ ! -e /usr/bin/docker ]
|
||||
then
|
||||
echo "kubectl nor docker did not install successfully"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
ensurekubectl
|
||||
|
||||
/bin/systemctl restart etcd
|
||||
|
||||
# start all the services
|
||||
/bin/systemctl restart docker
|
||||
ensureDocker()
|
||||
{
|
||||
dockerStarted=1
|
||||
for i in {1..600}; do
|
||||
/usr/bin/docker ps 2>&1 | grep "daemon running"
|
||||
if [ "$?" = "0" ]
|
||||
then
|
||||
echo "status $?"
|
||||
/bin/systemctl restart docker
|
||||
else
|
||||
echo "docker started"
|
||||
dockerStarted=0
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ $dockerStarted -ne 0 ]
|
||||
then
|
||||
echo "docker did not start"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
ensureDocker
|
||||
|
||||
/bin/systemctl restart kubelet
|
||||
#wait for kubernetes to start
|
||||
ensureKubernetes()
|
||||
{
|
||||
kubernetesStarted=1
|
||||
for i in {1..600}; do
|
||||
if [ -e /usr/local/bin/kubectl ]
|
||||
then
|
||||
/usr/local/bin/kubectl cluster-info
|
||||
if [ "$?" = "0" ]
|
||||
then
|
||||
echo "kubernetes started"
|
||||
kubernetesStarted=0
|
||||
break
|
||||
fi
|
||||
else
|
||||
/usr/bin/docker ps | grep apiserver
|
||||
if [ "$?" = "0" ]
|
||||
then
|
||||
echo "kubernetes started"
|
||||
kubernetesStarted=0
|
||||
break
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ $kubernetesStarted -ne 0 ]
|
||||
then
|
||||
echo "kubernetes did not start"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
ensureKubernetes
|
||||
|
||||
echo "Install complete successfully"
|
|
@ -0,0 +1,323 @@
|
|||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('masterAvailabilitySet')]",
|
||||
"properties": {},
|
||||
"type": "Microsoft.Compute/availabilitySets"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionStorage')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('masterStorageAccountName')]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('masterVMSize')].storageAccountType]"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
{{if not .MasterProfile.IsCustomVNET}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
|
||||
"[concat('Microsoft.Network/routeTables/', variables('routeTableName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('virtualNetworkName')]",
|
||||
"properties": {
|
||||
"addressSpace": {
|
||||
"addressPrefixes": [
|
||||
"[variables('vnetCidr')]"
|
||||
]
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"name": "[variables('subnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('subnet')]",
|
||||
"networkSecurityGroup": {
|
||||
"id": "[variables('nsgID')]"
|
||||
},
|
||||
"routeTable": {
|
||||
"id": "[variables('routeTableID')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
},
|
||||
{{end}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('nsgName')]",
|
||||
"properties": {
|
||||
"securityRules": [
|
||||
{
|
||||
"name": "allow_ssh",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "Allow SSH traffic to master",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationPortRange": "22-22",
|
||||
"direction": "Inbound",
|
||||
"priority": 101,
|
||||
"protocol": "Tcp",
|
||||
"sourceAddressPrefix": "*",
|
||||
"sourcePortRange": "*"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "allow_kube_tls",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "Allow kube-apiserver (tls) traffic to master",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationPortRange": "443-443",
|
||||
"direction": "Inbound",
|
||||
"priority": 100,
|
||||
"protocol": "Tcp",
|
||||
"sourceAddressPrefix": "*",
|
||||
"sourcePortRange": "*"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('routeTableName')]",
|
||||
"type": "Microsoft.Network/routeTables"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('masterLbName')]",
|
||||
"properties": {
|
||||
"backendAddressPools": [
|
||||
{
|
||||
"name": "[variables('masterLbBackendPoolName')]"
|
||||
}
|
||||
],
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"name": "[variables('masterLbIPConfigName')]",
|
||||
"properties": {
|
||||
"publicIPAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('masterPublicIPAddressName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"loadBalancingRules": [
|
||||
{
|
||||
"name": "LBRuleHTTPS",
|
||||
"properties": {
|
||||
"frontendIPConfiguration": {
|
||||
"id": "[variables('masterLbIPConfigID')]"
|
||||
},
|
||||
"backendAddressPool": {
|
||||
"id": "[concat(variables('masterLbID'), '/backendAddressPools/', variables('masterLbBackendPoolName'))]"
|
||||
},
|
||||
"protocol": "tcp",
|
||||
"frontendPort": 443,
|
||||
"backendPort": 443,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 5,
|
||||
"loadDistribution": "Default",
|
||||
"probe": {
|
||||
"id": "[concat(variables('masterLbID'),'/probes/tcpHTTPSProbe')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"name": "tcpHTTPSProbe",
|
||||
"properties": {
|
||||
"protocol": "tcp",
|
||||
"port": 443,
|
||||
"intervalInSeconds": "5",
|
||||
"numberOfProbes": "2"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/loadBalancers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('masterPublicIPAddressName')]",
|
||||
"properties": {
|
||||
"dnsSettings": {
|
||||
"domainNameLabel": "[variables('masterFqdnPrefix')]"
|
||||
},
|
||||
"publicIPAllocationMethod": "Dynamic"
|
||||
},
|
||||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "masterLbLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[variables('masterLbID')]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[concat(variables('masterLbName'), '/', 'SSH-', variables('masterVMNamePrefix'), copyIndex())]",
|
||||
"properties": {
|
||||
"backendPort": 22,
|
||||
"enableFloatingIP": false,
|
||||
"frontendIPConfiguration": {
|
||||
"id": "[variables('masterLbIPConfigID')]"
|
||||
},
|
||||
"frontendPort": "[variables('sshNatPorts')[copyIndex()]]",
|
||||
"protocol": "tcp"
|
||||
},
|
||||
"type": "Microsoft.Network/loadBalancers/inboundNatRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "nicLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
"[variables('nsgID')]",
|
||||
{{else}}
|
||||
"[variables('vnetID')]",
|
||||
{{end}}
|
||||
"[concat(variables('masterLbID'),'/inboundNatRules/SSH-',variables('masterVMNamePrefix'),copyIndex())]",
|
||||
"[variables('nsgID')]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[concat(variables('masterVMNamePrefix'), 'nic-', copyIndex())]",
|
||||
"properties": {
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"name": "ipconfig1",
|
||||
"properties": {
|
||||
"loadBalancerBackendAddressPools": [
|
||||
{
|
||||
"id": "[concat(variables('masterLbID'), '/backendAddressPools/', variables('masterLbBackendPoolName'))]"
|
||||
}
|
||||
],
|
||||
"loadBalancerInboundNatRules": [
|
||||
{
|
||||
"id": "[concat(variables('masterLbID'),'/inboundNatRules/SSH-',variables('masterVMNamePrefix'),copyIndex())]"
|
||||
}
|
||||
],
|
||||
"privateIPAddress": "[concat(variables('masterFirstAddrPrefix'), copyIndex(int(variables('masterFirstAddrOctet4'))))]",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"id": "[variables('vnetSubnetID')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"enableIPForwarding": true
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
,"networkSecurityGroup": {
|
||||
"id": "[variables('nsgID')]"
|
||||
}
|
||||
{{end}}
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "vmLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/networkInterfaces/', variables('masterVMNamePrefix'), 'nic-', copyIndex())]",
|
||||
"[concat('Microsoft.Compute/availabilitySets/',variables('masterAvailabilitySet'))]",
|
||||
"[variables('masterStorageAccountName')]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[concat(variables('masterVMNamePrefix'), copyIndex())]",
|
||||
"properties": {
|
||||
"availabilitySet": {
|
||||
"id": "[resourceId('Microsoft.Compute/availabilitySets',variables('masterAvailabilitySet'))]"
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "[variables('masterVMSize')]"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('masterVMNamePrefix'),'nic-', copyIndex()))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminUsername": "[variables('username')]",
|
||||
"computername": "[concat(variables('masterVMNamePrefix'), copyIndex())]",
|
||||
{{GetKubernetesMasterCustomData}}
|
||||
"linuxConfiguration": {
|
||||
"disablePasswordAuthentication": "true",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "[variables('sshPublicKeyData')]",
|
||||
"path": "[variables('sshKeyPath')]"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
"imageReference": {
|
||||
"offer": "[variables('osImageOffer')]",
|
||||
"publisher": "[variables('osImagePublisher')]",
|
||||
"sku": "[variables('osImageSku')]",
|
||||
"version": "[variables('osImageVersion')]"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[concat(variables('masterVMNamePrefix'), copyIndex(),'-osdisk')]",
|
||||
"vhd": {
|
||||
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('masterStorageAccountName')),variables('apiVersionStorage')).primaryEndpoints.blob,'vhds/',variables('masterVMNamePrefix'),copyIndex(),'-osdisk.vhd')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "vmLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Compute/virtualMachines/', variables('masterVMNamePrefix'), copyIndex())]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"type": "Microsoft.Compute/virtualMachines/extensions",
|
||||
"name": "[concat(variables('masterVMNamePrefix'), copyIndex(),'/cse', copyIndex())]",
|
||||
"properties": {
|
||||
"publisher": "Microsoft.OSTCExtensions",
|
||||
"type": "CustomScriptForLinux",
|
||||
"typeHandlerVersion": "1.5",
|
||||
"autoUpgradeMinorVersion": true,
|
||||
"settings": {},
|
||||
"protectedSettings": {
|
||||
"commandToExecute": "[concat('/usr/bin/nohup /bin/bash -c \"/bin/bash /opt/azure/containers/provision.sh ',variables('tenantID'),' ',variables('subscriptionId'),' ',variables('resourceGroup'),' ',variables('location'),' ',variables('subnetName'),' ',variables('nsgName'),' ',variables('virtualNetworkName'),' ',variables('routeTableName'),' {{GetMasterSecrets}} >> /var/log/azure/cluster-provision.log 2>&1 &\" &')]"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
"maxVMsPerPool": 100,
|
||||
"maxVMsPerStorageAccount": 20,
|
||||
"maxStorageAccountsPerAgent": "[div(variables('maxVMsPerPool'),variables('maxVMsPerStorageAccount'))]",
|
||||
"apiServerCertificate": "[parameters('apiServerCertificate')]",
|
||||
"apiServerPrivateKey": "[parameters('apiServerPrivateKey')]",
|
||||
"caCertificate": "[parameters('caCertificate')]",
|
||||
"clientCertificate": "[parameters('clientCertificate')]",
|
||||
"clientPrivateKey": "[parameters('clientPrivateKey')]",
|
||||
"kubeConfigCertificate": "[parameters('kubeConfigCertificate')]",
|
||||
"kubeConfigPrivateKey": "[parameters('kubeConfigPrivateKey')]",
|
||||
"kubernetesHyperkubeSpec": "[parameters('kubernetesHyperkubeSpec')]",
|
||||
"servicePrincipalClientId": "[parameters('servicePrincipalClientId')]",
|
||||
"servicePrincipalClientSecret": "[parameters('servicePrincipalClientSecret')]",
|
||||
"username": "[parameters('linuxAdminUsername')]",
|
||||
"masterFqdnPrefix": "[parameters('masterEndpointDNSNamePrefix')]",
|
||||
"masterPrivateIp": "[parameters('firstConsecutiveStaticIP')]",
|
||||
"masterVMSize": "[parameters('masterVMSize')]",
|
||||
"sshPublicKeyData": "[parameters('sshRSAPublicKey')]",
|
||||
"masterCount": {{.MasterProfile.Count}},
|
||||
"apiVersionDefault": "2016-03-30",
|
||||
"apiVersionStorage": "2015-06-15",
|
||||
"location": "[resourceGroup().location]",
|
||||
"masterAvailabilitySet": "master-availabilityset",
|
||||
"storageAccountBaseName": "[uniqueString(concat(variables('masterFqdnPrefix'),resourceGroup().location, variables('orchestratorName')))]",
|
||||
"masterStorageAccountName": "[concat(variables('storageAccountBaseName'), 'mstr0')]",
|
||||
"nameSuffix": "[parameters('nameSuffix')]",
|
||||
"orchestratorName": "k8s",
|
||||
"osImageOffer": "UbuntuServer",
|
||||
"osImagePublisher": "Canonical",
|
||||
"osImageSKU": "16.04.0-LTS",
|
||||
"osImageVersion": "16.04.201606270",
|
||||
"resourceGroup": "[resourceGroup().name]",
|
||||
"routeTableName": "[concat(variables('masterVMNamePrefix'),'routetable')]",
|
||||
"routeTableID": "[resourceId('Microsoft.Network/routeTables', variables('routeTableName'))]",
|
||||
"sshNatPorts": [22,2201,2202,2203,2204],
|
||||
"sshKeyPath": "[concat('/home/',variables('username'),'/.ssh/authorized_keys')]",
|
||||
"storageAccountBaseName": "[uniqueString(concat(variables('masterFqdnPrefix'),resourceGroup().location))]",
|
||||
"storageAccountPrefixes": [ "0", "6", "c", "i", "o", "u", "1", "7", "d", "j", "p", "v", "2", "8", "e", "k", "q", "w", "3", "9", "f", "l", "r", "x", "4", "a", "g", "m", "s", "y", "5", "b", "h", "n", "t", "z" ],
|
||||
"storageAccountPrefixesCount": "[length(variables('storageAccountPrefixes'))]",
|
||||
"vmsPerStorageAccount": 20,
|
||||
{{if AnyAgentHasDisks}}
|
||||
"dataStorageAccountPrefixSeed": 97,
|
||||
{{end}}
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
"vnetSubnetID": "[parameters('masterVnetSubnetID')]",
|
||||
"subnetName": "[parameters('masterVnetSubnetID')]",
|
||||
"vnetParts": "[split(parameters('masterVnetSubnetID'),'/subnets/')]",
|
||||
"virtualNetworkName": "[variables('vnetParts')[0]]",
|
||||
{{else}}
|
||||
"subnet": "[parameters('masterSubnet')]",
|
||||
"subnetName": "[concat(variables('orchestratorName'), '-subnet')]",
|
||||
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
|
||||
"vnetSubnetID": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
|
||||
"virtualNetworkName": "[concat(variables('orchestratorName'), '-vnet-', variables('nameSuffix'))]",
|
||||
"vnetCidr": "10.0.0.0/8",
|
||||
{{end}}
|
||||
"kubeDnsServiceIp": "10.0.0.10",
|
||||
"kubeServiceCidr": "10.0.0.0/16",
|
||||
"nsgName": "[concat(variables('masterVMNamePrefix'), 'nsg')]",
|
||||
"nsgID": "[resourceId('Microsoft.Network/networkSecurityGroups',variables('nsgName'))]",
|
||||
"masterPublicIPAddressName": "[concat(variables('orchestratorName'), '-master-ip-', variables('masterFqdnPrefix'), '-', variables('nameSuffix'))]",
|
||||
"masterLbID": "[resourceId('Microsoft.Network/loadBalancers',variables('masterLbName'))]",
|
||||
"masterLbIPConfigID": "[concat(variables('masterLbID'),'/frontendIPConfigurations/', variables('masterLbIPConfigName'))]",
|
||||
"masterLbIPConfigName": "[concat(variables('orchestratorName'), '-master-lbFrontEnd-', variables('nameSuffix'))]",
|
||||
"masterLbName": "[concat(variables('orchestratorName'), '-master-lb-', variables('nameSuffix'))]",
|
||||
"masterLbBackendPoolName": "[concat(variables('orchestratorName'), '-master-pool-', variables('nameSuffix'))]",
|
||||
"masterFirstAddrComment": "these MasterFirstAddrComment are used to place multiple masters consecutively in the address space",
|
||||
"masterFirstAddrOctets": "[split(parameters('firstConsecutiveStaticIP'),'.')]",
|
||||
"masterFirstAddrOctet4": "[variables('masterFirstAddrOctets')[3]]",
|
||||
"masterFirstAddrPrefix": "[concat(variables('masterFirstAddrOctets')[0],'.',variables('masterFirstAddrOctets')[1],'.',variables('masterFirstAddrOctets')[2],'.')]",
|
||||
"masterVMNamePrefix": "[concat(variables('orchestratorName'), '-master-', variables('nameSuffix'), '-')]",
|
||||
"subscriptionId": "[subscription().subscriptionId]",
|
||||
"tenantId": "[subscription().tenantId]"
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
"apiServerCertificate": {
|
||||
"metadata": {
|
||||
"description": "The base 64 server certificate used on the master"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"apiServerPrivateKey": {
|
||||
"metadata": {
|
||||
"description": "The base 64 server private key used on the master."
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"caCertificate": {
|
||||
"metadata": {
|
||||
"description": "The base 64 certificate authority certificate"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"clientCertificate": {
|
||||
"metadata": {
|
||||
"description": "The base 64 client certificate used to communicate with the master"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"clientPrivateKey": {
|
||||
"metadata": {
|
||||
"description": "The base 64 client private key used to communicate with the master"
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"kubeConfigCertificate": {
|
||||
"metadata": {
|
||||
"description": "The base 64 certificate used by cli to communicate with the master"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"kubeConfigPrivateKey": {
|
||||
"metadata": {
|
||||
"description": "The base 64 private key used by cli to communicate with the master"
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"kubernetesHyperkubeSpec": {
|
||||
"metadata": {
|
||||
"description": "The container spec for hyperkube."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"servicePrincipalClientId": {
|
||||
"metadata": {
|
||||
"description": "Client ID (used by cloudprovider)"
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"servicePrincipalClientSecret": {
|
||||
"metadata": {
|
||||
"description": "The Service Principal Client Secret."
|
||||
},
|
||||
"type": "securestring"
|
||||
}
|
|
@ -2,3 +2,19 @@
|
|||
"type": "string",
|
||||
"value": "[reference(concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))).dnsSettings.fqdn]"
|
||||
}
|
||||
{{if .GetClassicMode}}
|
||||
{{if RequiresFakeAgentOutput}}
|
||||
,"agentFQDN": {
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{{end}}
|
||||
"diagnosticsStorageAccountUri": {
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
"jumpboxFQDN": {
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
{{end}}
|
|
@ -1,12 +1,10 @@
|
|||
"linuxAdminUsername": {
|
||||
"defaultValue": "{{.LinuxProfile.AdminUsername}}",
|
||||
"metadata": {
|
||||
"description": "User name for the Linux Virtual Machines (SSH or Password)."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"masterEndpointDNSNamePrefix": {
|
||||
"defaultValue": "{{.MasterProfile.DNSPrefix}}",
|
||||
"metadata": {
|
||||
"description": "Sets the Domain name label for the master IP Address. The concatenation of the domain name label and the regional DNS zone make up the fully qualified domain name associated with the public IP address."
|
||||
},
|
||||
|
@ -14,7 +12,6 @@
|
|||
},
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
"masterVnetSubnetID": {
|
||||
"defaultValue": "{{.MasterProfile.VnetSubnetID}}",
|
||||
"metadata": {
|
||||
"description": "Sets the vnet subnet of the master."
|
||||
},
|
||||
|
@ -24,7 +21,7 @@
|
|||
"masterSubnet": {
|
||||
"defaultValue": "{{.MasterProfile.GetSubnet}}",
|
||||
"metadata": {
|
||||
"description": "Sets the subnet of the master."
|
||||
"description": "Sets the subnet of the master node(s)."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -37,65 +34,25 @@
|
|||
"type": "string"
|
||||
},
|
||||
"masterVMSize": {
|
||||
"allowedValues": [
|
||||
"Standard_A0",
|
||||
"Standard_A1",
|
||||
"Standard_A2",
|
||||
"Standard_A3",
|
||||
"Standard_A4",
|
||||
"Standard_A5",
|
||||
"Standard_A6",
|
||||
"Standard_A7",
|
||||
"Standard_A8",
|
||||
"Standard_A9",
|
||||
"Standard_A10",
|
||||
"Standard_A11",
|
||||
"Standard_D1",
|
||||
"Standard_D2",
|
||||
"Standard_D3",
|
||||
"Standard_D4",
|
||||
"Standard_D11",
|
||||
"Standard_D12",
|
||||
"Standard_D13",
|
||||
"Standard_D14",
|
||||
"Standard_D1_v2",
|
||||
"Standard_D2_v2",
|
||||
"Standard_D3_v2",
|
||||
"Standard_D4_v2",
|
||||
"Standard_D5_v2",
|
||||
"Standard_D11_v2",
|
||||
"Standard_D12_v2",
|
||||
"Standard_D13_v2",
|
||||
"Standard_D14_v2",
|
||||
"Standard_G1",
|
||||
"Standard_G2",
|
||||
"Standard_G3",
|
||||
"Standard_G4",
|
||||
"Standard_G5",
|
||||
"Standard_DS1",
|
||||
"Standard_DS2",
|
||||
"Standard_DS3",
|
||||
"Standard_DS4",
|
||||
"Standard_DS11",
|
||||
"Standard_DS12",
|
||||
"Standard_DS13",
|
||||
"Standard_DS14",
|
||||
"Standard_GS1",
|
||||
"Standard_GS2",
|
||||
"Standard_GS3",
|
||||
"Standard_GS4",
|
||||
"Standard_GS5"
|
||||
],
|
||||
"defaultValue": "{{.MasterProfile.VMSize}}",
|
||||
{{GetMasterAllowedSizes}}
|
||||
"metadata": {
|
||||
"description": "The size of the Virtual Machine."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"sshRSAPublicKey": {
|
||||
"defaultValue": "{{GetLinuxProfileFirstSSHPublicKey}}",
|
||||
"metadata": {
|
||||
"description": "SSH public key used for auth to all Linux machines. Not Required. If not set, you must provide a password key."
|
||||
},
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"nameSuffix": {
|
||||
"defaultValue": "{{GetUniqueNameSuffix}}",
|
||||
"metadata": {
|
||||
"description": "A string hash of the master DNS name to uniquely identify the cluster."
|
||||
},
|
||||
"type": "string"
|
||||
}
|
||||
{{if .GetClassicMode}}
|
||||
,{{template "classicparams.t" .}}
|
||||
{{end}}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"apiVersion": "[variables('storageApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionStorage')]",
|
||||
"copy": {
|
||||
"count": "[variables('agentStorageAccountsCount')]",
|
||||
"count": "[variables('{{.Name}}StorageAccountsCount')]",
|
||||
"name": "vmLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
{{if IsPublic .Ports}}
|
||||
{
|
||||
"apiVersion": "[variables('networkApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('{{.Name}}IPAddressName')]",
|
||||
"properties": {
|
||||
|
@ -28,7 +28,7 @@
|
|||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('{{.Name}}IPAddressName'))]"
|
||||
],
|
||||
|
@ -62,16 +62,18 @@
|
|||
},
|
||||
{{end}}
|
||||
{
|
||||
"apiVersion": "[variables('computeApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountPrefixes')[mod(add(0,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(0,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountPrefixes')[mod(add(1,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(1,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountPrefixes')[mod(add(2,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(2,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountPrefixes')[mod(add(3,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(3,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountPrefixes')[mod(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"[variables('vnetID')]"
|
||||
{{if IsPublic .Ports}},
|
||||
"[variables('{{.Name}}LbID')]"
|
||||
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountPrefixes')[mod(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]"
|
||||
{{if not .IsCustomVNET}}
|
||||
,"[variables('vnetID')]"
|
||||
{{end}}
|
||||
{{if IsPublic .Ports}}
|
||||
,"[variables('{{.Name}}LbID')]"
|
||||
{{end}}
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
|
@ -98,7 +100,7 @@
|
|||
],
|
||||
{{end}}
|
||||
"subnet": {
|
||||
"id": "[variables('{{.Name}}SubnetRef')]"
|
||||
"id": "[variables('{{.Name}}VnetSubnetID')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,11 +138,11 @@
|
|||
"createOption": "FromImage",
|
||||
"name": "vmssosdisk",
|
||||
"vhdContainers": [
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(0,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(0,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('storageApiVersion') ).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(1,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(1,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('storageApiVersion')).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(2,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(2,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('storageApiVersion')).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(3,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(3,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('storageApiVersion')).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('storageApiVersion')).primaryEndpoints.blob, 'osdisk')]"
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(0,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(0,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('apiVersionStorage') ).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(1,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(1,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('apiVersionStorage')).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(2,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(2,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('apiVersionStorage')).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(3,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(3,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('apiVersionStorage')).primaryEndpoints.blob, 'osdisk')]",
|
||||
"[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(4,variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')), variables('apiVersionStorage')).primaryEndpoints.blob, 'osdisk')]"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}Count')]",
|
||||
"name": "loop"
|
||||
},
|
||||
"dependsOn": [
|
||||
{{if not .IsCustomVNET}}
|
||||
"[variables('vnetID')]"
|
||||
{{end}}
|
||||
{{if IsPublic .Ports}}
|
||||
,"[variables('{{.Name}}LbID')]"
|
||||
{{end}}
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex())]",
|
||||
"properties": {
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"name": "ipConfigNode",
|
||||
"properties": {
|
||||
{{if IsPublic .Ports}}
|
||||
"loadBalancerBackendAddressPools": [
|
||||
{
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('{{.Name}}LbName'), '/backendAddressPools/',variables('{{.Name}}LbBackendPoolName'))]"
|
||||
}
|
||||
],
|
||||
{{end}}
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"subnet": {
|
||||
"id": "[variables('{{.Name}}VnetSubnetID')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionStorage')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}StorageAccountsCount')]",
|
||||
"name": "vmLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('storageAccountPrefixes')[mod(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(copyIndex(),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('{{.Name}}VMSize')].storageAccountType]"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
{{if .HasDisks}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionStorage')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}StorageAccountsCount')]",
|
||||
"name": "datadiskLoop"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('storageAccountPrefixes')[mod(add(copyIndex(variables('dataStorageAccountPrefixSeed')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(copyIndex(variables('dataStorageAccountPrefixSeed')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}DataAccountName'))]",
|
||||
"properties": {
|
||||
"accountType": "[variables('vmSizesMap')[variables('{{.Name}}VMSize')].storageAccountType]"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
{{end}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('{{.Name}}AvailabilitySet')]",
|
||||
"properties": {},
|
||||
"type": "Microsoft.Compute/availabilitySets"
|
||||
},
|
||||
{{if IsPublic .Ports}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('{{.Name}}IPAddressName')]",
|
||||
"properties": {
|
||||
"dnsSettings": {
|
||||
"domainNameLabel": "[variables('{{.Name}}EndpointDNSNamePrefix')]"
|
||||
},
|
||||
"publicIPAllocationMethod": "Dynamic"
|
||||
},
|
||||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('{{.Name}}IPAddressName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('{{.Name}}LbName')]",
|
||||
"properties": {
|
||||
"backendAddressPools": [
|
||||
{
|
||||
"name": "[variables('{{.Name}}LbBackendPoolName')]"
|
||||
}
|
||||
],
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"name": "[variables('{{.Name}}LbIPConfigName')]",
|
||||
"properties": {
|
||||
"publicIPAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('{{.Name}}IPAddressName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"inboundNatRules": [],
|
||||
"loadBalancingRules": [
|
||||
{{(GetLBRules .Name .Ports)}}
|
||||
],
|
||||
"probes": [
|
||||
{{(GetProbes .Ports)}}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/loadBalancers"
|
||||
},
|
||||
{{end}}
|
||||
{
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('{{.Name}}Count')]",
|
||||
"name": "vmLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
|
||||
{{if .HasDisks}}
|
||||
"[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}DataAccountName'))]",
|
||||
{{end}}
|
||||
"[concat('Microsoft.Network/networkInterfaces/', variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex())]",
|
||||
"[concat('Microsoft.Compute/availabilitySets/', variables('{{.Name}}AvailabilitySet'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex())]",
|
||||
"properties": {
|
||||
"availabilitySet": {
|
||||
"id": "[resourceId('Microsoft.Compute/availabilitySets',variables('{{.Name}}AvailabilitySet'))]"
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "[variables('{{.Name}}VMSize')]"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex()))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminUsername": "[variables('adminUsername')]",
|
||||
"computername": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex())]",
|
||||
"customData": "[base64({{template "swarmagentcustomdata.t" .}})]",
|
||||
"linuxConfiguration": {
|
||||
"disablePasswordAuthentication": "true",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "[parameters('sshRSAPublicKey')]",
|
||||
"path": "[variables('sshKeyPath')]"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
{{GetDataDisks .}}
|
||||
"imageReference": {
|
||||
"offer": "[variables('osImageOffer')]",
|
||||
"publisher": "[variables('osImagePublisher')]",
|
||||
"sku": "[variables('osImageSKU')]",
|
||||
"version": "[variables('osImageVersion')]"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadOnly",
|
||||
"createOption": "FromImage",
|
||||
"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(),'-osdisk')]",
|
||||
"vhd": {
|
||||
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')),variables('apiVersionStorage')).primaryEndpoints.blob,'osdisk/', variables('{{.Name}}VMNamePrefix'), copyIndex(), '-osdisk.vhd')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
}
|
|
@ -1,10 +1,20 @@
|
|||
"{{.Name}}StorageAccountOffset": "[mul(variables('agentStorageAccountsCount'),variables('{{.Name}}Index'))]",
|
||||
"{{.Name}}StorageAccountOffset": "[mul(variables('maxStorageAccountsPerAgent'),variables('{{.Name}}Index'))]",
|
||||
"{{.Name}}Count": "[parameters('{{.Name}}Count')]",
|
||||
{{if .IsVolumeBasedStorage}}
|
||||
"{{.Name}}AvailabilitySet": "[concat('{{.Name}}-availabilitySet-', variables('nameSuffix'))]",
|
||||
"{{.Name}}StorageAccountsCount": "[add(div(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')), mod(add(mod(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')),2), add(mod(variables('{{.Name}}Count'), variables('maxVMsPerStorageAccount')),1)))]",
|
||||
{{else}}
|
||||
"{{.Name}}StorageAccountsCount": "[variables('maxStorageAccountsPerAgent')]",
|
||||
{{end}}
|
||||
"{{.Name}}VMNamePrefix": "[concat(variables('orchestratorName'), '-{{.Name}}-', variables('nameSuffix'))]",
|
||||
"{{.Name}}VMSize": "[parameters('{{.Name}}VMSize')]",
|
||||
{{if .IsCustomVNET}}
|
||||
"{{.Name}}VnetSubnetID": "[parameters('{{.Name}}VnetSubnetID')]",
|
||||
{{else}}
|
||||
"{{.Name}}Subnet": "[parameters('{{.Name}}Subnet')]",
|
||||
"{{.Name}}SubnetName": "[concat(variables('orchestratorName'), '-{{.Name}}subnet')]",
|
||||
"{{.Name}}SubnetRef": "[concat(variables('vnetID'),'/subnets/',variables('{{.Name}}SubnetName'))]",
|
||||
"{{.Name}}VnetSubnetID": "[concat(variables('vnetID'),'/subnets/',variables('{{.Name}}SubnetName'))]",
|
||||
{{end}}
|
||||
{{if IsPublic .Ports}}
|
||||
"{{.Name}}EndpointDNSNamePrefix": "[tolower(parameters('{{.Name}}EndpointDNSNamePrefix'))]",
|
||||
"{{.Name}}IPAddressName": "[concat(variables('orchestratorName'), '-agent-ip-', variables('{{.Name}}EndpointDNSNamePrefix'), '-', variables('nameSuffix'))]",
|
||||
|
@ -13,4 +23,8 @@
|
|||
"{{.Name}}LbIPConfigID": "[concat(variables('{{.Name}}LbID'),'/frontendIPConfigurations/', variables('{{.Name}}LbIPConfigName'))]",
|
||||
"{{.Name}}LbIPConfigName": "[concat(variables('orchestratorName'), '-{{.Name}}-', variables('nameSuffix'))]",
|
||||
"{{.Name}}LbName": "[concat(variables('orchestratorName'), '-{{.Name}}-', variables('nameSuffix'))]",
|
||||
{{if .IsWindows}}
|
||||
"{{.Name}}WindowsRDPNatRangeStart": 3389,
|
||||
"{{.Name}}WindowsRDPEndRangeStop": "[add(variables('{{.Name}}WindowsRDPNatRangeStart'), add(variables('{{.Name}}Count'),variables('{{.Name}}Count')))]",
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -3,19 +3,55 @@
|
|||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
{{range .AgentPoolProfiles}}{{template "agentparams.t" .}},{{end}}
|
||||
{{if .HasWindows}}
|
||||
{{template "windowsparams.t"}},
|
||||
{{end}}
|
||||
{{template "masterparams.t" .}}
|
||||
},
|
||||
"variables": {
|
||||
{{range $index, $agent := .AgentPoolProfiles}}
|
||||
{{template "swarmagentvars.t" .}}
|
||||
{{if .IsVolumeBasedStorage}}
|
||||
"{{.Name}}DataAccountName": "[concat(variables('storageAccountBaseName'), 'data{{$index}}')]",
|
||||
{{end}}
|
||||
"{{.Name}}Index": {{$index}},
|
||||
"{{.Name}}AccountName": "[concat(variables('storageAccountBaseName'), 'agnt{{$index}}')]",
|
||||
{{end}}
|
||||
|
||||
{{template "swarmmastervars.t" .}}
|
||||
{{if .HasWindows}}
|
||||
"windowsAdminUsername": "[parameters('windowsAdminUsername')]",
|
||||
"windowsAdminPassword": "[parameters('windowsAdminPassword')]",
|
||||
"agentWindowsPublisher": "MicrosoftWindowsServer",
|
||||
"agentWindowsOffer": "WindowsServer",
|
||||
"agentWindowsSku": "2016-Technical-Preview-with-Containers",
|
||||
"agentWindowsVersion": "5.0.20160803",
|
||||
"singleQuote": "'",
|
||||
"windowsCustomScriptArguments": "[concat('$arguments = ', variables('singleQuote'),'-SwarmMasterIP ', variables('masterFirstAddrPrefix'), variables('masterFirstAddrOctet4'), variables('singleQuote'), ' ; ')]",
|
||||
"windowsCustomScriptSuffix": " $inputFile = '%SYSTEMDRIVE%\\AzureData\\CustomData.bin' ; $outputFile = '%SYSTEMDRIVE%\\AzureData\\CustomDataSetupScript.ps1' ; $inputStream = New-Object System.IO.FileStream $inputFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read) ; $sr = New-Object System.IO.StreamReader(New-Object System.IO.Compression.GZipStream($inputStream, [System.IO.Compression.CompressionMode]::Decompress)) ; $sr.ReadToEnd() | Out-File($outputFile) ; Invoke-Expression('{0} {1}' -f $outputFile, $arguments) ; ",
|
||||
"windowsCustomScript": "[concat('powershell.exe -ExecutionPolicy Unrestricted -command \"', variables('windowsCustomScriptArguments'), variables('windowsCustomScriptSuffix'), '\" > %SYSTEMDRIVE%\\AzureData\\CustomDataSetupScript.log 2>&1')]",
|
||||
"agentWindowsBackendPort": 3389,
|
||||
{{end}}
|
||||
|
||||
{{template "swarmmastervars.t" .}},
|
||||
|
||||
{{GetSizeMap}}
|
||||
},
|
||||
"resources": [
|
||||
{{range .AgentPoolProfiles}}{{template "swarmagentresources.t" .}},{{end}}
|
||||
{{range .AgentPoolProfiles}}
|
||||
{{if .IsWindows}}
|
||||
{{if .IsVolumeBasedStorage}}
|
||||
{{template "swarmwinagentresourcesdisks.t" .}},
|
||||
{{else}}
|
||||
{{template "swarmwinagentresources.t" .}},
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{if .IsVolumeBasedStorage}}
|
||||
{{template "swarmagentresourcesdisks.t" .}},
|
||||
{{else}}
|
||||
{{template "swarmagentresources.t" .}},
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{template "swarmmasterresources.t" .}}
|
||||
],
|
||||
"outputs": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"apiVersion": "[variables('storageApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionStorage')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
|
@ -9,9 +9,10 @@
|
|||
"accountType": "[variables('vmSizesMap')[variables('masterVMSize')].storageAccountType]"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
},
|
||||
{{if not .MasterProfile.IsCustomVNET}}
|
||||
{
|
||||
"apiVersion": "[variables('networkApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('virtualNetworkName')]",
|
||||
"properties": {
|
||||
|
@ -25,16 +26,17 @@
|
|||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
},
|
||||
},
|
||||
{{end}}
|
||||
{
|
||||
"apiVersion": "[variables('computeApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('masterAvailabilitySet')]",
|
||||
"properties": {},
|
||||
"type": "Microsoft.Compute/availabilitySets"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('masterPublicIPAddressName')]",
|
||||
"properties": {
|
||||
|
@ -46,7 +48,7 @@
|
|||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
|
||||
],
|
||||
|
@ -72,7 +74,7 @@
|
|||
"type": "Microsoft.Network/loadBalancers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "masterLbLoopNode"
|
||||
|
@ -94,14 +96,16 @@
|
|||
"type": "Microsoft.Network/loadBalancers/inboundNatRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "nicLoopNode"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[variables('masterLbID')]",
|
||||
{{if not .MasterProfile.IsCustomVNET}}
|
||||
"[variables('vnetID')]",
|
||||
{{end}}
|
||||
"[variables('masterLbID')]",
|
||||
"[concat(variables('masterLbID'),'/inboundNatRules/SSH-',variables('masterVMNamePrefix'),copyIndex())]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
|
@ -124,7 +128,7 @@
|
|||
"privateIPAddress": "[concat(variables('masterFirstAddrPrefix'), copyIndex(int(variables('masterFirstAddrOctet4'))))]",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"id": "[variables('masterSubnetRef')]"
|
||||
"id": "[variables('masterVnetSubnetID')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +137,7 @@
|
|||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('computeApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "vmLoopNode"
|
||||
|
@ -187,7 +191,7 @@
|
|||
"createOption": "FromImage",
|
||||
"name": "[concat(variables('masterVMNamePrefix'), copyIndex(),'-osdisk')]",
|
||||
"vhd": {
|
||||
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('masterStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.blob, 'vhds/', variables('masterVMNamePrefix'), copyIndex(), '-osdisk.vhd')]"
|
||||
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('masterStorageAccountName')), variables('apiVersionStorage')).primaryEndpoints.blob, 'vhds/', variables('masterVMNamePrefix'), copyIndex(), '-osdisk.vhd')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +199,7 @@
|
|||
"type": "Microsoft.Compute/virtualMachines"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('computeApiVersion')]",
|
||||
"apiVersion": "[variables('apiVersionDefault')]",
|
||||
"copy": {
|
||||
"count": "[variables('masterCount')]",
|
||||
"name": "vmLoopNode"
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
"adminUsername": "[parameters('linuxAdminUsername')]",
|
||||
"agentStorageAccountsCount": 5,
|
||||
"maxVMsPerPool": 100,
|
||||
"maxVMsPerStorageAccount": 20,
|
||||
"maxStorageAccountsPerAgent": "[div(variables('maxVMsPerPool'),variables('maxVMsPerStorageAccount'))]",
|
||||
"dataStorageAccountPrefixSeed": 97,
|
||||
"apiVersionDefault": "2016-03-30",
|
||||
"apiVersionStorage": "2015-06-15",
|
||||
"agentCustomScript": "[concat('/usr/bin/nohup /bin/bash -c \"/bin/bash /opt/azure/containers/configure-swarm-cluster.sh ',variables('clusterInstallParameters'),' >> /var/log/azure/cluster-bootstrap.log 2>&1 &\" &')]",
|
||||
"agentRunCmd": "[concat('runcmd:\n - [ /bin/bash, /opt/azure/containers/install-cluster.sh ]\n\n')]",
|
||||
"agentRunCmdFile": "[concat(' - content: |\n #!/bin/bash\n ',variables('agentCustomScript'),'\n path: /opt/azure/containers/install-cluster.sh\n permissions: \"0744\"\n')]",
|
||||
"clusterInstallParameters": "[concat(variables('masterCount'), ' ',variables('masterVMNamePrefix'), ' ',variables('masterFirstAddr'), ' ',variables('adminUsername'),' ',variables('postInstallScriptURI'),' ',split(variables('masterSubnet'),'0/24')[0])]",
|
||||
"computeApiVersion": "2016-03-30",
|
||||
"masterSubnet": "[parameters('masterSubnet')]",
|
||||
"agentMaxVMs": 100,
|
||||
"clusterInstallParameters": "[concat(variables('masterCount'), ' ',variables('masterVMNamePrefix'), ' ',variables('masterFirstAddrOctet4'), ' ',variables('adminUsername'),' ',variables('postInstallScriptURI'),' ',variables('masterFirstAddrPrefix'))]",
|
||||
"masterAvailabilitySet": "[concat(variables('orchestratorName'), '-master-availabilitySet-', variables('nameSuffix'))]",
|
||||
"masterCount": {{.MasterProfile.Count}},
|
||||
"masterCustomScript": "[concat('/bin/bash -c \"/bin/bash /opt/azure/containers/configure-swarm-cluster.sh ',variables('clusterInstallParameters'),' >> /var/log/azure/cluster-bootstrap.log 2>&1\"')]",
|
||||
"masterEndpointDNSNamePrefix": "[tolower(parameters('masterEndpointDNSNamePrefix'))]",
|
||||
"masterFirstAddr": 5,
|
||||
"masterLbBackendPoolName": "[concat(variables('orchestratorName'), '-master-pool-', variables('nameSuffix'))]",
|
||||
"masterLbID": "[resourceId('Microsoft.Network/loadBalancers',variables('masterLbName'))]",
|
||||
"masterLbIPConfigID": "[concat(variables('masterLbID'),'/frontendIPConfigurations/', variables('masterLbIPConfigName'))]",
|
||||
|
@ -18,15 +21,21 @@
|
|||
"masterLbName": "[concat(variables('orchestratorName'), '-master-lb-', variables('nameSuffix'))]",
|
||||
"masterPublicIPAddressName": "[concat(variables('orchestratorName'), '-master-ip-', variables('masterEndpointDNSNamePrefix'), '-', variables('nameSuffix'))]",
|
||||
"masterStorageAccountName": "[concat(variables('storageAccountBaseName'), '0')]",
|
||||
"masterSubnetName": "[concat(variables('orchestratorName'), '-masterSubnet')]",
|
||||
"masterSubnetRef": "[concat(variables('vnetID'),'/subnets/',variables('masterSubnetName'))]",
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
"masterVnetSubnetID": "[parameters('masterVnetSubnetID')]",
|
||||
{{else}}
|
||||
"masterSubnet": "[parameters('masterSubnet')]",
|
||||
"masterSubnetName": "[concat(variables('orchestratorName'), '-masterSubnet')]",
|
||||
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
|
||||
"masterVnetSubnetID": "[concat(variables('vnetID'),'/subnets/',variables('masterSubnetName'))]",
|
||||
"virtualNetworkName": "[concat(variables('orchestratorName'), '-vnet-', variables('nameSuffix'))]",
|
||||
{{end}}
|
||||
"masterFirstAddrOctets": "[split(parameters('firstConsecutiveStaticIP'),'.')]",
|
||||
"masterFirstAddrOctet4": "[variables('masterFirstAddrOctets')[3]]",
|
||||
"masterFirstAddrPrefix": "[concat(variables('masterFirstAddrOctets')[0],'.',variables('masterFirstAddrOctets')[1],'.',variables('masterFirstAddrOctets')[2],'.')]",
|
||||
"masterVMNamePrefix": "[concat(variables('orchestratorName'), '-master-', variables('nameSuffix'), '-')]",
|
||||
"masterVMSize": "[parameters('masterVMSize')]",
|
||||
"nameSuffix": "{{GetUniqueNameSuffix}}",
|
||||
"networkApiVersion": "2016-03-30",
|
||||
"nameSuffix": "[parameters('nameSuffix')]",
|
||||
"orchestratorName": "swarm",
|
||||
"osImageOffer": "UbuntuServer",
|
||||
"osImagePublisher": "Canonical",
|
||||
|
@ -35,191 +44,8 @@
|
|||
"postInstallScriptURI": "disabled",
|
||||
"sshKeyPath": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]",
|
||||
"sshRSAPublicKey": "[parameters('sshRSAPublicKey')]",
|
||||
"storageAccountBaseName": "[concat(uniqueString(concat(variables('masterEndpointDNSNamePrefix'),resourceGroup().location)))]",
|
||||
"storageAccountPrefixes": [
|
||||
"0",
|
||||
"6",
|
||||
"c",
|
||||
"i",
|
||||
"o",
|
||||
"u",
|
||||
"1",
|
||||
"7",
|
||||
"d",
|
||||
"j",
|
||||
"p",
|
||||
"v",
|
||||
"2",
|
||||
"8",
|
||||
"e",
|
||||
"k",
|
||||
"q",
|
||||
"w",
|
||||
"3",
|
||||
"9",
|
||||
"f",
|
||||
"l",
|
||||
"r",
|
||||
"x",
|
||||
"4",
|
||||
"a",
|
||||
"g",
|
||||
"m",
|
||||
"s",
|
||||
"y",
|
||||
"5",
|
||||
"b",
|
||||
"h",
|
||||
"n",
|
||||
"t",
|
||||
"z"
|
||||
],
|
||||
"storageAccountBaseName": "[uniqueString(concat(variables('masterEndpointDNSNamePrefix'),resourceGroup().location))]",
|
||||
"storageAccountPrefixes": [ "0", "6", "c", "i", "o", "u", "1", "7", "d", "j", "p", "v", "2", "8", "e", "k", "q", "w", "3", "9", "f", "l", "r", "x", "4", "a", "g", "m", "s", "y", "5", "b", "h", "n", "t", "z" ],
|
||||
"storageAccountPrefixesCount": "[length(variables('storageAccountPrefixes'))]",
|
||||
"storageApiVersion": "2015-06-15",
|
||||
"virtualNetworkName": "[concat(variables('orchestratorName'), '-vnet-', variables('nameSuffix'))]",
|
||||
"vmSizesMap": {
|
||||
"Standard_A0": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A1": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A10": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A11": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A5": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A6": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A7": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A8": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A9": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D1": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D11": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D11_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D12": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D12_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D13": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D13_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D14": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D14_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D1_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D2_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D3_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D4_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D5_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_DS1": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS11": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS12": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS13": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS14": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS3": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS4": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_G1": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G5": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_GS1": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS3": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS4": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS5": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
}
|
||||
},
|
||||
"vmsPerStorageAccount": 20,
|
||||
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]"
|
||||
"vmsPerStorageAccount": 20
|
||||
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,12 @@
|
|||
"windowsAdminUsername": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "User name for the Windows Swarm Agent Virtual Machines (Password Only Supported)."
|
||||
}
|
||||
},
|
||||
"windowsAdminPassword": {
|
||||
"type": "securestring",
|
||||
"metadata": {
|
||||
"description": "Password for the Windows Swarm Agent Virtual Machines."
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Autogenerates the allowed sizes for masters and agents and the
|
||||
associated storage map.
|
||||
|
||||
.DESCRIPTION
|
||||
Autogenerates the allowed sizes for masters and agents and the
|
||||
associated storage map.
|
||||
|
||||
.PARAMETER OutFile
|
||||
The name of the outputfile (Default is azureconst.go)
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-AzureConstants.ps1 -OutFile "azureconst.go"
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName="Standard")]
|
||||
param(
|
||||
[string]
|
||||
$OutFile = "azureconst.go"
|
||||
)
|
||||
|
||||
function
|
||||
Get-AllSizes() {
|
||||
$locations = Get-AzureRmLocation | Select-Object -Property Location
|
||||
$sizeMap = @{}
|
||||
ForEach ($location in $locations) {
|
||||
#Write-Output $location.Location
|
||||
$sizes = Get-AzureRmVMSize -Location $location.Location
|
||||
ForEach ($size in $sizes) {
|
||||
if (!$sizeMap.ContainsKey($size.Name)) {
|
||||
$sizeMap.Add($size.Name, $size)
|
||||
}
|
||||
}
|
||||
#break
|
||||
}
|
||||
return $sizeMap
|
||||
}
|
||||
|
||||
# 1. Agents >= 2 cores
|
||||
# 2. Masters >= 2 cores and ephemeral disk >= 100 GB
|
||||
$MINIMUM_CORES = 2
|
||||
$MASTERS_EPHEMERAL_DISK_MIN = 102400
|
||||
|
||||
function
|
||||
Get-MasterMap() {
|
||||
param(
|
||||
[System.Collections.Hashtable]
|
||||
$SizeMap
|
||||
)
|
||||
|
||||
$masterMap = @{}
|
||||
ForEach ($k in ($SizeMap.Keys | Sort-Object)) {
|
||||
#Write-Output $location.Location
|
||||
$size = $SizeMap[$k]
|
||||
if ($size.NumberOfCores -ge $MINIMUM_CORES -and
|
||||
$size.ResourceDiskSizeInMB -ge $MASTERS_EPHEMERAL_DISK_MIN) {
|
||||
$masterMap.Add($size.Name, $size)
|
||||
}
|
||||
}
|
||||
return $masterMap
|
||||
}
|
||||
|
||||
function
|
||||
Get-AgentMap() {
|
||||
param(
|
||||
[System.Collections.Hashtable]
|
||||
$SizeMap
|
||||
)
|
||||
|
||||
$agentMap = @{}
|
||||
ForEach ($k in ($SizeMap.Keys | Sort-Object)) {
|
||||
#Write-Output $location.Location
|
||||
$size = $SizeMap[$k]
|
||||
if ($size.NumberOfCores -ge $MINIMUM_CORES) {
|
||||
$agentMap.Add($size.Name, $size)
|
||||
}
|
||||
}
|
||||
return $agentMap
|
||||
}
|
||||
|
||||
function
|
||||
Get-Locations() {
|
||||
$locations = Get-AzureRmLocation | Select-Object -Property Location
|
||||
$locationList = @()
|
||||
ForEach ($location in $locations) {
|
||||
$locationList += $location.Location
|
||||
}
|
||||
return $locationList
|
||||
}
|
||||
|
||||
function
|
||||
Get-FileContents() {
|
||||
param(
|
||||
[System.Collections.Hashtable]
|
||||
$MasterMap,
|
||||
[System.Collections.Hashtable]
|
||||
$AgentMap,
|
||||
[System.Collections.ArrayList]
|
||||
$Locations
|
||||
)
|
||||
|
||||
$text = "package tgen"
|
||||
$text += @"
|
||||
|
||||
|
||||
import "fmt"
|
||||
|
||||
// AUTOGENERATED FILE - last generated $(Get-Date -format 'u')
|
||||
|
||||
const (
|
||||
// AzureProdFQDNFormat specifies the format for a prod dns name
|
||||
AzureProdFQDNFormat = "%s.%s.cloudapp.azure.com"
|
||||
)
|
||||
|
||||
// AzureLocations provides all azure regions in prod.
|
||||
// Related powershell to refresh this list:
|
||||
// Get-AzureRmLocation | Select-Object -Property Location
|
||||
var AzureLocations = []string{
|
||||
|
||||
"@
|
||||
ForEach ($location in ($Locations | Sort-Object)) {
|
||||
$text += ' "' + $location + '"' + ",`r`n"
|
||||
}
|
||||
$text += @"
|
||||
}
|
||||
|
||||
// FormatAzureProdFQDNs constructs all possible Azure prod fqdn
|
||||
func FormatAzureProdFQDNs(fqdnPrefix string) []string {
|
||||
var fqdns []string
|
||||
for _, location := range AzureLocations {
|
||||
fqdns = append(fqdns, FormatAzureProdFQDN(fqdnPrefix, location))
|
||||
}
|
||||
return fqdns
|
||||
}
|
||||
|
||||
// FormatAzureProdFQDN constructs an Azure prod fqdn
|
||||
func FormatAzureProdFQDN(fqdnPrefix string, location string) string {
|
||||
return fmt.Sprintf(AzureProdFQDNFormat, fqdnPrefix, location)
|
||||
}
|
||||
|
||||
// GetMasterAllowedSizes returns the master allowed sizes
|
||||
func GetMasterAllowedSizes() string{
|
||||
return `` "allowedValues": [
|
||||
|
||||
"@
|
||||
$first = $TRUE
|
||||
ForEach ($k in ($MasterMap.Keys | Sort-Object)) {
|
||||
if ($first -eq $TRUE)
|
||||
{
|
||||
$first = $FALSE
|
||||
}
|
||||
else
|
||||
{
|
||||
$text += ",`r`n"
|
||||
}
|
||||
$text += ' "' + $MasterMap.Item($k).Name + '"'
|
||||
}
|
||||
$text += @"
|
||||
|
||||
],
|
||||
``
|
||||
}
|
||||
|
||||
// GetAgentAllowedSizes returns the agent allowed sizes
|
||||
func GetAgentAllowedSizes() string {
|
||||
return `` "allowedValues": [
|
||||
|
||||
"@
|
||||
$first = $TRUE
|
||||
ForEach ($k in ($AgentMap.Keys | Sort-Object)) {
|
||||
if ($first -eq $TRUE)
|
||||
{
|
||||
$first = $FALSE
|
||||
}
|
||||
else
|
||||
{
|
||||
$text += ",`r`n"
|
||||
}
|
||||
$text += ' "' + $AgentMap.Item($k).Name + '"'
|
||||
}
|
||||
$text += @"
|
||||
|
||||
],
|
||||
``
|
||||
}
|
||||
|
||||
// GetSizeMap returns the size / storage map
|
||||
func GetSizeMap() string{
|
||||
return `` "vmSizesMap": {
|
||||
|
||||
"@
|
||||
|
||||
# merge the maps
|
||||
$mergedMap = @{}
|
||||
ForEach ($k in $AgentMap.Keys) {
|
||||
$size = $AgentMap.Item($k)
|
||||
if (!$mergedMap.ContainsKey($k)) {
|
||||
$mergedMap.Add($size.Name, $size)
|
||||
}
|
||||
}
|
||||
ForEach ($k in $MasterMap.Keys) {
|
||||
$size = $MasterMap.Item($k)
|
||||
if (!$mergedMap.ContainsKey($k)) {
|
||||
$mergedMap.Add($size.Name, $size)
|
||||
}
|
||||
}
|
||||
|
||||
$first = $TRUE
|
||||
ForEach ($k in ($mergedMap.Keys | Sort-Object)) {
|
||||
$size = $mergedMap.Item($k)
|
||||
if ($first -eq $TRUE)
|
||||
{
|
||||
$first = $FALSE
|
||||
}
|
||||
else
|
||||
{
|
||||
$text += ",`r`n"
|
||||
}
|
||||
$text += ' "' + $size.Name + '": {' + "`r`n"
|
||||
if ($size.Name.Contains("GS") -Or $size.Name.Contains("DS")) {
|
||||
$text += ' "storageAccountType": "Premium_LRS"' + "`r`n"
|
||||
}
|
||||
else
|
||||
{
|
||||
$text += ' "storageAccountType": "Standard_LRS"' + "`r`n"
|
||||
}
|
||||
$text += ' }'
|
||||
}
|
||||
$text += @"
|
||||
|
||||
}
|
||||
``
|
||||
}
|
||||
"@
|
||||
return $text
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$allSizes = Get-AllSizes
|
||||
$masterMap = Get-MasterMap -SizeMap $allSizes
|
||||
$agentMap = Get-AgentMap -SizeMap $allSizes
|
||||
$locations = Get-Locations
|
||||
$text = Get-FileContents -MasterMap $masterMap -AgentMap $agentMap -Locations $locations
|
||||
$text | Out-File $OutFile
|
||||
(Get-Content $OutFile) -replace "`0", "" | Set-Content $OutFile
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Error $_
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
package tgen
|
||||
|
||||
import "fmt"
|
||||
|
||||
// AUTOGENERATED FILE - last generated 2016-10-05 06:09:49Z
|
||||
|
||||
const (
|
||||
// AzureProdFQDNFormat specifies the format for a prod dns name
|
||||
AzureProdFQDNFormat = "%s.%s.cloudapp.azure.com"
|
||||
)
|
||||
|
||||
// AzureLocations provides all azure regions in prod.
|
||||
// Related powershell to refresh this list:
|
||||
// Get-AzureRmLocation | Select-Object -Property Location
|
||||
var AzureLocations = []string{
|
||||
"australiaeast",
|
||||
"australiasoutheast",
|
||||
"brazilsouth",
|
||||
"canadacentral",
|
||||
"canadaeast",
|
||||
"centralindia",
|
||||
"centralus",
|
||||
"eastasia",
|
||||
"eastus",
|
||||
"eastus2",
|
||||
"japaneast",
|
||||
"japanwest",
|
||||
"northcentralus",
|
||||
"northeurope",
|
||||
"southcentralus",
|
||||
"southeastasia",
|
||||
"southindia",
|
||||
"uksouth",
|
||||
"ukwest",
|
||||
"westcentralus",
|
||||
"westeurope",
|
||||
"westindia",
|
||||
"westus",
|
||||
"westus2",
|
||||
}
|
||||
|
||||
// FormatAzureProdFQDNs constructs all possible Azure prod fqdn
|
||||
func FormatAzureProdFQDNs(fqdnPrefix string) []string {
|
||||
var fqdns []string
|
||||
for _, location := range AzureLocations {
|
||||
fqdns = append(fqdns, FormatAzureProdFQDN(fqdnPrefix, location))
|
||||
}
|
||||
return fqdns
|
||||
}
|
||||
|
||||
// FormatAzureProdFQDN constructs an Azure prod fqdn
|
||||
func FormatAzureProdFQDN(fqdnPrefix string, location string) string {
|
||||
return fmt.Sprintf(AzureProdFQDNFormat, fqdnPrefix, location)
|
||||
}
|
||||
|
||||
// GetMasterAllowedSizes returns the master allowed sizes
|
||||
func GetMasterAllowedSizes() string{
|
||||
return ` "allowedValues": [
|
||||
"Basic_A3",
|
||||
"Basic_A4",
|
||||
"Standard_A10",
|
||||
"Standard_A11",
|
||||
"Standard_A2",
|
||||
"Standard_A3",
|
||||
"Standard_A4",
|
||||
"Standard_A5",
|
||||
"Standard_A6",
|
||||
"Standard_A7",
|
||||
"Standard_A8",
|
||||
"Standard_A9",
|
||||
"Standard_D11",
|
||||
"Standard_D11_v2",
|
||||
"Standard_D12",
|
||||
"Standard_D12_v2",
|
||||
"Standard_D13",
|
||||
"Standard_D13_v2",
|
||||
"Standard_D14",
|
||||
"Standard_D14_v2",
|
||||
"Standard_D15_v2",
|
||||
"Standard_D2",
|
||||
"Standard_D2_v2",
|
||||
"Standard_D3",
|
||||
"Standard_D3_v2",
|
||||
"Standard_D4",
|
||||
"Standard_D4_v2",
|
||||
"Standard_D5_v2",
|
||||
"Standard_DS13",
|
||||
"Standard_DS13_v2",
|
||||
"Standard_DS14",
|
||||
"Standard_DS14_v2",
|
||||
"Standard_DS15_v2",
|
||||
"Standard_DS5_v2",
|
||||
"Standard_F16",
|
||||
"Standard_F8",
|
||||
"Standard_G1",
|
||||
"Standard_G2",
|
||||
"Standard_G3",
|
||||
"Standard_G4",
|
||||
"Standard_G5",
|
||||
"Standard_GS2",
|
||||
"Standard_GS3",
|
||||
"Standard_GS4",
|
||||
"Standard_GS5",
|
||||
"Standard_H16",
|
||||
"Standard_H16m",
|
||||
"Standard_H16mr",
|
||||
"Standard_H16r",
|
||||
"Standard_H8",
|
||||
"Standard_H8m",
|
||||
"Standard_NC12",
|
||||
"Standard_NC24",
|
||||
"Standard_NC6",
|
||||
"Standard_NV12",
|
||||
"Standard_NV24",
|
||||
"Standard_NV6"
|
||||
],
|
||||
`
|
||||
}
|
||||
|
||||
// GetAgentAllowedSizes returns the agent allowed sizes
|
||||
func GetAgentAllowedSizes() string {
|
||||
return ` "allowedValues": [
|
||||
"Basic_A2",
|
||||
"Basic_A3",
|
||||
"Basic_A4",
|
||||
"Standard_A10",
|
||||
"Standard_A11",
|
||||
"Standard_A2",
|
||||
"Standard_A3",
|
||||
"Standard_A4",
|
||||
"Standard_A5",
|
||||
"Standard_A6",
|
||||
"Standard_A7",
|
||||
"Standard_A8",
|
||||
"Standard_A9",
|
||||
"Standard_D11",
|
||||
"Standard_D11_v2",
|
||||
"Standard_D12",
|
||||
"Standard_D12_v2",
|
||||
"Standard_D13",
|
||||
"Standard_D13_v2",
|
||||
"Standard_D14",
|
||||
"Standard_D14_v2",
|
||||
"Standard_D15_v2",
|
||||
"Standard_D2",
|
||||
"Standard_D2_v2",
|
||||
"Standard_D3",
|
||||
"Standard_D3_v2",
|
||||
"Standard_D4",
|
||||
"Standard_D4_v2",
|
||||
"Standard_D5_v2",
|
||||
"Standard_DS11",
|
||||
"Standard_DS11_v2",
|
||||
"Standard_DS12",
|
||||
"Standard_DS12_v2",
|
||||
"Standard_DS13",
|
||||
"Standard_DS13_v2",
|
||||
"Standard_DS14",
|
||||
"Standard_DS14_v2",
|
||||
"Standard_DS15_v2",
|
||||
"Standard_DS2",
|
||||
"Standard_DS2_v2",
|
||||
"Standard_DS3",
|
||||
"Standard_DS3_v2",
|
||||
"Standard_DS4",
|
||||
"Standard_DS4_v2",
|
||||
"Standard_DS5_v2",
|
||||
"Standard_F16",
|
||||
"Standard_F16s",
|
||||
"Standard_F2",
|
||||
"Standard_F2s",
|
||||
"Standard_F4",
|
||||
"Standard_F4s",
|
||||
"Standard_F8",
|
||||
"Standard_F8s",
|
||||
"Standard_G1",
|
||||
"Standard_G2",
|
||||
"Standard_G3",
|
||||
"Standard_G4",
|
||||
"Standard_G5",
|
||||
"Standard_GS1",
|
||||
"Standard_GS2",
|
||||
"Standard_GS3",
|
||||
"Standard_GS4",
|
||||
"Standard_GS5",
|
||||
"Standard_H16",
|
||||
"Standard_H16m",
|
||||
"Standard_H16mr",
|
||||
"Standard_H16r",
|
||||
"Standard_H8",
|
||||
"Standard_H8m",
|
||||
"Standard_NC12",
|
||||
"Standard_NC24",
|
||||
"Standard_NC6",
|
||||
"Standard_NV12",
|
||||
"Standard_NV24",
|
||||
"Standard_NV6"
|
||||
],
|
||||
`
|
||||
}
|
||||
|
||||
// GetSizeMap returns the size / storage map
|
||||
func GetSizeMap() string{
|
||||
return ` "vmSizesMap": {
|
||||
"Basic_A2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Basic_A3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Basic_A4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A10": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A11": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A5": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A6": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A7": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A8": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_A9": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D11": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D11_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D12": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D12_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D13": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D13_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D14": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D14_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D15_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D2_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D3_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D4_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_D5_v2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_DS11": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS11_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS12": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS12_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS13": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS13_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS14": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS14_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS15_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS2_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS3": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS3_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS4": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS4_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_DS5_v2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_F16": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_F16s": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_F2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_F2s": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_F4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_F4s": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_F8": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_F8s": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G1": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G2": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G3": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G4": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_G5": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_GS1": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS2": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS3": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS4": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_GS5": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"Standard_H16": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_H16m": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_H16mr": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_H16r": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_H8": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_H8m": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_NC12": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_NC24": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_NC6": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_NV12": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_NV24": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"Standard_NV6": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package tgen
|
||||
|
||||
const (
|
||||
// BaseLBPriority specifies the base lb priority.
|
||||
BaseLBPriority = 200
|
||||
// DefaultMasterSubnet specifies the default master subnet for DCOS or Swarm
|
||||
DefaultMasterSubnet = "172.16.0.0/24"
|
||||
// DefaultFirstConsecutiveStaticIP specifies the static IP address on master 0 for DCOS or Swarm
|
||||
DefaultFirstConsecutiveStaticIP = "172.16.0.5"
|
||||
// DefaultSwarmWindowsMasterSubnet specifies the default master subnet for a Swarm Windows cluster
|
||||
DefaultSwarmWindowsMasterSubnet = "192.168.255.0/24"
|
||||
// DefaultSwarmWindowsFirstConsecutiveStaticIP specifies the static IP address on master 0 for a Swarm WIndows cluster
|
||||
DefaultSwarmWindowsFirstConsecutiveStaticIP = "192.168.255.5"
|
||||
// DefaultKubernetesMasterSubnet specifies the default kubernetes master subnet
|
||||
DefaultKubernetesMasterSubnet = "10.240.0.0/16"
|
||||
// DefaultFirstConsecutiveKubernetesStaticIP specifies the static IP address on Kubernetes master 0
|
||||
DefaultFirstConsecutiveKubernetesStaticIP = "10.240.255.5"
|
||||
// DefaultAgentSubnetTemplate specifies a default agent subnet
|
||||
DefaultAgentSubnetTemplate = "10.%d.0.0/24"
|
||||
// DefaultKubernetesClusterDomain is the dns suffix used in the cluster (used as a SAN in the PKI generation)
|
||||
DefaultKubernetesClusterDomain = "cluster.local"
|
||||
// KubernetesHyperkubeSpec is the hyperkube version used for Kubernetes setup
|
||||
// The latest stable version can be found here: https://storage.googleapis.com/kubernetes-release/release/stable.txt
|
||||
KubernetesHyperkubeSpec = "gcr.io/google_containers/hyperkube-amd64:v1.4.0"
|
||||
)
|
|
@ -0,0 +1,129 @@
|
|||
package tgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"./../api/vlabs"
|
||||
"./../util"
|
||||
)
|
||||
|
||||
// SetAcsClusterDefaults for an AcsCluster, returns true if certs are generated
|
||||
func SetAcsClusterDefaults(a *vlabs.AcsCluster) (bool, error) {
|
||||
|
||||
setMasterNetworkDefaults(a)
|
||||
|
||||
setAgentNetworkDefaults(a)
|
||||
|
||||
setStorageDefaults(a)
|
||||
|
||||
certsGenerated, e := setDefaultCerts(a)
|
||||
if e != nil {
|
||||
return false, e
|
||||
}
|
||||
return certsGenerated, nil
|
||||
}
|
||||
|
||||
// SetMasterNetworkDefaults for masters
|
||||
func setMasterNetworkDefaults(a *vlabs.AcsCluster) {
|
||||
if !a.MasterProfile.IsCustomVNET() {
|
||||
if a.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
a.MasterProfile.SetSubnet(DefaultKubernetesMasterSubnet)
|
||||
a.MasterProfile.FirstConsecutiveStaticIP = DefaultFirstConsecutiveKubernetesStaticIP
|
||||
} else if a.HasWindows() {
|
||||
a.MasterProfile.SetSubnet(DefaultSwarmWindowsMasterSubnet)
|
||||
a.MasterProfile.FirstConsecutiveStaticIP = DefaultSwarmWindowsFirstConsecutiveStaticIP
|
||||
} else {
|
||||
a.MasterProfile.SetSubnet(DefaultMasterSubnet)
|
||||
a.MasterProfile.FirstConsecutiveStaticIP = DefaultFirstConsecutiveStaticIP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetAgentNetworkDefaults for agents
|
||||
func setAgentNetworkDefaults(a *vlabs.AcsCluster) {
|
||||
// configure the subnets if not in custom VNET
|
||||
if !a.MasterProfile.IsCustomVNET() {
|
||||
subnetCounter := 0
|
||||
for i := range a.AgentPoolProfiles {
|
||||
profile := &a.AgentPoolProfiles[i]
|
||||
|
||||
if a.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
profile.SetSubnet(a.MasterProfile.GetSubnet())
|
||||
} else {
|
||||
profile.SetSubnet(fmt.Sprintf(DefaultAgentSubnetTemplate, subnetCounter))
|
||||
}
|
||||
|
||||
subnetCounter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setStorageDefaults for agents
|
||||
func setStorageDefaults(a *vlabs.AcsCluster) {
|
||||
for i := range a.AgentPoolProfiles {
|
||||
profile := &a.AgentPoolProfiles[i]
|
||||
if len(profile.StorageType) == 0 {
|
||||
profile.StorageType = vlabs.StorageExternal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setDefaultCerts(a *vlabs.AcsCluster) (bool, error) {
|
||||
if !certGenerationRequired(a) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
masterWildCardFQDN := FormatAzureProdFQDN(a.MasterProfile.DNSPrefix, "*")
|
||||
masterExtraFQDNs := FormatAzureProdFQDNs(a.MasterProfile.DNSPrefix)
|
||||
firstMasterIP := net.ParseIP(a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
|
||||
if firstMasterIP == nil {
|
||||
return false, fmt.Errorf("MasterProfile.FirstConsecutiveStaticIP '%s' is an invalid IP address", a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
}
|
||||
|
||||
ips := []net.IP{firstMasterIP}
|
||||
|
||||
for i := 1; i < a.MasterProfile.Count; i++ {
|
||||
ips = append(ips, net.IP{firstMasterIP[12], firstMasterIP[13], firstMasterIP[14], firstMasterIP[15] + byte(i)})
|
||||
}
|
||||
|
||||
caPair, apiServerPair, clientPair, kubeConfigPair, err := util.CreatePki(masterWildCardFQDN, masterExtraFQDNs, ips, DefaultKubernetesClusterDomain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
a.CertificateProfile.APIServerCertificate = apiServerPair.CertificatePem
|
||||
a.CertificateProfile.APIServerPrivateKey = apiServerPair.PrivateKeyPem
|
||||
a.CertificateProfile.CaCertificate = caPair.CertificatePem
|
||||
a.CertificateProfile.SetCAPrivateKey(caPair.PrivateKeyPem)
|
||||
a.CertificateProfile.ClientCertificate = clientPair.CertificatePem
|
||||
a.CertificateProfile.ClientPrivateKey = clientPair.PrivateKeyPem
|
||||
a.CertificateProfile.KubeConfigCertificate = kubeConfigPair.CertificatePem
|
||||
a.CertificateProfile.KubeConfigPrivateKey = kubeConfigPair.PrivateKeyPem
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func certGenerationRequired(a *vlabs.AcsCluster) bool {
|
||||
if len(a.CertificateProfile.APIServerCertificate) > 0 || len(a.CertificateProfile.APIServerPrivateKey) > 0 ||
|
||||
len(a.CertificateProfile.CaCertificate) > 0 ||
|
||||
len(a.CertificateProfile.ClientCertificate) > 0 || len(a.CertificateProfile.ClientPrivateKey) > 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch a.OrchestratorProfile.OrchestratorType {
|
||||
case vlabs.DCOS:
|
||||
return false
|
||||
case vlabs.DCOS184:
|
||||
return false
|
||||
case vlabs.DCOS173:
|
||||
return false
|
||||
case vlabs.Swarm:
|
||||
return false
|
||||
case vlabs.Kubernetes:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Package tgen takes an ACS cluster model and generates the corresponding template
|
||||
package tgen
|
|
@ -0,0 +1,630 @@
|
|||
package tgen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"./../api/vlabs"
|
||||
)
|
||||
|
||||
const (
|
||||
kubernetesMasterCustomDataYaml = "kubernetesmastercustomdata.yml"
|
||||
kubernetesMasterCustomScript = "kubernetesmastercustomscript.sh"
|
||||
kubernetesAgentCustomDataYaml = "kubernetesagentcustomdata.yml"
|
||||
kubernetesAgentCustomScript = "kubernetesagentcustomscript.sh"
|
||||
kubeConfigJSON = "kubeconfig.json"
|
||||
)
|
||||
|
||||
const (
|
||||
agentOutputs = "agentoutputs.t"
|
||||
agentParams = "agentparams.t"
|
||||
classicParams = "classicparams.t"
|
||||
dcosAgentResources = "dcosagentresources.t"
|
||||
dcosAgentResourcesDisks = "dcosagentresourcesdisks.t"
|
||||
dcosAgentVars = "dcosagentvars.t"
|
||||
dcosBaseFile = "dcosbase.t"
|
||||
dcosCustomData173 = "dcoscustomdata173.t"
|
||||
dcosCustomData184 = "dcoscustomdata184.t"
|
||||
dcosMasterResources = "dcosmasterresources.t"
|
||||
dcosMasterVars = "dcosmastervars.t"
|
||||
kubernetesBaseFile = "kubernetesbase.t"
|
||||
kubernetesAgentResources = "kubernetesagentresources.t"
|
||||
kubernetesAgentVars = "kubernetesagentvars.t"
|
||||
kubernetesMasterResources = "kubernetesmasterresources.t"
|
||||
kubernetesMasterVars = "kubernetesmastervars.t"
|
||||
kubernetesParams = "kubernetesparams.t"
|
||||
masterOutputs = "masteroutputs.t"
|
||||
masterParams = "masterparams.t"
|
||||
swarmBaseFile = "swarmbase.t"
|
||||
swarmAgentCustomData = "swarmagentcustomdata.t"
|
||||
swarmAgentResources = "swarmagentresources.t"
|
||||
swarmAgentResourcesDisks = "swarmagentresourcesdisks.t"
|
||||
swarmAgentVars = "swarmagentvars.t"
|
||||
swarmMasterCustomData = "swarmmastercustomdata.t"
|
||||
swarmMasterResources = "swarmmasterresources.t"
|
||||
swarmMasterVars = "swarmmastervars.t"
|
||||
swarmWinAgentResources = "swarmwinagentresources.t"
|
||||
swarmWinAgentResourcesDisks = "swarmwinagentresourcesdisks.t"
|
||||
windowsParams = "windowsparams.t"
|
||||
)
|
||||
|
||||
var commonTemplateFiles = []string{agentOutputs, agentParams, classicParams, masterOutputs, masterParams}
|
||||
var dcosTemplateFiles = []string{dcosAgentResources, dcosAgentResourcesDisks, dcosAgentVars, dcosBaseFile, dcosCustomData173, dcosCustomData184, dcosMasterResources, dcosMasterVars}
|
||||
var kubernetesTemplateFiles = []string{kubernetesBaseFile, kubernetesAgentResources, kubernetesAgentVars, kubernetesMasterResources, kubernetesMasterVars, kubernetesParams}
|
||||
var swarmTemplateFiles = []string{swarmBaseFile, swarmAgentCustomData, swarmAgentResources, swarmAgentVars, swarmAgentResourcesDisks, swarmBaseFile, swarmMasterCustomData, swarmMasterResources, swarmMasterVars, swarmWinAgentResources, swarmWinAgentResourcesDisks, windowsParams}
|
||||
|
||||
// VerifyFiles verifies that the required template files exist
|
||||
func VerifyFiles(partsDirectory string) error {
|
||||
allFiles := append(commonTemplateFiles, dcosTemplateFiles...)
|
||||
allFiles = append(allFiles, kubernetesTemplateFiles...)
|
||||
allFiles = append(allFiles, swarmTemplateFiles...)
|
||||
for _, file := range allFiles {
|
||||
templateFile := path.Join(partsDirectory, file)
|
||||
if _, err := os.Stat(templateFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("template file %s does not exist, did you specify the correct template directory?", templateFile)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateTemplate generates the template from the API Model
|
||||
func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (string, string, error) {
|
||||
var err error
|
||||
var templ *template.Template
|
||||
|
||||
templ = template.New("acs template").Funcs(getTemplateFuncMap(acsCluster, partsDirectory))
|
||||
|
||||
var files []string
|
||||
var baseFile string
|
||||
if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS184 ||
|
||||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS ||
|
||||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS173 {
|
||||
files = append(commonTemplateFiles, dcosTemplateFiles...)
|
||||
baseFile = dcosBaseFile
|
||||
} else if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Swarm {
|
||||
files = append(commonTemplateFiles, swarmTemplateFiles...)
|
||||
baseFile = swarmBaseFile
|
||||
} else if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
files = append(commonTemplateFiles, kubernetesTemplateFiles...)
|
||||
baseFile = kubernetesBaseFile
|
||||
} else {
|
||||
return "", "", fmt.Errorf("orchestrator '%s' is unsupported", acsCluster.OrchestratorProfile.OrchestratorType)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
templateFile := path.Join(partsDirectory, file)
|
||||
bytes, e := ioutil.ReadFile(templateFile)
|
||||
if e != nil {
|
||||
return "", "", fmt.Errorf("Error reading file %s: %s", templateFile, e.Error())
|
||||
}
|
||||
if _, err = templ.New(file).Parse(string(bytes)); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
if err = templ.ExecuteTemplate(&b, baseFile, acsCluster); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var parametersMap *map[string]interface{}
|
||||
if parametersMap, err = getParameters(acsCluster); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
var parameterBytes []byte
|
||||
if parameterBytes, err = json.Marshal(parametersMap); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return b.String(), string(parameterBytes), nil
|
||||
}
|
||||
|
||||
// GenerateClusterID creates a unique 8 string cluster ID
|
||||
func GenerateClusterID(acsCluster *vlabs.AcsCluster) string {
|
||||
uniqueNameSuffixSize := 8
|
||||
// the name suffix uniquely identifies the cluster and is generated off a hash
|
||||
// from the master dns name
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(acsCluster.MasterProfile.DNSPrefix))
|
||||
rand.Seed(int64(h.Sum64()))
|
||||
return fmt.Sprintf("%08d", rand.Uint32())[:uniqueNameSuffixSize]
|
||||
}
|
||||
|
||||
// GenerateKubeConfig returns a JSON string representing the KubeConfig
|
||||
func GenerateKubeConfig(acsCluster *vlabs.AcsCluster, templateDirectory string, location string) (string, error) {
|
||||
kubeTemplateFile := path.Join(templateDirectory, kubeConfigJSON)
|
||||
if _, err := os.Stat(kubeTemplateFile); os.IsNotExist(err) {
|
||||
return "", fmt.Errorf("file %s does not exist, did you specify the correct template directory?", kubeTemplateFile)
|
||||
}
|
||||
b, err := ioutil.ReadFile(kubeTemplateFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error reading kube config template file %s: %s", kubeTemplateFile, err.Error())
|
||||
}
|
||||
kubeconfig := string(b)
|
||||
// variable replacement
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<variables('caCertificate')>>>", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.CaCertificate)), -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<reference(concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))).dnsSettings.fqdn>>>", FormatAzureProdFQDN(acsCluster.MasterProfile.DNSPrefix, location), -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "{{{resourceGroup}}}", acsCluster.MasterProfile.DNSPrefix, -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<variables('kubeConfigCertificate')>>>", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigCertificate)), -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<variables('kubeConfigPrivateKey')>>>", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigPrivateKey)), -1)
|
||||
|
||||
return kubeconfig, nil
|
||||
}
|
||||
|
||||
func getParameters(acsCluster *vlabs.AcsCluster) (*map[string]interface{}, error) {
|
||||
parametersMap := &map[string]interface{}{}
|
||||
|
||||
// Master Parameters
|
||||
addValue(parametersMap, "linuxAdminUsername", acsCluster.LinuxProfile.AdminUsername)
|
||||
addValue(parametersMap, "masterEndpointDNSNamePrefix", acsCluster.MasterProfile.DNSPrefix)
|
||||
if acsCluster.MasterProfile.IsCustomVNET() {
|
||||
addValue(parametersMap, "masterVnetSubnetID", acsCluster.MasterProfile.VnetSubnetID)
|
||||
} else {
|
||||
addValue(parametersMap, "masterSubnet", acsCluster.MasterProfile.GetSubnet())
|
||||
}
|
||||
addValue(parametersMap, "firstConsecutiveStaticIP", acsCluster.MasterProfile.FirstConsecutiveStaticIP)
|
||||
addValue(parametersMap, "masterVMSize", acsCluster.MasterProfile.VMSize)
|
||||
addValue(parametersMap, "sshRSAPublicKey", acsCluster.LinuxProfile.SSH.PublicKeys[0].KeyData)
|
||||
|
||||
// Kubernetes Parameters
|
||||
if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
addValue(parametersMap, "apiServerCertificate", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.APIServerCertificate)))
|
||||
addValue(parametersMap, "apiServerPrivateKey", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.APIServerPrivateKey)))
|
||||
addValue(parametersMap, "caCertificate", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.CaCertificate)))
|
||||
addValue(parametersMap, "clientCertificate", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.ClientCertificate)))
|
||||
addValue(parametersMap, "clientPrivateKey", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.ClientPrivateKey)))
|
||||
addValue(parametersMap, "kubeConfigCertificate", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigCertificate)))
|
||||
addValue(parametersMap, "kubeConfigPrivateKey", base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigPrivateKey)))
|
||||
addValue(parametersMap, "kubernetesHyperkubeSpec", KubernetesHyperkubeSpec)
|
||||
addValue(parametersMap, "servicePrincipalClientId", acsCluster.ServicePrincipalProfile.ClientID)
|
||||
addValue(parametersMap, "servicePrincipalClientSecret", acsCluster.ServicePrincipalProfile.Secret)
|
||||
}
|
||||
|
||||
// Agent parameters
|
||||
for _, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
addValue(parametersMap, fmt.Sprintf("%sCount", agentProfile.Name), agentProfile.Count)
|
||||
addValue(parametersMap, fmt.Sprintf("%sVMSize", agentProfile.Name), agentProfile.VMSize)
|
||||
if agentProfile.IsCustomVNET() {
|
||||
addValue(parametersMap, fmt.Sprintf("%sVnetSubnetID", agentProfile.Name), agentProfile.VnetSubnetID)
|
||||
} else {
|
||||
addValue(parametersMap, fmt.Sprintf("%sSubnet", agentProfile.Name), agentProfile.GetSubnet())
|
||||
}
|
||||
if len(agentProfile.Ports) > 0 {
|
||||
addValue(parametersMap, fmt.Sprintf("%sEndpointDNSNamePrefix", agentProfile.Name), agentProfile.DNSPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
// Windows parameters
|
||||
if acsCluster.HasWindows() {
|
||||
addValue(parametersMap, "windowsAdminUsername", acsCluster.WindowsProfile.AdminUsername)
|
||||
addValue(parametersMap, "windowsAdminPassword", acsCluster.WindowsProfile.AdminPassword)
|
||||
}
|
||||
|
||||
return parametersMap, nil
|
||||
}
|
||||
|
||||
func addValue(m *map[string]interface{}, k string, v interface{}) {
|
||||
(*m)[k] = *(&map[string]interface{}{})
|
||||
(*m)[k].(map[string]interface{})["value"] = v
|
||||
}
|
||||
|
||||
// getTemplateFuncMap returns all functions used in template generation
|
||||
func getTemplateFuncMap(acsCluster *vlabs.AcsCluster, partsDirectory string) map[string]interface{} {
|
||||
return template.FuncMap{
|
||||
"IsDCOS173": func() bool {
|
||||
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS173
|
||||
},
|
||||
"IsDCOS184": func() bool {
|
||||
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS184 ||
|
||||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS
|
||||
},
|
||||
"RequiresFakeAgentOutput": func() bool {
|
||||
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes
|
||||
},
|
||||
"IsPublic": func(ports []int) bool {
|
||||
return len(ports) > 0
|
||||
},
|
||||
"GetVNETSubnetDependencies": func() string {
|
||||
return getVNETSubnetDependencies(acsCluster)
|
||||
},
|
||||
"GetLBRules": func(name string, ports []int) string {
|
||||
return getLBRules(name, ports)
|
||||
},
|
||||
"GetProbes": func(ports []int) string {
|
||||
return getProbes(ports)
|
||||
},
|
||||
"GetSecurityRules": func(ports []int) string {
|
||||
return getSecurityRules(ports)
|
||||
},
|
||||
"GetMasterRolesFileContents": func() string {
|
||||
return getMasterRolesFileContents()
|
||||
},
|
||||
"GetAgentRolesFileContents": func(ports []int) string {
|
||||
return getAgentRolesFileContents(ports)
|
||||
},
|
||||
"GetDCOSCustomDataPublicIPStr": func() string {
|
||||
return getDCOSCustomDataPublicIPStr(acsCluster.OrchestratorProfile.OrchestratorType, acsCluster.MasterProfile.Count)
|
||||
},
|
||||
"GetDCOSGUID": func() string {
|
||||
return getPackageGUID(acsCluster.OrchestratorProfile.OrchestratorType, acsCluster.MasterProfile.Count)
|
||||
},
|
||||
"GetUniqueNameSuffix": func() string {
|
||||
return GenerateClusterID(acsCluster)
|
||||
},
|
||||
"GetVNETAddressPrefixes": func() string {
|
||||
return getVNETAddressPrefixes(acsCluster)
|
||||
},
|
||||
"GetVNETSubnets": func(addNSG bool) string {
|
||||
return getVNETSubnets(acsCluster, addNSG)
|
||||
},
|
||||
"GetDataDisks": func(profile *vlabs.AgentPoolProfile) string {
|
||||
return getDataDisks(profile)
|
||||
},
|
||||
"GetMasterAllowedSizes": func() string {
|
||||
return GetMasterAllowedSizes()
|
||||
},
|
||||
"GetAgentAllowedSizes": func() string {
|
||||
return GetAgentAllowedSizes()
|
||||
},
|
||||
"GetSizeMap": func() string {
|
||||
return GetSizeMap()
|
||||
},
|
||||
"Base64": func(s string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(s))
|
||||
},
|
||||
"GetKubernetesMasterCustomScript": func() string {
|
||||
return getBase64CustomScript(acsCluster, kubernetesMasterCustomScript, partsDirectory)
|
||||
},
|
||||
"GetKubernetesMasterCustomData": func() string {
|
||||
str, e := getSingleLineForTemplate(kubernetesMasterCustomDataYaml, partsDirectory)
|
||||
if e != nil {
|
||||
return ""
|
||||
}
|
||||
// add the master provisioning script
|
||||
masterProvisionB64GzipStr := getBase64CustomScript(acsCluster, kubernetesMasterCustomScript, partsDirectory)
|
||||
str = strings.Replace(str, "MASTER_PROVISION_B64_GZIP_STR", masterProvisionB64GzipStr, -1)
|
||||
|
||||
// return the custom data
|
||||
return fmt.Sprintf("\"customData\": \"[base64(concat('%s'))]\",", str)
|
||||
},
|
||||
"GetKubernetesAgentCustomData": func(profile *vlabs.AgentPoolProfile) string {
|
||||
str, e := getSingleLineForTemplate(kubernetesAgentCustomDataYaml, partsDirectory)
|
||||
if e != nil {
|
||||
return ""
|
||||
}
|
||||
// add the agent provisioning script
|
||||
agentProvisionB64GzipStr := getBase64CustomScript(acsCluster, kubernetesAgentCustomScript, partsDirectory)
|
||||
str = strings.Replace(str, "AGENT_PROVISION_B64_GZIP_STR", agentProvisionB64GzipStr, -1)
|
||||
|
||||
return fmt.Sprintf("\"customData\": \"[base64(concat('%s'))]\",", str)
|
||||
},
|
||||
"GetKubernetesKubeConfig": func() string {
|
||||
str, e := getSingleLineForTemplate(kubeConfigJSON, partsDirectory)
|
||||
if e != nil {
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
},
|
||||
"GetMasterSecrets": func() string {
|
||||
clientPrivateKey := base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.ClientPrivateKey))
|
||||
serverPrivateKey := base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.APIServerPrivateKey))
|
||||
return fmt.Sprintf("%s %s %s %s", acsCluster.ServicePrincipalProfile.ClientID, acsCluster.ServicePrincipalProfile.Secret, clientPrivateKey, serverPrivateKey)
|
||||
},
|
||||
"GetAgentSecrets": func() string {
|
||||
clientPrivateKey := base64.StdEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.ClientPrivateKey))
|
||||
return fmt.Sprintf("%s %s %s", acsCluster.ServicePrincipalProfile.ClientID, acsCluster.ServicePrincipalProfile.Secret, clientPrivateKey)
|
||||
},
|
||||
"AnyAgentHasDisks": func() bool {
|
||||
for _, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
if agentProfile.HasDisks() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
// inspired by http://stackoverflow.com/questions/18276173/calling-a-template-with-several-pipeline-parameters/18276968#18276968
|
||||
"dict": func(values ...interface{}) (map[string]interface{}, error) {
|
||||
if len(values)%2 != 0 {
|
||||
return nil, errors.New("invalid dict call")
|
||||
}
|
||||
dict := make(map[string]interface{}, len(values)/2)
|
||||
for i := 0; i < len(values); i += 2 {
|
||||
key, ok := values[i].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("dict keys must be strings")
|
||||
}
|
||||
dict[key] = values[i+1]
|
||||
}
|
||||
return dict, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getPackageGUID(orchestratorType string, masterCount int) string {
|
||||
if orchestratorType == vlabs.DCOS || orchestratorType == vlabs.DCOS184 {
|
||||
switch masterCount {
|
||||
case 1:
|
||||
return "5ac6a7d060584c58c704e1f625627a591ecbde4e"
|
||||
case 3:
|
||||
return "42bd1d74e9a2b23836bd78919c716c20b98d5a0e"
|
||||
case 5:
|
||||
return "97947a91e2c024ed4f043bfcdad49da9418d3095"
|
||||
}
|
||||
} else if orchestratorType == vlabs.DCOS173 {
|
||||
switch masterCount {
|
||||
case 1:
|
||||
return "6b604c1331c2b8b52bb23d1ea8a8d17e0f2b7428"
|
||||
case 3:
|
||||
return "6af5097e7956962a3d4318d28fbf280a47305485"
|
||||
case 5:
|
||||
return "376e07e0dbad2af3da2c03bc92bb07e84b3dafd5"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getDCOSCustomDataPublicIPStr(orchestratorType string, masterCount int) string {
|
||||
if orchestratorType == vlabs.DCOS ||
|
||||
orchestratorType == vlabs.DCOS173 ||
|
||||
orchestratorType == vlabs.DCOS184 {
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < masterCount; i++ {
|
||||
buf.WriteString(fmt.Sprintf("reference(variables('masterVMNic')[%d]).ipConfigurations[0].properties.privateIPAddress,", i))
|
||||
if i < (masterCount - 1) {
|
||||
buf.WriteString(`'\\\", \\\"', `)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getVNETAddressPrefixes(acsCluster *vlabs.AcsCluster) string {
|
||||
visitedSubnets := make(map[string]bool)
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(`"[variables('masterSubnet')]"`)
|
||||
visitedSubnets[acsCluster.MasterProfile.GetSubnet()] = true
|
||||
for i := range acsCluster.AgentPoolProfiles {
|
||||
profile := &acsCluster.AgentPoolProfiles[i]
|
||||
if _, ok := visitedSubnets[profile.GetSubnet()]; !ok {
|
||||
buf.WriteString(fmt.Sprintf(",\n \"[variables('%sSubnet')]\"", profile.Name))
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getVNETSubnetDependencies(acsCluster *vlabs.AcsCluster) string {
|
||||
agentString := ` "[concat('Microsoft.Network/networkSecurityGroups/', variables('%sNSGName'))]"`
|
||||
var buf bytes.Buffer
|
||||
for index, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(agentString, agentProfile.Name))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getVNETSubnets(acsCluster *vlabs.AcsCluster, addNSG bool) string {
|
||||
masterString := `{
|
||||
"name": "[variables('masterSubnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('masterSubnet')]"
|
||||
}
|
||||
}`
|
||||
agentString := ` {
|
||||
"name": "[variables('%sSubnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('%sSubnet')]"
|
||||
}
|
||||
}`
|
||||
agentStringNSG := ` {
|
||||
"name": "[variables('%sSubnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('%sSubnet')]",
|
||||
"networkSecurityGroup": {
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('%sNSGName'))]"
|
||||
}
|
||||
}
|
||||
}`
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(masterString)
|
||||
for _, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
buf.WriteString(",\n")
|
||||
if addNSG {
|
||||
buf.WriteString(fmt.Sprintf(agentStringNSG, agentProfile.Name, agentProfile.Name, agentProfile.Name))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf(agentString, agentProfile.Name, agentProfile.Name))
|
||||
}
|
||||
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getLBRule(name string, port int) string {
|
||||
return fmt.Sprintf(` {
|
||||
"name": "LBRule%d",
|
||||
"properties": {
|
||||
"backendAddressPool": {
|
||||
"id": "[concat(variables('%sLbID'), '/backendAddressPools/', variables('%sLbBackendPoolName'))]"
|
||||
},
|
||||
"backendPort": %d,
|
||||
"enableFloatingIP": false,
|
||||
"frontendIPConfiguration": {
|
||||
"id": "[variables('%sLbIPConfigID')]"
|
||||
},
|
||||
"frontendPort": %d,
|
||||
"idleTimeoutInMinutes": 5,
|
||||
"loadDistribution": "Default",
|
||||
"probe": {
|
||||
"id": "[concat(variables('%sLbID'),'/probes/tcp%dProbe')]"
|
||||
},
|
||||
"protocol": "tcp"
|
||||
}
|
||||
}`, port, name, name, port, name, port, name, port)
|
||||
}
|
||||
|
||||
func getLBRules(name string, ports []int) string {
|
||||
var buf bytes.Buffer
|
||||
for index, port := range ports {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(getLBRule(name, port))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getProbe(port int) string {
|
||||
return fmt.Sprintf(` {
|
||||
"name": "tcp%dProbe",
|
||||
"properties": {
|
||||
"intervalInSeconds": "5",
|
||||
"numberOfProbes": "2",
|
||||
"port": %d,
|
||||
"protocol": "tcp"
|
||||
}
|
||||
}`, port, port)
|
||||
}
|
||||
|
||||
func getProbes(ports []int) string {
|
||||
var buf bytes.Buffer
|
||||
for index, port := range ports {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(getProbe(port))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getSecurityRule(port int, portIndex int) string {
|
||||
return fmt.Sprintf(` {
|
||||
"name": "Allow_%d",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "Allow traffic from the Internet to port %d",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationPortRange": "%d",
|
||||
"direction": "Inbound",
|
||||
"priority": %d,
|
||||
"protocol": "*",
|
||||
"sourceAddressPrefix": "Internet",
|
||||
"sourcePortRange": "*"
|
||||
}
|
||||
}`, port, port, port, BaseLBPriority+portIndex)
|
||||
}
|
||||
|
||||
func getDataDisks(a *vlabs.AgentPoolProfile) string {
|
||||
if !a.HasDisks() {
|
||||
return ""
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("\"dataDisks\": [\n")
|
||||
dataDisks := ` {
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": "%d",
|
||||
"lun": %d,
|
||||
"name": "[concat(variables('%sVMNamePrefix'), copyIndex(),'-datadisk%d')]",
|
||||
"vhd": {
|
||||
"uri": "[concat('http://',variables('storageAccountPrefixes')[mod(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('%sStorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('%sStorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('%sDataAccountName'),'.blob.core.windows.net/vhds/',variables('%sVMNamePrefix'),copyIndex(), '--datadisk%d.vhd')]"
|
||||
}
|
||||
}`
|
||||
for i, diskSize := range a.DiskSizesGB {
|
||||
if i > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(dataDisks, diskSize, i, a.Name, i, a.Name, a.Name, a.Name, a.Name, i))
|
||||
}
|
||||
buf.WriteString("\n ],")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getSecurityRules(ports []int) string {
|
||||
var buf bytes.Buffer
|
||||
for index, port := range ports {
|
||||
if index > 0 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
buf.WriteString(getSecurityRule(port, index))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getMasterRolesFileContents() string {
|
||||
return `{\"content\": \"\", \"path\": \"/etc/mesosphere/roles/master\"}, {\"content\": \"\", \"path\": \"/etc/mesosphere/roles/azure_master\"},`
|
||||
}
|
||||
|
||||
func getAgentRolesFileContents(ports []int) string {
|
||||
if len(ports) > 0 {
|
||||
// public agents
|
||||
return `{\"content\": \"\", \"path\": \"/etc/mesosphere/roles/slave_public\"},`
|
||||
}
|
||||
// private agents
|
||||
return `{\"content\": \"\", \"path\": \"/etc/mesosphere/roles/slave\"},`
|
||||
}
|
||||
|
||||
// getSingleLineForTemplate returns the file as a single line for embedding in an arm template
|
||||
func getSingleLineForTemplate(yamlFilename string, partsDirectory string) (string, error) {
|
||||
yamlFile := path.Join(partsDirectory, yamlFilename)
|
||||
if _, err := os.Stat(yamlFile); os.IsNotExist(err) {
|
||||
return "", fmt.Errorf("yaml file %s does not exist, did you specify the correct template directory?", yamlFile)
|
||||
}
|
||||
b, err := ioutil.ReadFile(yamlFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error reading yaml file %s: %s", yamlFile, err.Error())
|
||||
}
|
||||
// template.JSEscapeString leaves undesirable chars that don't work with pretty print
|
||||
yamlStr := string(b)
|
||||
yamlStr = strings.Replace(yamlStr, "\\", "\\\\", -1)
|
||||
yamlStr = strings.Replace(yamlStr, "\r\n", "\\n", -1)
|
||||
yamlStr = strings.Replace(yamlStr, "\n", "\\n", -1)
|
||||
yamlStr = strings.Replace(yamlStr, "\"", "\\\"", -1)
|
||||
|
||||
// variable replacement
|
||||
rVariable, e1 := regexp.Compile("{{{([^}]*)}}}")
|
||||
if e1 != nil {
|
||||
return "", e1
|
||||
}
|
||||
yamlStr = rVariable.ReplaceAllString(yamlStr, "',variables('$1'),'")
|
||||
// verbatim replacement
|
||||
rVerbatim, e2 := regexp.Compile("<<<([^>]*)>>>")
|
||||
if e2 != nil {
|
||||
return "", e2
|
||||
}
|
||||
yamlStr = rVerbatim.ReplaceAllString(yamlStr, "',$1,'")
|
||||
return yamlStr, nil
|
||||
}
|
||||
|
||||
// getBase64CustomScript will return a base64 of the CSE
|
||||
func getBase64CustomScript(a *vlabs.AcsCluster, csFilename string, partsDirectory string) string {
|
||||
csFile := path.Join(partsDirectory, csFilename)
|
||||
if _, err := os.Stat(csFile); os.IsNotExist(err) {
|
||||
panic(err.Error())
|
||||
}
|
||||
b, err := ioutil.ReadFile(csFile)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
// translate the parameters
|
||||
csStr := string(b)
|
||||
csStr = strings.Replace(csStr, "\r\n", "\n", -1)
|
||||
|
||||
var gzipB bytes.Buffer
|
||||
w := gzip.NewWriter(&gzipB)
|
||||
w.Write([]byte(csStr))
|
||||
w.Close()
|
||||
|
||||
return base64.StdEncoding.EncodeToString(gzipB.Bytes())
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Package util provides various utility functions for the generator
|
||||
package util
|
|
@ -0,0 +1,171 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
ValidityDuration = time.Hour * 24 * 365 * 2
|
||||
PkiKeySize = 4096
|
||||
)
|
||||
|
||||
type PkiKeyCertPair struct {
|
||||
CertificatePem string
|
||||
PrivateKeyPem string
|
||||
}
|
||||
|
||||
func CreatePki(masterFQDN string, extraFQDNs []string, extraIPs []net.IP, clusterDomain string) (*PkiKeyCertPair, *PkiKeyCertPair, *PkiKeyCertPair, *PkiKeyCertPair, error) {
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.default"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.default.svc"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.default.svc.%s", clusterDomain))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.kube-system"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.kube-system.svc"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.kube-system.svc.%s", clusterDomain))
|
||||
start := time.Now()
|
||||
caCertificate, caPrivateKey, err := createCertificate("ca", nil, nil, false, "", nil, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
apiServerCertificate *x509.Certificate
|
||||
apiServerPrivateKey *rsa.PrivateKey
|
||||
clientCertificate *x509.Certificate
|
||||
clientPrivateKey *rsa.PrivateKey
|
||||
kubeConfigCertificate *x509.Certificate
|
||||
kubeConfigPrivateKey *rsa.PrivateKey
|
||||
)
|
||||
errors := make(chan error)
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
apiServerCertificate, apiServerPrivateKey, err = createCertificate("apiserver", caCertificate, caPrivateKey, true, masterFQDN, extraFQDNs, extraIPs)
|
||||
errors <- err
|
||||
}()
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
clientCertificate, clientPrivateKey, err = createCertificate("client", caCertificate, caPrivateKey, false, "", nil, nil)
|
||||
errors <- err
|
||||
}()
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
kubeConfigCertificate, kubeConfigPrivateKey, err = createCertificate("client", caCertificate, caPrivateKey, false, "", nil, nil)
|
||||
errors <- err
|
||||
}()
|
||||
|
||||
e1 := <-errors
|
||||
e2 := <-errors
|
||||
e3 := <-errors
|
||||
if e1 != nil {
|
||||
return nil, nil, nil, nil, e1
|
||||
}
|
||||
if e2 != nil {
|
||||
return nil, nil, nil, nil, e2
|
||||
}
|
||||
if e3 != nil {
|
||||
return nil, nil, nil, nil, e2
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "cert creation took %s\n", time.Since(start))
|
||||
return &PkiKeyCertPair{CertificatePem: string(certificateToPem(caCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(caPrivateKey))},
|
||||
&PkiKeyCertPair{CertificatePem: string(certificateToPem(apiServerCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(apiServerPrivateKey))},
|
||||
&PkiKeyCertPair{CertificatePem: string(certificateToPem(clientCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(clientPrivateKey))},
|
||||
&PkiKeyCertPair{CertificatePem: string(certificateToPem(kubeConfigCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(kubeConfigPrivateKey))},
|
||||
nil
|
||||
}
|
||||
|
||||
func createCertificate(commonName string, caCertificate *x509.Certificate, caPrivateKey *rsa.PrivateKey, isServer bool, FQDN string, extraFQDNs []string, extraIPs []net.IP) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
var err error
|
||||
|
||||
isCA := (caCertificate == nil)
|
||||
|
||||
now := time.Now()
|
||||
|
||||
template := x509.Certificate{
|
||||
Subject: pkix.Name{CommonName: commonName},
|
||||
NotBefore: now,
|
||||
NotAfter: now.Add(ValidityDuration),
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
if isCA {
|
||||
template.KeyUsage |= x509.KeyUsageCertSign
|
||||
template.IsCA = isCA
|
||||
} else if isServer {
|
||||
extraFQDNs = append(extraFQDNs, FQDN)
|
||||
extraIPs = append(extraIPs, net.ParseIP("10.0.0.1"))
|
||||
|
||||
template.DNSNames = extraFQDNs
|
||||
template.IPAddresses = extraIPs
|
||||
template.ExtKeyUsage = append(template.ExtKeyUsage, x509.ExtKeyUsageServerAuth)
|
||||
} else {
|
||||
template.ExtKeyUsage = append(template.ExtKeyUsage, x509.ExtKeyUsageClientAuth)
|
||||
}
|
||||
|
||||
snMax := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
template.SerialNumber, err = rand.Int(rand.Reader, snMax)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, PkiKeySize)
|
||||
|
||||
var privateKeyToUse *rsa.PrivateKey
|
||||
var certificateToUse *x509.Certificate
|
||||
if !isCA {
|
||||
privateKeyToUse = caPrivateKey
|
||||
certificateToUse = caCertificate
|
||||
} else {
|
||||
privateKeyToUse = privateKey
|
||||
certificateToUse = &template
|
||||
}
|
||||
|
||||
certDerBytes, err := x509.CreateCertificate(rand.Reader, &template, certificateToUse, &privateKey.PublicKey, privateKeyToUse)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
certificate, err := x509.ParseCertificate(certDerBytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return certificate, privateKey, nil
|
||||
}
|
||||
|
||||
func certificateToPem(derBytes []byte) []byte {
|
||||
pemBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: derBytes,
|
||||
}
|
||||
pemBuffer := bytes.Buffer{}
|
||||
pem.Encode(&pemBuffer, pemBlock)
|
||||
|
||||
return pemBuffer.Bytes()
|
||||
}
|
||||
|
||||
func privateKeyToPem(privateKey *rsa.PrivateKey) []byte {
|
||||
pemBlock := &pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
||||
}
|
||||
pemBuffer := bytes.Buffer{}
|
||||
pem.Encode(&pemBuffer, pemBlock)
|
||||
|
||||
return pemBuffer.Bytes()
|
||||
}
|
Загрузка…
Ссылка в новой задаче