diff --git a/src/quantum/azext_quantum/_help.py b/src/quantum/azext_quantum/_help.py index a8e07a3ad39..d2f01030ffa 100644 --- a/src/quantum/azext_quantum/_help.py +++ b/src/quantum/azext_quantum/_help.py @@ -54,6 +54,9 @@ - name: Get the list of Azure Quantum workspaces available text: |- az quantum workspace list + - name: Create a new Azure Quantum workspace + text: |- + az quantum workspace create -g MyResourceGroup -w MyWorkspace -l MyLocation -sa MyStorageAccountName - name: Delete an Azure Quantum workspace that is no longer being used text: |- az quantum workspace delete -g MyResourceGroup -w MyWorkspace diff --git a/src/quantum/azext_quantum/_params.py b/src/quantum/azext_quantum/_params.py index 085a69f637a..349005032bc 100644 --- a/src/quantum/azext_quantum/_params.py +++ b/src/quantum/azext_quantum/_params.py @@ -9,6 +9,7 @@ def load_arguments(self, _): workspace_name_type = CLIArgumentType(options_list=['--workspace-name', '-w'], help='Name of the Quantum Workspace. You can configure the default workspace using `az quantum workspace set`.', id_part=None, required=False) + storage_account_name_type = CLIArgumentType(options_list=['--storage_account', '-sa'], help='Name of the storage account to be used by a quantum workspace.') program_args_type = CLIArgumentType(nargs='*', help='List of arguments expected by the Q# operation specified as --name=value after `--`.') target_id_type = CLIArgumentType(options_list=['--target-id', '-t'], help='Target id.') project_type = CLIArgumentType(help='The location of the Q# project to submit. Defaults to current folder.') @@ -19,6 +20,7 @@ def load_arguments(self, _): with self.argument_context('quantum workspace') as c: c.argument('workspace_name', workspace_name_type) + c.argument('storage_account', storage_account_name_type) with self.argument_context('quantum target') as c: c.argument('workspace_name', workspace_name_type) diff --git a/src/quantum/azext_quantum/commands.py b/src/quantum/azext_quantum/commands.py index de94c55da57..a5481ca273d 100644 --- a/src/quantum/azext_quantum/commands.py +++ b/src/quantum/azext_quantum/commands.py @@ -82,6 +82,7 @@ def load_command_table(self, _): target_ops = CliCommandType(operations_tmpl='azext_quantum.operations.target#{}') with self.command_group('quantum workspace', workspace_ops) as w: + w.command('create', 'create') w.command('delete', 'delete', validator=validate_workspace_info) w.command('list', 'list') w.command('show', 'show', validator=validate_workspace_info) diff --git a/src/quantum/azext_quantum/operations/workspace.py b/src/quantum/azext_quantum/operations/workspace.py index c6a2e5adf3f..c00561f34b3 100644 --- a/src/quantum/azext_quantum/operations/workspace.py +++ b/src/quantum/azext_quantum/operations/workspace.py @@ -8,6 +8,9 @@ from knack.util import CLIError from .._client_factory import cf_workspaces +from ..vendored_sdks.azure_mgmt_quantum.models import QuantumWorkspace +from ..vendored_sdks.azure_mgmt_quantum.models import QuantumWorkspaceIdentity +from ..vendored_sdks.azure_mgmt_quantum.models import Provider class WorkspaceInfo(object): @@ -43,6 +46,39 @@ def save(self, cmd): cmd.cli_ctx.config.set_value('quantum', 'group', self.resource_group) cmd.cli_ctx.config.set_value('quantum', 'workspace', self.name) +def get_basic_quantum_workspace(location, info, storage_account): + qw = QuantumWorkspace() + # Use a default provider + # Replace this with user specified providers as part of task: + # https://ms-quantum.visualstudio.com/Quantum%20Program/_workitems/edit/16184 + prov = Provider() + prov.provider_id = "Microsoft" + prov.provider_sku = "Basic" + qw.providers = [prov] + # Allow the system to assign the workspace identity + qw.identity = QuantumWorkspaceIdentity() + qw.identity.type = "SystemAssigned" + qw.location = location + qw.storage_account = f"/subscriptions/{info.subscription}/resourceGroups/{info.resource_group}/providers/Microsoft.Storage/storageAccounts/{storage_account}" + return qw + + +def create(cmd, resource_group_name=None, workspace_name=None, location=None, storage_account=None): + """ + Creates a new Azure Quantum workspace. + """ + client = cf_workspaces(cmd.cli_ctx) + if (not workspace_name): + raise CLIError("An explicit workspace name is required for this command.") + if (not storage_account): + raise CLIError("A quantum workspace requires a valid storage account.") + info = WorkspaceInfo(cmd, resource_group_name, workspace_name) + if (not info.resource_group): + raise CLIError("Please run 'az quantum workspace set' first to select a default Quantum Workspace.") + quantum_workspace = get_basic_quantum_workspace(location, info, storage_account) + return client.create_and_update(info.resource_group, info.name, quantum_workspace, polling=False) + + def delete(cmd, resource_group_name=None, workspace_name=None): """ Deletes the given (or current) Azure Quantum workspace. diff --git a/src/quantum/azext_quantum/tests/latest/test_quantum_workspace.py b/src/quantum/azext_quantum/tests/latest/test_quantum_workspace.py index 862ebc4fb9a..b011cf93358 100644 --- a/src/quantum/azext_quantum/tests/latest/test_quantum_workspace.py +++ b/src/quantum/azext_quantum/tests/latest/test_quantum_workspace.py @@ -46,9 +46,14 @@ def test_workspace(self): # clear self.cmd(f'az quantum workspace clear') + # create + self.cmd(f'az quantum workspace create -g {TEST_RG} -w {TEST_WORKSPACE_CREATE_DELETE} -l {TEST_WORKSPACE_LOCATION} -sa {TEST_WORKSPACE_SA} -o json'), checks=[ + self.check("name", TEST_WORKSPACE_CREATE_DELETE), + self.check("provisioningState", "Succeeded") + ]) + # delete - ## TODO: This test is disabled until the 'create' command is added. - # self.cmd(f'az quantum workspace delete -g {TEST_RG} -w {TEST_WORKSPACE_CREATE_DELETE} -o json'), checks=[ - # self.check("name", TEST_WORKSPACE_CREATE_DELETE), - # self.check("provisioningState", ) - #]) + self.cmd(f'az quantum workspace delete -g {TEST_RG} -w {TEST_WORKSPACE_CREATE_DELETE} -o json'), checks=[ + self.check("name", TEST_WORKSPACE_CREATE_DELETE), + self.check("provisioningState", "Deleting") + ]) diff --git a/src/quantum/azext_quantum/tests/latest/utils.py b/src/quantum/azext_quantum/tests/latest/utils.py index a22c23f78b9..829f35e9176 100644 --- a/src/quantum/azext_quantum/tests/latest/utils.py +++ b/src/quantum/azext_quantum/tests/latest/utils.py @@ -7,6 +7,8 @@ TEST_RG = 'aqua-provider-validator' TEST_WORKSPACE = 'validator-workspace-westus' TEST_WORKSPACE_CREATE_DELETE = 'validator-workspace-crdl-westus' +TEST_WORKSPACE_SA = 'aqvalidatorstorage' +TEST_WORKSPACE_LOCATION = 'westus' def is_private_preview_subscription(scenario):