add stateful pool support to dcos

This commit is contained in:
Anthony Howe 2016-09-28 12:33:38 -07:00
Родитель 2c130400c4
Коммит 15ea4a5c2d
14 изменённых файлов: 452 добавлений и 37 удалений

Просмотреть файл

@ -84,11 +84,12 @@ func usage(errs ...error) {
fmt.Fprintf(os.Stderr, "usage: %s 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:")
fmt.Fprintf(os.Stderr, "options:\n")
flag.PrintDefaults()
}
var templateDirectory = flag.String("templateDirectory", "./parts", "directory containing base template files")
var noPrettyPrint = flag.Bool("noPrettyPrint", false, "do not pretty print output")
func main() {
var acsCluster *vlabs.AcsCluster
@ -128,10 +129,11 @@ func main() {
os.Exit(1)
}
if template, err = prettyPrintArmTemplate(template); err != nil {
fmt.Fprintf(os.Stderr, "error pretty printing template %s", err.Error())
os.Exit(1)
if !*noPrettyPrint {
if template, err = prettyPrintArmTemplate(template); err != nil {
fmt.Fprintf(os.Stderr, "error pretty printing template %s", err.Error())
os.Exit(1)
}
}
fmt.Print(template)
}

Просмотреть файл

@ -25,4 +25,6 @@ const (
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
)

Просмотреть файл

@ -29,9 +29,10 @@ type AgentPoolProfile struct {
Name string `json:"name"`
Count int `json:"count"`
VMSize string `json:"vmSize"`
IsStateless bool `json:"isStateless,omitempty"`
DNSPrefix string `json:"dnsPrefix,omitempty"`
Ports []int `json:"ports,omitempty"`
IsStateful bool `json:"isStateful,omitempty"`
DiskSizesGB []int `json:"diskSizesGB,omitempty"`
VnetSubnetID string `json:"vnetSubnetID,omitempty"`
// subnet is internal
subnet string
@ -68,6 +69,11 @@ func (a *AgentPoolProfile) IsCustomVNET() bool {
return len(a.VnetSubnetID) > 0
}
// HasDisks returns true if the customer specified disks
func (a *AgentPoolProfile) HasDisks() bool {
return len(a.DiskSizesGB) > 0
}
// GetSubnet returns the read-only subnet for the agent pool
func (a *AgentPoolProfile) GetSubnet() string {
return a.subnet

Просмотреть файл

@ -28,10 +28,12 @@ func (m *MasterProfile) Validate() error {
if e := validateName(m.DNSPrefix, "MasterProfile.DNSPrefix"); e != nil {
return e
}
if e := validateDNSName(m.DNSPrefix); e != nil {
return e
}
if e := validateName(m.VMSize, "MasterProfile.VMSize"); e != nil {
return e
}
return nil
}
@ -40,6 +42,9 @@ func (a *AgentPoolProfile) Validate() error {
if e := validateName(a.Name, "AgentPoolProfile.Name"); e != nil {
return e
}
if e := validatePoolName(a.Name); e != nil {
return e
}
if a.Count < MinAgentCount || a.Count > MaxAgentCount {
return fmt.Errorf("AgentPoolProfile count needs to be in the range [%d,%d]", MinAgentCount, MaxAgentCount)
}
@ -58,6 +63,15 @@ func (a *AgentPoolProfile) Validate() error {
if e := validateName(a.DNSPrefix, "AgentPoolProfile.DNSPrefix when specifying AgentPoolProfile Ports"); e != nil {
return e
}
if e := validateDNSName(a.DNSPrefix); e != nil {
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) > 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)
}
if len(a.Ports) == 0 && len(a.DNSPrefix) > 0 {
return fmt.Errorf("AgentPoolProfile.Ports must be non empty when AgentPoolProfile.DNSPrefix is specified")
@ -94,6 +108,9 @@ func (a *AcsCluster) Validate() error {
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")
}
}
if e := a.LinuxProfile.Validate(); e != nil {
return e
@ -141,6 +158,33 @@ func parseCIDR(cidr string) (octet1 int, octet2 int, octet3 int, octet4 int, sub
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})$`
re, err := regexp.Compile(poolNameRegex)
if err != nil {
return err
}
submatches := re.FindStringSubmatch(poolName)
if len(submatches) != 2 {
return fmt.Errorf("pool name '%s' is invalid. A pool name must start with a lowercase letter, have max length of 12, and only have characters a-z0-9", poolName)
}
return nil
}
func validateDNSName(dnsName string) error {
dnsNameRegex := `^([a-z][a-z0-9-]{1,13}[a-z0-9])$`
re, err := regexp.Compile(dnsNameRegex)
if err != nil {
return err
}
submatches := re.FindStringSubmatch(dnsName)
if len(submatches) != 2 {
return fmt.Errorf("DNS name '%s' is invalid. The DNS name must contain between 3 and 15 characters. The name can contain only letters, numbers, and hyphens. The name must start with a letter and must end with a letter or a number", dnsName)
}
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/
@ -199,7 +243,7 @@ func validateVNET(a *AcsCluster) error {
}
if isCustomVNET {
if a.OrchestratorProfile.OrchestratorType == SWARM {
return errors.New("bring your own VNET is not supported with 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 {

Просмотреть файл

@ -0,0 +1,34 @@
{
"orchestratorProfile": {
"orchestratorType": "DCOS"
},
"masterProfile": {
"count": 3,
"dnsPrefix": "mgmtanhowe0928d",
"vmSize": "Standard_D2_v2"
},
"agentPoolProfiles": [
{
"name": "agtnodisks1",
"count": 1,
"vmSize": "Standard_D2_v2",
"isStateful": true
},
{
"name": "agtnodisks2",
"count": 1,
"vmSize": "Standard_D2_v2",
"isStateful": true
}
],
"linuxProfile": {
"adminUsername": "azureuser",
"ssh": {
"publicKeys": [
{
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
}
]
}
}
}

Просмотреть файл

@ -0,0 +1,70 @@
{
"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"
}
]
}
}
}

Просмотреть файл

@ -9,12 +9,12 @@
},
"agentPoolProfiles": [
{
"name": "agentPrivate",
"name": "agentprivate",
"count": 3,
"vmSize": "Standard_D2_v2"
},
{
"name": "agentPublic",
"name": "agentpublic",
"count": 3,
"vmSize": "Standard_D2_v2",
"dnsPrefix": "appanhowe0927i",

Просмотреть файл

@ -9,12 +9,12 @@
},
"agentPoolProfiles": [
{
"name": "agentPrivate",
"name": "agentprivate",
"count": 3,
"vmSize": "Standard_D2_v2"
},
{
"name": "agentPublic",
"name": "agentpublic",
"count": 3,
"vmSize": "Standard_D2_v2",
"dnsPrefix": "appanhowe0926i",

Просмотреть файл

@ -15,27 +15,28 @@ import (
)
const (
agentOutputs = "agentoutputs.t"
agentParams = "agentparams.t"
dcosAgentResources = "dcosagentresources.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"
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, dcosAgentVars, dcosBaseFile, dcosCustomData173, dcosCustomData184, dcosMasterResources, dcosMasterVars, masterOutputs, masterParams}
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
@ -101,6 +102,9 @@ func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (stri
"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 {
@ -327,6 +331,31 @@ func getSecurityRule(port int, portIndex int) string {
}`, 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 {

Просмотреть файл

@ -12,7 +12,7 @@
{
"apiVersion": "[variables('apiVersionStorage')]",
"copy": {
"count": "[variables('agentStorageAccountsCount')]",
"count": "[variables('{{.Name}}StorageAccountsCount')]",
"name": "loop"
},
"dependsOn": [

Просмотреть файл

@ -0,0 +1,210 @@
{
"apiVersion": "[variables('apiVersionDefault')]",
"location": "[resourceGroup().location]",
"name": "[variables('{{.Name}}NSGName')]",
"properties": {
"securityRules": [
{{GetSecurityRules .Ports}}
]
},
"type": "Microsoft.Network/networkSecurityGroups"
},
{
"apiVersion": "[variables('apiVersionDefault')]",
"copy": {
"count": "[variables('{{.Name}}Count')]",
"name": "loop"
},
"dependsOn": [
{{if .IsCustomVNET}}
"[concat('Microsoft.Network/networkSecurityGroups/', variables('{{.Name}}NSGName'))]"
{{else}}
"[variables('vnetID')]"
{{end}}
{{if IsPublic .Ports}}
,"[variables('{{.Name}}LbID')]"
{{end}}
],
"location": "[resourceGroup().location]",
"name": "[concat(variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex())]",
"properties": {
{{if .IsCustomVNET}}
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/', variables('{{.Name}}NSGName'))]"
},
{{end}}
"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": "loop"
},
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))]"
],
"location": "[variables('storageLocation')]",
"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('storageLocation')]",
"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(concat({{if IsDCOS173}}{{template "dcoscustomdata173.t" dict "DCOSCustomDataPublicIPStr" GetDCOSCustomDataPublicIPStr "DCOSGUID" GetDCOSGUID "RolesString" (GetAgentRolesFileContents .Ports)}}{{else if IsDCOS184}}{{template "dcoscustomdata184.t" dict "DCOSCustomDataPublicIPStr" GetDCOSCustomDataPublicIPStr "DCOSGUID" GetDCOSGUID "RolesString" (GetAgentRolesFileContents .Ports)}}{{end}}))]",
"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,5 +1,11 @@
"{{.Name}}StorageAccountOffset": "[mul(variables('agentStorageAccountsCount'),variables('{{.Name}}Index'))]",
"{{.Name}}Count": "[parameters('{{.Name}}Count')]",
"{{.Name}}StorageAccountOffset": "[mul(variables('maxStorageAccountsPerAgent'),variables('{{.Name}}Index'))]",
"{{.Name}}Count": "[parameters('{{.Name}}Count')]",
{{if .IsStateful}}
"{{.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}}NSGID": "[resourceId('Microsoft.Network/networkSecurityGroups',variables('{{.Name}}NSGName'))]",
"{{.Name}}NSGName": "[concat(variables('orchestratorName'), '-{{.Name}}-nsg-', variables('nameSuffix'))]",
"{{.Name}}VMNamePrefix": "[concat(variables('orchestratorName'), '-{{.Name}}-', variables('nameSuffix'))]",

Просмотреть файл

@ -8,14 +8,23 @@
"variables": {
{{range $index, $agent := .AgentPoolProfiles}}
{{template "dcosagentvars.t" .}}
{{if .IsStateful}}
"{{.Name}}DataAccountName": "[concat(variables('storageAccountBaseName'), 'data{{$index}}')]",
{{end}}
"{{.Name}}Index": {{$index}},
"{{.Name}}AccountName": "[concat(variables('storageAccountBaseName'), 'agnt{{$index}}')]",
"{{.Name}}AccountName": "[concat(variables('storageAccountBaseName'), 'agnt{{$index}}')]",
{{end}}
{{template "dcosmastervars.t" .}}
},
"resources": [
{{range .AgentPoolProfiles}}{{template "dcosagentresources.t" .}},{{end}}
{{range .AgentPoolProfiles}}
{{if .IsStateful}}
{{template "dcosagentresourcesdisks.t" .}},
{{else}}
{{template "dcosagentresources.t" .}},
{{end}}
{{end}}
{{template "dcosmasterresources.t" .}}
],
"outputs": {

Просмотреть файл

@ -1,5 +1,8 @@
"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",
"masterAvailabilitySet": "[concat(variables('orchestratorName'), '-master-availabilitySet-', variables('nameSuffix'))]",