* temp eth upload

* Update vmExtension.json

* Update joiningVmExtension.json

* Update joiningVmExtension.json

* Update joiningVmExtension.json

* removed old eth

* added new eth
This commit is contained in:
Ali Nikravesh 2018-06-29 14:24:02 -07:00 коммит произвёл Krishna Nithin
Родитель 198c5495a4
Коммит fc69dbf31f
110 изменённых файлов: 10217 добавлений и 0 удалений

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

@ -0,0 +1,21 @@
{
"alloc": {
"#PREFUND_ADDRESS": {
"balance": "1000000000000000000000000000000"
}
},
"config": {
"homesteadBlock": 0,
"chainID": #NETWORKID,
"eip155Block": 0,
"eip158Block": 0
},
"nonce": "0x0000000000000042",
"difficulty": "#DIFFICULTY",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x4c4b40"
}

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

@ -0,0 +1,641 @@
{
"handler": "Microsoft.Compute.MultiVm",
"version": "0.0.1-preview",
"parameters": {
"basics": [
{
"name": "namePrefix",
"type": "Microsoft.Common.TextBox",
"label": "Resource prefix",
"toolTip": "String used as a base for naming resources (6 alphanumeric characters or less). A unique hash is prepended to the string for some resources, while resource-specific information is appended.",
"constraints": {
"required": true,
"regex": "^[a-z][a-z0-9-]{1,5}$",
"validationMessage": "Resource prefix must be between 2 and 6 characters long, must begin with a lowercase letter, and can contain only numbers and lowercase letters."
}
},
{
"name": "adminUsername",
"type": "Microsoft.Compute.UserNameTextBox",
"label": "VM user name",
"defaultValue": "gethadmin",
"toolTip": "Admin username for all of the deployed virtual machines.",
"osPlatform": "Linux"
},
{
"name": "adminCredentials",
"type": "Microsoft.Compute.CredentialsCombo",
"label": {
"authenticationType": "Authentication type",
"password": "Password",
"confirmPassword": "Confirm password",
"sshPublicKey": "SSH public key"
},
"toolTip": {
"authenticationType": "",
"password": "VM password must be 12 characters and have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character.",
"sshPublicKey": ""
},
"constraints": {
"required": true
},
"options": {
"hideConfirmation": false
},
"osPlatform": "Linux"
}
],
"steps": [
{
"name": "NetworkSize",
"label": "Network size and performance",
"subLabel": {
"preValidation": "Define the number and size and nodes in the network",
"postValidation": "Done"
},
"bladeTitle": "Network Size and Performance",
"elements": [
{
"name": "consortiumMemberIdValue",
"type": "Microsoft.Common.DropDown",
"label": "Consortium Member Id",
"toolTip": "The Member Id for this Consortium. Each Member Id must be unique.",
"constraints": {
"allowedValues": [
{
"label": "0",
"value": 0
},
{
"label": "1",
"value": 1
},
{
"label": "2",
"value": 2
},
{
"label": "3",
"value": 3
},
{
"label": "4",
"value": 4
},
{
"label": "5",
"value": 5
},
{
"label": "6",
"value": 6
},
{
"label": "7",
"value": 7
},
{
"label": "8",
"value": 8
},
{
"label": "9",
"value": 9
},
{
"label": "10",
"value": 10
},
{
"label": "11",
"value": 11
},
{
"label": "11",
"value": 11
},
{
"label": "12",
"value": 12
},
{
"label": "13",
"value": 13
},
{
"label": "14",
"value": 14
},
{
"label": "15",
"value": 15
}
]
},
"visible": true
},
{
"name": "mnSection",
"type": "Microsoft.Common.Section",
"label": "Mining Nodes",
"elements": [
{
"name": "numberOfMiningNodes",
"type": "Microsoft.Common.DropDown",
"label": "Number of mining nodes per member",
"defaultValue": "2",
"toolTip": "Mining nodes record transactions within a blockchain network. Choose the number of nodes that meet your availability and security requirements.",
"constraints": {
"allowedValues": [
{
"label": "2",
"value": 2
},
{
"label": "3",
"value": 3
},
{
"label": "4",
"value": 4
},
{
"label": "5",
"value": 5
},
{
"label": "6",
"value": 6
},
{
"label": "7",
"value": 7
},
{
"label": "8",
"value": 8
},
{
"label": "9",
"value": 9
},
{
"label": "10",
"value": 10
},
{
"label": "11",
"value": 11
},
{
"label": "12",
"value": 12
},
{
"label": "13",
"value": 13
},
{
"label": "14",
"value": 14
},
{
"label": "15",
"value": 15
}
]
},
"visible": true
},
{
"name": "mnStoragePerformance",
"type": "Microsoft.Common.OptionsGroup",
"label": "Mining node storage performance",
"defaultValue": "Standard",
"toolTip": "Standard storage is backed by magnetic drives and provides the lowest cost per GB. Premium storage accounts are backed by solid state drives and offer consistent, low-latency performance. They can only be used with Azure virtual machine disks, and are best for I/O-intensive applications. This setting can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-introduction/#introducing-the-azure-storage-services)",
"constraints": {
"allowedValues": [
{
"label": "Standard",
"value": "Standard"
},
{
"label": "Premium",
"value": "Premium"
}
]
},
"visible": true
},
{
"name": "mnStorageReplication-Standard",
"type": "Microsoft.Common.DropDown",
"label": "Mining node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
},
{
"label": "Geo-redundant storage (GRS)",
"value": "GRS"
},
{
"label": "Read-access geo-redundant storage (RAGRS)",
"value": "RAGRS"
}
]
},
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Standard')]"
},
{
"name": "mnStorageReplication-Premium",
"type": "Microsoft.Common.DropDown",
"label": "Mining node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
}
]
},
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Premium')]"
},
{
"name": "mnNodeVMSizeHDD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Mining node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_D1_v2",
"Standard_D1",
"Standard_A1"
],
"constraints": {
"allowedSizes": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_A8",
"Standard_A9",
"Standard_A10",
"Standard_A11",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Standard')]"
},
{
"name": "mnNodeVMSizeSSD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Mining node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_DS1_v2",
"Standard_DS1",
"Standard_F1s"
],
"constraints": {
"allowedSizes": [
"Standard_DS1",
"Standard_DS2",
"Standard_DS3",
"Standard_DS4",
"Standard_DS11",
"Standard_DS12",
"Standard_DS13",
"Standard_DS14",
"Standard_DS1_v2",
"Standard_DS2_v2",
"Standard_DS3_v2",
"Standard_DS4_v2",
"Standard_DS5_v2",
"Standard_DS11_v2",
"Standard_DS12_v2",
"Standard_DS13_v2",
"Standard_DS14_v2",
"Standard_DS15_v2",
"Standard_F1s",
"Standard_F2s",
"Standard_F4s",
"Standard_F8s",
"Standard_F16s"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Premium')]"
}
]
},
{
"name": "txSection",
"type": "Microsoft.Common.Section",
"label": "Transaction Nodes",
"elements": [
{
"name": "numTXNodes",
"type": "Microsoft.Common.DropDown",
"label": "Number of load balanced transaction nodes",
"defaultValue": "1",
"toolTip": "An application or user interacts with a load balanced set of transaction nodes to submit transactions to the network. Choose the number of nodes that meets your availability requirements.",
"constraints": {
"allowedValues": [
{
"label": "1",
"value": 1
},
{
"label": "2",
"value": 2
},
{
"label": "3",
"value": 3
},
{
"label": "4",
"value": 4
},
{
"label": "5",
"value": 5
}
]
},
"visible": true
},
{
"name": "txStoragePerformance",
"type": "Microsoft.Common.OptionsGroup",
"label": "Transaction node storage performance",
"defaultValue": "Standard",
"toolTip": "Standard storage is backed by magnetic drives and provides the lowest cost per GB. Premium storage accounts are backed by solid state drives and offer consistent, low-latency performance. They can only be used with Azure virtual machine disks, and are best for I/O-intensive applications. This setting can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-introduction/#introducing-the-azure-storage-services)",
"constraints": {
"allowedValues": [
{
"label": "Standard",
"value": "Standard"
},
{
"label": "Premium",
"value": "Premium"
}
]
},
"visible": true
},
{
"name": "txStorageReplication-Standard",
"type": "Microsoft.Common.DropDown",
"label": "Transaction node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
},
{
"label": "Geo-redundant storage (GRS)",
"value": "GRS"
},
{
"label": "Read-access geo-redundant storage (RAGRS)",
"value": "RAGRS"
}
]
},
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Standard')]"
},
{
"name": "txStorageReplication-Premium",
"type": "Microsoft.Common.DropDown",
"label": "Transaction node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
}
]
},
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Premium')]"
},
{
"name": "txNodeVMSizeHDD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Transaction node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_D1_v2",
"Standard_D1",
"Standard_A1"
],
"constraints": {
"allowedSizes": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_A8",
"Standard_A9",
"Standard_A10",
"Standard_A11",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').txSection.numTXNodes]",
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Standard')]"
},
{
"name": "txNodeVMSizeSSD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Transaction node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_DS1_v2",
"Standard_DS1",
"Standard_F1s"
],
"constraints": {
"allowedSizes": [
"Standard_DS1",
"Standard_DS2",
"Standard_DS3",
"Standard_DS4",
"Standard_DS11",
"Standard_DS12",
"Standard_DS13",
"Standard_DS14",
"Standard_DS1_v2",
"Standard_DS2_v2",
"Standard_DS3_v2",
"Standard_DS4_v2",
"Standard_DS5_v2",
"Standard_DS11_v2",
"Standard_DS12_v2",
"Standard_DS13_v2",
"Standard_DS14_v2",
"Standard_DS15_v2",
"Standard_F1s",
"Standard_F2s",
"Standard_F4s",
"Standard_F8s",
"Standard_F16s"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').txSection.numTXNodes]",
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Premium')]"
}
]
}
]
},
{
"name": "EthereumSettings",
"label": "Ethereum Settings",
"subLabel": {
"preValidation": "Configure the Ethereum nodes",
"postValidation": "Done"
},
"bladeTitle": "Ethereum Settings",
"elements": [
{
"name": "consortiumInformation",
"type": "Microsoft.Common.TextBox",
"label": "Consortium Data Url",
"defaultValue": "",
"toolTip": "Url to the consortium data.",
"constraints": {
"required": true
},
"visible": "true"
},
{
"name": "ethereumAccountPsswd",
"type": "Microsoft.Common.PasswordBox",
"label": {
"password": "Ethereum account password",
"confirmPassword": "Confirm password"
},
"toolTip": "Password used to secure the default Ethereum account that will be generated.",
"constraints": {
"required": true,
"regex": "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[^\"]{12,}$",
"validationMessage": "Password must be 12 characters or more with a minimum of 1 lower case, 1 upper case and one number. Double quotes are not allowed."
},
"options": {
"hideConfirmation": false
},
"visible": true
},
{
"name": "ethereumAccountPassphrase",
"type": "Microsoft.Common.PasswordBox",
"label": {
"password": "Ethereum private key passphrase",
"confirmPassword": "Confirm passphrase"
},
"toolTip": "Passphrase used to generate the private key associated with the default Ethereum account that is generated. Consider a passphrase with sufficient randomness to ensure a strong private key.",
"constraints": {
"required": true,
"regex": "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[^\"]{12,}$",
"validationMessage": "Password must be 12 characters or more with a minimum of 1 lower case, 1 upper case and one number. Double quotes are not allowed."
},
"options": {
"hideConfirmation": false
},
"visible": true
}
]
}
],
"outputs": {
"namePrefix": "[basics('namePrefix')]",
"authType": "[basics('adminCredentials').authenticationType]",
"adminUsername": "[basics('adminUsername')]",
"adminPassword": "[basics('adminCredentials').password]",
"adminSSHKey": "[basics('adminCredentials').sshPublicKey]",
"ethereumAccountPsswd": "[steps('EthereumSettings').ethereumAccountPsswd]",
"ethereumAccountPassphrase": "[steps('EthereumSettings').ethereumAccountPassphrase]",
"consortiumMemberId": "[steps('NetworkSize').consortiumMemberIdValue]",
"numMiningNodes": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"mnNodeVMSize": "[coalesce(steps('NetworkSize').mnSection.mnNodeVMSizeHDD, steps('NetworkSize').mnSection.mnNodeVMSizeSSD)]",
"mnStorageAccountType": "[concat(steps('NetworkSize').mnSection.mnStoragePerformance, '_', coalesce(steps('NetworkSize').mnSection.mnStorageReplication-Standard, steps('NetworkSize').mnSection.mnStorageReplication-Premium))]",
"numTXNodes": "[steps('NetworkSize').txSection.numTXNodes]",
"txNodeVMSize": "[coalesce(steps('NetworkSize').txSection.txNodeVMSizeHDD, steps('NetworkSize').txSection.txNodeVMSizeSSD)]",
"txStorageAccountType": "[concat(steps('NetworkSize').txSection.txStoragePerformance, '_', coalesce(steps('NetworkSize').txSection.txStorageReplication-Standard, steps('NetworkSize').txSection.txStorageReplication-Premium))]",
"consortiumData": "[steps('EthereumSettings').consortiumInformation]",
"location": "[location()]"
}
}
}

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

@ -0,0 +1,92 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"MemberNamePrefix": {
"type": "string",
"metadata": {
"description": "String used as a base for naming resources (6 alphanumeric characters or less). A unique hash is prepended to the string for some resources, while resource-specific information is appended."
}
},
"MemberRouteTableName": {
"type": "string",
"metadata": {
"description": "RouteTableName"
}
},
"RemoteMemberVnetAddressSpace": {
"type": "string",
"metadata": {
"description": "The Address Space of the Consortium Member VNet to connect to"
}
},
"RemoteMemberNvaPublicIP": {
"type": "string",
"metadata": {
"description": "The Public IP address of the Consortium Member NVA to connect to"
}
},
"connectionSharedKey": {
"type": "string",
"metadata": {
"description": "Shared Key for the Gateway Connection"
}
},
"MemberNvaPrivateIp":
{
"type": "string"
},
"baseUrl": {
"type": "string",
"metadata": {
"description": "The base URL for dependent assets",
"artifactsBaseUrl": ""
},
"defaultValue": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/ethereum-consortium-blockchain"
}
},
"variables": {
"apiVersionDeployments": "2016-02-01",
"apiVersionRouteTables": "2015-06-15",
"namingInfix": "[toLower(substring(concat(parameters('MemberNamePrefix'), uniqueString(resourceGroup().id)), 0, 9))]",
"nvaVMName": "[concat(variables('namingInfix'), '-nva')]",
"vpnName": "[concat('v', uniqueString(variables('namingInfix'), parameters('RemoteMemberVnetAddressSpace')), '-vpn')]",
"NvaRouteName": "[concat('r', uniqueString(variables('namingInfix'), parameters('RemoteMemberVnetAddressSpace')), '-Route')]",
"location": "[resourceGroup().location]"
},
"resources": [
{
"apiVersion": "[variables('apiVersionRouteTables')]",
"type": "Microsoft.Network/routeTables/routes",
"name": "[concat(parameters('MemberRouteTableName'), '/', variables('NvaRouteName'))]",
"location": "[variables('location')]",
"properties": {
"addressPrefix": "[parameters('RemoteMemberVnetAddressSpace')]",
"nextHopType": "VirtualAppliance",
"nextHopIpAddress": "[parameters('MemberNvaPrivateIp')]"
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "nvaExtension",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/joiningNVAExtension.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"nvaVMName": {"value": "[variables('nvaVMName')]" },
"location": {"value": "[variables('location')]" },
"remoteIpAddress": { "value": "[parameters('RemoteMemberNvaPublicIP')]" },
"remoteAddressSpace": { "value": "[parameters('RemoteMemberVnetAddressSpace')]" },
"sharedKey": { "value": "[parameters('connectionSharedKey')]" },
"vpnName": { "value": "[variables('vpnName')]" },
"artifactsLocationURL": { "value": "[parameters('baseUrl')]" }
}
}
}
],
"outputs": {}
}

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

@ -0,0 +1,611 @@
{
"handler": "Microsoft.Compute.MultiVm",
"version": "0.0.1-preview",
"parameters": {
"basics": [
{
"name": "namePrefix",
"type": "Microsoft.Common.TextBox",
"label": "Resource prefix",
"toolTip": "String used as a base for naming resources (6 alphanumeric characters or less). A unique hash is prepended to the string for some resources, while resource-specific information is appended.",
"constraints": {
"required": true,
"regex": "^[a-z][a-z0-9-]{1,5}$",
"validationMessage": "Resource prefix must be between 2 and 6 characters long, must begin with a lowercase letter, and can contain only numbers and lowercase letters."
}
},
{
"name": "adminUsername",
"type": "Microsoft.Compute.UserNameTextBox",
"label": "VM user name",
"defaultValue": "gethadmin",
"toolTip": "Admin username for all of the deployed virtual machines.",
"osPlatform": "Linux"
},
{
"name": "adminCredentials",
"type": "Microsoft.Compute.CredentialsCombo",
"label": {
"authenticationType": "Authentication type",
"password": "Password",
"confirmPassword": "Confirm password",
"sshPublicKey": "SSH public key"
},
"toolTip": {
"authenticationType": "",
"password": "VM password must be 12 characters and have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character.",
"sshPublicKey": ""
},
"constraints": {
"required": true
},
"options": {
"hideConfirmation": false
},
"osPlatform": "Linux"
}
],
"steps": [
{
"name": "NetworkSize",
"label": "Network size and performance",
"subLabel": {
"preValidation": "Define the number and size and nodes in the network",
"postValidation": "Done"
},
"bladeTitle": "Network Size and Performance",
"elements": [
{
"name": "consortiumMemberIdValue",
"type": "Microsoft.Common.TextBox",
"label": "Consortium Member Id",
"defaultValue": "0",
"toolTip": "The Id associated with each member participating in the consortium network. Member Id should be unique across different members in the same network.",
"constraints": {
"required": true,
"regex": "^(?:25[0-5]|2[0-4]\\d|[01]\\d\\d|\\d?\\d)$",
"validationMessage": "Must be between 0 and 255"
},
"visible": "true"
},
{
"name": "mnSection",
"type": "Microsoft.Common.Section",
"label": "Mining Nodes",
"elements": [
{
"name": "numberOfMiningNodes",
"type": "Microsoft.Common.DropDown",
"label": "Number of mining nodes per member",
"defaultValue": "2",
"toolTip": "Mining nodes record transactions within a blockchain network. Choose the number of nodes that meet your availability and security requirements.",
"constraints": {
"allowedValues": [
{
"label": "2",
"value": 2
},
{
"label": "3",
"value": 3
},
{
"label": "4",
"value": 4
},
{
"label": "5",
"value": 5
},
{
"label": "6",
"value": 6
},
{
"label": "7",
"value": 7
},
{
"label": "8",
"value": 8
},
{
"label": "9",
"value": 9
},
{
"label": "10",
"value": 10
},
{
"label": "11",
"value": 11
},
{
"label": "12",
"value": 12
},
{
"label": "13",
"value": 13
},
{
"label": "14",
"value": 14
},
{
"label": "15",
"value": 15
}
]
},
"visible": true
},
{
"name": "mnStoragePerformance",
"type": "Microsoft.Common.OptionsGroup",
"label": "Mining node storage performance",
"defaultValue": "Standard",
"toolTip": "Standard storage is backed by magnetic drives and provides the lowest cost per GB. Premium storage accounts are backed by solid state drives and offer consistent, low-latency performance. They can only be used with Azure virtual machine disks, and are best for I/O-intensive applications. This setting can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-introduction/#introducing-the-azure-storage-services)",
"constraints": {
"allowedValues": [
{
"label": "Standard",
"value": "Standard"
},
{
"label": "Premium",
"value": "Premium"
}
]
},
"visible": true
},
{
"name": "mnStorageReplication-Standard",
"type": "Microsoft.Common.DropDown",
"label": "Mining node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
},
{
"label": "Geo-redundant storage (GRS)",
"value": "GRS"
},
{
"label": "Read-access geo-redundant storage (RAGRS)",
"value": "RAGRS"
}
]
},
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Standard')]"
},
{
"name": "mnStorageReplication-Premium",
"type": "Microsoft.Common.DropDown",
"label": "Mining node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
}
]
},
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Premium')]"
},
{
"name": "mnNodeVMSizeHDD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Mining node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_D1_v2",
"Standard_D1",
"Standard_A1"
],
"constraints": {
"allowedSizes": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_A8",
"Standard_A9",
"Standard_A10",
"Standard_A11",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Standard')]"
},
{
"name": "mnNodeVMSizeSSD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Mining node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_DS1_v2",
"Standard_DS1",
"Standard_F1s"
],
"constraints": {
"allowedSizes": [
"Standard_DS1",
"Standard_DS2",
"Standard_DS3",
"Standard_DS4",
"Standard_DS11",
"Standard_DS12",
"Standard_DS13",
"Standard_DS14",
"Standard_DS1_v2",
"Standard_DS2_v2",
"Standard_DS3_v2",
"Standard_DS4_v2",
"Standard_DS5_v2",
"Standard_DS11_v2",
"Standard_DS12_v2",
"Standard_DS13_v2",
"Standard_DS14_v2",
"Standard_DS15_v2",
"Standard_F1s",
"Standard_F2s",
"Standard_F4s",
"Standard_F8s",
"Standard_F16s"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Premium')]"
}
]
},
{
"name": "txSection",
"type": "Microsoft.Common.Section",
"label": "Transaction Nodes",
"elements": [
{
"name": "numTXNodes",
"type": "Microsoft.Common.DropDown",
"label": "Number of load balanced transaction nodes",
"defaultValue": "1",
"toolTip": "An application or user interacts with a load balanced set of transaction nodes to submit transactions to the network. Choose the number of nodes that meets your availability requirements.",
"constraints": {
"allowedValues": [
{
"label": "1",
"value": 1
},
{
"label": "2",
"value": 2
},
{
"label": "3",
"value": 3
},
{
"label": "4",
"value": 4
},
{
"label": "5",
"value": 5
}
]
},
"visible": true
},
{
"name": "txStoragePerformance",
"type": "Microsoft.Common.OptionsGroup",
"label": "Transaction node storage performance",
"defaultValue": "Standard",
"toolTip": "Standard storage is backed by magnetic drives and provides the lowest cost per GB. Premium storage accounts are backed by solid state drives and offer consistent, low-latency performance. They can only be used with Azure virtual machine disks, and are best for I/O-intensive applications. This setting can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-introduction/#introducing-the-azure-storage-services)",
"constraints": {
"allowedValues": [
{
"label": "Standard",
"value": "Standard"
},
{
"label": "Premium",
"value": "Premium"
}
]
},
"visible": true
},
{
"name": "txStorageReplication-Standard",
"type": "Microsoft.Common.DropDown",
"label": "Transaction node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
},
{
"label": "Geo-redundant storage (GRS)",
"value": "GRS"
},
{
"label": "Read-access geo-redundant storage (RAGRS)",
"value": "RAGRS"
}
]
},
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Standard')]"
},
{
"name": "txStorageReplication-Premium",
"type": "Microsoft.Common.DropDown",
"label": "Transaction node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
}
]
},
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Premium')]"
},
{
"name": "txNodeVMSizeHDD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Transaction node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_D1_v2",
"Standard_D1",
"Standard_A1"
],
"constraints": {
"allowedSizes": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_A8",
"Standard_A9",
"Standard_A10",
"Standard_A11",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').txSection.numTXNodes]",
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Standard')]"
},
{
"name": "txNodeVMSizeSSD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Transaction node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_DS1_v2",
"Standard_DS1",
"Standard_F1s"
],
"constraints": {
"allowedSizes": [
"Standard_DS1",
"Standard_DS2",
"Standard_DS3",
"Standard_DS4",
"Standard_DS11",
"Standard_DS12",
"Standard_DS13",
"Standard_DS14",
"Standard_DS1_v2",
"Standard_DS2_v2",
"Standard_DS3_v2",
"Standard_DS4_v2",
"Standard_DS5_v2",
"Standard_DS11_v2",
"Standard_DS12_v2",
"Standard_DS13_v2",
"Standard_DS14_v2",
"Standard_DS15_v2",
"Standard_F1s",
"Standard_F2s",
"Standard_F4s",
"Standard_F8s",
"Standard_F16s"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').txSection.numTXNodes]",
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Premium')]"
}
]
}
]
},
{
"name": "EthereumSettings",
"label": "Ethereum Settings",
"subLabel": {
"preValidation": "Configure the Ethereum nodes",
"postValidation": "Done"
},
"bladeTitle": "Ethereum Settings",
"elements": [
{
"name": "ethereumNetworkID",
"type": "Microsoft.Common.TextBox",
"label": "Network ID",
"defaultValue": "10101010",
"toolTip": "ID used to name the private Ethereum network created. Only nodes that share the same ID peer with each other.",
"constraints": {
"required": true,
"regex": "^[0-9]{1,9}$",
"validationMessage": "Only numeric values up to 9 characters long allowed."
},
"visible": "true"
},
{
"type": "Microsoft.Common.OptionsGroup",
"name": "genesisBlockCreation",
"label": "Custom Genesis Block",
"toolTip": "Option to either automatically generate a genesis block or provide a custom one.",
"defaultValue": "No",
"constraints": {
"allowedValues": [
{
"label": "Yes",
"value": "GENESIS"
},
{
"label": "No",
"value": "PASSWORD"
}
],
"required": true
}
},
{
"name": "genesisBlock",
"type": "Microsoft.Common.TextBox",
"label": "Genesis Block",
"defaultValue": "",
"toolTip": "JSON string representing custom genesis block",
"constraints": {
"required": "[contains(steps('EthereumSettings').genesisBlockCreation, 'GENESIS')]"
},
"visible": "[contains(steps('EthereumSettings').genesisBlockCreation, 'GENESIS')]"
},
{
"name": "ethereumAccountPsswd",
"type": "Microsoft.Common.PasswordBox",
"label": {
"password": "Ethereum account password",
"confirmPassword": "Confirm password"
},
"defaultValue": "",
"toolTip": "Password used to secure the default Ethereum account that will be generated.",
"constraints": {
"required": "[contains(steps('EthereumSettings').genesisBlockCreation, 'PASSWORD')]",
"regex": "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[^\"]{12,}$",
"validationMessage": "Password must be 12 characters or more with a minimum of 1 lower case, 1 upper case and one number. Double quotes are not allowed."
},
"options": {
"hideConfirmation": false
},
"visible": "[contains(steps('EthereumSettings').genesisBlockCreation, 'PASSWORD')]"
},
{
"name": "ethereumAccountPassphrase",
"type": "Microsoft.Common.PasswordBox",
"label": {
"password": "Ethereum private key passphrase",
"confirmPassword": "Confirm passphrase"
},
"defaultValue": "",
"toolTip": "Passphrase used to generate the private key associated with the default Ethereum account that is generated. Consider a passphrase with sufficient randomness to ensure a strong private key.",
"constraints": {
"required": "[contains(steps('EthereumSettings').genesisBlockCreation, 'PASSWORD')]",
"regex": "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[^\"]{12,}$",
"validationMessage": "Password must be 12 characters or more with a minimum of 1 lower case, 1 upper case and one number. Double quotes are not allowed."
},
"options": {
"hideConfirmation": false
},
"visible": "[contains(steps('EthereumSettings').genesisBlockCreation, 'PASSWORD')]"
}
]
}
],
"outputs": {
"namePrefix": "[basics('namePrefix')]",
"authType": "[basics('adminCredentials').authenticationType]",
"adminUsername": "[basics('adminUsername')]",
"adminPassword": "[basics('adminCredentials').password]",
"adminSSHKey": "[basics('adminCredentials').sshPublicKey]",
"ethereumNetworkID": "[int(steps('EthereumSettings').ethereumNetworkID)]",
"ethereumAccountPsswd": "[steps('EthereumSettings').ethereumAccountPsswd]",
"ethereumAccountPassphrase": "[steps('EthereumSettings').ethereumAccountPassphrase]",
"consortiumMemberId": "[int(steps('NetworkSize').consortiumMemberIdValue)]",
"numMiningNodes": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"mnNodeVMSize": "[coalesce(steps('NetworkSize').mnSection.mnNodeVMSizeHDD, steps('NetworkSize').mnSection.mnNodeVMSizeSSD)]",
"mnStorageAccountType": "[concat(steps('NetworkSize').mnSection.mnStoragePerformance, '_', coalesce(steps('NetworkSize').mnSection.mnStorageReplication-Standard, steps('NetworkSize').mnSection.mnStorageReplication-Premium))]",
"numTXNodes": "[steps('NetworkSize').txSection.numTXNodes]",
"txNodeVMSize": "[coalesce(steps('NetworkSize').txSection.txNodeVMSizeHDD, steps('NetworkSize').txSection.txNodeVMSizeSSD)]",
"txStorageAccountType": "[concat(steps('NetworkSize').txSection.txStoragePerformance, '_', coalesce(steps('NetworkSize').txSection.txStorageReplication-Standard, steps('NetworkSize').txSection.txStorageReplication-Premium))]",
"location": "[location()]",
"genesisBlock": "[steps('EthereumSettings').genesisBlock]"
}
}
}

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

@ -0,0 +1,662 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"namePrefix": {
"type": "string",
"metadata": {
"description": "String used as a base for naming resources (6 alphanumeric characters or less). A unique hash is prepended to the string for some resources, while resource-specific information is appended."
},
"maxLength": 6
},
"authType": {
"type": "string",
"allowedValues": [
"password",
"sshPublicKey"
],
"metadata": {
"description": "Authorization type for SSH access to VMs"
}
},
"adminUsername": {
"type": "string",
"defaultValue": "gethadmin",
"metadata": {
"description": "Administrator username of each deployed VM (alphanumeric characters only)"
}
},
"adminPassword": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Administrator password for each deployed VM"
}
},
"adminSSHKey": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "SSH RSA public key file as a string"
}
},
"genesisBlock": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Genesis Block for the network"
}
},
"ethereumAccountPsswd": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Password used to secure the default Ethereum account that will be generated"
}
},
"ethereumAccountPassphrase": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Password used to generate the private key associated with the default Ethereum account that is generated. Consider a password with sufficient randomness to ensure a strong private key"
}
},
"ethereumNetworkID": {
"type": "int",
"defaultValue": 72,
"metadata": {
"description": "Private Ethereum network ID to which to connect (max 9 digit number)"
},
"maxValue": 2147483647
},
"consortiumMemberId": {
"type": "int",
"defaultValue": 0,
"metadata": {
"description": "Unique Identifier for the current member of this consortium"
},
"minValue": 0,
"maxValue": 255
},
"numMiningNodes": {
"type": "int",
"defaultValue": 2,
"metadata": {
"description": "Number of mining nodes to create for each consortium member."
},
"minValue": 1,
"maxValue": 15
},
"mnNodeVMSize": {
"type": "string",
"defaultValue": "Standard_A1",
"allowedValues": [],
"metadata": {
"description": "Size of the virtual machine used for mining nodes"
}
},
"mnStorageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS",
"Premium_LRS"
],
"metadata": {
"description": "Type of storage accounts to create"
}
},
"numTXNodes": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Number of load balanced transaction nodes"
},
"minValue": 1,
"maxValue": 5
},
"txNodeVMSize": {
"type": "string",
"defaultValue": "Standard_A1",
"allowedValues": [],
"metadata": {
"description": "Size of the virtual machine for transaction nodes"
}
},
"txStorageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS",
"Premium_LRS"
],
"metadata": {
"description": "Type of storage accounts to create"
}
},
"baseUrl": {
"type": "string",
"metadata": {
"description": "The base URL for dependent assets",
"artifactsBaseUrl": ""
},
"defaultValue": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/ethereum-consortium-blockchain"
}
},
"variables": {
"adminHash": "[uniqueString(parameters('adminPassword'))]",
"apiVersionRouteTables": "2015-06-15",
"apiVersionDeployments": "2015-01-01",
"apiVersionStorageAccounts": "2015-06-15",
"apiVersionAvailabilitySets": "2016-03-30",
"apiVersionNetworkSecurityGroups": "2015-06-15",
"apiVersionNetworkInterfaces": "2015-06-15",
"apiVersionVirtualMachines": "2015-06-15",
"apiVersionVirtualNetworks": "2015-06-15",
"namingInfix": "[toLower(substring(concat(parameters('namePrefix'), uniqueString(resourceGroup().id)), 0, 9))]",
"availabilitySetName": "[concat(variables('namingInfix'), 'AvSet')]",
"httpPort": 80,
"adminSitePort": 3000,
"sshPort": 22,
"sshNATFrontEndStartingPort": 3000,
"genesisBlock": "[parameters('genesisBlock')]",
"gethRPCPort": 8545,
"gethIPCPort": 30303,
"routeTableName": "NVARouteTable",
"loadBalancerName": "[concat(variables('namingInfix'), '-LB')]",
"routeTableName": "VNARouteTable",
"loadBalancerName": "[concat(variables('namingInfix'), '-LB')]",
"loadBalancerBackendAddressPoolName": "LoadBalancerBackend1",
"loadBalancerInboundNatRuleNamePrefix": "SSH-VM",
"location": "[resourceGroup().location]",
"numMNNodes": "[parameters('numMiningNodes')]",
"maxVMsPerStorageAcct": 20,
"mnStorageAcctCount": "[add(div(variables('numMNNodes'), variables('maxVMsPerStorageAcct')), 1)]",
"mnStorageAcctNames": [
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'mn0')]"
],
"nvaNICName": "nic-nva",
"nvaVMName": "[concat(variables('namingInfix'), '-nva')]",
"nvaStorageAcctName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'nva')]",
"nvaStorageAccountType": "Standard_LRS",
"nvaNodeVMSize": "Standard_A1",
"nvaPublicIpName": "nvaPip",
"nvaSubnetName": "[concat(uniqueString(concat(resourceGroup().id, concat(variables('namingInfix'), 'subnet')), 'nva'))]",
"nvaSubnetPrefix": "[replace('10._.14.0/27','_', string(parameters('consortiumMemberId')))]",
"nvaNetPrefix": "10.0.0.0/12",
"mnVMNamePrefix": "[concat(variables('namingInfix'), '-mn')]",
"mnNICPrefix": "nic-mn",
"vnaNICName": "nic-vna",
"vnaVMName": "[concat(variables('namingInfix'), '-vna')]",
"vnaStorageAcctName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'vna')]",
"vnaStorageAccountType": "Standard_LRS",
"vnaNodeVMSize": "Standard_A1",
"vnaPublicIpName": "vnaPip",
"vnaSubnetName": "[concat(uniqueString(concat(resourceGroup().id, concat(variables('namingInfix'), 'subnet')), 'vna'))]",
"vnaSubnetPrefix": "[replace('10._.14.0/27','_', string(parameters('consortiumMemberId')))]",
"vnaNetPrefix": "10.0.0.0/12",
"mnVMNamePrefix": "[concat(variables('namingInfix'), '-mn')]",
"mnNICPrefix": "nic-mn",
"txStorageAcctName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'tx')]",
"txVMNamePrefix": "[concat(variables('namingInfix'), '-tx')]",
"txSubnetName": "[concat(uniqueString(concat(resourceGroup().id, concat(variables('namingInfix'), 'subnet')), 'tx'))]",
"txSubnetPrefix": "[replace('10._.0.0/24','_', string(parameters('consortiumMemberId')))]",
"txNIPrefix": "nic-tx",
"txNsgName": "[concat(variables('namingInfix'), 'TXNsg')]",
"mnNsgName": "[concat(variables('namingInfix'), 'MNNsg')]",
"mnSubnetName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'snet-mn0')]",
"mnSubnetPrefix": "[replace('10._.1.0/24','_', string(parameters('consortiumMemberId')))]",
"numSubnets": 3,
"subnetPropertiesArray": [
{
"name": "[variables('txSubnetName')]",
"properties": {
"addressPrefix": "[variables('txSubnetPrefix')]",
"routeTable": {
"id": "[resourceId ('Microsoft.Network/routeTables', variables('routeTableName'))]"
},
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('txNsgName'))]"
}
}
},
{
"name": "[variables('mnSubnetName')]",
"properties": {
"addressPrefix": "[variables('mnSubnetPrefix')]",
"routeTable": {
"id": "[resourceId ('Microsoft.Network/routeTables', variables('routeTableName'))]"
},
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mnNsgName'))]"
}
}
},
{
"name": "[variables('nvaSubnetName')]",
"properties": {
"addressPrefix": "[replace('10._.14.0/27','_',string(parameters('consortiumMemberId')))]"
}
}
],
"ubuntuImage": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "16.04-LTS",
"version": "latest"
},
"windowsImage": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2016-Datacenter",
"version": "latest"
},
"vNet": {
"name": "[concat(variables('namingInfix'), 'vnet')]",
"addressSpacePrefix": "[replace('10._.0.0/20', '_',string(parameters('consortiumMemberId')))]",
"asn": "[add(parameters('consortiumMemberId'),65050)]"
},
"vnetRef": "[resourceId('Microsoft.Network/virtualNetworks',variables('vNet').name)]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', variables('vNet').name)]",
"txSubnetRef": "[concat(variables('vnetID'),'/subnets/', variables('txSubnetName'))]",
"mnSubnetRefArray": [
"[concat(variables('vnetID'),'/subnets/', variables('mnSubnetName'))]"
],
"nvaSubnetRef": "[concat(variables('vnetID'),'/subnets/', variables('nvaSubnetName'))]"
},
"resources": [
{
"apiVersion": "[variables('apiVersionAvailabilitySets')]",
"type": "Microsoft.Compute/availabilitySets",
"name": "[variables('availabilitySetName')]",
"location": "[variables('location')]",
"properties": {}
},
{
"apiVersion": "[variables('apiVersionRouteTables')]",
"type": "Microsoft.Network/routeTables",
"name": "[variables('routeTableName')]",
"location": "[variables('location')]",
"properties": {}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "loadBalancerLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/loadBalancer.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"loadBalancerName": { "value": "[variables('loadBalancerName')]" },
"dnsHostName": { "value": "[variables('namingInfix')]" },
"loadBalancerBackendAddressPoolName": { "value": "[variables('loadBalancerBackendAddressPoolName')]" },
"loadBalancerInboundNatRuleNamePrefix": { "value": "[variables('loadBalancerInboundNatRuleNamePrefix')]" },
"frontendPort1": { "value": "[variables('httpPort')]" },
"backendPort1": { "value": "[variables('adminSitePort')]" },
"frontendPort2": { "value": "[variables('gethRPCPort')]" },
"backendPort2": { "value": "[variables('gethRPCPort')]" },
"numInboundNATRules": { "value": "[parameters('numTXNodes')]" },
"inboundNATRuleFrontendStartingPort": { "value": "[variables('sshNATFrontEndStartingPort')]" },
"inboundNATRuleBackendPort": { "value": "[variables('sshPort')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionNetworkSecurityGroups')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('mnNsgName')]",
"location": "[variables('location')]",
"tags": {
"displayName": "NSG - Mining (MN)"
},
"properties": {
"securityRules": [
{
"name": "allow-nva-bootnodes",
"properties": {
"description": "Allows NVA Bootnodes access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"destinationAddressPrefix": "[variables('nvaNetPrefix')]",
"access": "Allow",
"priority": 100,
"direction": "Outbound"
}
},
{
"name": "block-internet-bootnodes",
"properties": {
"description": "Block Internet Bootnodes",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "Internet",
"access": "Deny",
"priority": 101,
"direction": "Outbound"
}
},
{
"name": "allow-nva-inbound",
"properties": {
"description": "Allow NVA inbound access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "[variables('nvaNetPrefix')]",
"destinationAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
}
]
}
},
{
"apiVersion": "[variables('apiVersionNetworkSecurityGroups')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('txNsgName')]",
"location": "[variables('location')]",
"tags": {
"displayName": "NSG - Transaction (TX)"
},
"properties": {
"securityRules": [
{
"name": "allow-ssh",
"properties": {
"description": "Allow SSH",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
},
{
"name": "allow-geth-rpc",
"properties": {
"description": "Allow geth RPC",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "8545",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 101,
"direction": "Inbound"
}
},
{
"name": "allow-etheradmin",
"properties": {
"description": "Allow etheradmin web service",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "3000",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 102,
"direction": "Inbound"
}
},
{
"name": "allow-nva-inbound",
"properties": {
"description": "Allow NVA inbound access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "[variables('nvaNetPrefix')]",
"destinationAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"access": "Allow",
"priority": 103,
"direction": "Inbound"
}
},
{
"name": "allow-nva-bootnodes",
"properties": {
"description": "Allows NVA Bootnodes access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"destinationAddressPrefix": "[variables('nvaNetPrefix')]",
"access": "Allow",
"priority": 100,
"direction": "Outbound"
}
},
{
"name": "block-internet-bootnodes",
"properties": {
"description": "Block Internet Bootnodes",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "Internet",
"access": "Deny",
"priority": 101,
"direction": "Outbound"
}
}
]
}
},
{
"apiVersion": "[variables('apiVersionVirtualNetworks')]",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('vNet').name]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('txNsgName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('mnNsgName'))]",
"[concat('Microsoft.Network/routeTables/', variables('routeTableName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('vNet').addressSpacePrefix]"
]
},
"subnets": "[take(variables('subnetPropertiesArray'), variables('numSubnets'))]"
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "txVMLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('vNet').name)]",
"[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]",
"loadBalancerLinkedTemplate"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/txVMAuth', '-', parameters('authType'), '.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines": { "value": "[variables('apiVersionVirtualMachines')]" },
"apiVersionNetworkInterfaces": { "value": "[variables('apiVersionNetworkInterfaces')]" },
"apiVersionStorageAccounts": { "value": "[variables('apiVersionStorageAccounts')]" },
"loadBalancerName": { "value": "[variables('loadBalancerName')]" },
"loadBalancerBackendAddressPoolName": { "value": "[variables('loadBalancerBackendAddressPoolName')]" },
"loadBalancerInboundNatRuleNamePrefix": { "value": "[variables('loadBalancerInboundNatRuleNamePrefix')]" },
"txSubnetRef": { "value": "[variables('txSubnetRef')]" },
"txVMNamePrefix": { "value": "[variables('txVMNamePrefix')]" },
"numTXNodes": { "value": "[parameters('numTXNodes')]" },
"txStorageAcctName": { "value": "[variables('txStorageAcctName')]" },
"txNIPrefix": { "value": "[variables('txNIPrefix')]" },
"storageAccountType": { "value": "[parameters('txStorageAccountType')]" },
"availabilitySetName": { "value": "[variables('availabilitySetName')]" },
"txNodeVMSize": { "value": "[parameters('txNodeVMSize')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"adminPassword": { "value": "[parameters('adminPassword')]" },
"adminSSHKey": { "value": "[parameters('adminSSHKey')]" },
"ubuntuImage": { "value": "[variables('ubuntuImage')]" },
"namingInfix": { "value": "[variables('namingInfix')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "mnVMLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('vNet').name)]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/mnVMAuth', '-', parameters('authType'), '.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines": { "value": "[variables('apiVersionVirtualMachines')]" },
"apiVersionNetworkInterfaces": { "value": "[variables('apiVersionNetworkInterfaces')]" },
"apiVersionStorageAccounts": { "value": "[variables('apiVersionStorageAccounts')]" },
"mnVMNamePrefix": { "value": "[variables('mnVMNamePrefix')]" },
"numMNNodes": { "value": "[variables('numMNNodes')]" },
"mnNICPrefix": { "value": "[variables('mnNICPrefix')]" },
"mnStorageAcctNames": { "value": "[variables('mnStorageAcctNames')]" },
"mnStorageAcctCount": { "value": "[variables('mnStorageAcctCount')]" },
"mnSubnetRefArray": { "value": "[variables('mnSubnetRefArray')]" },
"numConsortiumMembers": { "value": 1 },
"storageAccountType": { "value": "[parameters('mnStorageAccountType')]" },
"mnNodeVMSize": { "value": "[parameters('mnNodeVMSize')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"adminPassword": { "value": "[parameters('adminPassword')]" },
"adminSSHKey": { "value": "[parameters('adminSSHKey')]" },
"ubuntuImage": { "value": "[variables('ubuntuImage')]" },
"namingInfix": { "value": "[variables('namingInfix')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "nvaResources",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('vNet').name)]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/networkVirtualAppliance.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines": { "value": "[variables('apiVersionVirtualMachines')]" },
"apiVersionNetworkInterfaces": { "value": "[variables('apiVersionNetworkInterfaces')]" },
"apiVersionStorageAccounts": { "value": "[variables('apiVersionStorageAccounts')]" },
"nvaVMName": { "value": "[variables('nvaVMName')]" },
"nvaNICName": { "value": "[variables('nvaNICName')]" },
"nvaStorageAcctName": { "value": "[variables('nvaStorageAcctName')]" },
"nvaSubnetRef": { "value": "[variables('nvaSubnetRef')]" },
"storageAccountType": { "value": "[variables('nvaStorageAccountType')]" },
"nvaNodeVMSize": { "value": "[variables('nvaNodeVMSize')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"adminPassword": { "value": "[parameters('adminPassword')]" },
"windowsImage": { "value": "[variables('windowsImage')]" },
"namingInfix": { "value": "[variables('namingInfix')]" },
"nvaPublicIpName": { "value": "[variables('nvaPublicIpName')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "vmExtensionLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"txVMLinkedTemplate",
"mnVMLinkedTemplate"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/vmExtension.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"numBootNodes": { "value": 2 },
"txVMNamePrefix": { "value": "[variables('txVMNamePrefix')]" },
"numTXNodes": { "value": "[parameters('numTXNodes')]" },
"mnVMNamePrefix": { "value": "[variables('mnVMNamePrefix')]" },
"numMNNodes": { "value": "[variables('numMNNodes')]" },
"artifactsLocationURL": { "value": "[parameters('baseUrl')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"ethereumAccountPsswd": { "value": "[parameters('ethereumAccountPsswd')]" },
"ethereumAccountPassphrase": { "value": "[parameters('ethereumAccountPassphrase')]" },
"ethereumNetworkID": { "value": "[parameters('ethereumNetworkID')]" },
"consortiumMemberId": { "value": "[parameters('consortiumMemberId')]" },
"gethIPCPort": { "value": "[variables('gethIPCPort')]" },
"adminSitePort": { "value": "[variables('adminSitePort')]" },
"location": { "value": "[variables('location')]" },
"genesisBlock": { "value": "[variables('genesisBlock')]" },
"adminHash": { "value": "[variables('adminHash')]" }
}
}
}
],
"outputs": {
"admin-site": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
},
"ethereum-rpc-endpoint": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value, ':', variables('gethRPCPort'))]"
},
"ssh-to-first-tx-node": {
"type": "string",
"value": "[concat('ssh -p ', variables('sshNATFrontEndStartingPort'), ' ', parameters('adminUsername'), '@', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
},
"consortium-data": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
},
"member-nva-ipaddress": {
"type": "string",
"value": "[reference('nvaResources').outputs.nvaPrivateIpAddress.value]"
},
"member-nva-public-ipaddress": {
"type": "string",
"value": "[reference('nvaResources').outputs.nvaPublicIpAddress.value]"
},
"member-vnet-address-space": {
"type": "string",
"value": "[string(reference(variables('vNet').name).AddressSpace.AddressPrefixes[0])]"
},
"member-prefix": {
"type": "string",
"value": "[variables('namingInfix')]"
},
"member-routetable-name": {
"type": "string",
"value": "[variables('routeTableName')]"
}
}
}

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

@ -0,0 +1,600 @@
{
"handler": "Microsoft.Compute.MultiVm",
"version": "0.0.1-preview",
"parameters": {
"basics": [
{
"name": "namePrefix",
"type": "Microsoft.Common.TextBox",
"label": "Resource prefix",
"toolTip": "String used as a base for naming resources (6 alphanumeric characters or less). A unique hash is prepended to the string for some resources, while resource-specific information is appended.",
"constraints": {
"required": true,
"regex": "^[a-z][a-z0-9-]{1,5}$",
"validationMessage": "Resource prefix must be between 2 and 6 characters long, must begin with a lowercase letter, and can contain only numbers and lowercase letters."
}
},
{
"name": "adminUsername",
"type": "Microsoft.Compute.UserNameTextBox",
"label": "VM user name",
"defaultValue": "gethadmin",
"toolTip": "Admin username for all of the deployed virtual machines.",
"osPlatform": "Linux"
},
{
"name": "adminCredentials",
"type": "Microsoft.Compute.CredentialsCombo",
"label": {
"authenticationType": "Authentication type",
"password": "Password",
"confirmPassword": "Confirm password",
"sshPublicKey": "SSH public key"
},
"toolTip": {
"authenticationType": "",
"password": "VM password must be 12 characters and have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character.",
"sshPublicKey": ""
},
"constraints": {
"required": true
},
"options": {
"hideConfirmation": false
},
"osPlatform": "Linux"
}
],
"steps": [
{
"name": "NetworkSize",
"label": "Network size and performance",
"subLabel": {
"preValidation": "Define the number and size and nodes in the network",
"postValidation": "Done"
},
"bladeTitle": "Network Size and Performance",
"elements": [
{
"name": "consortiumMemberIdValue",
"type": "Microsoft.Common.TextBox",
"label": "Consortium Member Id",
"toolTip": "The Id associated with each member participating in the consortium network. Member Id should be unique across different members in the same network.",
"constraints": {
"required": true,
"regex": "^(?:25[0-5]|2[0-4]\\d|[01]\\d\\d|\\d?\\d)$",
"validationMessage": "Must be between 0 and 255"
},
"visible": "true"
},
{
"name": "mnSection",
"type": "Microsoft.Common.Section",
"label": "Mining Nodes",
"elements": [
{
"name": "numberOfMiningNodes",
"type": "Microsoft.Common.DropDown",
"label": "Number of mining nodes per member",
"defaultValue": "2",
"toolTip": "Mining nodes record transactions within a blockchain network. Choose the number of nodes that meet your availability and security requirements.",
"constraints": {
"allowedValues": [
{
"label": "2",
"value": 2
},
{
"label": "3",
"value": 3
},
{
"label": "4",
"value": 4
},
{
"label": "5",
"value": 5
},
{
"label": "6",
"value": 6
},
{
"label": "7",
"value": 7
},
{
"label": "8",
"value": 8
},
{
"label": "9",
"value": 9
},
{
"label": "10",
"value": 10
},
{
"label": "11",
"value": 11
},
{
"label": "12",
"value": 12
},
{
"label": "13",
"value": 13
},
{
"label": "14",
"value": 14
},
{
"label": "15",
"value": 15
}
]
},
"visible": true
},
{
"name": "mnStoragePerformance",
"type": "Microsoft.Common.OptionsGroup",
"label": "Mining node storage performance",
"defaultValue": "Standard",
"toolTip": "Standard storage is backed by magnetic drives and provides the lowest cost per GB. Premium storage accounts are backed by solid state drives and offer consistent, low-latency performance. They can only be used with Azure virtual machine disks, and are best for I/O-intensive applications. This setting can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-introduction/#introducing-the-azure-storage-services)",
"constraints": {
"allowedValues": [
{
"label": "Standard",
"value": "Standard"
},
{
"label": "Premium",
"value": "Premium"
}
]
},
"visible": true
},
{
"name": "mnStorageReplication-Standard",
"type": "Microsoft.Common.DropDown",
"label": "Mining node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
},
{
"label": "Geo-redundant storage (GRS)",
"value": "GRS"
},
{
"label": "Read-access geo-redundant storage (RAGRS)",
"value": "RAGRS"
}
]
},
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Standard')]"
},
{
"name": "mnStorageReplication-Premium",
"type": "Microsoft.Common.DropDown",
"label": "Mining node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
}
]
},
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Premium')]"
},
{
"name": "mnNodeVMSizeHDD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Mining node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_D1_v2",
"Standard_D1",
"Standard_A1"
],
"constraints": {
"allowedSizes": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_A8",
"Standard_A9",
"Standard_A10",
"Standard_A11",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Standard')]"
},
{
"name": "mnNodeVMSizeSSD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Mining node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_DS1_v2",
"Standard_DS1",
"Standard_F1s"
],
"constraints": {
"allowedSizes": [
"Standard_DS1",
"Standard_DS2",
"Standard_DS3",
"Standard_DS4",
"Standard_DS11",
"Standard_DS12",
"Standard_DS13",
"Standard_DS14",
"Standard_DS1_v2",
"Standard_DS2_v2",
"Standard_DS3_v2",
"Standard_DS4_v2",
"Standard_DS5_v2",
"Standard_DS11_v2",
"Standard_DS12_v2",
"Standard_DS13_v2",
"Standard_DS14_v2",
"Standard_DS15_v2",
"Standard_F1s",
"Standard_F2s",
"Standard_F4s",
"Standard_F8s",
"Standard_F16s"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"visible": "[equals(steps('NetworkSize').mnSection.mnStoragePerformance, 'Premium')]"
}
]
},
{
"name": "txSection",
"type": "Microsoft.Common.Section",
"label": "Transaction Nodes",
"elements": [
{
"name": "numTXNodes",
"type": "Microsoft.Common.DropDown",
"label": "Number of load balanced transaction nodes",
"defaultValue": "1",
"toolTip": "An application or user interacts with a load balanced set of transaction nodes to submit transactions to the network. Choose the number of nodes that meets your availability requirements.",
"constraints": {
"allowedValues": [
{
"label": "1",
"value": 1
},
{
"label": "2",
"value": 2
},
{
"label": "3",
"value": 3
},
{
"label": "4",
"value": 4
},
{
"label": "5",
"value": 5
}
]
},
"visible": true
},
{
"name": "txStoragePerformance",
"type": "Microsoft.Common.OptionsGroup",
"label": "Transaction node storage performance",
"defaultValue": "Standard",
"toolTip": "Standard storage is backed by magnetic drives and provides the lowest cost per GB. Premium storage accounts are backed by solid state drives and offer consistent, low-latency performance. They can only be used with Azure virtual machine disks, and are best for I/O-intensive applications. This setting can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-introduction/#introducing-the-azure-storage-services)",
"constraints": {
"allowedValues": [
{
"label": "Standard",
"value": "Standard"
},
{
"label": "Premium",
"value": "Premium"
}
]
},
"visible": true
},
{
"name": "txStorageReplication-Standard",
"type": "Microsoft.Common.DropDown",
"label": "Transaction node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
},
{
"label": "Geo-redundant storage (GRS)",
"value": "GRS"
},
{
"label": "Read-access geo-redundant storage (RAGRS)",
"value": "RAGRS"
}
]
},
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Standard')]"
},
{
"name": "txStorageReplication-Premium",
"type": "Microsoft.Common.DropDown",
"label": "Transaction node storage replication",
"defaultValue": "Locally-redundant storage (LRS)",
"toolTip": "Data Azure storage is always replicated to ensure durability and high availability. Choose a replication strategy that matches your durability requirements. Some settings can't be changed after the storage account is created. [Learn more](https://azure.microsoft.com/documentation/articles/storage-redundancy/)",
"constraints": {
"allowedValues": [
{
"label": "Locally-redundant storage (LRS)",
"value": "LRS"
}
]
},
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Premium')]"
},
{
"name": "txNodeVMSizeHDD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Transaction node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_D1_v2",
"Standard_D1",
"Standard_A1"
],
"constraints": {
"allowedSizes": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_A8",
"Standard_A9",
"Standard_A10",
"Standard_A11",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').txSection.numTXNodes]",
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Standard')]"
},
{
"name": "txNodeVMSizeSSD",
"type": "Microsoft.Compute.SizeSelector",
"label": "Transaction node virtual machine size",
"toolTip": "",
"recommendedSizes": [
"Standard_DS1_v2",
"Standard_DS1",
"Standard_F1s"
],
"constraints": {
"allowedSizes": [
"Standard_DS1",
"Standard_DS2",
"Standard_DS3",
"Standard_DS4",
"Standard_DS11",
"Standard_DS12",
"Standard_DS13",
"Standard_DS14",
"Standard_DS1_v2",
"Standard_DS2_v2",
"Standard_DS3_v2",
"Standard_DS4_v2",
"Standard_DS5_v2",
"Standard_DS11_v2",
"Standard_DS12_v2",
"Standard_DS13_v2",
"Standard_DS14_v2",
"Standard_DS15_v2",
"Standard_F1s",
"Standard_F2s",
"Standard_F4s",
"Standard_F8s",
"Standard_F16s"
],
"excludedSizes": []
},
"osPlatform": "Linux",
"count": "[steps('NetworkSize').txSection.numTXNodes]",
"visible": "[equals(steps('NetworkSize').txSection.txStoragePerformance, 'Premium')]"
}
]
}
]
},
{
"name": "EthereumSettings",
"label": "Ethereum Settings",
"subLabel": {
"preValidation": "Configure the Ethereum nodes",
"postValidation": "Done"
},
"bladeTitle": "Ethereum Settings",
"elements": [
{
"name": "consortiumInformation",
"type": "Microsoft.Common.TextBox",
"label": "Consortium Data Location",
"defaultValue": "",
"toolTip": "The URL pointing to consortium configuration data provided by another member's deployment",
"constraints": {
"required": true
},
"visible": "true"
},
{
"name": "consortiumMemberGateway",
"type": "Microsoft.Common.TextBox",
"label": "VNet Gateway to Connect to",
"defaultValue": "",
"toolTip": "The resource path of the VNet Gateway to which to connect. This information is provided by an already connected member who has a deployment",
"constraints": {
"required": true
},
"visible": "true"
},
{
"name": "connectionSharedKey",
"type": "Microsoft.Common.TextBox",
"label": "Shared Key for Connection",
"defaultValue": "",
"toolTip": "A mixture of letters and numbers, used to establish encryption for the connection. The same shared key must be used in both the virtual network gateways",
"constraints": {
"required": true,
"regex": "^[A-Za-z0-9]{1,128}$",
"validationMessage": "Must only be letters and numbers between 1 and 128 characters."
},
"visible": "true"
},
{
"name": "ethereumAccountPsswd",
"type": "Microsoft.Common.PasswordBox",
"label": {
"password": "Ethereum account password",
"confirmPassword": "Confirm password"
},
"toolTip": "Password used to secure the default Ethereum account that will be generated.",
"constraints": {
"required": true,
"regex": "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[^\"]{12,}$",
"validationMessage": "Password must be 12 characters or more with a minimum of 1 lower case, 1 upper case and one number. Double quotes are not allowed."
},
"options": {
"hideConfirmation": false
},
"visible": true
},
{
"name": "ethereumAccountPassphrase",
"type": "Microsoft.Common.PasswordBox",
"label": {
"password": "Ethereum private key passphrase",
"confirmPassword": "Confirm passphrase"
},
"toolTip": "Passphrase used to generate the private key associated with the default Ethereum account that is generated. Consider a passphrase with sufficient randomness to ensure a strong private key.",
"constraints": {
"required": true,
"regex": "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[^\"]{12,}$",
"validationMessage": "Password must be 12 characters or more with a minimum of 1 lower case, 1 upper case and one number. Double quotes are not allowed."
},
"options": {
"hideConfirmation": false
},
"visible": true
}
]
}
],
"outputs": {
"namePrefix": "[basics('namePrefix')]",
"authType": "[basics('adminCredentials').authenticationType]",
"adminUsername": "[basics('adminUsername')]",
"adminPassword": "[basics('adminCredentials').password]",
"adminSSHKey": "[basics('adminCredentials').sshPublicKey]",
"ethereumAccountPsswd": "[steps('EthereumSettings').ethereumAccountPsswd]",
"ethereumAccountPassphrase": "[steps('EthereumSettings').ethereumAccountPassphrase]",
"consortiumMemberId": "[int(steps('NetworkSize').consortiumMemberIdValue)]",
"numMiningNodes": "[steps('NetworkSize').mnSection.numberOfMiningNodes]",
"mnNodeVMSize": "[coalesce(steps('NetworkSize').mnSection.mnNodeVMSizeHDD, steps('NetworkSize').mnSection.mnNodeVMSizeSSD)]",
"mnStorageAccountType": "[concat(steps('NetworkSize').mnSection.mnStoragePerformance, '_', coalesce(steps('NetworkSize').mnSection.mnStorageReplication-Standard, steps('NetworkSize').mnSection.mnStorageReplication-Premium))]",
"numTXNodes": "[steps('NetworkSize').txSection.numTXNodes]",
"txNodeVMSize": "[coalesce(steps('NetworkSize').txSection.txNodeVMSizeHDD, steps('NetworkSize').txSection.txNodeVMSizeSSD)]",
"txStorageAccountType": "[concat(steps('NetworkSize').txSection.txStoragePerformance, '_', coalesce(steps('NetworkSize').txSection.txStorageReplication-Standard, steps('NetworkSize').txSection.txStorageReplication-Premium))]",
"consortiumData": "[steps('EthereumSettings').consortiumInformation]",
"location": "[location()]",
"consortiumMemberGateway": "[steps('EthereumSettings').consortiumMemberGateway]",
"connectionSharedKey": "[steps('EthereumSettings').connectionSharedKey]"
}
}
}

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

@ -0,0 +1,720 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"namePrefix": {
"type": "string",
"metadata": {
"description": "String used as a base for naming resources (6 alphanumeric characters or less). A unique hash is prepended to the string for some resources, while resource-specific information is appended."
},
"maxLength": 6
},
"authType": {
"type": "string",
"allowedValues": [
"password",
"sshPublicKey"
],
"metadata": {
"description": "Authorization type for SSH access to VMs"
}
},
"adminUsername": {
"type": "string",
"defaultValue": "gethadmin",
"metadata": {
"description": "Administrator username of each deployed VM (alphanumeric characters only)"
}
},
"adminPassword": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Administrator password for each deployed VM"
}
},
"adminSSHKey": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "SSH RSA public key file as a string"
}
},
"ethereumAccountPsswd": {
"type": "securestring",
"metadata": {
"description": "Password used to secure the default Ethereum account that will be generated"
}
},
"ethereumAccountPassphrase": {
"type": "securestring",
"metadata": {
"description": "Password used to generate the private key associated with the default Ethereum account that is generated. Consider a password with sufficient randomness to ensure a strong private key"
}
},
"consortiumMemberId": {
"type": "int",
"metadata": {
"description": "Unique Identifier for the current member of this consortium"
},
"minValue": 0,
"maxValue": 255
},
"numMiningNodes": {
"type": "int",
"defaultValue": 2,
"metadata": {
"description": "Number of mining nodes to create for each consortium member."
},
"minValue": 2,
"maxValue": 15
},
"mnNodeVMSize": {
"type": "string",
"defaultValue": "Standard_A1",
"allowedValues": [],
"metadata": {
"description": "Size of the virtual machine used for mining nodes"
}
},
"mnStorageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS",
"Premium_LRS"
],
"metadata": {
"description": "Type of storage accounts to create"
}
},
"numTXNodes": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Number of load balanced transaction nodes"
},
"minValue": 1,
"maxValue": 5
},
"txNodeVMSize": {
"type": "string",
"defaultValue": "Standard_A1",
"allowedValues": [],
"metadata": {
"description": "Size of the virtual machine for transaction nodes"
}
},
"txStorageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS",
"Premium_LRS"
],
"metadata": {
"description": "Type of storage accounts to create"
}
},
"consortiumData": {
"type": "string",
"metadata": {
"description": "The URL pointing to the consortium configuration data provided by another member's deployment"
}
},
"RemoteMemberVnetAddressSpace": {
"type": "string",
"metadata": {
"description": "The Address Space of the Consortium Member VNet to connect to"
}
},
"RemoteMemberNVAPublicIP": {
"type": "string",
"metadata": {
"description": "The Public IP address of the Consortium Member NVA to connect to"
}
},
"connectionSharedKey": {
"type": "string",
"metadata": {
"description": "Shared Key for the Gateway Connection"
}
},
"baseUrl": {
"type": "string",
"metadata": {
"description": "The base URL for dependent assets",
"artifactsBaseUrl": ""
},
"defaultValue": "https://raw.githubusercontent.com/Azure/AzureStack-QuickStart-Templates/master/ethereum-consortium-blockchain"
}
},
"variables": {
"apiVersionRouteTables": "2015-06-15",
"apiVersionDeployments": "2016-02-01",
"apiVersionStorageAccounts": "2015-06-15",
"apiVersionAvailabilitySets": "2016-03-30",
"apiVersionNetworkSecurityGroups": "2015-06-15",
"apiVersionNetworkInterfaces": "2015-06-15",
"apiVersionVirtualMachines": "2015-06-15",
"apiVersionVirtualNetworks": "2015-06-15",
"namingInfix": "[toLower(substring(concat(parameters('namePrefix'), uniqueString(resourceGroup().id)), 0, 9))]",
"availabilitySetName": "[concat(variables('namingInfix'), 'AvSet')]",
"httpPort": 80,
"adminSitePort": 3000,
"sshPort": 22,
"sshNATFrontEndStartingPort": 3000,
"gethRPCPort": 8545,
"gethIPCPort": 30303,
"routeTableName": "NVARouteTable",
"NvaRouteName": "[concat(variables('namingInfix'), '-Route')]",
"loadBalancerName": "[concat(variables('namingInfix'), '-LB')]",
"loadBalancerBackendAddressPoolName": "LoadBalancerBackend1",
"loadBalancerInboundNatRuleNamePrefix": "SSH-VM",
"location": "[resourceGroup().location]",
"numMNNodes": "[parameters('numMiningNodes')]",
"maxVMsPerStorageAcct": 20,
"mnStorageAcctCount": "[add(div(variables('numMNNodes'), variables('maxVMsPerStorageAcct')), 1)]",
"mnStorageAcctNames": [
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'mn')]"
],
"nvaNICName": "nic-nva",
"nvaVMName": "[concat(variables('namingInfix'), '-nva')]",
"vpnName": "[concat('v', uniqueString(resourceGroup().id), '-vpn')]",
"nvaStorageAcctName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'nva')]",
"nvaStorageAccountType": "Standard_LRS",
"nvaNodeVMSize": "Standard_A1",
"nvaPublicIpName": "nvaPip",
"nvaSubnetName": "[concat(uniqueString(concat(resourceGroup().id, concat(variables('namingInfix'), 'subnet')), 'nva'))]",
"nvaSubnetPrefix": "[replace('10._.14.0/27','_', string(parameters('consortiumMemberId')))]",
"nvaPrivateIp": "[replace('10._.14.4','_', string(parameters('consortiumMemberId')))]",
"nvaNetPrefix": "10.0.0.0/12",
"mnVMNamePrefix": "[concat(variables('namingInfix'), '-mn')]",
"mnNICPrefix": "nic-mn",
"txStorageAcctName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'tx')]",
"txVMNamePrefix": "[concat(variables('namingInfix'), '-tx')]",
"txSubnetName": "[concat(uniqueString(concat(resourceGroup().id, concat(variables('namingInfix'), 'subnet')), 'tx'))]",
"txSubnetPrefix": "[replace('10._.0.0/24','_', string(parameters('consortiumMemberId')))]",
"txNIPrefix": "nic-tx",
"txNsgName": "[concat(variables('namingInfix'), 'TXNsg')]",
"mnNsgName": "[concat(variables('namingInfix'), 'MNNsg')]",
"mnSubnetName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'snet-mn0')]",
"mnSubnetPrefix": "[replace('10._.1.0/24','_', string(parameters('consortiumMemberId')))]",
"subnetPropertiesArray": [
{
"name": "[variables('txSubnetName')]",
"properties": {
"addressPrefix": "[variables('txSubnetPrefix')]",
"routeTable": {
"id": "[resourceId ('Microsoft.Network/routeTables', variables('routeTableName'))]"
},
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('txNsgName'))]"
}
}
},
{
"name": "[variables('mnSubnetName')]",
"properties": {
"addressPrefix": "[variables('mnSubnetPrefix')]",
"routeTable": {
"id": "[resourceId ('Microsoft.Network/routeTables', variables('routeTableName'))]"
},
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mnNsgName'))]"
}
}
},
{
"name": "[variables('nvaSubnetName')]",
"properties": {
"addressPrefix": "[replace('10._.14.0/27','_',string(parameters('consortiumMemberId')))]"
}
}
],
"ubuntuImage": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "16.04-LTS",
"version": "latest"
},
"windowsImage": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2016-Datacenter",
"version": "latest"
},
"vNet": {
"name": "[concat('vNet',string(parameters('consortiumMemberId')),'-', resourceGroup().location)]",
"addressSpacePrefix": "[replace('10._.0.0/20', '_',string(parameters('consortiumMemberId')))]",
"subnetName": "[concat('subnet-', resourceGroup().location, variables('namingInfix'))]",
"subnetPrefix": "[replace('10._.1.0/24','_', string(parameters('consortiumMemberId')))]",
"asn": "[add(parameters('consortiumMemberId'),65050)]"
},
"vnetRef": "[resourceId('Microsoft.Network/virtualNetworks',variables('vNet').name)]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', variables('vNet').name)]",
"txSubnetRef": "[concat(variables('vnetID'),'/subnets/', variables('txSubnetName'))]",
"memberVNetRef": "[resourceId('Microsoft.Network/virtualNetworks',variables('vNet').name)]",
"mnSubnetRefArray": [
"[concat(variables('vnetID'),'/subnets/', variables('mnSubnetName'))]"
],
"nvaSubnetRef": "[concat(variables('vnetID'),'/subnets/', variables('nvaSubnetName'))]"
},
"resources": [
{
"apiVersion": "[variables('apiVersionAvailabilitySets')]",
"type": "Microsoft.Compute/availabilitySets",
"name": "[variables('availabilitySetName')]",
"location": "[variables('location')]",
"properties": {}
},
{
"apiVersion": "[variables('apiVersionRouteTables')]",
"type": "Microsoft.Network/routeTables",
"name": "[variables('routeTableName')]",
"location": "[variables('location')]",
"properties": {}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "loadBalancerLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/loadBalancer.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"loadBalancerName": { "value": "[variables('loadBalancerName')]" },
"dnsHostName": { "value": "[variables('namingInfix')]" },
"loadBalancerBackendAddressPoolName": { "value": "[variables('loadBalancerBackendAddressPoolName')]" },
"loadBalancerInboundNatRuleNamePrefix": { "value": "[variables('loadBalancerInboundNatRuleNamePrefix')]" },
"frontendPort1": { "value": "[variables('httpPort')]" },
"backendPort1": { "value": "[variables('adminSitePort')]" },
"frontendPort2": { "value": "[variables('gethRPCPort')]" },
"backendPort2": { "value": "[variables('gethRPCPort')]" },
"numInboundNATRules": { "value": "[parameters('numTXNodes')]" },
"inboundNATRuleFrontendStartingPort": { "value": "[variables('sshNATFrontEndStartingPort')]" },
"inboundNATRuleBackendPort": { "value": "[variables('sshPort')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionNetworkSecurityGroups')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('mnNsgName')]",
"location": "[variables('location')]",
"tags": {
"displayName": "NSG - Mining (MN)"
},
"properties": {
"securityRules": [
{
"name": "allow-nva-bootnodes",
"properties": {
"description": "Allows NVA Bootnodes access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"destinationAddressPrefix": "[variables('nvaNetPrefix')]",
"access": "Allow",
"priority": 100,
"direction": "Outbound"
}
},
{
"name": "block-internet-bootnodes",
"properties": {
"description": "Block Internet Bootnodes",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "Internet",
"access": "Deny",
"priority": 101,
"direction": "Outbound"
}
},
{
"name": "allow-nva-inbound",
"properties": {
"description": "Allow NVA inbound access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "[variables('nvaNetPrefix')]",
"destinationAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
}
]
}
},
{
"apiVersion": "[variables('apiVersionNetworkSecurityGroups')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('txNsgName')]",
"location": "[variables('location')]",
"tags": {
"displayName": "NSG - Transaction (TX)"
},
"properties": {
"securityRules": [
{
"name": "allow-ssh",
"properties": {
"description": "Allow SSH",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
},
{
"name": "allow-geth-rpc",
"properties": {
"description": "Allow geth RPC",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "8545",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 101,
"direction": "Inbound"
}
},
{
"name": "allow-etheradmin",
"properties": {
"description": "Allow etheradmin web service",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "3000",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 102,
"direction": "Inbound"
}
},
{
"name": "allow-nva-inbound",
"properties": {
"description": "Allow NVA inbound access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "[variables('nvaNetPrefix')]",
"destinationAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"access": "Allow",
"priority": 103,
"direction": "Inbound"
}
},
{
"name": "allow-nva-bootnodes",
"properties": {
"description": "Allows NVA Bootnodes access",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "[variables('vNet').addressSpacePrefix]",
"destinationAddressPrefix": "[variables('nvaNetPrefix')]",
"access": "Allow",
"priority": 100,
"direction": "Outbound"
}
},
{
"name": "block-bootnodes",
"properties": {
"description": "Block Internet Bootnodes",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "[variables('gethIPCPort')]",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "Internet",
"access": "Deny",
"priority": 101,
"direction": "Outbound"
}
}
]
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('vNet').name]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('txNsgName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('mnNsgName'))]",
"[concat('Microsoft.Network/routeTables/', variables('routeTableName'))]"
],
"comments": "This is my vNet",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('vNet').addressSpacePrefix]"
]
},
"subnets": "[variables('subnetPropertiesArray')]"
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "txVMLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('vNet').name)]",
"[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]",
"loadBalancerLinkedTemplate"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/txVMAuth', '-', parameters('authType'), '.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines": { "value": "[variables('apiVersionVirtualMachines')]" },
"apiVersionNetworkInterfaces": { "value": "[variables('apiVersionNetworkInterfaces')]" },
"apiVersionStorageAccounts": { "value": "[variables('apiVersionStorageAccounts')]" },
"loadBalancerName": { "value": "[variables('loadBalancerName')]" },
"loadBalancerBackendAddressPoolName": { "value": "[variables('loadBalancerBackendAddressPoolName')]" },
"loadBalancerInboundNatRuleNamePrefix": { "value": "[variables('loadBalancerInboundNatRuleNamePrefix')]" },
"txSubnetRef": { "value": "[variables('txSubnetRef')]" },
"txVMNamePrefix": { "value": "[variables('txVMNamePrefix')]" },
"numTXNodes": { "value": "[parameters('numTXNodes')]" },
"txStorageAcctName": { "value": "[variables('txStorageAcctName')]" },
"txNIPrefix": { "value": "[variables('txNIPrefix')]" },
"storageAccountType": { "value": "[parameters('txStorageAccountType')]" },
"availabilitySetName": { "value": "[variables('availabilitySetName')]" },
"txNodeVMSize": { "value": "[parameters('txNodeVMSize')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"adminPassword": { "value": "[parameters('adminPassword')]" },
"adminSSHKey": { "value": "[parameters('adminSSHKey')]" },
"ubuntuImage": { "value": "[variables('ubuntuImage')]" },
"namingInfix": { "value": "[variables('namingInfix')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "mnVMLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('vNet').name)]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/mnVMAuth', '-', parameters('authType'), '.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines": { "value": "[variables('apiVersionVirtualMachines')]" },
"apiVersionNetworkInterfaces": { "value": "[variables('apiVersionNetworkInterfaces')]" },
"apiVersionStorageAccounts": { "value": "[variables('apiVersionStorageAccounts')]" },
"mnVMNamePrefix": { "value": "[variables('mnVMNamePrefix')]" },
"numMNNodes": { "value": "[variables('numMNNodes')]" },
"mnNICPrefix": { "value": "[variables('mnNICPrefix')]" },
"mnStorageAcctNames": { "value": "[variables('mnStorageAcctNames')]" },
"mnStorageAcctCount": { "value": "[variables('mnStorageAcctCount')]" },
"mnSubnetRefArray": { "value": "[variables('mnSubnetRefArray')]" },
"numConsortiumMembers": { "value": 1 },
"storageAccountType": { "value": "[parameters('mnStorageAccountType')]" },
"mnNodeVMSize": { "value": "[parameters('mnNodeVMSize')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"adminPassword": { "value": "[parameters('adminPassword')]" },
"adminSSHKey": { "value": "[parameters('adminSSHKey')]" },
"ubuntuImage": { "value": "[variables('ubuntuImage')]" },
"namingInfix": { "value": "[variables('namingInfix')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "nvaResources",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('vNet').name)]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/networkVirtualAppliance.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines": { "value": "[variables('apiVersionVirtualMachines')]" },
"apiVersionNetworkInterfaces": { "value": "[variables('apiVersionNetworkInterfaces')]" },
"apiVersionStorageAccounts": { "value": "[variables('apiVersionStorageAccounts')]" },
"nvaVMName": { "value": "[variables('nvaVMName')]" },
"nvaNICName": { "value": "[variables('nvaNICName')]" },
"nvaStorageAcctName": { "value": "[variables('nvaStorageAcctName')]" },
"nvaSubnetRef": { "value": "[variables('nvaSubnetRef')]" },
"storageAccountType": { "value": "[variables('nvaStorageAccountType')]" },
"nvaNodeVMSize": { "value": "[variables('nvaNodeVMSize')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"adminPassword": { "value": "[parameters('adminPassword')]" },
"windowsImage": { "value": "[variables('windowsImage')]" },
"namingInfix": { "value": "[variables('namingInfix')]" },
"nvaPublicIpName": { "value": "[variables('nvaPublicIpName')]" },
"location": { "value": "[variables('location')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"type": "Microsoft.Resources/deployments",
"name": "updateRouteTable",
"dependsOn": [
"nvaResources"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"apiVersion": "[variables('apiVersionRouteTables')]",
"name": "[variables('routeTableName')]",
"location": "[variables('location')]",
"type": "Microsoft.Network/routeTables",
"properties": {
"routes": [
{
"name": "[variables('NvaRouteName')]",
"properties": {
"addressPrefix": "[parameters('RemoteMemberVnetAddressSpace')]",
"nextHopType": "VirtualAppliance",
"nextHopIpAddress": "[reference('nvaResources').outputs.nvaPrivateIpAddress.value]"
}
}
]
}
}
]
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "nvaExtension",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"nvaResources"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/joiningNVAExtension.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"nvaVMName": {"value": "[variables('nvaVMName')]" },
"location": {"value": "[variables('location')]" },
"remoteIpAddress": { "value": "[parameters('RemoteMemberNVAPublicIP')]" },
"remoteAddressSpace": { "value": "[parameters('RemoteMemberVnetAddressSpace')]" },
"sharedKey": { "value": "[parameters('connectionSharedKey')]" },
"vpnName": { "value": "[variables('vpnName')]" },
"artifactsLocationURL": { "value": "[parameters('baseUrl')]" }
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "vmExtensionLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"txVMLinkedTemplate",
"mnVMLinkedTemplate"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('baseUrl'), '/nested/joiningVmExtension.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"numBootNodes": { "value": 2 },
"txVMNamePrefix": { "value": "[variables('txVMNamePrefix')]" },
"numTXNodes": { "value": "[parameters('numTXNodes')]" },
"mnVMNamePrefix": { "value": "[variables('mnVMNamePrefix')]" },
"numMNNodes": { "value": "[variables('numMNNodes')]" },
"artifactsLocationURL": { "value": "[parameters('baseUrl')]" },
"adminUsername": { "value": "[parameters('adminUsername')]" },
"ethereumAccountPsswd": { "value": "[parameters('ethereumAccountPsswd')]" },
"ethereumAccountPassphrase": { "value": "[parameters('ethereumAccountPassphrase')]" },
"consortiumData": { "value": "[parameters('consortiumData')]" },
"consortiumMemberId": { "value": "[parameters('consortiumMemberId')]" },
"gethIPCPort": { "value": "[variables('gethIPCPort')]" },
"adminSitePort": { "value": "[variables('adminSitePort')]" },
"location": { "value": "[variables('location')]" }
}
}
}
],
"outputs": {
"admin-site": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
},
"ethereum-rpc-endpoint": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value, ':', variables('gethRPCPort'))]"
},
"ssh-to-first-tx-node": {
"type": "string",
"value": "[concat('ssh -p ', variables('sshNATFrontEndStartingPort'), ' ', parameters('adminUsername'), '@', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
},
"consortium-data": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
},
"member-nva-ipaddress": {
"type": "string",
"value": "[reference('nvaResources').outputs.nvaPrivateIpAddress.value]"
},
"member-nva-public-ipaddress": {
"type": "string",
"value": "[reference('nvaResources').outputs.nvaPublicIpAddress.value]"
},
"member-vnet-address-space": {
"type": "string",
"value": "[string(reference(variables('vNet').name).AddressSpace.AddressPrefixes[0])]"
},
"member-prefix": {
"type": "string",
"value": "[variables('namingInfix')]"
},
"member-routetable-name": {
"type": "string",
"value": "[variables('routeTableName')]"
}
}
}

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

@ -0,0 +1,100 @@
<p><b>MICROSOFT TERMS OF USE</b></p>
<p><b>MICROSOFT-PUBLISHED ETHEREUM BLOCKCHAIN SOLUTION TEMPLATE FOR USE IN MICROSOFT AZURE</b></p>
<p>These terms of use are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. They apply to the solution templates named below (each a &quot;solution template&quot;) and described below. The terms also apply to any Microsoft</p>
<ul>
<li>updates,</li>
<li>supplements,</li>
<li>Internet-based services, and</li>
<li>support services</li>
</ul>
<p>for this solution template, unless other terms accompany those items. If so, those terms apply.</p>
<p><b>By using the solution template, you accept these terms. If you do not accept them,
do not use the solution template.</b></p>
<p><b>As described below, using some features also operates as your consent to the transmission of certain standard computer information for Internet-based services.</b></p>
<ol>
<li><b>DEFINITIONS</b></li>
<ol>
<li><b>&quot;solution template&quot;</b> means:
Ethereum Consortium Blockchain
Hyperledger Fabric Single Member Blockchain
<li><b>&quot;Customer Agreement&quot;</b> means the agreement under which you have obtained Microsoft Azure services from Microsoft or an authorized reseller or Microsoft affiliate.</li>
</ol>
<li><b>USE RIGHTS.</b></li>
<ol>
<li><b>Use within Microsoft Azure. </b>Subject to the terms and conditions of this agreement, Microsoft grants you a limited, non-exclusive, non-transferable right to use the solution template within Microsoft Azure.  Modification of the solution template is permitted provided that use of the modified solution template is internal and solely within Microsoft Azure. If you obtained access to software through the solution template, you may use the software only in virtual machines in Microsoft Azure deployed from the solution template. Use of Microsoft Azure resources and services deployed by the solution template shall be governed by your Customer Agreement.</li>
<li><b>Ubuntu Server. </b>Each solution template deploys a network of 3 or more Azure Virtual Machines. Each Virtual Machine uses Ubuntu Server, an Azure Marketplace operating system virtual machine image published by Canonical. The Ethereum Consortium Blockchain solution template uses Ubuntu Server 16.04.0 LTS. The Hyperledger Fabric Single Member Blockchain solution template uses Ubuntu Server 16.04.0 LTS. Your use of the Ubuntu Server shall be governed by the terms embedded in or accompanying that image. More information can be found <a href="https://azuremarketplace.microsoft.com/en-us/marketplace/apps/Canonical.UbuntuServer?tab=Overview">here</a>.</li>
<li><b>Third-Party Programs. </b>The solution template may download one or more of the third-party programs listed below to each Azure Virtual Machine. Your use of such programs will be governed by the terms embedded in or accompanying those programs.  In all cases, the disclaimers and limitations on exclusion of damages below also apply.</li>
<ol>
<li>The Ethereum Consortium Blockchain solution template may download the following:</li>
<ul>
<li>Go Ethereum Client</li>
<li>Git</li>
<li>Software Properties Common</li>
<li>NPM</li>
<li>NPM Packages:</li>
<ul>
<li>Express</li>
<li>Body Parser</li>
<li>Express Handlebars</li>
<li>Express Session</li>
<li>Moment</li>
<li>Promise</li>
<li>Web3</li>
</ul>
</ul>
<li>The Hyperledger Fabric Single Member Blockchain solution template may download the following:</li>
<ul>
<li>Hyperledger Fabric CA</li>
<li>Hyperledger Fabric Orderer</li>
<li>Hyperledger Fabric</li>
<li>Hyperledger Fabric Peer</li>
<li>Hyperledger CCenv</li>
<li>Hyperledger Fabric SDK Node</li>
<li>NodeJS</li>
<li>Build-Essential</li>
<li>Docker-CE</li>
<li>Git</li>
<li>Software Properties Common</li>
<li>NPM Packages:</li>
<ul>
<li>Gulp</li>
<li>Body-parser</li>
<li>Cookie-parser</li>
<li>Cors</li>
<li>Express</li>
<li>Express-JWT</li>
<li>Express-Session</li>
<li>Fabric-ca-client</li>
<li>Fabric-client</li>
<li>Log4js</li>
<li>Jsonwebtoken</li>
</ul>
</ul>
</ol>
</ol>
<li><b>SCOPE OF RIGHT. </b>This agreement only gives you some rights to use the solution template. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the solution template only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the solution template that only allow you to use it in certain ways. You may not
<ul>
<li>transfer the solution template to or use the solution template outside of Microsoft Azure, unless you have obtained such rights apart from this agreement;</li>
<li>work around any technical limitations in the solution template;</li>
<li>reverse engineer, decompile, or disassemble the solution template, except and only to the extent that this agreement or applicable law expressly permits, despite this limitation;</li>
<li>make more copies of the solution template than specified in this agreement or allowed by applicable law, despite this limitation;</li>
<li>publish the solution template for others to copy;</li>
<li>rent, lease, or lend the solution template; or</li>
<li>transfer the solution template or this agreement to any third party.</li>
</ul>
</li>
<li><b>INTERNET-BASED SERVICES. </b>Microsoft or its licensors may provide Internet-based services in connection with the solution template. &nbsp;For example, Microsoft or its licensors may configure the solution template to check occasionally for updates or supplements to the solution template.&nbsp; Microsoft or its licensors may change or cancel such Internet-based services, if any, at any time.  For more information on Microsoft Azure privacy practices, see <a href="http://go.microsoft.com/fwlink/p/?linkid=131004&amp;clcid=0x409">http://go.microsoft.com/fwlink/p/?linkid=131004&amp;clcid=0x409</a> and any disclosures within the solution template user interface, if any. This privacy statement does not apply to interned-based services or data collected by Ubuntu Server or any other third party programs deployed by the solution template.</li>
<li><b>EXPORT RESTRICTIONS. </b>The solution template is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the solution template or any direct product thereof. These laws include restrictions on destinations, end users, and end use. For additional information, see <a href="http://www.microsoft.com/exporting">www.microsoft.com/exporting</a></li>
<li><b>ENTIRE AGREEMENT. </b>This agreement, and the terms for supplements, updates, Internet-based services, and support services that you use, are the entire agreement for the solution template and support services, if any.</li>
<li><b>APPLICABLE LAW. </b>This agreement, including any claims for breach of it, will be governed by the laws of the state or country applicable to your Customer Agreement.</li>
<li><b>LEGAL EFFECT </b>This agreement describes certain legal rights. You may have other rights under the laws of your country. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.</li>
<li><b>DISCLAIMER OF WARRANTY. The solution template is provided &quot;as-is.&quot; You bear the risk of using it. Microsoft gives no express warranties, guarantees, or conditions. You may have additional consumer rights or statutory guarantees under your local laws that this agreement cannot change. To the extent permitted under your local laws, Microsoft excludes all implied warranties, including warranties of merchantability, fitness for a particular purpose, and non-infringement.
<p>FOR AUSTRALIA – You have statutory guarantees under the Australian Consumer Law, and nothing in these terms is intended to affect those rights.</p></b></li>
<li><b>LLIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. For any claim arising in connection with this agreement, you can recover from Microsoft only direct damages up to U.S. $5.00. You cannot recover from Microsoft any other damages, including consequential, special, indirect, punitive, incidental, or damages based on any loss of profits, revenue, data, or data use arising from or relating to the Microsoft Azure platform and the use of the solution template.</b>
<p>This limitation applies to</p>
<ul>
<li>anything related to the solution template, services, content (including code) on third-party Internet sites, or third-party programs; and</li>
<li>claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.</li>
</ul>
It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential, or other damages.</li>
</ol>

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

После

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

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

После

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

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

После

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

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

После

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

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

После

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

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

После

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

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

@ -0,0 +1,53 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"nvaVMName": {
"type": "string"
},
"location": {
"type": "string"
},
"remoteIpAddress": {
"type": "string"
},
"remoteAddressSpace": {
"type": "string"
},
"sharedKey": {
"type": "string"
},
"vpnName": {
"type": "string"
},
"artifactsLocationURL": {
"type": "string"
}
},
"variables": {
"apiVersionVirtualMachinesExtensions": "2016-03-30"
},
"resources": [
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('nvaVMName'), '/newuserscript')]",
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/CreateVPN.ps1')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('powershell.exe -ExecutionPolicy Unrestricted -Command .\\CreateVPN.ps1 -VPNName \"',parameters('vpnName'),'\" -RemoteIPAddress \"',parameters('remoteIpAddress'),'\" -AddressSpace \"',parameters('remoteAddressSpace'),'\" -SharedKey \"',parameters('sharedKey'),'\"')]"
}
}
}
]
}

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

@ -0,0 +1,104 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"numBootNodes": {
"type": "int"
},
"txVMNamePrefix": {
"type": "string"
},
"numTXNodes": {
"type": "int"
},
"mnVMNamePrefix": {
"type": "string"
},
"numMNNodes": {
"type": "int"
},
"artifactsLocationURL": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"ethereumAccountPsswd": {
"type": "securestring"
},
"ethereumAccountPassphrase": {
"type": "securestring"
},
"consortiumData": {
"type": "string"
},
"consortiumMemberId": {
"type": "int"
},
"gethIPCPort": {
"type": "int"
},
"adminSitePort": {
"type": "int"
},
"location": {
"type": "string"
}
},
"variables": {
"apiVersionVirtualMachinesExtensions": "2016-03-30",
"txNode": 0,
"mnNode": 1,
"maxPeers": 25
},
"resources": [
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('txVMNamePrefix'), copyIndex(), '/newuserscript')]",
"copy": {
"name": "txNodesConfigLoop",
"count": "[parameters('numTXNodes')]"
},
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Azure.Extensions",
"type": "CustomScript",
"typeHandlerVersion": "2.0",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/configure-geth-joining.sh')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('/bin/bash configure-geth-joining.sh \"', parameters('adminUsername'), '\" \"', parameters('ethereumAccountPsswd'), '\" \"', parameters('ethereumAccountPassphrase'), '\" \"', parameters('artifactsLocationURL'), '\" \"', parameters('consortiumData'), '\" \"', variables('maxPeers'), '\" \"', variables('txNode'), '\" \"', parameters('gethIPCPort'), '\" \"', parameters('numBootNodes'), '\" \"', parameters('numMNNodes'), '\" \"', parameters('mnVMNamePrefix'), '\" \"', parameters('numTXNodes'), '\" \"', parameters('txVMNamePrefix'), '\" \"', parameters('adminSitePort'), '\" \"', parameters('consortiumMemberId'), '\"')]"
}
}
},
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('mnVMNamePrefix'), copyIndex(), '/newuserscript')]",
"copy": {
"name": "bootMNNodesConfigLoop",
"count": "[parameters('numMNNodes')]"
},
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Azure.Extensions",
"type": "CustomScript",
"typeHandlerVersion": "2.0",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/configure-geth-joining.sh')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('/bin/bash configure-geth-joining.sh \"', parameters('adminUsername'), '\" \"', parameters('ethereumAccountPsswd'), '\" \"', parameters('ethereumAccountPassphrase'), '\" \"',parameters('artifactsLocationURL'), '\" \"', parameters('consortiumData'), '\" \"', variables('maxPeers'), '\" \"', variables('mnNode'), '\" \"', parameters('gethIPCPort'), '\" \"', parameters('numBootNodes'), '\" \"', parameters('numMNNodes'), '\" \"', parameters('mnVMNamePrefix'), '\" \"', copyIndex(), '\"')]"
}
}
}
]
}

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

@ -0,0 +1,104 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"numBootNodes": {
"type": "int"
},
"txVMNamePrefix": {
"type": "string"
},
"numTXNodes": {
"type": "int"
},
"mnVMNamePrefix": {
"type": "string"
},
"numMNNodes": {
"type": "int"
},
"artifactsLocationURL": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"ethereumAccountPsswd": {
"type": "securestring"
},
"ethereumAccountPassphrase": {
"type": "securestring"
},
"consortiumData": {
"type": "string"
},
"consortiumMemberId": {
"type": "int"
},
"gethIPCPort": {
"type": "int"
},
"adminSitePort": {
"type": "int"
},
"location": {
"type": "string"
}
},
"variables": {
"apiVersionVirtualMachinesExtensions": "2016-03-30",
"txNode": 0,
"mnNode": 1,
"maxPeers": 25
},
"resources": [
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('txVMNamePrefix'), copyIndex(), '/newuserscript')]",
"copy": {
"name": "txNodesConfigLoop",
"count": "[parameters('numTXNodes')]"
},
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"type": "CustomScriptForLinux",
"typeHandlerVersion": "1.5",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/configure-geth-joining.sh')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('/bin/bash configure-geth-joining.sh \"', parameters('adminUsername'), '\" \"', parameters('ethereumAccountPsswd'), '\" \"', parameters('ethereumAccountPassphrase'), '\" \"', parameters('artifactsLocationURL'), '\" \"', parameters('consortiumData'), '\" \"', variables('maxPeers'), '\" \"', variables('txNode'), '\" \"', parameters('gethIPCPort'), '\" \"', parameters('numBootNodes'), '\" \"', parameters('numMNNodes'), '\" \"', parameters('mnVMNamePrefix'), '\" \"', parameters('numTXNodes'), '\" \"', parameters('txVMNamePrefix'), '\" \"', parameters('adminSitePort'), '\" \"', parameters('consortiumMemberId'), '\"')]"
}
}
},
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('mnVMNamePrefix'), copyIndex(), '/newuserscript')]",
"copy": {
"name": "bootMNNodesConfigLoop",
"count": "[parameters('numMNNodes')]"
},
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"type": "CustomScriptForLinux",
"typeHandlerVersion": "1.5",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/configure-geth.sh')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('/bin/bash configure-geth-joining.sh \"', parameters('adminUsername'), '\" \"', parameters('ethereumAccountPsswd'), '\" \"', parameters('ethereumAccountPassphrase'), '\" \"',parameters('artifactsLocationURL'), '\" \"', parameters('consortiumData'), '\" \"', variables('maxPeers'), '\" \"', variables('mnNode'), '\" \"', parameters('gethIPCPort'), '\" \"', parameters('numBootNodes'), '\" \"', parameters('numMNNodes'), '\" \"', parameters('mnVMNamePrefix'), '\" \"', copyIndex(), '\"')]"
}
}
}
]
}

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

@ -0,0 +1,181 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"loadBalancerName": {
"type": "string"
},
"dnsHostName": {
"type": "string"
},
"loadBalancerBackendAddressPoolName": {
"type": "string"
},
"loadBalancerInboundNatRuleNamePrefix": {
"type": "string"
},
"frontendPort1": {
"type": "int"
},
"backendPort1": {
"type": "int"
},
"frontendPort2": {
"type": "int"
},
"backendPort2": {
"type": "int"
},
"numInboundNATRules": {
"type": "int"
},
"inboundNATRuleFrontendStartingPort": {
"type": "int"
},
"inboundNATRuleBackendPort": {
"type": "int"
},
"location": {
"type": "string"
}
},
"variables": {
"apiVersionPublicIPAddresses": "2015-06-15",
"apiVersionLoadBalancers": "2015-06-15",
"apiVersionLoadBalanceInboundNATRules": "2015-06-15",
"lbID": "[resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName'))]",
"lbPublicIPAddressName": "[concat(parameters('dnsHostName'), '-publicip')]",
"lbFrontEndIpConfigName": "LoadBalancerFrontEnd",
"lbFrontEndIPConfigID": "[concat(variables('lbID'),'/frontendIPConfigurations/',variables('lbFrontEndIpConfigName'))]",
"lbBackendAddressPoolID": "[concat(variables('lbID'), '/backendAddressPools/', parameters('loadBalancerBackendAddressPoolName'))]",
"loadBalancerInboundNatRuleIDprefix": "[concat(variables('lbID'),'/inboundNatRules/',parameters('loadBalancerInboundNatRuleNamePrefix'))]"
},
"resources": [
{
"apiVersion": "[variables('apiVersionPublicIPAddresses')]",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('lbPublicIPAddressName')]",
"location": "[parameters('location')]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsHostName')]"
}
}
},
{
"apiVersion": "[variables('apiVersionLoadBalancers')]",
"name": "[parameters('loadBalancerName')]",
"type": "Microsoft.Network/loadBalancers",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('lbPublicIPAddressName'))]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "[variables('lbFrontEndIpConfigName')]",
"properties": {
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses/', variables('lbPublicIPAddressName'))]"
}
}
}
],
"backendAddressPools": [
{
"name": "[parameters('loadBalancerBackendAddressPoolName')]"
}
],
"loadBalancingRules": [
{
"name": "LB-Rule1",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('lbFrontEndIPConfigID')]"
},
"backendAddressPool": {
"id": "[variables('lbBackendAddressPoolID')]"
},
"protocol": "Tcp",
"frontendPort": "[parameters('FrontendPort1')]",
"backendPort": "[parameters('BackendPort1')]",
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(variables('lbID'),'/probes/lbProbe1')]"
}
}
},
{
"name": "LB-Rule2",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('lbFrontEndIPConfigID')]"
},
"backendAddressPool": {
"id": "[variables('lbBackendAddressPoolID')]"
},
"protocol": "Tcp",
"frontendPort": "[parameters('FrontendPort2')]",
"backendPort": "[parameters('BackendPort2')]",
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[concat(variables('lbID'),'/probes/lbProbe2')]"
}
}
}
],
"probes": [
{
"name": "lbProbe1",
"properties": {
"protocol": "Tcp",
"port": "[parameters('BackendPort1')]",
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "lbProbe2",
"properties": {
"protocol": "Tcp",
"port": "[parameters('BackendPort2')]",
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
]
}
},
{
"apiVersion": "[variables('apiVersionLoadBalanceInboundNATRules')]",
"type": "Microsoft.Network/loadBalancers/inboundNatRules",
"name": "[concat(parameters('loadBalancerName'), '/', parameters('loadBalancerInboundNatRuleNamePrefix'), copyIndex())]",
"location": "[parameters('location')]",
"copy": {
"name": "lbNatLoop",
"count": "[parameters('numInboundNATRules')]"
},
"dependsOn": [
"[concat('Microsoft.Network/loadBalancers/', parameters('loadBalancerName'))]"
],
"properties": {
"frontendIPConfiguration": {
"id": "[variables('lbFrontEndIPConfigID')]"
},
"protocol": "tcp",
"frontendPort": "[copyIndex(parameters('inboundNATRuleFrontendStartingPort'))]",
"backendPort": "[parameters('inboundNATRuleBackendPort')]",
"enableFloatingIP": false
}
}
],
"outputs": {
"fqdn": {
"type": "string",
"value": "[reference(variables('lbPublicIPAddressName')).dnsSettings.fqdn]"
}
}
}

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

@ -0,0 +1,142 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiVersionVirtualMachines": {
"type": "string"
},
"apiVersionNetworkInterfaces": {
"type": "string"
},
"apiVersionStorageAccounts": {
"type": "string"
},
"mnVMNamePrefix": {
"type": "string"
},
"numMNNodes": {
"type": "int"
},
"mnNICPrefix": {
"type": "string"
},
"mnStorageAcctNames": {
"type": "array"
},
"mnStorageAcctCount": {
"type": "int"
},
"mnSubnetRefArray": {
"type": "array"
},
"numConsortiumMembers": {
"type": "int"
},
"storageAccountType": {
"type": "string"
},
"mnNodeVMSize": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"adminPassword": {
"type": "securestring"
},
"adminSSHKey": {
"type": "string"
},
"ubuntuImage": {
"type": "object"
},
"namingInfix": {
"type": "string"
},
"location": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "[parameters('apiVersionStorageAccounts')]",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('mnStorageAcctNames')[copyIndex()]]",
"location": "[parameters('location')]",
"copy": {
"name": "mnStorageLoop",
"count": "[parameters('mnStorageAcctCount')]"
},
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "Storage",
"properties": {}
},
{
"apiVersion": "[parameters('apiVersionNetworkInterfaces')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(parameters('mnNICPrefix'), copyindex())]",
"location": "[parameters('location')]",
"copy": {
"name": "mnNicLoop",
"count": "[parameters('numMNNodes')]"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[parameters('mnSubnetRefArray')[mod(copyIndex(), parameters('numConsortiumMembers'))]]"
}
}
}
]
}
},
{
"apiVersion": "[parameters('apiVersionVirtualMachines')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('mnVMNamePrefix'), copyIndex())]",
"location": "[parameters('location')]",
"copy": {
"name": "mnVMLoop",
"count": "[parameters('numMNNodes')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('mnStorageAcctNames')[mod(copyIndex(), parameters('mnStorageAcctCount'))])]",
"[concat('Microsoft.Network/networkInterfaces/', parameters('mnNICPrefix'), copyindex())]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('mnNodeVMSize')]"
},
"osProfile": {
"computerName": "[concat(parameters('mnVMNamePrefix'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": "[parameters('ubuntuImage')]",
"osDisk": {
"name": "[concat(parameters('namingInfix'), '-osdisk')]",
"vhd": {
"uri" :"[concat(reference(concat('Microsoft.Storage/storageAccounts/', parameters('mnStorageAcctNames')[mod(copyIndex(), parameters('mnStorageAcctCount'))]), parameters('apiVersionStorageAccounts')).primaryEndpoints.blob, 'vhds/osdisk', copyIndex(), '.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('mnNICPrefix'), copyindex()))]"
}
]
}
}
}
]
}

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

@ -0,0 +1,155 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiVersionVirtualMachines": {
"type": "string"
},
"apiVersionNetworkInterfaces": {
"type": "string"
},
"apiVersionStorageAccounts": {
"type": "string"
},
"mnVMNamePrefix": {
"type": "string"
},
"numMNNodes": {
"type": "int"
},
"mnNICPrefix": {
"type": "string"
},
"mnStorageAcctNames": {
"type": "array"
},
"mnStorageAcctCount": {
"type": "int"
},
"mnSubnetRefArray": {
"type": "array"
},
"numConsortiumMembers": {
"type": "int"
},
"storageAccountType": {
"type": "string"
},
"mnNodeVMSize": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"adminPassword": {
"type": "securestring"
},
"adminSSHKey": {
"type": "string"
},
"ubuntuImage": {
"type": "object"
},
"namingInfix": {
"type": "string"
},
"location": {
"type": "string"
}
},
"variables": {
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]"
},
"resources": [
{
"apiVersion": "[parameters('apiVersionStorageAccounts')]",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('mnStorageAcctNames')[copyIndex()]]",
"location": "[parameters('location')]",
"copy": {
"name": "mnStorageLoop",
"count": "[parameters('mnStorageAcctCount')]"
},
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "Storage",
"properties": {}
},
{
"apiVersion": "[parameters('apiVersionNetworkInterfaces')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(parameters('mnNICPrefix'), copyindex())]",
"location": "[parameters('location')]",
"copy": {
"name": "mnNicLoop",
"count": "[parameters('numMNNodes')]"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[parameters('mnSubnetRefArray')[mod(copyIndex(), parameters('numConsortiumMembers'))]]"
}
}
}
]
}
},
{
"apiVersion": "[parameters('apiVersionVirtualMachines')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('mnVMNamePrefix'), copyIndex())]",
"location": "[parameters('location')]",
"copy": {
"name": "mnVMLoop",
"count": "[parameters('numMNNodes')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('mnStorageAcctNames')[mod(copyIndex(), parameters('mnStorageAcctCount'))])]",
"[concat('Microsoft.Network/networkInterfaces/', parameters('mnNICPrefix'), copyindex())]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('mnNodeVMSize')]"
},
"osProfile": {
"computerName": "[concat(parameters('mnVMNamePrefix'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"linuxConfiguration": {
"disablePasswordAuthentication": "true",
"ssh": {
"publicKeys": [
{
"path": "[variables('sshKeyPath')]",
"keyData": "[parameters('adminSSHKey')]"
}
]
}
}
},
"storageProfile": {
"imageReference": "[parameters('ubuntuImage')]",
"osDisk": {
"name": "[concat(parameters('namingInfix'), '-osdisk')]",
"vhd": {
"uri" :"[concat(reference(concat('Microsoft.Storage/storageAccounts/', parameters('mnStorageAcctNames')[mod(copyIndex(), parameters('mnStorageAcctCount'))]), parameters('apiVersionStorageAccounts')).primaryEndpoints.blob, 'vhds/osdisk', copyIndex(), '.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('mnNICPrefix'), copyindex()))]"
}
]
}
}
}
]
}

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

@ -0,0 +1,149 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiVersionVirtualMachines": {
"type": "string"
},
"apiVersionNetworkInterfaces": {
"type": "string"
},
"apiVersionStorageAccounts": {
"type": "string"
},
"nvaVMName": {
"type": "string"
},
"nvaNICName": {
"type": "string"
},
"nvaStorageAcctName": {
"type": "string"
},
"nvaSubnetRef": {
"type": "string"
},
"storageAccountType": {
"type": "string"
},
"nvaNodeVMSize": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"adminPassword": {
"type": "securestring"
},
"windowsImage": {
"type": "object"
},
"namingInfix": {
"type": "string"
},
"nvaPublicIpName": {
"type": "string"
},
"location": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "[parameters('apiVersionStorageAccounts')]",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('nvaStorageAcctName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "Storage",
"properties": {}
},
{
"apiVersion": "[parameters('apiVersionNetworkInterfaces')]",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[parameters('nvaPublicIpName')]",
"location": "[parameters('location')]",
"properties": {
"publicIPAddressVersion": "IPv4",
"publicIPAllocationMethod": "Static",
"idleTimeoutInMinutes": 4
}
},
{
"apiVersion": "[parameters('apiVersionNetworkInterfaces')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[parameters('nvaNICName')]",
"dependsOn": [
"[resourceId('Microsoft.Network/publicIPAddresses',parameters('nvaPublicIpName'))]"
],
"location": "[parameters('location')]",
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[parameters('nvaSubnetRef')]"
},
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',parameters('nvaPublicIpName'))]"
}
}
}
]
}
},
{
"apiVersion": "[parameters('apiVersionVirtualMachines')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('nvaVMName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('nvaStorageAcctName'))]",
"[concat('Microsoft.Network/networkInterfaces/', parameters('nvaNICName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('nvaNodeVMSize')]"
},
"osProfile": {
"computerName": "[parameters('nvaVMName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": "[parameters('windowsImage')]",
"osDisk": {
"name": "[concat(parameters('namingInfix'), '-osdisk')]",
"vhd": {
"uri" :"[concat(reference(concat('Microsoft.Storage/storageAccounts/', parameters('nvaStorageAcctName')), parameters('apiVersionStorageAccounts')).primaryEndpoints.blob, 'vhds/osdisk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nvaNICName'))]"
}
]
}
}
}
],
"outputs":
{
"nvaPrivateIpAddress": {
"type": "string",
"value": "[string(reference(parameters('nvaNICName')).IpConfigurations[0].Properties.privateIPAddress)]"
},
"nvaPublicIpAddress": {
"type": "string",
"value": "[reference(concat('Microsoft.Network/publicIPAddresses/',parameters('nvaPublicIpName'))).ipAddress]"
}
}
}

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

@ -0,0 +1,162 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiVersionVirtualMachines": {
"type": "string"
},
"apiVersionNetworkInterfaces": {
"type": "string"
},
"apiVersionStorageAccounts": {
"type": "string"
},
"loadBalancerName": {
"type": "string"
},
"loadBalancerBackendAddressPoolName": {
"type": "string"
},
"loadBalancerInboundNatRuleNamePrefix": {
"type": "string"
},
"txSubnetRef": {
"type": "string"
},
"txVMNamePrefix": {
"type": "string"
},
"numTXNodes": {
"type": "int"
},
"txStorageAcctName": {
"type": "string"
},
"txNIPrefix": {
"type": "string"
},
"storageAccountType": {
"type": "string"
},
"availabilitySetName": {
"type": "string"
},
"txNodeVMSize": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"adminPassword": {
"type": "securestring"
},
"adminSSHKey": {
"type": "string"
},
"ubuntuImage": {
"type": "object"
},
"namingInfix": {
"type": "string"
},
"location": {
"type": "string"
}
},
"variables": {
"loadBalancerID": "[resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName'))]",
"loadBalancerBackendAddressPoolID": "[concat(variables('loadBalancerID'), '/backendAddressPools/', parameters('loadBalancerBackendAddressPoolName'))]",
"loadBalancerInboundNatRuleIDprefix": "[concat(variables('loadBalancerID'),'/inboundNatRules/',parameters('loadBalancerInboundNatRuleNamePrefix'))]"
},
"resources": [
{
"apiVersion": "[parameters('apiVersionNetworkInterfaces')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(parameters('txNIPrefix'), copyindex())]",
"location": "[parameters('location')]",
"copy": {
"name": "txNicLoop",
"count": "[parameters('numTXNodes')]"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[parameters('txSubnetRef')]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[variables('loadBalancerBackendAddressPoolID')]"
}
],
"loadBalancerInboundNatRules": [
{
"id": "[concat(variables('loadBalancerInboundNatRuleIDprefix'), copyindex())]"
}
]
}
}
]
}
},
{
"apiVersion": "[parameters('apiVersionStorageAccounts')]",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('txStorageAcctName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "Storage",
"properties": {}
},
{
"apiVersion": "[parameters('apiVersionVirtualMachines')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('txVMNamePrefix'), copyIndex())]",
"location": "[parameters('location')]",
"copy": {
"name": "txVMLoop",
"count": "[parameters('numTXNodes')]"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', parameters('txNIPrefix'), copyIndex())]",
"[concat('Microsoft.Storage/storageAccounts/', parameters('txStorageAcctName'))]"
],
"properties": {
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets',parameters('availabilitySetName'))]"
},
"hardwareProfile": {
"vmSize": "[parameters('txNodeVMSize')]"
},
"osProfile": {
"computerName": "[concat(parameters('txVMNamePrefix'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": "[parameters('ubuntuImage')]",
"osDisk": {
"name": "[concat(parameters('namingInfix'), '-osdisk')]",
"vhd": {
"uri" :"[concat(reference(concat('Microsoft.Storage/storageAccounts/', parameters('txStorageAcctName')), parameters('apiVersionStorageAccounts')).primaryEndpoints.blob, 'vhds/osdisk', copyIndex(), '.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('txNIPrefix'), copyindex()))]"
}
]
}
}
}
]
}

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

@ -0,0 +1,173 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiVersionVirtualMachines": {
"type": "string"
},
"apiVersionNetworkInterfaces": {
"type": "string"
},
"apiVersionStorageAccounts": {
"type": "string"
},
"loadBalancerName": {
"type": "string"
},
"loadBalancerBackendAddressPoolName": {
"type": "string"
},
"loadBalancerInboundNatRuleNamePrefix": {
"type": "string"
},
"txSubnetRef": {
"type": "string"
},
"txVMNamePrefix": {
"type": "string"
},
"numTXNodes": {
"type": "int"
},
"txStorageAcctName": {
"type": "string"
},
"txNIPrefix": {
"type": "string"
},
"storageAccountType": {
"type": "string"
},
"availabilitySetName": {
"type": "string"
},
"txNodeVMSize": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"adminPassword": {
"type": "securestring"
},
"adminSSHKey": {
"type": "string"
},
"ubuntuImage": {
"type": "object"
},
"namingInfix": {
"type": "string"
},
"location": {
"type": "string"
}
},
"variables": {
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
"loadBalancerID": "[resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName'))]",
"loadBalancerBackendAddressPoolID": "[concat(variables('loadBalancerID'), '/backendAddressPools/', parameters('loadBalancerBackendAddressPoolName'))]",
"loadBalancerInboundNatRuleIDprefix": "[concat(variables('loadBalancerID'),'/inboundNatRules/',parameters('loadBalancerInboundNatRuleNamePrefix'))]"
},
"resources": [
{
"apiVersion": "[parameters('apiVersionNetworkInterfaces')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(parameters('txNIPrefix'), copyindex())]",
"location": "[parameters('location')]",
"copy": {
"name": "txNicLoop",
"count": "[parameters('numTXNodes')]"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[parameters('txSubnetRef')]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[variables('loadBalancerBackendAddressPoolID')]"
}
],
"loadBalancerInboundNatRules": [
{
"id": "[concat(variables('loadBalancerInboundNatRuleIDprefix'), copyindex())]"
}
]
}
}
]
}
},
{
"apiVersion": "[parameters('apiVersionStorageAccounts')]",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('txStorageAcctName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "Storage",
"properties": {}
},
{
"apiVersion": "[parameters('apiVersionVirtualMachines')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('txVMNamePrefix'), copyIndex())]",
"location": "[parameters('location')]",
"copy": {
"name": "txVMLoop",
"count": "[parameters('numTXNodes')]"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', parameters('txNIPrefix'), copyIndex())]",
"[concat('Microsoft.Storage/storageAccounts/', parameters('txStorageAcctName'))]"
],
"properties": {
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets',parameters('availabilitySetName'))]"
},
"hardwareProfile": {
"vmSize": "[parameters('txNodeVMSize')]"
},
"osProfile": {
"computerName": "[concat(parameters('txVMNamePrefix'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"linuxConfiguration": {
"disablePasswordAuthentication": "true",
"ssh": {
"publicKeys": [
{
"path": "[variables('sshKeyPath')]",
"keyData": "[parameters('adminSSHKey')]"
}
]
}
}
},
"storageProfile": {
"imageReference": "[parameters('ubuntuImage')]",
"osDisk": {
"name": "[concat(parameters('namingInfix'), '-osdisk')]",
"vhd": {
"uri" :"[concat(reference(concat('Microsoft.Storage/storageAccounts/', parameters('txStorageAcctName')), parameters('apiVersionStorageAccounts')).primaryEndpoints.blob, 'vhds/osdisk', copyIndex(), '.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('txNIPrefix'), copyindex()))]"
}
]
}
}
}
]
}

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

@ -0,0 +1,44 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"nvaNicResourceId": {
"type": "string"
},
"routeTableName": {
"type": "string"
},
"remoteAddressSpace": {
"type": "string"
},
"artifactsLocationURL": {
"type": "string"
}
},
"variables": {
"apiVersionVirtualMachinesExtensions": "2016-03-30"
},
"resources": [
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "['routetable/newuserscript']",
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/UpdateRouteTable.ps1')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('powershell.exe -ExecutionPolicy Unrestricted -Command .\\UpdateRouteTable.ps1 -RouteTableName \"',parameters('routeTableName'),'\" -NicResourceId \"',parameters('nvaNicResourceId'),'\" -RemoteAddressSpace \"',parameters('remoteAddressSpace'),'\"')]"
}
}
}
]
}

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

@ -0,0 +1,110 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"numBootNodes": {
"type": "int"
},
"txVMNamePrefix": {
"type": "string"
},
"numTXNodes": {
"type": "int"
},
"mnVMNamePrefix": {
"type": "string"
},
"numMNNodes": {
"type": "int"
},
"artifactsLocationURL": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"ethereumAccountPsswd": {
"type": "securestring"
},
"ethereumAccountPassphrase": {
"type": "securestring"
},
"ethereumNetworkID": {
"type": "int"
},
"consortiumMemberId": {
"type": "int"
},
"gethIPCPort": {
"type": "int"
},
"adminSitePort": {
"type": "int"
},
"location": {
"type": "string"
},
"genesisBlock": {
"type": "string"
},
"adminHash": {
"type": "string"
}
},
"variables": {
"apiVersionVirtualMachinesExtensions": "2016-03-30",
"txNode": 0,
"mnNode": 1,
"maxPeers": 25
},
"resources": [
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('txVMNamePrefix'), copyIndex(), '/newuserscript')]",
"copy": {
"name": "txNodesConfigLoop",
"count": "[parameters('numTXNodes')]"
},
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Azure.Extensions",
"type": "CustomScript",
"typeHandlerVersion": "2.0",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/configure-geth.sh')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('/bin/bash configure-geth.sh \"', parameters('adminUsername'), '\" \"', parameters('ethereumAccountPsswd'), '\" \"', parameters('ethereumAccountPassphrase'), '\" \"', parameters('artifactsLocationURL'), '\" \"', parameters('ethereumNetworkID'), '\" \"', variables('maxPeers'), '\" \"', variables('txNode'), '\" \"', parameters('gethIPCPort'), '\" \"', parameters('numBootNodes'), '\" \"', parameters('numMNNodes'), '\" \"', parameters('mnVMNamePrefix'), '\" \"', base64(parameters('genesisBlock')), '\" \"', uniqueString(string(parameters('consortiumMemberId')), parameters('adminHash')), '\" \"', parameters('numTXNodes'), '\" \"', parameters('txVMNamePrefix'), '\" \"', parameters('adminSitePort'), '\" \"', parameters('consortiumMemberId'), '\"')]"
}
}
},
{
"apiVersion": "[variables('apiVersionVirtualMachinesExtensions')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('mnVMNamePrefix'), copyIndex(), '/newuserscript')]",
"copy": {
"name": "bootMNNodesConfigLoop",
"count": "[parameters('numMNNodes')]"
},
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Azure.Extensions",
"type": "CustomScript",
"typeHandlerVersion": "2.0",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat(parameters('artifactsLocationURL'), '/scripts/configure-geth.sh')]"
]
},
"protectedSettings": {
"commandToExecute": "[concat('/bin/bash configure-geth.sh \"', parameters('adminUsername'), '\" \"', parameters('ethereumAccountPsswd'), '\" \"', parameters('ethereumAccountPassphrase'), '\" \"', parameters('artifactsLocationURL'), '\" \"', parameters('ethereumNetworkID'), '\" \"', variables('maxPeers'), '\" \"', variables('mnNode'), '\" \"', parameters('gethIPCPort'), '\" \"', parameters('numBootNodes'), '\" \"', parameters('numMNNodes'), '\" \"', parameters('mnVMNamePrefix'), '\" \"', base64(parameters('genesisBlock')), '\" \"', uniqueString(string(parameters('consortiumMemberId')), parameters('adminHash')), '\" \"', copyIndex(), '\"')]"
}
}
}
]
}

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

@ -0,0 +1,53 @@
<#
.SYNOPSIS
Packages up template topology for deployment
.PARAMETER MarketplaceDirectory
The marketplace directory path
.PARAMETER Topology
Topology name
.PARAMETER OutputFile
Path to the output zip file
#>
function CreatePackage(
[string] $MarketplaceDirectory,
[string] $Topology,
[string] $OutputFile
){
Remove-Item "temp" -Recurse
md temp
md temp\ethereum
md temp\nested
md temp\etheradmin
md temp\powershell
# don't force the $OutputFile parameter to be passed in, if it's not it just the same name as the Topology folder + .zip appended
if( !([bool]$OutputFile))
{
$OutputFile=$Topology+".zip"
}
$root = Join-Path "." "temp"
$ethereumPath = Join-Path $root "ethereum"
$templatePath = Join-Path $MarketplaceDirectory $Topology
$mainTemplate = Join-Path $templatePath "mainTemplate.json"
$createUiDef = Join-Path $templatePath "createUiDefinition.json"
$commonDir = Join-Path $MarketplaceDirectory "..\common"
$genesisTemplate = "genesis-template.json"
$scriptsFolder = Join-Path $commonDir "scripts"
$nestedFolder = Join-Path $commonDir "nested"
$adminFolder = Join-Path $scriptsFolder "etheradmin"
$powershellFolder = Join-Path $commonDir "powershell"
# copy the files to the appropriate directory structure
Copy-Item $mainTemplate $root
Copy-Item $createUiDef $root
Copy-Item (Join-Path $commonDir $genesisTemplate) (Join-Path $root "ethereum")
Copy-Item (Join-Path $scriptsFolder "*") (Join-Path $root "scripts")
Copy-Item (Join-Path $nestedFolder "*") (Join-Path $root "nested")
Copy-Item (Join-Path $adminFolder "*") (Join-Path $root "etheradmin")
Copy-Item (Join-Path $powershellFolder "*") (Join-Path $root "powershell")
# zip it
$root = Join-Path $root "*"
Compress-Archive -Path $root -Force -DestinationPath $OutputFile
}

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

@ -0,0 +1,45 @@
<#
.SYNOPSIS
Join the Virtual Networks of two consortium members together
.PARAMETER MyGatewayResourceId
ResourceId of my Gateway
.PARAMETER OtherGatewayResourceId
ResourceId of the Gateway I am trying to connect to
.PARAMETER ConnectionName
Name of the Connection
.PARAMETER SharedKey
Shared Key used by both Gateways to establish trust
#>
function CreateConnection(
[string] $MyGatewayResourceId,
[string] $OtherGatewayResourceId,
[string] $ConnectionName,
[string] $SharedKey
){
Import-Module AzureRM.Network
Import-Module AzureRM.Profile
# $myGatewayResourceId tells me what subscription I am in, what ResourceGroup and the VNetGatewayName
$splitValue = $MyGatewayResourceId.Split('/')
$MySubscriptionid = $splitValue[2]
$MyResourceGroup = $splitValue[4]
$MyGatewayName = $splitValue[8]
# $otherGatewayResourceid tells me what the subscription and VNet GatewayName are
$OtherGatewayName = $OtherGatewayResourceId.Split('/')[8]
$Subscription=Select-AzureRmSubscription -SubscriptionId $MySubscriptionid
# create a PSVirtualNetworkGateway instance for the gateway I want to connect to
$OtherGateway=New-Object Microsoft.Azure.Commands.Network.Models.PSVirtualNetworkGateway
$OtherGateway.Name = $OtherGatewayName
$OtherGateway.Id = $OtherGatewayResourceId
$OtherGateway.GatewayType = "Vpn"
$OtherGateway.VpnType = "RouteBased"
# get a PSVirtualNetworkGateway instance for my gateway
$MyGateway = Get-AzureRmVirtualNetworkGateway -Name $MyGatewayName -ResourceGroupName $MyResourceGroup
# create the connection
New-AzureRmVirtualNetworkGatewayConnection -Name $ConnectionName -ResourceGroupName $MyResourceGroup -VirtualNetworkGateway1 $MyGateway -VirtualNetworkGateway2 $OtherGateway -Location $MyGateway.Location -ConnectionType Vnet2Vnet -SharedKey $SharedKey -EnableBgp $True
}

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

@ -0,0 +1,186 @@
# Ethereum Consortium Network Deployments Made Easy
[![Deploy to Azure](http://azuredeploy.net/deploybutton.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Fethereum-consortium-blockchain-network%2Fazuredeploy.json) [![Deploy to Azure Gov](http://azuredeploy.net/AzureGov.png)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Fethereum-consortium-blockchain-network%2Fazuredeploy.json) [![Visualize](http://armviz.io/visualizebutton.png)](http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Fethereum-consortium-blockchain-network%2Fazuredeploy.json)
## Overview
The next phase of our support of blockchain on Microsoft Azure is the release of the Ethereum Consortium Blockchain Network solution template in the Azure Quick Start Templates that simplifies the infrastructure and protocol substantially. This template deploys and configures a private Ethereum network from the Azure Portal or cmdline with a single click. While there are many valuable scenarios for the public Ethereum network, we expect in many enterprise scenarios, you will want to configure Ethereum to build out and deploy your own consortium network.
After reading this article, you will
* Obtain working knowledge of blockchain, Ethereum, and one consortium network architecture
* Learn how to deploy and configure a multi-node Ethereum consortium network with the published ARM template
## About blockchain
For those of you new to the blockchain community, this is a great opportunity to learn about the technology in an easy and configurable manner on Azure. Blockchain is the underlying technology behind Bitcoin; however, it is much more than just a virtual currency. It is a composite of existing database, distributed system, and cryptographic technologies that enables secure multi-party computation with guarantees around immutability, verifiability, auditability, and resiliency to attack. Different implementations employ different mechanisms to provide these attributes. Ethereum is one such protocol, with several different implementations.
While this article will not go into the details of the [Ethereum](https://www.ethereum.org/) protocol, implementations, architecture, or public network, it is still important to briefly describe a simplified application and network architecture to better understand the different deployment topology options now available. Ultimately, there is no single canonical network layout; it all depends on the use cases and stage within the development lifecycle.
Similar to applications interacting with databases today, decentralized applications will communicate and execute logic against the Ethereum blockchain. A private Ethereum network consists of a peer-to-peer decentralized network of nodes. These nodes maintain a copy of the data store (i.e. distributed ledger) and run a virtual machine to support arbitrary computation against the ledger, while maintaining consensus. Smart contracts are the mechanism that allows for this complicated computation on the network, similar to stored procedures on traditional databases.
Nodes are divided into mining and transaction nodes (non-mining nodes). Transaction nodes maintain a copy of the distributed ledger, but are used to submit or look up transactions from the network. Applications interact with these nodes using Ethereums web3 JavaScript object to execute and store important transactions within their application. A wallet is usually backed by a transaction node on the public network. Mining nodes process and commit transactions to the underlying distributed database (i.e. ledger) through a consensus process.
## Getting Started
To begin, you will need an Azure subscription that can support deploying several virtual machines and standard storage accounts. By default, most subscription types will support a small deployment topology without needing to increase quota.
Once you have a subscription, click the Deploy to Azure button above to take you to the Template deployment wizard in the Azure Portal. Note, you will be prompted to sign into your account and Azure subscription in the process if you are not already logged in.
Once signed in, you land within the Template deployment wizard as shown below.
![consortium network](images/azure2.png)
The template is pre-populated with the main azuredeploy.json ARM template file and can be displayed. If you are interested in understanding or modifying the ARM template itself, select Edit to open the editor in the Azure portal. For a more detailed inspection, you can also select the Browse on Github, instead of Deploy To Azure button to take you to the Azure Github repository that contains the Ethereum Consortium Blockchain Network template.
The Template Deployment will prompt you for a set of simple inputs to configure the deployment properly. Under the Basics section, you will provide values for standard parameters for any deployment, while under the Settings section, you will provide values for parameters specific to this blockchain consortium template. The standard parameters include the subscription, resource group, and location to which to deploy resources. We recommend using a new separate resource group to avoid resource conflicts and for ease of management and deletion.
<TODO: ADD IMAGE FROM pdf>
Finally, acknowledge legal terms and click Purchase to deploy. Depending on the number of VMs being provisioned, deployment time can vary from a few minutes to tens of minutes.
## Ethereum consortium network architecture on Azure
While there is no single canonical architecture for a consortium network, this template provides a sample architecture to use to get started quickly. Fundamentally, the network consists of a set of shared transaction nodes with which an application can interact to submit transactions and a set of mining nodes per consortium member to record transactions. All nodes are within the same virtual network, though each consortium members subnet can be easily pulled into individual VNets communicating through application gateways. The network is illustrated in the figure below.
![consortium network](images/eth-network.png)
## Mining Nodes
Each consortium member is given a separate, identical subnet containing one or more mining nodes, backed by a storage account. The first default VM in the subnet is configured as a boot node to support dynamic discoverability of the nodes in the network. Mining nodes communicate with other mining nodes to come to consensus on the state of the underlying distributed ledger. There is no need for your application to be aware of or communicate with these nodes. Since we are focused on private networks, these nodes are isolated from inbound public internet traffic adding a secondary level of protection. Outbound traffic is allowed, but not to the Ethereum discovery port. While each members VMs are in a separate subnet, the individual nodes are still connected and communicating with one another via Ethereums discovery protocol.
All nodes have the latest stable Go Ethereum (Geth) client software and are configured to be mining nodes. All nodes use the same Ethereum account (Ethereum address and key pair) that is protected by the Ethereum account password. The public private key pair generated from the Ethereum passphrase provided is stored on each of the Geth nodes. As mining nodes mine, they collect fees that are added to this account.
## Transaction Nodes
All consortium members share a set of load-balanced transaction nodes. These nodes are reachable from outside the virtual network so that applications can use these nodes to submit transactions or execute smart contracts within the blockchain networks. All nodes have the latest stable Go Ethereum (Geth) client software and are configured to maintain a complete copy of the distributed ledger. These nodes use the same Ethereum account, protected by the Ethereum account password provided.
We have explicitly separated the nodes that accept transactions from the nodes that mine transactions to ensure that the two actions are not competing for the same resources. We have also load-balanced the transaction nodes within an availability set to maintain high availability.
## Ethereum configuration
Besides the infrastructural footprint and configuration of nodes, the blockchain network itself is created. The genesis block is configured with the desired Ethereum network id, an appropriate mining difficulty, and a pre-configured account. The mining difficult varies depending on the number of mining nodes deployed to ensure mining time remains short even in the beginning. The pre-configured account contains 1 trillion Ether to seed the consortium network with enough gas (Ethereums fuel) to handle millions of transactions. Since the mining nodes use this account, their collected fees feed back into the account to ensure continual funds.
## Administrator page
Once the deployment has completed successfully and all resources have been provisioned, you can go to the administrator page to get a simple view of your blockchain network.
The admin site URL is the DNS name of the load balancer; it is also the first output of the template deployment. To find the template output, select the resource group just deployed. Select the Overview tab, then Last Deployment.
![consortium network](images/deployment.png)
Finally, select Microsoft.Template and look for the outputs section.
![consortium network](images/output.png)
You can get a high level overview of the topology you just deployed by reviewing the Ethereum Node Status section. This section includes all node hostnames and the participant to which the node belongs. It also displays node connectivity with the peer count. Peer count is the minimum of the number of mining nodes in the network and twenty-five where twenty-five is the configured maximum peer count, as in the public Ethereum network. Note, that peer count does not restrict the number of nodes that can be deployed within the network. Occasionally, you will see peer count fluctuate and be less for certain nodes. This is not always a sign that the nodes are unhealthy, since forks in the ledger can cause minor changes in peer count. Finally, you can inspect the latest block seen by each node in the network to determine forks or lags in the system.
![consortium network](images/admin-site.png)
The node status is refreshed every 10 seconds. Reload the page via the browser or "Reload" button to update the view.
## Create Ethereum Account
To create an additional account, you can use a variety of solutions. One such solution is [MetaMask](https://metamask.io/), a Chrome extension that provides an “identity vault” and connection to an Ethereum network, public, test or custom. MetaMask formulates a transaction to register the account in the network. This transaction, like any other transaction, will go to one of the transaction nodes, and eventually be mined into a block as illustrated below.
![consortium network](images/azure3.png)
To install the extension in Chrome, go to Customize and control Google Chrome (Overflow button), More Tools, Extensions, Get More Extensions, and search for MetaMask.
![consortium network](images/azure4.png)
Once installed, open MetaMask and create a new vault. By default, the vault will be connected to the Morden Test Network. You will need to change this to connect to the deployed private consortium network, specifically to the load balancer in front of the transaction nodes. From the template output, retrieve the exposed Ethereum RPC endpoint at port 8545, the second template output, and enter it in custom RPC as shown below.
![consortium network](images/azure5.png)
By creating the vault, you create a wallet containing an account. To create additional accounts, select Switch Accounts and then the + button as shown below.
![consortium network](images/azure6.png)
## Initiate Ether Allocation
Through the administrator page, you can formulate a transaction to transfer Ether from the pre-allocated account to another Ethereum account. This Ether transfer is a transaction that is sent to the transaction node and mined into a block as illustrated below.
![consortium network](images/azure7.png)
Via the clipboard icon in the MetaMask wallet, copy the address of the Ethereum account to which you want to transfer ether and go back to the administrator page. Paste the copied account into the input field to transfer 1000 ether from the pre-allocated Ethereum account to your newly created account. Click submit and wait for the transaction to be mined into a block.
![consortium network](images/azure8.png)
Once the transaction is committed into a mined block, the account balance in MetaMask for your account will reflect the transfer of 1000 Ether.
![consortium network](images/azure9.png)
## Transfer of Ether Between Accounts
At this point, you are ready to execute transactions within your private consortium network. The simplest transaction is to transfer Ether from one account to another. To formulate such a transaction, you can use MetaMask once again, transferring money from the first account used above to a second account.
From Wallet 1 in MetaMask, click on send. Copy the address of the second wallet created into Recipient Address input field and amount of Ether to transfer in the Amount input field. Click send and accept the transaction.
![consortium network](images/azure10.png)
Once again, when the transaction is mined and committed into a block, the account balances will be reflected accordingly. Note, wallet 1s balance is deducted a bit more than 15 Ether, since you had to pay a mining fee to process the transaction.
![consortium network](images/azure11.png) ![consortium network](images/azure12.png)
## Smart Contract Guide
Once you have an Ethereum account set up with some Ether, you can try deploying and interacting with smart contracts on your private blockchain. For this, we'll be using the Browser Solidity project, which integrates with Metamask and allows you to write smart contracts directly in your browser. Navigate [here](https://ethereum.github.io/browser-solidity/), and in the upper left click "New File".
The sample code for this exercise can be found in the "sample-contracts.sol" file [here](scripts/sample-contracts.sol). Copy and paste this code into the editor, and on the right you should see the compiled bytecode of your contracts, as well as buttons to create the contract on the blockchain or attach to an existing contract:
![consortium network](images/contracts1.png)
The first contract we'll be working with is the StateHolder contract. This is a simple contract that just stores some state on the blockchain - you can think of it as a very simplified database. There are three variables: a number that anyone can edit (openNumber), a string that anyone can edite (openString), and a string that only the contract owner can edit (myString). The owner of the contract is the person that first deploys the contract, as seen in the StateHolder() constructor function.
Click on the red "Create" button under the "StateHolder" contract section on the far right. Metamask will ask you to confirm the transaction - deploying a new contract to the blockchain costs gas, which is payable in Ether from your account:
![consortium network](images/contracts2.png)
Accept the transaction. On the right, you will see "Waiting for transaction to be mined..." Once the contract creation transaction is mined and included in your blockchain, the interface will show you the address of your new contract and allow you to interact with it:
![consortium network](images/contracts3.png)
The "owner" value should be the Ethereum address that you created the contract from. The public varialbes openString, openNumber, and myString are initialized with zero values or empty strings. You can change the values of these variables by sending transactions to the contracts functions. For example, to change the openNumber variable, enter a sample value into the "uint256 \_newNumber" textbox and click the red "changeOpenNumber" button. Accept the transaction from Metamask and, after waiting for the transaction to be mined, you will get back data on the transaction. Clicking on the blue "openNumber" button should update the display with the latest value:
![consortium network](images/contracts4.png)
The strings can be edited in the same way - make sure to enclose your new string in double quotes to adhere to proper JSON formatting.
The "onlyOwner" modifier is designed to ensure that only the owner account will be able to use the "changeMyString" function. To test this, switch your active Ethereum account in Metamask to a different account than the one used to create the transaction. Ensure that this account has some Ether so we can send transactions from it:
![consortium network](images/contracts5.png)
Next, copy the address of the contract from the interface on the right - for example, if the interface displays "StateHolder at 0xac1e0f9fa7bdb66612a444fa895358326d13d9b2 (blockchain)", you want to copy the "0xac1e0f9fa7bdb66612a444fa895358326d13d9b2". Refresh the browser-solidity window. Your smart contract code should still be in one of the editor tabs, but if not, you can click "New File" and paste the code from the GitHub file again.
Under the StateHolder section, click the "At Address" button, and enter the address you copied previously.
![consortium network](images/contracts6.png)
Your interface will change to reflect all the values that you modified before. This is an important point - by taking note of the contract address, you can allow other people to interact with the same contract on the blockchain, and they will see the same functions and values that you do.
Attempt to modify the "openString" variable. This should work fine - after the transaction is mined, clicking the blue openString button will reflect the new value in the interface. Now, attempt to modify the "myString" variable - this should fail since we are not currently the contract owner:
![consortium network](images/contracts7.png)
The error message of "Gas required exceeds limit: 50000000" is admittedly not very clear, but this shows that we cannot run this function unless we are the contract owner.
Next, we'll look at a very simple token contract. In this contract, we have a mapping between Ethereum addresses and integers - think of this like a bank balance, showing that a particular address has a particular amount of money. The constructor function assigns a balance of one million to whoever deploys the contract, and the "transfer" function allows us to transfer from our balance to an arbitrary Ethereum address.
Close the "StateHolder" section, and under the "Token" section, click the red "Create" button. This will instantiate the Token contract on our blockchain. We can check our balance by copying our current Metamask wallet address:
![consortium network](images/contracts8.png)
Placing this address in quotes and placing it in the "balances" dialog box, then clicking the blue "balances" button, will show the number of tokens currently associated with our account:
![consortium network](images/contracts9.png)
Since we deployed the contract from this address, we would expect our address to have a balance of one million tokens, and we can see that this is so.
We can transfer tokens to other addreses, as well. In Metamask, copy the address of your other account, without switching into it:
![consortium network](images/contracts10.png)
Enclose this address in quotes, put a comma, and then the amount of tokens you wish to transfer. Click the red "transfer" button to submit the transaction:
![consortium network](images/contracts11.png)
We can then check the updated balances to see if our transfer went through:
![consortium network](images/contracts12.png)
This concludes our smart contract sample. For additional information about the Solidity language, click [here](http://solidity.readthedocs.io/en/develop/).
## Accessing VMs running nodes
You can remotely connect to the virtual machines on which the nodes run via SSH with your provided admin username and password. Since the virtual machines on which the nodes run do not have their own public IP addresses, you will need to go through the load balancer and specify the port number. The SSH command to run to access the first transaction node is the third template output (e.g. for the sample deployment it is: ssh -p 3000 gethadmin@ethnet7tl.southeastasia.cloudapp.azure.com). To get to additional transaction nodes, increment the port number by one. (e.g. for a network with two transaction nodes, the first transaction node is on port 3000, second is 3001). To ssh to mining nodes, ssh to a transaction node first and then ssh to the mining node from there.
## Next Steps
You are now ready to focus on application and smart contract development against your private consortium blockchain network. Happy coding!

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

@ -0,0 +1,556 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"namePrefix": {
"type": "string",
"metadata": {
"description": "String used as a base for naming resources (6 alphanumeric characters or less). A unique hash is prepended to the string for some resources, while resource-specific information is appended."
},
"maxLength": 6
},
"adminUsername": {
"type": "string",
"defaultValue": "gethadmin",
"metadata": {
"description": "Administrator username of each deployed VM (alphanumeric characters only)"
},
"minLength": 1,
"maxLength": 64
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Administrator password for each deployed VM"
},
"minLength": 12,
"maxLength": 72
},
"ethereumAccountPsswd": {
"type": "securestring",
"metadata": {
"description": "Password used to secure the default Ethereum account that will be generated"
},
"minLength": 12
},
"ethereumAccountPassphrase": {
"type": "securestring",
"metadata": {
"description": "Password used to generate the private key associated with the default Ethereum account that is generated. Consider a password with sufficient randomness to ensure a strong private key"
},
"minLength": 12
},
"ethereumNetworkID": {
"type": "int",
"defaultValue": 10101010,
"metadata": {
"description": "Private Ethereum network ID to which to connect (max 9 digit number)"
},
"minValue": 5,
"maxValue": 2147483647
},
"numConsortiumMembers": {
"type": "int",
"defaultValue": 2,
"metadata": {
"description": "Number of members within the network. Each member's nodes live in their own subnet."
},
"minValue": 2,
"maxValue": 5
},
"numMiningNodesPerMember": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Number of mining nodes to create for each consortium member."
},
"minValue": 1,
"maxValue": 19
},
"mnNodeVMSize": {
"type": "string",
"defaultValue": "Standard_D1_v2",
"allowedValues": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"metadata": {
"description": "Size of the virtual machine used for mining nodes"
}
},
"numTXNodes": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Number of load balanced transaction nodes"
},
"minValue": 1,
"maxValue": 5
},
"txNodeVMSize": {
"type": "string",
"defaultValue": "Standard_D1_v2",
"allowedValues": [
"Standard_A1",
"Standard_A2",
"Standard_A3",
"Standard_A4",
"Standard_A5",
"Standard_A6",
"Standard_A7",
"Standard_D1",
"Standard_D2",
"Standard_D3",
"Standard_D4",
"Standard_D11",
"Standard_D12",
"Standard_D13",
"Standard_D14",
"Standard_D1_v2",
"Standard_D2_v2",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D11_v2",
"Standard_D12_v2",
"Standard_D13_v2",
"Standard_D14_v2",
"Standard_D15_v2",
"Standard_F1",
"Standard_F2",
"Standard_F4",
"Standard_F8",
"Standard_F16"
],
"metadata": {
"description": "Size of the virtual machine for transaction nodes"
}
}
},
"variables": {
"location": "local",
"artifactsLocationURL": "https://blkchainsa.blob.local.azurestack.external/blkchaincont",
"apiVersionDeployments": "2016-02-01",
"apiVersionStorageAccounts": "2015-06-15",
"apiVersionAvailabilitySets": "2016-03-30",
"apiVersionNetworkSecurityGroups": "2015-06-15",
"apiVersionNetworkInterfaces": "2015-06-15",
"apiVersionVirtualMachines": "2015-06-15",
"apiVersionVirtualNetworks": "2015-06-15",
"authType": "password",
"storageAccountType": "Standard_LRS",
"namingInfix": "[toLower(substring(concat(parameters('namePrefix'), uniqueString(resourceGroup().id)), 0, 9))]",
"availabilitySetName": "[concat(variables('namingInfix'), 'AvSet')]",
"httpPort": 80,
"adminSitePort": 3000,
"sshPort": 22,
"sshNATFrontEndStartingPort": 3000,
"gethRPCPort": 8545,
"gethIPCPort": 30303,
"loadBalancerName": "[concat(variables('namingInfix'), '-LB')]",
"loadBalancerBackendAddressPoolName": "LoadBalancerBackend1",
"loadBalancerInboundNatRuleNamePrefix": "SSH-VM",
"numMNNodes": "[mul(parameters('numConsortiumMembers'), parameters('numMiningNodesPerMember'))]",
"maxVMsPerStorageAcct": 20,
"mnStorageAcctCount": "[add(div(variables('numMNNodes'), variables('maxVMsPerStorageAcct')), 1)]",
"mnStorageAcctNames": [
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'mn0')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'mn1')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'mn2')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'mn3')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'mn4')]"
],
"mnVMNamePrefix": "[concat(variables('namingInfix'), '-mn')]",
"mnNICPrefix": "nic-mn",
"txStorageAcctName": "[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'tx')]",
"txVMNamePrefix": "[concat(variables('namingInfix'), '-tx')]",
"txSubnetName": "[concat(uniqueString(concat(resourceGroup().id, concat(variables('namingInfix'), 'subnet')), 'tx'))]",
"txSubnetPrefix": "10.0.10.0/24",
"txSubnetRef": "[concat(variables('vnetID'),'/subnets/', variables('txSubnetName'))]",
"txNIPrefix": "nic-tx",
"virtualNetworkName": "[concat(variables('namingInfix'), 'vnet')]",
"txNsgName": "[concat(variables('namingInfix'), 'TXNsg')]",
"mnNsgName": "[concat(variables('namingInfix'), 'MNNsg')]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]",
"addressPrefix": "10.0.0.0/20",
"mnSubnetNameArray": [
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'subnet-mn0')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'subnet-mn1')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'subnet-mn2')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'subnet-mn3')]",
"[concat(uniqueString(resourceGroup().id, variables('namingInfix')), 'subnet-mn4')]"
],
"mnSubnetPrefixArray": [
"10.0.0.0/24",
"10.0.1.0/24",
"10.0.2.0/24",
"10.0.3.0/24",
"10.0.4.0/24"],
"mnSubnetRefArray": [
"[concat(variables('vnetID'),'/subnets/', variables('mnSubnetNameArray')[0])]",
"[concat(variables('vnetID'),'/subnets/', variables('mnSubnetNameArray')[1])]",
"[concat(variables('vnetID'),'/subnets/', variables('mnSubnetNameArray')[2])]",
"[concat(variables('vnetID'),'/subnets/', variables('mnSubnetNameArray')[3])]",
"[concat(variables('vnetID'),'/subnets/', variables('mnSubnetNameArray')[4])]"],
"numSubnets": "[add(parameters('numConsortiumMembers'), 1)]",
"subnetPropertiesArray": [
{
"name": "[variables('txSubnetName')]",
"properties": {
"addressPrefix": "[variables('txSubnetPrefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('txNsgName'))]"
}
}
},
{
"name": "[variables('mnSubnetNameArray')[0]]",
"properties": {
"addressPrefix": "[variables('mnSubnetPrefixArray')[0]]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mnNsgName'))]"
}
}
},
{
"name": "[variables('mnSubnetNameArray')[1]]",
"properties": {
"addressPrefix": "[variables('mnSubnetPrefixArray')[1]]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mnNsgName'))]"
}
}
},
{
"name": "[variables('mnSubnetNameArray')[2]]",
"properties": {
"addressPrefix": "[variables('mnSubnetPrefixArray')[2]]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mnNsgName'))]"
}
}
},
{
"name": "[variables('mnSubnetNameArray')[3]]",
"properties": {
"addressPrefix": "[variables('mnSubnetPrefixArray')[3]]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mnNsgName'))]"
}
}
},
{
"name": "[variables('mnSubnetNameArray')[4]]",
"properties": {
"addressPrefix": "[variables('mnSubnetPrefixArray')[4]]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mnNsgName'))]"
}
}
}
],
"ubuntuImage": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "16.04-LTS",
"version": "latest"
}
},
"resources": [
{
"apiVersion": "[variables('apiVersionAvailabilitySets')]",
"type": "Microsoft.Compute/availabilitySets",
"name": "[variables('availabilitySetName')]",
"location": "[variables('location')]",
"properties": {}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "loadBalancerLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(variables('artifactsLocationURL'), '/nested/loadBalancer.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"loadBalancerName": {"value": "[variables('loadBalancerName')]"},
"dnsHostName":{"value": "[variables('namingInfix')]"},
"loadBalancerBackendAddressPoolName":{"value": "[variables('loadBalancerBackendAddressPoolName')]"},
"loadBalancerInboundNatRuleNamePrefix":{"value": "[variables('loadBalancerInboundNatRuleNamePrefix')]"},
"frontendPort1":{"value": "[variables('httpPort')]"},
"backendPort1":{"value": "[variables('adminSitePort')]"},
"frontendPort2":{"value": "[variables('gethRPCPort')]"},
"backendPort2":{"value": "[variables('gethRPCPort')]"},
"numInboundNATRules":{"value": "[parameters('numTXNodes')]"},
"inboundNATRuleFrontendStartingPort":{"value": "[variables('sshNATFrontEndStartingPort')]"},
"inboundNATRuleBackendPort":{"value": "[variables('sshPort')]"},
"location":{"value": "[variables('location')]"}
}
}
},
{
"apiVersion": "[variables('apiVersionNetworkSecurityGroups')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('mnNsgName')]",
"location": "[variables('location')]",
"tags": {
"displayName": "NSG - Mining (MN)"
},
"properties": {
"securityRules": [
{
"name": "block-bootnodes",
"properties": {
"description": "Block Internet Bootnodes",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "30303",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "Internet",
"access": "Deny",
"priority": 100,
"direction": "Outbound"
}
}
]
}
},
{
"apiVersion": "[variables('apiVersionNetworkSecurityGroups')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('txNsgName')]",
"location": "[variables('location')]",
"tags": {
"displayName": "NSG - Transaction (TX)"
},
"properties": {
"securityRules": [
{
"name": "allow-ssh",
"properties": {
"description": "Allow SSH",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
},
{
"name": "allow-geth-rpc",
"properties": {
"description": "Allow geth RPC",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "8545",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 101,
"direction": "Inbound"
}
},
{
"name": "allow-etheradmin",
"properties": {
"description": "Allow etheradmin web service",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "3000",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 102,
"direction": "Inbound"
}
},
{
"name": "block-bootnodes",
"properties": {
"description": "Block Internet Bootnodes",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "30303",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "Internet",
"access": "Deny",
"priority": 100,
"direction": "Outbound"
}
}
]
}
},
{
"apiVersion": "[variables('apiVersionVirtualNetworks')]",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('txNsgName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('mnNsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": "[take(variables('subnetPropertiesArray'), variables('numSubnets'))]"
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "txVMLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
"[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]",
"loadBalancerLinkedTemplate"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(variables('artifactsLocationURL'), '/nested/txVMAuth', '-', variables('authType'), '.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines":{"value": "[variables('apiVersionVirtualMachines')]"},
"apiVersionNetworkInterfaces":{"value": "[variables('apiVersionNetworkInterfaces')]"},
"apiVersionStorageAccounts":{"value": "[variables('apiVersionStorageAccounts')]"},
"loadBalancerName":{"value": "[variables('loadBalancerName')]"},
"loadBalancerBackendAddressPoolName":{"value": "[variables('loadBalancerBackendAddressPoolName')]"},
"loadBalancerInboundNatRuleNamePrefix":{"value": "[variables('loadBalancerInboundNatRuleNamePrefix')]"},
"txSubnetRef":{"value": "[variables('txSubnetRef')]"},
"txVMNamePrefix":{"value": "[variables('txVMNamePrefix')]"},
"numTXNodes":{"value": "[parameters('numTXNodes')]"},
"txStorageAcctName":{"value": "[variables('txStorageAcctName')]"},
"txNIPrefix":{"value": "[variables('txNIPrefix')]"},
"storageAccountType":{"value": "[variables('storageAccountType')]"},
"availabilitySetName":{"value": "[variables('availabilitySetName')]"},
"txNodeVMSize":{"value": "[parameters('txNodeVMSize')]"},
"adminUsername":{"value": "[parameters('adminUsername')]"},
"adminPassword":{"value": "[parameters('adminPassword')]"},
"adminSSHKey":{"value": ""},
"ubuntuImage":{"value": "[variables('ubuntuImage')]"},
"namingInfix":{"value": "[variables('namingInfix')]"},
"location":{"value": "[variables('location')]"}
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "mnVMLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(variables('artifactsLocationURL'), '/nested/mnVMAuth', '-', variables('authType'), '.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apiVersionVirtualMachines":{"value": "[variables('apiVersionVirtualMachines')]"},
"apiVersionNetworkInterfaces":{"value": "[variables('apiVersionNetworkInterfaces')]"},
"apiVersionStorageAccounts":{"value": "[variables('apiVersionStorageAccounts')]"},
"mnVMNamePrefix":{"value": "[variables('mnVMNamePrefix')]"},
"numMNNodes":{"value": "[variables('numMNNodes')]"},
"mnNICPrefix":{"value": "[variables('mnNICPrefix')]"},
"mnStorageAcctNames":{"value": "[variables('mnStorageAcctNames')]"},
"mnStorageAcctCount":{"value": "[variables('mnStorageAcctCount')]"},
"mnSubnetRefArray":{"value": "[variables('mnSubnetRefArray')]"},
"numConsortiumMembers":{"value": "[parameters('numConsortiumMembers')]"},
"storageAccountType":{"value": "[variables('storageAccountType')]"},
"mnNodeVMSize":{"value": "[parameters('mnNodeVMSize')]"},
"adminUsername":{"value": "[parameters('adminUsername')]"},
"adminPassword":{"value": "[parameters('adminPassword')]"},
"adminSSHKey":{"value": ""},
"ubuntuImage":{"value": "[variables('ubuntuImage')]"},
"namingInfix":{"value": "[variables('namingInfix')]"},
"location":{"value": "[variables('location')]"}
}
}
},
{
"apiVersion": "[variables('apiVersionDeployments')]",
"name": "vmExtensionLinkedTemplate",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"txVMLinkedTemplate",
"mnVMLinkedTemplate"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(variables('artifactsLocationURL'), '/nested/vmExtension.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"numBootNodes":{"value": "[parameters('numConsortiumMembers')]"},
"txVMNamePrefix":{"value": "[variables('txVMNamePrefix')]"},
"numTXNodes":{"value": "[parameters('numTXNodes')]"},
"mnVMNamePrefix":{"value": "[variables('mnVMNamePrefix')]"},
"numMNNodes":{"value": "[variables('numMNNodes')]"},
"artifactsLocationURL":{"value": "[variables('artifactsLocationURL')]"},
"adminUsername":{"value": "[parameters('adminUsername')]"},
"ethereumAccountPsswd":{"value": "[parameters('ethereumAccountPsswd')]"},
"ethereumAccountPassphrase": {"value": "[parameters('ethereumAccountPassphrase')]"},
"ethereumNetworkID":{"value": "[parameters('ethereumNetworkID')]"},
"gethIPCPort":{"value": "[variables('gethIPCPort')]"},
"adminSitePort":{"value": "[variables('adminSitePort')]"},
"apiVersionStorageAccounts":{"value": "[variables('apiVersionStorageAccounts')]"},
"location":{"value": "[variables('location')]"}
}
}
}
],
"outputs": {
"admin-site": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
},
"ethereum-rpc-endpoint": {
"type": "string",
"value": "[concat('http://', reference('loadBalancerLinkedTemplate').outputs.fqdn.value, ':', variables('gethRPCPort'))]"
},
"ssh-to-first-tx-node": {
"type": "string",
"value": "[concat('ssh -p ', variables('sshNATFrontEndStartingPort'), ' ', parameters('adminUsername'), '@', reference('loadBalancerLinkedTemplate').outputs.fqdn.value)]"
}
}
}

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

@ -0,0 +1,39 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"namePrefix" : {
"value": "ethnet"
},
"adminUsername": {
"value": "auser1"
},
"adminPassword": {
"value": "GEN-PASSWORD"
},
"ethereumAccountPsswd": {
"value": "GEN-PASSWORD"
},
"ethereumAccountPassphrase": {
"value": "GEN-PASSWORD"
},
"ethereumNetworkID": {
"value": 1010101
},
"numConsortiumMembers": {
"value": 2
},
"numMiningNodesPerMember": {
"value": 1
},
"mnNodeVMSize": {
"value": "Standard_A1"
},
"numTXNodes": {
"value": 1
},
"txNodeVMSize": {
"value": "Standard_A1"
}
}
}

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/admin-site.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure1.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure10.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure11.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure12.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure2.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure3.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure4.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure5.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure6.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure7.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure8.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/azure9.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts1.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts10.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts11.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts12.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts2.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts3.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts4.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts5.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts6.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts7.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts8.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/contracts9.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/deployment.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/eth-network.png Normal file

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

После

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

Двоичные данные
ethereum-consortium-blockchain/quickstart/images/output.png Normal file

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

После

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

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

@ -0,0 +1,7 @@
{
"itemDisplayName" : "Blockchain - Ethereum Private Consortium Network",
"description" : "This template fully automates the provisioning of necessary Azure resources like VMs, storage, network settings etc. as well as the configuration of Go Ethereum (geth) and accounts. It also stands up an administration website to monitor the nodes in the network and provide ether to new accounts. To deploy on Azure Government, go to the Azure quick start repository via the Browse on GitHub button.",
"summary" : "A template to deploy and setup an private Ethereum consortium network.",
"githubUsername" : "cavanes",
"dateUpdated" : "2016-09-20"
}

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

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

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

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

@ -0,0 +1,19 @@
# install azure CLI with the following command line on Ubuntu 16+
# sudo apt-get update
# sudo apt-get install -y libssl-dev libffi-dev python-dev build-essential
# curl -L https://aka.ms/InstallAzureCli | bash
MyGatewayResourceId=$1
OtherGatewayResourceId=$2
ConnectionName=$3
SharedKey=$4
# MyGatewayResourceId tells me what subscription I am in, what ResourceGroup and the VNetGatewayName
IFS='/'
read -r -a arr <<< "$MyGatewayResourceId"
MySubscriptionId=`echo "${arr[2]}"`
MyResourceGroup=`echo "${arr[4]}"`
IFS=''
az account set --subscription $MySubscriptionId
az network vpn-connection create --name $ConnectionName --resource-group $MyResourceGroup --vnet-gateway1 $MyGatewayResourceId --shared-key $SharedKey --vnet-gateway2 $OtherGatewayResourceId --enable-bgp

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

@ -0,0 +1,35 @@
Param
(
[Parameter(Mandatory = $true)]
$VPNName,
[Parameter(Mandatory = $true)]
$RemoteIPAddress,
[Parameter(Mandatory = $true)]
$AddressSpace,
[Parameter(Mandatory = $true)]
$SharedKey
)
Install-WindowsFeature -Name Routing
Install-WindowsFeature -Name 'RSAT-RemoteAccess-PowerShell'
Install-RemoteAccess -VpnType VpnS2S
Start-Sleep -Seconds 10
Get-Service -Name RemoteAccess
$params = @{
Name = $VPNName
Protocol = 'IKEv2'
Destination = $RemoteIPAddress
AuthenticationMethod = 'PSKOnly'
SharedSecret = $SharedKey
IPv4Subnet = '{0}:{1}' -f $AddressSpace,'200'
AuthenticationTransformConstants = 'GCMAES256'
CipherTransformConstants = 'GCMAES256'
DHGroup = 'Group2'
EncryptionMethod = 'AES256'
IntegrityCheckMethod = 'SHA256'
PfsGroup = 'PFS2048'
EnableQoS = 'Enabled'
NumberOfTries = 0
}
Add-VpnS2SInterface @params -Persistent -CustomPolicy
Connect-VpnS2SInterface -Name $VPNName

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

@ -0,0 +1,20 @@
Param
(
[Parameter(Mandatory = $true)]
$RouteTableName,
[Parameter(Mandatory = $true)]
$NicResourceId,
[Parameter(Mandatory = $true)]
$RemoteAddressSpace
)
Import-Module AzureRM.Network
$splited = $NicResourceId.Split('/')
$resourceGroup = $splited[4]
$nicName = $splited[8]
$routeTable = Get-AzureRmRouteTable -Name $RouteTableName -ResourceGroupName $resourceGroup
$nic = Get-AzureRmNetworkInterface -Name $nicname -ResourceGroupName $resourceGroup
$privateIpAddress = $nic.IpConfigurations[0].PrivateIpAddress
Add-AzureRmRouteConfig -Name "WinNVARoute" -AddressPrefix $RemoteAddressSpace -NextHopType VirtualAppliance -NextHopIpAddress $privateIpAddress -RouteTable $routeTable
Set-AzureRmRouteTable -RouteTable $routeTable

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

@ -0,0 +1,103 @@
#!/bin/bash
source deployment-utility.sh
echo "===== Initializing geth installation =====";
date;
############
# Parameters
############
# Validate that all arguments are supplied
if [ $# -lt 12 ]; then echo "Insufficient parameters supplied. Exiting"; exit 1; fi
AZUREUSER=$1;
PASSWD=$2;
PASSPHRASE=$3;
ARTIFACTS_URL_PREFIX=$4;
CONSORTIUM_DATA_ROOT=$5;
MAX_PEERS=$6;
NODE_TYPE=$7; # (0=Transaction node; 1=Mining node )
GETH_IPC_PORT=$8;
NUM_BOOT_NODES=$9;
NUM_MN_NODES=${10};
MN_NODE_PREFIX=${11};
MN_NODE_SEQNUM=${12}; #Only supplied for NODE_TYPE=1
NUM_TX_NODES=${12}; #Only supplied for NODE_TYPE=0
TX_NODE_PREFIX=${13}; #Only supplied for NODE_TYPE=0
ADMIN_SITE_PORT=${14}; #Only supplied for NODE_TYPE=0
CONSORTIUM_MEMBER_ID=${15}; #Only supplied for NODE_TYPE=0
#############
# Globals
#############
declare -a NODE_KEYS
PREFUND_ADDRESS=""
BOOTNODE_URLS="";
#############
# Constants
#############
MINER_THREADS=1;
HOMEDIR="/home/$AZUREUSER";
VMNAME=`hostname`;
GETH_HOME="$HOMEDIR/.ethereum";
mkdir -p $GETH_HOME;
ETHERADMIN_HOME="$HOMEDIR/etheradmin";
GETH_LOG_FILE_PATH="$HOMEDIR/geth.log";
GENESIS_FILE_PATH="$HOMEDIR/genesis.json";
GETH_CFG_FILE_PATH="$HOMEDIR/geth.cfg";
NODEKEY_SHARE_PATH="$GETH_HOME/nodekey";
BOOTNODE_SHARE_PATH="$ETHERADMIN_HOME/public/bootnodes.txt"
NETWORKID_SHARE_PATH="$ETHERADMIN_HOME/public/networkid.txt"
# Below information will be loaded from another consortium member
REMOTE_BOOTNODE_URL="$CONSORTIUM_DATA_ROOT/bootnodes.txt";
REMOTE_GENESIS_BLOCK_URL="$CONSORTIUM_DATA_ROOT/genesis.json";
REMOTE_NETWORK_ID_URL="$CONSORTIUM_DATA_ROOT/networkid.txt";
echo "CONSORTIUM_DATA_ROOT = "$CONSORTIUM_DATA_ROOT;
cd $HOMEDIR;
setup_dependencies
setup_node_info
#########################################
# Download Boot Node Urls of other member and get IP to
# append to bootnodes.txt
#########################################
wget -N ${REMOTE_BOOTNODE_URL} || exit 1;
IP_TO_PING=$(grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' bootnodes.txt | head -1)
REMOTE_BOOTNODE_URLS=`cat bootnodes.txt`;
BOOTNODE_URLS="${BOOTNODE_URLS} ${REMOTE_BOOTNODE_URLS}";
#########################################
# Setup ethereum account for the system
#########################################
setup_system_ethereum_account
##################################
# Download the genesis block file
##################################
cd $HOMEDIR;
sudo /bin/bash -c "wget -N ${REMOTE_GENESIS_BLOCK_URL}";
##################################
# Download and read the NetworkId
##################################
wget -N ${REMOTE_NETWORK_ID_URL} || exit 140;
NETWORK_ID=`cat networkid.txt`;
initialize_geth
setup_admin_website
create_config
setup_rc_local
############
# Start geth
############
cd $HOMEDIR;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/start-private-blockchain.sh || exit 1;
nohup /bin/bash $HOMEDIR/start-private-blockchain.sh $GETH_CFG_FILE_PATH $PASSWD $IP_TO_PING &
echo "Commands succeeded. Exiting";
exit 0;

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

@ -0,0 +1,118 @@
#!/bin/bash
source deployment-utility.sh
echo "===== Initializing geth installation =====";
date;
############
# Parameters
############
# Validate that all arguments are supplied
if [ $# -lt 14 ]; then echo "Insufficient parameters supplied. Exiting"; exit 1; fi
AZUREUSER=$1;
PASSWD=$2;
PASSPHRASE=$3;
ARTIFACTS_URL_PREFIX=$4;
NETWORK_ID=$5;
MAX_PEERS=$6;
NODE_TYPE=$7; # (0=Transaction node; 1=Mining node )
GETH_IPC_PORT=$8;
NUM_BOOT_NODES=$9;
NUM_MN_NODES=${10};
MN_NODE_PREFIX=${11};
SPECIFIED_GENESIS_BLOCK=${12};
ADMIN_HASH=${13};
MN_NODE_SEQNUM=${14}; #Only supplied for NODE_TYPE=1
NUM_TX_NODES=${14}; #Only supplied for NODE_TYPE=0
TX_NODE_PREFIX=${15}; #Only supplied for NODE_TYPE=0
ADMIN_SITE_PORT=${16}; #Only supplied for NODE_TYPE=0
CONSORTIUM_MEMBER_ID=${17}; #Only supplied for NODE_TYPE=0
#############
# Globals
#############
declare -a NODE_KEYS
PREFUND_ADDRESS=""
BOOTNODE_URLS="";
#############
# Constants
#############
MINER_THREADS=1;
# Difficulty constant represents ~15 sec. block generation for one node
DIFFICULTY_CONSTANT="0x3333";
HOMEDIR="/home/$AZUREUSER";
VMNAME=`hostname`;
GETH_HOME="$HOMEDIR/.ethereum";
mkdir -p $GETH_HOME;
ETHERADMIN_HOME="$HOMEDIR/etheradmin";
GETH_LOG_FILE_PATH="$HOMEDIR/geth.log";
GENESIS_FILE_PATH="$HOMEDIR/genesis.json";
GETH_CFG_FILE_PATH="$HOMEDIR/geth.cfg";
NODEKEY_SHARE_PATH="$GETH_HOME/nodekey";
BOOTNODE_SHARE_PATH="$ETHERADMIN_HOME/public/bootnodes.txt"
NETWORKID_SHARE_PATH="$ETHERADMIN_HOME/public/networkid.txt"
cd $HOMEDIR;
setup_dependencies
setup_node_info
echo $BOOTNODE_URLS
##############################################
# Did we get a genesis file specified? if so decode the base64
# Otherwise we need to create one
##############################################
if [ ${#SPECIFIED_GENESIS_BLOCK} -gt 0 ]; then
# Genesis block comes in as base64, need to decode it
SPECIFIED_GENESIS_BLOCK=`echo ${SPECIFIED_GENESIS_BLOCK} | base64 --decode`;
echo ${SPECIFIED_GENESIS_BLOCK} > $GENESIS_FILE_PATH;
fi
##############################################
# only the transaction nodes need to create the private key
##############################################
if [ ${#SPECIFIED_GENESIS_BLOCK} -gt 0 ]; then
echo "===========================Genesis block specified===========================";
# ADMIN_HASH serves as the password and a salt for deriving the private key
PASSWD_FILE="$GETH_HOME/passwd.info";
PASSWD=$ADMIN_HASH;
printf %s $ADMIN_HASH > $PASSWD_FILE;
# PRIV_KEY for the admin site is derived from genesis block and the admin hash which is derived from the admin password
PRIV_KEY=`echo "$SPECIFIED_GENESIS_BLOCK$ADMIN_HASH" | sha256sum | sed s/-// | sed "s/ //"`;
printf "%s" $PRIV_KEY > $HOMEDIR/priv_genesis.key;
PREFUND_ADDRESS=`geth --datadir $GETH_HOME --password $PASSWD_FILE account import $HOMEDIR/priv_genesis.key | grep -oP '\{\K[^}]+'`;
rm $HOMEDIR/priv_genesis.key;
rm $PASSWD_FILE;
cd $HOMEDIR
else
##############################################
# Setup Genesis file and pre-allocated account
##############################################
setup_system_ethereum_account
cd $HOMEDIR
wget -N ${ARTIFACTS_URL_PREFIX}/genesis-template.json || exit 1;
# Scale difficulty: Target difficulty scales with number of miners
DIFFICULTY=`printf "0x%X" $(($DIFFICULTY_CONSTANT * $NUM_MN_NODES))`;
# Place our calculated difficulty into genesis file
sed s/#DIFFICULTY/$DIFFICULTY/ $HOMEDIR/genesis-template.json > $HOMEDIR/genesis-intermediate.json;
sed s/#NETWORKID/$NETWORK_ID/ $HOMEDIR/genesis-intermediate.json > $HOMEDIR/genesis-intermediate2.json;
sed s/#PREFUND_ADDRESS/$PREFUND_ADDRESS/ $HOMEDIR/genesis-intermediate2.json > $GENESIS_FILE_PATH;
fi
initialize_geth
setup_admin_website
create_config
setup_rc_local
############
# Start geth
############
cd $HOMEDIR;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/start-private-blockchain.sh || exit 1;
/bin/bash $HOMEDIR/start-private-blockchain.sh $GETH_CFG_FILE_PATH $PASSWD "" || exit 1;
echo "Commands succeeded. Exiting";
exit 0;

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

@ -0,0 +1,42 @@
#!/bin/bash
#############
# Parameters
#############
# Validate that all arguments are supplied
if [ $# -lt 12 ]; then echo "Insufficient parameters supplied. Exiting"; exit 1; fi
AZUREUSER=$1;
ARTIFACTS_URL_PREFIX=$4
###########
# Constants
###########
HOMEDIR="/home/$AZUREUSER";
CONFIG_LOG_FILE_PATH="$HOMEDIR/config.log";
###########################################
# Get the script for running as Azure user
###########################################
cd "/home/$AZUREUSER";
sudo -u $AZUREUSER /bin/bash -c "wget -N ${ARTIFACTS_URL_PREFIX}/scripts/configure-geth-azureuser-joining.sh";
sudo -u $AZUREUSER /bin/bash -c "wget -N ${ARTIFACTS_URL_PREFIX}/scripts/deployment-utility.sh";
##################################
# Initiate loop for error checking
##################################
for LOOPCOUNT in `seq 1 5`; do
sudo -u $AZUREUSER /bin/bash /home/$AZUREUSER/configure-geth-azureuser-joining.sh "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}" "${14}" "${15}" >> $CONFIG_LOG_FILE_PATH 2>&1;
if [ $? -ne 0 ]; then
echo "Command failed on try $LOOPCOUNT, retrying..." >> $CONFIG_LOG_FILE_PATH;
sleep 5;
continue;
else
echo "======== Deployment successful! ======== " >> $CONFIG_LOG_FILE_PATH;
exit 0;
fi
done
echo "One or more commands failed after 5 tries. Deployment failed." >> $CONFIG_LOG_FILE_PATH;
exit 1

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

@ -0,0 +1,42 @@
#!/bin/bash
#############
# Parameters
#############
# Validate that all arguments are supplied
if [ $# -lt 13 ]; then echo "Insufficient parameters supplied. Exiting"; exit 1; fi
AZUREUSER=$1;
ARTIFACTS_URL_PREFIX=$4
###########
# Constants
###########
HOMEDIR="/home/$AZUREUSER";
CONFIG_LOG_FILE_PATH="$HOMEDIR/config.log";
#############
# Get the script for running as Azure user
#############
cd "/home/$AZUREUSER";
sudo -u $AZUREUSER /bin/bash -c "wget -N ${ARTIFACTS_URL_PREFIX}/scripts/configure-geth-azureuser.sh";
sudo -u $AZUREUSER /bin/bash -c "wget -N ${ARTIFACTS_URL_PREFIX}/scripts/deployment-utility.sh";
##################################
# Initiate loop for error checking
##################################
for LOOPCOUNT in `seq 1 5`; do
sudo -u $AZUREUSER /bin/bash /home/$AZUREUSER/configure-geth-azureuser.sh "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}" "${14}" "${15}" "${16}" "${17}" >> $CONFIG_LOG_FILE_PATH 2>&1;
if [ $? -ne 0 ]; then
echo "Command failed on try $LOOPCOUNT, retrying..." >> $CONFIG_LOG_FILE_PATH;
sleep 5;
continue;
else
echo "======== Deployment successful! ======== " >> $CONFIG_LOG_FILE_PATH;
exit 0;
fi
done
echo "One or more commands failed after 5 tries. Deployment failed." >> $CONFIG_LOG_FILE_PATH;
exit 1

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

@ -0,0 +1,188 @@
function setup_dependencies
{
################
# Update modules
################
sudo apt-get -y update || exit 1;
# To avoid intermittent issues with package DB staying locked when next apt-get runs
sleep 5;
##################
# Install packages
##################
sudo apt-get -y --allow-downgrades install npm=3.5.2-0ubuntu4 git=1:2.7.4-0ubuntu1 software-properties-common || exit 1;
sudo update-alternatives --install /usr/bin/node nodejs /usr/bin/nodejs 100 || exit 1;
##############
# Install geth
##############
wget https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz || exit 1;
wget https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz.asc || exit 1;
# Import geth buildserver keys
gpg --recv-keys --keyserver hkp://keyserver.ubuntu.com F9585DE6 C2FF8BBF 9BA28146 7B9E2481 D2A67EAC || exit 1;
# Validate signature
gpg --verify geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz.asc || exit 1;
# Unpack archive
tar xzf geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz || exit 1;
# /usr/bin is in $PATH by default, we'll put our binaries there
sudo cp geth-alltools-linux-amd64-1.6.0-facc47cb/* /usr/bin/ || exit 1;
}
function setup_node_info
{
declare -a NODE_IDS
#############
# Build node keys and node IDs
#############
for i in `seq 0 $(($NUM_BOOT_NODES - 1))`; do
BOOT_NODE_HOSTNAME=$MN_NODE_PREFIX$i;
NODE_KEYS[$i]=`echo $BOOT_NODE_HOSTNAME | sha256sum | cut -d ' ' -f 1`;
setsid geth -nodekeyhex ${NODE_KEYS[$i]} > $HOMEDIR/tempbootnodeoutput 2>&1 &
while sleep 10; do
if [ -s $HOMEDIR/tempbootnodeoutput ]; then
killall geth;
NODE_IDS[$i]=`grep -Po '(?<=\/\/).*(?=@)' $HOMEDIR/tempbootnodeoutput`;
rm $HOMEDIR/tempbootnodeoutput;
if [ $? -ne 0 ]; then
exit 1;
fi
break;
fi
done
done
##################################
# Check for empty node keys or IDs
##################################
for nodekey in "${NODE_KEYS[@]}"; do
if [ -z $nodekey ]; then
exit 1;
fi
done
for nodeid in "${NODE_IDS[@]}"; do
if [ -z $nodeid ]; then
exit 1;
fi
done
##########################
# Generate boot node URLs
##########################
for i in `seq 0 $(($NUM_BOOT_NODES - 1))`; do
BOOTNODE_URLS="${BOOTNODE_URLS} --bootnodes enode://${NODE_IDS[$i]}@#${MN_NODE_PREFIX}${i}#:${GETH_IPC_PORT}";
done
}
function setup_system_ethereum_account
{
PASSWD_FILE="$GETH_HOME/passwd.info";
printf %s $PASSWD > $PASSWD_FILE;
PRIV_KEY=`echo "$PASSPHRASE" | sha256sum | sed s/-// | sed "s/ //"`;
printf "%s" $PRIV_KEY > $HOMEDIR/priv_genesis.key;
PREFUND_ADDRESS=`geth --datadir $GETH_HOME --password $PASSWD_FILE account import $HOMEDIR/priv_genesis.key | grep -oP '\{\K[^}]+'`;
rm $HOMEDIR/priv_genesis.key;
rm $PASSWD_FILE;
}
function initialize_geth
{
####################
# Initialize geth for private network
####################
if [ $NODE_TYPE -eq 1 ] && [ $MN_NODE_SEQNUM -lt $NUM_BOOT_NODES ]; then #Boot node logic
printf %s ${NODE_KEYS[$MN_NODE_SEQNUM]} > $NODEKEY_SHARE_PATH;
fi
#################
# Initialize geth
#################
# Clear out old chaindata
rm -rf $GETH_HOME/geth/chaindata
geth --datadir $GETH_HOME -verbosity 6 init $GENESIS_FILE_PATH >> $GETH_LOG_FILE_PATH 2>&1;
if [ $? -ne 0 ]; then
exit 1;
fi
echo "===== Completed geth initialization =====";
}
function setup_admin_website
{
POWERSHELL_SHARE_PATH="$ETHERADMIN_HOME/public/ConsortiumBridge.psm1"
CLI_SHARE_PATH="$ETHERADMIN_HOME/public/ConsortiumBridge.sh"
#####################
# Setup admin website
#####################
if [ $NODE_TYPE -eq 0 ]; then # TX nodes only
mkdir -p $ETHERADMIN_HOME/views/layouts;
cd $ETHERADMIN_HOME/views/layouts;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/main.handlebars || exit 1;
cd $ETHERADMIN_HOME/views;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/etheradmin.handlebars || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/etherstartup.handlebars || exit 1;
cd $ETHERADMIN_HOME;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/package.json || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/npm-shrinkwrap.json || exit 1;
npm install || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/app.js || exit 1;
mkdir $ETHERADMIN_HOME/public;
cd $ETHERADMIN_HOME/public;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/skeleton.css || exit 1;
# Make consortium data available to joining members
cp $GENESIS_FILE_PATH $ETHERADMIN_HOME/public;
printf "%s" $NETWORK_ID > $NETWORKID_SHARE_PATH;
# Copy the powershell script to admin site
wget -N ${ARTIFACTS_URL_PREFIX}/powershell/ConsortiumBridge.psm1 -O ${POWERSHELL_SHARE_PATH} || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/ConsortiumBridge.sh -O ${CLI_SHARE_PATH} || exit 1;
fi
}
function create_config
{
##################
# Create conf file
##################
printf "%s\n" "HOMEDIR=$HOMEDIR" > $GETH_CFG_FILE_PATH;
printf "%s\n" "IDENTITY=$VMNAME" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NETWORK_ID=$NETWORK_ID" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "MAX_PEERS=$MAX_PEERS" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NODE_TYPE=$NODE_TYPE" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "BOOTNODE_URLS=\"$BOOTNODE_URLS\"" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "MN_NODE_PREFIX=$MN_NODE_PREFIX" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NUM_BOOT_NODES=$NUM_BOOT_NODES" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "MINER_THREADS=$MINER_THREADS" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "GETH_HOME=$GETH_HOME" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "GETH_LOG_FILE_PATH=$GETH_LOG_FILE_PATH" >> $GETH_CFG_FILE_PATH;
if [ $NODE_TYPE -eq 0 ]; then #TX node
printf "%s\n" "ETHERADMIN_HOME=$ETHERADMIN_HOME" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "PREFUND_ADDRESS=$PREFUND_ADDRESS" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NUM_MN_NODES=$NUM_MN_NODES" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "TX_NODE_PREFIX=$TX_NODE_PREFIX" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NUM_TX_NODES=$NUM_TX_NODES" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "ADMIN_SITE_PORT=$ADMIN_SITE_PORT" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "BOOTNODE_SHARE_PATH=$BOOTNODE_SHARE_PATH" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "CONSORTIUM_MEMBER_ID=$CONSORTIUM_MEMBER_ID" >> $GETH_CFG_FILE_PATH;
fi
}
function setup_rc_local
{
##########################################
# Setup rc.local for service start on boot
##########################################
echo -e '#!/bin/bash' "\nsudo -u $AZUREUSER /bin/bash $HOMEDIR/start-private-blockchain.sh $GETH_CFG_FILE_PATH $PASSWD \"\"" | sudo tee /etc/rc.local 2>&1 1>/dev/null
if [ $? -ne 0 ]; then
exit 1;
fi
}

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

@ -0,0 +1,188 @@
function setup_dependencies
{
################
# Update modules
################
sudo apt-get -y update || exit 1;
# To avoid intermittent issues with package DB staying locked when next apt-get runs
sleep 5;
##################
# Install packages
##################
sudo apt-get -y install npm=3.5.2-0ubuntu4 git=1:2.7.4-0ubuntu1 software-properties-common || exit 1;
sudo update-alternatives --install /usr/bin/node nodejs /usr/bin/nodejs 100 || exit 1;
##############
# Install geth
##############
wget https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz || exit 1;
wget https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz.asc || exit 1;
# Import geth buildserver keys
gpg --recv-keys --keyserver hkp://keyserver.ubuntu.com F9585DE6 C2FF8BBF 9BA28146 7B9E2481 D2A67EAC || exit 1;
# Validate signature
gpg --verify geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz.asc || exit 1;
# Unpack archive
tar xzf geth-alltools-linux-amd64-1.6.0-facc47cb.tar.gz || exit 1;
# /usr/bin is in $PATH by default, we'll put our binaries there
sudo cp geth-alltools-linux-amd64-1.6.0-facc47cb/* /usr/bin/ || exit 1;
}
function setup_node_info
{
declare -a NODE_IDS
#############
# Build node keys and node IDs
#############
for i in `seq 0 $(($NUM_BOOT_NODES - 1))`; do
BOOT_NODE_HOSTNAME=$MN_NODE_PREFIX$i;
NODE_KEYS[$i]=`echo $BOOT_NODE_HOSTNAME | sha256sum | cut -d ' ' -f 1`;
setsid geth -nodekeyhex ${NODE_KEYS[$i]} > $HOMEDIR/tempbootnodeoutput 2>&1 &
while sleep 10; do
if [ -s $HOMEDIR/tempbootnodeoutput ]; then
killall geth;
NODE_IDS[$i]=`grep -Po '(?<=\/\/).*(?=@)' $HOMEDIR/tempbootnodeoutput`;
rm $HOMEDIR/tempbootnodeoutput;
if [ $? -ne 0 ]; then
exit 1;
fi
break;
fi
done
done
##################################
# Check for empty node keys or IDs
##################################
for nodekey in "${NODE_KEYS[@]}"; do
if [ -z $nodekey ]; then
exit 1;
fi
done
for nodeid in "${NODE_IDS[@]}"; do
if [ -z $nodeid ]; then
exit 1;
fi
done
##########################
# Generate boot node URLs
##########################
for i in `seq 0 $(($NUM_BOOT_NODES - 1))`; do
BOOTNODE_URLS="${BOOTNODE_URLS} --bootnodes enode://${NODE_IDS[$i]}@#${MN_NODE_PREFIX}${i}#:${GETH_IPC_PORT}";
done
}
function setup_system_ethereum_account
{
PASSWD_FILE="$GETH_HOME/passwd.info";
printf %s $PASSWD > $PASSWD_FILE;
PRIV_KEY=`echo "$PASSPHRASE" | sha256sum | sed s/-// | sed "s/ //"`;
printf "%s" $PRIV_KEY > $HOMEDIR/priv_genesis.key;
PREFUND_ADDRESS=`geth --datadir $GETH_HOME --password $PASSWD_FILE account import $HOMEDIR/priv_genesis.key | grep -oP '\{\K[^}]+'`;
rm $HOMEDIR/priv_genesis.key;
rm $PASSWD_FILE;
}
function initialize_geth
{
####################
# Initialize geth for private network
####################
if [ $NODE_TYPE -eq 1 ] && [ $MN_NODE_SEQNUM -lt $NUM_BOOT_NODES ]; then #Boot node logic
printf %s ${NODE_KEYS[$MN_NODE_SEQNUM]} > $NODEKEY_SHARE_PATH;
fi
#################
# Initialize geth
#################
# Clear out old chaindata
rm -rf $GETH_HOME/geth/chaindata
geth --datadir $GETH_HOME -verbosity 6 init $GENESIS_FILE_PATH >> $GETH_LOG_FILE_PATH 2>&1;
if [ $? -ne 0 ]; then
exit 1;
fi
echo "===== Completed geth initialization =====";
}
function setup_admin_website
{
POWERSHELL_SHARE_PATH="$ETHERADMIN_HOME/public/ConsortiumBridge.psm1"
CLI_SHARE_PATH="$ETHERADMIN_HOME/public/ConsortiumBridge.sh"
#####################
# Setup admin website
#####################
if [ $NODE_TYPE -eq 0 ]; then # TX nodes only
mkdir -p $ETHERADMIN_HOME/views/layouts;
cd $ETHERADMIN_HOME/views/layouts;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/main.handlebars || exit 1;
cd $ETHERADMIN_HOME/views;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/etheradmin.handlebars || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/etherstartup.handlebars || exit 1;
cd $ETHERADMIN_HOME;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/package.json || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/npm-shrinkwrap.json || exit 1;
npm install || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/app.js || exit 1;
mkdir $ETHERADMIN_HOME/public;
cd $ETHERADMIN_HOME/public;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/etheradmin/skeleton.css || exit 1;
# Make consortium data available to joining members
cp $GENESIS_FILE_PATH $ETHERADMIN_HOME/public;
printf "%s" $NETWORK_ID > $NETWORKID_SHARE_PATH;
# Copy the powershell script to admin site
wget -N ${ARTIFACTS_URL_PREFIX}/powershell/ConsortiumBridge.psm1 -O ${POWERSHELL_SHARE_PATH} || exit 1;
wget -N ${ARTIFACTS_URL_PREFIX}/scripts/ConsortiumBridge.sh -O ${CLI_SHARE_PATH} || exit 1;
fi
}
function create_config
{
##################
# Create conf file
##################
printf "%s\n" "HOMEDIR=$HOMEDIR" > $GETH_CFG_FILE_PATH;
printf "%s\n" "IDENTITY=$VMNAME" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NETWORK_ID=$NETWORK_ID" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "MAX_PEERS=$MAX_PEERS" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NODE_TYPE=$NODE_TYPE" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "BOOTNODE_URLS=\"$BOOTNODE_URLS\"" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "MN_NODE_PREFIX=$MN_NODE_PREFIX" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NUM_BOOT_NODES=$NUM_BOOT_NODES" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "MINER_THREADS=$MINER_THREADS" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "GETH_HOME=$GETH_HOME" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "GETH_LOG_FILE_PATH=$GETH_LOG_FILE_PATH" >> $GETH_CFG_FILE_PATH;
if [ $NODE_TYPE -eq 0 ]; then #TX node
printf "%s\n" "ETHERADMIN_HOME=$ETHERADMIN_HOME" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "PREFUND_ADDRESS=$PREFUND_ADDRESS" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NUM_MN_NODES=$NUM_MN_NODES" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "TX_NODE_PREFIX=$TX_NODE_PREFIX" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "NUM_TX_NODES=$NUM_TX_NODES" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "ADMIN_SITE_PORT=$ADMIN_SITE_PORT" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "BOOTNODE_SHARE_PATH=$BOOTNODE_SHARE_PATH" >> $GETH_CFG_FILE_PATH;
printf "%s\n" "CONSORTIUM_MEMBER_ID=$CONSORTIUM_MEMBER_ID" >> $GETH_CFG_FILE_PATH;
fi
}
function setup_rc_local
{
##########################################
# Setup rc.local for service start on boot
##########################################
echo -e '#!/bin/bash' "\nsudo -u $AZUREUSER /bin/bash $HOMEDIR/start-private-blockchain.sh $GETH_CFG_FILE_PATH $PASSWD \"\"" | sudo tee /etc/rc.local 2>&1 1>/dev/null
if [ $? -ne 0 ]; then
exit 1;
fi
}

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

@ -0,0 +1,170 @@
var express = require('express');
var exphbs = require('express-handlebars');
var session = require('express-session');
var bodyParser = require('body-parser');
var fs = require('fs');
var dns = require('dns');
var Web3 = require('web3');
var moment = require('moment');
var Promise = require('promise');
/*
* Parameters
*/
var listenPort = process.argv[2]
var gethIPCPath = process.argv[3];
var coinbase = process.argv[4];
var coinbasePw = process.argv[5];
var mnNodePrefix = process.argv[6];
var numMNNodes = process.argv[7];
var txNodePrefix = process.argv[8];
var numTXNodes = process.argv[9];
var consortiumId = process.argv[10];
/*
* Constants
*/
var gethRPCPort = "8545";
var refreshInterval = 10000;
var app = express();
var web3IPC = new Web3(new Web3.providers.IpcProvider(gethIPCPath, require('net')));
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
secret: coinbasePw,
resave: false,
saveUninitialized: true
}))
var nodeInfoArray = [];
var timeStamp;
function getNodeInfo(hostName) {
return new Promise(function (resolve, reject){
try {
var web3RPC = new Web3(new Web3.providers.HttpProvider("http://" + hostName + ":" + gethRPCPort));
}
catch(err) {
console.log(err);
}
var web3PromiseArray = [];
web3PromiseArray.push(new Promise(function(resolve, reject) {
web3RPC.net.getPeerCount(function(error, result) {
if(!error)
{
resolve(result);
}
else {
resolve("Not running");
}
});
}));
web3PromiseArray.push(new Promise(function(resolve, reject) {
web3RPC.eth.getBlockNumber(function(error, result) {
if(!error)
{
resolve(result);
}
else {
resolve("Not running");
}
});
}));
Promise.all(web3PromiseArray).then(function(values){
var peerCount = values[0];
var blockNumber = values[1];
var nodeInfo = {hostname: hostName, peercount: peerCount, blocknumber: blockNumber};
resolve(nodeInfo);
});
});
}
function getNodesInfo() {
console.time("getNodesInfo");
var promiseArray = [];
for(var i = 0; i < numTXNodes; i++) {
promiseArray.push(getNodeInfo(txNodePrefix.concat(i)));
}
for(var i = 0; i < numMNNodes; i++) {
promiseArray.push(getNodeInfo(mnNodePrefix.concat(i)));
}
Promise.all(promiseArray).then(function(values) {
nodeInfoArray = [];
var arrLen = values.length;
for(var i = 0; i< arrLen; ++i) {
nodeInfoArray.push(values[i]);
}
// sort in alphabetical order
nodeInfoArray = nodeInfoArray.sort();
timeStamp = moment().format('h:mm:ss A UTC, MMM Do YYYY');
console.timeEnd("getNodesInfo");
// Schedule next refresh
setTimeout(getNodesInfo, refreshInterval);
});
}
// Kick-off refresh cycle
getNodesInfo();
// Check if we've mined a block yet
function minedABlock () {
var result = nodeInfoArray.filter(function(item) {
return item.blocknumber > 0;
});
return result.length > 0;
}
app.get('/', function (req, res) {
// Check if the IPC endpoint is up and running
if(fs.existsSync(gethIPCPath)) {
var hasNodeRows = nodeInfoArray.length > 0;
web3IPC.eth.getBalance(
coinbase,
function(err, result)
{
var balance = web3IPC.fromWei(result, "ether");
console.log(coinbase + ": " + result)
var data = { isSent: req.session.isSent, error: req.session.error, hasNodeRows: hasNodeRows, myAddress: coinbase, myBalance: balance, consortiumid: consortiumId, nodeRows: nodeInfoArray, minedABlock: minedABlock(), timestamp: timeStamp, refreshinterval: (refreshInterval/1000) };
req.session.isSent = false;
req.session.error = false;
res.render('etheradmin', data);
});
}
else {
res.render('etherstartup');
}
});
app.post('/', function(req, res) {
var address = req.body.etherAddress;
var amount = req.body.amount;
if(web3IPC.isAddress(address)) {
web3IPC.personal.unlockAccount(coinbase, coinbasePw, function(err, res) {
console.log(res);
web3IPC.eth.sendTransaction({from: coinbase, to: address, value: web3IPC.toWei(amount, 'ether')}, function(err, res){ console.log(address)});
});
req.session.isSent = true;
} else {
req.session.error = "Not a valid Ethereum address";
}
res.redirect('/');
});
app.listen(listenPort, function () {
console.log('Admin webserver listening on port ' + listenPort);
});

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

@ -0,0 +1,62 @@
<div class="container">
<table class="u-full-width">
<tbody>
<tr>
<td><h2>Ethereum Node Status</h2></td>
<td>
<form action="" method="GET">
<input class="button-primary" type="submit" value="Reload">
</form>
</td>
</tr>
</tbody>
</table>
<b>Consortium Member ID: {{this.consortiumid}}<b>
<p>My Account Address: {{this.myAddress}}<br>
Ether Balance: {{this.myBalance}}</p>
{{#if hasNodeRows}}
<table class="u-full-width">
<thead>
<tr>
<th>Node Hostname</th>
<th>Peer Count</th>
<th>Latest Block Number</th>
</tr>
</thead>
<tbody>
{{#each nodeRows}}
<tr>
<td>{{this.hostname}}</td>
<td>{{this.peercount}}</td>
<td>{{this.blocknumber}}</td>
</tr>
{{/each}}
</tbody>
</table>
<i>As of {{this.timestamp}} (Refresh interval: ~{{this.refreshinterval}} seconds)</i>
<hr />
{{else}}
<h4>Waiting on all Ethereum nodes to boot up...</h4>
{{/if}}
<h3>Bootstrap New Address with Ether</h3>
{{#if minedABlock}}
<p>Use this function to send Ether from the predefined account to a new address</p>
<form action="" method="POST">
<label for="etherAddress">Address of Recipient</label>
<input class="u-full-width" type="text" placeholder="Ex: 0x17Bf5e7b3CE6779DBaeDEB907010601A8c1e3118"
name="etherAddress">
<label for="amount">Amount</label>
<input class="u-full-width" type="number" name="amount" value="1000" min="0">
<input class="button-primary" type="submit" value="Submit">
</form>
{{#if error}}
<h4>Error sending ether</h4>
<p>{{error}}</p>
{{/if}}
{{#if isSent}}
<h4>Ether sent!</h4>
{{/if}}
{{else}}
<h4>Waiting for first block to be mined...</h4>
{{/if}}
</div>

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

@ -0,0 +1,14 @@
<div class="container">
<table>
<tbody>
<tr>
<td><h1>Waiting on local geth node to boot...</h1></td>
<td>
<form action="" method="GET">
<input class="button-primary" type="submit" value="Refresh">
</form>
</td>
</tr>
</tbody>
</table>
</div>

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockchain Admin</title>
<link rel="stylesheet" href="skeleton.css">
</head>
<body>
{{{body}}}
</body>
</html>

578
ethereum-consortium-blockchain/scripts/etheradmin/npm-shrinkwrap.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,578 @@
{
"name": "etheradmin",
"version": "0.0.0",
"dependencies": {
"accepts": {
"version": "1.3.3",
"from": "accepts@>=1.3.3 <1.4.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz"
},
"align-text": {
"version": "0.1.4",
"from": "align-text@>=0.1.3 <0.2.0",
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz"
},
"amdefine": {
"version": "1.0.1",
"from": "amdefine@>=0.0.4",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz"
},
"array-flatten": {
"version": "1.1.1",
"from": "array-flatten@1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz"
},
"asap": {
"version": "2.0.5",
"from": "asap@>=2.0.3 <2.1.0",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz"
},
"async": {
"version": "1.5.2",
"from": "async@>=1.4.0 <2.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
},
"balanced-match": {
"version": "1.0.0",
"from": "balanced-match@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz"
},
"bignumber.js": {
"version": "4.0.2",
"from": "bignumber.js@>=4.0.2 <5.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.2.tgz"
},
"body-parser": {
"version": "1.16.1",
"from": "body-parser@>=1.16.1 <1.17.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.16.1.tgz"
},
"brace-expansion": {
"version": "1.1.8",
"from": "brace-expansion@>=1.1.7 <2.0.0",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz"
},
"bytes": {
"version": "2.4.0",
"from": "bytes@2.4.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz"
},
"camelcase": {
"version": "1.2.1",
"from": "camelcase@>=1.0.2 <2.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
},
"center-align": {
"version": "0.1.3",
"from": "center-align@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz"
},
"cliui": {
"version": "2.1.0",
"from": "cliui@>=2.1.0 <3.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
"dependencies": {
"wordwrap": {
"version": "0.0.2",
"from": "wordwrap@0.0.2",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
}
}
},
"concat-map": {
"version": "0.0.1",
"from": "concat-map@0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
},
"content-disposition": {
"version": "0.5.2",
"from": "content-disposition@0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz"
},
"content-type": {
"version": "1.0.2",
"from": "content-type@>=1.0.2 <1.1.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz"
},
"cookie": {
"version": "0.3.1",
"from": "cookie@0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz"
},
"cookie-signature": {
"version": "1.0.6",
"from": "cookie-signature@1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
},
"crc": {
"version": "3.4.4",
"from": "crc@3.4.4",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz"
},
"crypto-js": {
"version": "3.1.8",
"from": "crypto-js@>=3.1.4 <4.0.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz"
},
"debug": {
"version": "2.6.1",
"from": "debug@2.6.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz"
},
"decamelize": {
"version": "1.2.0",
"from": "decamelize@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
},
"define-properties": {
"version": "1.1.2",
"from": "define-properties@>=1.1.2 <2.0.0",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz"
},
"depd": {
"version": "1.1.0",
"from": "depd@>=1.1.0 <1.2.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz"
},
"destroy": {
"version": "1.0.4",
"from": "destroy@>=1.0.4 <1.1.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz"
},
"ee-first": {
"version": "1.1.1",
"from": "ee-first@1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
},
"encodeurl": {
"version": "1.0.1",
"from": "encodeurl@>=1.0.1 <1.1.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz"
},
"escape-html": {
"version": "1.0.3",
"from": "escape-html@>=1.0.3 <1.1.0",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz"
},
"etag": {
"version": "1.8.0",
"from": "etag@>=1.8.0 <1.9.0",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz"
},
"express": {
"version": "4.15.3",
"from": "express@>=4.15.2 <5.0.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.15.3.tgz",
"dependencies": {
"debug": {
"version": "2.6.7",
"from": "debug@2.6.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz"
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
},
"qs": {
"version": "6.4.0",
"from": "qs@6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz"
},
"setprototypeof": {
"version": "1.0.3",
"from": "setprototypeof@1.0.3",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz"
}
}
},
"express-handlebars": {
"version": "3.0.0",
"from": "express-handlebars@>=3.0.0 <3.1.0",
"resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.0.0.tgz"
},
"express-session": {
"version": "1.15.3",
"from": "express-session@>=1.15.2 <2.0.0",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.3.tgz",
"dependencies": {
"debug": {
"version": "2.6.7",
"from": "debug@2.6.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz"
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
}
}
},
"finalhandler": {
"version": "1.0.3",
"from": "finalhandler@>=1.0.3 <1.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz",
"dependencies": {
"debug": {
"version": "2.6.7",
"from": "debug@2.6.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz"
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
}
}
},
"foreach": {
"version": "2.0.5",
"from": "foreach@>=2.0.5 <3.0.0",
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz"
},
"forwarded": {
"version": "0.1.0",
"from": "forwarded@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz"
},
"fresh": {
"version": "0.5.0",
"from": "fresh@0.5.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz"
},
"function-bind": {
"version": "1.1.0",
"from": "function-bind@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz"
},
"glob": {
"version": "6.0.4",
"from": "glob@>=6.0.4 <7.0.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz"
},
"graceful-fs": {
"version": "4.1.11",
"from": "graceful-fs@>=4.1.2 <5.0.0",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
},
"handlebars": {
"version": "4.0.10",
"from": "handlebars@>=4.0.5 <5.0.0",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz"
},
"http-errors": {
"version": "1.5.1",
"from": "http-errors@>=1.5.1 <1.6.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz"
},
"iconv-lite": {
"version": "0.4.15",
"from": "iconv-lite@0.4.15",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz"
},
"inflight": {
"version": "1.0.6",
"from": "inflight@>=1.0.4 <2.0.0",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
},
"inherits": {
"version": "2.0.3",
"from": "inherits@2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
},
"ipaddr.js": {
"version": "1.3.0",
"from": "ipaddr.js@1.3.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz"
},
"is-buffer": {
"version": "1.1.5",
"from": "is-buffer@>=1.1.5 <2.0.0",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz"
},
"kind-of": {
"version": "3.2.2",
"from": "kind-of@>=3.0.2 <4.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
},
"lazy-cache": {
"version": "1.0.4",
"from": "lazy-cache@>=1.0.3 <2.0.0",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz"
},
"longest": {
"version": "1.0.1",
"from": "longest@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz"
},
"media-typer": {
"version": "0.3.0",
"from": "media-typer@0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
},
"merge-descriptors": {
"version": "1.0.1",
"from": "merge-descriptors@1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz"
},
"methods": {
"version": "1.1.2",
"from": "methods@>=1.1.2 <1.2.0",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz"
},
"mime": {
"version": "1.3.4",
"from": "mime@1.3.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz"
},
"mime-db": {
"version": "1.27.0",
"from": "mime-db@>=1.27.0 <1.28.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz"
},
"mime-types": {
"version": "2.1.15",
"from": "mime-types@>=2.1.15 <2.2.0",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz"
},
"minimatch": {
"version": "3.0.4",
"from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"
},
"minimist": {
"version": "0.0.10",
"from": "minimist@>=0.0.1 <0.1.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
},
"moment": {
"version": "2.17.1",
"from": "moment@>=2.17.1 <2.18.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz"
},
"ms": {
"version": "0.7.2",
"from": "ms@0.7.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
},
"negotiator": {
"version": "0.6.1",
"from": "negotiator@0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz"
},
"object-keys": {
"version": "1.0.11",
"from": "object-keys@>=1.0.10 <2.0.0",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz"
},
"object.assign": {
"version": "4.0.4",
"from": "object.assign@>=4.0.3 <5.0.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz"
},
"on-finished": {
"version": "2.3.0",
"from": "on-finished@>=2.3.0 <2.4.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz"
},
"on-headers": {
"version": "1.0.1",
"from": "on-headers@>=1.0.1 <1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz"
},
"once": {
"version": "1.4.0",
"from": "once@>=1.3.0 <2.0.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
},
"optimist": {
"version": "0.6.1",
"from": "optimist@>=0.6.1 <0.7.0",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz"
},
"parseurl": {
"version": "1.3.1",
"from": "parseurl@>=1.3.1 <1.4.0",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz"
},
"path-is-absolute": {
"version": "1.0.1",
"from": "path-is-absolute@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
},
"path-to-regexp": {
"version": "0.1.7",
"from": "path-to-regexp@0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz"
},
"promise": {
"version": "7.1.1",
"from": "promise@>=7.1.1 <7.2.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz"
},
"proxy-addr": {
"version": "1.1.4",
"from": "proxy-addr@>=1.1.4 <1.2.0",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz"
},
"qs": {
"version": "6.2.1",
"from": "qs@6.2.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz"
},
"random-bytes": {
"version": "1.0.0",
"from": "random-bytes@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz"
},
"range-parser": {
"version": "1.2.0",
"from": "range-parser@>=1.2.0 <1.3.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz"
},
"raw-body": {
"version": "2.2.0",
"from": "raw-body@>=2.2.0 <2.3.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz"
},
"repeat-string": {
"version": "1.6.1",
"from": "repeat-string@>=1.5.2 <2.0.0",
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz"
},
"right-align": {
"version": "0.1.3",
"from": "right-align@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz"
},
"send": {
"version": "0.15.3",
"from": "send@0.15.3",
"resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz",
"dependencies": {
"debug": {
"version": "2.6.7",
"from": "debug@2.6.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz"
},
"http-errors": {
"version": "1.6.1",
"from": "http-errors@>=1.6.1 <1.7.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz"
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
},
"setprototypeof": {
"version": "1.0.3",
"from": "setprototypeof@1.0.3",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz"
}
}
},
"serve-static": {
"version": "1.12.3",
"from": "serve-static@1.12.3",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz"
},
"setprototypeof": {
"version": "1.0.2",
"from": "setprototypeof@1.0.2",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz"
},
"source-map": {
"version": "0.4.4",
"from": "source-map@>=0.4.4 <0.5.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
},
"statuses": {
"version": "1.3.1",
"from": "statuses@>=1.3.1 <2.0.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz"
},
"type-is": {
"version": "1.6.15",
"from": "type-is@>=1.6.14 <1.7.0",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz"
},
"uglify-js": {
"version": "2.8.29",
"from": "uglify-js@>=2.6.0 <3.0.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
"dependencies": {
"source-map": {
"version": "0.5.6",
"from": "source-map@>=0.5.1 <0.6.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
}
}
},
"uglify-to-browserify": {
"version": "1.0.2",
"from": "uglify-to-browserify@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
},
"uid-safe": {
"version": "2.1.4",
"from": "uid-safe@>=2.1.4 <2.2.0",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz"
},
"unpipe": {
"version": "1.0.0",
"from": "unpipe@1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
},
"utf8": {
"version": "2.1.2",
"from": "utf8@>=2.1.1 <3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz"
},
"utils-merge": {
"version": "1.0.0",
"from": "utils-merge@1.0.0",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz"
},
"vary": {
"version": "1.1.1",
"from": "vary@>=1.1.1 <1.2.0",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz"
},
"web3": {
"version": "0.19.1",
"from": "web3@>=0.19.1 <0.20.0",
"resolved": "https://registry.npmjs.org/web3/-/web3-0.19.1.tgz"
},
"window-size": {
"version": "0.1.0",
"from": "window-size@0.1.0",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
},
"wordwrap": {
"version": "0.0.3",
"from": "wordwrap@>=0.0.2 <0.1.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
},
"wrappy": {
"version": "1.0.2",
"from": "wrappy@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
},
"xhr2": {
"version": "0.1.4",
"from": "xhr2@*",
"resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz"
},
"xmlhttprequest": {
"version": "1.8.0",
"from": "xmlhttprequest@*",
"resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz"
},
"yargs": {
"version": "3.10.0",
"from": "yargs@>=3.10.0 <3.11.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz"
}
}
}

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

@ -0,0 +1,20 @@
{
"name": "etheradmin",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "BSD-2-Clause",
"dependencies": {
"body-parser": "~1.16.1",
"express": "^4.15.2",
"express-handlebars": "~3.0.0",
"express-session": "^1.15.2",
"moment": "~2.17.1",
"promise": "~7.1.1",
"web3": "~0.19.1"
}
}

418
ethereum-consortium-blockchain/scripts/etheradmin/skeleton.css поставляемый Normal file
Просмотреть файл

@ -0,0 +1,418 @@
/*
* Skeleton V2.0.4
* Copyright 2014, Dave Gamache
* www.getskeleton.com
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* 12/29/2014
*/
/* Table of contents
- Grid
- Base Styles
- Typography
- Links
- Buttons
- Forms
- Lists
- Code
- Tables
- Spacing
- Utilities
- Clearing
- Media Queries
*/
/* Grid
*/
.container {
position: relative;
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 0 20px;
box-sizing: border-box; }
.column,
.columns {
width: 100%;
float: left;
box-sizing: border-box; }
/* For devices larger than 400px */
@media (min-width: 400px) {
.container {
width: 85%;
padding: 0; }
}
/* For devices larger than 550px */
@media (min-width: 550px) {
.container {
width: 80%; }
.column,
.columns {
margin-left: 4%; }
.column:first-child,
.columns:first-child {
margin-left: 0; }
.one.column,
.one.columns { width: 4.66666666667%; }
.two.columns { width: 13.3333333333%; }
.three.columns { width: 22%; }
.four.columns { width: 30.6666666667%; }
.five.columns { width: 39.3333333333%; }
.six.columns { width: 48%; }
.seven.columns { width: 56.6666666667%; }
.eight.columns { width: 65.3333333333%; }
.nine.columns { width: 74.0%; }
.ten.columns { width: 82.6666666667%; }
.eleven.columns { width: 91.3333333333%; }
.twelve.columns { width: 100%; margin-left: 0; }
.one-third.column { width: 30.6666666667%; }
.two-thirds.column { width: 65.3333333333%; }
.one-half.column { width: 48%; }
/* Offsets */
.offset-by-one.column,
.offset-by-one.columns { margin-left: 8.66666666667%; }
.offset-by-two.column,
.offset-by-two.columns { margin-left: 17.3333333333%; }
.offset-by-three.column,
.offset-by-three.columns { margin-left: 26%; }
.offset-by-four.column,
.offset-by-four.columns { margin-left: 34.6666666667%; }
.offset-by-five.column,
.offset-by-five.columns { margin-left: 43.3333333333%; }
.offset-by-six.column,
.offset-by-six.columns { margin-left: 52%; }
.offset-by-seven.column,
.offset-by-seven.columns { margin-left: 60.6666666667%; }
.offset-by-eight.column,
.offset-by-eight.columns { margin-left: 69.3333333333%; }
.offset-by-nine.column,
.offset-by-nine.columns { margin-left: 78.0%; }
.offset-by-ten.column,
.offset-by-ten.columns { margin-left: 86.6666666667%; }
.offset-by-eleven.column,
.offset-by-eleven.columns { margin-left: 95.3333333333%; }
.offset-by-one-third.column,
.offset-by-one-third.columns { margin-left: 34.6666666667%; }
.offset-by-two-thirds.column,
.offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
.offset-by-one-half.column,
.offset-by-one-half.columns { margin-left: 52%; }
}
/* Base Styles
*/
/* NOTE
html is set to 62.5% so that all the REM measurements throughout Skeleton
are based on 10px sizing. So basically 1.5rem = 15px :) */
html {
font-size: 62.5%; }
body {
font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
line-height: 1.6;
font-weight: 400;
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #222; }
/* Typography
*/
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 2rem;
font-weight: 300; }
h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
/* Larger than phablet */
@media (min-width: 550px) {
h1 { font-size: 5.0rem; }
h2 { font-size: 4.2rem; }
h3 { font-size: 3.6rem; }
h4 { font-size: 3.0rem; }
h5 { font-size: 2.4rem; }
h6 { font-size: 1.5rem; }
}
p {
margin-top: 0; }
/* Links
*/
a {
color: #1EAEDB; }
a:hover {
color: #0FA0CE; }
/* Buttons
*/
.button,
button,
input[type="submit"],
input[type="reset"],
input[type="button"] {
display: inline-block;
height: 38px;
padding: 0 30px;
color: #555;
text-align: center;
font-size: 11px;
font-weight: 600;
line-height: 38px;
letter-spacing: .1rem;
text-transform: uppercase;
text-decoration: none;
white-space: nowrap;
background-color: transparent;
border-radius: 4px;
border: 1px solid #bbb;
cursor: pointer;
box-sizing: border-box; }
.button:hover,
button:hover,
input[type="submit"]:hover,
input[type="reset"]:hover,
input[type="button"]:hover,
.button:focus,
button:focus,
input[type="submit"]:focus,
input[type="reset"]:focus,
input[type="button"]:focus {
color: #333;
border-color: #888;
outline: 0; }
.button.button-primary,
button.button-primary,
input[type="submit"].button-primary,
input[type="reset"].button-primary,
input[type="button"].button-primary {
color: #FFF;
background-color: #33C3F0;
border-color: #33C3F0; }
.button.button-primary:hover,
button.button-primary:hover,
input[type="submit"].button-primary:hover,
input[type="reset"].button-primary:hover,
input[type="button"].button-primary:hover,
.button.button-primary:focus,
button.button-primary:focus,
input[type="submit"].button-primary:focus,
input[type="reset"].button-primary:focus,
input[type="button"].button-primary:focus {
color: #FFF;
background-color: #1EAEDB;
border-color: #1EAEDB; }
/* Forms
*/
input[type="email"],
input[type="number"],
input[type="search"],
input[type="text"],
input[type="tel"],
input[type="url"],
input[type="password"],
textarea,
select {
height: 38px;
padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
background-color: #fff;
border: 1px solid #D1D1D1;
border-radius: 4px;
box-shadow: none;
box-sizing: border-box; }
/* Removes awkward default styles on some inputs for iOS */
input[type="email"],
input[type="number"],
input[type="search"],
input[type="text"],
input[type="tel"],
input[type="url"],
input[type="password"],
textarea {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none; }
textarea {
min-height: 65px;
padding-top: 6px;
padding-bottom: 6px; }
input[type="email"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
input[type="text"]:focus,
input[type="tel"]:focus,
input[type="url"]:focus,
input[type="password"]:focus,
textarea:focus,
select:focus {
border: 1px solid #33C3F0;
outline: 0; }
label,
legend {
display: block;
margin-bottom: .5rem;
font-weight: 600; }
fieldset {
padding: 0;
border-width: 0; }
input[type="checkbox"],
input[type="radio"] {
display: inline; }
label > .label-body {
display: inline-block;
margin-left: .5rem;
font-weight: normal; }
/* Lists
*/
ul {
list-style: circle inside; }
ol {
list-style: decimal inside; }
ol, ul {
padding-left: 0;
margin-top: 0; }
ul ul,
ul ol,
ol ol,
ol ul {
margin: 1.5rem 0 1.5rem 3rem;
font-size: 90%; }
li {
margin-bottom: 1rem; }
/* Code
*/
code {
padding: .2rem .5rem;
margin: 0 .2rem;
font-size: 90%;
white-space: nowrap;
background: #F1F1F1;
border: 1px solid #E1E1E1;
border-radius: 4px; }
pre > code {
display: block;
padding: 1rem 1.5rem;
white-space: pre; }
/* Tables
*/
th,
td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #E1E1E1; }
th:first-child,
td:first-child {
padding-left: 0; }
th:last-child,
td:last-child {
padding-right: 0; }
/* Spacing
*/
button,
.button {
margin-bottom: 1rem; }
input,
textarea,
select,
fieldset {
margin-bottom: 1.5rem; }
pre,
blockquote,
dl,
figure,
table,
p,
ul,
ol,
form {
margin-bottom: 2.5rem; }
/* Utilities
*/
.u-full-width {
width: 100%;
box-sizing: border-box; }
.u-max-full-width {
max-width: 100%;
box-sizing: border-box; }
.u-pull-right {
float: right; }
.u-pull-left {
float: left; }
/* Misc
*/
hr {
margin-top: 3rem;
margin-bottom: 3.5rem;
border-width: 0;
border-top: 1px solid #E1E1E1; }
/* Clearing
*/
/* Self Clearing Goodness */
.container:after,
.row:after,
.u-cf {
content: "";
display: table;
clear: both; }
/* Media Queries
*/
/*
Note: The best way to structure the use of media queries is to create the queries
near the relevant code. For example, if you wanted to change the styles for buttons
on small devices, paste the mobile query code up in the buttons section and style it
there.
*/
/* Larger than mobile */
@media (min-width: 400px) {}
/* Larger than phablet (also point when grid becomes active) */
@media (min-width: 550px) {}
/* Larger than tablet */
@media (min-width: 750px) {}
/* Larger than desktop */
@media (min-width: 1000px) {}
/* Larger than Desktop HD */
@media (min-width: 1200px) {}

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

@ -0,0 +1,47 @@
pragma solidity ^0.4.0;
contract StateHolder {
address public owner;
uint public openNumber;
string public openString;
string public myString;
modifier onlyOwner {
if (msg.sender != owner)
throw;
_;
}
function StateHolder() {
owner = msg.sender;
}
function changeOpenNumber(uint _newNumber) {
openNumber = _newNumber;
}
function changeOpenString(string _newString) {
openString = _newString;
}
function changeMyString(string _newString) onlyOwner {
myString = _newString;
}
}
contract Token {
mapping (address => uint) public balances;
function Token() {
balances[msg.sender] = 1000000;
}
function transfer(address _to, uint _amount) {
if (balances[msg.sender] < _amount) {
throw;
}
balances[msg.sender] -= _amount;
balances[_to] += _amount;
}
}

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

@ -0,0 +1,111 @@
#!/bin/bash
#############
# Parameters
#############
if [ $# -lt 2 ]; then echo "Incomplete parameters supplied. usage: \"$0 <config file path> <ethereum account passwd>\""; exit 1; fi
GETH_CFG=$1;
PASSWD=$2;
IP_TO_PING=$3;
########################
# Load config variables
########################
if [ ! -e $GETH_CFG ]; then echo "Config file not found. Exiting"; exit 1; fi
. $GETH_CFG
#############
# Constants
#############
ETHERADMIN_LOG_FILE_PATH="$HOMEDIR/etheradmin.log";
# Log level of geth
VERBOSITY=4;
###########################################
# Ensure that at least one bootnode is up
# If not, wait 5 seconds then retry
###########################################
FOUND_BOOTNODE=false
while sleep 5; do
for i in `seq 0 $(($NUM_BOOT_NODES - 1))`; do
if [ `hostname` = $MN_NODE_PREFIX$i ]; then
continue
fi
LOOKUP=`nslookup $MN_NODE_PREFIX$i | grep "can't find"`
if [ -z $LOOKUP ]; then
FOUND_BOOTNODE=true
break
fi
done
if [ "$FOUND_BOOTNODE" = true ]; then
break
fi
done
#####################################################
# Replace hostnames in config file with IP addresses
#####################################################
BOOTNODE_URLS=`echo $BOOTNODE_URLS | perl -pe 's/#(.*?)#/qx\/nslookup $1| egrep "Address: [0-9]"| cut -d" " -f2 | xargs echo -n\//ge'`
############################################################
# Make boot node urls available to other consortium members
############################################################
if [ $NODE_TYPE -eq 0 ]; then
printf "%s" "$BOOTNODE_URLS" > $BOOTNODE_SHARE_PATH; # overwrite, don't append
fi
######################################
# Get IP address for geth RPC binding
######################################
IPADDR=`ifconfig eth0 | grep "inet addr" | cut -d ':' -f 2 | cut -d ' ' -f 1`;
############################
# Only mine on mining nodes
############################
if [ $NODE_TYPE -ne 0 ]; then
MINE_OPTIONS="--mine --minerthreads $MINER_THREADS";
else
FAST_SYNC="--fast";
fi
##########################################
# Startup admin site if this is a TX Node
##########################################
if [ $NODE_TYPE -eq 0 ]; then
cd $ETHERADMIN_HOME;
echo "===== Starting admin webserver =====";
nohup nodejs app.js $ADMIN_SITE_PORT $GETH_HOME/geth.ipc $PREFUND_ADDRESS $PASSWD $MN_NODE_PREFIX $NUM_MN_NODES $TX_NODE_PREFIX $NUM_TX_NODES $CONSORTIUM_MEMBER_ID >> $ETHERADMIN_LOG_FILE_PATH 2>&1 &
if [ $? -ne 0 ]; then echo "Previous command failed. Exiting"; exit $?; fi
echo "===== Started admin webserver =====";
fi
echo "===== Completed $0 =====";
############
# Spin until connection has been established
############
while [ ${#IP_TO_PING} -gt 0 ]
do
ping -c 1 $IP_TO_PING > /dev/null
if [ $? -eq 0 ]
then
echo "connection established"
break
fi
sleep 60
done
##################
# Start geth node
##################
echo "===== Starting geth node =====";
set -x;
nohup geth --datadir $GETH_HOME -verbosity $VERBOSITY $BOOTNODE_URLS --maxpeers $MAX_PEERS --nat none --networkid $NETWORK_ID --identity $IDENTITY $MINE_OPTIONS $FAST_SYNC --rpc --rpcaddr "$IPADDR" --rpccorsdomain "*" >> $GETH_LOG_FILE_PATH 2>&1 &
if [ $? -ne 0 ]; then echo "Previous command failed. Exiting"; exit $?; fi
set +x;
echo "===== Started geth node =====";

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

@ -0,0 +1,13 @@
# ARM Template automated validation via Powershell Guide
<Work in progress - watch this space>
## Initial setup
1. Make a copy of the ARMTemplate-automated-validation.ps1 file and include the word "personal" in the file name to avoid it from being checked-in accidentally
2. If you are testing the marketplace deployment template (mainTemplate.json) you will need to make a copy of those parameter files and swap in the location where the template files you are testing reside - replace the <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>. e.g. you may have your files in Azure storage so place the URI of the folder where the main template is located.
3. Set the value of constants in this file to relevant ones for your environment and desired tests
4. The script will ask you to login to Azure the first time in each session. IMPORTANT: Do not save this password into any of the scripts to avoid the risk of checking this secret into the repo accidentally
5. I recommend working in Windows PowerShell ISE as you can edit the script and see the console in onw view and it has a nice Module explorer built-in as well as auto-complete etc.
## Parameter fiels
Parameter files define a set of input parameters that are used to run multiple deployments in parallel. If you have 5 sets of parameters, 5 deployments will be kicked off. You can then tear down all 5 deployments with a single command (Option "T" in the script)

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

@ -0,0 +1,10 @@
# !!! Set all mandatory variables used in the params file here !!!
$baseUrl = $MARKETPLACE_BASE_URL # (location of artifacts that are being validated, set to folder path of template file)
$location = $LOCATION;
#$authType = (either password or sshPublicKey) and corresponding variable below:
#$vmAdminPasswd =
#$sshPublicKey =
#$ethPasswd =
#$passphrase =
# Load the params file which will set the $paramSet variable
# !!! Set all mandatory variables used in the params file here !!!

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

@ -0,0 +1,18 @@
# Uncomment line below only on Automated Monitoring VM. For local machine, ServicePrinciplePasswdLoader.ps1 will dynamically set the password.
# IMPORTANT: !!!!! Set the $global:SP_PASSWD only on the file on the monitoring VM to avoid accidental check-in with source code !!!!!
#$global:SP_PASSWD = "";
# Subscription under which resources will be deployed
$SUBSCRIPTION_ID = "";
# Azure Location where resource group and all resources will be deployed in (format e.g. "Central US" or "centralus")
$LOCATION = "";
# Root folder within which all template files that are being validated are contained. Determine latest path via test
# deployment of published marketplace solution.
$MARKETPLACE_BASE_URL = "";
$MARKETPLACE_TEMPLATE_URI = $MARKETPLACE_BASE_URL+"\mainTemplate.json";
$QUICKSTART_TEMPLATE_URI = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/ethereum-consortium-blockchain-network/azuredeploy.json";
$NOTIFICATION_ENABLED = "TRUE"; # Any value other than "TRUE" will disable notification
$NOTIFICATION_USER_NAME = "azure_bc8d0746cc32dcb3aceee23ddb70a0f7@azure.com"; # Username of sendgrid account
$NOTIFICATION_PASSWORD = ""; # Password of sendgrid account (Stored in Key Vault of Runner subscription)
$NOTIFICATION_ALIAS = "";

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

@ -0,0 +1,69 @@
#####
# IMPORTANT: !!!!! Ensure the password is set outside of this script to prevent a secret from being checked into the repo accidentally !!!!!
#####
# This script performs a fully automated deployment and teardown of ARM tepmplates using configured parameters and us used
# for automated canary monitoring and alerting of the Blockchain templates. Status is e-mailed to the configured aliases
#
# Note: Instructions to setup service principle were sourced from http://blog.davidebbo.com/2014/12/azure-service-principal.html
#####
# Load variables file
$variablesFilePath = $PSScriptRoot+"\automated-validation-variables.ps1";
. $variablesFilePath;
# Load template params file
$templateParamsFilePath = $PSScriptRoot+"\automated-validation-template-params.ps1";
. $templateParamsFilePath;
# This needs to be done before the module is loaded as the module depends on the password being set.
$passwdCheckerModule = $PSScriptRoot+"\modules\ServicePrinciplePasswdLoader.ps1";
. $passwdCheckerModule;
Import-Module $PSScriptRoot"\modules\"ARMTemplateDeployment.psm1;
# Ensure a unique resource group name incase we don't teardown the deployment to avoid conflict with subsequent deployments
$RESOURCE_GROUP_NAME_PREFIX = "automated-canary-test-"+(Get-Date ([TimeZoneInfo]::ConvertTime((Get-Date), [TimeZoneInfo]::UTC)) -UFormat %Y-%m-%d_%H.%M.%SZ-);
$finalOutput = "`n`n====================== BEGINNING MARKETPLACE DEPLOYMENT ======================`n`n"
$PARAMS_FILE_PATH = $PSScriptRoot+"\param-sets\mainTemplate-param-set-canary.ps1";
. $PARAMS_FILE_PATH;
$output = RunAllDeployments -ParamSet $paramSet -SubscriptionID $SUBSCRIPTION_ID -ResourceGroupLocation $LOCATION -TemplateURI $MARKETPLACE_TEMPLATE_URI -ResourceGroupNamePrefix $RESOURCE_GROUP_NAME_PREFIX;
$finalOutput = $finalOutput + $output;
$deploymentFailed = $output | Select-String -Pattern "failed";
if (-not [string]::IsNullOrEmpty($deploymentFailed))
{ $finalOutput = $finalOutput + "One or more deployment failed so leaving failed deployments running. PLEASE TEARDOWN AFTER INVESTIGATING."; }
$finalOutput = $finalOutput + "`n`n====================== BEGINNING QUICKSTART DEPLOYMENT ======================`n`n";
$PARAMS_FILE_PATH = $PSScriptRoot+"\param-sets\azureDeploy-param-set-canary.ps1";
. $PARAMS_FILE_PATH;
$RESOURCE_GROUP_NAME_PREFIX = "automated-canary-test-"+(Get-Date ([TimeZoneInfo]::ConvertTime((Get-Date), [TimeZoneInfo]::UTC)) -UFormat %Y-%m-%d_%H.%M.%SZ-);
$output = RunAllDeployments -ParamSet $paramSet -SubscriptionID $SUBSCRIPTION_ID -ResourceGroupLocation $LOCATION -TemplateURI $QUICKSTART_TEMPLATE_URI -ResourceGroupNamePrefix $RESOURCE_GROUP_NAME_PREFIX;
$finalOutput = $finalOutput + $output;
$deploymentFailed = $output | Select-String -Pattern "failed";
if (-not [string]::IsNullOrEmpty($deploymentFailed))
{ $finalOutput = $finalOutput + "One or more deployment failed so leaving failed deployments running. PLEASE TEARDOWN AFTER INVESTIGATING."; }
$testRunFailed = $finalOutput | Select-String -Pattern "failed";
Remove-Module ARMTemplateDeployment;
if(-not [string]::IsNullOrEmpty($NOTIFICATION_ENABLED) -and $NOTIFICATION_ENABLED -eq "TRUE")
{
# Sendgrid Email Service Info
$Password = ConvertTo-SecureString $NOTIFICATION_PASSWORD -AsPlainText -Force;
$credential = New-Object System.Management.Automation.PSCredential $NOTIFICATION_USER_NAME, $Password;
$SMTPServer = "smtp.sendgrid.net";
$EmailFrom = "templatemonitoring@tmonitoring.com";
$EmailTo = @($NOTIFICATION_ALIAS);
$Subject = "";
if (![string]::IsNullOrEmpty($testRunFailed))
{ $Subject = "One or more deployments FAILED"; }
else { $Subject = "All deployments SUCCEEDED"; }
$Body = "$finalOutput";
Send-MailMessage -smtpServer $SMTPServer -Credential $credential -Usessl -Port 587 -from $EmailFrom -to $EmailTo -subject $Subject -Body $Body;
}

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

@ -0,0 +1,20 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"aparam": {
"type": "string"
}
},
"resources": [],
"outputs": {
"output1": {
"type": "string",
"value": "[parameters('aparam')]"
},
"output2": {
"type": "string",
"value": "[parameters('aparam')]"
}
}
}

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

@ -0,0 +1,75 @@
#####
# IMPORTANT: !!!!! Ensure the password is set outside of this script to prevent a secret from being checked into the repo accidentally !!!!!
#
# ===== Instructions =====
# 1. Set SUBSCRIPTION_ID to where you want to deploy into.
# 2. Set $PARAMS_FILE_PATH to the location of the parameters powershell file (e.g. "mainTemplate-param-set-happy-path.ps1").
# Be sure to set all variables needed by the param file before loading it!
# 3. Set $LOCATION to the desired Azure region where the resource group will be created (e.g. "Central US" or "centralus")
# 4. Set the TEMPLATE_URI to the location of the deployment template json file - should be reachable without any authentication.
# The template specified should be of a type that matches the parameters specified in #2 (quickstart, marketplace templates
# have different parameter sets)
# 5. On first run, you will be asked to login. Login with your account that has access to the Key Vault containig the password
# of the service principle that the workflow will be run as.
#
# Note: Instructions to setup service principle were sourced from http://blog.davidebbo.com/2014/12/azure-service-principal.html
#####
#####
# Deployment specific variables
#####
# Subscription under which resources will be deployed
$SUBSCRIPTION_ID = "922bb5fb-9ac3-4aa7-9a6b-f965aa49e6a3";
$LOCATION = "eastus";
$BASE_URL = "https://gallery.azure.com/artifact/20161101/microsoft-azure-blockchain.azure-multi-member-blockchain-service-previewethereum-consortium-leader.1.0.1/Artifacts"; # Specify this for marketplace deployments
$TEMPLATE_URI = $BASE_URL+"/mainTemplate.json"; # either mainTemplate.json for marketplace or azureDeploy.json for quickstart
# Append timestamp so each run creates a unique resource group name
$RESOURCE_GROUP_NAME_PREFIX = "gproano"+"-"+"test"+"-"+(Get-Date ([TimeZoneInfo]::ConvertTime((Get-Date), [TimeZoneInfo]::UTC)) -UFormat %Y-%m-%d_%H.%M.%SZ-);
#####
# Template params global values
#####
$PARAMS_FILE_PATH = $PSScriptRoot+"\param-sets\mainTemplate-param-set-multinetwork.ps1";
# !!! Set all mandatory variables used in the params file here !!!
$baseUrl = $BASE_URL # (location of artifacts that are being validated, set to folder path of template file)
$location = $LOCATION;
$authType = "password";
$vmAdminPasswd = "Test-3212017";
$sshPublicKey = "";
$ethPasswd = "Test-3212017";
$passphrase = "Test-3212017";
# Load the params file which will set the $paramSet variable
# !!! Set all mandatory variables used in the params file here !!!
#####
# Execution logic begins here
#####
# This needs to be done before the module is loaded as the module depends on the password being set.
$passwdCheckerModule = $PSScriptRoot+"\modules\ServicePrinciplePasswdLoader.ps1";
. $passwdCheckerModule;
Import-Module $PSScriptRoot"\modules\"ARMTemplateDeployment.psm1;
if(-not $?) { Exit -1; }
. $PARAMS_FILE_PATH;
$output = RunAllDeployments -ParamSet $paramSet -SubscriptionID $SUBSCRIPTION_ID -ResourceGroupLocation $LOCATION -TemplateURI $TEMPLATE_URI -ResourceGroupNamePrefix $RESOURCE_GROUP_NAME_PREFIX -Teardown $FALSE;
$deploymentFailed = $output | Select-String -Pattern "failed";
if (-not [string]::IsNullOrEmpty($deploymentFailed))
{ echo "Deployment FAILED"; }
else
{ echo "Deployment SUCCEEDED"}
echo "====================== DEPLOYMENT OUTPUT ======================"
echo $output;
echo "==============================================================="
$teardown = Read-Host -Prompt "Teardown deployment? (Y/N)";
if ($teardown -eq "Y")
{
echo "Tearing down first deployment";
$resourceGroupName = $RESOURCE_GROUP_NAME_PREFIX+"0"
TeardownDeployment -SubscriptionID $SUBSCRIPTION_ID -ResourceGroupName $resourceGroupName;
echo "Teardown complete";
}
Remove-Module ARMTemplateDeployment;

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

@ -0,0 +1,242 @@
#####
# IMPORTANT: !!!!! Ensure the password is set outside of this script to prevent a secret from being checked into the repo accidentally !!!!!
#
# ===== Instructions =====
# 1. In the console, set the variable $global:SP_PASSWD to the value of the blockchain dev service principle password. This is saved in the
# "BlockchainTeamSecrets" KeyVault under Blockchain Non-Prod subscription secret named "blockchain-service-principle-devs"
# 2. This function runAllDeployments() in this module can be run in two modes: "D" provisions resources via the deployment template
# and "T" tears down resources that were provisioned. Manually validate the deployments and then tear them down.
#
# Note: In this module, various commands return value is assigned to $tmp to avoid excess logging to the console
# Instructions to setup service principle were sourced from http://blog.davidebbo.com/2014/12/azure-service-principal.html
#####
# Constants
$SERVICE_PRINCIPAL_NAME = "http://blockchain-app-dev";
$CLIENT_ID = "ff15344d-ba38-4088-b9e3-42558a3a3d23"; # blockchain dev service principle username (password is retrieved from key vault)
$TENANT_ID = "72f988bf-86f1-41af-91ab-2d7cd011db47"; # @microsoft.com tenant
$PRE_VALIDATION_SLEEP_SEC = 90;
$CONNECTION_SLEEP_SEC = 300;
# Create a credentials object that will be used to login as the service principle authorized on the subscription
if([string]::IsNullOrEmpty($global:SP_PASSWD)) {
throw "Service Principle password is not set. Exiting";
}
$secpasswd = ConvertTo-SecureString $global:SP_PASSWD -AsPlainText -Force
$sp_creds = New-Object System.Management.Automation.PSCredential ($CLIENT_ID, $secpasswd)
$deploymentBlock = {
$tenantID = $args[0];
$creds = $args[1];
$subscriptionID = $args[2];
$resourceGroupName = $args[3];
$resourceGroupLocation = $args[4];
$templateURI = $args[5];
$templateParams = $args[6];
$deploymentName = $resourceGroupName;
$preValidationSleepSec = $args[7];
$runValidation = $args[8];
Try {
# Login in this job session
$output = Login-AzureRmAccount -ServicePrincipal -Tenant $tenantID -Credential $creds -SubscriptionId $subscriptionID 2>&1;
$err = $output | ?{$_.gettype().Name -eq "ErrorRecord"};
if($err)
{ throw "Encountered Error logging in as service principal: $output"; }
# Create resource group
$output = New-AzureRmResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation 2>&1;
$err = $output | ?{$_.gettype().Name -eq "ErrorRecord"};
if($err)
{ throw "Encountered Error creating resource group: $output"; }
# Params as object version
$output = New-AzureRmResourceGroupDeployment -Name $deploymentName -ResourceGroupName $resourceGroupName -TemplateUri $templateURI -TemplateParameterObject $templateParams 2>&1;
$err = $output | ?{$_.gettype().Name -eq "ErrorRecord"};
if($err)
{ throw "Encountered Error deploying to resource group: $output"; }
}
Catch {
echo "Deployment Job for resource group $resourceGroupName failed with the following errors:`n";
echo "$Error`n";
}
}
$teardownBlock = {
$tenantID = $args[0];
$creds = $args[1];
$subscriptionID = $args[2];
$resourceGroupName = $args[3];
Try {
# Login in this job session
$temp = Login-AzureRmAccount -ServicePrincipal -Tenant $tenantID -Credential $creds -SubscriptionId $subscriptionID 2>&1
$status = Remove-AzureRmResourceGroup -ResourceGroupName $resourceGroupName -Force 2>&1;
$err = $status | ?{$_.gettype().Name -eq "ErrorRecord"};
if($status -and !$err)
{ echo "Successfully tore down resource group $resourceGroupName`n"; }
else
{
echo "Failed to tear down resource group $resourceGroupName due to:`n";
echo "$status`n";
}
}
Catch {
echo "Deployment Job for resource group $resourceGroupName failed with the following errors:`n";
echo "$Error`n";
}
}
function RunAllDeployments([HashTable]$ParamSet,
[String]$SubscriptionID,
[String]$ResourceGroupLocation,
[String]$TemplateURI,
[String]$ResourceGroupNamePrefix="ethnet-automated-test",
[String]$JobNamePrefix="TemplateDeployment",
[Bool]$Teardown=$TRUE,
[Bool]$RunValidation=$TRUE
)
{
echo "Deploying into SubscriptionID: $SubscriptionID`n";
$paramKeyToResourceGroupNameMap = @{};
$paramKeyToJobNameMap = @{};
$paramKeyToJobOutputMap = @{};
# $ParamSet variable is defined in the params file that was dot sourced above
$seqNum = 0;
foreach ($key in $ParamSet.Keys)
{
$jobNum = $seqNum++;
$jobName = $JobNamePrefix+$jobNum;
$resourceGroupName = $ResourceGroupNamePrefix+$jobNum;
$paramKeyToResourceGroupNameMap.Add($key, $resourceGroupName);
$paramKeyToJobNameMap.Add($key, $jobName);
$temp = Start-Job $deploymentBlock -Name $jobName -ArgumentList $TENANT_ID, $sp_creds, $SubscriptionID, $resourceGroupName, $ResourceGroupLocation, $TemplateURI, $ParamSet.Item($key), $PRE_VALIDATION_SLEEP_SEC, $RunValidation;
echo "Started deployment into resource group $resourceGroupName`n"
}
# Wait for jobs to finish and save output
foreach ($key in $ParamSet.Keys)
{
$jobName = $paramKeyToJobNameMap.Item($key);
echo "Waiting for job $jobName (params $key)`n"
$jobOutput = Receive-Job -Name $jobName -Wait -Force
$paramKeyToJobOutputMap.Add($key, $jobOutput);
Remove-Job -Name $jobName
}
# Check and report on operation status of each parameter set
$temp = Login-AzureRmAccount -ServicePrincipal -Tenant $TENANT_ID -Credential $sp_creds -SubscriptionId $SubscriptionID
foreach ($key in $ParamSet.Keys)
{
# Deployment name of the main deployment is the same as the resoruce group name if none was specified
$resourceGroupName = $paramKeyToResourceGroupNameMap.Item($key);
Try {
$deployment = Get-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -deploymentName $resourceGroupName;
$err = $deployment | ?{$_.gettype().Name -eq "ErrorRecord"};
if($err)
{ throw "Failed to get resoruce group deployment via Get-AzureRmResourceGroupDeployment for resource group $resourceGroupName`n"; }
}
Catch {
echo $Error;
}
if(($deployment.ProvisioningState -eq "Succeeded") -and (-not ($paramKeyToJobOutputMap.Item($key) -like "*failed*")))
{
echo "`n";
echo "========================================`n"
echo "Deployment SUCCEEDED for parameter set ($key) and resource group ($resourceGroupName)`n";
echo "Deployment outputs:`n";
echo "========================================`n"
foreach ($output in $deployment.Outputs)
{
foreach ($key in $output.Keys)
{
$msg = "$key --> "+$deployment.Outputs[$key].Value;
echo "$msg`n";
}
}
echo "========================================`n"
if($Teardown)
{
$temp = Start-Job $teardownBlock -ArgumentList $TENANT_ID, $sp_creds, $SubscriptionID, $resourceGroupName;
echo "Started teardown of resource group $resourceGroupName`n"
}
else
{
#echo "Teardown of resource group $resourceGroupName skipped as requested`n"
}
}
else
{
echo "`n";
echo "========================================`n"
echo "Deployment FAILED for parameter set ($key) and resource group ($resourceGroupName)`n";
echo "!!!DEPLOYMENT WILL BE LEFT RUNNING FOR INVESTIGATION!!!`n"
echo "Deployment job output:`n";
echo "========================================`n"
$msg = $paramKeyToJobOutputMap.Item($key);
echo "$msg`n"
echo "========================================`n"
}
}
Get-Job | Wait-Job
echo "All operations completed`n";
}
function TeardownDeployment([String]$SubscriptionID,
[String]$ResourceGroupName)
{
try{
$jobID = Start-Job $teardownBlock -ArgumentList $TENANT_ID, $sp_creds, $SubscriptionID, $ResourceGroupName;
echo "Started teardown of resource group $resourceGroupName`n";
Wait-Job $jobID;
echo "Teardown of resource group $resourceGroupName complete`n";
}
catch
{
echo $error[0];
}
}
function Validate(
[String]$ResourceGroupName,
[Int32] $PreValidationSleepSec=0,
[Int32] $PeerCountGreaterThan=0
)
{
$deployment = Get-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName -deploymentName $ResourceGroupName;
# Wait for nodes to peer before validating deployment
Start-Sleep -s $PreValidationSleepSec;
# Verify that admin website is up
$webpage = Invoke-WebRequest $deployment.Outputs['admin-site'].Value
$isRunning = $webpage.Content | Select-String -Pattern "Not Running"
if (![string]::IsNullOrEmpty($isRunning))
{ throw "At least one node is not running" }
# Verify that no nodes have peercount 0
# Peercounts are in the 2nd table, 3rd column
$table = @($webpage.ParsedHtml.getElementsByTagName("table"))[1]
$rows = @($table.rows)
foreach($row in $rows) {
$cells = @($row.Cells)
$peercount = $cells[1].innerText
if ($peercount -eq "0")
{ throw "At least one node has peercount 0" }
if($peercount -ne "Peer Count"){
$peerNum = $peercount -as [Int32]
if ($peercount -le $PeerCountGreaterThan)
{ throw "Not enough peers" }
}
}
# Verify that the JSON RPC endpoint is responsive
$webpage = Invoke-WebRequest $deployment.Outputs['ethereum-rpc-endpoint'].Value
$isRunning = $webpage.Content | Select-String -Pattern "jsonrpc"
if ([string]::IsNullOrEmpty($isRunning))
{ throw "JSON RPC not responding" }
}

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

@ -0,0 +1,26 @@
##
# This module should be dot sourced. It checks if the service principle password was already loaded from
# key vault and loads if if not. Vault access is restricted to authorized users.
# Logging in as a service principle avoids asking the user to login (with 2FA) from within each job session
# where the parent's context is not available
##
if([string]::IsNullOrEmpty($global:SP_PASSWD)) {
echo "Service Principle password is not set. Attempting to set it."
Try {
# Test to see if user is logged in. Select-AzureRmSubscription with error if there is no active login.
if ((Select-AzureRmSubscription -SubscriptionName "Blockchain NonProd").Account.AccountType -ne "User")
{
echo "Found a non-user logged in. Logging in as current user.";
Login-AzureRmAccount;
}
} Catch {
echo "No login found. Logging in as current user.";
# Login as current user
Login-AzureRmAccount;
} Finally {
# Store the service principle password from the vault so we can login as the service principle in job sessions
$global:SP_PASSWD = (Get-AzureKeyVaultSecret -VaultName BlockchainTeamSecrets -Name blockchain-service-principle-dev).SecretValueText;
echo "Service Principle password retrieved and set.";
}
}

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

@ -0,0 +1,14 @@
function GeneratePrefix()
{
$seed = [guid]::NewGuid()
return "e"+$seed.ToString().Substring(0,5)
}
function DownloadFile(
[String] $Uri,
[String] $Destination
)
{
$webclient = New-Object System.Net.WebClient
$webclient.DownloadFile($Uri,$Destination)
}

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

@ -0,0 +1,25 @@
# Uncomment line below only on Automated Monitoring VM. For local machine, ServicePrinciplePasswdLoader.ps1 will dynamically set the password.
# IMPORTANT: !!!!! Set the $global:SP_PASSWD only on the file on the monitoring VM to avoid accidental check-in with source code !!!!!
#$global:SP_PASSWD = "";
# Subscription under which resources will be deployed
$SUBSCRIPTION_ID = "922bb5fb-9ac3-4aa7-9a6b-f965aa49e6a3"; # "Azure Blockchain Service Runners" subscription
# Azure Location where resource group and all resources will be deployed in (format e.g. "Central US" or "centralus")
$LOCATION = "southcentralus";
# Root folder within which all template files that are being validated are contained. Determine latest path via test
# deployment of published marketplace solution.
$BASE_URL="https://gallery.azure.com/artifact/20161101/microsoft-azure-blockchain.azure-multi-member-blockchain-service-previewethereum-consortium-leader.1.0.1/Artifacts"
$LEADER_TEMPLATE_URI = $BASE_URL+"/mainTemplate.json";
$JOINING_TEMPLATE_URI = "https://gallery.azure.com/artifact/20161101/microsoft-azure-blockchain.azure-multi-member-blockchain-service-previewethereum-consortium-member.1.0.5/Artifacts/mainTemplate.json";
$NOTIFICATION_ENABLED = "FALSE"; # Any value other than "TRUE" will disable notification
$NOTIFICATION_USER_NAME = "azure_bc8d0746cc32dcb3aceee23ddb70a0f7@azure.com"; # Username of sendgrid account
$NOTIFICATION_PASSWORD = ""; # Password of sendgrid account
$NOTIFICATION_ALIAS = "azblockchain-icm-trg@microsoft.com";
$authType = "password";
$vmAdminPasswd = "";
$ethPasswd = $vmAdminPasswd;
$passphrase = $vmAdminPasswd;
$sshPublicKey = ""

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

@ -0,0 +1,203 @@
#####
# IMPORTANT: !!!!! Ensure the password is set outside of this script to prevent a secret from being checked into the repo accidentally !!!!!
#####
# This script performs a fully automated deployment and teardown of ARM tepmplates using configured parameters and us used
# for automated canary monitoring and alerting of the Blockchain templates. Status is e-mailed to the configured aliases
#
# Note: Instructions to setup service principle were sourced from http://blog.davidebbo.com/2014/12/azure-service-principal.html
#####
Import-Module $PSScriptRoot"\modules\"Utility.psm1;
$PRE_VALIDATION_SLEEP_SEC = 90;
$POST_CONNECTION_PRE_VALIDATION_SLEEP_SEC = 300;
# Load variables file
$variablesFilePath = $PSScriptRoot+"\multinetwork-validation-variables.ps1";
. $variablesFilePath;
# This needs to be done before the module is loaded as the module depends on the password being set.
$passwdCheckerModule = $PSScriptRoot+"\modules\ServicePrinciplePasswdLoader.ps1";
. $passwdCheckerModule;
Import-Module $PSScriptRoot"\modules\"ARMTemplateDeployment.psm1;
# uncomment for local testing
#Select-AzureRmSubscription -SubscriptionId $SUBSCRIPTION_ID
# Ensure a unique resource group name incase we don't teardown the deployment to avoid conflict with subsequent deployments
$RESOURCE_GROUP_NAME_PREFIX = "fts-automated-multi-leader-test-"+(Get-Date ([TimeZoneInfo]::ConvertTime((Get-Date), [TimeZoneInfo]::UTC)) -UFormat %Y-%m-%d_%H.%M.%SZ-);
$finalOutput = "`n`n====================== BEGINNING LEADER MARKETPLACE DEPLOYMENT ======================`n`n"
try{
$PARAMS_FILE_PATH = $PSScriptRoot+"\param-sets\mainTemplate-param-set-multinetwork.ps1";
. $PARAMS_FILE_PATH;
$output = RunAllDeployments -ParamSet $paramSet -SubscriptionID $SUBSCRIPTION_ID -ResourceGroupLocation $LOCATION -TemplateURI $LEADER_TEMPLATE_URI -ResourceGroupNamePrefix $RESOURCE_GROUP_NAME_PREFIX -Teardown $false
$finalOutput = $finalOutput + $output;
$deploymentFailed = $output | Select-String -Pattern "failed";
if (-not [string]::IsNullOrEmpty($deploymentFailed))
{ $finalOutput = $finalOutput + "One or more deployment failed so leaving failed deployments running. PLEASE TEARDOWN AFTER INVESTIGATING."; }
$leaderDeploymentA=$RESOURCE_GROUP_NAME_PREFIX+"0"
$leaderDeploymentB=$RESOURCE_GROUP_NAME_PREFIX+"1"
Start-Sleep -s $PRE_VALIDATION_SLEEP_SEC
Validate -ResourceGroupName $leaderDeploymentA
Validate -ResourceGroupName $leaderDeploymentB
# read the outputs of deployment A
$previousDeploymentOutputs = (Get-AzureRmResourceGroupDeployment -ResourceGroupName $leaderDeploymentA -deploymentName $leaderDeploymentA).Outputs
$gatewayIdA = $previousDeploymentOutputs["gateway-Id"].Value
$consortiumDataA = $previousDeploymentOutputs["consortium-data"].Value
$sharedKeyA = GeneratePrefix
# read the outputs of deployment B
$previousDeploymentOutputs = (Get-AzureRmResourceGroupDeployment -ResourceGroupName $leaderDeploymentB -deploymentName $leaderDeploymentB).Outputs
$gatewayIdB = $previousDeploymentOutputs["gateway-Id"].Value
$consortiumDataB = $previousDeploymentOutputs["consortium-data"].Value
$sharedKeyB = GeneratePrefix
$finalOutput = $finalOutput+ "`n`n====================== BEGINNING JOINING MEMBER DEPLOYMENTS ======================`n`n"
$PARAMS_FILE_PATH = $PSScriptRoot+"\param-sets\mainTemplate-param-set-multinetwork-join.ps1";
. $PARAMS_FILE_PATH;
$RESOURCE_GROUP_NAME_PREFIX = "fts-automated-multi-join-test-"+(Get-Date ([TimeZoneInfo]::ConvertTime((Get-Date), [TimeZoneInfo]::UTC)) -UFormat %Y-%m-%d_%H.%M.%SZ-);
$output = RunAllDeployments -ParamSet $paramSet -SubscriptionID $SUBSCRIPTION_ID -ResourceGroupLocation $LOCATION -TemplateURI $JOINING_TEMPLATE_URI -ResourceGroupNamePrefix $RESOURCE_GROUP_NAME_PREFIX -Teardown $false -RunValidation $false -JobNamePrefix "JoiningMember"
$finalOutput = $finalOutput + $output;
$deploymentFailed = $output | Select-String -Pattern "failed";
if (-not [string]::IsNullOrEmpty($deploymentFailed))
{ $finalOutput = $finalOutput + "One or more deployment failed so leaving failed deployments running. PLEASE TEARDOWN AFTER INVESTIGATING."; }
# read the outputs the the joining member deploy
$joiningMemberA=$RESOURCE_GROUP_NAME_PREFIX+"0"
$joiningMemberB=$RESOURCE_GROUP_NAME_PREFIX+"1"
# Member Y connects to JoiningMemberA
$previousDeploymentOutputs = (Get-AzureRmResourceGroupDeployment -ResourceGroupName $joiningMemberA -deploymentName $joiningMemberA).Outputs
$otherGatewayIdA = $previousDeploymentOutputs["gateway-Id"].Value
$gatewayIdY=$otherGatewayIdA
$consortiumDataY = $previousDeploymentOutputs["consortium-data"].Value
$sharedKeyY = GeneratePrefix
# MemberZ connects to Leader b
$previousDeploymentOutputs = (Get-AzureRmResourceGroupDeployment -ResourceGroupName $joiningMemberB -deploymentName $joiningMemberB).Outputs
$otherGatewayIdB = $previousDeploymentOutputs["gateway-Id"].Value
# run the connection script
DownloadFile -Uri ($consortiumDataA+"/ConsortiumBridge.psm1") -Destination ".\ConsortiumBridge.psm1"
Import-Module ".\ConsortiumBridge.psm1"
CreateConnection $gatewayIdA $otherGatewayIdA "TestConnectionA" $sharedKeyA
CreateConnection $gatewayIdB $otherGatewayIdB "TestConnectionB" $sharedKeyB
Start-Sleep -s $POST_CONNECTION_PRE_VALIDATION_SLEEP_SEC
Validate -ResourceGroupName $joiningMemberA -PeerCountGreaterThan $localPeers
Validate -ResourceGroupName $joiningMemberB -PeerCountGreaterThan $localPeers
<#################################
At this point two networks are connected
Leader1->A
Leader2->B
Now we connected A->Y so the topology looks like L1->A->Y
Connect Leader2 to Z for a hub and spoke topology; Z<-L2->B
#################################>
$finalOutput = $finalOutput+ "`n`n====================== BEGINNING JOINING MEMBER DEPLOYMENTS STEP TWO ======================`n`n"
$PARAMS_FILE_PATH = $PSScriptRoot+"\param-sets\mainTemplate-param-set-multinetwork-join-step2.ps1";
. $PARAMS_FILE_PATH;
$RESOURCE_GROUP_NAME_PREFIX = "fts-automated-multi-join2-test-"+(Get-Date ([TimeZoneInfo]::ConvertTime((Get-Date), [TimeZoneInfo]::UTC)) -UFormat %Y-%m-%d_%H.%M.%SZ-);
$output = RunAllDeployments -ParamSet $paramSet -SubscriptionID $SUBSCRIPTION_ID -ResourceGroupLocation $LOCATION -TemplateURI $JOINING_TEMPLATE_URI -ResourceGroupNamePrefix $RESOURCE_GROUP_NAME_PREFIX -Teardown $false -RunValidation $false -JobNamePrefix "JoiningMember"
$finalOutput = $finalOutput + $output;
$deploymentFailed = $output | Select-String -Pattern "failed";
if (-not [string]::IsNullOrEmpty($deploymentFailed))
{ $finalOutput = $finalOutput + "One or more deployment failed so leaving failed deployments running. PLEASE TEARDOWN AFTER INVESTIGATING."; }
# read the outputs the the joining member deploy
$joiningMemberY=$RESOURCE_GROUP_NAME_PREFIX+"0"
$joiningMemberZ=$RESOURCE_GROUP_NAME_PREFIX+"1"
$previousDeploymentOutputs = (Get-AzureRmResourceGroupDeployment -ResourceGroupName $joiningMemberY -deploymentName $joiningMemberY).Outputs
$otherGatewayIdY = $previousDeploymentOutputs["gateway-Id"].Value
$previousDeploymentOutputs = (Get-AzureRmResourceGroupDeployment -ResourceGroupName $joiningMemberZ -deploymentName $joiningMemberZ).Outputs
$otherGatewayIdZ = $previousDeploymentOutputs["gateway-Id"].Value
CreateConnection $gatewayIdY $otherGatewayIdY "TestConnectionY" $sharedKeyY
CreateConnection $gatewayIdB $otherGatewayIdZ "TestConnectionZ" $sharedKeyB
Start-Sleep -s $POST_CONNECTION_PRE_VALIDATION_SLEEP_SEC
Validate -ResourceGroupName $joiningMemberY -PeerCountGreaterThan $localPeers
Validate -ResourceGroupName $joiningMemberZ -PeerCountGreaterThan $localPeers
$testRunFailed = $finalOutput | Select-String -Pattern "failed";
}
catch
{
$finalOutput = $finalOutput + "`n`n!!!!!!!!!!!!!!!!!!!!DEPLOYMENT FAILED!!!!!!!!!!!!!!!!!!!!`n`n"
$finalOutput = $finalOutput + $error[0]
$finalOutput = $finalOutput + "`n"
$testRunFailed = $TRUE
}
# if tests passed then tear it all down
if($testRunFailed -eq $TRUE)
{
$finalOutput = $finalOutput+"`n`n====================Preventing Teardown====================`n`n"
}
else
{
if( $leaderDeploymentA -ne $NULL){
$finalOutput = $finalOutput+(TeardownDeployment $SUBSCRIPTION_ID $leaderDeploymentA)
}
if( $leaderDeploymentB -ne $NULL){
$finalOutput = $finalOutput+(TeardownDeployment $SUBSCRIPTION_ID $leaderDeploymentB)
}
if( $joiningMemberA -ne $NULL){
$finalOutput = $finalOutput+(TeardownDeployment $SUBSCRIPTION_ID $joiningMemberA)
}
if( $joiningMemberB -ne $NULL){
$finalOutput = $finalOutput+(TeardownDeployment $SUBSCRIPTION_ID $joiningMemberB)
}
if( $joiningMemberY -ne $NULL){
$finalOutput = $finalOutput+(TeardownDeployment $SUBSCRIPTION_ID $joiningMemberY)
}
if( $joiningMemberZ -ne $NULL){
$finalOutput = $finalOutput+(TeardownDeployment $SUBSCRIPTION_ID $joiningMemberZ)
}
}
Remove-Module ARMTemplateDeployment;
if(-not [string]::IsNullOrEmpty($NOTIFICATION_ENABLED) -and $NOTIFICATION_ENABLED -eq "TRUE")
{
# Sendgrid Email Service Info
$Password = ConvertTo-SecureString $NOTIFICATION_PASSWORD -AsPlainText -Force;
$credential = New-Object System.Management.Automation.PSCredential $NOTIFICATION_USER_NAME, $Password;
$SMTPServer = "smtp.sendgrid.net";
$EmailFrom = "templatemonitoring@tmonitoring.com";
$EmailTo = @($NOTIFICATION_ALIAS);
$Subject = "";
if (![string]::IsNullOrEmpty($testRunFailed))
{ $Subject = "MultiNetwork: One or more deployments FAILED"; }
else { $Subject = "MultiNetwork: All deployments SUCCEEDED"; }
$Body = "$finalOutput";
Send-MailMessage -smtpServer $SMTPServer -Credential $credential -Usessl -Port 587 -from $EmailFrom -to $EmailTo -subject $Subject -Body $Body;
}

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

@ -0,0 +1,76 @@
# Params for mainTemplate.json
echo "Loading VM size parameter set for mainTemplate.json"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
if ([string]::IsNullOrEmpty($location))
{ $location = "centralus"; }
if (!$networkID)
{ $networkID = 10101; }
if ([string]::IsNullOrEmpty($authType))
{ $authType = "password"; }
$paramSet = @{
"Tiny-sshPubKey-Standard_A1_A2" = @{
"namePrefix" = "ethnet"
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A1"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A2"
};
"Tiny-sshPubKey-Standard_A3_A4" = @{
"namePrefix" = "ethnet"
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A3"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A4"
};
"Tiny-sshPubKey-Standard_A5_A6" = @{
"namePrefix" = "ethnet"
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A5"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A6"
};
"Tiny-sshPubKey-Standard_A7" = @{
"namePrefix" = "ethnet"
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A1"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A7"
};
};

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

@ -0,0 +1,34 @@
# Params for mainTemplate.json
echo "Loading param sets for canary validation of Azure Quickstart template"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
if ([string]::IsNullOrEmpty($location))
{ $location = "centralus"; }
if (!$networkID)
{ $networkID = 10101; }
$paramSet = @{
"Tiny-Standard_A1" = @{
"namePrefix" = "ethnet"
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A1"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A1"
}
};

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

@ -0,0 +1,11 @@
# Params for mainTemplate.json
echo "Loading 2 param sets from dummyTemplate-param-set.json"
$paramSet = @{
"Set1" = @{
"aparam" = "param in deploy dud Set1"
};
"Set2" = @{
"aparam" = "param in deploy dud Set2"
};
};

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

@ -0,0 +1,100 @@
# Params for mainTemplate.json
echo "Loading VM size parameter set for mainTemplate.json"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
if ([string]::IsNullOrEmpty($location))
{ $location = "centralus"; }
if (!$networkID)
{ $networkID = 10101; }
if ([string]::IsNullOrEmpty($authType))
{ $authType = "password"; }
$paramSet = @{
"Tiny-Standard_A1_A2" = @{
"namePrefix" = "ethnet"
"authType" = $authType;
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A1"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A2"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_A3_A4" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A3"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A4"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_A5_A6" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A5"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A6"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_A7" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A1"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A7"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
};

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

@ -0,0 +1,63 @@
# Params for mainTemplate.json
echo "Loading VM size parameter set for mainTemplate.json"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
# These sizes are only available in East US, West US, North Central US and South Central US per https://azure.microsoft.com/en-us/regions/services/
if ([string]::IsNullOrEmpty($location))
{ $location = "North Central US"; }
if (!$networkID)
{ $networkID = 10101; }
if ([string]::IsNullOrEmpty($authType))
{ $authType = "password"; }
$paramSet = @{
"Tiny-Standard_A8_A9" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A8"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A9"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_A10_A11" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_A10"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_A11"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
}
};

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

@ -0,0 +1,100 @@
# Params for mainTemplate.json
echo "Loading VM size parameter set for mainTemplate.json"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
if ([string]::IsNullOrEmpty($location))
{ $location = "centralus"; }
if (!$networkID)
{ $networkID = 10101; }
if ([string]::IsNullOrEmpty($authType))
{ $authType = "password"; }
$paramSet = @{
"Tiny-Standard_D1_D2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D1"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D2"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_D3_D4" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D3"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D4"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_D11_D12" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D11"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D12"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_D13_D14" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D13"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D14"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
}
};

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

@ -0,0 +1,119 @@
# Params for mainTemplate.json
echo "Loading VM size parameter set for mainTemplate.json"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
if ([string]::IsNullOrEmpty($location))
{ $location = "centralus"; }
if (!$networkID)
{ $networkID = 10101; }
if ([string]::IsNullOrEmpty($authType))
{ $authType = "password"; }
$paramSet = @{
"Tiny-Standard_D1_v2_D2_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D1_v2"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D2_v2"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_D3_v2_D4_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D3_v2"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D4_v2"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_D5_v2_D11_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D5_v2"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D11_v2"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_D12_v2_D13_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D12_v2"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D13_v2"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_D14_v2_D15_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_D14_v2"
"mnStorageAccountType" = "Standard_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_D15_v2"
"txStorageAccountType" = "Standard_LRS"
"location" = $location
"baseUrl" = $baseUrl
}
};

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

@ -0,0 +1,100 @@
# Params for mainTemplate.json
echo "Loading VM size parameter set for mainTemplate.json"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
if ([string]::IsNullOrEmpty($location))
{ $location = "centralus"; }
if (!$networkID)
{ $networkID = 10101; }
if ([string]::IsNullOrEmpty($authType))
{ $authType = "password"; }
$paramSet = @{
"Tiny-Standard_DS1_DS2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS1"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS2"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_DS3_DS4" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS3"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS4"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_DS11_DS12" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS11"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS12"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_DS13_DS14" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS13"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS14"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
}
};

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

@ -0,0 +1,119 @@
# Params for mainTemplate.json
echo "Loading VM size parameter set for mainTemplate.json"
# Plese define the following variables in your personal automated-validation script
#$location = <SET TO DESIRED AZURE REGION>;
#$baseUrl = <SET TO BASE FOLDER LOCATION OF TEMPLTE FILE>;
#$authType = <SET TO EITHER password or sshPublicKey>;
#$vmAdminPasswd = <SET TO DESIRED PASSWORD>;
#$ethPasswd = <SET TO DESIRED PASSWORD>;
#$passphrase = <SET TO DESIRED PASSPHRASE>;
#$sshPublicKey = <SET TO YOUR SSH PUBLIC KEY>;
# Some overridable defaults
if ([string]::IsNullOrEmpty($location))
{ $location = "centralus"; }
if (!$networkID)
{ $networkID = 10101; }
if ([string]::IsNullOrEmpty($authType))
{ $authType = "password"; }
$paramSet = @{
"Tiny-Standard_DS1_v2_DS2_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS1_v2"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS2_v2"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_DS3_v2_DS4_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS3_v2"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS4_v2"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_DS5_v2_DS11_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS5_v2"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS11_v2"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_DS12_v2_DS13_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS12_v2"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS13_v2"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
};
"Tiny-Standard_DS14_v2_DS15_v2" = @{
"namePrefix" = "ethnet"
"authType" = $authType
"adminUsername" = "gethadmin"
"adminPassword" = $vmAdminPasswd
"adminSSHKey" = $sshPublicKey
"ethereumAccountPsswd" = $ethPasswd
"ethereumAccountPassphrase" = $passphrase
"ethereumNetworkID" = $networkID
"numConsortiumMembers" = 2
"numMiningNodesPerMember" = 1
"mnNodeVMSize" = "Standard_DS14_v2"
"mnStorageAccountType" = "Premium_LRS"
"numTXNodes" = 1
"txNodeVMSize" = "Standard_DS15_v2"
"txStorageAccountType" = "Premium_LRS"
"location" = $location
"baseUrl" = $baseUrl
}
};

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше