Archived
26 KiB
26 KiB
In [ ]:
import sys,os,json,html,getpass,time,ntpath,uuid
def run_command(command:str, displayCommand:str = "", returnObject:bool = False):
print("Executing: " + (displayCommand if displayCommand != "" else command))
if returnObject:
output = os.popen(command).read()
print(f'Command successfully executed')
return json.loads(''.join(output))
else:
!{command}
if _exit_code != 0:
sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\n')
else:
print(f'Command successfully executed')
run_command(command='az --version')In [ ]:
extensions = run_command('az extension list', returnObject=True)
extensions = [ext for ext in extensions if ext['name'] == 'azure-cli-iot-ext']
if len(extensions) > 0:
run_command('az extension remove --name azure-cli-iot-ext')
run_command('az extension add --name azure-iot')In [ ]:
azure_subscription_id = os.environ["AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID"]
azure_resource_group = os.environ["AZDATA_NB_VAR_ASDE_RESOURCEGROUP"]
azure_location = os.environ["AZDATA_NB_VAR_ASDE_AZURE_LOCATION"]
sa_password = os.environ["AZDATA_NB_VAR_SA_PASSWORD"]
vm_admin = os.environ["AZDATA_NB_VAR_ASDE_VM_ADMIN"]
vm_password = os.environ["AZDATA_NB_VAR_ASDE_VM_PASSWORD"]
package_path = os.environ["AZDATA_NB_VAR_ASDE_PACKAGE_PATH"]
sql_port = os.environ["AZDATA_NB_VAR_ASDE_SQL_PORT"]
new_rg_flag = os.environ["AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP"]
new_rg_name = os.environ["AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP_NAME"]
if new_rg_flag == 'true':
azure_resource_group = new_rg_name
print(f'Subscription: {azure_subscription_id}')
print(f'Resource group: {azure_resource_group}')
print(f'Location: {azure_location}')
print(f'VM admin username: {vm_admin}')
print(f'VM admin password: ******')
print(f'SQL Server port: {sql_port}')
print(f'SQL Server sa password: ******')
print(f'Package path: {package_path}')In [ ]:
suffix = time.strftime("%y%m%d%H%M%S", time.localtime())
iot_hub_name = f'hub{suffix}'
iot_hub_sku = 'S1'
iot_hub_units = 4
iot_device_id = f'vm{suffix}'
azure_storage_account = f'sa{suffix}'
storage_account_container = 'sqldatabasepackage'
sql_lcid = '1033'
sql_collation = 'SQL_Latin1_General_CP1_CI_AS'
vm_size = 'Standard_DS1_v2'In [ ]:
run_command('az login')In [ ]:
if azure_subscription_id != "":
run_command(f'az account set --subscription {azure_subscription_id}')
else:
print('Using the default Azure subscription', {azure_subscription_id})
run_command(f'az account show')In [ ]:
rg_exists = run_command(f'az group exists --name {azure_resource_group}', returnObject=True)
if rg_exists:
print(f'resource group \"{azure_resource_group}\" already exists.')
else:
run_command(f'az group create --location {azure_location} --name {azure_resource_group}')In [ ]:
hub_list = run_command(f'az iot hub list --resource-group {azure_resource_group}', returnObject=True)
hub_list = [hub for hub in hub_list if hub['name'] == iot_hub_name]
if len(hub_list) == 0:
run_command(f'az iot hub create --name {iot_hub_name} --resource-group {azure_resource_group} --location {azure_location} --sku {iot_hub_sku} --unit {iot_hub_units}')
else:
print(f'IoT hub \"{iot_hub_name}\" already exists')In [ ]:
storage_account_created = False
if package_path == "":
print(f'Package file not provided')
blob_sas = ''
else:
package_name = ntpath.basename(package_path)
storage_accounts = run_command(f'az storage account list --resource-group {azure_resource_group} --subscription {azure_subscription_id}', returnObject=True)
storage_accounts = [storage_account for storage_account in storage_accounts if storage_account['name'] == azure_storage_account]
if len(storage_accounts) == 0:
storage_account_created = True
run_command(f'az storage account create -n {azure_storage_account} -g {azure_resource_group} -l {azure_location} --sku Standard_LRS --kind Storage')
else:
print(f'storage account \"{azure_storage_account}\" already exists.')
storage_account_key = run_command(f'az storage account keys list --account-name {azure_storage_account} --resource-group {azure_resource_group}', returnObject=True)[0]['value']
container_exists = run_command(f'az storage container exists --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key --output json', returnObject=True)['exists']
if container_exists:
print(f'storage account container \"{storage_account_container}\" already exists.')
else:
run_command(f'az storage container create --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key')
blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \"{package_name}\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']
if blob_exists:
print(f'blob \"{package_name}\" already exists.')
else:
run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {package_name} --file \"{package_path}\" --account-key {storage_account_key} --auth-mode key')
now = time.localtime()
expiry = f'{(now.tm_year + 1)}-{now.tm_mon}-{now.tm_mday}'
blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \"{package_name}\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)In [ ]:
device_list = run_command(f'az iot hub device-identity list --edge-enabled true --hub-name {iot_hub_name} --resource-group {azure_resource_group}', returnObject=True)
device_list = [device for device in device_list if device['deviceId'] == iot_device_id]
if len(device_list) == 0:
run_command(f'az iot hub device-identity create --device-id {iot_device_id} --hub-name {iot_hub_name} --resource-group {azure_resource_group} --edge-enabled true')
else:
print(f'Edge device \"{iot_device_id}\" already exists.')
connection_string = run_command(f'az iot hub device-identity show-connection-string --device-id {iot_device_id} --hub-name {iot_hub_name} --resource-group {azure_resource_group}', returnObject=True)
connection_string = connection_string['connectionString']In [ ]:
iot_deploy_result = run_command((f"az deployment group create "
f"--resource-group {azure_resource_group} "
f"--template-uri \"https://aka.ms/iotedge-vm-deploy\" "
f"--parameters vmSize={vm_size} "
f"--parameters dnsLabelPrefix={iot_device_id} "
f"--parameters adminUsername={vm_admin} "
f"--parameters deviceConnectionString={connection_string} "
f"--parameters authenticationType=password "
f"--parameters adminPasswordOrKey=\"{vm_password}\""), returnObject=True)
vm_resource = [resource for resource in iot_deploy_result['properties']['dependencies'] if resource['resourceType'] == 'Microsoft.Compute/virtualMachines']
if len(vm_resource) != 1:
sys.exit('Failed to deploy the IoT Edge VM')
vm_name = vm_resource[0]['resourceName']
nsg_name = vm_name.replace('vm-','nsg-')
ip_address = run_command(f'az vm show -d -g {azure_resource_group} -n {vm_name} --query publicIps', returnObject=True)
run_command(f'az network nsg rule create --name \"SQL\" --nsg-name {nsg_name} --priority 100 --resource-group {azure_resource_group} --access Allow --description \"Allow SQL\" --destination-address-prefixes \"*\" --destination-port-ranges {sql_port} --direction Inbound --source-address-prefixes Internet --protocol Tcp')In [ ]:
manifest = '{\"modulesContent\":{\"$edgeAgent\":{\"properties.desired\":{\"modules\":{\"AzureSQLEdge\":{\"settings\":{\"image\":\"mcr.microsoft.com/azure-sql-edge\",\"createOptions\":\"{\\\"HostConfig\\\":{\\\"CapAdd\\\":[\\\"SYS_PTRACE\\\"],\\\"Binds\\\":[\\\"sqlvolume:/sqlvolume\\\"],\\\"PortBindings\\\":{\\\"1433/tcp\\\":[{\\\"HostPort\\\":\\\"<SQL_Port>\\\"}]},\\\"Mounts\\\":[{\\\"Type\\\":\\\"volume\\\",\\\"Source\\\":\\\"sqlvolume\\\",\\\"Target\\\":\\\"/var/opt/mssql\\\"}]},\\\"User\\\":\\\"0:0\\\",\\\"Env\\\":[\\\"MSSQL_AGENT_ENABLED=TRUE\\\",\\\"ClientTransportType=AMQP_TCP_Only\\\",\\\"PlanId=asde-developer-on-iot-edge\\\"]}\"},\"type\":\"docker\",\"version\":\"1.0\",\"env\":{\"ACCEPT_EULA\":{\"value\":\"Y\"},\"SA_PASSWORD\":{\"value\":\"<Default_SQL_SA_Password>\"},\"MSSQL_LCID\":{\"value\":\"<SQL_LCID>\"},\"MSSQL_COLLATION\":{\"value\":\"<SQL_Collation>\"}<PACKAGE_INFO>},\"status\":\"running\",\"restartPolicy\":\"always\"}},\"runtime\":{\"settings\":{\"minDockerVersion\":\"v1.25\"},\"type\":\"docker\"},\"schemaVersion\":\"1.0\",\"systemModules\":{\"edgeAgent\":{\"settings\":{\"image\":\"mcr.microsoft.com/azureiotedge-agent:1.0\",\"createOptions\":\"\"},\"type\":\"docker\"},\"edgeHub\":{\"settings\":{\"image\":\"mcr.microsoft.com/azureiotedge-hub:1.0\",\"createOptions\":\"{\\\"HostConfig\\\":{\\\"PortBindings\\\":{\\\"443/tcp\\\":[{\\\"HostPort\\\":\\\"443\\\"}],\\\"5671/tcp\\\":[{\\\"HostPort\\\":\\\"5671\\\"}],\\\"8883/tcp\\\":[{\\\"HostPort\\\":\\\"8883\\\"}]}}}\"},\"type\":\"docker\",\"status\":\"running\",\"restartPolicy\":\"always\"}}}},\"$edgeHub\":{\"properties.desired\":{\"routes\":{},\"schemaVersion\":\"1.0\",\"storeAndForwardConfiguration\":{\"timeToLiveSecs\":7200}}},\"AzureSQLEdge\":{\"properties.desired\":{\"ASAJobInfo\":\"<Optional_ASA_Job_SAS_URL>\"}}}}'
package_info = '' if blob_sas == ''else ',\"MSSQL_PACKAGE\":{\"value\":\"'+blob_sas+'\"}'
manifest = manifest.replace('<PACKAGE_INFO>', package_info).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)
file_name = f'{uuid.uuid4().hex}.json'
manifest_file = open(file_name, 'w')
manifest_file.write(manifest)
manifest_file.close()
run_command(f'az iot edge set-modules --device-id \"{iot_device_id}\" --hub-name \"{iot_hub_name}\" --content \"{file_name}\" --resource-group {azure_resource_group}')
os.remove(file_name)In [ ]:
from IPython.display import *
connectionParameter = '{"serverName":"' + f'{ip_address},{sql_port}' + '","providerName":"MSSQL","authenticationType":"SqlLogin","userName": "sa","password":' + json.dumps(sa_password) + ',"options": {"trustServerCertificate":true}}'
display(HTML('<br/><a href="command:azdata.connect?' + html.escape(connectionParameter)+'"><font size="3">Click here to connect to the Azure SQL Edge instance</font></a><br/>'))
display(HTML('<br/><span style="color:red"><font size="2">NOTE: The Azure SQL Edge instance password is included in this link, you may want to clear the results of this code cell before saving the notebook.</font></span>'))In [ ]:
if storage_account_created:
delete_storage_account_command = "run_command(f'az storage account delete -n {azure_storage_account} -g {azure_resource_group} --yes')"
display(HTML('<span style="color:red"><font size="2">NOTE: A storage account was created to host the package file, you can delete it after the database is created and populated successfully. To delete the storage account, copy the following code to a new code cell and run the cell.</font></span>'))
display(HTML('<span><font size="2">'+delete_storage_account_command+'</font></span>'))