Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/azure-cli/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Release History

**Compute**

* `az vm boot-diagnostics get-boot-log`: Fix `TypeError: 'method' object is not subscriptable` with azure-mgmt-storage 25.0.0 (#33727)
* `az vm create/update/show`: Support scheduled events profile via new parameters `--scheduled-events-api-version` and `--enable-all-instance-down` (#33451)
* `az vmss create/update/show`: Support scheduled events profile via new parameters `--scheduled-events-api-version` and `--enable-all-instance-down` (#33451)
* `az availability-set create/show`: Support scheduled events profile via new parameters `--scheduled-events-api-version` and `--enable-all-instance-down` (#33451)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def _get_storage_account_key(cli_ctx, account_name, account_key):
raise CLIError('Cannot find "{0}" storage account.'.format(account_name))
resource_group = parse_resource_id(account[0])['resource_group']
keys_list_result = storage_client.storage_accounts.list_keys(resource_group, account_name)
if not keys_list_result or not keys_list_result.keys:
if not keys_list_result or not keys_list_result.keys_property:
raise CLIError('Cannot find a key for "{0}" storage account.'.format(account_name))
key_value = None
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _get_mock_storage_accounts_and_keys(accounts_and_keys):
'/subscriptions/000/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/{0}'.format(a),
a, Endpoints('https://{0}.file.core.windows.net/'.format(a)))
for a in accounts_and_keys.keys()])
Keys = collections.namedtuple('Keys', 'keys')
Keys = collections.namedtuple('Keys', 'keys_property')
Key = collections.namedtuple('Key', 'value')
mock_storage_client.storage_accounts.list_keys = MagicMock(
side_effect=lambda _, account: Keys([Key(accounts_and_keys.get(account, None))]))
Expand Down
4 changes: 2 additions & 2 deletions src/azure-cli/azure/cli/command_modules/vm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def _get_disk_lun_by_aaz(data_disks):
def _get_private_config(cli_ctx, resource_group_name, storage_account):
storage_mgmt_client = _get_storage_management_client(cli_ctx)
# pylint: disable=no-member
keys = storage_mgmt_client.storage_accounts.list_keys(resource_group_name, storage_account).keys
keys = storage_mgmt_client.storage_accounts.list_keys(resource_group_name, storage_account).keys_property

private_config = {
'storageAccountName': storage_account,
Expand Down Expand Up @@ -2300,7 +2300,7 @@ def get_boot_log(cmd, resource_group_name, vm_name):
# Get account key
keys = storage_mgmt_client.storage_accounts.list_keys(rg, storage_account.name)

blob_client = BlobClient.from_blob_url(blob_url=blob_uri, credential=keys.keys[0].value)
blob_client = BlobClient.from_blob_url(blob_url=blob_uri, credential=keys.keys_property[0].value)

# our streamwriter not seekable, so no parallel.
downloader = blob_client.download_blob(max_concurrency=1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,60 @@ class ErrorToExitCommandEarly(Exception):
except ErrorToExitCommandEarly:
get_sdk_mock.assert_called_with(cli_ctx_mock, ResourceType.DATA_STORAGE_BLOB, '_blob_client#BlobClient')

@mock.patch('azure.cli.command_modules.vm.custom._get_storage_management_client')
@mock.patch('azure.cli.command_modules.vm.custom.get_instance_view')
@mock.patch('azure.cli.core.profiles.get_sdk', autospec=True)
def test_vm_boot_log_uses_keys_property(self, get_sdk_mock, get_instance_view_mock,
get_storage_management_client_mock):
"""Verify get_boot_log uses keys_property (not .keys) for azure-mgmt-storage >= 25.0.0."""
blob_uri = 'https://mystorage.blob.core.windows.net/bootdiagnostics/vm1/serial.log'

# VM with instanceView providing a blob URI (custom/non-managed storage path)
get_instance_view_mock.return_value = {
'instanceView': {
'bootDiagnostics': {
'serialConsoleLogBlobUri': blob_uri
}
}
}

# Storage account that matches the blob URI
storage_account_mock = mock.MagicMock()
storage_account_mock.primary_endpoints.blob = 'https://mystorage.blob.core.windows.net/'
storage_account_mock.id = '/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Storage/storageAccounts/mystorage'
storage_account_mock.name = 'mystorage'

storage_mgmt_mock = mock.MagicMock()
storage_mgmt_mock.storage_accounts.list.return_value = [storage_account_mock]

# Simulate azure-mgmt-storage >= 25.0.0: keys_property holds the list of keys
key_mock = mock.MagicMock()
key_mock.value = 'fakeaccountkey=='
keys_result_mock = mock.MagicMock(spec=[])
keys_result_mock.keys_property = [key_mock]
storage_mgmt_mock.storage_accounts.list_keys.return_value = keys_result_mock

get_storage_management_client_mock.return_value = storage_mgmt_mock

# BlobClient mock
blob_client_cls_mock = mock.MagicMock()
blob_client_mock = mock.MagicMock()
blob_client_cls_mock.from_blob_url.return_value = blob_client_mock
downloader_mock = mock.MagicMock()
blob_client_mock.download_blob.return_value = downloader_mock
get_sdk_mock.return_value = blob_client_cls_mock

cmd_mock = mock.MagicMock()
cli_ctx_mock = mock.MagicMock()
cmd_mock.cli_ctx = cli_ctx_mock

get_boot_log(cmd_mock, 'rg1', 'vm1')

# Verify from_blob_url was called with credential from keys_property[0].value
blob_client_cls_mock.from_blob_url.assert_called_once_with(
blob_url=blob_uri, credential='fakeaccountkey=='
)


class FakedVM: # pylint: disable=too-few-public-methods
def __init__(self, nics=None, disks=None, os_disk=None):
Expand Down
Loading