Repository: Azure/azure-cli

Issue:
[Lock] az create lock Fails
### Description
Creating locks fails with:
```
az lock create: error: 'Namespace' object has no attribute 'get'
```

---

### Environment summary

**Install Method:** How did you install the CLI? (e.g. pip, interactive script, apt-get, Docker, MSI, nightly)  
Answer here: `pip3`

**CLI Version:** What version of the CLI and modules are installed? (Use `az --version`)  
Answer here:
```
azure-cli (2.0.6)

acr (2.0.4)
acs (2.0.6)
appservice (0.1.6)
batch (2.0.4)
cdn (0.0.2)
cloud (2.0.2)
cognitiveservices (0.1.2)
command-modules-nspkg (2.0.0)
component (2.0.4)
configure (2.0.6)
core (2.0.6)
cosmosdb (0.1.6)
dla (0.0.6)
dls (0.0.6)
feedback (2.0.2)
find (0.2.2)
interactive (0.3.1)
iot (0.1.5)
keyvault (2.0.4)
lab (0.0.4)
monitor (0.0.4)
network (2.0.6)
nspkg (3.0.0)
profile (2.0.4)
rdbms (0.0.1)
redis (0.2.3)
resource (2.0.6)
role (2.0.4)
sf (1.0.1)
sql (2.0.3)
storage (2.0.6)
vm (2.0.6)

Python (Linux) 3.6.1 (default, Mar 27 2017, 00:27:06)
[GCC 6.3.1 20170306] 
```

**OS Version:** What OS and version are you using?  
Answer here: Arch Linux, kernel 4.10.8. But was tested in Ubuntu 17.04 container and it also fails.

**Shell Type:** What shell are you using? (e.g. bash, cmd.exe, Bash on Windows)  
Answer here: `bash` and `nash`. Both fails.



Discussion:
brendandburns: @tjprescott fixed (test fixed too)
tjprescott: ```
/home/travis/build/Azure/azure-cli/src/command_modules/azure-cli-resource/tests/test_resource_validators.py:20:1: E302 expected 2 blank lines, found 1
2     E302 expected 2 blank lines, found 1
```

Have I mentioned I hate PEP8?
yugangw-msft: @brendandburns, please add a functional test, say a VCR scenario test, to verify simple "az lock create/read/delete" command work.
brendandburns: VCR test added, please take another look...
codecov-io: # [Codecov](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=h1) Report
> Merging [#3409](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=desc) into [master](https://codecov.io/gh/Azure/azure-cli/commit/7c10cae4442c3d64d5570fe4dcdf96c47dd1531a?src=pr&el=desc) will **increase** coverage by `0.18%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/azure-cli/pull/3409/graphs/tree.svg?width=650&src=pr&token=2pog0TKvF8&height=150)](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #3409      +/-   ##
==========================================
+ Coverage   70.73%   70.92%   +0.18%     
==========================================
  Files         394      394              
  Lines       25534    25534              
  Branches     3889     3889              
==========================================
+ Hits        18062    18110      +48     
+ Misses       6337     6279      -58     
- Partials     1135     1145      +10
```


| [Impacted Files](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [.../azure/cli/command\_modules/resource/\_validators.py](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree#diff-c3JjL2NvbW1hbmRfbW9kdWxlcy9henVyZS1jbGktcmVzb3VyY2UvYXp1cmUvY2xpL2NvbW1hbmRfbW9kdWxlcy9yZXNvdXJjZS9fdmFsaWRhdG9ycy5weQ==) | `69.56% <100%> (ø)` | :arrow_up: |
| [...nent/azure/cli/command\_modules/component/custom.py](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree#diff-c3JjL2NvbW1hbmRfbW9kdWxlcy9henVyZS1jbGktY29tcG9uZW50L2F6dXJlL2NsaS9jb21tYW5kX21vZHVsZXMvY29tcG9uZW50L2N1c3RvbS5weQ==) | `16.23% <0%> (ø)` | :arrow_up: |
| [...dback/azure/cli/command\_modules/feedback/custom.py](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree#diff-c3JjL2NvbW1hbmRfbW9kdWxlcy9henVyZS1jbGktZmVlZGJhY2svYXp1cmUvY2xpL2NvbW1hbmRfbW9kdWxlcy9mZWVkYmFjay9jdXN0b20ucHk=) | `34.69% <0%> (ø)` | :arrow_up: |
| [src/azure-cli-core/azure/cli/core/util.py](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree#diff-c3JjL2F6dXJlLWNsaS1jb3JlL2F6dXJlL2NsaS9jb3JlL3V0aWwucHk=) | `68.61% <0%> (ø)` | :arrow_up: |
| [...re/cli/command\_modules/resource/\_client\_factory.py](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree#diff-c3JjL2NvbW1hbmRfbW9kdWxlcy9henVyZS1jbGktcmVzb3VyY2UvYXp1cmUvY2xpL2NvbW1hbmRfbW9kdWxlcy9yZXNvdXJjZS9fY2xpZW50X2ZhY3RvcnkucHk=) | `88.46% <0%> (+5.76%)` | :arrow_up: |
| [...ource/azure/cli/command\_modules/resource/custom.py](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=tree#diff-c3JjL2NvbW1hbmRfbW9kdWxlcy9henVyZS1jbGktcmVzb3VyY2UvYXp1cmUvY2xpL2NvbW1hbmRfbW9kdWxlcy9yZXNvdXJjZS9jdXN0b20ucHk=) | `61.64% <0%> (+7.53%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=footer). Last update [7c10cae...abc205c](https://codecov.io/gh/Azure/azure-cli/pull/3409?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

brendandburns: Comments (mostly) addressed, please take another look.

Patch:
diff --git a/src/azure-cli/setup.py b/src/azure-cli/setup.py
index 331db8c41..6a59bb8be 100644
--- a/src/azure-cli/setup.py
+++ b/src/azure-cli/setup.py
@@ -54,11 +54,13 @@ DEPENDENCIES = [
     'azure-cli-acs',
     'azure-cli-appservice',
     'azure-cli-batch',
+    'azure-cli-billing',
     'azure-cli-cdn',
     'azure-cli-cloud',
     'azure-cli-cognitiveservices',
     'azure-cli-component',
     'azure-cli-configure',
+    'azure-cli-consumption',
     'azure-cli-core',
     'azure-cli-dla',
     'azure-cli-dls',
diff --git a/src/command_modules/azure-cli-resource/azure/cli/command_modules/resource/_validators.py b/src/command_modules/azure-cli-resource/azure/cli/command_modules/resource/_validators.py
index f2436813e..4348e2b7b 100644
--- a/src/command_modules/azure-cli-resource/azure/cli/command_modules/resource/_validators.py
+++ b/src/command_modules/azure-cli-resource/azure/cli/command_modules/resource/_validators.py
@@ -64,8 +64,8 @@ def internal_validate_lock_parameters(resource_group_name, resource_provider_nam
 
 
 def validate_lock_parameters(namespace):
-    internal_validate_lock_parameters(namespace.get('resource_group_name', None),
-                                      namespace.get('resource_provider_namespace', None),
-                                      namespace.get('parent_resource_path', None),
-                                      namespace.get('resource_type', None),
-                                      namespace.get('resource_name', None))
+    internal_validate_lock_parameters(getattr(namespace, 'resource_group_name', None),
+                                      getattr(namespace, 'resource_provider_namespace', None),
+                                      getattr(namespace, 'parent_resource_path', None),
+                                      getattr(namespace, 'resource_type', None),
+                                      getattr(namespace, 'resource_name', None))
diff --git a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py
index f92f94630..39896c05e 100644
--- a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py
+++ b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py
@@ -292,7 +292,9 @@ def create_managed_disk(resource_group_name, disk_name, location=None,
                         # below are generated internally from 'source'
                         source_blob_uri=None, source_disk=None, source_snapshot=None,
                         source_storage_account_id=None, no_wait=False, tags=None):
-    from azure.mgmt.compute.models import Disk, CreationData, DiskCreateOption
+    Disk, CreationData, DiskCreateOption = get_sdk(ResourceType.MGMT_COMPUTE, 'Disk', 'CreationData',
+                                                   'DiskCreateOption', mod='models')
+
     location = location or get_resource_group_location(resource_group_name)
     if source_blob_uri:
         option = DiskCreateOption.import_enum
@@ -402,7 +404,8 @@ def create_snapshot(resource_group_name, snapshot_name, location=None, size_gb=N
                     # below are generated internally from 'source'
                     source_blob_uri=None, source_disk=None, source_snapshot=None, source_storage_account_id=None,
                     tags=None):
-    from azure.mgmt.compute.models import Snapshot, CreationData, DiskCreateOption
+    Snapshot, CreationData, DiskCreateOption = get_sdk(ResourceType.MGMT_COMPUTE, 'Snapshot', 'CreationData',
+                                                       'DiskCreateOption', mod='models')
 
     location = location or get_resource_group_location(resource_group_name)
     if source_blob_uri:
@@ -474,8 +477,10 @@ def create_image(resource_group_name, name, os_type=None, location=None,  # pyli
                  os_blob_uri=None, data_blob_uris=None,
                  os_snapshot=None, data_snapshots=None,
                  os_disk=None, data_disks=None, tags=None):
-    from azure.mgmt.compute.models import (ImageOSDisk, ImageDataDisk, ImageStorageProfile, Image, SubResource,
-                                           OperatingSystemStateTypes)
+    ImageOSDisk, ImageDataDisk, ImageStorageProfile, Image, SubResource, OperatingSystemStateTypes = get_sdk(
+        ResourceType.MGMT_COMPUTE, 'ImageOSDisk', 'ImageDataDisk', 'ImageStorageProfile', 'Image', 'SubResource',
+        'OperatingSystemStateTypes', mod='models')
+
     # pylint: disable=line-too-long
     if source_virtual_machine:
         location = location or get_resource_group_location(resource_group_name)


Test patch:
diff --git a/src/command_modules/azure-cli-resource/tests/recordings/test_list_locks.yaml b/src/command_modules/azure-cli-resource/tests/recordings/test_list_locks.yaml
new file mode 100644
index 000000000..b43592289
--- /dev/null
+++ b/src/command_modules/azure-cli-resource/tests/recordings/test_list_locks.yaml
@@ -0,0 +1,28 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock list]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['12']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:27:30 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/src/command_modules/azure-cli-resource/tests/recordings/test_lock_create_list_delete.yaml b/src/command_modules/azure-cli-resource/tests/recordings/test_lock_create_list_delete.yaml
new file mode 100644
index 000000000..60cb34dd2
--- /dev/null
+++ b/src/command_modules/azure-cli-resource/tests/recordings/test_lock_create_list_delete.yaml
@@ -0,0 +1,260 @@
+interactions:
+- request:
+    body: '{"name": "foo", "properties": {"level": "ReadOnly"}}'
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock create]
+      Connection: [keep-alive]
+      Content-Length: ['52']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: PUT
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['190']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:22 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1198']
+    status: {code: 201, message: Created}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock list]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['202']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:23 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock show]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['190']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:23 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['202']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:24 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Length: ['0']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: DELETE
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: ''}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['0']
+      date: ['Fri, 19 May 2017 23:38:25 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1198']
+    status: {code: 200, message: OK}
+- request:
+    body: '{"name": "foo", "properties": {"level": "CanNotDelete"}}'
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock create]
+      Connection: [keep-alive]
+      Content-Length: ['56']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: PUT
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['194']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:26 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1198']
+    status: {code: 201, message: Created}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock list]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['206']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:27 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock show]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['194']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:28 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['206']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:38:30 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Length: ['0']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: DELETE
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: ''}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['0']
+      date: ['Fri, 19 May 2017 23:38:30 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1196']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/src/command_modules/azure-cli-resource/tests/recordings/test_lock_create_list_delete_resource_group.yaml b/src/command_modules/azure-cli-resource/tests/recordings/test_lock_create_list_delete_resource_group.yaml
new file mode 100644
index 000000000..d3cd445b4
--- /dev/null
+++ b/src/command_modules/azure-cli-resource/tests/recordings/test_lock_create_list_delete_resource_group.yaml
@@ -0,0 +1,315 @@
+interactions:
+- request:
+    body: '{"tags": {"use": "az-test"}, "location": "westus"}'
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [group create]
+      Connection: [keep-alive]
+      Content-Length: ['50']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 resourcemanagementclient/1.1.0rc1 Azure-SDK-For-Python
+          AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: PUT
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10
+  response:
+    body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001","name":"clitest.rg000001","location":"westus","tags":{"use":"az-test"},"properties":{"provisioningState":"Succeeded"}}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['328']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:42:41 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1187']
+    status: {code: 201, message: Created}
+- request:
+    body: '{"properties": {"level": "ReadOnly"}, "name": "foo"}'
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock create]
+      Connection: [keep-alive]
+      Content-Length: ['52']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: PUT
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['281']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:42:43 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1189']
+    status: {code: 201, message: Created}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock list]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg6hms5bk4lei5ddclway74mxxuyl46kfsfuygwco5al3eh7ousyhogw676rbllwli3/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"},{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['575']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:42:46 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock show]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['281']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:42:53 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg6hms5bk4lei5ddclway74mxxuyl46kfsfuygwco5al3eh7ousyhogw676rbllwli3/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"},{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['575']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:43:05 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Length: ['0']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: DELETE
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: ''}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['0']
+      date: ['Fri, 19 May 2017 23:43:07 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1198']
+    status: {code: 200, message: OK}
+- request:
+    body: '{"properties": {"level": "CanNotDelete"}, "name": "foo"}'
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock create]
+      Connection: [keep-alive]
+      Content-Length: ['56']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: PUT
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['285']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:43:08 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1198']
+    status: {code: 201, message: Created}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock list]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg6hms5bk4lei5ddclway74mxxuyl46kfsfuygwco5al3eh7ousyhogw676rbllwli3/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"},{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['579']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:43:09 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock show]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: '{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['285']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:43:11 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/locks?api-version=2016-09-01
+  response:
+    body: {string: '{"value":[{"properties":{"level":"ReadOnly"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg6hms5bk4lei5ddclway74mxxuyl46kfsfuygwco5al3eh7ousyhogw676rbllwli3/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"},{"properties":{"level":"CanNotDelete"},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo","type":"Microsoft.Authorization/locks","name":"foo"}]}'}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['579']
+      content-type: [application/json; charset=utf-8]
+      date: ['Fri, 19 May 2017 23:43:12 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      transfer-encoding: [chunked]
+      vary: ['Accept-Encoding,Accept-Encoding']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [lock delete]
+      Connection: [keep-alive]
+      Content-Length: ['0']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 managementlockclient/1.1.0rc1 Azure-SDK-For-Python AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: DELETE
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Authorization/locks/foo?api-version=2016-09-01
+  response:
+    body: {string: ''}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['0']
+      date: ['Fri, 19 May 2017 23:43:13 GMT']
+      expires: ['-1']
+      pragma: [no-cache]
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1188']
+    status: {code: 200, message: OK}
+- request:
+    body: null
+    headers:
+      Accept: [application/json]
+      Accept-Encoding: ['gzip, deflate']
+      CommandName: [group delete]
+      Connection: [keep-alive]
+      Content-Length: ['0']
+      Content-Type: [application/json; charset=utf-8]
+      User-Agent: [python/3.5.3 (Windows-10-10.0.15063-SP0) requests/2.9.1 msrest/0.4.7
+          msrest_azure/0.4.7 resourcemanagementclient/1.1.0rc1 Azure-SDK-For-Python
+          AZURECLI/2.0.6+dev]
+      accept-language: [en-US]
+    method: DELETE
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10
+  response:
+    body: {string: ''}
+    headers:
+      cache-control: [no-cache]
+      content-length: ['0']
+      date: ['Fri, 19 May 2017 23:43:15 GMT']
+      expires: ['-1']
+      location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkdORlVXV05FUE4zVlQzRkJDSlc1UUwzQUVMTFE3Mk1TQ1JXQnwxMEFGMEY1QzVBMjE5M0FCLVdFU1RVUyIsImpvYkxvY2F0aW9uIjoid2VzdHVzIn0?api-version=2017-05-10']
+      pragma: [no-cache]
+      retry-after: ['15']
+      strict-transport-security: [max-age=31536000; includeSubDomains]
+      x-ms-ratelimit-remaining-subscription-writes: ['1196']
+    status: {code: 202, message: Accepted}
+version: 1
diff --git a/src/command_modules/azure-cli-resource/tests/test_locks.py b/src/command_modules/azure-cli-resource/tests/test_locks.py
new file mode 100644
index 000000000..fdee87239
--- /dev/null
+++ b/src/command_modules/azure-cli-resource/tests/test_locks.py
@@ -0,0 +1,45 @@
+# --------------------------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for license information.
+# --------------------------------------------------------------------------------------------
+
+import unittest
+
+from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer
+
+
+class ResourceLockTests(ScenarioTest):
+    def test_list_locks(self):
+        # just make sure this doesn't throw
+        self.cmd('az lock list').get_output_in_json()
+
+    # Test for subscription level locks
+    def test_lock_create_list_delete(self):
+        for lock_type in ['ReadOnly', 'CanNotDelete']:
+            self.cmd('az lock create -n foo --lock-type {}'.format(lock_type))
+            locks_list = self.cmd('az lock list').get_output_in_json()
+            assert len(locks_list) > 0
+            assert 'foo' in [l['name'] for l in locks_list]
+            lock = self.cmd('az lock show -n foo').get_output_in_json()
+            self.assertEqual(lock.get('name', None), 'foo')
+            self.assertEqual(lock.get('level', None), lock_type)
+            self.cmd('az lock delete -n foo')
+
+    # Test for resource group level locks
+    @ResourceGroupPreparer()
+    def test_lock_create_list_delete_resource_group(self, resource_group):
+        for lock_type in ['ReadOnly', 'CanNotDelete']:
+            self.cmd('az lock create -n foo -g {} --lock-type {}'.format(resource_group, lock_type))
+            locks_list = self.cmd('az lock list').get_output_in_json()
+            assert 'foo' in [l['name'] for l in locks_list]
+            assert len(locks_list) > 0
+            lock = self.cmd('az lock show -g {} -n foo'.format(resource_group)).get_output_in_json()
+            self.assertEqual(lock.get('name', None), 'foo')
+            self.assertEqual(lock.get('level', None), lock_type)
+            self.cmd('az lock delete -g {} -n foo'.format(resource_group))
+
+    # TODO: test for resource group level locks
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/command_modules/azure-cli-resource/tests/test_resource_validators.py b/src/command_modules/azure-cli-resource/tests/test_resource_validators.py
index ca533fd35..eea7b941b 100644
--- a/src/command_modules/azure-cli-resource/tests/test_resource_validators.py
+++ b/src/command_modules/azure-cli-resource/tests/test_resource_validators.py
@@ -4,8 +4,8 @@
 # --------------------------------------------------------------------------------------------
 
 import unittest
-import mock
 import os.path
+import mock
 from six import StringIO
 
 from azure.cli.core.util import CLIError
@@ -15,6 +15,10 @@ from azure.cli.command_modules.resource._validators import (
 )
 
 
+class NamespaceObject:
+    pass
+
+
 class Test_resource_validators(unittest.TestCase):
     def setUp(self):
         self.io = StringIO()
@@ -59,9 +63,12 @@ class Test_resource_validators(unittest.TestCase):
             }
         ]
         for valid_namespace in valid:
+            namespace_obj = NamespaceObject()
+            for key in valid_namespace:
+                setattr(namespace_obj, key, valid_namespace[key])
             try:
                 # If unexpected invalid, this throws, so no need for asserts
-                validate_lock_parameters(valid_namespace)
+                validate_lock_parameters(namespace_obj)
             except CLIError as ex:
                 self.fail('Test {} failed. {}'.format(valid_namespace['test'], ex))
 
@@ -102,7 +109,10 @@ class Test_resource_validators(unittest.TestCase):
         ]
         for invalid_namespace in invalid:
             with self.assertRaises(CLIError):
-                validate_lock_parameters(invalid_namespace)
+                namespace_obj = NamespaceObject()
+                for key in invalid_namespace:
+                    setattr(namespace_obj, key, invalid_namespace[key])
+                validate_lock_parameters(namespace_obj)
 
     def test_generate_deployment_name_from_file(self):
         # verify auto-gen from uri