diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js
index 3a49ec83be..295123418b 100644
--- a/build/gulpfile.hygiene.js
+++ b/build/gulpfile.hygiene.js
@@ -177,7 +177,8 @@ const copyrightFilter = [
'!**/*.gif',
'!**/*.xlf',
'!**/*.dacpac',
- '!**/*.bacpac'
+ '!**/*.bacpac',
+ '!**/*.py'
];
const jsHygieneFilter = [
diff --git a/extensions/arc/README.md b/extensions/arc/README.md
index 3af09dba13..6d7ad772e2 100644
--- a/extensions/arc/README.md
+++ b/extensions/arc/README.md
@@ -2,6 +2,33 @@
Welcome to Microsoft Azure Arc Extension for Azure Data Studio!
+**This extension is only applicable to customers in the Azure Arc data services private preview.**
+
+## Overview
+
+This extension adds the following features to Azure Data Studio.
+
+### Deployment Wizards
+
+A gui-based experience to deploy an Azure Arc data controller as well as resources on an existing Azure Arc data controller. Current list of supported resources:
+* SQL Managed Instance
+* PostgreSQL server groups
+
+### Management Dashboards
+
+After connecting to an existing Azure Arc data controller in the *Azure Arc Controllers* view of the *Connections* viewlet a list of the active resources registered to the controller is shown, which allow launching a dashboard for further management capabilities.
+
+## Usage Guide
+
+### Deployment Wizards
+
+* After installing this extension click on '...' to the right of the Connections section in the left Panel and click on 'New Deployment...'.
+* This opens a dialog box that shows several deployment tiles. This extension adds tiles for the supported resources listed above.
+* Click on that tile, accept any license agreements, and choose the appropriate 'Resource Type' to install
+* A required tools check will run, if any required tools are missing then instructions will be given for installing those tools
+* Once the check has passed successfully then click the *Select* button
+* This opens up a new dialog where you can enter input parameters specific to the deployment selected and then open a notebook that does the actual deployment.
+*
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
diff --git a/extensions/arc/images/microsoft-small-logo.png b/extensions/arc/images/microsoft-small-logo.png
new file mode 100644
index 0000000000..e0259ce252
Binary files /dev/null and b/extensions/arc/images/microsoft-small-logo.png differ
diff --git a/extensions/arc/notebooks/arcDeployment/deploy.arc.control.plane.ipynb b/extensions/arc/notebooks/arcDeployment/deploy.arc.control.plane.ipynb
new file mode 100644
index 0000000000..dcb6ef5051
--- /dev/null
+++ b/extensions/arc/notebooks/arcDeployment/deploy.arc.control.plane.ipynb
@@ -0,0 +1,250 @@
+{
+ "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": [
+ "\n",
+ " \n",
+ "## Deploy Azure Arc Data Controller on an existing cluster\n",
+ " \n",
+ "This notebook walks through the process of deploying a Azure Arc controller on an existing cluster.\n",
+ " \n",
+ "* Follow the instructions in the **Prerequisites** cell to install the tools if not already installed.\n",
+ "* The **Required information** will check and prompt you for password if it is not set in the environment variable. The password can be used to access the data controller.\n",
+ "\n",
+ "Please press the \"Run Cells\" button to run the notebook"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "82e60c1a-7acf-47ee-877f-9e85e92e11da"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Prerequisites** \n",
+ "Ensure the following tools are installed and added to PATH before proceeding.\n",
+ " \n",
+ "|Tools|Description|Installation|\n",
+ "|---|---|---|\n",
+ "|kubectl | Command-line tool for monitoring the underlying Kubernetes cluster | [Installation](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-using-native-package-management) |\n",
+ "|azdata | Command-line tool for installing and managing resources in an Azure Arc cluster |[Installation](https://github.com/microsoft/Azure-data-services-on-Azure-Arc/blob/master/scenarios/001-install-client-tools.md) |"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "714582b9-10ee-409e-ab12-15a4825c9471"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Setup**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "e3dd8e75-e15f-44b4-81fc-1f54d6f0b1e2"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import pandas,sys,os,json,html,getpass,time, tempfile\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",
+ "def run_command(command):\n",
+ " print(\"Executing: \" + command)\n",
+ " !{command}\n",
+ " if _exit_code != 0:\n",
+ " sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n\\t{command}\\n')\n",
+ " print(f'Successfully executed: {command}')"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "d973d5b4-7f0a-4a9d-b204-a16480f3940d",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Set variables**\n",
+ "Generated by Azure Data Studio using the values collected in the Azure Arc Data controller create wizard"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "4b266b2d-bd1b-4565-92c9-3fc146cdce6d"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Check dependencies**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "2544648b-59c9-4ce5-a3b6-87086e214d4c"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "run_command('azdata --version')"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "691671d7-3f05-406c-a183-4cff7d17f83d",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Required information**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "0bb02e76-fee8-4dbc-a75b-d5b9d1b187d0"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "if \"AZDATA_NB_VAR_ARC_DOCKER_PASSWORD\" in os.environ:\n",
+ " arc_docker_password = os.environ[\"AZDATA_NB_VAR_ARC_DOCKER_PASSWORD\"]\n",
+ "if \"AZDATA_NB_VAR_ARC_ADMIN_PASSWORD\" in os.environ:\n",
+ " arc_admin_password = os.environ[\"AZDATA_NB_VAR_ARC_ADMIN_PASSWORD\"]\n",
+ "else:\n",
+ " if arc_admin_password == \"\":\n",
+ " arc_admin_password = getpass.getpass(prompt = 'Azure Arc Data controller password')\n",
+ " if arc_admin_password == \"\":\n",
+ " sys.exit(f'Password is required.')\n",
+ " confirm_password = getpass.getpass(prompt = 'Confirm password')\n",
+ " if arc_admin_password != confirm_password:\n",
+ " sys.exit(f'Passwords do not match.')"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "e7e10828-6cae-45af-8c2f-1484b6d4f9ac",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Set and show current context**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "127c8042-181f-4862-a390-96e59c181d09"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "os.environ[\"KUBECONFIG\"] = arc_config_file\n",
+ "run_command(f'kubectl config use-context {arc_cluster_context}')\n",
+ "run_command('kubectl config current-context')"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "7d1a03d4-1df8-48eb-bff0-0042603b95b1",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Create Azure Arc Data controller**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "efe78cd3-ed73-4c9b-b586-fdd6c07dd37f"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "print (f'Creating Azure Arc controller: {arc_data_controller_name} using configuration {arc_cluster_context}')\n",
+ "os.environ[\"ACCEPT_EULA\"] = 'yes'\n",
+ "os.environ[\"AZDATA_USERNAME\"] = arc_admin_username\n",
+ "os.environ[\"AZDATA_PASSWORD\"] = arc_admin_password\n",
+ "os.environ[\"DOCKER_USERNAME\"] = arc_docker_username\n",
+ "os.environ[\"DOCKER_PASSWORD\"] = arc_docker_password\n",
+ "if os.name == 'nt':\n",
+ " print(f'If you don\\'t see output produced by azdata, you can run the following command in a terminal window to check the deployment status:\\n\\t {os.environ[\"AZDATA_NB_VAR_KUBECTL\"]} get pods -A')\n",
+ "run_command(f'azdata arc dc create --connectivity-mode {arc_data_controller_connectivity_mode} -n {arc_data_controller_name} -ns {arc_data_controller_namespace} -s {arc_subscription} -g {arc_resource_group} -l {arc_data_controller_location} -p {arc_profile}')\n",
+ "print(f'Azure Arc Data controller cluster: {arc_data_controller_name} created.') "
+ ],
+ "metadata": {
+ "azdata_cell_guid": "373947a1-90b9-49ee-86f4-17a4c7d4ca76",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Setting context to created Azure Arc Data controller**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "a3ddc701-811d-4058-b3fb-b7295fcf50ae"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Setting context to data controller.\n",
+ "#\n",
+ "run_command(f'kubectl config set-context --current --namespace {arc_data_controller_namespace}')"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "c974561f-13d0-4e7a-b74b-d781c2e06d68"
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Login to the data controller.**\n"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "9376b2ab-0edf-478f-9e3c-5ff46ae3501a"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Login to the data controller.\n",
+ "#\n",
+ "run_command(f'azdata login -n {arc_data_controller_namespace}')"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "9aed0c5a-2c8a-4ad7-becb-60281923a196"
+ },
+ "outputs": [],
+ "execution_count": null
+ }
+ ]
+}
diff --git a/extensions/arc/notebooks/arcDeployment/deploy.postgres.existing.arc.ipynb b/extensions/arc/notebooks/arcDeployment/deploy.postgres.existing.arc.ipynb
new file mode 100644
index 0000000000..a1968f7ea2
--- /dev/null
+++ b/extensions/arc/notebooks/arcDeployment/deploy.postgres.existing.arc.ipynb
@@ -0,0 +1,155 @@
+{
+ "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": [
+ "\n",
+ " \n",
+ "## Deploy a PostgreSQL server group on an existing Azure Arc data cluster\n",
+ " \n",
+ "This notebook walks through the process of deploying a PostgreSQL server group on an existing Azure Arc data cluster.\n",
+ " \n",
+ "* Follow the instructions in the **Prerequisites** cell to install the tools if not already installed.\n",
+ "* Make sure you have the target Azure Arc data cluster already created.\n",
+ "\n",
+ "Please press the \"Run Cells\" button to run the notebook"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "e4ed0892-7b5a-4d95-bd0d-a6c3eb0b2c99"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Check prerequisites**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "68531b91-ddce-47d7-a1d8-2ddc3d17f3e7"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import sys,os,json,subprocess\n",
+ "def run_command():\n",
+ " print(\"Executing: \" + cmd)\n",
+ " output = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )\n",
+ " if output.returncode != 0:\n",
+ " print(f'Command: {cmd} failed \\n')\n",
+ " print(f'\\t>>>Error output: {output.stderr.decode(\"utf-8\")}\\n')\n",
+ " sys.exit(f'exit code: {output.returncode}\\n')\n",
+ " print(f'Successfully executed: {cmd}')\n",
+ " print(f'\\t>>>Output: {output.stdout.decode(\"utf-8\")}\\n')\n",
+ " return output.stdout.decode(\"utf-8\")\n",
+ "cmd = 'azdata --version'\n",
+ "out = run_command()\n",
+ ""
+ ],
+ "metadata": {
+ "azdata_cell_guid": "749d8dba-3da8-46e9-ae48-2b38056ab7a2",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### **Ensure PostgreSQL server group name, subscription id and resource group name**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "68ec0760-27d1-4ded-9a9f-89077c40b8bb"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Required Values\n",
+ "subscription = os.environ[\"AZDATA_NB_VAR_ARC_SUBSCRIPTION\"]\n",
+ "resource_group_name = os.environ[\"AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME\"]\n",
+ "server_group_name = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAME\"]\n",
+ "server_group_namespace = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAMESPACE\"]\n",
+ "server_group_workers = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_WORKERS\"]\n",
+ "server_group_service_type = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_SERVICE_TYPE\"]\n",
+ "server_group_data_size = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_DATA_SIZE\"]\n",
+ "\n",
+ "# Optional Values\n",
+ "server_group_data_class = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_DATA_CLASS\")\n",
+ "server_group_port = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_PORT\")\n",
+ "server_group_extensions = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_EXTENSIONS\")\n",
+ "server_group_cpu_min = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MIN\")\n",
+ "server_group_cpu_max = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MAX\")\n",
+ "server_group_memory_min = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MIN\")\n",
+ "server_group_memory_max = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MAX\")\n",
+ "server_group_backup_classes = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_CLASSES\")\n",
+ "server_group_backup_sizes = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_SIZES\")\n",
+ "server_group_backup_full_interval = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_FULL_INTERVAL\")\n",
+ "server_group_backup_delta_interval = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_DELTA_INTERVAL\")\n",
+ "server_group_backup_retention_min = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MIN\")\n",
+ "server_group_backup_retention_max = os.environ.get(\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MAX\")"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "53769960-e1f8-4477-b4cf-3ab1ea34348b",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Installing PostgreSQL server group**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "90b0e162-2987-463f-9ce6-12dda1267189"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "print (f'Creating a PostgreSQL server group on Azure Arc')\n",
+ "\n",
+ "data_class_option = f' --dataClass \"{server_group_data_class}\"' if server_group_data_class else \"\"\n",
+ "port_option = f' --port \"{server_group_port}\"' if server_group_port else \"\"\n",
+ "extensions_option = f' --extensions \"{server_group_extensions}\"' if server_group_extensions else \"\"\n",
+ "cpu_min_option = f' --minCpu \"{server_group_cpu_min}\"' if server_group_cpu_min else \"\"\n",
+ "cpu_max_option = f' --maxCpu \"{server_group_cpu_max}\"' if server_group_cpu_max else \"\"\n",
+ "memory_min_option = f' --minMemoryMb \"{server_group_memory_min}\"' if server_group_memory_min else \"\"\n",
+ "memory_max_option = f' --maxMemoryMb \"{server_group_memory_max}\"' if server_group_memory_max else \"\"\n",
+ "backup_classes_option = f' --backupClasses \"{server_group_backup_classes}\"' if server_group_backup_classes else \"\"\n",
+ "backup_sizes_option = f' --backupSizesMb \"{server_group_backup_sizes}\"' if server_group_backup_sizes else \"\"\n",
+ "backup_full_interval_option = f' --fullBackupInterval \"{server_group_backup_full_interval}\"' if server_group_backup_full_interval else \"\"\n",
+ "backup_delta_interval_option = f' --deltaBackupInterval \"{server_group_backup_delta_interval}\"' if server_group_backup_delta_interval else \"\"\n",
+ "backup_retention_min_option = f' --retentionMin \"{server_group_backup_retention_min}\"' if server_group_backup_retention_min else \"\"\n",
+ "backup_retention_max_option = f' --retentionMax \"{server_group_backup_retention_max}\"' if server_group_backup_retention_max else \"\"\n",
+ "cmd = f'azdata postgres server create --subscription {subscription} --rg {resource_group_name} --name {server_group_name} --namespace {server_group_namespace} --workers {server_group_workers} --serviceType {server_group_service_type} --dataSizeMb {server_group_data_size}{data_class_option}{port_option}{extensions_option}{cpu_min_option}{cpu_max_option}{memory_min_option}{memory_max_option}{backup_classes_option}{backup_sizes_option}{backup_full_interval_option}{backup_delta_interval_option}{backup_retention_min_option}{backup_retention_max_option}'\n",
+ "out=run_command()"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "4fbaf071-55a1-40bc-be7e-7b9b5547b886"
+ },
+ "outputs": [],
+ "execution_count": null
+ }
+ ]
+}
diff --git a/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb b/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb
new file mode 100644
index 0000000000..f858ff323f
--- /dev/null
+++ b/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb
@@ -0,0 +1,137 @@
+{
+ "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": [
+ "\n",
+ " \n",
+ "## Deploy Azure SQL DB managed instance on an existing Azure Arc data cluster\n",
+ " \n",
+ "This notebook walks through the process of deploying a Azure SQL DB managed instance on an existing Azure Arc data cluster.\n",
+ " \n",
+ "* Follow the instructions in the **Prerequisites** cell to install the tools if not already installed.\n",
+ "* Make sure you have the target Azure Arc data cluster already created.\n",
+ "\n",
+ "Please press the \"Run Cells\" button to run the notebook"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "e4ed0892-7b5a-4d95-bd0d-a6c3eb0b2c99"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Check prerequisites**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "68531b91-ddce-47d7-a1d8-2ddc3d17f3e7"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import sys,os,json,subprocess\n",
+ "def run_command():\n",
+ " print(\"Executing: \" + cmd)\n",
+ " output = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )\n",
+ " if output.returncode != 0:\n",
+ " print(f'Command: {cmd} failed \\n')\n",
+ " print(f'\\t>>>Error output: {output.stderr.decode(\"utf-8\")}\\n')\n",
+ " sys.exit(f'exit code: {output.returncode}\\n')\n",
+ " print(f'Successfully executed: {cmd}')\n",
+ " print(f'\\t>>>Output: {output.stdout.decode(\"utf-8\")}\\n')\n",
+ " return output.stdout.decode(\"utf-8\")\n",
+ "cmd = 'azdata --version'\n",
+ "out = run_command()\n",
+ ""
+ ],
+ "metadata": {
+ "azdata_cell_guid": "749d8dba-3da8-46e9-ae48-2b38056ab7a2",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### **Ensure SQL instance name, username, password, subscription id and resource group name**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "68ec0760-27d1-4ded-9a9f-89077c40b8bb"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Required Values\n",
+ "env_var = \"AZDATA_NB_VAR_SQL_INSTANCE_NAME\" in os.environ\n",
+ "if env_var:\n",
+ " mssql_instance_name = os.environ[\"AZDATA_NB_VAR_SQL_INSTANCE_NAME\"]\n",
+ "else:\n",
+ " sys.exit(f'environment variable: AZDATA_NB_VAR_SQL_INSTANCE_NAME was not defined. Exiting\\n')\n",
+ "env_var = \"AZDATA_NB_VAR_SQL_PASSWORD\" in os.environ\n",
+ "if env_var:\n",
+ " mssql_password = os.environ[\"AZDATA_NB_VAR_SQL_PASSWORD\"]\n",
+ "else:\n",
+ " sys.exit(f'environment variable: AZDATA_NB_VAR_SQL_PASSWORD was not defined. Exiting\\n') \n",
+ "\n",
+ "# Optional Values\n",
+ "subscription = os.environ[\"AZDATA_NB_VAR_ARC_SUBSCRIPTION\"] \n",
+ "resource_group_name = os.environ[\"AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME\"]\n"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "53769960-e1f8-4477-b4cf-3ab1ea34348b",
+ "tags": []
+ },
+ "outputs": [],
+ "execution_count": null
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### **Installing Managed SQL Instance**"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "90b0e162-2987-463f-9ce6-12dda1267189"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "print (f'Creating Managed SQL Server instance on Azure Arc')\n",
+ "\n",
+ "os.environ[\"MSSQL_SA_PASSWORD\"] = mssql_password\n",
+ "subscription_option = f' -s \"{subscription}\"' if subscription else \"\"\n",
+ "resource_group_option = f' -r \"{resource_group_name}\"' if resource_group_name else \"\"\n",
+ "cmd = f'azdata sql instance create -n {mssql_instance_name}{subscription_option}{resource_group_option}'\n",
+ "out=run_command()"
+ ],
+ "metadata": {
+ "azdata_cell_guid": "4fbaf071-55a1-40bc-be7e-7b9b5547b886"
+ },
+ "outputs": [],
+ "execution_count": null
+ }
+ ]
+}
diff --git a/extensions/arc/package.json b/extensions/arc/package.json
index 55aa00ab29..f017aa4619 100644
--- a/extensions/arc/package.json
+++ b/extensions/arc/package.json
@@ -9,7 +9,7 @@
"icon": "images/extension.png",
"engines": {
"vscode": "*",
- "azdata": ">=1.19.0"
+ "azdata": ">=1.20.0"
},
"activationEvents": [
"onCommand:arc.manageArcController",
@@ -21,6 +21,7 @@
"type": "git",
"url": "https://github.com/Microsoft/azuredatastudio.git"
},
+ "forceReload": true,
"main": "./out/extension",
"contributes": {
"dataExplorer": {
@@ -140,7 +141,774 @@
"view": "azureArc",
"contents": "%arc.view.welcome%"
}
- ]
+ ],
+ "resourceDeploymentTypes": [
+ {
+ "name": "arc.control.create",
+ "displayName": "%resource.type.azure.arc.display.name%",
+ "description": "%resource.type.azure.arc.description%",
+ "platforms": "*",
+ "icon": {
+ "light": "./images/data_controller.svg",
+ "dark": "./images/data_controller.svg"
+ },
+ "providers": [
+ {
+ "notebookWizard": {
+ "notebook": "./notesbooks/arcDeployment/deploy.arc.control.plane.ipynb",
+ "type": "new-arc-control-plane",
+ "runNotebook": false,
+ "codeCellInsertionPosition": 5,
+ "actionText": "%deploy.arc.control.plane.action%",
+ "title": "%arc.control.plane.new.wizard.title%",
+ "name": "arc.control.plane.new.wizard",
+ "labelPosition": "left",
+ "generateSummaryPage": false,
+ "pages": [
+ {
+ "title": "%arc.control.plane.select.cluster.title%",
+ "sections": [
+ {
+ "fields": [
+ {
+ "type": "kube_cluster_context_picker",
+ "label": "%arc.control.plane.kube.cluster.context%",
+ "required": true,
+ "inputWidth": "350px",
+ "variableName": "AZDATA_NB_VAR_ARC_CLUSTER_CONTEXT",
+ "configFileVariableName": "AZDATA_NB_VAR_ARC_CONFIG_FILE"
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.docker.account.title%",
+ "fields": [
+ {
+ "label": "%arc.control.plane.docker.account.name%",
+ "variableName": "AZDATA_NB_VAR_ARC_DOCKER_USERNAME",
+ "type": "text",
+ "required": true,
+ "defaultValue": "22cda7bb-2eb1-419e-a742-8710c313fe79",
+ "enabled": true
+ },
+ {
+ "label": "%arc.control.plane.docker.account.password%",
+ "variableName": "AZDATA_NB_VAR_ARC_DOCKER_PASSWORD",
+ "type": "password",
+ "userName": "docker",
+ "confirmationRequired": false,
+ "defaultValue": "",
+ "required": true
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.cluster.config.profile.title%",
+ "sections": [
+ {
+ "fields": [
+ {
+ "type": "options",
+ "label": "%arc.control.plane.cluster.config.profile%",
+ "required": true,
+ "variableName": "AZDATA_NB_VAR_ARC_PROFILE",
+ "editable": false,
+ "options": {
+ "values":[
+ "azure-arc-aks-private-preview",
+ "azure-arc-eks-private-preview",
+ "azure-arc-kubeadm-private-preview"
+ ],
+ "defaultValue": "azure-arc-aks-private-preview",
+ "optionsType": "radio"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.data.controller.create.title%",
+ "sections": [
+ {
+ "title": "%arc.control.plane.project.details.title%",
+ "fields": [
+ {
+ "type": "readonly_text",
+ "label": "%arc.control.plane.project.details.description%",
+ "labelWidth": "600px"
+ },
+ {
+ "type": "azure_account",
+ "required": true,
+ "subscriptionVariableName": "AZDATA_NB_VAR_ARC_SUBSCRIPTION",
+ "displaySubscriptionVariableName": "AZDATA_NB_VAR_ARC_DISPLAY_SUBSCRIPTION",
+ "resourceGroupVariableName": "AZDATA_NB_VAR_ARC_RESOURCE_GROUP"
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.data.controller.details.title%",
+ "fields": [
+ {
+ "type": "readonly_text",
+ "label": "%arc.control.plane.data.controller.details.description%",
+ "labelWidth": "600px"
+ },
+ {
+ "type": "text",
+ "label": "%arc.control.plane.arc.data.controller.namespace%",
+ "textValidationRequired": true,
+ "textValidationRegex": "^[a-z0-9]([-a-z0-9]{0,11}[a-z0-9])?$",
+ "textValidationDescription": "%arc.control.plane.arc.data.controller.namespace.validation.description%",
+ "defaultValue": "arc",
+ "required": true,
+ "variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAMESPACE"
+ },
+ {
+ "type": "text",
+ "label": "%arc.control.plane.arc.data.controller.name%",
+ "textValidationRequired": true,
+ "textValidationRegex": "^[a-z0-9]([-a-z0-9]{0,11}[a-z0-9])?$",
+ "textValidationDescription": "%arc.control.plane.arc.data.controller.name.validation.description%",
+ "defaultValue": "arc-cp1",
+ "required": true,
+ "variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAME"
+ },
+ {
+ "type": "azure_locations",
+ "label": "%arc.control.plane.arc.data.controller.location%",
+ "defaultValue": "East US",
+ "required": true,
+ "locationVariableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_LOCATION",
+ "displayLocationVariableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_DISPLAY_LOCATION",
+ "locations": [
+ "East US",
+ "East US 2",
+ "Central US"
+ ]
+ },
+ {
+ "type": "options",
+ "label": "%arc.control.plane.arc.data.controller.connectivity.mode%",
+ "options": {
+ "values":[
+ "Indirect",
+ "Direct"
+ ],
+ "defaultValue": "Indirect",
+ "optionsType": "radio"
+ },
+ "required": true,
+ "variableName": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTIVITY_MODE"
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.admin.account.title%",
+ "fields": [
+ {
+ "label": "%arc.control.plane.admin.account.name%",
+ "variableName": "AZDATA_NB_VAR_ARC_ADMIN_USERNAME",
+ "type": "text",
+ "required": true,
+ "defaultValue": "arcadmin",
+ "enabled": true
+ },
+ {
+ "label": "%arc.control.plane.admin.account.password%",
+ "variableName": "AZDATA_NB_VAR_ARC_ADMIN_PASSWORD",
+ "type": "sql_password",
+ "userName": "arcadmin",
+ "confirmationRequired": true,
+ "confirmationLabel": "%arc.control.plane.admin.account.confirm.password%",
+ "defaultValue": "",
+ "required": true
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.data.controller.create.summary.title%",
+ "isSummaryPage": true,
+ "fieldHeight": "16px",
+ "sections": [
+ {
+ "title": "",
+ "collapsible": false,
+ "fieldWidth": "200px",
+ "fieldHeight": "14px",
+ "spaceBetweenFields": 0,
+ "rows": [
+ {
+ "items": [
+ {
+ "items": [
+ {
+ "label": "%arc.control.plane.summary.arc.data.controller%",
+ "type": "readonly_text",
+ "enabled": true,
+ "labelWidth": "185px"
+ }
+ ]
+ },
+ {
+ "items": [
+ {
+ "label": "%arc.control.plane.summary.estimated.cost.per.month%",
+ "type": "readonly_text",
+ "enabled": true,
+ "labelWidth": "190px",
+ "labelCSSStyles": {
+ "fontWeight": "Bold"
+ }
+
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "items": [
+ {
+ "items": [
+ {
+ "label": "%arc.control.plane.summary.arc.by.microsoft%",
+ "type": "readonly_text",
+ "labelWidth": "185px"
+ }
+ ]
+ },
+ {
+ "items": [
+ {
+ "label": "%arc.control.plane.summary.free%",
+ "type": "readonly_text",
+ "enabled": true,
+ "defaultValue": "",
+ "labelWidth": "100px"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "items": [
+ {
+ "items": [
+ {
+ "label": "{0}",
+ "type": "readonly_text",
+ "enabled": true,
+ "labelWidth": "67px",
+ "links": [
+ {
+ "text": "%arc.control.plane.summary.arc.terms.of.use%",
+ "url": "https://go.microsoft.com/fwlink/?linkid=2045708"
+ }
+ ]
+ },
+ {
+ "label": "|",
+ "type": "readonly_text",
+ "enabled": true,
+ "defaultValue": "",
+ "labelWidth": "4px",
+ "fieldWidth": "6px"
+ },
+ {
+ "label": "{0}",
+ "type": "readonly_text",
+ "enabled": true,
+ "labelWidth": "102px",
+ "links": [
+ {
+ "text": "%arc.control.plane.summary.arc.terms.privacy.policy%",
+ "url": "https://go.microsoft.com/fwlink/?linkid=512132"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.summary.terms%",
+ "fieldHeight": "88px",
+ "fields":[
+ {
+ "label": "%arc.control.plane.summary.terms.description%",
+ "type": "readonly_text",
+ "enabled": true,
+ "labelWidth": "750px",
+ "links": [
+ {
+ "text": "%arc.control.plane.summary.terms.link.text%",
+ "url": "https://go.microsoft.com/fwlink/?linkid=2045624"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.summary.kubernetes%",
+ "fields":[
+ {
+ "label": "%arc.control.plane.summary.kube.config.file.path%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_CONFIG_FILE)"
+ },
+ {
+ "label": "%arc.control.plane.summary.cluster.context%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_CLUSTER_CONTEXT)"
+ },
+ {
+ "label": "%arc.control.plane.summary.profile%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_PROFILE)"
+ },
+ {
+ "label": "%arc.control.plane.summary.username%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_ADMIN_USERNAME)"
+ },
+ {
+ "label": "%arc.control.plane.summary.docker.username%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_DOCKER_USERNAME)"
+ }
+ ]
+ },
+ {
+ "title": "%arc.control.plane.summary.azure%",
+ "fields":[
+ {
+ "label": "%arc.control.plane.summary.data.controller.namespace%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAMESPACE)"
+ },
+ {
+ "label": "%arc.control.plane.summary.data.controller.name%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAME)"
+ },
+ {
+ "label": "%arc.control.plane.summary.data.controller.connectivity.mode%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTIVITY_MODE)"
+ },
+ {
+ "label": "%arc.control.plane.summary.subscription%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_DISPLAY_SUBSCRIPTION)",
+ "inputWidth": "600"
+ },
+ {
+ "label": "%arc.control.plane.summary.resource.group%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_RESOURCE_GROUP)"
+ },
+ {
+ "label": "%arc.control.plane.summary.location%",
+ "type": "readonly_text",
+ "isEvaluated": true,
+ "defaultValue": "$(AZDATA_NB_VAR_ARC_DATA_CONTROLLER_DISPLAY_LOCATION)"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "requiredTools": [
+ {
+ "name": "kubectl"
+ },
+ {
+ "name": "azdata",
+ "version": "20.0.0"
+ }
+ ],
+ "when": true
+ }
+ ],
+ "agreement": {
+ "template": "%arc.control.plane.arc.data.controller.agreement%",
+ "links": [
+ {
+ "text": "%microsoft.agreement.privacy.statement%",
+ "url": "https://go.microsoft.com/fwlink/?LinkId=853010"
+ },
+ {
+ "text": "%arc.agreement.azdata.eula%",
+ "url": "https://aka.ms/eula-azdata-en"
+ }
+ ]
+ }
+ },
+ {
+ "name": "arc.sql",
+ "displayName": "%resource.type.arc.sql.display.name%",
+ "description": "%resource.type.arc.sql.description%",
+ "platforms": "*",
+ "icon": {
+ "light": "./images/miaa.svg",
+ "dark": "./images/miaa.svg"
+ },
+ "options": [
+ {
+ "name": "resourceType",
+ "displayName": "%resource.type.picker.display.name%",
+ "values": [
+ {
+ "name": "sql.managed.instance",
+ "displayName": "%sql.managed.instance.display.name%"
+ }
+ ]
+ }
+ ],
+ "providers": [
+ {
+ "dialog": {
+ "notebook": "./notesbooks/arcDeployment/deploy.sql.existing.arc.ipynb",
+ "runNotebook": true,
+ "taskName": "%arc.sql.new.dialog.title%",
+ "actionText": "%arc.deploy.action%",
+ "title": "%arc.sql.new.dialog.title%",
+ "name": "arc.sql.new.dialog",
+ "tabs": [
+ {
+ "title": "",
+ "sections": [
+ {
+ "title": "%arc.azure.section.title%",
+ "fields": [
+ {
+ "subscriptionVariableName": "AZDATA_NB_VAR_ARC_SUBSCRIPTION",
+ "resourceGroupVariableName": "AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME",
+ "type": "azure_account",
+ "required": true
+ }
+ ]
+ },
+ {
+ "title": "%arc.sql.settings.section.title%",
+ "fields": [
+ {
+ "label": "%arc.sql.instance.name%",
+ "variableName": "AZDATA_NB_VAR_SQL_INSTANCE_NAME",
+ "type": "text",
+ "defaultValue": "sqlinstance1",
+ "required": true
+ },
+ {
+ "label": "%arc.sql.username%",
+ "variableName": "AZDATA_NB_VAR_SQL_USERNAME",
+ "type": "text",
+ "defaultValue": "sa",
+ "enabled": false
+ },
+ {
+ "label": "%arc.sql.password%",
+ "variableName": "AZDATA_NB_VAR_SQL_PASSWORD",
+ "type": "sql_password",
+ "userName": "sa",
+ "confirmationRequired": true,
+ "confirmationLabel": "%arc.confirm.password%",
+ "defaultValue": "",
+ "required": true
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "requiredTools": [
+ {
+ "name": "kubectl"
+ },
+ {
+ "name": "azdata",
+ "version": "15.0.2100"
+ }
+ ],
+ "when": "resourceType=sql.managed.instance"
+ }
+ ],
+ "agreement": {
+ "template": "%arc.agreement%",
+ "links": [
+ {
+ "text": "%microsoft.agreement.privacy.statement%",
+ "url": "https://go.microsoft.com/fwlink/?LinkId=853010"
+ },
+ {
+ "text": "%arc.agreement.sql.terms.conditions%",
+ "url": "https://go.microsoft.com/fwlink/?linkid=2045708"
+ },
+ {
+ "text": "%arc.agreement.azdata.eula%",
+ "url": "https://aka.ms/eula-azdata-en"
+ }
+ ]
+ }
+ },
+ {
+ "name": "arc.postgres",
+ "displayName": "%resource.type.arc.postgres.display.name%",
+ "description": "%resource.type.arc.postgres.description%",
+ "platforms": "*",
+ "icon": {
+ "light": "./images/postgres.svg",
+ "dark": "./images/postgres.svg"
+ },
+ "options": [
+ {
+ "name": "resourceType",
+ "displayName": "%resource.type.picker.display.name%",
+ "values": [
+ {
+ "name": "postgres",
+ "displayName": "%postgres.server.group.display.name%"
+ }
+ ]
+ }
+ ],
+ "providers": [
+ {
+ "dialog": {
+ "notebook": "./notesbooks/arcDeployment/deploy.postgres.existing.arc.ipynb",
+ "runNotebook": true,
+ "taskName": "%arc.postgres.new.dialog.title%",
+ "actionText": "%arc.deploy.action%",
+ "title": "%arc.postgres.new.dialog.title%",
+ "name": "arc.postgres.new.dialog",
+ "tabs": [
+ {
+ "title": "",
+ "sections": [
+ {
+ "title": "%arc.azure.section.title%",
+ "fields": [
+ {
+ "subscriptionVariableName": "AZDATA_NB_VAR_ARC_SUBSCRIPTION",
+ "resourceGroupVariableName": "AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME",
+ "type": "azure_account",
+ "required": true
+ }
+ ]
+ },
+ {
+ "title": "%arc.postgres.settings.section.title%",
+ "fields": [
+ {
+ "label": "%arc.postgres.server.group.name%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAME",
+ "type": "text",
+ "textValidationRequired": true,
+ "textValidationRegex": "^[a-z]([-a-z0-9]{0,8}[a-z0-9])?$",
+ "textValidationDescription": "%arc.postgres.server.group.name.validation.description%",
+ "defaultValue": "postgres1",
+ "required": true
+ },
+ {
+ "label": "%arc.postgres.server.group.namespace%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAMESPACE",
+ "type": "text",
+ "defaultValue": "default",
+ "required": true
+ },
+ {
+ "label": "%arc.postgres.server.group.workers%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_WORKERS",
+ "type": "number",
+ "defaultValue": "1",
+ "required": true,
+ "min": 1
+ },
+ {
+ "label": "%arc.postgres.server.group.service.type%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_SERVICE_TYPE",
+ "type": "options",
+ "options": [
+ "ClusterIP",
+ "NodePort",
+ "LoadBalancer"
+ ],
+ "defaultValue": "NodePort",
+ "required": true
+ },
+ {
+ "label": "%arc.postgres.server.group.data.size%",
+ "description": "%arc.postgres.server.group.data.size.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_DATA_SIZE",
+ "type": "number",
+ "defaultValue": "1024",
+ "required": true,
+ "min": 1
+ },
+ {
+ "label": "%arc.postgres.server.group.data.class%",
+ "description": "%arc.postgres.server.group.data.class.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_DATA_CLASS",
+ "type": "text"
+ },
+ {
+ "label": "%arc.postgres.server.group.port%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_PORT",
+ "type": "number",
+ "defaultValue": "5432",
+ "min": 1,
+ "max": 65535
+ },
+ {
+ "label": "%arc.postgres.server.group.extensions%",
+ "description": "%arc.postgres.server.group.extensions.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_EXTENSIONS",
+ "type": "text",
+ "textValidationRequired": true,
+ "textValidationRegex": "^(?:(?:pg_cron|postgis|postgis_raster|postgis_topology)(?!\\s*,\\s*$)(?:\\s*,\\s*|$))*$",
+ "textValidationDescription": "%arc.postgres.server.group.extensions.validation.description%",
+ "defaultValue": ""
+ }
+ ]
+ },
+ {
+ "title": "%arc.postgres.settings.scheduling.title%",
+ "fields": [
+ {
+ "label": "%arc.postgres.server.group.cpu.min%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MIN",
+ "type": "number",
+ "min": 0
+ },
+ {
+ "label": "%arc.postgres.server.group.cpu.max%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MAX",
+ "type": "number",
+ "min": 0
+ },
+ {
+ "label": "%arc.postgres.server.group.memory.min%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MIN",
+ "type": "number",
+ "min": 0
+ },
+ {
+ "label": "%arc.postgres.server.group.memory.max%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MAX",
+ "type": "number",
+ "min": 0
+ }
+ ]
+ },
+ {
+ "title": "%arc.postgres.settings.backups.title%",
+ "fields": [
+ {
+ "label": "%arc.postgres.server.group.backup.classes%",
+ "description": "%arc.postgres.server.group.backup.classes.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_CLASSES",
+ "type": "text"
+ },
+ {
+ "label": "%arc.postgres.server.group.backup.sizes%",
+ "description": "%arc.postgres.server.group.backup.sizes.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_SIZES",
+ "type": "text"
+ },
+ {
+ "label": "%arc.postgres.server.group.backup.claims%",
+ "description": "%arc.postgres.server.group.backup.claims.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_CLAIMS",
+ "type": "text"
+ },
+ {
+ "label": "%arc.postgres.server.group.backup.full.interval%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_FULL_INTERVAL",
+ "type": "number",
+ "min": 0
+ },
+ {
+ "label": "%arc.postgres.server.group.backup.delta.interval%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_DELTA_INTERVAL",
+ "type": "number",
+ "min": 0
+ },
+ {
+ "label": "%arc.postgres.server.group.backup.retention.min%",
+ "description": "%arc.postgres.server.group.backup.retention.min.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MIN",
+ "type": "text",
+ "textValidationRequired": true,
+ "textValidationRegex": "^(?:(?:\\d+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[mMhHdDwW]|[mMgGtTpPeE][bB]))(?!\\s*[,;]\\s*$)(?:\\s*[,;]\\s*|$))*$",
+ "textValidationDescription": "%arc.postgres.server.group.backup.retention.min.validation.description%",
+ "defaultValue": ""
+ },
+ {
+ "label": "%arc.postgres.server.group.backup.retention.max%",
+ "description": "%arc.postgres.server.group.backup.retention.max.description%",
+ "variableName": "AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MAX",
+ "type": "text",
+ "textValidationRequired": true,
+ "textValidationRegex": "^(?:(?:\\d+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[mMhHdDwW]|[mMgGtTpPeE][bB]))(?!\\s*[,;]\\s*$)(?:\\s*[,;]\\s*|$))*$",
+ "textValidationDescription": "%arc.postgres.server.group.backup.retention.max.validation.description%",
+ "defaultValue": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "requiredTools": [
+ {
+ "name": "azure-cli"
+ },
+ {
+ "name": "azdata",
+ "version": "15.0.4003"
+ }
+ ],
+ "when": "resourceType=postgres"
+ }
+ ],
+ "agreement": {
+ "template": "%arc.agreement%",
+ "links": [
+ {
+ "text": "%microsoft.agreement.privacy.statement%",
+ "url": "https://go.microsoft.com/fwlink/?LinkId=853010"
+ },
+ {
+ "text": "%arc.agreement.postgres.terms.conditions%",
+ "url": "https://go.microsoft.com/fwlink/?linkid=2045708"
+ },
+ {
+ "text": "%arc.agreement.azdata.eula%",
+ "url": "https://aka.ms/eula-azdata-en"
+ }
+ ]
+ }
+ }
+ ]
},
"dependencies": {
"request": "^2.88.0",
diff --git a/extensions/arc/package.nls.json b/extensions/arc/package.nls.json
index 16ab2f243f..c963328b89 100644
--- a/extensions/arc/package.nls.json
+++ b/extensions/arc/package.nls.json
@@ -12,5 +12,120 @@
"command.connectToController.title": "Connect to Existing Controller",
"command.removeController.title": "Remove Controller",
"command.refresh.title": "Refresh",
- "arc.openDashboard": "Manage"
+ "arc.openDashboard": "Manage",
+
+ "resource.type.azure.arc.display.name": "Azure Arc data controller",
+ "resource.type.azure.arc.description": "Creates an Azure Arc data controller",
+
+ "arc.control.plane.new.wizard.title": "Create Azure Arc data controller",
+ "arc.control.plane.cluster.environment.title": "What is your target existing Kubernetes cluster environment?",
+ "arc.control.plane.select.cluster.title": "Select from installed existing Kubernetes clusters",
+ "arc.control.plane.kube.cluster.context": "Cluster context",
+ "arc.control.plane.docker.account.title": "Docker account details",
+ "arc.control.plane.docker.account.name": "Docker account login",
+ "arc.control.plane.docker.account.password": "Password",
+ "arc.control.plane.cluster.config.profile.title": "Choose the config profile",
+ "arc.control.plane.cluster.config.profile": "Config profile",
+ "arc.control.plane.data.controller.create.title": "Provide details to create Azure Arc data controller and register it with Azure",
+ "arc.control.plane.project.details.title": "Project details",
+ "arc.control.plane.project.details.description": "Select the subscription to manage deployed resources and costs. Use resource groups like folders to organize and manage all your resources.",
+ "arc.control.plane.data.controller.details.title": "Data controller details",
+ "arc.control.plane.data.controller.details.description": "Provide an Azure region and a name for your Azure Arc data controller. This name will be used to identify your Arc location for remote management and monitoring.",
+ "arc.control.plane.arc.data.controller.connectivity.mode": "Data controller connectivity mode",
+ "arc.control.plane.arc.data.controller.namespace": "Data controller namespace",
+ "arc.control.plane.arc.data.controller.namespace.validation.description": "Data controller namespace (lower case letters, digits and - only)",
+ "arc.control.plane.arc.data.controller.name": "Data controller name",
+ "arc.control.plane.arc.data.controller.name.validation.description": "Data controller name (lower case letters, digits and - only)",
+ "arc.control.plane.arc.data.controller.location": "Location",
+ "arc.control.plane.admin.account.title": "Administrator account",
+ "arc.control.plane.admin.account.name": "Data controller login",
+ "arc.control.plane.admin.account.password": "Password",
+ "arc.control.plane.admin.account.confirm.password": "Confirm password",
+ "arc.control.plane.data.controller.create.summary.title": "Review your configuration",
+ "arc.control.plane.summary.arc.data.controller": "Azure Arc data controller",
+ "arc.control.plane.summary.estimated.cost.per.month": "Estimated cost per month",
+ "arc.control.plane.summary.arc.by.microsoft" : "by Microsoft",
+ "arc.control.plane.summary.free" : "Free",
+ "arc.control.plane.summary.arc.terms.of.use" : "Terms of use",
+ "arc.control.plane.summary.arc.terms.separator" : "|",
+ "arc.control.plane.summary.arc.terms.privacy.policy" : "Privacy policy",
+ "arc.control.plane.summary.terms" : "Terms",
+ "arc.control.plane.summary.terms.description": "By clicking 'Script to notebook', I (a) agree to the legal terms and privacy statement(s) associated with the Marketplace offering(s) listed above; (b) authorize Microsoft to bill my current payment method for the fees associated with the offering(s), with the same billing frequency as my Azure subscription; and (c) agree that Microsoft may share my contact, usage and transactional information with the provider(s) of the offering(s) for support, billing and other transactional activities. Microsoft does not provide rights for third-party offerings. For additional details see {0}.",
+ "arc.control.plane.summary.terms.link.text": "Azure Marketplace Terms",
+ "arc.control.plane.summary.kubernetes": "Kubernetes",
+ "arc.control.plane.summary.kube.config.file.path": "Kube config file path",
+ "arc.control.plane.summary.cluster.context": "Cluster context",
+ "arc.control.plane.summary.profile": "Config profile",
+ "arc.control.plane.summary.username": "Username",
+ "arc.control.plane.summary.docker.username": "Docker username",
+ "arc.control.plane.summary.azure": "Azure",
+ "arc.control.plane.summary.subscription": "Subscription",
+ "arc.control.plane.summary.resource.group": "Resource group",
+ "arc.control.plane.summary.data.controller.connectivity.mode": "Data controller connectivity mode",
+ "arc.control.plane.summary.data.controller.name": "Data controller name",
+ "arc.control.plane.summary.data.controller.namespace": "Data controller namespace",
+ "arc.control.plane.summary.location": "Location",
+ "arc.control.plane.arc.data.controller.agreement": "I accept {0} and {1}.",
+ "microsoft.agreement.privacy.statement":"Microsoft Privacy Statement",
+ "arc.agreement.azdata.eula":"azdata license terms",
+ "deploy.arc.control.plane.action":"Script to notebook",
+
+
+ "resource.type.arc.sql.display.name": "Azure SQL DB managed instance - Azure Arc (preview)",
+ "resource.type.arc.postgres.display.name": "PostgreSQL server groups - Azure Arc (preview)",
+ "resource.type.arc.sql.description": "Managed SQL Instance service for app developers in a customer-managed environment",
+ "resource.type.arc.postgres.description": "Deploy PostgreSQL server groups into an Azure Arc environment",
+ "resource.type.picker.display.name": "Resource Type",
+ "sql.managed.instance.display.name": "SQL DB managed instance - Azure Arc",
+ "postgres.server.group.display.name": "PostgreSQL server groups - Azure Arc",
+ "arc.sql.new.dialog.title": "Deploy Azure SQL DB managed instance - Azure Arc (preview)",
+ "arc.sql.settings.section.title": "SQL Connection information",
+ "arc.azure.section.title": "Azure information",
+ "arc.sql.instance.name": "Instance name (lower case letters and digits only)",
+ "arc.sql.username": "Username",
+ "arc.sql.password": "Password",
+ "arc.confirm.password": "Confirm password",
+ "arc.azure.account": "Azure account",
+ "arc.azure.subscription": "Azure subscription",
+ "arc.azure.resource.group": "Azure resource group",
+ "arc.azure.location": "Azure location",
+ "arc.postgres.new.dialog.title": "Deploy a PostgreSQL server group on Azure Arc (preview)",
+ "arc.postgres.settings.section.title": "PostgreSQL server group settings",
+ "arc.postgres.settings.backups.title": "PostgreSQL server group backup settings",
+ "arc.postgres.settings.scheduling.title": "PostgreSQL server group scheduling settings",
+ "arc.postgres.server.group.name": "Server group name",
+ "arc.postgres.server.group.name.validation.description": "Server group name must consist of lower case alphanumeric characters or '-', start with a letter, end with an alphanumeric character, and be 10 characters or fewer in length.",
+ "arc.postgres.server.group.namespace": "Kubernetes namespace",
+ "arc.postgres.server.group.workers": "Number of workers",
+ "arc.postgres.server.group.service.type": "Kubernetes service type",
+ "arc.postgres.server.group.data.size": "Data volume size (MB)",
+ "arc.postgres.server.group.data.size.description": "The number of megabytes (per node) that will be requested for the PostgreSQL server group's data volumes.",
+ "arc.postgres.server.group.data.class": "Data volume storage class",
+ "arc.postgres.server.group.data.class.description": "The Kubernetes storage class to use for the PostgreSQL server group's data volumes, or empty to use the default storage class.",
+ "arc.postgres.server.group.port": "Port",
+ "arc.postgres.server.group.extensions": "PostgreSQL extensions",
+ "arc.postgres.server.group.extensions.description": "A comma-separated list of the PostgreSQL extensions that should be added. Supported values: pg_cron, postgis, postgis_raster, postgis_topology.",
+ "arc.postgres.server.group.extensions.validation.description": "Supported PostgreSQL extensions: pg_cron, postgis, postgis_raster, postgis_topology.",
+ "arc.postgres.server.group.cpu.min": "Min CPU cores (per node) to reserve",
+ "arc.postgres.server.group.cpu.max": "Max CPU cores (per node) to allow",
+ "arc.postgres.server.group.memory.min": "Min memory MB (per node) to reserve",
+ "arc.postgres.server.group.memory.max": "Max memory MB (per node) to allow",
+ "arc.postgres.server.group.backup.classes": "Backup volume storage classes",
+ "arc.postgres.server.group.backup.classes.description": "A comma-separated list of existing Kubernetes storage classes to use for the PostgreSQL server group's backup volumes, one per backup tier. If provided, backup volume sizes must also be provided.",
+ "arc.postgres.server.group.backup.sizes": "Backup volume sizes (MB)",
+ "arc.postgres.server.group.backup.sizes.description": "A comma-separated list of the number of megabytes (per node) that will be requested for the PostgreSQL server group's backup volumes, one per backup tier. If specified, backups will be enabled. In this configuration a separate backup volume is used for each node.",
+ "arc.postgres.server.group.backup.claims": "Backup volume claims",
+ "arc.postgres.server.group.backup.claims.description": "A comma-separated list of existing Kubernetes persistent volume claims (in the same namespace) to use for the PostgreSQL server group's backups, one per backup tier. If specified, backups will be enabled. In this configuration the backup volumes are shared across all nodes.",
+ "arc.postgres.server.group.backup.full.interval": "Minutes between full backups",
+ "arc.postgres.server.group.backup.delta.interval": "Minutes between delta backups",
+ "arc.postgres.server.group.backup.retention.min": "Minimum trim settings",
+ "arc.postgres.server.group.backup.retention.min.description": "A list of trim settings that specifies the minimum number of days/size/counts of backups to preserve per tier. Each trim setting contains 1 or more trim values separated by commas and each tier is separated by a semicolon. Possible trim values include '7d', '10GB', or '50'.",
+ "arc.postgres.server.group.backup.retention.min.validation.description": "Minimum trim settings must contain 1 or more trim values separated by commas with each tier separated by a semicolon.",
+ "arc.postgres.server.group.backup.retention.max": "Maximum trim settings",
+ "arc.postgres.server.group.backup.retention.max.description": "A list of trim settings that specifies the maximum number of days/size/counts of backups to preserve per tier. Each trim setting contains 1 or more trim values separated by commas and each tier is separated by a semicolon. Possible trim values include '7d', '10GB', or '50'.",
+ "arc.postgres.server.group.backup.retention.max.validation.description": "Maximum trim settings must contain 1 or more trim values separated by commas with each tier separated by a semicolon.",
+ "arc.agreement": "I accept {0}, {1} and {2}.",
+ "arc.agreement.sql.terms.conditions":"Azure SQL DB managed instance - Azure Arc terms and conditions",
+ "arc.agreement.postgres.terms.conditions":"PostgreSQL server groups - Azure Arc terms and conditions",
+ "arc.deploy.action":"Deploy"
}
diff --git a/extensions/arc/src/extension.ts b/extensions/arc/src/extension.ts
index b01f205777..23e41e8d79 100644
--- a/extensions/arc/src/extension.ts
+++ b/extensions/arc/src/extension.ts
@@ -41,7 +41,20 @@ export async function activate(context: vscode.ExtensionContext): Promise
vscode.commands.registerCommand('arc.openDashboard', async (treeNode: TreeNode) => {
await treeNode.openDashboard().catch(err => vscode.window.showErrorMessage(loc.openDashboardFailed(err)));
});
+
+ await checkArcDeploymentExtension();
}
export function deactivate(): void {
}
+
+async function checkArcDeploymentExtension(): Promise {
+ const version = vscode.extensions.getExtension('Microsoft.arcdeployment')?.packageJSON.version;
+ if (version && version !== '0.3.2') {
+ // If we have an older verison of the deployment extension installed then uninstall it now since it's replaced
+ // by this extension. (the latest version of the Arc Deployment extension will uninstall itself so don't do
+ // anything here if that's already updated)
+ await vscode.commands.executeCommand('workbench.extensions.uninstallExtension', 'Microsoft.arcdeployment');
+ vscode.window.showInformationMessage(loc.arcDeploymentDeprecation);
+ }
+}
diff --git a/extensions/arc/src/localizedConstants.ts b/extensions/arc/src/localizedConstants.ts
index 19a8ce90fe..7a72190d1b 100644
--- a/extensions/arc/src/localizedConstants.ts
+++ b/extensions/arc/src/localizedConstants.ts
@@ -7,6 +7,7 @@ import * as nls from 'vscode-nls';
import { getErrorMessage } from './common/utils';
const localize = nls.loadMessageBundle();
+export const arcDeploymentDeprecation = localize('arc.arcDeploymentDeprecation', "The Arc Deployment extension has been replaced by the Arc extension and has been uninstalled.");
export const arcControllerDashboard = localize('arc.controllerDashboard', "Azure Arc Controller Dashboard (Preview)");
export const miaaDashboard = localize('arc.miaaDashboard', "Managed Instance Dashboard (Preview)");
export const postgresDashboard = localize('arc.postgresDashboard', "Postgres Dashboard (Preview)");
diff --git a/extensions/arc/src/test/.gitignore b/extensions/arc/src/test/.gitignore
new file mode 100644
index 0000000000..e9ab85b883
--- /dev/null
+++ b/extensions/arc/src/test/.gitignore
@@ -0,0 +1,2 @@
+/env
+/__pycache__
diff --git a/extensions/arc/src/test/README.md b/extensions/arc/src/test/README.md
new file mode 100644
index 0000000000..ac0513c1e3
--- /dev/null
+++ b/extensions/arc/src/test/README.md
@@ -0,0 +1,21 @@
+# Tests for deploying Arc resources via Jupyter notebook
+
+## Prerequisites
+- Python >= 3.6
+- Pip package manager
+- Azdata CLI installed and logged into an Arc controller
+
+## Running the tests
+### 1. (Optional, recommended) Create and activate a Python virtual environment
+- `python -m venv env`
+- `source env/bin/activate` (Linux)
+- `env\Scripts\activate.bat` (Windows)
+
+### 2. Upgrade pip
+- `pip install --upgrade pip`
+
+### 3. Install the dependencies
+- `pip install -r requirements.txt`
+
+### 4. Run the tests
+- `pytest`
diff --git a/extensions/arc/src/test/requirements.txt b/extensions/arc/src/test/requirements.txt
new file mode 100644
index 0000000000..9a99b6a1cd
--- /dev/null
+++ b/extensions/arc/src/test/requirements.txt
@@ -0,0 +1,2 @@
+pytest==5.3.5
+notebook==6.0.3
diff --git a/extensions/arc/src/test/test_notebooks.py b/extensions/arc/src/test/test_notebooks.py
new file mode 100644
index 0000000000..a561589e06
--- /dev/null
+++ b/extensions/arc/src/test/test_notebooks.py
@@ -0,0 +1,111 @@
+##---------------------------------------------------------------------------------------------
+## Copyright (c) Microsoft Corporation. All rights reserved.
+## Licensed under the Source EULA. See License.txt in the project root for license information.
+##--------------------------------------------------------------------------------------------
+
+import json
+import nbformat
+import os
+import random
+import string
+import sys
+import uuid
+from nbconvert.preprocessors import ExecutePreprocessor
+from subprocess import Popen, PIPE, TimeoutExpired
+
+## Variables
+notebook_path = '../../notebooks/arcDeployment/'
+
+## Helper functions
+def generate_name(prefix, length=8):
+ return (prefix + '-' + ''.join(
+ [random.choice(string.ascii_lowercase)
+ for n in range(length - len(prefix) - 1)]))
+
+def clear_env():
+ for k in [k for k in os.environ.keys() if k.startswith('AZDATA_NB_VAR_')]:
+ del os.environ[k]
+
+def azdata(commands, timeout=None, stdin=None):
+ commands.insert(0, "azdata")
+ print('Executing command: \n', ' '.join(commands))
+ proc = Popen(commands, stdin=PIPE if stdin is not None else None, stdout=PIPE, stderr=PIPE, shell=os.name=='nt')
+ try:
+ (stdout, stderr) = proc.communicate(input=stdin, timeout=timeout)
+ except TimeoutExpired:
+ # https://docs.python.org/3.5/library/subprocess.html#subprocess.Popen.communicate
+ # The child process is not killed if the timeout expires, so in order to
+ # cleanup properly we should kill the child process and finish communication.
+ proc.kill()
+ (stdout, stderr) = proc.communicate(timeout=timeout)
+ sys.stdout.buffer.write(stdout)
+ sys.stderr.buffer.write(stderr)
+ raise
+
+ sys.stdout.buffer.write(stdout)
+ if proc.returncode != 0:
+ raise Exception(stderr)
+ else:
+ sys.stderr.buffer.write(stderr)
+
+ return (stdout.decode(sys.stdout.encoding),
+ stderr.decode(sys.stderr.encoding))
+
+## Tests
+def test_postgres_create():
+ # Load the notebook
+ with open(notebook_path + 'deploy.postgres.existing.arc.ipynb') as f:
+ nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)
+
+ name = generate_name('pg')
+ try:
+ # Setup the environment
+ os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAME'] = name
+ subscription = os.environ['AZDATA_NB_VAR_ARC_SUBSCRIPTION'] = str(uuid.uuid4())
+ resource_group = os.environ['AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME'] = 'test'
+ namespace = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAMESPACE'] = 'default'
+ workers = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_WORKERS'] = '1'
+ service_type = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_SERVICE_TYPE'] = 'NodePort'
+ data_size = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_DATA_SIZE'] = '512'
+ port = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_PORT'] = '5431'
+ extensions = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_EXTENSIONS'] = 'pg_cron,postgis'
+ cpu_min = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MIN'] = '1'
+ cpu_max = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_CPU_MAX'] = '2'
+ memory_min = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MIN'] = '256'
+ memory_max = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_MEMORY_MAX'] = '1023'
+ backup_sizes = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_SIZES'] = '512,1023'
+ backup_full_interval = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_FULL_INTERVAL'] = '20'
+ backup_delta_interval = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_DELTA_INTERVAL'] = '10'
+ backup_retention_min = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MIN'] = '1,1GB;2,2GB'
+ backup_retention_max = os.environ['AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_BACKUP_RETENTION_MAX'] = '2,2GB;3,3GB'
+
+ # Execute the notebook that creates Postgres
+ ExecutePreprocessor(timeout=1200).preprocess(nb, {'metadata': {'path': notebook_path}})
+
+ # Verify that Postgres was created successfully
+ (out, _) = azdata(['postgres', 'server', 'show', '-n', name])
+ db = json.loads(out)
+ assert db['metadata']['name'] == name
+ assert db['metadata']['namespace'] == namespace
+ assert db['spec']['scale']['shards'] == int(workers)
+ assert db['spec']['service']['type'] == service_type
+ assert db['spec']['storage']['volumeSize'] == data_size + 'Mi'
+ assert db['spec']['service']['port'] == int(port)
+ assert [p['name'] for p in db['spec']['engine']['plugins']] == ['pg_cron' ,'postgis']
+ assert db['spec']['scheduling']['default']['resources']['requests']['cpu'] == cpu_min
+ assert db['spec']['scheduling']['default']['resources']['limits']['cpu'] == cpu_max
+ assert db['spec']['scheduling']['default']['resources']['requests']['memory'] == memory_min + 'Mi'
+ assert db['spec']['scheduling']['default']['resources']['limits']['memory'] == memory_max + 'Mi'
+ assert [t['storage']['volumeSize'] for t in db['spec']['backups']['tiers']] == [b + 'Mi' for b in backup_sizes.split(',')]
+ assert db['spec']['backups']['fullMinutes'] == int(backup_full_interval)
+ assert db['spec']['backups']['deltaMinutes'] == int(backup_delta_interval)
+ for i in range(len(db['spec']['backups']['tiers'])):
+ assert db['spec']['backups']['tiers'][i]['retention']['minimums'] == backup_retention_min.split(';')[i].split(',')
+ assert db['spec']['backups']['tiers'][i]['retention']['maximums'] == backup_retention_max.split(';')[i].split(',')
+ except Exception:
+ # Capture cell outputs to help with debugging
+ print([c['outputs'] for c in nb['cells'] if c.get('outputs')])
+ raise
+ finally:
+ clear_env()
+ azdata(['postgres', 'server', 'delete', '-n', name])