diff --git a/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb b/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb index 0534e1c91f..4f4d7ea959 100644 --- a/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb +++ b/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb @@ -98,6 +98,18 @@ "source": [ "print (f'Creating the SQL managed instance - Azure Arc instance')\n", "\n", + "is_indirect = arc_data_controller_connection_mode == 'indirect'\n", + "\n", + "# Indirect Mode Parameters\n", + "namespace = f' --k8s-namespace {arc_data_controller_namespace}' if is_indirect else ''\n", + "use_k8s = ' --use-k8s' if is_indirect else ''\n", + "\n", + "# Direct Mode Parameters\n", + "resource_group = f' --resource-group {arc_data_controller_resource_group}' if not is_indirect else ''\n", + "custom_location = f' --custom-location {arc_data_controller_custom_location}' if not is_indirect else ''\n", + "location = f' --location {arc_data_controller_location}' if not is_indirect else ''\n", + "\n", + "# General Parameters\n", "cores_request_option = f' --cores-request \"{sql_cores_request}\"' if sql_cores_request else \"\"\n", "cores_limit_option = f' --cores-limit \"{sql_cores_limit}\"' if sql_cores_limit else \"\"\n", "memory_request_option = f' --memory-request \"{sql_memory_request}Gi\"' if sql_memory_request else \"\"\n", @@ -121,7 +133,7 @@ "\n", "os.environ[\"AZDATA_USERNAME\"] = sql_username\n", "os.environ[\"AZDATA_PASSWORD\"] = os.environ[\"AZDATA_NB_VAR_SQL_PASSWORD\"]\n", - "cmd = f'az sql mi-arc create --name {sql_instance_name} --k8s-namespace {arc_data_controller_namespace} --replicas {sql_replicas}{cores_request_option}{cores_limit_option}{memory_request_option}{memory_limit_option}{storage_class_data_option}{storage_class_datalogs_option}{storage_class_logs_option}{storage_class_backup_option}{volume_size_data}{volume_size_datalogs}{volume_size_logs}{volume_size_backups}{retention_days}{service_tier}{dev_use}{license_type}{cores_limit} --use-k8s'\n", + "cmd = f'az sql mi-arc create --name {sql_instance_name}{namespace}{resource_group}{location}{custom_location} --replicas {sql_replicas}{cores_request_option}{cores_limit_option}{memory_request_option}{memory_limit_option}{storage_class_data_option}{storage_class_datalogs_option}{storage_class_logs_option}{storage_class_backup_option}{volume_size_data}{volume_size_datalogs}{volume_size_logs}{volume_size_backups}{retention_days}{service_tier}{dev_use}{license_type}{cores_limit}{use_k8s}'\n", "out=run_command()" ] } diff --git a/extensions/arc/package.json b/extensions/arc/package.json index eb5148d27e..80c0abdadf 100644 --- a/extensions/arc/package.json +++ b/extensions/arc/package.json @@ -990,7 +990,11 @@ "variableNames": { "namespace": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAMESPACE", "kubeConfig": "AZDATA_NB_VAR_CONTROLLER_KUBECONFIG", - "clusterContext": "AZDATA_NB_VAR_CONTROLLER_KUBECTL_CONTEXT" + "clusterContext": "AZDATA_NB_VAR_CONTROLLER_KUBECTL_CONTEXT", + "resourceGroup": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_RESOURCE_GROUP", + "connectionMode": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CONNECTION_MODE", + "location": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_LOCATION", + "customLocation": "AZDATA_NB_VAR_ARC_DATA_CONTROLLER_CUSTOM_LOCATION" } }, "optionsType": "dropdown" diff --git a/extensions/arc/src/providers/arcControllersOptionsSourceProvider.ts b/extensions/arc/src/providers/arcControllersOptionsSourceProvider.ts index 54881b2573..6a93f74972 100644 --- a/extensions/arc/src/providers/arcControllersOptionsSourceProvider.ts +++ b/extensions/arc/src/providers/arcControllersOptionsSourceProvider.ts @@ -32,6 +32,10 @@ export class ArcControllersOptionsSourceProvider implements rd.IOptionsSourcePro case 'namespace': return controller.info.namespace || ''; case 'kubeConfig': return controller.info.kubeConfigFilePath; case 'clusterContext': return controller.info.kubeClusterContext; + case 'resourceGroup': return controller.info.resourceGroup; + case 'connectionMode': return controller.info.connectionMode; + case 'location': return controller.info.location; + case 'customLocation': return controller.info.customLocation; default: throw new Error(loc.variableValueFetchForUnsupportedVariable(variableName)); } } @@ -41,6 +45,10 @@ export class ArcControllersOptionsSourceProvider implements rd.IOptionsSourcePro case 'namespace': return false; case 'kubeConfig': return false; case 'clusterContext': return false; + case 'resourceGroup': return false; + case 'connectionMode': return false; + case 'location': return false; + case 'customLocation': return false; default: throw new Error(loc.isPasswordFetchForUnsupportedVariable(variableName)); } } diff --git a/extensions/arc/src/test/mocks/fakeControllerModel.ts b/extensions/arc/src/test/mocks/fakeControllerModel.ts index b147c6fdeb..8840c200b8 100644 --- a/extensions/arc/src/test/mocks/fakeControllerModel.ts +++ b/extensions/arc/src/test/mocks/fakeControllerModel.ts @@ -11,7 +11,7 @@ import { AzureArcTreeDataProvider } from '../../ui/tree/azureArcTreeDataProvider export class FakeControllerModel extends ControllerModel { constructor(treeDataProvider?: AzureArcTreeDataProvider, info?: Partial) { - const _info: ControllerInfo = Object.assign({ id: uuid(), endpoint: '', kubeConfigFilePath: '', kubeClusterContext: '', name: '', namespace: '', username: '', rememberPassword: false, resources: [] }, info); + const _info: ControllerInfo = Object.assign({ id: uuid(), endpoint: '', kubeConfigFilePath: '', kubeClusterContext: '', name: '', namespace: '', username: '', rememberPassword: false, resources: [], resourceGroup: '', connectionMode: '', location: '', customLocation: '' }, info); super(treeDataProvider!, _info); } diff --git a/extensions/arc/src/typings/arc.d.ts b/extensions/arc/src/typings/arc.d.ts index a0562829ae..a5d267ef44 100644 --- a/extensions/arc/src/typings/arc.d.ts +++ b/extensions/arc/src/typings/arc.d.ts @@ -39,7 +39,11 @@ declare module 'arc' { kubeClusterContext: string, namespace: string, name: string, - resources: ResourceInfo[] + resources: ResourceInfo[], + resourceGroup: string, + connectionMode: string, + location: string, + customLocation: string }; export interface DataController { diff --git a/extensions/arc/src/ui/dialogs/connectControllerDialog.ts b/extensions/arc/src/ui/dialogs/connectControllerDialog.ts index 94412c32e1..b0f76760a0 100644 --- a/extensions/arc/src/ui/dialogs/connectControllerDialog.ts +++ b/extensions/arc/src/ui/dialogs/connectControllerDialog.ts @@ -93,6 +93,10 @@ abstract class ControllerDialogBase extends InitializingComponent { protected completionPromise = new Deferred(); protected id!: string; protected resources: ResourceInfo[] = []; + protected resourceGroup!: string; + protected connectionMode!: string; + protected location!: string; + protected customLocation!: string; constructor(protected treeDataProvider: AzureArcTreeDataProvider, title: string) { super(); @@ -165,7 +169,11 @@ abstract class ControllerDialogBase extends InitializingComponent { kubeConfigFilePath: this.kubeConfigInputBox.value!, kubeClusterContext: this.clusterContextRadioGroup.value!, name: this.nameInputBox.value ?? '', - resources: this.resources + resources: this.resources, + resourceGroup: this.resourceGroup ?? '', + connectionMode: this.connectionMode ?? '', + location: this.location ?? '', + customLocation: this.customLocation ?? '' }; } } @@ -191,6 +199,15 @@ export class ConnectToControllerDialog extends ControllerDialogBase { await controllerModel.refresh(false, this.namespaceInputBox.value); // default info.name to the name of the controller instance if the user did not specify their own and to a pre-canned default if for some weird reason controller endpoint returned instanceName is also not a valid value controllerModel.info.name = controllerModel.info.name || controllerModel.controllerConfig?.metadata.name || loc.defaultControllerName; + controllerModel.info.resourceGroup = controllerModel.controllerConfig?.spec.settings.azure.resourceGroup; + controllerModel.info.connectionMode = controllerModel.controllerConfig?.spec.settings.azure.connectionMode; + controllerModel.info.location = controllerModel.controllerConfig?.spec.settings.azure.location; + + if (controllerModel.info.connectionMode === 'direct') { + const rawCustomLocation = controllerModel.controllerConfig?.metadata.annotations['management.azure.com/customLocation']; + const exp = /\/\bsubscriptions\b\/[\S]*\/\bresourceGroups\/[\S]*\/providers\/[\S]*\/customLocations\/([\S]*)/; + controllerModel.info.customLocation = exp.exec(rawCustomLocation)?.pop(); + } } catch (err) { this.dialog.message = { text: loc.connectToControllerFailed(this.namespaceInputBox.value, err), diff --git a/extensions/azcli/src/typings/az-ext.d.ts b/extensions/azcli/src/typings/az-ext.d.ts index 4d3d328809..d631cbdc2d 100644 --- a/extensions/azcli/src/typings/az-ext.d.ts +++ b/extensions/azcli/src/typings/az-ext.d.ts @@ -48,6 +48,9 @@ declare module 'az-ext' { apiVersion: string, // "arcdata.microsoft.com/v1alpha1" kind: string, // "DataController" metadata: { + annotations: { + 'management.azure.com/customLocation': string // "/subscriptions/a5082b19-8a6e-4bc5-8fdd-8ef39dfebc39/resourceGroups/canye-rg/providers/Microsoft.ExtendedLocation/customLocations/oakland" + }, creationTimestamp: string, // "2020-08-19T17:05:39Z" generation: number, // /1 name: string, // "arc"