diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 2207bdbfb4..90dca3bd61 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -209,7 +209,8 @@ const externalExtensions = [ 'liveshare', 'sql-database-projects', 'machine-learning', - 'sql-assessment' + 'sql-assessment', + 'asde-deployment' ]; // extensions that require a rebuild since they have native parts const rebuildExtensions = [ diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index f414359288..755f7af2c6 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -244,7 +244,8 @@ const externalExtensions = [ 'liveshare', 'sql-database-projects', 'machine-learning', - 'sql-assessment' + 'sql-assessment', + 'asde-deployment' ]; // extensions that require a rebuild since they have native parts diff --git a/extensions/asde-deployment/images/extension.png b/extensions/asde-deployment/images/extension.png new file mode 100644 index 0000000000..c86d6d1e00 Binary files /dev/null and b/extensions/asde-deployment/images/extension.png differ diff --git a/extensions/asde-deployment/images/sqldb_edge.svg b/extensions/asde-deployment/images/sqldb_edge.svg new file mode 100644 index 0000000000..234992e168 --- /dev/null +++ b/extensions/asde-deployment/images/sqldb_edge.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/asde-deployment/images/sqldb_edge_inverse.svg b/extensions/asde-deployment/images/sqldb_edge_inverse.svg new file mode 100644 index 0000000000..234992e168 --- /dev/null +++ b/extensions/asde-deployment/images/sqldb_edge_inverse.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/asde-deployment/notebooks/edge/deploy-sql-edge-local.ipynb b/extensions/asde-deployment/notebooks/edge/deploy-sql-edge-local.ipynb new file mode 100644 index 0000000000..c9db3fb69a --- /dev/null +++ b/extensions/asde-deployment/notebooks/edge/deploy-sql-edge-local.ipynb @@ -0,0 +1,261 @@ +{ + "metadata": { + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python", + "version": "3.6.6", + "mimetype": "text/x-python", + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "pygments_lexer": "ipython3", + "nbconvert_exporter": "python", + "file_extension": ".py" + } + }, + "nbformat_minor": 2, + "nbformat": 4, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "![Microsoft](https://raw.githubusercontent.com/microsoft/azuredatastudio/master/extensions/resource-deployment/images/microsoft-small-logo.png)\n", + "## Run Azure SQL Edge image locally with Docker\n", + "This notebook will use Docker to pull and run the Azure SQL Edge image and connect to it in Azure Data Studio\n", + "\n", + "### Dependencies\n", + "- Docker Engine. For more information, see [Install Docker](https://docs.docker.com/engine/installation/).\n", + "\n", + "Please press the \"Run all\" button to run the notebook" + ], + "metadata": { + "azdata_cell_guid": "565693e5-39d7-46cf-b0a1-3aa9945c3eed" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Check dependencies" + ], + "metadata": { + "azdata_cell_guid": "b9e09157-54b4-4358-90a2-1a54419bd2cc" + } + }, + { + "cell_type": "code", + "source": [ + "import pandas,sys,getpass,os,json,html,time\n", + "pandas_version = pandas.__version__.split('.')\n", + "pandas_major = int(pandas_version[0])\n", + "pandas_minor = int(pandas_version[1])\n", + "pandas_patch = int(pandas_version[2])\n", + "if not (pandas_major > 0 or (pandas_major == 0 and pandas_minor > 24) or (pandas_major == 0 and pandas_minor == 24 and pandas_patch >= 2)):\n", + " sys.exit('Please upgrade the Notebook dependency before you can proceed, you can do it by running the \"Reinstall Notebook dependencies\" command in command palette (View menu -> Command Palette…).')\n", + "\n", + "def run_command():\n", + " print(\"Executing: \" + cmd)\n", + " !{cmd}\n", + " if _exit_code != 0:\n", + " sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n\\t{cmd}\\n')\n", + " print(f'Successfully executed: {cmd}')\n", + "\n", + "cmd = 'docker version'\n", + "run_command()" + ], + "metadata": { + "azdata_cell_guid": "a0a8cd9b-ab0f-4ba2-b568-0c68d950c8bf" + }, + "outputs": [], + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "### List existing containers\n", + "You can view the ports that have been used by existing containers" + ], + "metadata": { + "azdata_cell_guid": "b5a3c41c-a2c3-44a7-94cc-9f1f61d0151d" + } + }, + { + "cell_type": "code", + "source": [ + "cmd = f'docker ps -a'\n", + "run_command()" + ], + "metadata": { + "azdata_cell_guid": "5a253372-1a98-4b07-a3e0-9ae5f47cb0a5" + }, + "outputs": [], + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "### Setting variables" + ], + "metadata": { + "azdata_cell_guid": "7c476b13-05f7-4975-bcb0-8c596bc01e6c" + } + }, + { + "cell_type": "code", + "source": [ + "env_var_flag = \"AZDATA_NB_VAR_SA_PASSWORD\" in os.environ\n", + "password_name = 'SQL Server sa account password'\n", + "if env_var_flag:\n", + " container_name = os.environ[\"AZDATA_NB_VAR_DOCKER_CONTAINER_NAME\"]\n", + " sql_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n", + " sql_port = os.environ[\"AZDATA_NB_VAR_DOCKER_PORT\"]\n", + " docker_registry = os.environ[\"AZDATA_NB_VAR_DOCKER_REGISTRY\"]\n", + " docker_repository = os.environ[\"AZDATA_NB_VAR_DOCKER_REPOSITORY\"]\n", + " docker_imagetag = os.environ[\"AZDATA_NB_VAR_DOCKER_IMAGETAG\"]\n", + " docker_username = os.environ[\"AZDATA_NB_VAR_DOCKER_USERNAME\"]\n", + " docker_password = os.environ[\"AZDATA_NB_VAR_DOCKER_PASSWORD\"]\n", + "else:\n", + " container_name = 'SQLEDGE-' + time.strftime(\"%Y%m%d%H%M%S\", time.localtime())\n", + " docker_registry = 'mcr.microsoft.com'\n", + " docker_repository = 'azure-sql-edge-developer'\n", + " docker_imagetag = 'latest'\n", + " docker_username = ''\n", + " docker_password = ''\n", + " sql_password = getpass.getpass(prompt = password_name)\n", + " password_confirm = getpass.getpass(prompt = f'Confirm {password_name}')\n", + " if sql_password != password_confirm:\n", + " sys.exit(f'{password_name} does not match the confirmation password.')\n", + " sql_port = input('SQL Server port, default value is 1433')\n", + " if len(sql_port) == 0:\n", + " sql_port = '1433'\n", + "print(f'{password_name}: ******')\n", + "print(f'Container name: {container_name}')\n", + "print(f'Port: {sql_port}')\n", + "print(f'Docker registry: {docker_registry}')\n", + "print(f'Docker repository: {docker_repository}')\n", + "print(f'Image tag: {docker_imagetag}')" + ], + "metadata": { + "azdata_cell_guid": "c0af4e4e-4232-4a67-9a21-05a4d54fd0f4" + }, + "outputs": [], + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "### Pull the container image" + ], + "metadata": { + "azdata_cell_guid": "92acb1bf-590d-426e-a9ee-2643c56dcdbe" + } + }, + { + "cell_type": "code", + "source": [ + "if docker_username != '':\n", + " cmd = f'docker login {docker_registry} -u {docker_username} -p {docker_password}'\n", + " run_command()\n", + "cmd = f'docker pull {docker_registry}/{docker_repository}:{docker_imagetag}'\n", + "run_command()" + ], + "metadata": { + "azdata_cell_guid": "58b2156b-da0c-47d5-9706-4bd9f630d28b" + }, + "outputs": [], + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "### Start a new container" + ], + "metadata": { + "azdata_cell_guid": "442e71cd-551b-4b37-8b5a-b814efd27908" + } + }, + { + "cell_type": "code", + "source": [ + "cmd = f'docker run -e ACCEPT_EULA=Y -e \"SA_PASSWORD={sql_password}\" -p {sql_port}:1433 --name {container_name} -d {docker_registry}/{docker_repository}:{docker_imagetag}'\n", + "run_command()" + ], + "metadata": { + "azdata_cell_guid": "4cdcf011-06fd-4df4-bd20-3024d0a5ab9d" + }, + "outputs": [], + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "### List all the containers" + ], + "metadata": { + "azdata_cell_guid": "072a9d13-4fb1-4114-9637-5255be9fcc81" + } + }, + { + "cell_type": "code", + "source": [ + "cmd = f'docker ps -a'\n", + "run_command()" + ], + "metadata": { + "azdata_cell_guid": "345dc24f-0028-47b4-b35b-aaac047b7a62" + }, + "outputs": [], + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "### Connect to SQL Server in Azure Data Studio\n", + "It might take a couple minutes for SQL Server to launch" + ], + "metadata": { + "azdata_cell_guid": "c84bc075-f8b2-48a3-bfc7-f07a5b8be7a0" + } + }, + { + "cell_type": "code", + "source": [ + "from IPython.display import *\n", + "connectionParameter = '{\"serverName\":\"localhost,' + sql_port + '\",\"providerName\":\"MSSQL\",\"authenticationType\":\"SqlLogin\",\"userName\":\"sa\",\"password\":' + json.dumps(sql_password) + '}'\n", + "display(HTML('
Click here to connect to SQL Server
'))" + ], + "metadata": { + "azdata_cell_guid": "187a0067-a04c-4afb-a684-3103bb4522ae" + }, + "outputs": [], + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "### Stop and remove the container" + ], + "metadata": { + "azdata_cell_guid": "94322968-02f5-49e5-8ff1-47a9af3c5e83" + } + }, + { + "cell_type": "code", + "source": [ + "stop_container_command = f'docker stop {container_name}'\n", + "remove_container_command = f'docker rm {container_name}'\n", + "display(HTML(\"Use this link to: open the terminal window in Azure Data Studio and use the links below to paste the command to the terminal.\"))\n", + "display(HTML(\"Stop the container: \" + stop_container_command + \"\"))\n", + "display(HTML(\"Remove the container: \" + remove_container_command + \"\"))" + ], + "metadata": { + "azdata_cell_guid": "9b6c34c2-7a47-43f5-971d-ce9768fec587" + }, + "outputs": [], + "execution_count": 8 + } + ] +} \ No newline at end of file diff --git a/extensions/asde-deployment/notebooks/edge/deploy-sql-edge-remote.ipynb b/extensions/asde-deployment/notebooks/edge/deploy-sql-edge-remote.ipynb new file mode 100644 index 0000000000..58ec30f1e0 --- /dev/null +++ b/extensions/asde-deployment/notebooks/edge/deploy-sql-edge-remote.ipynb @@ -0,0 +1,366 @@ +{ + "metadata": { + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python", + "version": "3.6.6", + "mimetype": "text/x-python", + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "pygments_lexer": "ipython3", + "nbconvert_exporter": "python", + "file_extension": ".py" + } + }, + "nbformat_minor": 2, + "nbformat": 4, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "![Microsoft](https://raw.githubusercontent.com/microsoft/azuredatastudio/master/extensions/resource-deployment/images/microsoft-small-logo.png)\n", + "## Run Azure SQL DB Edge image on a remote machine with Docker\n", + "This notebook will use SSH to connect to the remote machine, use Docker to pull and run the Azure SQL Edge image and connect to it in Azure Data Studio\n", + "\n", + "\n", + "Please press the \"Run all\" button to run the notebook" + ], + "metadata": { + "azdata_cell_guid": "565693e5-39d7-46cf-b0a1-3aa9945c3eed" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Install dependencies" + ], + "metadata": { + "azdata_cell_guid": "b9e09157-54b4-4358-90a2-1a54419bd2cc" + } + }, + { + "cell_type": "code", + "source": [ + "import pandas,sys,getpass,os,json,html,time\n", + "pandas_version = pandas.__version__.split('.')\n", + "pandas_major = int(pandas_version[0])\n", + "pandas_minor = int(pandas_version[1])\n", + "pandas_patch = int(pandas_version[2])\n", + "if not (pandas_major > 0 or (pandas_major == 0 and pandas_minor > 24) or (pandas_major == 0 and pandas_minor == 24 and pandas_patch >= 2)):\n", + " sys.exit('Please upgrade the Notebook dependency before you can proceed, you can do it by running the \"Reinstall Notebook dependencies\" command in command palette (View menu -> Command Palette…).')\n", + "\n", + "def run_command():\n", + " print(\"Executing: \" + cmd)\n", + " !{cmd}\n", + " if _exit_code != 0:\n", + " sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n\\t{cmd}\\n')\n", + " print(f'Successfully executed: {cmd}')\n", + "\n", + "cmd = 'pip install paramiko'\n", + "run_command()" + ], + "metadata": { + "azdata_cell_guid": "a0a8cd9b-ab0f-4ba2-b568-0c68d950c8bf", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### Setting variables" + ], + "metadata": { + "azdata_cell_guid": "7c476b13-05f7-4975-bcb0-8c596bc01e6c" + } + }, + { + "cell_type": "code", + "source": [ + "env_var_flag = \"AZDATA_NB_VAR_SA_PASSWORD\" in os.environ\n", + "password_name = 'SQL Server sa account password'\n", + "if env_var_flag:\n", + " container_name = os.environ[\"AZDATA_NB_VAR_DOCKER_CONTAINER_NAME\"]\n", + " sql_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n", + " sql_port = os.environ[\"AZDATA_NB_VAR_DOCKER_PORT\"]\n", + " docker_registry = os.environ[\"AZDATA_NB_VAR_DOCKER_REGISTRY\"]\n", + " docker_repository = os.environ[\"AZDATA_NB_VAR_DOCKER_REPOSITORY\"]\n", + " docker_imagetag = os.environ[\"AZDATA_NB_VAR_DOCKER_IMAGETAG\"]\n", + " docker_username = os.environ[\"AZDATA_NB_VAR_DOCKER_USERNAME\"]\n", + " docker_password = os.environ[\"AZDATA_NB_VAR_DOCKER_PASSWORD\"]\n", + " ssh_target = os.environ[\"AZDATA_NB_VAR_SSH_TARGET\"]\n", + " ssh_username = os.environ[\"AZDATA_NB_VAR_SSH_USERNAME\"]\n", + " ssh_password = os.environ[\"AZDATA_NB_VAR_SSH_PASSWORD\"]\n", + "else:\n", + " container_name = 'SQLEDGE-' + time.strftime(\"%Y%m%d%H%M%S\", time.localtime())\n", + " docker_registry = 'mcr.microsoft.com'\n", + " docker_repository = 'azure-sql-edge-developer'\n", + " docker_imagetag = 'latest'\n", + " docker_username = ''\n", + " docker_password = ''\n", + " sql_password = getpass.getpass(prompt = password_name)\n", + " password_confirm = getpass.getpass(prompt = f'Confirm {password_name}')\n", + " if sql_password != password_confirm:\n", + " sys.exit(f'{password_name} does not match the confirmation password.')\n", + " sql_port = input('SQL Server port, default value is 1433')\n", + " if len(sql_port) == 0:\n", + " sql_port = '1433'\n", + " ssh_target = input('Remote machine name or address')\n", + " ssh_username = input('Username for remote machine')\n", + " ssh_password = input('Password for remote machine')\n", + "\n", + "print(f'{password_name}: ******')\n", + "print(f'Remote machine: {ssh_target}')\n", + "print(f'Remote machine username: {ssh_username}')\n", + "print(f'Container name: {container_name}')\n", + "print(f'Port: {sql_port}')\n", + "print(f'Docker registry: {docker_registry}')\n", + "print(f'Docker repository: {docker_repository}')\n", + "print(f'Image tag: {docker_imagetag}')" + ], + "metadata": { + "azdata_cell_guid": "c0af4e4e-4232-4a67-9a21-05a4d54fd0f4", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### Log in to remote machine" + ], + "metadata": { + "azdata_cell_guid": "28593625-0d7a-4dd0-b3bc-fdc3a5500d55" + } + }, + { + "cell_type": "code", + "source": [ + "import paramiko\n", + "client = paramiko.SSHClient()\n", + "client.set_missing_host_key_policy(paramiko.AutoAddPolicy())\n", + "client.connect(ssh_target,username=ssh_username, password=ssh_password)\n", + "\n", + "def run_command_remote():\n", + " stdin, stdout, stderr = client.exec_command(f'bash --login -c \"{cmd}\"')\n", + " for line in stdout:\n", + " print(line.strip('\\n'))\n", + " stderr = stderr.readlines()\n", + " if len(stderr) != 0:\n", + " for line in stderr:\n", + " print(line.strip('\\n'))\n", + " sys.exit(f'Command execution failed')\n", + " else:\n", + " print(f'Command executed successfully')" + ], + "metadata": { + "azdata_cell_guid": "aadaa458-8c23-4b7a-a87e-cb2ee82046cf", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### Check dependencies on remote machine" + ], + "metadata": { + "azdata_cell_guid": "20d6ec5d-b706-4086-b583-6175c44740f2" + } + }, + { + "cell_type": "code", + "source": [ + "cmd = 'docker version'\n", + "run_command_remote()\n", + "" + ], + "metadata": { + "azdata_cell_guid": "f3f3946b-d950-477d-83d6-8bae320f619f", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### List all the containers" + ], + "metadata": { + "azdata_cell_guid": "85a12b48-3f7b-4181-bf91-90d3069bd0d8" + } + }, + { + "cell_type": "code", + "source": [ + "cmd = 'docker ps -a'\n", + "run_command_remote()" + ], + "metadata": { + "azdata_cell_guid": "8b2874af-de7e-4a0a-9cad-3be397eaa3e9", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### Pull the container image" + ], + "metadata": { + "azdata_cell_guid": "92acb1bf-590d-426e-a9ee-2643c56dcdbe" + } + }, + { + "cell_type": "code", + "source": [ + "if docker_username != '':\n", + " cmd = f'docker login {docker_registry} -u {docker_username} -p {docker_password}'\n", + " run_command_remote()\n", + "cmd = f'docker pull {docker_registry}/{docker_repository}:{docker_imagetag}'\n", + "run_command_remote()" + ], + "metadata": { + "azdata_cell_guid": "58b2156b-da0c-47d5-9706-4bd9f630d28b", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### Start a new container" + ], + "metadata": { + "azdata_cell_guid": "442e71cd-551b-4b37-8b5a-b814efd27908" + } + }, + { + "cell_type": "code", + "source": [ + "cmd = f'docker run -e ACCEPT_EULA=Y -e \"SA_PASSWORD={sql_password}\" -p {sql_port}:1433 --name {container_name} -d {docker_registry}/{docker_repository}:{docker_imagetag}'\n", + "run_command_remote()" + ], + "metadata": { + "azdata_cell_guid": "4cdcf011-06fd-4df4-bd20-3024d0a5ab9d", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### List all the containers" + ], + "metadata": { + "azdata_cell_guid": "072a9d13-4fb1-4114-9637-5255be9fcc81" + } + }, + { + "cell_type": "code", + "source": [ + "cmd = f'docker ps -a'\n", + "run_command_remote()" + ], + "metadata": { + "azdata_cell_guid": "345dc24f-0028-47b4-b35b-aaac047b7a62", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### Connect to SQL Server in Azure Data Studio\n", + "It might take a couple minutes for SQL Server to launch" + ], + "metadata": { + "azdata_cell_guid": "c84bc075-f8b2-48a3-bfc7-f07a5b8be7a0" + } + }, + { + "cell_type": "code", + "source": [ + "from IPython.display import *\n", + "connectionParameter = '{\"serverName\":\"' + ssh_target + ',' + sql_port + '\",\"providerName\":\"MSSQL\",\"authenticationType\":\"SqlLogin\",\"userName\":\"sa\",\"password\":' + json.dumps(sql_password) + '}'\n", + "display(HTML('
Click here to connect to SQL Server
'))" + ], + "metadata": { + "azdata_cell_guid": "187a0067-a04c-4afb-a684-3103bb4522ae", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "### Stop and remove the container\n", + "Please copy the output of this cell into the next empty code cell and run the cell to stop and remove the container" + ], + "metadata": { + "azdata_cell_guid": "94322968-02f5-49e5-8ff1-47a9af3c5e83" + } + }, + { + "cell_type": "code", + "source": [ + "remove_container_command = f'cmd = f\\'docker rm {container_name}\\'\\nrun_command_remote()'\n", + "stop_container_command = f'cmd = f\\'docker stop {container_name}\\'\\nrun_command_remote()'\n", + "print(stop_container_command)\n", + "print(remove_container_command)" + ], + "metadata": { + "azdata_cell_guid": "9b6c34c2-7a47-43f5-971d-ce9768fec587", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": { + "azdata_cell_guid": "9f2c9d3a-b996-4977-81f5-05a79a2e0e12", + "tags": [] + }, + "outputs": [], + "execution_count": null + } + ] +} \ No newline at end of file diff --git a/extensions/asde-deployment/package.json b/extensions/asde-deployment/package.json new file mode 100644 index 0000000000..3fb7578a79 --- /dev/null +++ b/extensions/asde-deployment/package.json @@ -0,0 +1,276 @@ +{ + "name": "asde-deployment", + "displayName": "%extension-displayName%", + "description": "%extension-description%", + "version": "0.1.0", + "publisher": "Microsoft", + "preview": true, + "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", + "icon": "images/extension.png", + "aiKey": "AIF-444c3af9-8e69-4462-ab49-4191e6ad1916", + "engines": { + "vscode": "*", + "azdata": "*" + }, + "repository": { + "type": "git", + "url": "https://github.com/Microsoft/azuredatastudio.git" + }, + "forceReload": true, + "contributes": { + "resourceDeploymentTypes": [ + { + "name": "sql-edge", + "enabled": false, + "displayName": "%resource-type-sql-edge-display-name%", + "description": "%resource-type-sql-edge-description%", + "platforms": "*", + "icon": { + "light": "./images/sqldb_edge.svg", + "dark": "./images/sqldb_edge_inverse.svg" + }, + "options": [ + { + "name": "type", + "displayName": "%sql-edge-type-display-name%", + "values": [ + { + "name": "local", + "displayName": "%sql-edge-local-display-name%" + }, + { + "name": "remote", + "displayName": "%sql-edge-remote-display-name%" + } + ] + } + ], + "providers": [ + { + "dialog": { + "notebook": "%sql-edge-local-notebook%", + "title": "%sql-edge-local-title%", + "name": "sql-edge-local-dialog", + "tabs": [ + { + "title": "", + "sections": [ + { + "title": "", + "fields": [ + { + "label": "%docker-container-name-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_CONTAINER_NAME", + "type": "datetime_text", + "defaultValue": "SQLEDGE-", + "required": true + }, + { + "label": "%docker-sql-password-field%", + "variableName": "AZDATA_NB_VAR_SA_PASSWORD", + "type": "sql_password", + "userName": "sa", + "confirmationRequired": true, + "confirmationLabel": "%docker-confirm-sql-password-field%", + "defaultValue": "", + "required": true + }, + { + "label": "%docker-sql-port-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_PORT", + "type": "number", + "defaultValue": "1433", + "required": true, + "min": 1, + "max": 65535 + } + ] + }, + { + "title": "%docker-settings-section-title%", + "collapsible": true, + "collapsed": true, + "fields": [ + { + "label": "%docker-registry-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_REGISTRY", + "type": "text", + "defaultValue": "mcr.microsoft.com", + "required": true + }, + { + "label": "%docker-repository-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_REPOSITORY", + "type": "text", + "defaultValue": "azure-sql-edge-developer", + "required": true + }, + { + "label": "%docker-imagetag-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_IMAGETAG", + "type": "text", + "defaultValue": "latest", + "required": true + }, + { + "label": "%docker-username-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_USERNAME", + "type": "text", + "defaultValue": "", + "required": false + }, + { + "label": "%docker-password-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_PASSWORD", + "type": "password", + "defaultValue": "", + "required": false + } + ] + } + ] + } + ] + }, + "requiredTools": [ + { + "name": "docker" + } + ], + "when": "type=local" + }, + { + "dialog": { + "notebook": "%sql-edge-remote-notebook%", + "title": "%sql-edge-remote-title%", + "name": "sql-edge-remote-dialog", + "tabs": [ + { + "title": "", + "sections": [ + { + "title": "", + "fields": [ + { + "label": "%docker-container-name-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_CONTAINER_NAME", + "type": "datetime_text", + "defaultValue": "SQLEDGE-", + "required": true + }, + { + "label": "%docker-sql-password-field%", + "variableName": "AZDATA_NB_VAR_SA_PASSWORD", + "type": "sql_password", + "userName": "sa", + "confirmationRequired": true, + "confirmationLabel": "%docker-confirm-sql-password-field%", + "defaultValue": "", + "required": true + }, + { + "label": "%docker-sql-port-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_PORT", + "type": "number", + "defaultValue": "1433", + "required": true, + "min": 1, + "max": 65535 + } + ] + }, + { + "title": "%remote-info-section-title%", + "collapsible": true, + "collapsed": false, + "fields": [ + { + "label": "%edge-remote-target-field%", + "variableName": "AZDATA_NB_VAR_SSH_TARGET", + "type": "text", + "defaultValue": "", + "required": true + }, + { + "label": "%edge-remote-username-field%", + "variableName": "AZDATA_NB_VAR_SSH_USERNAME", + "type": "text", + "defaultValue": "", + "required": true + }, + { + "label": "%edge-remote-password-field%", + "variableName": "AZDATA_NB_VAR_SSH_PASSWORD", + "type": "password", + "defaultValue": "", + "required": true + } + ] + }, + { + "title": "%docker-settings-section-title%", + "collapsible": true, + "collapsed": true, + "fields": [ + { + "label": "%docker-registry-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_REGISTRY", + "type": "text", + "defaultValue": "mcr.microsoft.com", + "required": true + }, + { + "label": "%docker-repository-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_REPOSITORY", + "type": "text", + "defaultValue": "azure-sql-edge-developer", + "required": true + }, + { + "label": "%docker-imagetag-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_IMAGETAG", + "type": "text", + "defaultValue": "latest", + "required": true + }, + { + "label": "%docker-username-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_USERNAME", + "type": "text", + "defaultValue": "", + "required": false + }, + { + "label": "%docker-password-field%", + "variableName": "AZDATA_NB_VAR_DOCKER_PASSWORD", + "type": "password", + "defaultValue": "", + "required": false + } + ] + } + ] + } + ] + }, + "requiredTools": [], + "when": "type=remote" + } + ], + "agreement": { + "template": "%edge-agreement%", + "links": [ + { + "text": "%microsoft-privacy-statement%", + "url": "https://go.microsoft.com/fwlink/?LinkId=853010" + }, + { + "text": "%edge-eula%", + "url": "https://go.microsoft.com/fwlink/?LinkId=746388" + } + ] + } + } + ] + } +} diff --git a/extensions/asde-deployment/package.nls.json b/extensions/asde-deployment/package.nls.json new file mode 100644 index 0000000000..63f548e556 --- /dev/null +++ b/extensions/asde-deployment/package.nls.json @@ -0,0 +1,30 @@ +{ + "extension-displayName": "Azure SQL DB Edge Deployment Extension", + "extension-description": "Provides a notebook-based experience to deploy Azure SQL DB Edge", + "docker-container-name-field": "Container name", + "docker-sql-password-field": "SQL Server password", + "docker-confirm-sql-password-field": "Confirm password", + "docker-sql-port-field": "Port", + "microsoft-privacy-statement": "Microsoft Privacy Statement", + "resource-type-sql-edge-display-name": "Azure SQL DB Edge", + "resource-type-sql-edge-description": "Deploy Azure SQL DB Edge (Preview)", + "sql-edge-type-display-name": "Type", + "sql-edge-local-display-name": "Local", + "sql-edge-remote-display-name": "Remote", + "sql-edge-local-notebook": "./notebooks/edge/deploy-sql-edge-local.ipynb", + "sql-edge-local-title": "Deploy Azure SQL DB Edge locally", + "docker-settings-section-title": "Docker settings", + "docker-registry-field": "Registry", + "docker-repository-field": "Repository", + "docker-imagetag-field": "Image tag", + "docker-username-field": "Username", + "docker-password-field": "Password", + "edge-agreement": "I accept {0} and {1}.", + "edge-eula": "Microsoft SQL Server License Agreement", + "sql-edge-remote-notebook": "./notebooks/edge/deploy-sql-edge-remote.ipynb", + "sql-edge-remote-title": "Deploy Azure SQL DB Edge on a remote machine", + "remote-info-section-title": "Target machine information", + "edge-remote-target-field": "Name or IP address", + "edge-remote-username-field": "Username", + "edge-remote-password-field": "Password" +} diff --git a/extensions/resource-deployment/package.json b/extensions/resource-deployment/package.json index fd46c1bc52..f1b1e66ec8 100644 --- a/extensions/resource-deployment/package.json +++ b/extensions/resource-deployment/package.json @@ -291,7 +291,7 @@ "template": "%bdc-agreement%", "links": [ { - "text": "%bdc-agreement-privacy-statement%", + "text": "%microsoft-privacy-statement%", "url": "https://go.microsoft.com/fwlink/?LinkId=853010" }, { diff --git a/extensions/resource-deployment/package.nls.json b/extensions/resource-deployment/package.nls.json index db2223270a..44e2438a22 100644 --- a/extensions/resource-deployment/package.nls.json +++ b/extensions/resource-deployment/package.nls.json @@ -45,7 +45,7 @@ "resource-type-sql-windows-setup-display-name": "SQL Server on Windows", "resource-type-sql-windows-setup-description": "Run SQL Server on Windows, select a version to get started.", "bdc-agreement": "I accept {0}, {1} and {2}.", - "bdc-agreement-privacy-statement": "Microsoft Privacy Statement", + "microsoft-privacy-statement": "Microsoft Privacy Statement", "bdc-agreement-azdata-eula": "azdata License Terms", "bdc-agreement-bdc-eula": "SQL Server License Terms", "deployment.configuration.title": "Deployment configuration", diff --git a/extensions/resource-deployment/src/test/resourceTypeService.test.ts b/extensions/resource-deployment/src/test/resourceTypeService.test.ts index b2396599cb..38af15a48b 100644 --- a/extensions/resource-deployment/src/test/resourceTypeService.test.ts +++ b/extensions/resource-deployment/src/test/resourceTypeService.test.ts @@ -19,23 +19,29 @@ suite('Resource Type Service Tests', function (): void { const toolsService = new ToolsService(mockPlatformService.object); const notebookService = new NotebookService(mockPlatformService.object, ''); const resourceTypeService = new ResourceTypeService(mockPlatformService.object, toolsService, notebookService); - // index 0: platform name, index 1: number of expected resource types - const platforms: { platform: string; resourceTypeCount: number }[] = [ - { platform: 'win32', resourceTypeCount: 3 }, - { platform: 'darwin', resourceTypeCount: 2 }, - { platform: 'linux', resourceTypeCount: 2 }]; - const totalResourceTypeCount = 3; + // index 0: platform name, index 1: expected resource types + const platforms: { platform: string; resourceTypes: string[] }[] = [ + { + platform: 'win32', resourceTypes: ['sql-image', 'sql-bdc', 'sql-windows-setup'] + }, + { + platform: 'darwin', resourceTypes: ['sql-image', 'sql-bdc'] + }, + { + platform: 'linux', resourceTypes: ['sql-image', 'sql-bdc'] + } + ]; platforms.forEach(platformInfo => { mockPlatformService.reset(); mockPlatformService.setup(service => service.platform()).returns(() => platformInfo.platform); mockPlatformService.setup(service => service.showErrorMessage(TypeMoq.It.isAnyString())); - const resourceTypes = resourceTypeService.getResourceTypes(true); - assert.equal(resourceTypes.length, platformInfo.resourceTypeCount, `number of resource types for platform:${platformInfo.resourceTypeCount} does not meet expected value:${resourceTypes.length}.`); + const resourceTypes = resourceTypeService.getResourceTypes(true).map(rt => rt.name); + for (let i = 0; i < platformInfo.resourceTypes.length; i++) { + assert(resourceTypes.indexOf(platformInfo.resourceTypes[i]) !== -1, `resource type '${platformInfo.resourceTypes[i]}' should be available for platform: ${platformInfo.platform}.`); + } }); const allResourceTypes = resourceTypeService.getResourceTypes(false); - assert.equal(allResourceTypes.length, totalResourceTypeCount, `number of resource types:${allResourceTypes.length} does not meet expected value:${totalResourceTypeCount}.`); - const validationErrors = resourceTypeService.validateResourceTypes(allResourceTypes); assert(validationErrors.length === 0, `Validation errors detected in the package.json: ${validationErrors.join(EOL)}.`); });