diff --git a/azure-templates/test_template.json b/azure-templates/test_template.json new file mode 100644 index 0000000..838d176 --- /dev/null +++ b/azure-templates/test_template.json @@ -0,0 +1,256 @@ +{ + "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", + "contentVersion": "1.0.0.0", + "parameters": { + "adminUserName": { + "type": "string", + "defaultValue": "azureSample", + "metadata": { + "description": "User name for the Virtual Machine." + } + }, + "sshKeyData": { + "type": "string", + "metadata": { + "description": "SSH rsa public key file as a string." + } + }, + "dnsLabelPrefix": { + "type": "string", + "metadata": { + "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "Standard_D1", + "metadata": { + "description": "Size of the VM" + } + }, + "vmName": { + "type": "string", + "metadata": { + "description": "Name of the VM" + } + }, + "imagePublisher": { + "type": "string", + "defaultValue": "canonical", + "metadata": { + "description": "Name of the image publisher" + } + }, + "imageOffer": { + "type": "string", + "defaultValue": "ubuntuserver", + "metadata": { + "description": "Name of the image offer" + } + }, + "imageSku": { + "type": "string", + "defaultValue": "16.04.0-DAILY-LTS", + "metadata": { + "description": "Name of the image sku" + } + }, + "imageVersion": { + "type": "string", + "defaultValue": "latest", + "metadata": { + "description": "Name of the image sku" + } + }, + "subnetName": { + "type": "string", + "defaultValue": "azsample-subnet", + "metadata": { + "description": "Name of the subnet" + } + }, + "virtualNetworkName": { + "type": "string", + "defaultValue": "azsampleVNET", + "metadata": { + "description": "Name of the virtual network" + } + } + }, + "variables": { + "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azsample')]", + "location": "[resourceGroup().location]", + "osDiskName": "osDisk1", + "addressPrefix": "10.0.0.0/16", + "subnetPrefix": "10.0.0.0/24", + "vmStorageAccountContainerName": "azsample-vhds", + "nicName": "[concat(parameters('vmName'), '-azsampleNIC')]", + "publicIPAddressName": "[concat(parameters('vmName'), '-azsamplePublicIP')]", + "publicIPAddressType": "Dynamic", + "storageAccountType": "Standard_LRS", + "networkSecurityGroupName": "[concat(parameters('vmName'), '-azsampleNSG')]", + "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", + "vnetID": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]", + "subnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('subnetName'))]", + "apiVersion": "2015-06-15" + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "name": "[variables('storageAccountName')]", + "apiVersion": "[variables('apiVersion')]", + "location": "[variables('location')]", + "properties": { + "accountType": "[variables('storageAccountType')]" + } + }, + { + "apiVersion": "[variables('apiVersion')]", + "type": "Microsoft.Network/networkSecurityGroups", + "name": "[variables('networkSecurityGroupName')]", + "location": "[variables('location')]", + "properties": { + "securityRules": [ + { + "name": "ssh_rule", + "properties": { + "description": "Locks inbound down to ssh default port 22.", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "22", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 123, + "direction": "Inbound" + } + } + ] + } + }, + { + "apiVersion": "[variables('apiVersion')]", + "type": "Microsoft.Network/publicIPAddresses", + "name": "[variables('publicIPAddressName')]", + "location": "[variables('location')]", + "properties": { + "publicIPAllocationMethod": "[variables('publicIPAddressType')]", + "dnsSettings": { + "domainNameLabel": "[parameters('dnsLabelPrefix')]" + } + } + }, + { + "apiVersion": "[variables('apiVersion')]", + "type": "Microsoft.Network/virtualNetworks", + "name": "[parameters('virtualNetworkName')]", + "location": "[variables('location')]", + "dependsOn": [ + "[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]" + ], + "properties": { + "addressSpace": { + "addressPrefixes": [ + "[variables('addressPrefix')]" + ] + }, + "subnets": [ + { + "name": "[parameters('subnetName')]", + "properties": { + "addressPrefix": "[variables('subnetPrefix')]", + "networkSecurityGroup": { + "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" + } + } + } + ] + } + }, + { + "apiVersion": "[variables('apiVersion')]", + "type": "Microsoft.Network/networkInterfaces", + "name": "[variables('nicName')]", + "location": "[variables('location')]", + "dependsOn": [ + "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", + "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]" + ], + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "publicIPAddress": { + "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]" + }, + "subnet": { + "id": "[variables('subnetRef')]" + } + } + } + ] + } + }, + { + "apiVersion": "[variables('apiVersion')]", + "type": "Microsoft.Compute/virtualMachines", + "name": "[parameters('vmName')]", + "location": "[variables('location')]", + "dependsOn": [ + "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", + "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" + ], + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "osProfile": { + "computerName": "[parameters('vmName')]", + "adminUsername": "[parameters('adminUsername')]", + "linuxConfiguration": { + "disablePasswordAuthentication": "true", + "ssh": { + "publicKeys": [ + { + "path": "[variables('sshKeyPath')]", + "keyData": "[parameters('sshKeyData')]" + } + ] + } + } + }, + "storageProfile": { + "imageReference": { + "publisher": "[parameters('imagePublisher')]", + "offer": "[parameters('imageOffer')]", + "sku": "[parameters('imageSku')]", + "version": "latest" + }, + "osDisk": { + "name": "osdisk", + "vhd": { + "uri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', variables('osDiskName'),'.vhd')]" + }, + "caching": "ReadWrite", + "createOption": "FromImage" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "true", + "storageUri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]" + } + } + } + } + ] +} \ No newline at end of file diff --git a/scripts/py/.gitignore b/scripts/py/.gitignore new file mode 100644 index 0000000..df80679 --- /dev/null +++ b/scripts/py/.gitignore @@ -0,0 +1,90 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +.venv/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject \ No newline at end of file diff --git a/scripts/py/deployer.py b/scripts/py/deployer.py index a971ae5..f33adbd 100644 --- a/scripts/py/deployer.py +++ b/scripts/py/deployer.py @@ -1,34 +1,53 @@ """A deployer class to deploy a template on Azure""" import os.path import json -from azure.common.credentials import UserPassCredentials +from haikunator import Haikunator from azure.mgmt.resource import ResourceManagementClient from azure.mgmt.resource.resources.models import DeploymentMode +from azure.common.credentials import UserPassCredentials + class Deployer(object): + """ Initialize the deployer class with subscription, resource group and public key. + + :raises IOError: If the public key path cannot be read (access or not exists) + :raises KeyError: If AZURE_CLIENT_ID, AZURE_CLIENT_SECRET or AZURE_TENANT_ID env + variables or not defined + """ + name_generator = Haikunator() - def __init__(self, resource_group): + def __init__(self, user_email, user_password, subscription_id, resource_group, template_path, pub_ssh_key_path): self.resource_group = resource_group - self.dns_label_prefix = "taivoasd" + self.template_path = template_path + self.dns_label_prefix = self.name_generator.haikunate() - credentials = UserPassCredentials('sinep@sq42nahotmail.onmicrosoft.com', "4D0$1QcK5:Nsn:jd!'1j4Uw'j*") - subscription_id = '0003c64e-455e-4794-8665-a59c04a8961b' - self.client = ResourceManagementClient(credentials, subscription_id) + pub_ssh_key_path = os.path.expanduser(pub_ssh_key_path) + # Will raise if file not exists or not enough permissions + with open(pub_ssh_key_path, 'r') as pub_ssh_file_fd: + self.pub_ssh_key = pub_ssh_file_fd.read() + + self.credentials = UserPassCredentials(user_email, user_password) + self.client = ResourceManagementClient(self.credentials, subscription_id) def deploy(self): """Deploy the template to a resource group.""" self.client.resource_groups.create_or_update( self.resource_group, { - 'location':'westeurope' + 'location': 'westeurope' } ) - template_path = "azure-templates/template3vms.json" - - with open(template_path, 'r') as template_file_fd: + with open(self.template_path, 'r') as template_file_fd: template = json.load(template_file_fd) + parameters = { + 'sshKeyData': self.pub_ssh_key, + 'vmName': 'azure-deployment-sample-vm', + 'dnsLabelPrefix': self.dns_label_prefix + } + parameters = {k: {'value': v} for k, v in parameters.items()} + deployment_properties = { 'mode': DeploymentMode.incremental, 'template': template, @@ -44,4 +63,4 @@ def deploy(self): def destroy(self): """Destroy the given resource group""" - self.client.resource_groups.delete(self.resource_group) \ No newline at end of file + self.client.resource_groups.delete(self.resource_group) diff --git a/scripts/py/pyazure.py b/scripts/py/pyazure.py index 7eb720e..0de4791 100644 --- a/scripts/py/pyazure.py +++ b/scripts/py/pyazure.py @@ -1,19 +1,34 @@ -from azure.common.credentials import UserPassCredentials -from azure.mgmt.resource import ResourceManagementClient -from azure.mgmt.storage import StorageManagementClient -from azure.storage import CloudStorageAccount -from azure.storage.blob.models import ContentSettings +import os.path from deployer import Deployer -credentials = UserPassCredentials('sinep@sq42nahotmail.onmicrosoft.com', "4D0$1QcK5:Nsn:jd!'1j4Uw'j*") -subscription_id = '0003c64e-455e-4794-8665-a59c04a8961b' +# region ---- Credentials ---- +my_subscription_id = "0003c64e-455e-4794-8665-a59c04a8961b" +my_email = "sinep@sq42nahotmail.onmicrosoft.com" +my_password = "4D0$1QcK5:Nsn:jd!'1j4Uw'j*" +my_pub_ssh_key_path = os.path.expanduser('~/.ssh/id_rsa.pub') # the path to your rsa public key file +# endregion -resource_client = ResourceManagementClient(credentials, subscription_id) -storage_client = StorageManagementClient(credentials, subscription_id) +# region ---- Parameters ---- +my_resource_group = 'azure-python-deployment-sample' # the resource group for deployment +template_path = "azure-templates/test_template.json" +# endregion +# region ---- Deployment ---- +msg = "\nInitializing the Deployer class with subscription id: {}, resource group: {}" \ + "\nand public key located at: {}...\n\n" +msg = msg.format(my_subscription_id, my_resource_group, my_pub_ssh_key_path) +print(msg) -resource_group_name = "for_asl_py_test" +# Initialize the deployer class +deployer = Deployer(my_email, my_password, my_subscription_id, my_resource_group, template_path, my_pub_ssh_key_path) -deployer = Deployer(resource_group_name) -deployer.deploy() -deployer.destroy() \ No newline at end of file +print("Beginning the deployment... \n\n") +# Deploy the template +my_deployment = deployer.deploy() + +print("Done deploying!!\n\nYou can connect via: `ssh azureSample@{}.westus.cloudapp.azure.com`".format( + deployer.dns_label_prefix)) +# endregion + +# Destroy the resource group which contains the deployment +deployer.destroy()