Repository: Azure/azure-cli-extensions

Issue:
az blueprint assignment create - fails

### **This is autogenerated. Please review and update as needed.**

## Describe the bug

**Command Name**
`az blueprint assignment create
Extension Name: blueprint. Version: 0.1.0.`

**Errors:**
```
'artifact_name'
Traceback (most recent call last):
python3.6/site-packages/knack/cli.py, ln 215, in invoke
    cmd_result = self.invocation.execute(args)
cli/core/commands/__init__.py, ln 625, in execute
    raise ex
cli/core/commands/__init__.py, ln 689, in _run_jobs_serially
    results.append(self._run_job(expanded_arg, cmd_copy))
...
cliextensions/blueprint/azext_blueprint/custom.py, ln 526, in <dictcomp>
    body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups} if resource_groups is not None else {}
KeyError: 'artifact_name'
```

## To Reproduce:
Steps to reproduce the behavior. Note that argument values have been redacted, as they may contain sensitive information.

- _Put any pre-requisite steps here..._
- `az blueprint assignment create --subscription {} --name {} --location {} --identity-type {} --description {} --blueprint-version {} --locks-mode {} --resource-group-value {} {} {} --parameters {}`

## Expected Behavior

## Environment Summary
```
Linux-5.3.0-46-generic-x86_64-with-debian-buster-sid
Python 3.6.5
Installer: DEB

azure-cli 2.3.1

Extensions:
blueprint 0.1.0

```
## Additional Context

<!--Please don't remove this:-->
<!--auto-generated-->




Discussion:
Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @alex-frankel, @filizt.
blueprint 
@fengzhou-msft  please take a look
@robfrut135 did you specify the `artifact_name` value in `--resource-group-value`? It is the key of your resource group under `resourceGroups` of your blueprint definition. An example is [here](https://github.com/Azure/azure-cli-extensions/blame/master/src/blueprint/README.md#L133).
@fengzhou-msft i get the same key error and I am specifying the `artifact_name` value in `--resource-group-value`. The command I run looks something like this:

```
az blueprint assignment update --subscription XXXX --name MyAssignment \
--location eastus --identity-type SystemAssigned \
--blueprint-version "/providers/Microsoft.Management/managementGroups/mymg/providers/Microsoft.Blueprint/blueprints/myblueprint/versions/v5" \
--resource-group-value artifact_name=SingleRG name=my-new-rg location=eastus
``` 
Error:
```
cli.azure.cli.core.util : The command failed with an unexpected error. Here is the traceback:

The command failed with an unexpected error. Here is the traceback:

cli.azure.cli.core.util : 'artifact_name'
Traceback (most recent call last):
  File "/opt/az/lib/python3.6/site-packages/knack/cli.py", line 215, in invoke
    cmd_result = self.invocation.execute(args)
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 631, in execute
    raise ex
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 695, in _run_jobs_serially
    results.append(self._run_job(expanded_arg, cmd_copy))
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 688, in _run_job
    six.reraise(*sys.exc_info())
  File "/opt/az/lib/python3.6/site-packages/six.py", line 693, in reraise
    raise value
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 665, in _run_job
    result = cmd_copy(params)
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 324, in __call__
    return self.handler(*args, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/__init__.py", line 574, in default_command_handler
    return op(**command_args)
  File "/home/paulb1/.azure/cliextensions/blueprint/azext_blueprint/custom.py", line 594, in update_blueprint_assignment
    body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups}  # dictionary
  File "/home/paulb1/.azure/cliextensions/blueprint/azext_blueprint/custom.py", line 594, in <dictcomp>
    body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups}  # dictionary
KeyError: 'artifact_name'
'artifact_name'
Traceback (most recent call last):
  File "/opt/az/lib/python3.6/site-packages/knack/cli.py", line 215, in invoke
    cmd_result = self.invocation.execute(args)
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 631, in execute
    raise ex
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 695, in _run_jobs_serially
    results.append(self._run_job(expanded_arg, cmd_copy))
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 688, in _run_job
    six.reraise(*sys.exc_info())
  File "/opt/az/lib/python3.6/site-packages/six.py", line 693, in reraise
    raise value
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 665, in _run_job
    result = cmd_copy(params)
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/commands/__init__.py", line 324, in __call__
    return self.handler(*args, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/azure/cli/core/__init__.py", line 574, in default_command_handler
    return op(**command_args)
  File "/home/paulb1/.azure/cliextensions/blueprint/azext_blueprint/custom.py", line 594, in update_blueprint_assignment
    body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups}  # dictionary
  File "/home/paulb1/.azure/cliextensions/blueprint/azext_blueprint/custom.py", line 594, in <dictcomp>
    body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups}  # dictionary
KeyError: 'artifact_name'
```
Reproduced this issue with Python 3.6 and 3.7, but not with Python 3.8.

In Python 3.6 and 3.7, `_del_artifact_name(rg)` happens before `rg['artifact_name']` in:
`body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups}`

I will submit a fix to process a copy of `rg` in `_del_artifact_name`.

Resolving patch:
diff --git a/src/blueprint/azext_blueprint/custom.py b/src/blueprint/azext_blueprint/custom.py
--- a/src/blueprint/azext_blueprint/custom.py
+++ b/src/blueprint/azext_blueprint/custom.py
@@ -442,6 +442,7 @@ def publish_blueprint(cmd,
                       change_notes=None):
     body = {}
     body['change_notes'] = change_notes  # str
+    body['blueprint_name'] = blueprint_name
     return client.create(scope=scope,
                          blueprint_name=blueprint_name,
                          version_id=version_id,
@@ -479,9 +480,14 @@ def list_blueprint_version_artifact(cmd, client, blueprint_name,
                        version_id=version_id)
 
 
-def _del_artifact_name(rg):
-    del rg['artifact_name']
-    return rg
+def resource_group_list_2_dict(resource_groups):
+    result = {}
+    if resource_groups is not None:
+        for rg in resource_groups:
+            key = rg['artifact_name']
+            del rg['artifact_name']
+            result[key] = rg
+    return result
 
 
 def create_blueprint_assignment(cmd,
@@ -523,7 +529,8 @@ def create_blueprint_assignment(cmd,
     body['description'] = description  # str
     body['blueprint_id'] = blueprint_id  # str
     body['parameters'] = parameters  # dictionary
-    body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups} if resource_groups is not None else {}
+    body['resource_groups'] = resource_group_list_2_dict(resource_groups)  # dictionary
+
     body.setdefault('locks', {})['mode'] = locks_mode  # str
     body.setdefault('locks', {})['excluded_principals'] = locks_excluded_principals
 
@@ -591,7 +598,7 @@ def update_blueprint_assignment(cmd,
     if parameters is not None:
         body['parameters'] = parameters  # dictionary
     if resource_groups is not None:
-        body['resource_groups'] = {rg['artifact_name']: _del_artifact_name(rg) for rg in resource_groups}  # dictionary
+        body['resource_groups'] = resource_group_list_2_dict(resource_groups)  # dictionary
     if locks_mode is not None:
         body.setdefault('locks', {})['mode'] = locks_mode  # str
     if locks_excluded_principals is not None:
diff --git a/src/blueprint/setup.py b/src/blueprint/setup.py
--- a/src/blueprint/setup.py
+++ b/src/blueprint/setup.py
@@ -16,7 +16,7 @@
 
 # TODO: Confirm this is the right version number you want and it matches your
 # HISTORY.rst entry.
-VERSION = '0.1.0'
+VERSION = '0.1.1'
 
 # The full list of classifiers is available at
 # https://pypi.python.org/pypi?%3Aaction=list_classifiers


Test patch: