From 61a2db0a619bfddb9845d2995d509b79af18e867 Mon Sep 17 00:00:00 2001 From: Bruce Campbell Date: Thu, 17 Aug 2017 11:56:33 -0700 Subject: [PATCH] DCOS with Windows Agents (#1132) --- Makefile | 9 +- examples/windows/dcos-win.json | 43 ++++ examples/windows/dcos-winagent.json | 43 ++++ parts/dcosWindowsAgentResourcesVmas.t | 270 ++++++++++++++++++++++++++ parts/dcosWindowsAgentResourcesVmss.t | 204 +++++++++++++++++++ parts/dcosWindowsProvision.ps1 | 200 +++++++++++++++++++ parts/dcosagentvars.t | 24 ++- parts/dcosbase.t | 32 ++- parts/dcosmastervars.t | 24 ++- parts/dcosparams.t | 9 +- parts/kubernetesbase.t | 2 +- pkg/acsengine/const.go | 1 + pkg/acsengine/defaults.go | 12 +- pkg/acsengine/engine.go | 93 +++++---- pkg/acsengine/json.go | 3 + pkg/acsengine/types.go | 7 +- pkg/api/vlabs/validate.go | 1 + 17 files changed, 919 insertions(+), 58 deletions(-) create mode 100644 examples/windows/dcos-win.json create mode 100644 examples/windows/dcos-winagent.json create mode 100644 parts/dcosWindowsAgentResourcesVmas.t create mode 100644 parts/dcosWindowsAgentResourcesVmss.t create mode 100644 parts/dcosWindowsProvision.ps1 diff --git a/Makefile b/Makefile index e5513b3110..c8a39310e9 100644 --- a/Makefile +++ b/Makefile @@ -5,12 +5,17 @@ DIST_DIRS = find * -type d -exec .PHONY: bootstrap build test test_fmt validate-generated fmt lint ci devenv +ifdef DEBUG +GOFLAGS := -gcflags="-N -l" +else +GOFLAGS := +endif + # go option GO ?= go PKG := $(shell glide novendor) TAGS := -LDFLAGS := -GOFLAGS := +LDFLAGS := BINDIR := $(CURDIR)/bin BINARIES := acs-engine VERSION ?= $(shell git rev-parse HEAD) diff --git a/examples/windows/dcos-win.json b/examples/windows/dcos-win.json new file mode 100644 index 0000000000..a3f10db5fd --- /dev/null +++ b/examples/windows/dcos-win.json @@ -0,0 +1,43 @@ +{ + "apiVersion": "vlabs", + "properties": { + "orchestratorProfile": { + "orchestratorType": "DCOS" + }, + "masterProfile": { + "count": 1, + "dnsPrefix": "dcos-mstr", + "vmSize": "Standard_D2_v2" + }, + "agentPoolProfiles": [ + { + "name": "win2", + "count": 2, + "vmSize": "Standard_D2_v2", + "availabilityProfile": "AvailabilitySet", + "osType": "Windows", + "dnsPrefix": "agnt", + "ports": [ + 80, + 443, + 8080, + 3389 + ] + } + ], + "windowsProfile": { + "adminUsername": "azureuser", + "adminPassword": "replacepassword1234$" + }, + "linuxProfile": { + "adminUsername": "azureuser", + "ssh": { + "publicKeys": [ + { + "keyData": "" + } + ] + } + } + } +} diff --git a/examples/windows/dcos-winagent.json b/examples/windows/dcos-winagent.json new file mode 100644 index 0000000000..a3f10db5fd --- /dev/null +++ b/examples/windows/dcos-winagent.json @@ -0,0 +1,43 @@ +{ + "apiVersion": "vlabs", + "properties": { + "orchestratorProfile": { + "orchestratorType": "DCOS" + }, + "masterProfile": { + "count": 1, + "dnsPrefix": "dcos-mstr", + "vmSize": "Standard_D2_v2" + }, + "agentPoolProfiles": [ + { + "name": "win2", + "count": 2, + "vmSize": "Standard_D2_v2", + "availabilityProfile": "AvailabilitySet", + "osType": "Windows", + "dnsPrefix": "agnt", + "ports": [ + 80, + 443, + 8080, + 3389 + ] + } + ], + "windowsProfile": { + "adminUsername": "azureuser", + "adminPassword": "replacepassword1234$" + }, + "linuxProfile": { + "adminUsername": "azureuser", + "ssh": { + "publicKeys": [ + { + "keyData": "" + } + ] + } + } + } +} diff --git a/parts/dcosWindowsAgentResourcesVmas.t b/parts/dcosWindowsAgentResourcesVmas.t new file mode 100644 index 0000000000..b3089cfede --- /dev/null +++ b/parts/dcosWindowsAgentResourcesVmas.t @@ -0,0 +1,270 @@ + { + "apiVersion": "[variables('apiVersionDefault')]", + "location": "[variables('location')]", + "name": "[variables('{{.Name}}NSGName')]", + "properties": { + "securityRules": [ + {{GetSecurityRules .Ports}} + ] + }, + "type": "Microsoft.Network/networkSecurityGroups" + }, + { + "apiVersion": "[variables('apiVersionDefault')]", + "copy": { + "count": "[sub(variables('{{.Name}}Count'), variables('{{.Name}}Offset'))]", + "name": "loop" + }, + "dependsOn": [ +{{if .IsCustomVNET}} + "[concat('Microsoft.Network/networkSecurityGroups/', variables('{{.Name}}NSGName'))]" +{{else}} + "[variables('vnetID')]" +{{end}} +{{if IsPublic .Ports}} + ,"[variables('{{.Name}}LbID')]" +{{end}} + ], + "location": "[variables('location')]", + "name": "[concat(variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex(variables('{{.Name}}Offset')))]", + "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'))]" + } + ], + "loadBalancerInboundNatPools": [ + { + "id": "[concat(variables('{{.Name}}LbID'), '/inboundNatPools/', 'RDP-', variables('{{.Name}}VMNamePrefix'))]" + } + ], +{{end}} + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[variables('{{.Name}}VnetSubnetID')]" + } + } + } + ] + }, + "type": "Microsoft.Network/networkInterfaces" + }, +{{if .IsManagedDisks}} + { + "apiVersion": "[variables('apiVersionStorageManagedDisks')]", + "location": "[variables('location')]", + "name": "[variables('{{.Name}}AvailabilitySet')]", + "properties": { + "platformFaultDomainCount": "2", + "platformUpdateDomainCount": "3", + "managed": "true" + }, + "type": "Microsoft.Compute/availabilitySets" + }, +{{else if .IsStorageAccount}} + { + "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" + }, +{{end}} +{{if IsPublic .Ports}} + { + "apiVersion": "[variables('apiVersionDefault')]", + "location": "[variables('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": "[variables('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'))]" + } + } + } + ], + "inboundNatPools": [ + { + "name": "[concat('RDP-', variables('{{.Name}}VMNamePrefix'))]", + "properties": { + "frontendIPConfiguration": { + "id": "[variables('{{.Name}}LbIPConfigID')]" + }, + "protocol": "tcp", + "frontendPortRangeStart": "[variables('{{.Name}}WindowsRDPNatRangeStart')]", + "frontendPortRangeEnd": "[variables('{{.Name}}WindowsRDPEndRangeStop')]", + "backendPort": "[variables('agentWindowsBackendPort')]" + } + } + ], + "loadBalancingRules": [ + {{(GetLBRules .Name .Ports)}} + ], + "probes": [ + {{(GetProbes .Ports)}} + ] + }, + "type": "Microsoft.Network/loadBalancers" + }, +{{end}} + { +{{if .IsManagedDisks}} + "apiVersion": "[variables('apiVersionStorageManagedDisks')]", +{{else}} + "apiVersion": "[variables('apiVersionDefault')]", +{{end}} + "copy": { + "count": "[sub(variables('{{.Name}}Count'), variables('{{.Name}}Offset'))]", + "name": "vmLoopNode" + }, + "dependsOn": [ +{{if .IsStorageAccount}} + "[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(variables('{{.Name}}Offset')),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(variables('{{.Name}}Offset')),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]", + {{if .HasDisks}} + "[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(add(div(copyIndex(variables('{{.Name}}Offset')),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(add(div(copyIndex(variables('{{.Name}}Offset')),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}DataAccountName'))]", + {{end}} +{{end}} + "[concat('Microsoft.Network/networkInterfaces/', variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex(variables('{{.Name}}Offset')))]", + "[concat('Microsoft.Compute/availabilitySets/', variables('{{.Name}}AvailabilitySet'))]" + ], + "tags": + { + "creationSource" : "[concat('acsengine-', variables('{{.Name}}VMNamePrefix'), copyIndex(variables('{{.Name}}Offset')))]" + }, + "location": "[variables('location')]", + "name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(variables('{{.Name}}Offset')))]", + "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(variables('{{.Name}}Offset'))))]" + } + ] + }, + "osProfile": { + "computername": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(variables('{{.Name}}Offset')))]", + "adminUsername": "[variables('windowsAdminUsername')]", + "adminPassword": "[variables('windowsAdminPassword')]", + {{GetDCOSWindowsAgentCustomData .}} + + }, + "storageProfile": { + {{GetDataDisks .}} + "imageReference": { + "offer": "[variables('agentWindowsOffer')]", + "publisher": "[variables('agentWindowsPublisher')]", + "sku": "[variables('agentWindowsSKU')]", + "version": "[variables('agentWindowsVersion')]" + } + ,"osDisk": { + "caching": "ReadOnly" + ,"createOption": "FromImage" +{{if .IsStorageAccount}} + ,"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(variables('{{.Name}}Offset')),'-osdisk')]" + ,"vhd": { + "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(variables('{{.Name}}Offset')),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(variables('{{.Name}}Offset')),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')),variables('apiVersionStorage')).primaryEndpoints.blob,'osdisk/', variables('{{.Name}}VMNamePrefix'), copyIndex(variables('{{.Name}}Offset')), '-osdisk.vhd')]" + } +{{end}} +{{if ne .OSDiskSizeGB 0}} + ,"diskSizeGB": {{.OSDiskSizeGB}} +{{end}} + } + } + }, + "type": "Microsoft.Compute/virtualMachines" + }, + { + "apiVersion": "[variables('apiVersionDefault')]", + "copy": { + "count": "[sub(variables('{{.Name}}Count'), variables('{{.Name}}Offset'))]", + "name": "vmLoopNode" + }, + "dependsOn": [ + "[concat('Microsoft.Compute/virtualMachines/', variables('{{.Name}}VMNamePrefix'), copyIndex(variables('{{.Name}}Offset')))]" + ], + "location": "[variables('location')]", + "name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(variables('{{.Name}}Offset')), '/cse')]", + "properties": { + "publisher": "Microsoft.Compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.8", + "autoUpgradeMinorVersion": true, + "settings": { + "commandToExecute": "[variables('{{.Name}}windowsAgentCustomScript')]" + } + }, + "type": "Microsoft.Compute/virtualMachines/extensions" + } diff --git a/parts/dcosWindowsAgentResourcesVmss.t b/parts/dcosWindowsAgentResourcesVmss.t new file mode 100644 index 0000000000..7b41afe580 --- /dev/null +++ b/parts/dcosWindowsAgentResourcesVmss.t @@ -0,0 +1,204 @@ + { + "apiVersion": "[variables('apiVersionDefault')]", + "location": "[variables('location')]", + "name": "[variables('{{.Name}}NSGName')]", + "properties": { + "securityRules": [ + {{GetSecurityRules .Ports}} + ] + }, + "type": "Microsoft.Network/networkSecurityGroups" + }, +{{if .IsStorageAccount}} + { + "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" + }, +{{end}} +{{if IsPublic .Ports}} + { + "apiVersion": "[variables('apiVersionDefault')]", + "location": "[variables('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": "[variables('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}} + { +{{if .IsManagedDisks}} + "apiVersion": "[variables('apiVersionStorageManagedDisks')]", +{{else}} + "apiVersion": "[variables('apiVersionDefault')]", +{{end}} + "dependsOn": [ +{{if .IsCustomVNET}} + "[concat('Microsoft.Network/networkSecurityGroups/', variables('{{.Name}}NSGName'))]" +{{else}} + "[variables('vnetID')]" +{{end}} +{{if .IsStorageAccount}} + ,"[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'))]" +{{end}} +{{if IsPublic .Ports}} + ,"[concat('Microsoft.Network/loadBalancers/', variables('{{.Name}}LbName'))]" +{{end}} + ], + "tags": + { + "creationSource" : "[concat('acsengine-', variables('{{.Name}}VMNamePrefix'), '-vmss')]" + }, + "location": "[variables('location')]", + "name": "[concat(variables('{{.Name}}VMNamePrefix'), '-vmss')]", + "properties": { + "upgradePolicy": { + "mode": "Manual" + }, + "virtualMachineProfile": { + "networkProfile": { + "networkInterfaceConfigurations": [ + { + "name": "nic", + "properties": { +{{if .IsCustomVNET}} + "networkSecurityGroup": { + "id": "[resourceId('Microsoft.Network/networkSecurityGroups/', variables('{{.Name}}NSGName'))]" + }, +{{end}} + "ipConfigurations": [ + { + "name": "nicipconfig", + "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}} + "subnet": { + "id": "[variables('{{.Name}}VnetSubnetID')]" + } + } + } + ], + "primary": "true" + } + } + ] + }, + "osProfile": { + "computerNamePrefix": "[concat(substring(variables('nameSuffix'), 0, 5), 'acs')]", + "adminUsername": "[variables('windowsAdminUsername')]", + "adminPassword": "[variables('windowsAdminPassword')]", + {{GetDCOSWindowsAgentCustomData .}} + {{if HasWindowsSecrets}} + , + "secrets": "[variables('windowsProfileSecrets')]" + {{end}} + }, + "storageProfile": { + "imageReference": { + "publisher": "[variables('agentWindowsPublisher')]", + "offer": "[variables('agentWindowsOffer')]", + "sku": "[variables('agentWindowsSku')]", + "version": "latest" + }, + {{GetDataDisks .}} + "osDisk": { + "caching": "ReadOnly", + "createOption": "FromImage" +{{if .IsStorageAccount}} + ,"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('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')]" + + ] +{{end}} +{{if ne .OSDiskSizeGB 0}} + ,"diskSizeGB": {{.OSDiskSizeGB}} +{{end}} + } + }, + "extensionProfile": { + "extensions": [ + { + "name": "vmssCustomScriptExtension", + "properties": { + "publisher": "Microsoft.Compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.8", + "autoUpgradeMinorVersion": true, + "settings": { + "commandToExecute": "[variables('{{.Name}}windowsAgentCustomScript')]" + } + } + } + ] + } + } + }, + "sku": { + "capacity": "[variables('{{.Name}}Count')]", + "name": "[variables('{{.Name}}VMSize')]", + "tier": "[variables('{{.Name}}VMSizeTier')]" + }, + "type": "Microsoft.Compute/virtualMachineScaleSets" + } diff --git a/parts/dcosWindowsProvision.ps1 b/parts/dcosWindowsProvision.ps1 new file mode 100644 index 0000000000..e5ebbd7dbb --- /dev/null +++ b/parts/dcosWindowsProvision.ps1 @@ -0,0 +1,200 @@ +<# + .SYNOPSIS + Provisions VM as a DCOS agent. + + .DESCRIPTION + Provisions VM as a DCOS agent. + + Invoke by: + +#> + +[CmdletBinding(DefaultParameterSetName="Standard")] +param( + [string] + [ValidateNotNullOrEmpty()] + $masterCount, + + [string] + [ValidateNotNullOrEmpty()] + $firstMasterIP, + + [string] + [ValidateNotNullOrEmpty()] + $bootstrapUri, + + [parameter()] + [ValidateNotNullOrEmpty()] + $isAgent, + + [parameter()] + [ValidateNotNullOrEmpty()] + $subnet, + + [switch] + [AllowNull()] + $isPublic = $false +) + + + + +$global:BootstrapInstallDir = "C:\AzureData" + +filter Timestamp {"$(Get-Date -Format o): $_"} + + +function +Write-Log($message) +{ + $msg = $message | Timestamp + Write-Output $msg +} + + +function +Expand-ZIPFile($file, $destination) +{ + $shell = new-object -com shell.application + $zip = $shell.NameSpace($file) + foreach($item in $zip.items()) + { + $shell.Namespace($destination).copyhere($item, 0x14) + } +} + + +function +Remove-Directory($dirname) +{ + + try { + #Get-ChildItem $dirname -Recurse | Remove-Item -force -confirm:$false + # This doesn't work because of long file names + # But this does: + Invoke-Expression ("cmd /C rmdir /s /q "+$dirname) + } + catch { + # If this fails we don't want it to stop + + } +} + + +function +Check-Subnet ([string]$cidr, [string]$ip) +{ + try { + + $network, [int]$subnetlen = $cidr.Split('/') + + if ($subnetlen -eq 0) + { + $subnetlen = 8 # Default in case we get an IP addr, not CIDR + } + $a = ([IPAddress] $network) + [uint32] $unetwork = [uint32]$a.Address + + $mask = -bnot ((-bnot [uint32]0) -shl (32 - $subnetlen)) + + $a = [IPAddress]$ip + [uint32] $uip = [uint32]$a.Address + + return ($unetwork -eq ($mask -band $uip)) + } + catch { + return $false + } +} + +# +# Gets the bootstrap script from the blob store and places it in c:\AzureData + +function +Get-BootstrapScript($download_uri, $download_dir) +{ + # Get Mesos Binaries + $scriptfile = "DCOSWindowsAgentSetup.ps1" + + Write-Log " get script "+ ($download_uri+"/"+$scriptfile) + "and put it "+ ($download_dir+"\"+$scriptfile) + + Invoke-WebRequest -Uri ($download_uri+"/"+$scriptfile) -OutFile ($download_dir+"\"+$scriptfile) + + $scriptfile = "packages.ps1" + Write-Log " get package file "+ ($download_uri+"/"+$scriptfile) + "and put it "+ ($download_dir+"\"+$scriptfile) + Invoke-WebRequest -Uri ($download_uri+"/"+$scriptfile) -OutFile ($download_dir+"\"+$scriptfile) + +} + + +try +{ + # Set to false for debugging. This will output the start script to + # c:\AzureData\dcosProvisionScript.log, and then you can RDP + # to the windows machine, and run the script manually to watch + # the output. + Write-Log "Get the install script" + + Write-Log ("Parameters = isAgent = ["+ $isAgent + "] mastercount = ["+$MasterCount + "] First master ip= [" + $firstMasterIp+ "] boostrap URI = ["+ $bootstrapUri+"] Subnet = ["+ $subnet +"]") + + # Get the boostrap script + + Get-BootstrapScript $bootstrapUri $global:BootstrapInstallDir + + # Convert Master count and first IP to a JSON array of IPAddresses + $ip = ([IPAddress]$firstMasterIp).getAddressBytes() + [Array]::Reverse($ip) + $ip = ([IPAddress]($ip -join '.')).Address + + $MasterIP = @([IPAddress]$null) + + for ($i = 0; $i -lt $MasterCount; $i++ ) + { + $new_ip = ([IPAddress]$ip).getAddressBytes() + [Array]::Reverse($new_ip) + $new_ip = [IPAddress]($new_ip -join '.') + $MasterIP += $new_ip + + $ip++ + + } + $master_str = $MasterIP.IPAddressToString + + # Add the port numbers + if ($master_str.count -eq 1) { + $master_str += ":2181" + } + else { + for ($i = 0; $i -lt $master_str.count; $i++) + { + $master_str[$i] += ":2181" + } + } + $master_json = ConvertTo-Json $master_str + $master_json = $master_json -replace [Environment]::NewLine,"" + + $private_ip = ( Get-NetIPAddress | where { $_.AddressFamily -eq "IPv4" } | where { Check-Subnet $subnet $_.IPAddress } ) # We know the subnet we are on. Makes it easier and more robust + [Environment]::SetEnvironmentVariable("DCOS_AGENT_IP", $private_ip.IPAddress, "Machine") + + if ($isAgent) + { + $run_cmd = $global:BootstrapInstallDir+"\DCOSWindowsAgentSetup.ps1 -MasterIP '$master_json' -AgentPrivateIP "+($private_ip.IPAddress) +" -BootstrapUrl '$bootstrapUri' " + if ($isPublic) + { + $run_cmd += " -isPublic:`$true " + } + $run_cmd += ">"+$global:BootstrapInstallDir+"\DCOSWindowsAgentSetup.log 2>&1" + Write-Log "run setup script $run_cmd" + Invoke-Expression $run_cmd + } + else # We must be deploying a master + { + $run_cmd = $global:BootstrapInstallDir+"\DCOSWindowsMasterSetup.ps1 -MasterIP '$master_json' -MasterPrivateIP $privateIP.IPAddress -BootstrapUrl '$bootstrapUri'" + Write-Log "run setup script $run_cmd" + Invoke-Expression $run_cmd + } +} +catch +{ + Write-Error $_ +} diff --git a/parts/dcosagentvars.t b/parts/dcosagentvars.t index 942930f4af..d4a5e5266f 100644 --- a/parts/dcosagentvars.t +++ b/parts/dcosagentvars.t @@ -1,7 +1,22 @@ "{{.Name}}Count": "[parameters('{{.Name}}Count')]", "{{.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'))]", +{{if .IsWindows}} + + "winResourceNamePrefix" : "[substring(variables('nameSuffix'), 0, 5)]", + "{{.Name}}VMNamePrefix": "[concat(variables('winResourceNamePrefix'), 'acs', add(900,variables('{{.Name}}Index')))]", + {{if IsPublic .Ports}} + "{{.Name}}windowsAgentCustomScriptArguments": "[concat('$arguments = ', variables('singleQuote'),'-subnet ', variables('{{.Name}}Subnet'), ' -MasterCount ', variables('masterCount'), ' -firstMasterIP ', parameters('firstConsecutiveStaticIP'), ' -bootstrapUri ', '\"', variables('dcosWindowsBootstrapURL'), '\"', ' -isAgent $true -isPublic:$true', variables('singleQuote'),' ; ')]", + {{else}} + "{{.Name}}windowsAgentCustomScriptArguments": "[concat('$arguments = ', variables('singleQuote'),'-subnet ', variables('{{.Name}}Subnet'), ' -MasterCount ', variables('masterCount'), ' -firstMasterIP ', parameters('firstConsecutiveStaticIP'), ' -bootstrapUri ', '\"', variables('dcosWindowsBootstrapURL'), '\"', ' -isAgent $true', variables('singleQuote'),' ; ')]", + {{end}} + + "{{.Name}}windowsAgentCustomScript": "[concat('powershell.exe -ExecutionPolicy Unrestricted -command \"', variables('{{.Name}}windowsAgentCustomScriptArguments'), variables('windowsCustomScriptSuffix'), '\" > %SYSTEMDRIVE%\\AzureData\\dcosWindowsProvision.log 2>&1')]", + +{{else}} + "{{.Name}}VMNamePrefix": "[concat(variables('orchestratorName'), '-{{.Name}}-', variables('nameSuffix'), '-')]", +{{end}} + "{{.Name}}VMSize": "[parameters('{{.Name}}VMSize')]", "{{.Name}}VMSizeTier": "[split(parameters('{{.Name}}VMSize'),'_')[0]]", {{if .IsAvailabilitySets}} @@ -31,4 +46,9 @@ "{{.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'))]", -{{end}} \ No newline at end of file + {{if .IsWindows}} + "{{.Name}}WindowsRDPNatRangeStart": 3389, + "{{.Name}}WindowsRDPEndRangeStop": "[add(variables('{{.Name}}WindowsRDPNatRangeStart'), add(variables('{{.Name}}Count'),variables('{{.Name}}Count')))]", + + {{end}} +{{end}} diff --git a/parts/dcosbase.t b/parts/dcosbase.t index 9583c91efc..45173b045e 100644 --- a/parts/dcosbase.t +++ b/parts/dcosbase.t @@ -3,11 +3,29 @@ "contentVersion": "1.0.0.0", "parameters": { {{range .AgentPoolProfiles}}{{template "agentparams.t" .}},{{end}} + {{if .HasWindows}} + "dcosBinariesURL": { + {{PopulateClassicModeDefaultValue "dcosBinariesURL"}} + "metadata": { + "description": "The download url for dcos/mesos windows binaries." + }, + "type": "string" + }, + "dcosBinariesVersion": { + {{PopulateClassicModeDefaultValue "dcosBinariesVersion"}} + "metadata": { + "description": "DCOS windows binaries version" + }, + "type": "string" + }, + {{template "windowsparams.t"}}, + {{end}} {{template "dcosparams.t" .}} {{template "masterparams.t" .}} }, "variables": { {{range $index, $agent := .AgentPoolProfiles}} + "{{.Name}}Index": {{$index}}, {{template "dcosagentvars.t" .}} {{if .IsStorageAccount}} "{{.Name}}StorageAccountOffset": "[mul(variables('maxStorageAccountsPerAgent'),{{$index}})]", @@ -22,10 +40,18 @@ }, "resources": [ {{range .AgentPoolProfiles}} - {{if .IsAvailabilitySets}} - {{template "dcosagentresourcesvmas.t" .}}, + {{if .IsWindows}} + {{if .IsAvailabilitySets}} + {{template "dcosWindowsAgentResourcesVmas.t" .}}, + {{else}} + {{template "dcosWindowsAgentResourcesVmss.t" .}}, + {{end}} {{else}} - {{template "dcosagentresourcesvmss.t" .}}, + {{if .IsAvailabilitySets}} + {{template "dcosagentresourcesvmas.t" .}}, + {{else}} + {{template "dcosagentresourcesvmss.t" .}}, + {{end}} {{end}} {{end}} {{template "dcosmasterresources.t" .}} diff --git a/parts/dcosmastervars.t b/parts/dcosmastervars.t index 49effe0976..88a0ee5cf5 100644 --- a/parts/dcosmastervars.t +++ b/parts/dcosmastervars.t @@ -2,6 +2,7 @@ "targetEnvironment": "[parameters('targetEnvironment')]", "maxVMsPerPool": 100, "apiVersionDefault": "2016-03-30", + "singleQuote": "'", {{if .LinuxProfile.HasSecrets}} "linuxProfileSecrets" : [ @@ -23,8 +24,22 @@ {{end}} ], {{end}} - "masterAvailabilitySet": "[concat(variables('orchestratorName'), '-master-availabilitySet-', variables('nameSuffix'))]", - "masterCount": {{.MasterProfile.Count}}, +{{if .HasWindows}} + "windowsAdminUsername": "[parameters('windowsAdminUsername')]", + "windowsAdminPassword": "[parameters('windowsAdminPassword')]", + "agentWindowsBackendPort": 3389, + "agentWindowsPublisher": "MicrosoftWindowsServer", + "agentWindowsOffer": "WindowsServer", + "agentWindowsSku": "2016-Datacenter-with-Containers", + "agentWindowsVersion": "latest", + "dcosWindowsBootstrapURL" : "[parameters('dcosWindowsBootstrapURL')]", + "windowsCustomScriptSuffix": " $inputFile = '%SYSTEMDRIVE%\\AzureData\\CustomData.bin' ; $outputFile = '%SYSTEMDRIVE%\\AzureData\\dcosWindowsProvision.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) ; ", + "windowsMasterCustomScriptArguments": "[concat('$arguments = ', variables('singleQuote'),'-MasterCount ', variables('masterCount'), ' -firstMasterIP ', parameters('firstConsecutiveStaticIP'), variables('singleQuote'), ' ; ')]", + + "windowsMasterCustomScript": "[concat('powershell.exe -ExecutionPolicy Unrestricted -command \"', variables('windowsMasterCustomScriptArguments'), variables('windowsCustomScriptSuffix'), '\" > %SYSTEMDRIVE%\\AzureData\\dcosWindowsProvision.log 2>&1')]", +{{end}} + "masterAvailabilitySet": "[concat(variables('orchestratorName'), '-master-availabilitySet-', variables('nameSuffix'))]", + "masterCount": {{.MasterProfile.Count}}, "masterEndpointDNSNamePrefix": "[tolower(parameters('masterEndpointDNSNamePrefix'))]", "masterHttpSourceAddressPrefix": "{{.MasterProfile.HTTPSourceAddressPrefix}}", "masterLbBackendPoolName": "[concat(variables('orchestratorName'), '-master-pool-', variables('nameSuffix'))]", @@ -36,8 +51,9 @@ "masterNSGName": "[concat(variables('orchestratorName'), '-master-nsg-', variables('nameSuffix'))]", "masterPublicIPAddressName": "[concat(variables('orchestratorName'), '-master-ip-', variables('masterEndpointDNSNamePrefix'), '-', variables('nameSuffix'))]", "apiVersionStorage": "2015-06-15", - "storageAccountBaseName": "[uniqueString(concat(variables('masterEndpointDNSNamePrefix'),variables('location'),variables('orchestratorName')))]", - "masterStorageAccountExhibitorName": "[concat(variables('storageAccountBaseName'), 'exhb0')]", + + "storageAccountBaseName": "[uniqueString(concat(variables('masterEndpointDNSNamePrefix'),variables('location'),variables('orchestratorName')))]", + "masterStorageAccountExhibitorName": "[concat(variables('storageAccountBaseName'), 'exhb0')]", "storageAccountType": "Standard_LRS", {{if .HasStorageAccountDisks}} "maxVMsPerStorageAccount": 20, diff --git a/parts/dcosparams.t b/parts/dcosparams.t index 014df34546..b7f96d8112 100644 --- a/parts/dcosparams.t +++ b/parts/dcosparams.t @@ -4,4 +4,11 @@ "description": "The default mesosphere bootstrap package." }, "type": "string" - }, \ No newline at end of file + }, + "dcosWindowsBootstrapURL": { + "defaultValue": "https://dcosio.azureedge.net/dcos/stable/windows-bootstrap/58fd0833ce81b6244fc73bf65b5deb43217b0bd7.WindowsBootstrap.zip", + "metadata": { + "description": "The default mesosphere bootstrap package for windows." + }, + "type": "string" + }, diff --git a/parts/kubernetesbase.t b/parts/kubernetesbase.t index 45c7fb3b46..70133516e8 100644 --- a/parts/kubernetesbase.t +++ b/parts/kubernetesbase.t @@ -53,4 +53,4 @@ {{end}} {{template "masteroutputs.t" .}} } -} \ No newline at end of file +} diff --git a/pkg/acsengine/const.go b/pkg/acsengine/const.go index c3f3733454..fbcc23cabe 100644 --- a/pkg/acsengine/const.go +++ b/pkg/acsengine/const.go @@ -156,4 +156,5 @@ const ( AzureEdgeDCOSBootstrapDownloadURL = "https://dcosio.azureedge.net/dcos/%s/bootstrap/%s.bootstrap.tar.xz" //AzureChinaCloudDCOSBootstrapDownloadURL is the China specific DCOS package download url. AzureChinaCloudDCOSBootstrapDownloadURL = "https://acsengine.blob.core.chinacloudapi.cn/dcos/%s.bootstrap.tar.xz" + //AzureEdgeDCOSWindowsBootstrapDownloadURL ) diff --git a/pkg/acsengine/defaults.go b/pkg/acsengine/defaults.go index eb052fffc4..de7386acb3 100644 --- a/pkg/acsengine/defaults.go +++ b/pkg/acsengine/defaults.go @@ -23,9 +23,10 @@ var ( }, DCOSSpecConfig: DCOSSpecConfig{ - DCOS173BootstrapDownloadURL: fmt.Sprintf(MsecndDCOSBootstrapDownloadURL, "testing", "df308b6fc3bd91e1277baa5a3db928ae70964722"), - DCOS188BootstrapDownloadURL: fmt.Sprintf(AzureEdgeDCOSBootstrapDownloadURL, "stable", "5df43052907c021eeb5de145419a3da1898c58a5"), - DCOS190BootstrapDownloadURL: fmt.Sprintf(AzureEdgeDCOSBootstrapDownloadURL, "stable", "58fd0833ce81b6244fc73bf65b5deb43217b0bd7"), + DCOS173BootstrapDownloadURL: fmt.Sprintf(MsecndDCOSBootstrapDownloadURL, "testing", "df308b6fc3bd91e1277baa5a3db928ae70964722"), + DCOS188BootstrapDownloadURL: fmt.Sprintf(AzureEdgeDCOSBootstrapDownloadURL, "stable", "5df43052907c021eeb5de145419a3da1898c58a5"), + DCOS190BootstrapDownloadURL: fmt.Sprintf(AzureEdgeDCOSBootstrapDownloadURL, "stable", "58fd0833ce81b6244fc73bf65b5deb43217b0bd7"), + DCOSWindowsBootstrapDownloadURL: "https://dcosdevstorage.blob.core.windows.net/dcos-windows", }, } @@ -42,8 +43,9 @@ var ( KubeBinariesSASURLBase: "https://acs-mirror.azureedge.net/wink8s/", }, DCOSSpecConfig: DCOSSpecConfig{ - DCOS173BootstrapDownloadURL: fmt.Sprintf(AzureChinaCloudDCOSBootstrapDownloadURL, "df308b6fc3bd91e1277baa5a3db928ae70964722"), - DCOS188BootstrapDownloadURL: fmt.Sprintf(AzureChinaCloudDCOSBootstrapDownloadURL, "5df43052907c021eeb5de145419a3da1898c58a5"), + DCOS173BootstrapDownloadURL: fmt.Sprintf(AzureChinaCloudDCOSBootstrapDownloadURL, "df308b6fc3bd91e1277baa5a3db928ae70964722"), + DCOS188BootstrapDownloadURL: fmt.Sprintf(AzureChinaCloudDCOSBootstrapDownloadURL, "5df43052907c021eeb5de145419a3da1898c58a5"), + DCOSWindowsBootstrapDownloadURL: "https://dcosdevstorage.blob.core.windows.net/dcos-windows", }, } ) diff --git a/pkg/acsengine/engine.go b/pkg/acsengine/engine.go index 0254f5fb45..0b051d6ea9 100644 --- a/pkg/acsengine/engine.go +++ b/pkg/acsengine/engine.go @@ -15,6 +15,7 @@ import ( "strings" "text/template" + //log "github.com/Sirupsen/logrus" "github.com/Azure/acs-engine/pkg/api" "github.com/Azure/acs-engine/pkg/i18n" "github.com/Masterminds/semver" @@ -30,10 +31,11 @@ const ( ) const ( - dcosCustomData173 = "dcoscustomdata173.t" - dcosCustomData188 = "dcoscustomdata188.t" - dcosCustomData190 = "dcoscustomdata190.t" - dcosProvision = "dcosprovision.sh" + dcosCustomData173 = "dcoscustomdata173.t" + dcosCustomData188 = "dcoscustomdata188.t" + dcosCustomData190 = "dcoscustomdata190.t" + dcosProvision = "dcosprovision.sh" + dcosWindowsProvision = "dcosWindowsProvision.ps1" ) const ( @@ -45,37 +47,39 @@ const ( ) const ( - agentOutputs = "agentoutputs.t" - agentParams = "agentparams.t" - classicParams = "classicparams.t" - dcosAgentResourcesVMAS = "dcosagentresourcesvmas.t" - dcosAgentResourcesVMSS = "dcosagentresourcesvmss.t" - dcosAgentVars = "dcosagentvars.t" - dcosBaseFile = "dcosbase.t" - dcosParams = "dcosparams.t" - dcosMasterResources = "dcosmasterresources.t" - dcosMasterVars = "dcosmastervars.t" - iaasOutputs = "iaasoutputs.t" - kubernetesBaseFile = "kubernetesbase.t" - kubernetesAgentResourcesVMAS = "kubernetesagentresourcesvmas.t" - kubernetesAgentVars = "kubernetesagentvars.t" - kubernetesMasterResources = "kubernetesmasterresources.t" - kubernetesMasterVars = "kubernetesmastervars.t" - kubernetesParams = "kubernetesparams.t" - kubernetesWinAgentVars = "kuberneteswinagentresourcesvmas.t" - kubernetesKubeletService = "kuberneteskubelet.service" - masterOutputs = "masteroutputs.t" - masterParams = "masterparams.t" - swarmBaseFile = "swarmbase.t" - swarmAgentResourcesVMAS = "swarmagentresourcesvmas.t" - swarmAgentResourcesVMSS = "swarmagentresourcesvmss.t" - swarmAgentResourcesClassic = "swarmagentresourcesclassic.t" - swarmAgentVars = "swarmagentvars.t" - swarmMasterResources = "swarmmasterresources.t" - swarmMasterVars = "swarmmastervars.t" - swarmWinAgentResourcesVMAS = "swarmwinagentresourcesvmas.t" - swarmWinAgentResourcesVMSS = "swarmwinagentresourcesvmss.t" - windowsParams = "windowsparams.t" + agentOutputs = "agentoutputs.t" + agentParams = "agentparams.t" + classicParams = "classicparams.t" + dcosAgentResourcesVMAS = "dcosagentresourcesvmas.t" + dcosWindowsAgentResourcesVMAS = "dcosWindowsAgentResourcesVmas.t" + dcosAgentResourcesVMSS = "dcosagentresourcesvmss.t" + dcosWindowsAgentResourcesVMSS = "dcosWindowsAgentResourcesVmss.t" + dcosAgentVars = "dcosagentvars.t" + dcosBaseFile = "dcosbase.t" + dcosParams = "dcosparams.t" + dcosMasterResources = "dcosmasterresources.t" + dcosMasterVars = "dcosmastervars.t" + iaasOutputs = "iaasoutputs.t" + kubernetesBaseFile = "kubernetesbase.t" + kubernetesAgentResourcesVMAS = "kubernetesagentresourcesvmas.t" + kubernetesAgentVars = "kubernetesagentvars.t" + kubernetesMasterResources = "kubernetesmasterresources.t" + kubernetesMasterVars = "kubernetesmastervars.t" + kubernetesParams = "kubernetesparams.t" + kubernetesWinAgentVars = "kuberneteswinagentresourcesvmas.t" + kubernetesKubeletService = "kuberneteskubelet.service" + masterOutputs = "masteroutputs.t" + masterParams = "masterparams.t" + swarmBaseFile = "swarmbase.t" + swarmAgentResourcesVMAS = "swarmagentresourcesvmas.t" + swarmAgentResourcesVMSS = "swarmagentresourcesvmss.t" + swarmAgentResourcesClassic = "swarmagentresourcesclassic.t" + swarmAgentVars = "swarmagentvars.t" + swarmMasterResources = "swarmmasterresources.t" + swarmMasterVars = "swarmmastervars.t" + swarmWinAgentResourcesVMAS = "swarmwinagentresourcesvmas.t" + swarmWinAgentResourcesVMSS = "swarmwinagentresourcesvmss.t" + windowsParams = "windowsparams.t" ) const ( @@ -129,7 +133,7 @@ var calicoAddonYamls15 = map[string]string{ } var commonTemplateFiles = []string{agentOutputs, agentParams, classicParams, masterOutputs, iaasOutputs, masterParams, windowsParams} -var dcosTemplateFiles = []string{dcosAgentResourcesVMAS, dcosAgentResourcesVMSS, dcosAgentVars, dcosBaseFile, dcosMasterResources, dcosMasterVars, dcosParams} +var dcosTemplateFiles = []string{dcosBaseFile, dcosAgentResourcesVMAS, dcosAgentResourcesVMSS, dcosAgentVars, dcosMasterResources, dcosMasterVars, dcosParams, dcosWindowsAgentResourcesVMAS, dcosWindowsAgentResourcesVMSS} var kubernetesTemplateFiles = []string{kubernetesBaseFile, kubernetesAgentResourcesVMAS, kubernetesAgentVars, kubernetesMasterResources, kubernetesMasterVars, kubernetesParams, kubernetesWinAgentVars} var swarmTemplateFiles = []string{swarmBaseFile, swarmAgentResourcesVMAS, swarmAgentVars, swarmAgentResourcesVMSS, swarmAgentResourcesClassic, swarmBaseFile, swarmMasterResources, swarmMasterVars, swarmWinAgentResourcesVMAS, swarmWinAgentResourcesVMSS} var swarmModeTemplateFiles = []string{swarmBaseFile, swarmAgentResourcesVMAS, swarmAgentVars, swarmAgentResourcesVMSS, swarmAgentResourcesClassic, swarmBaseFile, swarmMasterResources, swarmMasterVars, swarmWinAgentResourcesVMAS, swarmWinAgentResourcesVMSS} @@ -461,6 +465,9 @@ func getParameters(cs *api.ContainerService, isClassicMode bool) (paramsMap, err } } addValue(parametersMap, "dcosBootstrapURL", dcosBootstrapURL) + + dcosWindowsBootstrapURL := cloudSpecConfig.DCOSSpecConfig.DCOSWindowsBootstrapDownloadURL + addValue(parametersMap, "dcosWindowsBootstrapURL", dcosWindowsBootstrapURL) } // Agent parameters @@ -634,6 +641,10 @@ func (t *TemplateGenerator) getTemplateFuncMap(cs *api.ContainerService) templat return fmt.Sprintf("\"customData\": \"[base64(concat('#cloud-config\\n\\n', '%s'))]\",", str) }, + "GetDCOSWindowsAgentCustomData": func(profile *api.AgentPoolProfile) string { + str := getBase64CustomScript(dcosWindowsProvision) + return fmt.Sprintf("\"customData\": \"%s\"", str) + }, "GetMasterAllowedSizes": func() string { if t.ClassicMode { return GetClassicAllowedSizes() @@ -1217,7 +1228,15 @@ func getBase64CustomScriptFromStr(str string) string { func getDCOSAgentProvisionScript(profile *api.AgentPoolProfile) string { // add the provision script - bp, err1 := Asset(dcosProvision) + + var scriptname string + if profile.OSType == api.Windows { + scriptname = dcosWindowsProvision + } else { + scriptname = dcosProvision + } + + bp, err1 := Asset(scriptname) if err1 != nil { panic(fmt.Sprintf("BUG: %s", err1.Error())) } diff --git a/pkg/acsengine/json.go b/pkg/acsengine/json.go index cc2c615818..5a3e97e9d9 100644 --- a/pkg/acsengine/json.go +++ b/pkg/acsengine/json.go @@ -1,6 +1,7 @@ package acsengine import ( + // "fmt" "encoding/json" "strings" ) @@ -31,6 +32,8 @@ func PrettyPrintArmTemplate(template string) (string, error) { // PrettyPrintJSON will pretty print the json into func PrettyPrintJSON(content string) (string, error) { var data map[string]interface{} + // fmt.Printf("content = %s\n", content); + if err := json.Unmarshal([]byte(content), &data); err != nil { return "", err } diff --git a/pkg/acsengine/types.go b/pkg/acsengine/types.go index 8786c5b676..510bdd5eaa 100644 --- a/pkg/acsengine/types.go +++ b/pkg/acsengine/types.go @@ -33,9 +33,10 @@ type DockerSpecConfig struct { //DCOSSpecConfig is the configurations of DCOS type DCOSSpecConfig struct { - DCOS173BootstrapDownloadURL string - DCOS188BootstrapDownloadURL string - DCOS190BootstrapDownloadURL string + DCOS173BootstrapDownloadURL string + DCOS188BootstrapDownloadURL string + DCOS190BootstrapDownloadURL string + DCOSWindowsBootstrapDownloadURL string } //KubernetesSpecConfig is the kubernetes container images used. diff --git a/pkg/api/vlabs/validate.go b/pkg/api/vlabs/validate.go index 0edb25b3b7..cd13740675 100644 --- a/pkg/api/vlabs/validate.go +++ b/pkg/api/vlabs/validate.go @@ -253,6 +253,7 @@ func (a *Properties) Validate() error { return fmt.Errorf("WindowsProfile must not be empty since agent pool '%s' specifies windows", agentPoolProfile.Name) } switch a.OrchestratorProfile.OrchestratorType { + case DCOS: case Swarm: case SwarmMode: case Kubernetes: