Marc van Eijk 2018-04-17 19:12:21 +02:00
Родитель 35ca4073ea 5116d591a7
Коммит 8a831a49b0
27 изменённых файлов: 2618 добавлений и 380 удалений

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

@ -239,33 +239,13 @@
}
}
},
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(variables('vmName'),'/LinuxVMAccessExtension')]",
"apiVersion": "2016-03-30",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'),'/extensions/LinuxCustomScriptExtension')]"
],
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"type": "VMAccessForLinux",
"typeHandlerVersion": "1.3",
"autoUpgradeMinorVersion": "true",
"settings": { },
"protectedSettings": {
"username": "[parameters('adminUsername')]",
"password": "[parameters('adminPassword')]"
}
}
},
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(variables('vmName'),'/installospatching')]",
"apiVersion": "2016-03-30",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'),'/extensions/LinuxVMAccessExtension')]"
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'),'/extensions/LinuxCustomScriptExtension')]"
],
"properties": {
"publisher": "Microsoft.OSTCExtensions",

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

@ -0,0 +1,152 @@
# Deploy Multinode DELLEMC ECS Elastic Storage S3 Community Edition in an AzureStack Availabilty Set
<a href="https://portal.local.azurestack.external/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazurestack-quickstart-templates%2Fmaster%2F301-availability-set-elastic-storage-ecs%2Fazuredeploy.json" target="_blank">
<img src="images/deploytoasdk.png"/>
</a>
<a href="https://adminportal.local.azurestack.external/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazurestack-quickstart-templates%2Fmaster%2F301-availability-set-elastic-storage-ecs%2Fazuredeploy.json" target="_blank">
<img src="images/deploytoasdkadmin.png"/>
</a>
<a href="http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazurestack-quickstart-templates%2Fmaster%2F301-availability-set-elastic-storage-ecs%2Fazuredeploy.json" target="_blank">
<img src="https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/visualizebutton.png"/>
</a>
## Prerequisites
The required VM Types need to have at least 4vCPU and 16GB memory.
With the current AzureStrack VM Sizes, this would be 28G Memory per machine, so make sure you ASDK has enough Memory...
To depoloy to an ASDK Admin Tenant, just click on "ASDK Admin Tenant"
To depoloy to an ASDK User Tenant, just click on "Deploy to ASDK"
To deploy this template using the scripts from the root of this repo: (change the folder name below to match the folder name for this sample)
```PowerShell
.\Deploy-AzureResourceGroup.ps1 -ResourceGroupLocation 'local' -ArtifactsStagingDirectory '301-availability-set-elastic-storage-ecs'
```
```bash
azure-group-deploy.sh -a '301-availability-set-elastic-storage-ecs' -l local
```
This template deploys a **multinode dellemc ecs community edition**. The **ecs community edition** is a **elastic cloud storage solution providing object storage (sr, atoms, cas)**
`Tags: arm, centos, ecs, ecs community edition`
## Solution overview and deployed resources
This is an overview of the solution
The following resources are deployed as part of the solution
#### Storage Accounts
Storage ressources provided per vm
+ **vm storage account**: holds the os copy from image (CentOS) and up to 8 data disks per node
+ **diagnostic storage account**: storage for vm diagnostics
#### Supported OSimage Publisher / SKU /Versions
the following images are supported:
+ **CentOS** this is based on the RogueWave Centos Image using Publicher OpenLogic, SKU CentOS, Version 7.4
+ **CentOS-7** this is based on the original Centos CloudImage using Publisher CentOS, SKU Centos-7, Version Centos-7.4
The Centos-7 must be loaded manually or using [Azurestack-Kickstart](https://github.com/bottkars/Azurestack-Kickstart)
#### networkSecurityGroups
Firewall rules for Network
#### networkLoadbalancer
Public loadbalancer for ECS Nodes
+ **lbRulesA**: Load Balancing rules for ECS Ports 111,2049,9020.9021,9022,9023,9024,9025,10000
+ **inboundNatRules**: ports 220x are forwarded to port 22 on NodeX
#### OSTCExtensions
Custom Script Extensions for Linux
The deployment utilizes the custom script extension
+ **configurenode**: Used on the Node to configure installer Prerequirements, used on nodes 2-N
+ **install_ecs**: the ecs installer, run´s on node 1
Password Change extension
the Deployment utilizes the Password change extension for linux
+ **resetpassword** to overcome some issues where cloudinit does not accept password
the default password is Subscription#**id**, example Subscription#8c21cadc-9e41-459e-bf4b-9b5aa2fad938
## Deployment steps
### deploy to Azure from this site
You can click the "deploy to Azure" button at the beginning of this document or follow the instructions for command line deployment using the scripts in the root of this repo.
the parameters section will be the same
### from new azure template from azure portal
From the azure Portal, click new and type in template.
select the new custom template dialog
![new deploy](images/template_new.png "new template from azure portal")
once open, click on the upload and load the azuredeploy.json
![new deploy](images/template_load.png "new template from azure portal")
fill in all parameters to you need and make sure the dns prefix is not used
![new deploy](images/template_edit.png "new template from azure portal")
### quickstart template
Also, you can use Visual Studio to deploy the template. If you have installed the ressourcegroup extensions creater a new deployment and select '301-availability-set-elastic-storage-ecs' from the quickstart templates
### visual studio example
![new deploy](images/new_rg.png "Create new deployment from Visual Studio")
#### parameters of resource group
![deploy](images/rg_parameter.png "parameters for resource group")
The ressource group deployment will take between 10 and 15 Minutes, depneding on VM Types
![rg](images/rg_done.png "parameters for resource group")
once the resource group deployment has finished, the ecs installer will be started from
[ecs.sh](scripts/ecs.sh)
#### monitor installation
ssh into the first node (use the external dns name ), port 2201
```bash
sudo su
tail -f /root/install.log
```
![log](images/log.png "installation logs")
the system will do a reboot after package installation.
the reboot(s) will be controlled by a systemd service [ecs-installer.service](scripts/ecs-installer.service)
after the reboot, the ECS ansible installer starts withn step1 and step2
the progress is also logged
```bash
sudo su
tail -f /root/install.log
```
![log](images/ansible.png "ansible logger")
#### Connect
once the installation has finished step2, you can connect to port 443 of your externa DNS from a webbrowser.
the initial user / password is root:ChangeMe
![log](images/dashboard.png "ECS Dashboard")
#### Management
For more information, see
[DellEMC ECS Community Edition readthedocs](http://ecsce.readthedocs.io/en/latest/installation/ECS-Installation.html)
and
[DellEMC ECS Documentation](https://community.emc.com/docs/DOC-56978)
## Notes
future improvement´s
+ feedback of installation logs to arm
+ ubntu based install ( pending verification )
+ singlenode from same deployment
+ nested template for loadbalancer as copy set

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

@ -0,0 +1,732 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "The name of the Administrator of the new VMs"
},
"defaultValue": "ecsadmin"
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "The password for the Administrator account of the new VMs. Default value is Subscription#<id>"
},
"defaultValue": "[concat('Subscription#',substring(resourcegroup().id,15,36))]"
},
"numberOfInstances": {
"type": "int",
"defaultValue": 3,
"allowedValues": [
2,
3,
4,
5,
6,
7,
8
],
"metadata": {
"description": "Number of VMs to deploy, limit 5 since this sample is using a single storage account"
}
},
"dataDiskCount": {
"type": "int",
"defaultValue": 3,
"allowedValues": [
1,
2,
3,
4,
5,
6,
7,
8
],
"metadata": {
"description": "NUmber of ECS Data Disks"
}
},
"dataDiskSize": {
"type": "int",
"defaultValue": 150,
"minValue": 150,
"maxValue": 1023,
"metadata": {
"description": "Size of the Data Disk in GB"
}
},
"vmNamePrefix": {
"type": "string",
"defaultValue": "ecs",
"metadata": {
"description": "VM name prefix"
}
},
"vmSize": {
"allowedValues": [
"Standard_A6",
"Standard_D4",
"Standard_D12",
"Standard_D4_v2",
"Standard_D12_v2",
"Standard_DS4",
"Standard_DS12",
"Standard_DS4_v2",
"Standard_DS12_v2"
],
"defaultValue": "Standard_D4",
"metadata": {
"description": "This is the size of your ECS Nodes. Minimum is A6/D4"
},
"type": "string"
},
"dnsPrefix": {
"type": "string",
"defaultValue": "[concat('ecs', uniquestring(resourceGroup().id))]",
"metadata": {
"description": "dns name prefix. this is the external dns prefix to reach your ECS via the loadbalancer"
}
},
"osImagePublisher": {
"type": "string",
"defaultValue": "OpenLogic",
"allowedValues": [
"Centos",
"OpenLogic"
],
"metadata": {
"description": "The Image Publisher, use Openlogic for default Marketplace"
}
},
"osImageOffer": {
"type": "string",
"defaultValue": "CentOS",
"allowedValues": [
"Centos-7",
"CentOS"
],
"metadata": {
"description": "The Image Offer, use centos for default Marketplace"
}
},
"osImageSKU": {
"type": "string",
"defaultValue": "7.4",
"allowedValues": [
"Centos-7.4",
"7.4"
],
"metadata": {
"description": "The Linux version for the VM. Use 7.4 for default Marketplace"
}
},
"_artifactsLocation": {
"type": "string",
"metadata": {
"description": "The base URI where artifacts required by this template are located. When the template is deployed using the accompanying scripts, a private location in the subscription will be used and this value will be automatically generated."
},
"defaultValue": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-templates/master/301-availability-set-elastic-storage-ecs"
},
"_artifactsLocationSasToken": {
"type": "securestring",
"metadata": {
"description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated."
},
"defaultValue": ""
}
},
"variables": {
"availabilitySetName": "[toLower(concat('ECSaSet-', resourceGroup().name))]",
"storageAccountType": "Standard_LRS",
"vmSize": "[parameters('vmSize')]",
"dnsPrefix": "[parameters('dnsPrefix')]",
"osImageVersion": "latest",
"addressPrefix": "10.0.0.0/16",
"virtualNetworkName": "[tolower(concat('vNet-',resourceGroup().name))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]",
"NICPrefix": "vnic-",
"subnetPrefix": "10.0.0.0/24",
"subnetName": "vmstaticsubnet",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"storageName": "[concat('sa', uniquestring(resourceGroup().id))]",
"loadBalancerProbeName": "443Probe",
"publicLBName": "[tolower(concat('external-lb-', resourceGroup().name))]",
"publiclbID": "[resourceId('Microsoft.Network/loadBalancers',variables('publicLBName'))]",
"lbFE": "[tolower(concat('external-lb-fe-',resourceGroup().name))]",
"publiclbFEConfigID": "[concat(variables('publiclbID'),'/frontendIPConfigurations/',variables('lbFE'))]",
"publicIPAddressName": "[tolower(concat('public-ip',resourceGroup().name))]",
"nsgName": "[tolower(concat('vmnsg',resourceGroup().name))]",
"nsgID": "[resourceId('Microsoft.Network/networkSecurityGroups',variables('nsgName'))]",
"vmContainerName": "vhds",
"diagnosticsStorageAccountName": "[concat('diag', uniquestring(resourceGroup().id))]",
"diagnosticsStorageAccountType": "Standard_LRS"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageName')]",
"apiVersion": "2016-01-01",
"location": "[resourceGroup().location]",
"properties": {
"accountType": "[variables('storageAccountType')]"
},
"dependsOn": [
"[variables('publiclbName')]"
]
},
{
"name": "[variables('diagnosticsStorageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2016-01-01",
"location": "[resourceGroup().location]",
"properties": {
"accountType": "[variables('diagnosticsStorageAccountType')]"
}
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('nsgName')]",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"properties": {
"securityRules": [
{
"name": "rule1",
"properties": {
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 101,
"direction": "Inbound"
}
}
]
}
},
{
"type": "Microsoft.Compute/availabilitySets",
"name": "[variables('availabilitySetName')]",
"apiVersion": "2016-03-30",
"location": "[resourceGroup().location]",
"properties": {
"platformFaultDomainCount": 1,
"platformUpdateDomainCount": 1
}
},
{
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[variables('dnsPrefix')]"
}
},
"dependsOn": [
"[variables('vnetID')]"
]
},
{
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]",
"networkSecurityGroup": {
"id": "[variables('nsgID')]"
}
}
}
]
},
"dependsOn": [
"[variables('nsgID')]"
]
},
{
"apiVersion": "2015-06-15",
"name": "[variables('publiclbName')]",
"type": "Microsoft.Network/loadBalancers",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('vnetID')]",
"[variables('publicIPAddressName')]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "[variables('lbFE')]",
"properties": {
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
}
}
}
],
"backendAddressPools": [
{
"name": "LoadBalancerBackend"
}
],
"loadBalancingRules": [
{
"name": "443_HTTPS_LBRule",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 443,
"backendPort": 443,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "9020_S3_HTTP",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 9020,
"backendPort": 9020,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "9021_S3_HTTPS",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 9021,
"backendPort": 9021,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "9022_ATMOS_HTTP",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 9022,
"backendPort": 9022,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "9023_ATMOS_HTTPS",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 9023,
"backendPort": 9023,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "9024_Swift_HTTP",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 9024,
"backendPort": 9024,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "9025_Swift_HTTPS",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 9025,
"backendPort": 9025,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "4443_Management_API",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 4443,
"backendPort": 4443,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "2049_mountd",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 2049,
"backendPort": 2049,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "111_portmap",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 111,
"backendPort": 111,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
},
{
"name": "10000_lockd",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/frontendIPConfigurations/', variables('lbFE'))]"
},
"backendAddressPool": {
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
},
"protocol": "Tcp",
"frontendPort": 10000,
"backendPort": 10000,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('publicLBName')), '/probes/', variables('loadBalancerProbeName'))]"
}
}
}
],
"probes": [
{
"name": "[variables('loadBalancerProbeName')]",
"properties": {
"protocol": "Tcp",
"port": 443,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
]
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/loadBalancers/inboundNatRules",
"name": "[concat(variables('publicLBName'), '/ssh-VM', copyIndex(1))]",
"location": "[resourceGroup().location]",
"copy": {
"name": "lbNatLoop",
"count": "[parameters('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/loadBalancers/', variables('publiclbName'))]"
],
"properties": {
"frontendIPConfiguration": {
"id": "[variables('publiclbFEConfigID')]"
},
"protocol": "tcp",
"frontendPort": "[copyIndex(2201)]",
"backendPort": 22,
"enableFloatingIP": false
}
},
{
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(variables('NICPrefix'), parameters('vmNamePrefix'), copyIndex(1))]",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"copy": {
"name": "nicLoop",
"count": "[parameters('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
"[concat('Microsoft.Network/loadBalancers/', variables('publicLBName'))]",
"[concat('Microsoft.Network/loadBalancers/', variables('publicLBName'), '/inboundNatRules/', 'ssh-VM', copyIndex(1))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Static",
"privateIPAddress": "[concat('10.0.0.',copyIndex(4))]",
"subnet": {
"id": "[variables('subnetRef')]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[concat(variables('publiclbID'), '/backendAddressPools/LoadBalancerBackend')]"
}
],
"loadBalancerInboundNatRules": [
{
"id": "[concat(variables('publiclbID'), '/inboundNatRules/ssh-VM', copyIndex(1))]"
}
]
}
}
]
}
},
{
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('vmNamePrefix'), copyIndex(1))]",
"apiVersion": "2015-06-15",
"location": "[resourceGroup().location]",
"copy": {
"name": "virtualMachineLoop",
"count": "[parameters('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/',variables('storageName'))]",
"[resourceId('Microsoft.Network/networkInterfaces', concat(variables('NICPrefix'), parameters('vmNamePrefix'), copyIndex(1)))]",
"[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]"
],
"properties": {
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets',variables('availabilitySetName'))]"
},
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[concat(parameters('vmNamePrefix'), copyIndex(1))]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[parameters('osImagePublisher')]",
"offer": "[parameters('osImageOffer')]",
"sku": "[parameters('osImageSKU')]",
"version": "[variables('osImageVersion')]"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob, variables('vmContainerName'),'/', parameters('vmNamePrefix'), copyIndex(1),'-osdisk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
},
"copy": [
{
"name": "dataDisks",
"count": "[parameters('dataDiskCount')]",
"input": {
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob, variables('vmContainerName'),'/', parameters('vmNamePrefix'), copyIndex(1),'-data-', copyIndex('dataDisks'), '.vhd')]"
},
"name": "[concat(parameters('vmNamePrefix'), copyIndex(1),'-data-', copyIndex('dataDisks'), '.vhd')]",
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty",
"diskSizeGB": "[parameters('dataDiskSize')]"
}
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('NICPrefix'), parameters('vmNamePrefix'), copyIndex(1)))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": "true",
"storageUri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob)]"
}
}
}
},
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"apiVersion": "2016-03-30",
"copy": {
"count": "[parameters('numberOfInstances')]",
"mode": "Parallel",
"name": "vmLoopNode"
},
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNamePrefix'), parameters('numberOfInstances'))]"
],
"location": "[resourceGroup().location]",
"name": "[concat(parameters('VMNamePrefix'), copyIndex(1), '/resetpassword')]",
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"type": "VMAccessForLinux",
"typeHandlerVersion": "1.4",
"autoUpgradeMinorVersion": true,
"settings": {},
"protectedSettings": {
"username": "[parameters('adminUsername')]",
"password": "[parameters('adminPassword')]",
"reset_ssh": true
}
}
},
{
"apiVersion": "2016-03-30",
"copy": {
"count": "[sub(parameters('numberOfInstances'),1)]",
"mode": "Parallel",
"name": "vmLoopNode"
},
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNamePrefix'), copyIndex(2),'/extensions/resetpassword')]"
],
"location": "[resourceGroup().location]",
"name": "[concat(parameters('VMNamePrefix'), copyIndex(2), '/configurenode')]",
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"settings": {
"commandToExecute": "./ecs_pre.sh",
"fileUris": [ "[concat(parameters('_artifactsLocation'),'/scripts/ecs_pre.sh')]" ]
},
"type": "CustomScriptForLinux",
"typeHandlerVersion": "1.4",
"autoUpgradeMinorVersion": true
},
"type": "Microsoft.Compute/virtualMachines/extensions"
},
{
"apiVersion": "2016-03-30",
"location": "[resourceGroup().location]",
"name": "[concat(parameters('VMNamePrefix'),'1','/installecs')]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNamePrefix'),'1','/extensions/resetpassword')]"
],
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"settings": {
"fileUris": [
"[concat(parameters('_artifactsLocation'),'/scripts/ecs_pre.sh')]",
"[concat(parameters('_artifactsLocation'),'/scripts/deploy.yml')]",
"[concat(parameters('_artifactsLocation'),'/scripts/ecs.sh')]",
"[concat(parameters('_artifactsLocation'),'/scripts/ecs-installer.service')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('bash ecs.sh --DISKNUM ',parameters('dataDiskCount'),' --NODENUM ',parameters('numberOfInstances'),' --NODEPREFIX ',parameters('VMNamePrefix'),' --ECSUSER ',parameters('adminUsername'),' --ECSPASSWORD ',parameters('adminPassword'))]"
},
"type": "CustomScriptForLinux",
"typeHandlerVersion": "1.4",
"autoUpgradeMinorVersion": true
},
"type": "Microsoft.Compute/virtualMachines/extensions"
}
],
"outputs": {
"fileruris": {
"value": "reference('fileUris')",
"type": "string"
}
}
}

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

@ -0,0 +1,15 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"value": "GEN-UNIQUE"
},
"adminPassword": {
"value": "GEN-PASSWORD"
},
"dnsLabelPrefix": {
"value": "GEN-UNIQUE"
}
}
}

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

@ -0,0 +1,118 @@
#Requires -Version 3.0
Param(
[string] [Parameter(Mandatory=$true)] $ResourceGroupLocation,
[string] $ResourceGroupName = 'ecs_compatible',
[switch] $UploadArtifacts,
[string] $StorageAccountName,
[string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts',
[string] $TemplateFile = 'azuredeploy.json',
[string] $TemplateParametersFile = 'azuredeploy.parameters.json',
[string] $ArtifactStagingDirectory = '.',
[string] $DSCSourceFolder = 'DSC',
[switch] $ValidateOnly
)
try {
[Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0')
} catch { }
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 3
function Format-ValidationOutput {
param ($ValidationOutput, [int] $Depth = 0)
Set-StrictMode -Off
return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) })
}
$OptionalParameters = New-Object -TypeName Hashtable
$TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile))
$TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile))
if ($UploadArtifacts) {
# Convert relative paths to absolute paths if needed
$ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory))
$DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder))
# Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present
$JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json
if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) {
$JsonParameters = $JsonParameters.parameters
}
$ArtifactsLocationName = '_artifactsLocation'
$ArtifactsLocationSasTokenName = '_artifactsLocationSasToken'
$OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore
$OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore
# Create DSC configuration archive
if (Test-Path $DSCSourceFolder) {
$DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName})
foreach ($DSCSourceFilePath in $DSCSourceFilePaths) {
$DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip'
Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose
}
}
# Create a storage account name if none was provided
if ($StorageAccountName -eq '') {
$StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19)
}
$StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName})
# Create the storage account if it doesn't already exist
if ($StorageAccount -eq $null) {
$StorageResourceGroupName = 'ARM_Deploy_Staging'
New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force
$StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation"
}
# Generate the value for artifacts location if it is not provided in the parameter file
if ($OptionalParameters[$ArtifactsLocationName] -eq $null) {
$OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName
}
# Copy files from the local storage staging location to the storage account container
New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1
$ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName}
foreach ($SourcePath in $ArtifactFilePaths) {
Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) `
-Container $StorageContainerName -Context $StorageAccount.Context -Force
}
# Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file
if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) {
$OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force `
(New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4))
}
}
# Create or update the resource group using the specified template file and template parameters file
New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force
if ($ValidateOnly) {
$ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName `
-TemplateFile $TemplateFile `
-TemplateParameterFile $TemplateParametersFile `
@OptionalParameters)
if ($ErrorMessages) {
Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.'
}
else {
Write-Output '', 'Template is valid.'
}
}
else {
New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) `
-ResourceGroupName $ResourceGroupName `
-TemplateFile $TemplateFile `
-TemplateParameterFile $TemplateParametersFile `
@OptionalParameters `
-Force -Verbose `
-ErrorVariable ErrorMessages
if ($ErrorMessages) {
Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") })
}
}

Двоичные данные
301-availability-set-elastic-storage-ecs/images/ansible.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 125 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/dashboard.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 317 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/deploytoasdk.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.9 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/log.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 125 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/new_rg.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 33 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/rg_done.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 308 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/rg_parameter.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 40 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/template_edit.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 86 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/template_load.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 44 KiB

Двоичные данные
301-availability-set-elastic-storage-ecs/images/template_new.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.0 KiB

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

@ -0,0 +1,7 @@
{
"itemDisplayName": "301-availability-set-elastic-storage-ecs",
"description": "deploys a multinote elastic cloud storage into an availability set",
"summary": "this template automates the deployment of dellemc ecs elastic cloud storage community edition",
"githubUsername": "bottkars",
"dateUpdated": "2018-03-07"
}

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

@ -0,0 +1,205 @@
# deploy.yml reference implementation v2.6.0
# [Optional]
# By changing the license_accepted boolean value to "true" you are
# declaring your agreement to the terms of the license agreement
# contained in the license.txt file included with this software
# distribution.
licensing:
license_accepted: true
autonames:
custom: [myhosts]
# - ecs04
# - ecs05
# - ecs06
# [Required]
# Deployment facts reference
facts:
# [Required]
# Node IP or resolvable hostname from which installations will be launched
# The only supported configuration is to install from the same node as the
# bootstrap.sh script is run.
# NOTE: if the install node is to be migrated into an island environment,
# the hostname or IP address listed here should be the one in the
# island environment.
install_node: 10.0.0.4
# [Required]
# IPs of machines that will be whitelisted in the firewall and allowed
# to access management ports of all nodes. If this is set to the
# wildcard (0.0.0.0/0) then anyone can access management ports.
management_clients:
- 0.0.0.0/0
# [Required]
# These credentials must be the same across all nodes. Ansible uses these credentials to
# gain initial access to each node in the deployment and set up ssh public key authentication.
# If these are not correct, the deployment will fail.
ssh_defaults:
# [Required]
# Username to use when logging in to nodes
ssh_username: ECSUSER
# [Required]
# Password to use with SSH login
# *** Set to same value as ssh_username to enable SSH public key authentication ***
ssh_password: ECSPASSWORD
# [Required when enabling SSH public key authentication]
# Password to give to sudo when gaining root access.
ansible_become_pass: ECSPASSWORD
# [Required]
# Select the type of crypto to use when dealing with ssh public key
# authentication. Valid values here are:
# - "rsa" (Default)
# - "ed25519"
ssh_crypto: rsa
# [Required]
# Environment configuration for this deployment.
node_defaults:
dns_domain: local
dns_servers:
- 168.63.129.16
ntp_servers:
- 88.198.197.205
#
# [Optional]
# VFS path to source of randomness
# Defaults to /dev/urandom for speed considerations. If you prefer /dev/random, put that here.
# If you have a /dev/srandom implementation or special entropy hardware, you may use that too
# so long as it implements a /dev/random type device.
entropy_source: /dev/urandom
#
# [Optional]
# Picklist for node names.
# Available options:
# - "moons" (ECS CE default)
# - "cities" (ECS SKU-flavored)
# - "custom" (uncomment and use the top-level autonames block to define these)
autonaming: custom
#
# [Optional]
# If your ECS comes with differing default credentials, you can specify those here
# ecs_root_user: root
# ecs_root_pass: ChangeMe
# [Optional]
# Storage pool defaults. Configure to your liking.
# All block devices that will be consumed by ECS on ALL nodes must be listed under the
# ecs_block_devices option. This can be overridden by the storage pool configuration.
# At least ONE (1) block device is REQUIRED for a successful install. More is better.
storage_pool_defaults:
is_cold_storage_enabled: false
is_protected: false
description: Default storage pool description
ecs_block_devices: [mydisks]
# [Required]
# Storage pool layout. You MUST have at least ONE (1) storage pool for a successful install.
storage_pools:
- name: sp1
members: [mymembers]
options:
is_protected: false
is_cold_storage_enabled: false
description: My First SP
ecs_block_devices: [mydisks]
# [Optional]
# VDC defaults. Configure to your liking.
virtual_data_center_defaults:
description: Default virtual data center description
# [Required]
# Virtual data center layout. You MUST have at least ONE (1) VDC for a successful install.
# Multi-VDC deployments are not yet implemented
virtual_data_centers:
- name: vdc1
members:
- sp1
options:
description: AzureStack VDC
# [Optional]
# Replication group defaults. Configure to your liking.
replication_group_defaults:
description: Default replication group description
enable_rebalancing: true
allow_all_namespaces: true
is_full_rep: false
# [Optional, required for namespaces]
# Replication group layout. You MUST have at least ONE (1) RG to provision namespaces.
replication_groups:
- name: rg1
members:
- vdc1
options:
description: AzureStack RG
enable_rebalancing: true
allow_all_namespaces: true
is_full_rep: false
# [Optional]
# Management User defaults
management_user_defaults:
is_system_admin: false
is_system_monitor: false
# [Optional]
# Management Users
management_users:
- username: admin1
password: ChangeMe
options:
is_system_admin: true
- username: monitor1
password: ChangeMe
options:
is_system_monitor: true
# [Optional]
# Namespace defaults
namespace_defaults:
is_stale_allowed: false
is_compliance_enabled: false
# [Optional]
# Namespace layout
namespaces:
- name: ns1
replication_group: rg1
administrators:
- root
options:
is_stale_allowed: false
is_compliance_enabled: false
# [Optional]
# Object User defaults
object_user_defaults:
# Comma-separated list of Swift authorization groups
swift_groups_list:
- users
# Lifetime of S3 secret key in minutes
s3_expiry_time: 2592000
# [Optional]
# Object Users
object_users:
- username: object_admin1
namespace: ns1
options:
swift_password: ChangeMe
swift_groups_list:
- admin
- users
s3_secret_key: ChangeMeChangeMeChangeMeChangeMeChangeMe
s3_expiry_time: 2592000
- username: object_user1
namespace: ns1
options:
swift_password: ChangeMe
s3_secret_key: ChangeMeChangeMeChangeMeChangeMeChangeMe

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

@ -0,0 +1,10 @@
[Unit]
Description=EMC ECS Installer start
After=docker.service
[Service]
Type=simple
Restart=no
ExecStart=/root/ecs.sh
ExecStop=
[Install]
WantedBy=default.target

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

@ -0,0 +1,141 @@
#!/bin/bash
edit_template(){
# this creates an ansible list for disks in forma ['/dev/sdc',...]
chars=( {c..z} )
n=$1
for ((i=0; i<n; i++))
do
disks[i]="\/dev\/sd${chars[i]}"
done
disklist="$(echo "'${disks[*]}'" | tr ' ' ,)"
disklist=${disklist//","/"','"}
echo "start customizing ECS at $(date)" |& tee -a /root/install.log
echo "replacing mydisks with disklist $disklist" >> /root/install.log
sed -i -e 's/mydisks/'"$disklist"'/g' /root/ECS-CommunityEdition/deploy.yml
# this creates an ansible list for nodes in formar ['ecs1',...]
n=$2
for ((i=1; i<=n; i++))
do
hosts[i]=$3$i
done
hostlist="$(echo "'${hosts[*]}'" | tr ' ' ,)"
hostlist=${hostlist//","/"','"}
echo "replacing myhosts with hostlist $hostlist" >> /root/install.log
sed -i -e 's/myhosts/'"$hostlist"'/g' /root/ECS-CommunityEdition/deploy.yml
# this creates an ansible list for members in format ['10.0.0',...]
n=$2
for ((i=4; i<=n+3; i++))
do
members[i]=10.0.0.$i
done
memberlist="$(echo "'${members[*]}'" | tr ' ' ,)"
memberlist=${memberlist//","/"','"}
echo "replacing mymembers with memberlist $memberlist" >> /root/install.log
sed -i -e 's/mymembers/'"$memberlist"'/g' /root/ECS-CommunityEdition/deploy.yml
echo "replacing ECSUSER with $4" >> /root/install.log
sed -i -e 's/ECSUSER/'"$4"'/g' /root/ECS-CommunityEdition/deploy.yml
echo "replacing ECSPASSWORD with $5" >> /root/install.log
sed -i -e 's/ECSPASSWORD/'"$5"'/g' /root/ECS-CommunityEdition/deploy.yml
}
before_reboot(){
yum install git firewalld -y
# for openlogic
# update, we handle this with reset password in extension
# sed -i -e 's/#GatewayPorts no/GatewayPorts yes/g' /etc/ssh/sshd_config
# sed -i -e 's/#PasswordAuthentication yes/PasswordAuthentication yes/g' /etc/ssh/sshd_config
systemctl disable rpcbind
cp ecs.sh /root/
chmod +X /root/ecs.sh
chmod 755 /root/ecs.sh
cp ecs-installer.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable ecs-installer.service
git clone https://github.com/emcecs/ecs-communityedition /root/ECS-CommunityEdition
cp deploy.yml /root/ECS-CommunityEdition
edit_template $1 $2 $3 $4 $5
echo "$1 $2 $3 $4 $5" >> /root/parameters.txt
myreboot &
echo $?
}
myreboot () {
sleep 60
shutdown -r now
}
after_bootstrap(){
cd /root/ECS-CommunityEdition
/usr/bin/step1 |& tee -a /root/install.log
/usr/bin/step2 |& tee -a /root/install.log
echo "finished customizing at $(date)" |& tee -a /root/install.log
}
after_waagent(){
cd /root/ECS-CommunityEdition
./bootstrap.sh -c ./deploy.yml -y |& tee -a /root/install.log
}
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-d|--DISKNUM)
DISKNUM="$2"
shift # past argument
shift # past value
;;
-n|--NODENUM)
NODENUM="$2"
shift # past argument
shift # past value
;;
-u|--ECSUSER)
ECSUSER="$2"
shift # past argument
shift # past value
;;
-s|--ECSPASSWORD)
ECSPASSWORD="$2"
shift # past argument
shift # past value
;;
-p|--NODEPREFIX)
NODEPREFIX="$2"
shift # past argument
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
echo "DISKNUM = ${DISKNUM}" >> /root/install.log
echo "NODENUM = ${NODENUM}" >> /root/install.log
echo "NODEPREFIX = ${NODEPREFIX}" >> /root/install.log
echo "ECSUSER = ${ECSUSER}" >> /root/install.log
echo "ECSPASSWORD = ${ECSPASSWORD}" >> /root/install.log
if [[ -n $1 ]]; then
echo "Last line of file specified as non-opt/last argument:"
tail -1 "$1"
fi
if [ -f /root/rebooting-for-bootstrap ]; then
after_bootstrap
rm /root/rebooting-for-bootstrap
systemctl disable ecs-installer.service
elif [ -f /root/rebooting-for-waagent ]; then
rm /root/rebooting-for-waagent
touch /root/rebooting-for-bootstrap
after_waagent
else
touch /root/rebooting-for-waagent
echo "$DISKNUM $NODENUM $NODEPREFIX $ECSUSER $ECSPASSWORD" >> /root/parameters.txt
before_reboot $DISKNUM $NODENUM $NODEPREFIX $ECSUSER $ECSPASSWORD
fi

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

@ -0,0 +1,15 @@
#!/bin/bash
# yum update -y &>> /root/install.log
myreboot () {
sleep 60
shutdown -r now
}
yum install firewalld libselinux-python docker ntp pigz python-docker-py -y
# for openlogic
# update, we handle this with reset password in extension
# sed -i -e 's/#GatewayPorts no/GatewayPorts yes/g' /etc/ssh/sshd_config
# sed -i -e 's/#PasswordAuthentication yes/PasswordAuthentication yes/g' /etc/ssh/sshd_config
yum remove *nfs* -y
systemctl disable rpcbind
myreboot &
echo $?

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

@ -0,0 +1,208 @@
#
# Copyright="?Microsoft Corporation. All rights reserved."
#
Configuration ConfigureVMBootAll
{
param (
[Parameter(Mandatory)]
[PSCredential]$AzureAccountCreds,
[Parameter(Mandatory)]
[string]$TenantId,
[Parameter(Mandatory)]
[string]$Location,
[Parameter(Mandatory)]
[string]$VMName,
[Parameter(Mandatory)]
[int32]$VMCount,
[Parameter(Mandatory)]
[PSCredential]$VMAdminCreds,
[Parameter(Mandatory)]
[string]$AzureStorageAccount,
[Parameter(Mandatory)]
[string]$AzureStorageAccessKey,
[Parameter(Mandatory)]
[string]$AzureStorageEndpoint,
[Parameter(Mandatory)]
[string]$AzureSubscription
)
# Turn off private firewall
netsh advfirewall set privateprofile state off
# Get full path and name of the script being run
$PSPath = $PSCommandPath
# Local file storage location
$localPath = "$env:SystemDrive"
# Log file
$logFileName = "VMBootDSC.log"
$logFilePath = "$localPath\$logFileName"
$AzureAccountUsername = $AzureAccountCreds.UserName
$AzureAccountPasswordBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($AzureAccountCreds.Password)
$AzureAccountPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($AzureAccountPasswordBSTR)
$VMAdminUserName = $VMAdminCreds.UserName
$VMAdminPasswordBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($VMAdminCreds.Password)
$VMAdminPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($VMAdminPasswordBSTR)
# DSC Script Resource - VM Bootstorm
Script VMBAll
{
TestScript = { (Get-ScheduledTask -TaskName "VMBootAll" -ErrorAction SilentlyContinue) -ne $null }
GetScript = { return @{"TaskName" = "VMBootAll"} }
SetScript = {
function IsAzureStack
{
param
(
[Parameter(Mandatory)]
$Location
)
if($Location -eq "AzureCloud" -or $Location -eq "AzureChinaCloud" -or $Location -eq "AzureUSGovernment" -or $Location -eq "AzureGermanCloud") {
return $false
}
return $true
}
# Azure uses AzureAdApplicationId and AzureAdApplicationPassword values as AzureUserName and AzurePassword parameters respectively
# AzureStack uses tenant UserName and Password values as AzureUserName and AzurePassword parameters respectively
$azureUsername = $using:AzureAccountUsername
$azurePassword = $using:AzureAccountPassword
$tenant = $using:TenantId
$location = $using:Location
$vmName = $using:VMName
$vmCount = $using:VMCount
# Scheduled task execution credentials without any logged-in user
$vmAdminUserName = $using:VMAdminUserName
$vmAdminPassword = $using:VMAdminPassword
$storageAccount = $using:AzureStorageAccount
$storageKey = $using:AzureStorageAccessKey
$storageEndpoint = $using:AzureStorageEndpoint
$subscription = $using:AzureSubscription
$storageEndpoint = $storageEndpoint.ToLower()
# Prepare storage context to upload results to Azure storage table
if($storageEndpoint.Contains("blob")) {
$storageEndpoint = $storageEndpoint.Substring($storageEndpoint.LastIndexOf("blob") + "blob".Length + 1)
$storageEndpoint = $storageEndpoint.replace("/", "")
# Remove port number from storage endpoint e.g. http://saiostorm.blob.azurestack.local:3456/
if($storageEndpoint.Contains(":")) {
$storageEndpoint = $storageEndpoint.Substring(0, $storageEndpoint.LastIndexOf(":"))
}
}
"Storage endpoint given: $using:AzureStorageEndpoint Storage endpoint passed to script: $storageEndpoint" | Tee-Object -FilePath $logFilePath -Append
$psPath = $using:PSPath
$psScriptDir = Split-Path -Parent -Path $psPath
$psScriptName = "VMBootAllScript.ps1"
$psScriptPath = "$psScriptDir\$psScriptName"
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument "& $psScriptPath -azureUserName $azureUsername -azurePassword $azurePassword -tenant $tenant -location $location -vmName $vmName -vmCount $vmCount -azureStorageAccount $storageAccount -azureStorageAccessKey $storageKey -azureStorageEndpoint $storageEndpoint -AzureSubscription $subscription -Verbose" -ErrorAction Ignore
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(5) -RepetitionInterval (New-TimeSpan -Minutes 10) -RepetitionDuration (New-TimeSpan -Minutes 30) -ErrorAction Ignore
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -RunOnlyIfNetworkAvailable -DontStopOnIdleEnd -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 2) -ErrorAction Ignore
Unregister-ScheduledTask -TaskName "VMBootAll" -Confirm:0 -ErrorAction Ignore
Register-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -TaskName "VMBootAll" -Description "VMBootstorm" -User $vmAdminUserName -Password $vmAdminPassword -RunLevel Highest -ErrorAction Ignore
######################
### AZURE RM SETUP ###
######################
$logFilePath = $using:logFilePath
$azureStackSdkPath = $using:azureStackSdkPath
$azureStackInstallerPath = $using:azureStackInstallerPath
if((IsAzureStack -Location $location) -eq $true) {
# Ignore server certificate errors to avoid https://api.azurestack.local/ certificate error
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Write-Warning -Message "CertificatePolicy set to ignore all server certificate errors"
$count = 0
$installFinished = $false
while (!$installFinished -and $count -lt 5) {
try {
Install-Module -Name AzureRM -RequiredVersion 1.2.10 -Scope AllUsers -ErrorAction Stop -Confirm:0
$installFinished = $true
}
catch {
$count++
Start-Sleep -Seconds 10
Write-Warning "Could not install AzureRM module. Trying again ($count / 5)"
}
}
# Import Azure Resource Manager PS module if already present
try {
"Importing Azure module" | Tee-Object -FilePath $logFilePath -Append
Import-Module AzureRm -ErrorAction Stop | Out-Null
} catch [Exception] {
"Cannot import AzureRm module. Cannot proceed further without AzureRm module. Exception: $_" | Tee-Object -FilePath $logFilePath -Append
}
}
# Azure Cloud
else {
# Import Azure Resource Manager PS module if already present
try {
"Importing Azure module" | Tee-Object -FilePath $logFilePath -Append
Import-Module AzureRm -ErrorAction Stop | Out-Null
}
# Install Azure Resource Manager PS module
catch {
# Suppress prompts
$ConfirmPreference = 'None'
"Cannot import Azure module, proceeding with installation" | Tee-Object -FilePath $logFilePath -Append
# Install AzureRM
try {
Get-PackageProvider -Name nuget -ForceBootstrap -Force | Out-Null
Install-Module AzureRm -repository PSGallery -Force -Confirm:0 -Scope AllUsers | Out-Null
}
catch {
"Installation of AzureRm module failed." | Tee-Object -FilePath $logFilePath -Append
}
# Import AzureRM
try {
Import-Module AzureRm -ErrorAction Stop | Out-Null
} catch {
"Cannot import Azure module. Try importing after restart PowerShell instance. Cannot proceed further without Azure module." | Tee-Object -FilePath $logFilePath -Append
}
}
}
Disable-AzureRmDataCollection
# Test status file
$statusFilePath = "$localPath\VMBootStatus.log"
# Wait for VM bootstorm test to finish if vm count is small and DSC can finish within 90 minutes
$waitCount = 75
while(((Test-Path $statusFilePath) -eq $false) -and ($waitCount -gt 0)) {
"Waiting for bootstorm test to finish $waitCount" | Tee-Object -FilePath $logFilePath -Append
Start-Sleep -Seconds 60
$waitCount--
}
if((Test-Path $statusFilePath) -eq $false) {
"Bootstorm test finished successfully." | Tee-Object -FilePath $logFilePath -Append
}
else {
"Bootstorm test not finished successfully." | Tee-Object -FilePath $logFilePath -Append
}
}
}
}

Двоичные данные
bootstorm-vm-boot-time/VMBootAll.zip

Двоичный файл не отображается.

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

@ -0,0 +1,647 @@
#
# Copyright="?Microsoft Corporation. All rights reserved."
#
param (
[Parameter(Mandatory)]
[string]$AzureUsername,
[Parameter(Mandatory)]
[string]$AzurePassword,
[Parameter(Mandatory)]
[string]$TenantId,
[Parameter(Mandatory)]
[string]$Location,
[Parameter(Mandatory)]
[string]$VMName,
[Parameter(Mandatory)]
[int32]$VMCount,
[Parameter(Mandatory)]
[string]$AzureStorageAccount,
[Parameter(Mandatory)]
[string]$AzureStorageAccessKey,
[Parameter(Mandatory)]
[string]$AzureStorageEndpoint,
[Parameter(Mandatory)]
[string]$AzureSubscription
)
"Importing Azure module" | Tee-Object -FilePath $logFilePath -Append
Import-Module AzureRm -ErrorAction Stop | Out-Null
function VMBootAll {
# Azure uses AzureAdApplicationId and AzureAdApplicationPassword values as AzureUserName and AzurePassword parameters respectively
# AzureStack uses tenant UserName and Password values as AzureUserName and AzurePassword parameters respectively
$azureUsername = $AzureUsername
$azurePassword = $AzurePassword
$tenant = $TenantId
$location = $Location
$vmName = $VMName
$vmCount = $VMCount
$storageAccountName = $AzureStorageAccount
$storageAccountKey = $AzureStorageAccessKey
$storageEndpoint = $AzureStorageEndpoint
# Local file storage location
$localPath = "$env:SystemDrive"
# Log file
$logFileName = "VMBoot.log"
$logFilePath = "$localPath\$logFileName"
# Test status file
$statusFilePath = "$localPath\VMBootStatus.log"
if(Test-Path $logFilePath) {
"Log file $logFilePath already exists. Skipped text execution" | Tee-Object -FilePath $logFilePath -Append
return
}
# Turn off private firewall
netsh advfirewall set privateprofile state off
# PS Credentials
$pw = ConvertTo-SecureString -AsPlainText -Force -String $azurePassword
$pscred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $azureUsername,$pw
if($pscred -eq $null) {
"Powershell Credential object is null. Cannot proceed." | Tee-Object -FilePath $logFilePath -Append
return
}
$azureCreds = Get-Credential -Credential $pscred
if($azureCreds -eq $null) {
"Get-Credential returned null. Cannot proceed." | Tee-Object -FilePath $logFilePath -Append
return
}
#TODO Query the ARM endpoint or parameterize it
$resourceManagerEndpoint = $("https://management.$storageEndpoint".ToLowerInvariant())
$endptres = Invoke-RestMethod "${ResourceManagerEndpoint}/metadata/endpoints?api-version=1.0"
$activeDirectoryServiceEndpointResourceId = $($endptres.authentication.audiences[0])
$aadTenantId = $tenant
$activeDirectoryEndpoint = $($endptres.authentication.loginEndpoint)
$activeDirectoryEndpoint = $($endptres.authentication.loginEndpoint).TrimEnd("/") + "/"
$galleryEndpoint = $endptres.galleryEndpoint
$graphEndpoint = $endptres.graphEndpoint
$storageEndpointSuffix="$($storageEndpoint)".ToLowerInvariant()
$azureKeyVaultDnsSuffix="vault.$($storageEndpoint)".ToLowerInvariant()
# Get AzureToken
$resourceManagerEndpoint = $("https://management.$storageEndpoint".ToLowerInvariant())
$endptres = Invoke-RestMethod "${ResourceManagerEndpoint}/metadata/endpoints?api-version=1.0"
$activeDirectoryServiceEndpointResourceId = $($endptres.authentication.audiences[0])
$aadTenantId = $tenant
$activeDirectoryEndpoint = $($endptres.authentication.loginEndpoint).TrimEnd("/") + "/"
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
$contextAuthorityEndpoint = ([System.IO.Path]::Combine($activeDirectoryEndpoint, $aadTenantId)).Replace('\','/')
$authContext = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext($contextAuthorityEndpoint, $false)
$userCredential = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential($azureCreds.UserName, $azureCreds.Password)
$azureToken = ($authContext.AcquireToken($activeDirectoryServiceEndpointResourceId, $clientId, $userCredential)).AccessToken
if(!$azureToken)
{
"Error: Unable to generate Authorization token" | Tee-Object -FilePath $logFilePath -Append
return;
}
# AzureStack
# determine proper way to detect we are running on AzureStack
if((IsAzureStack -Location $location) -eq $true) {
# Authenticate to AzureStack
try {
$envName = "AzureStackCloud"
Add-AzureRmEnvironment -Name ($envName) `
-ActiveDirectoryEndpoint ($activeDirectoryEndpoint) `
-ActiveDirectoryServiceEndpointResourceId ($activeDirectoryServiceEndpointResourceId) `
-ResourceManagerEndpoint ($resourceManagerEndpoint) `
-GalleryEndpoint ($galleryEndpoint) `
-GraphEndpoint ($graphEndpoint) `
-StorageEndpointSuffix ($storageEndpointSuffix) `
-AzureKeyVaultDnsSuffix ($azureKeyVaultDnsSuffix) | Out-Null
Add-AzureRmAccount -EnvironmentName $envName -Credential $azureCreds -TenantId $aadTenantId | Out-Null
}
catch [Exception] {
"Failed to authenticate with Azure Stack. Exception details $_" | Tee-Object -FilePath $logFilePath -Append
}
}
# AzureCloud
else {
if($azureCreds -eq $null) {
"Powershell Credential object is null. Cannot proceed." | Tee-Object -FilePath $logFilePath -Append
return
}
# Authenticate to Azure using AzureAdApplication
try {
Add-AzureRmAccount -Credential $azureCreds -ServicePrincipal -Tenant $tenant
}
catch [Exception] {
"Failed to authenticate with Azure. Exception details $_" | Tee-Object -FilePath $logFilePath -Append
}
}
try {
"Subscription ID $AzureSubscription" | Tee-Object -FilePath $logFilePath -Append
"Setting subscription" | Tee-Object -FilePath $logFilePath -Append
Select-AzureRmSubscription -SubscriptionId $AzureSubscription | Tee-Object -FilePath $logFilePath -Append
}
catch {
"Failed to select Azure subscription (id: $AzureSubscription)" | Tee-Object -FilePath $logFilePath -Append
"Exception: $_" | Tee-Object -FilePath $logFilePath -Append
}
##############################
### VM PRE-BOOTSTORM SETUP ###
##############################
# Get VMs
"Getting VMs" | Tee-Object -FilePath $logFilePath -Append
$vms = Get-AzureRmVM | Where-Object {$_.Name -match $vmName}
$resourceGroupName = $null
# Turn off all VMs (except jump box VM which stores results)
foreach($vm in $vms) {
$_vmName = $vm.Name
# All VMs except jump box VM
if($_vmName -match "[0-9]$") {
$_date = Get-Date -Format hh:mmtt
$logFile = $localPath + "\VmBoot_" + $_vmName + ".log"
"Turning off VM $_vmName in parallel at $_date" | Tee-Object -FilePath $logFilePath -Append
Start-Job -ScriptBlock {
param($_vmName,$_resourceGroupName,$location,$logFile,$azureSubscription,$armEndpoint,$token)
# Ignore server certificate errors to avoid https://api.azurestack.local/ certificate error
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Write-Warning -Message "CertificatePolicy set to ignore all server certificate errors"
$d = Get-Date
"$d Stopping VM $_vmName" | Tee-Object -FilePath $logFile -Append
try {
# Make the calls using REST and passing in token to avoid too many fast Auth calls
$stopAzureVM = @{
Uri ='{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.Compute/virtualMachines/{3}/powerOff?api-version=2015-06-15' `
-f $armEndpoint, $azureSubscription, $_resourceGroupName, $_vmName
Method = "POST"
Headers = @{ "Authorization" = "Bearer " + $token }
ContentType = "application/json"
}
"URI: $($stopAzureVM.Uri)" | Tee-Object -FilePath $logFile -Append
$result = Invoke-RestMethod @stopAzureVM
} catch [Exception] {
"Failed to turn off $_vmName VM. Exception details $_" | Tee-Object -FilePath $logFile -Append
}
$d = Get-Date
"$d VM $_vmName Stopped" | Tee-Object -FilePath $logFile -Append
} -ArgumentList $_vmName,$vm.ResourceGroupName,$location,$logFile,$AzureSubscription,$resourceManagerEndpoint,$azureToken | Out-Null
$resourceGroupName = $vm.ResourceGroupName
}
}
$numberOfRetries = 60
# Wait for background jobs
$jobs = Get-Job | Where-Object {$_.State -eq "Running"}
$noOfRetries = $numberOfRetries
while(($jobs.Count -gt 0) -and ($noOfRetries -gt 0)) {
"Waiting for VMs to all be stopped. $($jobs.Count) jobs left. Retries left: $noOfRetries" | Tee-Object -FilePath $logFilePath -Append
Start-Sleep -Seconds 15
$noOfRetries--
$jobs = Get-Job | Where-Object {$_.State -eq "Running"}
}
"Done waiting for VMs to all be stopped." | Tee-Object -FilePath $logFilePath -Append
# Clear background jobs
Get-Job | Remove-Job -Force -Confirm:0
# Check if all VMs are deallocated (i.e. turned off)
$noOfRetries = $numberOfRetries
[System.Collections.ArrayList]$runningVMs = $vms
#1 VM = the controller VM
while(($noOfRetries -gt 0) -and ($runningVMs.Count -gt 1)) {
Start-Sleep -Seconds 30
# All VMs except jump box VM
[System.Collections.ArrayList]$removeArray = @()
foreach($vm in $runningVMs) {
if($vm.Name -match "[0-9]$") {
try {
"$(Get-Date -displayhint Time) Start Get-AzureRmVM on $($vm.Name)" | Tee-Object -FilePath $logFilePath -Append
$vmStatus = Get-AzureRmVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Status
"$(Get-Date -displayhint Time) End Get-AzureRmVM on $($vm.Name) : Status '$($vmStatus.Statuses[1].Code)'" | Tee-Object -FilePath $logFilePath -Append
} catch {
"Get-AzureRmVM on $($vm.Name) failed $_" | Tee-Object -FilePath $logFilePath -Append
}
$isVmRunning = $vmStatus.Statuses[1].Code.Contains("running")
if($isVmRunning -eq $false) {
$removeArray.Add($vm)
}
}
}
foreach($vm in $RemoveArray) {
$runningVMs.Remove($vm)
}
$RemoveArray.Clear()
"Waiting for all VMs to no longer be running. Running VMs: $($runningVMs.Count). Retries left: $noOfRetries" | Tee-Object -FilePath $logFilePath -Append
$noOfRetries -= 1
}
if($noOfRunningVMs -gt 0) {
"$noOfRunningVMs out of $vmCount VMs failed to turn off." | Tee-Object -FilePath $logFilePath -Append
}
else {
"All $vmCount VMs are turned off" | Tee-Object -FilePath $logFilePath -Append
}
# Get Token again incase it needs refreshing
$azureToken = ($authContext.AcquireToken($activeDirectoryServiceEndpointResourceId, $clientId, $userCredential)).AccessToken
####################
### VM BOOTSTORM ###
####################
# Boot all VMs at the same time
foreach($vm in $vms) {
$_vmName = $vm.Name
# All VMs except jump box VM
if($_vmName -match "[0-9]$") {
$_date = Get-Date -Format hh:mmtt
$logFile = $localPath + "\VmBoot_" + $_vmName + ".log"
"Booting VM $_vmName at $_date" | Tee-Object -FilePath $logFilePath -Append
Start-Job -ScriptBlock {
param($_vmName,$_resourceGroupName,$location,$logFile,$azureSubscription, $armEndpoint, $token)
# Ignore server certificate errors to avoid https://api.azurestack.local/ certificate error
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Write-Warning -Message "CertificatePolicy set to ignore all server certificate errors"
# Get VM Boot Start Time
$_statusBootStartTime = Get-Date
"Starting boot at $_statusBootStartTime" | Tee-Object -FilePath $logFile -Append
try {
# Make the calls using REST and passing in token to avoid too many fast Auth calls
$startAzureVM = @{
Uri ='{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.Compute/virtualMachines/{3}/start?api-version=2015-06-15' `
-f $armEndpoint, $azureSubscription, $_resourceGroupName, $_vmName
Method = "POST"
Headers = @{ "Authorization" = "Bearer " + $token }
ContentType = "application/json"
}
"URI: $($startAzureVM.Uri)" | Tee-Object -FilePath $logFile -Append
$result = Invoke-RestMethod @startAzureVM
} catch [Exception] {
"Failed to turn on VM $_vmName Exception: $_" | Tee-Object -FilePath $logFile -Append
}
$_dateAfterBoot = Get-Date
"Boot succeeded at $_dateAfterBoot" | Tee-Object -FilePath $logFile -Append
# Get VM Boot End Time (Ignore NULL values of Time)
$numberOfRetries = 60
$retries = 0
do
{
"Waiting for boot. Retry Count $retries" | Tee-Object -FilePath $logFile -Append
Start-Sleep -Seconds 60
$retries++
# Make the calls using REST and passing in token to avoid too many fast Auth calls
$getAzureVM = @{
Uri ='{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.Compute/virtualMachines/{3}?$expand=instanceView&api-version=2015-06-15' `
-f $armEndpoint, $azureSubscription, $_resourceGroupName, $_vmName
Method = "Get"
Headers = @{ "Authorization" = "Bearer " + $token }
ContentType = "application/json"
}
"URI: $($getAzureVM.Uri)" | Tee-Object -FilePath $logFile -Append
$result = Invoke-RestMethod @getAzureVM
$_statusBootEndTime = $result.Properties.InstanceView.Statuses[0].Time
}while(!$_statusBootEndTime -and $retries -lt $numberOfRetries)
# Create custom vm boot result object
$_vmBootResult = "" | Select-Object VMName, VMBootStartTime, VMBootEndTime, VMBootTimeInSeconds
$_vmBootResult.VMName = ($_vmName).Trim()
$_vmBootResult.VMBootStartTime = ([DateTimeOffset]$_statusBootStartTime).DateTime
$_vmBootResult.VMBootEndTime = ([DateTimeOffset]$_statusBootEndTime).DateTime
if($_vmBootResult.VMBootEndTime -gt $_vmBootResult.VMBootStartTime) {
$_vmBootResult.VMBootTimeInSeconds = [float]($_vmBootResult.VMBootEndTime - $_vmBootResult.VMBootStartTime).TotalSeconds
}
else {
$_vmBootResult.VMBootTimeInSeconds = 0
"VM boot end time is invalid for VM $_vmName" | Tee-Object -FilePath $logFile -Append
}
return $_vmBootResult
} -ArgumentList $vm.Name,$vm.ResourceGroupName,$location,$logFile,$AzureSubscription,$resourceManagerEndpoint, $azureToken | Out-Null
}
}
# Wait for background jobs
$jobs = Get-Job | Where-Object {$_.State -eq "Running"}
while($jobs.Count -gt 0) {
"$($jobs.Count) VMs still booting" | Tee-Object -FilePath $logFilePath -Append
Start-Sleep -Seconds 15
$jobs = Get-Job | Where-Object {$_.State -eq "Running"}
}
# Receive job results
$vmbootResults = @()
foreach($job in Get-Job) { $vmbootResults += ,(Receive-Job -Job $job) }
# Clear background jobs
Get-Job | Remove-Job -Force -Confirm:0
# Prepare storage context to upload results to Azure storage table
"Azure ad resource id is $storageEndpoint" | Tee-Object -FilePath $logFilePath -Append
"Azure storage endpoint $storageEndpoint is being used." | Tee-Object -FilePath $logFilePath -Append
$storageContext = $null
$storageTable = $null
try {
$storageContext = New-AzureStorageContext $storageAccountName -StorageAccountKey $storageAccountKey -Endpoint $storageEndpoint
if($storageContext -eq $null) {
"Azure Storage context is null." | Tee-Object -FilePath $logFilePath -Append
}
$storageTableName = "VMBootResults"
# Retrieve the table if it already exists.
try {
$storageTable = Get-AzureStorageTable -Name $storageTableName -Context $storageContext -ErrorAction SilentlyContinue
if($storageTable -ne $null) {
Remove-AzureStorageTable -Name $storageTableName -Context $storageContext -Force -ErrorAction SilentlyContinue
}
} catch {
"Storage table $storageTableName does not exists. Creating a new table." | Tee-Object -FilePath $logFilePath -Append
}
# Create a new table if it does not exist.
if ($storageTable -eq $null) {
try {
$storageTable = New-AzureStorageTable -Name $storageTableName -Context $storageContext
} catch [Exception] {
"Storage table $storageTableName cannot be created. Exception: $_" | Tee-Object -FilePath $logFilePath -Append
try {
$storageTable = New-AzureStorageTable -Name $storageTableName -Context $storageContext
} catch [Exception] {
"Storage table $storageTableName cannot be created. Exception: $_" | Tee-Object -FilePath $logFilePath -Append
}
}
}
}
catch {
"Azure storage context cannot be created for a given storage account $storageAccountName" | Tee-Object -FilePath $logFilePath -Append
}
# Function to add a result row to the Azure Storage Table
function Add-TableEntity() {
[CmdletBinding()]
param(
$table,
[String]$PartitionKey,
[String]$RowKey,
[String]$Value
)
if($table -eq $null) {
"Value cannot be inserted into null table" | Tee-Object -FilePath $logFilePath -Append
}
$entity = New-Object -TypeName Microsoft.WindowsAzure.Storage.Table.DynamicTableEntity -ArgumentList $PartitionKey, $RowKey
$entity.Properties.Add("Value", $Value)
if($entity -eq $null) {
"Entity cannot be created for partition key $PartitionKey and row $RowKey" | Tee-Object -FilePath $logFilePath -Append
}
$result = $table.CloudTable.Execute([Microsoft.WindowsAzure.Storage.Table.TableOperation]::Insert($entity))
return $result
}
# Display boot results
$vmbootResultFile = "$env:SystemDrive\VMBootResult.log"
# Skip test if already executed
if(Test-Path $vmbootResultFile -ErrorAction SilentlyContinue) {
"Result file already exists. Skipping test execution." | Tee-Object -FilePath $logFilePath -Append
return
}
if($vmbootResults.Count -gt 0) {
"----------------------------------------------------------" | Tee-Object -FilePath $vmbootResultFile
"VM Name `t`tVM Boot Time (sec)" | Tee-Object -FilePath $vmbootResultFile -Append
"----------------------------------------------------------" | Tee-Object -FilePath $vmbootResultFile -Append
$_vmBootFailedCount = 0
$_vmBootTimeCount = 0
$_vmBootTimeSum = 0.0
$_vmBootTimeAvg = 0.0
$_vmBootTimeAbsolute = 0.0
$_vmBootTimeAbsoluteStart = Get-Date
$_vmBootTimeAbsoluteEnd = (Get-Date).AddDays(-30)
$_vmBootTimeMax = 0.0
$_vmBootTimeMin = [float]::MaxValue
$_executionId = Get-Date -Format yyyyMMdd_HHmm
$vmResultIndex = 0
foreach($vmbootResult in $vmbootResults) {
if($vmbootResult -ne $null) {
# Remove extra array object with properties Environment,Account,Tenant,Subscription,CurrentStorageAccount
$vmbootResult = $vmbootResult | Where-Object { $_.GetType().ToString().Contains("System.Management.Automation.PSCustomObject") }
$_vmName = $vmbootResult.VMName
$_vmBootTime = ([double]::Parse($vmbootResult.VMBootTimeInSeconds))
$_vmBootTimeString = "{0:N0}" -f [float]($_vmBootTime)
if(($_vmBootTime -le 0) -and ($_vmBootTime -ge [Int32]::MaxValue)) {
"Skipping invalid boot time $_vmBootTimeString for VM $_vmname" | Tee-Object -FilePath $logFilePath -Append
$_vmBootFailedCount++
continue
}
"$_vmName `t`t$_vmBootTimeString" | Tee-Object -FilePath $vmbootResultFile -Append
# Add vm boot results to the Azure storage table
if($storageTable -ne $null) {
try {
Add-TableEntity -Table $storageTable -PartitionKey $_executionId -RowKey $_vmName -Value $_vmBootTimeString
} catch {
Write-Verbose "Adding Azure storage table entry for row $vmResultIndex failed."
"Adding Azure storage table entry for row $vmResultIndex failed." | Tee-Object -FilePath $logFilePath -Append
}
}
else {
"Azure storage table object $storageTable is null" | Tee-Object -FilePath $logFilePath -Append
}
$_vmBootTimeSum += $_vmBootTime
$_vmBootTimeCount += 1
if($_vmBootTimeAbsoluteStart -gt $vmbootResult.VMBootStartTime) {
$_vmBootTimeAbsoluteStart = $vmbootResult.VMBootStartTime
}
if($_vmBootTimeAbsoluteEnd -lt $vmbootResult.VMBootEndTime) {
$_vmBootTimeAbsoluteEnd = $vmbootResult.VMBootEndTime
}
if($_vmBootTimeMax -lt $_vmBootTime) {
$_vmBootTimeMax = $_vmBootTime
}
if($_vmBootTimeMin -gt $_vmBootTime) {
$_vmBootTimeMin = $_vmBootTime
}
}
$vmResultIndex += 1
}
$_vmBootTimeAvg = "{0:N0}" -f [float]($_vmBootTimeSum/$_vmBootTimeCount)
$_vmBootTimeAbsolute = "{0:N0}" -f [float](($_vmBootTimeAbsoluteEnd - $_vmBootTimeAbsoluteStart).TotalSeconds)
$_vmBootTimeMax = "{0:N0}" -f [float]($_vmBootTimeMax)
$_vmBootTimeMin = "{0:N0}" -f [float]($_vmBootTimeMin)
"----------------------------------------------------------" | Tee-Object -FilePath $logFilePath -Append
if($VMCount -gt $_vmBootTimeCount) {
"$_vmBootTimeCount out of $VMCount Azure A1-sized VMs cold booted in $_vmBootTimeAbsolute seconds at an average start time $_vmBootTimeAvg seconds/VM." | Tee-Object -FilePath $logFilePath -Append
}
else {
"$_vmBootTimeCount Azure A1-sized VMs cold booted in $_vmBootTimeAbsolute seconds at an average start time $_vmBootTimeAvg seconds/VM." | Tee-Object -FilePath $logFilePath -Append
}
"----------------------------------------------------------" | Tee-Object -FilePath $logFilePath -Append
"Minimum vm boot time is $_vmBootTimeMin sec and maximum vm boot time is $_vmBootTimeMax sec" | Tee-Object -FilePath $logFilePath -Append
"----------------------------------------------------------" | Tee-Object -FilePath $logFilePath -Append
"$_vmBootTimeCount A1 VMs in $_vmBootTimeAbsolute sec @ $_vmBootTimeAvg sec/VM" | Tee-Object -FilePath $logFilePath -Append
"----------------------------------------------------------" | Tee-Object -FilePath $logFilePath -Append
if($_vmBootFailedCount -gt 0) {
"Failed to get boot time for $_vmBootFailedCount VMs" | Tee-Object -FilePath $logFilePath -Append
"----------------------------------------------------------" | Tee-Object -FilePath $logFilePath -Append
}
# Add vm average boot results to the Azure storage table
if($storageTable -ne $null) {
try {
# Average vm boot time
Add-TableEntity -Table $storageTable -PartitionKey $_executionId -RowKey "AverageBootTime" -Value $_vmBootTimeAvg
$vmResultIndex += 1
# Absolute vm boot time
Add-TableEntity -Table $storageTable -PartitionKey $_executionId -RowKey "AbsoluteBootTime" -Value $_vmBootTimeAbsolute
$vmResultIndex += 1
# Max vm boot time
Add-TableEntity -Table $storageTable -PartitionKey $_executionId -RowKey "MaxBootTime" -Value $_vmBootTimeMax
$vmResultIndex += 1
# Max vm boot time
Add-TableEntity -Table $storageTable -PartitionKey $_executionId -RowKey "MinBootTime" -Value $_vmBootTimeMin
$vmResultIndex += 1
# Summary
Add-TableEntity -Table $storageTable -PartitionKey $_executionId -RowKey "Summary" -Value "$_vmBootTimeCount A1 VMs in $_vmBootTimeAbsolute sec @ $_vmBootTimeAvg sec/VM"
$vmResultIndex += 1
} catch {
"Adding Azure storage table summary entry for row $vmResultIndex failed." | Tee-Object -FilePath $logFilePath -Append
}
} else {
"Azure storage table object $storageTable is null" | Tee-Object -FilePath $logFilePath -Append
}
"----------------------------------------------------------" | Tee-Object -FilePath $vmbootResultFile -Append
"$_vmBootTimeCount Azure A1-sized VMs cold booted in $_vmBootTimeAbsolute seconds at an average start time $_vmBootTimeAvg seconds/VM" | Tee-Object -FilePath $vmbootResultFile -Append
"----------------------------------------------------------" | Tee-Object -FilePath $vmbootResultFile -Append
"Minimum vm boot time is $_vmBootTimeMin sec and maximum vm boot time is $_vmBootTimeMax sec" | Tee-Object -FilePath $vmbootResultFile -Append
"----------------------------------------------------------" | Tee-Object -FilePath $vmbootResultFile -Append
"$_vmBootTimeCount A1 VMs in $_vmBootTimeAbsolute sec @ $_vmBootTimeAvg sec/VM" | Tee-Object -FilePath $vmbootResultFile -Append
"----------------------------------------------------------" | Tee-Object -FilePath $vmbootResultFile -Append
if($_vmBootFailedCount -gt 0) {
"Failed to get boot time for $_vmBootFailedCount VMs" | Tee-Object -FilePath $vmbootResultFile -Append
"----------------------------------------------------------" | Tee-Object -FilePath $vmbootResultFile -Append
}
}
else {
Write-Error "Failed to get VM boot results" -ForegroundColor Red
"Failed to get VM boot results" | Tee-Object -FilePath $logFilePath -Append
"Failed to get VM boot results" | Tee-Object -FilePath $vmbootResultFile -Append
}
"VM boot storm test finished." | Tee-Object -FilePath $logFilePath -Append
"VM boot storm test finished." | Tee-Object -FilePath $statusFilePath -Append
# Upload VM boot results and logs file to Azure storage container
$storageContainerName = "results-vmbootstorm"
if($storageContext -ne $null) {
try {
New-AzureStorageContainer -Name $storageContainerName -Permission Blob -Context $storageContext -Verbose -ErrorAction Stop;
try {
Set-AzureStorageBlobContent -File $vmbootResultFile -Container $storageContainerName -Context $storageContext -ErrorAction Stop;
Set-AzureStorageBlobContent -File $logFilePath -Container $storageContainerName -Context $storageContext -ErrorAction Stop;
}
catch {
"Failed to upload VM boot storm result and log file." | Tee-Object -FilePath $logFilePath -Append
}
} catch {
"Failed to create storage container $storageContainerName to upload result and log file." | Tee-Object -FilePath $logFilePath -Append
}
}
else {
"Cannot upload VM boot storm result and log file as storage context is null." | Tee-Object -FilePath $logFilePath -Append
}
}
function IsAzureStack
{
param
(
[Parameter(Mandatory)]
$Location
)
if($Location -eq "AzureCloud" -or $Location -eq "AzureChinaCloud" -or $Location -eq "AzureUSGovernment" -or $Location -eq "AzureGermanCloud") {
return $false
}
return $true
}
VMBootAll

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

@ -28,6 +28,13 @@
"description": "Number of VMs to create."
}
},
"batchSize": {
"type": "int",
"defaultValue": "[parameters('vmCount')]",
"metadata": {
"description": "Number of VMs to create in a batch."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_A2",
@ -78,11 +85,11 @@
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"nsgName": "[concat('ng', resourceGroup().name)]",
"nsgID": "[resourceId('Microsoft.Network/networkSecurityGroups',variables('nsgName'))]",
"modulesPath": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/bootstorm-vm-boot-time/",
"modulesPath": "https://raw.githubusercontent.com/BrianLPeterson/AzureStack-QuickStart-Templates/bootstormfix/bootstorm-vm-boot-time/",
"moduleVMBootAll": "VMBootAll.zip",
"modulesUrlVMBootAll": "[concat(variables('modulesPath'),variables('moduleVMBootAll'))]",
"configurationFunctionVMBootAll": "VMBootAll.ps1\\ConfigureVMBootAll",
"controllerVmSize": "Standard_A2"
"controllerVmSize": "Standard_A4"
},
"resources": [
{
@ -196,8 +203,7 @@
"name": "[variables('vmName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/',variables('uniqueStorageAccountName'))]",
"[concat('Microsoft.Network/networkInterfaces/',variables('vmNicName'))]"
"vmLoop"
],
"properties": {
"hardwareProfile": {
@ -246,7 +252,9 @@
"location": "[variables('location')]",
"copy": {
"name": "vmLoop",
"count": "[parameters('vmCount')]"
"count": "[parameters('vmCount')]",
"mode": "Serial",
"batchSize": "[parameters('batchSize')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/',variables('uniqueStorageAccountName'))]",

Двоичный файл не отображается.