From b07882a1780caa7642f6f08c75b92cfba0004e06 Mon Sep 17 00:00:00 2001 From: gossion Date: Fri, 30 Jun 2017 07:41:09 +0000 Subject: [PATCH] Support multiple resource group for VM resources --- ci/pipeline.yml | 54 +- ci/tasks/azure-provision.sh | 24 +- ci/tasks/azure-provision.yml | 12 +- ci/tasks/reset-resources.sh | 30 +- ci/tasks/reset-resources.yml | 12 +- ci/tasks/run-bats.sh | 1 + ci/tasks/run-lifecycle.sh | 14 +- ci/tasks/run-lifecycle.yml | 4 +- ci/tasks/setup-director.sh | 14 +- ci/tasks/setup-director.yml | 4 +- src/bosh_azure_cpi/lib/cloud/azure.rb | 3 + .../lib/cloud/azure/azure_client2.rb | 242 +++++--- src/bosh_azure_cpi/lib/cloud/azure/cloud.rb | 126 ++-- src/bosh_azure_cpi/lib/cloud/azure/disk_id.rb | 137 +++++ .../lib/cloud/azure/disk_manager.rb | 157 ++--- .../lib/cloud/azure/disk_manager2.rb | 119 ++-- src/bosh_azure_cpi/lib/cloud/azure/helpers.rb | 18 +- .../lib/cloud/azure/instance_id.rb | 114 ++++ .../cloud/azure/storage_account_manager.rb | 2 +- .../lib/cloud/azure/vm_manager.rb | 230 ++++---- .../spec/integration/azure_cpi_spec.rb | 4 +- .../spec/integration/lifecycle_spec.rb | 67 ++- .../managed_disks_migration_spec.rb | 13 +- .../resource_group_name/README.md | 22 + .../manual_tests/resource_group_name/cpi.cfg | 18 + .../resource_group_name/helpers.rb | 128 ++++ .../resource_group_name/migrate_to_new_rg.rb | 445 ++++++++++++++ .../manual_tests/resource_group_name/test.cfg | 10 + .../attach_disk_to_virtual_machine_spec.rb | 55 +- .../azure_client2/availability_set_spec.rb | 24 +- .../unit/azure_client2/azure_client2_spec.rb | 19 +- .../create_load_balancer_spec.rb | 2 +- .../create_network_interface_spec.rb | 6 +- .../azure_client2/create_public_ip_spec.rb | 8 +- .../create_resource_group_spec.rb | 76 +++ .../create_virtual_machine_spec.rb | 42 +- .../delete_load_balancer_spec.rb | 2 +- .../delete_network_interface_spec.rb | 6 +- .../azure_client2/delete_public_ip_spec.rb | 6 +- .../delete_virtual_machine_spec.rb | 38 +- .../detach_disk_from_virtual_machine_spec.rb | 81 ++- .../unit/azure_client2/get_operation_spec.rb | 136 ++++- .../unit/azure_client2/managed_disks_spec.rb | 12 +- .../unit/azure_client2/managed_images_spec.rb | 2 +- .../azure_client2/managed_snapshots_spec.rb | 8 +- .../restart_virtual_machine_spec.rb | 26 +- .../update_tags_of_virtual_machine_spec.rb | 82 ++- .../spec/unit/blob_manager_spec.rb | 22 +- .../spec/unit/cloud/attach_disk_spec.rb | 79 ++- .../spec/unit/cloud/create_disk_spec.rb | 64 +- .../spec/unit/cloud/create_vm_spec.rb | 151 +++-- .../spec/unit/cloud/delete_disk_spec.rb | 46 +- .../spec/unit/cloud/delete_snapshot_spec.rb | 24 +- .../spec/unit/cloud/delete_vm_spec.rb | 7 +- .../spec/unit/cloud/detach_disk_spec.rb | 15 +- .../spec/unit/cloud/get_disks_spec.rb | 19 +- .../spec/unit/cloud/has_disk_spec.rb | 31 +- .../spec/unit/cloud/has_vm_spec.rb | 13 +- .../spec/unit/cloud/reboot_vm_spec.rb | 9 +- .../spec/unit/cloud/set_vm_metadata_spec.rb | 11 +- .../spec/unit/cloud/snapshot_disk_spec.rb | 66 ++- src/bosh_azure_cpi/spec/unit/disk_id_spec.rb | 422 +++++++++++++ .../spec/unit/disk_manager2_spec.rb | 176 +++--- .../spec/unit/disk_manager_spec.rb | 209 ++++--- src/bosh_azure_cpi/spec/unit/helpers_spec.rb | 28 +- .../spec/unit/instance_id_spec.rb | 362 ++++++++++++ .../spec/unit/light_stemcell_manager_spec.rb | 4 +- .../spec/unit/stemcell_manager2_spec.rb | 2 +- .../spec/unit/stemcell_manager_spec.rb | 4 +- .../spec/unit/storage_account_manager_spec.rb | 27 +- .../spec/unit/vm_manager/attach_disk_spec.rb | 100 ++++ .../create_spec.rb} | 553 +++++------------- .../spec/unit/vm_manager/delete_spec.rb | 178 ++++++ .../spec/unit/vm_manager/detach_disk_spec.rb | 39 ++ .../spec/unit/vm_manager/find_spec.rb | 34 ++ .../spec/unit/vm_manager/reboot_spec.rb | 34 ++ .../spec/unit/vm_manager/set_metadata_spec.rb | 34 ++ 77 files changed, 4046 insertions(+), 1372 deletions(-) create mode 100644 src/bosh_azure_cpi/lib/cloud/azure/disk_id.rb create mode 100644 src/bosh_azure_cpi/lib/cloud/azure/instance_id.rb create mode 100644 src/bosh_azure_cpi/spec/manual_tests/resource_group_name/README.md create mode 100644 src/bosh_azure_cpi/spec/manual_tests/resource_group_name/cpi.cfg create mode 100644 src/bosh_azure_cpi/spec/manual_tests/resource_group_name/helpers.rb create mode 100644 src/bosh_azure_cpi/spec/manual_tests/resource_group_name/migrate_to_new_rg.rb create mode 100644 src/bosh_azure_cpi/spec/manual_tests/resource_group_name/test.cfg create mode 100644 src/bosh_azure_cpi/spec/unit/azure_client2/create_resource_group_spec.rb create mode 100644 src/bosh_azure_cpi/spec/unit/disk_id_spec.rb create mode 100644 src/bosh_azure_cpi/spec/unit/instance_id_spec.rb create mode 100644 src/bosh_azure_cpi/spec/unit/vm_manager/attach_disk_spec.rb rename src/bosh_azure_cpi/spec/unit/{vm_manager_spec.rb => vm_manager/create_spec.rb} (80%) create mode 100644 src/bosh_azure_cpi/spec/unit/vm_manager/delete_spec.rb create mode 100644 src/bosh_azure_cpi/spec/unit/vm_manager/detach_disk_spec.rb create mode 100644 src/bosh_azure_cpi/spec/unit/vm_manager/find_spec.rb create mode 100644 src/bosh_azure_cpi/spec/unit/vm_manager/reboot_spec.rb create mode 100644 src/bosh_azure_cpi/spec/unit/vm_manager/set_metadata_spec.rb diff --git a/ci/pipeline.yml b/ci/pipeline.yml index 006494491..8acc60620 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -23,12 +23,12 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network}} - AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS: {{azure_group_name_for_vms_managed_disks}} - AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS: {{azure_group_name_for_network_managed_disks}} - AZURE_GROUP_NAME_FOR_VMS_CENTOS: {{azure_group_name_for_vms_centos}} - AZURE_GROUP_NAME_FOR_NETWORK_CENTOS: {{azure_group_name_for_network_centos}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name}} + AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS: {{azure_default_group_name_managed_disks}} + AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS: {{azure_additional_group_name_managed_disks}} + AZURE_DEFAULT_GROUP_NAME_CENTOS: {{azure_default_group_name_centos}} + AZURE_ADDITIONAL_GROUP_NAME_CENTOS: {{azure_additional_group_name_centos}} AZURE_REGION_NAME: {{azure_region_name}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_VNET_NAME_FOR_LIFECYCLE: {{azure_vnet_name_for_lifecycle}} @@ -52,12 +52,12 @@ jobs: AZURE_TENANT_ID: {{azure_tenant_id}} AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network}} - AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS: {{azure_group_name_for_vms_managed_disks}} - AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS: {{azure_group_name_for_network_managed_disks}} - AZURE_GROUP_NAME_FOR_VMS_CENTOS: {{azure_group_name_for_vms_centos}} - AZURE_GROUP_NAME_FOR_NETWORK_CENTOS: {{azure_group_name_for_network_centos}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name}} + AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS: {{azure_default_group_name_managed_disks}} + AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS: {{azure_additional_group_name_managed_disks}} + AZURE_DEFAULT_GROUP_NAME_CENTOS: {{azure_default_group_name_centos}} + AZURE_ADDITIONAL_GROUP_NAME_CENTOS: {{azure_additional_group_name_centos}} AZURE_STORAGE_ACCOUNT_NAME: {{azure_storage_account_name}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_VNET_NAME_FOR_LIFECYCLE: {{azure_vnet_name_for_lifecycle}} @@ -97,8 +97,8 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name}} AZURE_STORAGE_ACCOUNT_NAME: {{azure_storage_account_name}} AZURE_VNET_NAME_FOR_LIFECYCLE: {{azure_vnet_name_for_lifecycle}} AZURE_BOSH_SUBNET_NAME: {{azure_bosh_subnet_name}} @@ -127,8 +127,8 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_STORAGE_ACCOUNT_NAME: {{azure_storage_account_name}} AZURE_BOSH_SUBNET_NAME: {{azure_bosh_subnet_name}} @@ -149,7 +149,7 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME: {{azure_group_name_for_network}} + AZURE_GROUP_NAME: {{azure_additional_group_name}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_CF_SUBNET_NAME: {{azure_cf_subnet_name}} AZURE_CF_SECOND_SUBNET_NAME: {{azure_cf_second_subnet_name}} @@ -192,10 +192,10 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms_managed_disks}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network_managed_disks}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name_managed_disks}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name_managed_disks}} AZURE_STORAGE_ACCOUNT_NAME: {{azure_storage_account_name_managed_disks}} AZURE_VNET_NAME_FOR_LIFECYCLE: {{azure_vnet_name_for_lifecycle}} AZURE_BOSH_SUBNET_NAME: {{azure_bosh_subnet_name}} @@ -224,8 +224,8 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms_managed_disks}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network_managed_disks}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name_managed_disks}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name_managed_disks}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_BOSH_SUBNET_NAME: {{azure_bosh_subnet_name}} AZURE_DEFAULT_SECURITY_GROUP: {{azure_default_security_group}} @@ -245,7 +245,7 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME: {{azure_group_name_for_network_managed_disks}} + AZURE_GROUP_NAME: {{azure_additional_group_name_managed_disks}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_CF_SUBNET_NAME: {{azure_cf_subnet_name}} AZURE_CF_SECOND_SUBNET_NAME: {{azure_cf_second_subnet_name}} @@ -293,8 +293,8 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME_FOR_VMS: {{azure_group_name_for_vms_centos}} - AZURE_GROUP_NAME_FOR_NETWORK: {{azure_group_name_for_network_centos}} + AZURE_DEFAULT_GROUP_NAME: {{azure_default_group_name_centos}} + AZURE_ADDITIONAL_GROUP_NAME: {{azure_additional_group_name_centos}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_BOSH_SUBNET_NAME: {{azure_bosh_subnet_name}} AZURE_DEFAULT_SECURITY_GROUP: {{azure_default_security_group}} @@ -312,7 +312,7 @@ jobs: AZURE_CLIENT_ID: {{azure_client_id}} AZURE_CLIENT_SECRET: {{azure_client_secret}} AZURE_TENANT_ID: {{azure_tenant_id}} - AZURE_GROUP_NAME: {{azure_group_name_for_network_centos}} + AZURE_GROUP_NAME: {{azure_additional_group_name_centos}} AZURE_VNET_NAME_FOR_BATS: {{azure_vnet_name_for_bats}} AZURE_CF_SUBNET_NAME: {{azure_cf_subnet_name}} AZURE_CF_SECOND_SUBNET_NAME: {{azure_cf_second_subnet_name}} diff --git a/ci/tasks/azure-provision.sh b/ci/tasks/azure-provision.sh index 88cfe13f1..562c4fee9 100755 --- a/ci/tasks/azure-provision.sh +++ b/ci/tasks/azure-provision.sh @@ -5,12 +5,12 @@ set -e : ${AZURE_CLIENT_ID:?} : ${AZURE_CLIENT_SECRET:?} : ${AZURE_TENANT_ID:?} -: ${AZURE_GROUP_NAME_FOR_VMS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK:?} -: ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS:?} -: ${AZURE_GROUP_NAME_FOR_VMS_CENTOS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS:?} +: ${AZURE_DEFAULT_GROUP_NAME:?} +: ${AZURE_ADDITIONAL_GROUP_NAME:?} +: ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS:?} +: ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS:?} +: ${AZURE_DEFAULT_GROUP_NAME_CENTOS:?} +: ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS:?} : ${AZURE_REGION_NAME:?} : ${AZURE_REGION_SHORT_NAME:?} : ${AZURE_STORAGE_ACCOUNT_NAME:?} @@ -27,7 +27,7 @@ azure config mode arm set +e -resource_group_names="${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_VMS_CENTOS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_DEFAULT_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_DEFAULT_GROUP_NAME_CENTOS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do # Check if the resource group already exists @@ -52,7 +52,7 @@ done set -e # Create the virtual networks, subnets, and the security groups -resource_group_names="${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_VMS_CENTOS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_DEFAULT_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_DEFAULT_GROUP_NAME_CENTOS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do echo azure group create ${resource_group_name} ${AZURE_REGION_SHORT_NAME} @@ -83,14 +83,14 @@ EOF done # Create the Public IPs -resource_group_names="${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_VMS_CENTOS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_DEFAULT_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_DEFAULT_GROUP_NAME_CENTOS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do echo azure network public-ip create --resource-group ${resource_group_name} --name AzureCPICI-cf-lifecycle --location ${AZURE_REGION_SHORT_NAME} --allocation-method Static azure network public-ip create --resource-group ${resource_group_name} --name AzureCPICI-cf-lifecycle --location ${AZURE_REGION_SHORT_NAME} --allocation-method Static done -resource_group_names="${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do echo azure network public-ip create --resource-group ${resource_group_name} --name AzureCPICI-bosh --location ${AZURE_REGION_SHORT_NAME} --allocation-method Static @@ -100,14 +100,14 @@ do done # Setup the storage account -resource_group_name="${AZURE_GROUP_NAME_FOR_VMS}" +resource_group_name="${AZURE_DEFAULT_GROUP_NAME}" storage_account_name="${AZURE_STORAGE_ACCOUNT_NAME}" azure storage account create --location ${AZURE_REGION_SHORT_NAME} --sku-name LRS --kind Storage --resource-group ${resource_group_name} ${storage_account_name} storage_account_key=$(azure storage account keys list ${storage_account_name} --resource-group ${resource_group_name} --json | jq '.[0].value' -r) azure storage container create --account-name ${storage_account_name} --account-key ${storage_account_key} --container bosh azure storage container create --account-name ${storage_account_name} --account-key ${storage_account_key} --permission blob --container stemcell -resource_group_name="${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS}" +resource_group_name="${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS}" storage_account_name="${AZURE_STORAGE_ACCOUNT_NAME_MANAGED_DISKS}" azure storage account create --location ${AZURE_REGION_SHORT_NAME} --sku-name LRS --kind Storage --resource-group ${resource_group_name} ${storage_account_name} storage_account_key=$(azure storage account keys list ${storage_account_name} --resource-group ${resource_group_name} --json | jq '.[0].value' -r) diff --git a/ci/tasks/azure-provision.yml b/ci/tasks/azure-provision.yml index c0969e44e..1fcafcb4f 100644 --- a/ci/tasks/azure-provision.yml +++ b/ci/tasks/azure-provision.yml @@ -14,12 +14,12 @@ params: AZURE_CLIENT_ID: "" AZURE_CLIENT_SECRET: "" AZURE_TENANT_ID: "" - AZURE_GROUP_NAME_FOR_VMS: "" - AZURE_GROUP_NAME_FOR_NETWORK: "" - AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS: "" - AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS: "" - AZURE_GROUP_NAME_FOR_VMS_CENTOS: "" - AZURE_GROUP_NAME_FOR_NETWORK_CENTOS: "" + AZURE_DEFAULT_GROUP_NAME: "" + AZURE_ADDITIONAL_GROUP_NAME: "" + AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS: "" + AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS: "" + AZURE_DEFAULT_GROUP_NAME_CENTOS: "" + AZURE_ADDITIONAL_GROUP_NAME_CENTOS: "" AZURE_REGION_NAME: "" AZURE_REGION_SHORT_NAME: "" AZURE_STORAGE_ACCOUNT_NAME: "" diff --git a/ci/tasks/reset-resources.sh b/ci/tasks/reset-resources.sh index a349f5a75..91f2bb976 100755 --- a/ci/tasks/reset-resources.sh +++ b/ci/tasks/reset-resources.sh @@ -10,12 +10,12 @@ function exit_if_error { : ${AZURE_TENANT_ID:?} : ${AZURE_CLIENT_ID:?} : ${AZURE_CLIENT_SECRET:?} -: ${AZURE_GROUP_NAME_FOR_VMS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK:?} -: ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS:?} -: ${AZURE_GROUP_NAME_FOR_VMS_CENTOS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS:?} +: ${AZURE_DEFAULT_GROUP_NAME:?} +: ${AZURE_ADDITIONAL_GROUP_NAME:?} +: ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS:?} +: ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS:?} +: ${AZURE_DEFAULT_GROUP_NAME_CENTOS:?} +: ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS:?} : ${AZURE_STORAGE_ACCOUNT_NAME:?} : ${AZURE_VNET_NAME_FOR_BATS:?} : ${AZURE_VNET_NAME_FOR_LIFECYCLE:?} @@ -29,7 +29,7 @@ azure config mode arm set +e -resource_group_names="${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_VMS_CENTOS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_DEFAULT_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_DEFAULT_GROUP_NAME_CENTOS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do echo "Check if the resource group exists" @@ -46,7 +46,7 @@ set -e echo "Check if the needed resources exist" -resource_group_names="${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_VMS_CENTOS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_DEFAULT_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_DEFAULT_GROUP_NAME_CENTOS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do vnets="${AZURE_VNET_NAME_FOR_BATS} ${AZURE_VNET_NAME_FOR_LIFECYCLE}" @@ -80,7 +80,7 @@ do fi done -resource_group_names="${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do public_ips="AzureCPICI-bosh AzureCPICI-cf-bats" @@ -97,30 +97,30 @@ done set +e -echo "azure storage account show --resource-group ${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_STORAGE_ACCOUNT_NAME}" -azure storage account show --resource-group ${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_STORAGE_ACCOUNT_NAME} +echo "azure storage account show --resource-group ${AZURE_DEFAULT_GROUP_NAME} ${AZURE_STORAGE_ACCOUNT_NAME}" +azure storage account show --resource-group ${AZURE_DEFAULT_GROUP_NAME} ${AZURE_STORAGE_ACCOUNT_NAME} if [ $? -eq 1 ]; then - echo "The task failed because the storage account ${AZURE_STORAGE_ACCOUNT_NAME} does not exist in resource group ${AZURE_GROUP_NAME_FOR_VMS}" + echo "The task failed because the storage account ${AZURE_STORAGE_ACCOUNT_NAME} does not exist in resource group ${AZURE_DEFAULT_GROUP_NAME}" exit_if_error fi set -e -AZURE_ACCOUNT_KEY=$(azure storage account keys list ${AZURE_STORAGE_ACCOUNT_NAME} --resource-group ${AZURE_GROUP_NAME_FOR_VMS} --json | jq '.[0].value' -r) +AZURE_ACCOUNT_KEY=$(azure storage account keys list ${AZURE_STORAGE_ACCOUNT_NAME} --resource-group ${AZURE_DEFAULT_GROUP_NAME} --json | jq '.[0].value' -r) containers="bosh stemcell" for container in ${containers} do container_actual=$(azure storage container show --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --account-key ${AZURE_ACCOUNT_KEY} --container ${container} --json | jq '.name' -r) if [ "${container_actual}" != "${container}" ]; then - echo "The task failed because the container ${container} does not exist in resource group ${AZURE_GROUP_NAME_FOR_VMS}" + echo "The task failed because the container ${container} does not exist in resource group ${AZURE_DEFAULT_GROUP_NAME}" exit_if_error fi done echo "Deleting the unneeded resources" -resource_group_names="${AZURE_GROUP_NAME_FOR_VMS} ${AZURE_GROUP_NAME_FOR_NETWORK} ${AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS} ${AZURE_GROUP_NAME_FOR_VMS_CENTOS} ${AZURE_GROUP_NAME_FOR_NETWORK_CENTOS}" +resource_group_names="${AZURE_DEFAULT_GROUP_NAME} ${AZURE_ADDITIONAL_GROUP_NAME} ${AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS} ${AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS} ${AZURE_DEFAULT_GROUP_NAME_CENTOS} ${AZURE_ADDITIONAL_GROUP_NAME_CENTOS}" for resource_group_name in ${resource_group_names} do vms=$(azure vm list --resource-group ${resource_group_name} --json | jq '.[].name' -r) diff --git a/ci/tasks/reset-resources.yml b/ci/tasks/reset-resources.yml index 36feaa1e0..7f39f0c8d 100644 --- a/ci/tasks/reset-resources.yml +++ b/ci/tasks/reset-resources.yml @@ -14,12 +14,12 @@ params: AZURE_TENANT_ID: "" AZURE_CLIENT_ID: "" AZURE_CLIENT_SECRET: "" - AZURE_GROUP_NAME_FOR_VMS: "" - AZURE_GROUP_NAME_FOR_NETWORK: "" - AZURE_GROUP_NAME_FOR_VMS_MANAGED_DISKS: "" - AZURE_GROUP_NAME_FOR_NETWORK_MANAGED_DISKS: "" - AZURE_GROUP_NAME_FOR_VMS_CENTOS: "" - AZURE_GROUP_NAME_FOR_NETWORK_CENTOS: "" + AZURE_DEFAULT_GROUP_NAME: "" + AZURE_ADDITIONAL_GROUP_NAME: "" + AZURE_DEFAULT_GROUP_NAME_MANAGED_DISKS: "" + AZURE_ADDITIONAL_GROUP_NAME_MANAGED_DISKS: "" + AZURE_DEFAULT_GROUP_NAME_CENTOS: "" + AZURE_ADDITIONAL_GROUP_NAME_CENTOS: "" AZURE_STORAGE_ACCOUNT_NAME: "" AZURE_VNET_NAME_FOR_BATS: "" AZURE_VNET_NAME_FOR_LIFECYCLE: "" diff --git a/ci/tasks/run-bats.sh b/ci/tasks/run-bats.sh index e609702b7..272c4d559 100755 --- a/ci/tasks/run-bats.sh +++ b/ci/tasks/run-bats.sh @@ -123,6 +123,7 @@ resource_pools: version: '<%= properties.stemcell.version %>' cloud_properties: instance_type: Standard_D3_v2 + resource_group_name: ${AZURE_GROUP_NAME} <% if properties.key_name %> key_name: <%= properties.key_name %> <% end %> diff --git a/ci/tasks/run-lifecycle.sh b/ci/tasks/run-lifecycle.sh index de5acc45a..6ff71ac35 100755 --- a/ci/tasks/run-lifecycle.sh +++ b/ci/tasks/run-lifecycle.sh @@ -7,8 +7,8 @@ set -e : ${AZURE_CLIENT_ID:?} : ${AZURE_CLIENT_SECRET:?} : ${AZURE_STORAGE_ACCOUNT_NAME:?} -: ${AZURE_GROUP_NAME_FOR_VMS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK:?} +: ${AZURE_DEFAULT_GROUP_NAME:?} +: ${AZURE_ADDITIONAL_GROUP_NAME:?} : ${AZURE_VNET_NAME_FOR_LIFECYCLE:?} : ${AZURE_BOSH_SUBNET_NAME:?} : ${AZURE_BOSH_SECOND_SUBNET_NAME:?} @@ -19,8 +19,8 @@ export BOSH_AZURE_SUBSCRIPTION_ID=${AZURE_SUBSCRIPTION_ID} export BOSH_AZURE_TENANT_ID=${AZURE_TENANT_ID} export BOSH_AZURE_CLIENT_ID=${AZURE_CLIENT_ID} export BOSH_AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET} -export BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_VMS=${AZURE_GROUP_NAME_FOR_VMS} -export BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_NETWORK=${AZURE_GROUP_NAME_FOR_NETWORK} +export BOSH_AZURE_DEFAULT_RESOURCE_GROUP_NAME=${AZURE_DEFAULT_GROUP_NAME} +export BOSH_AZURE_ADDITIONAL_RESOURCE_GROUP_NAME=${AZURE_ADDITIONAL_GROUP_NAME} export BOSH_AZURE_STORAGE_ACCOUNT_NAME=${AZURE_STORAGE_ACCOUNT_NAME} export BOSH_AZURE_VNET_NAME=${AZURE_VNET_NAME_FOR_LIFECYCLE} export BOSH_AZURE_SUBNET_NAME=${AZURE_BOSH_SUBNET_NAME} @@ -32,11 +32,11 @@ export BOSH_AZURE_STEMCELL_ID="bosh-stemcell-00000000-0000-0000-0000-0AZURECPICI azure login --service-principal -u ${AZURE_CLIENT_ID} -p ${AZURE_CLIENT_SECRET} --tenant ${AZURE_TENANT_ID} azure config mode arm -export BOSH_AZURE_PRIMARY_PUBLIC_IP=$(azure network public-ip show ${AZURE_GROUP_NAME_FOR_VMS} AzureCPICI-cf-lifecycle --json | jq '.ipAddress' -r) -export BOSH_AZURE_SECONDARY_PUBLIC_IP=$(azure network public-ip show ${AZURE_GROUP_NAME_FOR_NETWORK} AzureCPICI-cf-lifecycle --json | jq '.ipAddress' -r) +export BOSH_AZURE_PRIMARY_PUBLIC_IP=$(azure network public-ip show ${AZURE_DEFAULT_GROUP_NAME} AzureCPICI-cf-lifecycle --json | jq '.ipAddress' -r) +export BOSH_AZURE_SECONDARY_PUBLIC_IP=$(azure network public-ip show ${AZURE_ADDITIONAL_GROUP_NAME} AzureCPICI-cf-lifecycle --json | jq '.ipAddress' -r) export AZURE_STORAGE_ACCOUNT=${AZURE_STORAGE_ACCOUNT_NAME} -export AZURE_STORAGE_ACCESS_KEY=$(azure storage account keys list ${AZURE_STORAGE_ACCOUNT_NAME} -g ${AZURE_GROUP_NAME_FOR_VMS} --json | jq '.[0].value' -r) +export AZURE_STORAGE_ACCESS_KEY=$(azure storage account keys list ${AZURE_STORAGE_ACCOUNT_NAME} -g ${AZURE_DEFAULT_GROUP_NAME} --json | jq '.[0].value' -r) # Always upload the latest stemcell for lifecycle test tar -xf $(realpath stemcell/*.tgz) -C /mnt/ diff --git a/ci/tasks/run-lifecycle.yml b/ci/tasks/run-lifecycle.yml index c3372c85e..aec1a7640 100644 --- a/ci/tasks/run-lifecycle.yml +++ b/ci/tasks/run-lifecycle.yml @@ -16,8 +16,8 @@ params: AZURE_CLIENT_ID: "" AZURE_CLIENT_SECRET: "" AZURE_TENANT_ID: "" - AZURE_GROUP_NAME_FOR_VMS: "" - AZURE_GROUP_NAME_FOR_NETWORK: "" + AZURE_DEFAULT_GROUP_NAME: "" + AZURE_ADDITIONAL_GROUP_NAME: "" AZURE_STORAGE_ACCOUNT_NAME: "" AZURE_VNET_NAME_FOR_LIFECYCLE: "" AZURE_BOSH_SUBNET_NAME: "" diff --git a/ci/tasks/setup-director.sh b/ci/tasks/setup-director.sh index 5de3f96af..a6d58ed29 100755 --- a/ci/tasks/setup-director.sh +++ b/ci/tasks/setup-director.sh @@ -6,8 +6,8 @@ set -e : ${AZURE_CLIENT_ID:?} : ${AZURE_CLIENT_SECRET:?} : ${AZURE_TENANT_ID:?} -: ${AZURE_GROUP_NAME_FOR_VMS:?} -: ${AZURE_GROUP_NAME_FOR_NETWORK:?} +: ${AZURE_DEFAULT_GROUP_NAME:?} +: ${AZURE_ADDITIONAL_GROUP_NAME:?} : ${AZURE_VNET_NAME_FOR_BATS:?} : ${AZURE_BOSH_SUBNET_NAME:?} : ${AZURE_DEFAULT_SECURITY_GROUP:?} @@ -24,7 +24,7 @@ set -e azure login --service-principal -u ${AZURE_CLIENT_ID} -p ${AZURE_CLIENT_SECRET} --tenant ${AZURE_TENANT_ID} azure config mode arm -DIRECTOR_PIP=$(azure network public-ip show ${AZURE_GROUP_NAME_FOR_NETWORK} AzureCPICI-bosh --json | jq '.ipAddress' -r) +DIRECTOR_PIP=$(azure network public-ip show ${AZURE_ADDITIONAL_GROUP_NAME} AzureCPICI-bosh --json | jq '.ipAddress' -r) source /etc/profile.d/chruby.sh chruby ${RUBY_VERSION} @@ -78,7 +78,7 @@ networks: - name: public type: vip cloud_properties: - resource_group_name: ${AZURE_GROUP_NAME_FOR_NETWORK} + resource_group_name: ${AZURE_ADDITIONAL_GROUP_NAME} - name: private type: manual subnets: @@ -86,7 +86,7 @@ networks: gateway: 10.0.0.1 dns: [168.63.129.16] cloud_properties: - resource_group_name: ${AZURE_GROUP_NAME_FOR_NETWORK} + resource_group_name: ${AZURE_ADDITIONAL_GROUP_NAME} virtual_network_name: ${AZURE_VNET_NAME_FOR_BATS} subnet_name: ${AZURE_BOSH_SUBNET_NAME} @@ -96,7 +96,7 @@ resource_pools: stemcell: url: file://stemcell/stemcell.tgz cloud_properties: - instance_type: Standard_D1 + instance_type: Standard_D1_v2 disk_pools: - name: disks @@ -202,7 +202,7 @@ jobs: azure: &azure environment: AzureCloud subscription_id: ${AZURE_SUBSCRIPTION_ID} - resource_group_name: ${AZURE_GROUP_NAME_FOR_VMS} + resource_group_name: ${AZURE_DEFAULT_GROUP_NAME} tenant_id: ${AZURE_TENANT_ID} client_id: ${AZURE_CLIENT_ID} client_secret: ${AZURE_CLIENT_SECRET} diff --git a/ci/tasks/setup-director.yml b/ci/tasks/setup-director.yml index 5aeb59539..e106c2831 100644 --- a/ci/tasks/setup-director.yml +++ b/ci/tasks/setup-director.yml @@ -22,8 +22,8 @@ params: AZURE_CLIENT_ID: "" AZURE_CLIENT_SECRET: "" AZURE_TENANT_ID: "" - AZURE_GROUP_NAME_FOR_VMS: "" - AZURE_GROUP_NAME_FOR_NETWORK: "" + AZURE_DEFAULT_GROUP_NAME: "" + AZURE_ADDITIONAL_GROUP_NAME: "" AZURE_VNET_NAME_FOR_BATS: "" AZURE_STORAGE_ACCOUNT_NAME: "" AZURE_SUBSCRIPTION_ID: "" diff --git a/src/bosh_azure_cpi/lib/cloud/azure.rb b/src/bosh_azure_cpi/lib/cloud/azure.rb index cea18a674..1804082c9 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure.rb @@ -57,6 +57,9 @@ module AzureCloud; end require 'cloud/azure/stemcell_manager2' require 'cloud/azure/storage_account_manager' +require 'cloud/azure/instance_id' +require 'cloud/azure/disk_id' + module Bosh module Clouds Azure = Bosh::AzureCloud::Cloud diff --git a/src/bosh_azure_cpi/lib/cloud/azure/azure_client2.rb b/src/bosh_azure_cpi/lib/cloud/azure/azure_client2.rb index b3a3e157e..58acad765 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure/azure_client2.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure/azure_client2.rb @@ -102,17 +102,39 @@ def get_resource_by_id(url, params = {}) # Resource Groups - # Get the default resource group's information + # Create resource group # + # @param [String] resource_group_name - Name of resource group. + # @param [String] location - location of the resource group. + # + # @return [Boolean] + # + # @See https://docs.microsoft.com/en-us/rest/api/resources/resourcegroups#ResourceGroups_CreateOrUpdate + # + def create_resource_group(resource_group_name, location) + url = "/subscriptions/#{URI.escape(@azure_properties['subscription_id'])}" + url += "/resourceGroups/#{URI.escape(resource_group_name)}" + + resource_group = { + 'name' => resource_group_name, + 'location' => location + } + + http_put(url, resource_group) + end + + # Get resource group's information + # + # @param [String] resource_group_name - Name of resource group. # @return [Hash] # # @See https://docs.microsoft.com/en-us/rest/api/resources/resourcegroups#ResourceGroups_Get # - def get_resource_group() + def get_resource_group(resource_group_name) resource_group = nil url = "/subscriptions/#{URI.escape(@azure_properties['subscription_id'])}" - url += "/resourceGroups/#{URI.escape(@azure_properties['resource_group_name'])}" + url += "/resourceGroups/#{URI.escape(resource_group_name)}" result = get_resource_by_id(url) unless result.nil? @@ -132,9 +154,10 @@ def get_resource_group() # # ==== Attributes # - # @param [Hash] vm_params - Parameters for creating the virtual machine. - # @param [Array] network_interfaces - Network Interface Instances. network_interfaces[0] will be picked as the primary network and able to bind to public ip or load balancers. - # @param [Hash] availability_set - Availability set. + # @param [String] resource_group_name - Name of resource group. + # @param [Hash] vm_params - Parameters for creating the virtual machine. + # @param [Array] network_interfaces - Network Interface Instances. network_interfaces[0] will be picked as the primary network and able to bind to public ip or load balancers. + # @param [Hash] availability_set - Availability set. # # ==== vm_params # @@ -189,8 +212,8 @@ def get_resource_group() # # @See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-create-or-update # - def create_virtual_machine(vm_params, network_interfaces, availability_set = nil) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, name: vm_params[:name]) + def create_virtual_machine(resource_group_name, vm_params, network_interfaces, availability_set = nil) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, resource_group_name: resource_group_name, name: vm_params[:name]) os_profile = { 'customData' => vm_params[:custom_data], @@ -331,34 +354,39 @@ def create_virtual_machine(vm_params, network_interfaces, availability_set = nil end # Restart a virtual machine - # @param [String] name - Name of virtual machine. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of virtual machine. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-restart # - def restart_virtual_machine(name) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, name: name, others: 'restart') + def restart_virtual_machine(resource_group_name, name) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, resource_group_name: resource_group_name, name: name, others: 'restart') http_post(url) end # Set tags for a virtual machine - # @param [String] name - Name of virtual machine. - # @param [Hash] tags - tags key/value pairs. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of virtual machine. + # @param [Hash] tags - tags key/value pairs. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-create-or-update # - def update_tags_of_virtual_machine(name, tags) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, name: name) + def update_tags_of_virtual_machine(resource_group_name, name, tags) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, resource_group_name: resource_group_name, name: name) vm = get_resource_by_id(url) if vm.nil? - raise AzureNotFoundError, "update_tags_of_virtual_machine - cannot find the virtual machine by name `#{name}'" + raise AzureNotFoundError, "update_tags_of_virtual_machine - cannot find the virtual machine by name `#{name}' in resource group `#{resource_group_name}'" end vm = remove_resources_from_vm(vm) + # keep disk_id in tags if it exists + tags.merge!(vm['tags'].select{ |k, _| k.start_with?(DISK_ID_TAG_PREFIX)}) + vm['tags'] = tags http_put(url, vm) end @@ -367,8 +395,9 @@ def update_tags_of_virtual_machine(name, tags) # # ==== Attributes # - # @param [String] vm_name - Name of virtual machine. - # @param [Hash] disk_params - Parameters of disk. + # @param [String] resource_group_name - Name of resource group. + # @param [String] vm_name - Name of virtual machine. + # @param [Hash] disk_params - Parameters of disk. # # ==== disk_params # @@ -376,6 +405,7 @@ def update_tags_of_virtual_machine(name, tags) # * +:disk_name+ - String. Disk name. # * +:caching+ - String. Caching option: None, ReadOnly or ReadWrite. # * +:managed+ - Boolean. Needs to be true to attach disk to a managed disk VM. + # * +:disk_bosh_id - String. Disk id for BOSH # # When managed is true, below parameters are required # * +:disk_id+ - String. ID of a managed disk. @@ -388,13 +418,19 @@ def update_tags_of_virtual_machine(name, tags) # # @See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-create-or-update # - def attach_disk_to_virtual_machine(vm_name, disk_params) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, name: vm_name) + def attach_disk_to_virtual_machine(resource_group_name, vm_name, disk_params) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, resource_group_name: resource_group_name, name: vm_name) vm = get_resource_by_id(url) if vm.nil? - raise AzureNotFoundError, "attach_disk_to_virtual_machine - cannot find the virtual machine by name `#{vm_name}'" + raise AzureNotFoundError, "attach_disk_to_virtual_machine - cannot find the virtual machine by name `#{vm_name}' in resource group `#{resource_group_name}'" end + # Record disk_id in VM's tag, which will be used in cpi.get_disks(instance_id) + disk_id_tag = { + "#{DISK_ID_TAG_PREFIX}-#{disk_params[:disk_name]}" => disk_params[:disk_bosh_id] + } + vm['tags'].merge!(disk_id_tag) + vm = remove_resources_from_vm(vm) disk_info = DiskInfo.for(vm['properties']['hardwareProfile']['vmSize']) @@ -440,20 +476,24 @@ def attach_disk_to_virtual_machine(vm_name, disk_params) end # Detach a specified disk from a virtual machine - # @param [String] name - Name of virtual machine. - # @param [String] disk_name - Disk name. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of virtual machine. + # @param [String] disk_name - Disk name. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-create-or-update # - def detach_disk_from_virtual_machine(name, disk_name) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, name: name) + def detach_disk_from_virtual_machine(resource_group_name, name, disk_name) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, resource_group_name: resource_group_name, name: name) vm = get_resource_by_id(url) if vm.nil? - raise AzureNotFoundError, "detach_disk_from_virtual_machine - cannot find the virtual machine by name `#{name}'" + raise AzureNotFoundError, "detach_disk_from_virtual_machine - cannot find the virtual machine by name `#{name}' in resource group `#{resource_group_name}'" end + disk_id_tag = "#{DISK_ID_TAG_PREFIX}-#{disk_name}" + vm['tags'].delete(disk_id_tag) + vm = remove_resources_from_vm(vm) @logger.debug("detach_disk_from_virtual_machine - virtual machine:\n#{JSON.pretty_generate(vm)}") @@ -468,14 +508,15 @@ def detach_disk_from_virtual_machine(name, disk_name) end # Get a virtual machine's information - # @param [String] name - Name of virtual machine. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of virtual machine. # # @return [Hash] # # @See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-get # - def get_virtual_machine_by_name(name) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, name: name) + def get_virtual_machine_by_name(resource_group_name, name) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, resource_group_name: resource_group_name, name: name) get_virtual_machine(url) end @@ -534,6 +575,8 @@ def get_virtual_machine(url) disk[:managed_disk][:storage_account_type] = data_disk['managedDisk']['storageAccountType'] end + disk[:disk_bosh_id] = result['tags'].fetch("#{DISK_ID_TAG_PREFIX}-#{data_disk['name']}", data_disk['name']) + vm[:data_disks].push(disk) end @@ -551,15 +594,16 @@ def get_virtual_machine(url) end # Delete a virtual machine - # @param [String] name - Name of virtual machine. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of virtual machine. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-delete # - def delete_virtual_machine(name) - @logger.debug("delete_virtual_machine - trying to delete #{name}") - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, name: name) + def delete_virtual_machine(resource_group_name, name) + @logger.debug("delete_virtual_machine - trying to delete `#{name}' from resource group `#{resource_group_name}'") + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_VIRTUAL_MACHINES, resource_group_name: resource_group_name, name: name) http_delete(url) end @@ -569,7 +613,8 @@ def delete_virtual_machine(name) # # ==== Attributes # - # @param [Hash] params - Parameters for creating the availability set. + # @param [String] resource_group_name - Name of resource group. + # @param [Hash] params - Parameters for creating the availability set. # # ==== Params # @@ -585,8 +630,8 @@ def delete_virtual_machine(name) # # @See https://docs.microsoft.com/en-us/rest/api/compute/availabilitysets/availabilitysets-create # - def create_availability_set(params) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_AVAILABILITY_SETS, name: params[:name]) + def create_availability_set(resource_group_name, params) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_AVAILABILITY_SETS, resource_group_name: resource_group_name, name: params[:name]) availability_set = { 'name' => params[:name], 'type' => "#{REST_API_PROVIDER_COMPUTE}/#{REST_API_COMPUTE_AVAILABILITY_SETS}", @@ -608,14 +653,15 @@ def create_availability_set(params) end # Get an availability set's information - # @param [String] name - Name of availability set. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of availability set. # # @return [Hash] # # @See https://docs.microsoft.com/en-us/rest/api/compute/availabilitysets/availabilitysets-get # - def get_availability_set_by_name(name) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_AVAILABILITY_SETS, name: name) + def get_availability_set_by_name(resource_group_name, name) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_AVAILABILITY_SETS, resource_group_name: resource_group_name, name: name) get_availability_set(url) end @@ -656,15 +702,16 @@ def get_availability_set(url) end # Delete an availability set - # @param [String] name - Name of availability set. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of availability set. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/compute/availabilitysets/availabilitysets-delete # - def delete_availability_set(name) - @logger.debug("delete_availability_set - trying to delete #{name}") - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_AVAILABILITY_SETS, name: name) + def delete_availability_set(resource_group_name, name) + @logger.debug("delete_availability_set - trying to delete `#{name}' from resource group `#{resource_group_name}'") + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_AVAILABILITY_SETS, resource_group_name: resource_group_name, name: name) http_delete(url) end @@ -674,7 +721,8 @@ def delete_availability_set(name) # # ==== Attributes # - # @param [Hash] params - Parameters for creating the empty managed disk. + # @param [String] resource_group_name - Name of resource group. + # @param [Hash] params - Parameters for creating the empty managed disk. # # ==== params # @@ -688,8 +736,8 @@ def delete_availability_set(name) # # @See https://docs.microsoft.com/en-us/rest/api/manageddisks/disks/disks-create-or-update # - def create_empty_managed_disk(params) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, name: params[:name]) + def create_empty_managed_disk(resource_group_name, params) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, resource_group_name: resource_group_name, name: params[:name]) disk = { 'location' => params[:location], 'tags' => params[:tags], @@ -708,7 +756,8 @@ def create_empty_managed_disk(params) # # ==== Attributes # - # @param [Hash] params - Parameters for creating the managed disk. + # @param [String] resource_group_name - Name of resource group. + # @param [Hash] params - Parameters for creating the managed disk. # # ==== params # @@ -722,8 +771,8 @@ def create_empty_managed_disk(params) # # @See https://docs.microsoft.com/en-us/rest/api/manageddisks/disks/disks-create-or-update # - def create_managed_disk_from_blob(params) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, name: params[:name]) + def create_managed_disk_from_blob(resource_group_name, params) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, resource_group_name: resource_group_name, name: params[:name]) disk = { 'location' => params[:location], 'tags' => params[:tags], @@ -739,27 +788,29 @@ def create_managed_disk_from_blob(params) end # Delete a managed disk - # @param [String] name - Name of managed disk. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of managed disk. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/manageddisks/disks/disks-delete # - def delete_managed_disk(name) - @logger.debug("delete_managed_disk - trying to delete #{name}") - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, name: name) + def delete_managed_disk(resource_group_name, name) + @logger.debug("delete_managed_disk - trying to delete #{name} from resource group #{resource_group_name}") + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, resource_group_name: resource_group_name, name: name) http_delete(url) end # Get a managed disk's information - # @param [String] name - Name of managed disk. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of managed disk. # # @return [Hash] # # @See https://docs.microsoft.com/en-us/rest/api/manageddisks/disks/disks-get # - def get_managed_disk_by_name(name) - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, name: name) + def get_managed_disk_by_name(resource_group_name, name) + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, resource_group_name:resource_group_name, name: name) get_managed_disk(url) end @@ -882,6 +933,9 @@ def list_user_images() # # ==== Attributes # + # @param [String] resource_group_name - Name of resource group. + # @param [Hash] params - Parameters for creating the managed snapshot. + # # ==== params # # Accepted key/value pairs are: @@ -893,20 +947,20 @@ def list_user_images() # # @See https://docs.microsoft.com/en-us/rest/api/manageddisks/snapshots/snapshots-create-or-update # - def create_managed_snapshot(params) + def create_managed_snapshot(resource_group_name, params) snapshot_name = params[:name] disk_name = params[:disk_name] @logger.debug("create_managed_snapshot - trying to create a snapshot `#{snapshot_name}' for the managed disk `#{disk_name}'") - disk = get_managed_disk_by_name(disk_name) + disk = get_managed_disk_by_name(resource_group_name, disk_name) raise AzureNotFoundError, "The disk `#{disk_name}' cannot be found" if disk.nil? - snapshot_url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_SNAPSHOTS, name: snapshot_name) + snapshot_url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_SNAPSHOTS, resource_group_name: resource_group_name, name: snapshot_name) snapshot = { 'location' => disk[:location], 'tags' => params[:tags], 'properties' => { 'creationData' => { 'createOption' => 'Copy', - 'sourceUri' => rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, name: disk_name) + 'sourceUri' => rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_DISKS, resource_group_name: resource_group_name, name: disk_name) } } } @@ -915,15 +969,16 @@ def create_managed_snapshot(params) end # Delete a snapshot of managed disk - # @param [String] name - Name of snapshot. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of snapshot. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/manageddisks/snapshots/snapshots-delete # - def delete_managed_snapshot(name) - @logger.debug("delete_managed_snapshot - trying to delete `#{name}'") - url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_SNAPSHOTS, name: name) + def delete_managed_snapshot(resource_group_name, name) + @logger.debug("delete_managed_snapshot - trying to delete `#{name}' from resource group `#{resource_group_name}'") + url = rest_api_url(REST_API_PROVIDER_COMPUTE, REST_API_COMPUTE_SNAPSHOTS, resource_group_name: resource_group_name, name: name) http_delete(url) end @@ -962,6 +1017,7 @@ def list_platform_image_versions(location, publisher, offer, sku) # Network/Public IP # Create a public IP + # @param [String] resource_group_name - Name of resource group. # @param [String] name - Name of public IP. # @param [String] location - Location where the public IP will be created. # @param [Boolean] is_static - Whether the IP address is static or dynamic. @@ -971,8 +1027,8 @@ def list_platform_image_versions(location, publisher, offer, sku) # # @See https://docs.microsoft.com/en-us/rest/api/network/create-or-update-a-public-ip-address # - def create_public_ip(name, location, is_static = true, idle_timeout_in_minutes = 4) - url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_PUBLIC_IP_ADDRESSES, name: name) + def create_public_ip(resource_group_name, name, location, is_static = true, idle_timeout_in_minutes = 4) + url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_PUBLIC_IP_ADDRESSES, resource_group_name: resource_group_name, name: name) public_ip = { 'name' => name, 'location' => location, @@ -985,14 +1041,15 @@ def create_public_ip(name, location, is_static = true, idle_timeout_in_minutes = end # Get a public IP's information - # @param [String] name - Name of public IP. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of public IP. # # @return [Hash] # # @See https://docs.microsoft.com/en-us/rest/api/network/get-information-about-a-public-ip-address # - def get_public_ip_by_name(name) - url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_PUBLIC_IP_ADDRESSES, name: name) + def get_public_ip_by_name(resource_group_name, name) + url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_PUBLIC_IP_ADDRESSES, resource_group_name: resource_group_name, name: name) get_public_ip(url) end @@ -1029,15 +1086,16 @@ def list_public_ips(resource_group_name) end # Delete a public IP - # @param [String] name - Name of public IP. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of public IP. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/network/delete-a-public-ip-address # - def delete_public_ip(name) - @logger.debug("delete_public_ip - trying to delete #{name}") - url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_PUBLIC_IP_ADDRESSES, name: name) + def delete_public_ip(resource_group_name, name) + @logger.debug("delete_public_ip - trying to delete #{name} from resource group #{resource_group_name}") + url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_PUBLIC_IP_ADDRESSES, resource_group_name: resource_group_name, name: name) http_delete(url) end @@ -1192,10 +1250,11 @@ def delete_load_balancer(name) # # ==== Attributes # - # @param [Hash] nic_params - Parameters for creating the network interface. - # @param [Hash] subnet - The subnet which the network interface is binded to. - # @param [Hash] tags - The tags of the network interface. - # @param [Hash] load_balancer - The load balancer which the network interface is binded to. + # @param [String] resource_group_name - Name of resource group. + # @param [Hash] nic_params - Parameters for creating the network interface. + # @param [Hash] subnet - The subnet which the network interface is binded to. + # @param [Hash] tags - The tags of the network interface. + # @param [Hash] load_balancer - The load balancer which the network interface is binded to. # # ==== Params # @@ -1212,8 +1271,8 @@ def delete_load_balancer(name) # # @See https://docs.microsoft.com/en-us/rest/api/network/create-or-update-a-network-interface-card # - def create_network_interface(nic_params, subnet, tags, load_balancer = nil) - url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES, name: nic_params[:name]) + def create_network_interface(resource_group_name, nic_params, subnet, tags, load_balancer = nil) + url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES, resource_group_name: resource_group_name, name: nic_params[:name]) interface = { 'name' => nic_params[:name], 'location' => nic_params[:location], @@ -1255,14 +1314,15 @@ def create_network_interface(nic_params, subnet, tags, load_balancer = nil) end # Get a network interface's information - # @param [String] name - Name of network interface. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of network interface. # # @return [Hash] # # @See https://docs.microsoft.com/en-us/rest/api/network/get-information-about-a-network-interface-card # - def get_network_interface_by_name(name) - url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES, name: name) + def get_network_interface_by_name(resource_group_name, name) + url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES, resource_group_name: resource_group_name, name: name) get_network_interface(url) end @@ -1279,15 +1339,16 @@ def get_network_interface(url) end # List network interfaces whose name contains a keyword - # @param [String] keyword - Keyword of network interfaces to list. keyword stands for a VM, and NICs of that VM are "#{keyword}-0", "#{keyword}-1" and so on. + # @param [String] resource_group_name - Name of resource group. + # @param [String] keyword - Keyword of network interfaces to list. keyword stands for a VM, and NICs of that VM are "#{keyword}-0", "#{keyword}-1" and so on. # # @return [Array] - Array of network interfaces, however, the network interface here will not contain details about public ip or load balancer. # # @See https://docs.microsoft.com/en-us/rest/api/network/list-network-interface-cards-within-a-resource-group # - def list_network_interfaces_by_instance_id(keyword) + def list_network_interfaces_by_keyword(resource_group_name, keyword) network_interfaces = [] - network_interfaces_url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES) + network_interfaces_url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES, resource_group_name: resource_group_name) results = get_resource_by_id(network_interfaces_url) unless results.nil? || results["value"].nil? results["value"].each do |network_interface_spec| @@ -1305,15 +1366,16 @@ def list_network_interfaces_by_instance_id(keyword) end # Delete a network interface - # @param [String] name - Name of network interface. + # @param [String] resource_group_name - Name of resource group. + # @param [String] name - Name of network interface. # # @return [Boolean] # # @See https://docs.microsoft.com/en-us/rest/api/network/delete-a-network-interface-card # - def delete_network_interface(name) - @logger.debug("delete_network_interface - trying to delete #{name}") - url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES, name: name) + def delete_network_interface(resource_group_name, name) + @logger.debug("delete_network_interface - trying to delete #{name} from resource group #{resource_group_name}") + url = rest_api_url(REST_API_PROVIDER_NETWORK, REST_API_NETWORK_INTERFACES, resource_group_name: resource_group_name, name: name) http_delete(url) end @@ -2074,7 +2136,7 @@ def http_put(url, body = nil, params = {}, retry_after = 5) response = http_get_response(uri, request, retry_after) options = { :operation => 'http_put', - :return_code => [HTTP_CODE_OK], + :return_code => [HTTP_CODE_OK, HTTP_CODE_CREATED], :success_code => [HTTP_CODE_CREATED, HTTP_CODE_ACCEPTED], :api_version => params['api-version'], :retry_after => retry_after diff --git a/src/bosh_azure_cpi/lib/cloud/azure/cloud.rb b/src/bosh_azure_cpi/lib/cloud/azure/cloud.rb index 0bd2c94bf..8eeec0d8a 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure/cloud.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure/cloud.rb @@ -103,7 +103,8 @@ def delete_stemcell(stemcell_id) # "use_root_disk" => false, # Whether to use OS disk to store the ephemeral data # "size" => 30720, # disk size in MiB # }, - # "assign_dynamic_public_ip": true + # "assign_dynamic_public_ip" => true, + # "resource_group_name" => "rg1" # } # # Sample env config: @@ -135,8 +136,11 @@ def create_vm(agent_id, stemcell_id, resource_pool, networks, disk_locality = ni vnet = @azure_client2.get_virtual_network_by_name(network.resource_group_name, network.virtual_network_name) cloud_error("Cannot find the virtual network `#{network.virtual_network_name}' under resource group `#{network.resource_group_name}'") if vnet.nil? location = vnet[:location] + resource_group_name = resource_pool.fetch('resource_group_name', azure_properties['resource_group_name']) + if @use_managed_disks - instance_id = agent_id + instance_id = InstanceId.create(resource_group_name, agent_id) + storage_account_type = resource_pool['storage_account_type'] storage_account_type = get_storage_account_type_by_instance_type(resource_pool['instance_type']) if storage_account_type.nil? @@ -153,6 +157,7 @@ def create_vm(agent_id, stemcell_id, resource_pool, networks, disk_locality = ni end else storage_account = @storage_account_manager.get_storage_account_from_resource_pool(resource_pool, location) + instance_id = InstanceId.create(resource_group_name, agent_id, storage_account[:name]) if is_light_stemcell_id?(stemcell_id) raise Bosh::Clouds::VMCreationFailed.new(false), "Given stemcell `#{stemcell_id}' does not exist" unless @light_stemcell_manager.has_stemcell?(location, stemcell_id) @@ -163,8 +168,6 @@ def create_vm(agent_id, stemcell_id, resource_pool, networks, disk_locality = ni end stemcell_info = @stemcell_manager.get_stemcell_info(storage_account[:name], stemcell_id) end - - instance_id = "#{storage_account[:name]}-#{agent_id}" end vm_params = @vm_manager.create( @@ -173,7 +176,8 @@ def create_vm(agent_id, stemcell_id, resource_pool, networks, disk_locality = ni stemcell_info, resource_pool, network_configurator, - env) + env + ) @logger.info("Created new vm `#{instance_id}'") @@ -184,9 +188,9 @@ def create_vm(agent_id, stemcell_id, resource_pool, networks, disk_locality = ni env, vm_params ) - registry.update_settings(instance_id, registry_settings) + registry.update_settings(instance_id.to_s, registry_settings) - instance_id + instance_id.to_s rescue => e @logger.error(%Q[Failed to update registry after new vm was created: #{e.inspect}\n#{e.backtrace.join("\n")}]) @vm_manager.delete(instance_id) @@ -203,7 +207,7 @@ def create_vm(agent_id, stemcell_id, resource_pool, networks, disk_locality = ni def delete_vm(instance_id) with_thread_name("delete_vm(#{instance_id})") do @logger.info("Deleting instance `#{instance_id}'") - @vm_manager.delete(instance_id) + @vm_manager.delete(InstanceId.parse(instance_id, azure_properties)) end end @@ -214,7 +218,7 @@ def delete_vm(instance_id) # @return [Boolean] True if the vm exists def has_vm?(instance_id) with_thread_name("has_vm?(#{instance_id})") do - vm = @vm_manager.find(instance_id) + vm = @vm_manager.find(InstanceId.parse(instance_id, azure_properties)) !vm.nil? && vm[:provisioning_state] != 'Deleting' end end @@ -226,11 +230,12 @@ def has_vm?(instance_id) # @return [Boolean] True if the disk exists def has_disk?(disk_id) with_thread_name("has_disk?(#{disk_id})") do + disk_id = DiskId.parse(disk_id, azure_properties) if @use_managed_disks - return true if @disk_manager2.has_disk?(disk_id) + return true if @disk_manager2.has_data_disk?(disk_id) return false if @disk_manager.is_migrated?(disk_id) end - @disk_manager.has_disk?(disk_id) + @disk_manager.has_data_disk?(disk_id) end end @@ -242,7 +247,7 @@ def has_disk?(disk_id) # @return [void] def reboot_vm(instance_id, options = nil) with_thread_name("reboot_vm(#{instance_id}, #{options})") do - @vm_manager.reboot(instance_id) + @vm_manager.reboot(InstanceId.parse(instance_id, azure_properties)) end end @@ -256,7 +261,7 @@ def reboot_vm(instance_id, options = nil) # @return [void] def set_vm_metadata(instance_id, metadata) @logger.info("set_vm_metadata(#{instance_id}, #{metadata})") - @vm_manager.set_metadata(instance_id, encode_metadata(metadata)) + @vm_manager.set_metadata(InstanceId.parse(instance_id, azure_properties), encode_metadata(metadata)) end ## @@ -299,13 +304,16 @@ def create_disk(size, cloud_properties, instance_id = nil) if @use_managed_disks if instance_id.nil? # If instance_id is nil, the managed disk will be created in the resource group location. - resource_group = @azure_client2.get_resource_group() + resource_group_name = azure_properties['resource_group_name'] + resource_group = @azure_client2.get_resource_group(resource_group_name) location = resource_group[:location] default_storage_account_type = STORAGE_ACCOUNT_TYPE_STANDARD_LRS else - cloud_error("Cannot create a managed disk for a VM with unmanaged disks") unless is_managed_vm?(instance_id) + instance_id = InstanceId.parse(instance_id, azure_properties) + cloud_error("Cannot create a managed disk for a VM with unmanaged disks") unless instance_id.use_managed_disks?() + resource_group_name = instance_id.resource_group_name() # If the instance is a managed VM, the managed disk will be created in the location of the VM. - vm = @azure_client2.get_virtual_machine_by_name(instance_id) + vm = @azure_client2.get_virtual_machine_by_name(resource_group_name, instance_id.vm_name()) location = vm[:location] instance_type = vm[:vm_size] default_storage_account_type = get_storage_account_type_by_instance_type(instance_type) @@ -313,19 +321,21 @@ def create_disk(size, cloud_properties, instance_id = nil) storage_account_type = cloud_properties.fetch('storage_account_type', default_storage_account_type) caching = cloud_properties.fetch('caching', 'None') validate_disk_caching(caching) - disk_id = @disk_manager2.create_disk(location, size/1024, storage_account_type, caching) + disk_id = DiskId.create(caching, true, resource_group_name: resource_group_name) + @disk_manager2.create_disk(disk_id, location, size/1024, storage_account_type) else storage_account_name = azure_properties['storage_account_name'] caching = cloud_properties.fetch('caching', 'None') validate_disk_caching(caching) unless instance_id.nil? - @logger.info("Create disk for vm #{instance_id}") - storage_account_name = get_storage_account_name_from_instance_id(instance_id) + instance_id = InstanceId.parse(instance_id, azure_properties) + @logger.info("Create disk for vm `#{instance_id.vm_name()}'") + storage_account_name = instance_id.storage_account_name() end - - disk_id = @disk_manager.create_disk(size/1024, storage_account_name, caching) + disk_id = DiskId.create(caching, false, storage_account_name: storage_account_name) + @disk_manager.create_disk(disk_id, size/1024) end - disk_id + disk_id.to_s end end @@ -337,16 +347,17 @@ def create_disk(size, cloud_properties, instance_id = nil) # @return [void] def delete_disk(disk_id) with_thread_name("delete_disk(#{disk_id})") do + disk_id = DiskId.parse(disk_id, azure_properties) if @use_managed_disks # A managed disk may be created from an old blob disk, so its name still starts with 'bosh-data' instead of 'bosh-disk-data' # CPI checks whether the managed disk with the name exists. If not, delete the old blob disk. - unless disk_id.start_with?(MANAGED_DATA_DISK_PREFIX) - disk = @disk_manager2.get_disk(disk_id) - return @disk_manager.delete_disk(disk_id) if disk.nil? + unless disk_id.disk_name().start_with?(MANAGED_DATA_DISK_PREFIX) + disk = @disk_manager2.get_data_disk(disk_id) + return @disk_manager.delete_data_disk(disk_id) if disk.nil? end - @disk_manager2.delete_disk(disk_id) + @disk_manager2.delete_data_disk(disk_id) else - @disk_manager.delete_disk(disk_id) + @disk_manager.delete_data_disk(disk_id) end end end @@ -357,35 +368,39 @@ def delete_disk(disk_id) # @return [void] def attach_disk(instance_id, disk_id) with_thread_name("attach_disk(#{instance_id},#{disk_id})") do + instance_id = InstanceId.parse(instance_id, azure_properties) + disk_id = DiskId.parse(disk_id, azure_properties) + vm_name = instance_id.vm_name() + disk_name = disk_id.disk_name() if @use_managed_disks - disk = @disk_manager2.get_disk(disk_id) - unless is_managed_vm?(instance_id) + disk = @disk_manager2.get_data_disk(disk_id) + unless instance_id.use_managed_disks?() cloud_error("Cannot attach a managed disk to a VM with unmanaged disks") unless disk.nil? - @logger.debug("attach_disk - although use_managed_disks is enabled, will still attach the unmanaged disk `#{disk_id}' to the VM `#{instance_id}' with unmanaged disks") + @logger.debug("attach_disk - although use_managed_disks is enabled, will still attach the unmanaged disk `#{disk_name}' to the VM `#{vm_name}' with unmanaged disks") else if disk.nil? begin - blob_uri = @disk_manager.get_disk_uri(disk_id) - storage_account_name = get_storage_account_name_from_disk_id(disk_id) + storage_account_name = disk_id.storage_account_name() + blob_uri = @disk_manager.get_data_disk_uri(disk_id) storage_account = @azure_client2.get_storage_account_by_name(storage_account_name) location = storage_account[:location] # Can not use the type of the default storage account because only Standard_LRS and Premium_LRS are supported for managed disk. account_type = (storage_account[:account_type] == STORAGE_ACCOUNT_TYPE_PREMIUM_LRS) ? STORAGE_ACCOUNT_TYPE_PREMIUM_LRS : STORAGE_ACCOUNT_TYPE_STANDARD_LRS - @logger.debug("attach_disk - Migrating the unmanaged disk `#{disk_id}' to a managed disk") + @logger.debug("attach_disk - Migrating the unmanaged disk `#{disk_name}' to a managed disk") @disk_manager2.create_disk_from_blob(disk_id, blob_uri, location, account_type) # Set below metadata but not delete it. # Users can manually delete all blobs in container `bosh` whose names start with `bosh-data` after migration is finished. - @blob_manager.set_blob_metadata(storage_account_name, DISK_CONTAINER, "#{disk_id}.vhd", METADATA_FOR_MIGRATED_BLOB_DISK) + @blob_manager.set_blob_metadata(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd", METADATA_FOR_MIGRATED_BLOB_DISK) rescue => e if account_type # There are no other functions between defining account_type and @disk_manager2.create_disk_from_blob begin - @disk_manager2.delete_disk(disk_id) + @disk_manager2.delete_data_disk(disk_id) rescue => err - @logger.error("attach_disk - Failed to delete the created managed disk #{disk_id}. Error: #{e.inspect}\n#{e.backtrace.join("\n")}") + @logger.error("attach_disk - Failed to delete the created managed disk #{disk_name}. Error: #{e.inspect}\n#{e.backtrace.join("\n")}") end end - cloud_error("attach_disk - Failed to create the managed disk for #{disk_id}. Error: #{e.inspect}\n#{e.backtrace.join("\n")}") + cloud_error("attach_disk - Failed to create the managed disk for #{disk_name}. Error: #{e.inspect}\n#{e.backtrace.join("\n")}") end end end @@ -393,10 +408,10 @@ def attach_disk(instance_id, disk_id) lun = @vm_manager.attach_disk(instance_id, disk_id) - update_agent_settings(instance_id) do |settings| + update_agent_settings(instance_id.to_s) do |settings| settings["disks"] ||= {} settings["disks"]["persistent"] ||= {} - settings["disks"]["persistent"][disk_id] = { + settings["disks"]["persistent"][disk_id.to_s] = { 'lun' => lun, 'host_device_id' => AZURE_SCSI_HOST_DEVICE_ID, @@ -422,7 +437,10 @@ def detach_disk(instance_id, disk_id) settings["disks"]["persistent"].delete(disk_id) end - @vm_manager.detach_disk(instance_id, disk_id) + @vm_manager.detach_disk( + InstanceId.parse(instance_id, azure_properties), + DiskId.parse(disk_id, azure_properties) + ) @logger.info("Detached `#{disk_id}' from `#{instance_id}'") end @@ -435,10 +453,10 @@ def detach_disk(instance_id, disk_id) def get_disks(instance_id) with_thread_name("get_disks(#{instance_id})") do disks = [] - vm = @vm_manager.find(instance_id) + vm = @vm_manager.find(InstanceId.parse(instance_id, azure_properties)) raise Bosh::Clouds::VMNotFound, "VM `#{instance_id}' cannot be found" if vm.nil? vm[:data_disks].each do |disk| - disks << disk[:name] unless is_ephemeral_disk?(disk[:name]) + disks << disk[:disk_bosh_id] unless is_ephemeral_disk?(disk[:name]) end disks end @@ -450,19 +468,27 @@ def get_disks(instance_id) # @return [String] snapshot id def snapshot_disk(disk_id, metadata = {}) with_thread_name("snapshot_disk(#{disk_id},#{metadata})") do - if disk_id.start_with?(MANAGED_DATA_DISK_PREFIX) - snapshot_id = @disk_manager2.snapshot_disk(disk_id, encode_metadata(metadata)) + disk_id = DiskId.parse(disk_id, azure_properties) + resource_group_name = disk_id.resource_group_name() + disk_name = disk_id.disk_name() + caching = disk_id.caching() + if disk_name.start_with?(MANAGED_DATA_DISK_PREFIX) + snapshot_id = DiskId.create(caching, true, resource_group_name: resource_group_name) + @disk_manager2.snapshot_disk(snapshot_id, disk_name, encode_metadata(metadata)) else - disk = @disk_manager2.get_disk(disk_id) + disk = @disk_manager2.get_data_disk(disk_id) unless disk.nil? - snapshot_id = @disk_manager2.snapshot_disk(disk_id, encode_metadata(metadata)) + snapshot_id = DiskId.create(caching, true, resource_group_name: resource_group_name) + @disk_manager2.snapshot_disk(snapshot_id, disk_name, encode_metadata(metadata)) else - snapshot_id = @disk_manager.snapshot_disk(disk_id, encode_metadata(metadata)) + storage_account_name = disk_id.storage_account_name() + snapshot_name = @disk_manager.snapshot_disk(storage_account_name, disk_name, encode_metadata(metadata)) + snapshot_id = DiskId.create(caching, false, disk_name: snapshot_name, storage_account_name: storage_account_name) end end @logger.info("Take a snapshot `#{snapshot_id}' for the disk `#{disk_id}'") - snapshot_id + snapshot_id.to_s end end @@ -471,7 +497,9 @@ def snapshot_disk(disk_id, metadata = {}) # @return [void] def delete_snapshot(snapshot_id) with_thread_name("delete_snapshot(#{snapshot_id})") do - if snapshot_id.start_with?(MANAGED_DATA_DISK_PREFIX) + snapshot_id = DiskId.parse(snapshot_id, azure_properties) + snapshot_name = snapshot_id.disk_name() + if snapshot_name.start_with?(MANAGED_DATA_DISK_PREFIX) @disk_manager2.delete_snapshot(snapshot_id) else @disk_manager.delete_snapshot(snapshot_id) diff --git a/src/bosh_azure_cpi/lib/cloud/azure/disk_id.rb b/src/bosh_azure_cpi/lib/cloud/azure/disk_id.rb new file mode 100644 index 000000000..a61baf89e --- /dev/null +++ b/src/bosh_azure_cpi/lib/cloud/azure/disk_id.rb @@ -0,0 +1,137 @@ +module Bosh::AzureCloud + class DiskId + include Helpers + + # V1 format: + # With unmanaged disks: + # data disk: "bosh-data-[STORAGE-ACCOUNT-NAME]-[UUID]-[CACHING]" + # snapshot disk: "bosh-data-[STORAGE-ACCOUNT-NAME]-[UUID]-[CACHING]--[SNAPSHOTTIME]" + # With managed disks: + # data disk: "bosh-disk-data-[AGENTID]-[CACHING]" + # snapshot disk: "bosh-disk-data-[AGENTID]-[CACHING]" + # V2 format: + # With unmanaged disks: + # data disk: "disk_name:bosh-data-[UUID];caching:[CACHING];storage_account_name:[STORAGE-ACCOUNT-NAME]" + # snapshot disk: "disk_name:bosh-data-[UUID]--[SNAPSHOTTIME];caching:[CACHING];storage_account_name:[STORAGE-ACCOUNT-NAME]" + # With managed disks: + # data disk: "disk_name:bosh-disk-data-[UUID];caching:[CACHING];resource_group_name:[RESOURCE-GROUP-NAME]" + # snapshot disk: "disk_name:bosh-disk-data-[UUID];caching:[CACHING];storage_account_name:[STORAGE-ACCOUNT-NAME]" + # + # Usage: + # Creating id for a new disk + # disk_id = DiskId.create(caching, false, storage_account_name: 'ss') # Create V2 unmanaged disk id + # disk_id = DiskId.create(caching, true, resource_group_name: 'rr') # Create V2 managed disk id + # Parsing id for an existing disk + # disk_id = DiskId.parse(id, azure_properties) + + VERSION1 = 'v1' # class properties: version (string), id (string), default_resource_group_name (string) + VERSION2 = 'v2' # class properties: version (string), id (json) + + private_class_method :new + + def initialize(version, options = {}) + @version = version + @id = options[:id] + @default_resource_group_name = options[:default_resource_group_name] + end + + def self.create(caching, use_managed_disks, disk_name: nil, resource_group_name: nil, storage_account_name: nil) + id = { + 'disk_name' => disk_name.nil? ? generate_data_disk_name(use_managed_disks) : disk_name, + 'caching' => caching + } + id['resource_group_name'] = resource_group_name unless resource_group_name.nil? + id['storage_account_name'] = storage_account_name unless storage_account_name.nil? + new(VERSION2, { :id => id }) + end + + def self.parse(id, azure_properties) + disk_id = nil + + if id.include?(';') + id_hash = Hash.new + array = id.split(';') + array.each do |item| + ret = item.match("^([^:]*):(.*)$") + id_hash[ret[1]] = ret[2] + end + disk_id = new(VERSION2, { :id => id_hash, :default_resource_group_name => azure_properties['resource_group_name'] }) + else + disk_id = new(VERSION1, { :id => id, :default_resource_group_name => azure_properties['resource_group_name'] }) + end + + disk_id.validate() + disk_id + end + + def self.generate_data_disk_name(use_managed_disks) + "#{use_managed_disks ? MANAGED_DATA_DISK_PREFIX : DATA_DISK_PREFIX}-#{SecureRandom.uuid}" + end + + def to_s() + return @id if @version == VERSION1 + array = Array.new + @id.each {|key, value| array << "#{key}:#{value}"} + array.sort.join(';') + end + + def resource_group_name() + return @default_resource_group_name if @version == VERSION1 + @id.fetch('resource_group_name', @default_resource_group_name) + end + + def disk_name() + return @id if @version == VERSION1 + @id['disk_name'] + end + + def caching() + cloud_error('This function should only be called for data disks') unless disk_name().start_with?(DATA_DISK_PREFIX) || disk_name().start_with?(MANAGED_DATA_DISK_PREFIX) + + if @version == VERSION1 + return parse_data_disk_caching_v1(@id) + end + @id['caching'] + end + + def storage_account_name() + cloud_error('This function should only be called for unmanaged disks') if disk_name().start_with?(MANAGED_DATA_DISK_PREFIX) + + if @version == VERSION1 + return parse_storage_account_v1(@id) + end + @id['storage_account_name'] + end + + def validate() + if @version == VERSION2 + cloud_error("Invalid disk_name in disk id (version 2) `#{@id}'") if disk_name().nil? || disk_name().empty? + cloud_error("Invalid caching in disk id (version 2) `#{@id}'") if caching().nil? || caching().empty? + unless resource_group_name().nil? + cloud_error("Invalid resource_group_name in disk id (version 2) `#{@id}'") if resource_group_name().empty? + end + if disk_name().start_with?(DATA_DISK_PREFIX) + cloud_error("Invalid storage_account_name in disk id (version 2) `#{@id}'") if storage_account_name().nil? || storage_account_name().empty? + end + end + end + + private + + def parse_data_disk_caching_v1(disk_name) + caching = disk_name.split('-')[-1] + validate_disk_caching(caching) + caching + end + + def parse_storage_account_v1(disk_name) + if disk_name.start_with?(DATA_DISK_PREFIX) + ret = disk_name.match("^#{DATA_DISK_PREFIX}-([^-]*)-(.*)-([^-]*)$") + cloud_error("Invalid unmanaged data disk name #{disk_name}") if ret.nil? + ret[1] + else + cloud_error("Invalid data disk name (version 1) #{disk_name}") + end + end + end +end diff --git a/src/bosh_azure_cpi/lib/cloud/azure/disk_manager.rb b/src/bosh_azure_cpi/lib/cloud/azure/disk_manager.rb index c8b4a2211..156c66049 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure/disk_manager.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure/disk_manager.rb @@ -11,10 +11,16 @@ def initialize(azure_properties, blob_manager) @logger = Bosh::Clouds::Config.logger end - def delete_disk(disk_name) - @logger.info("delete_disk(#{disk_name})") - storage_account_name = get_storage_account_name(disk_name) - @blob_manager.delete_blob(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd") if has_disk?(disk_name) + def delete_disk(storage_account_name, disk_name) + @logger.info("delete_disk(#{storage_account_name}, #{disk_name})") + @blob_manager.delete_blob(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd") if has_disk?(storage_account_name, disk_name) + end + + def delete_data_disk(disk_id) + @logger.info("delete_data_disk(#{disk_id})") + storage_account_name = disk_id.storage_account_name() + disk_name = disk_id.disk_name() + delete_disk(storage_account_name, disk_name) end def delete_vm_status_files(storage_account_name, prefix) @@ -29,83 +35,90 @@ def delete_vm_status_files(storage_account_name, prefix) @logger.debug("delete_vm_status_files - error: #{e.inspect}\n#{e.backtrace.join("\n")}") end - def snapshot_disk(disk_name, metadata) - @logger.info("snapshot_disk(#{disk_name}, #{metadata})") - storage_account_name = get_storage_account_name(disk_name) + def snapshot_disk(storage_account_name, disk_name, metadata) + @logger.info("snapshot_disk(#{storage_account_name}, #{disk_name}, #{metadata})") snapshot_time = @blob_manager.snapshot_blob(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd", metadata) - generate_snapshot_id(disk_name, snapshot_time) + generate_snapshot_name(disk_name, snapshot_time) end def delete_snapshot(snapshot_id) @logger.info("delete_snapshot(#{snapshot_id})") - disk_name, snapshot_time = parse_snapshot_id(snapshot_id) - storage_account_name = get_storage_account_name(disk_name) + storage_account_name = snapshot_id.storage_account_name() + snapshot_name = snapshot_id.disk_name() + disk_name, snapshot_time = parse_snapshot_name(snapshot_name) @blob_manager.delete_blob_snapshot(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd", snapshot_time) end ## # Creates a disk (possibly lazily) that will be attached later to a VM. # - # @param [Integer] size disk size in GiB - # @param [string] storage_account_name the storage account where the disk is created - # @param [string] caching the disk caching type. Possible values: None, ReadOnly or ReadWrite. + # @param [String] disk_id - instance of DiskId + # @param [Integer] size - disk size in GiB # - # @return [String] disk name - def create_disk(size, storage_account_name, caching) - @logger.info("create_disk(#{size}, #{storage_account_name}, #{caching})") - disk_name = generate_data_disk_name(storage_account_name, caching) + # @return [void] + def create_disk(disk_id, size) + @logger.info("create_disk(#{disk_id}, #{size}") + storage_account_name = disk_id.storage_account_name() + disk_name = disk_id.disk_name() @logger.info("Start to create an empty vhd blob: blob_name: #{disk_name}.vhd") @blob_manager.create_empty_vhd_blob(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd", size) - disk_name end - def has_disk?(disk_name) - @logger.info("has_disk?(#{disk_name})") - storage_account_name = get_storage_account_name(disk_name) + def has_disk?(storage_account_name, disk_name) + @logger.info("has_disk?(#{storage_account_name}, #{disk_name})") blob_properties = @blob_manager.get_blob_properties(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd") !blob_properties.nil? end - def is_migrated?(disk_name) - @logger.info("is_migrated?(#{disk_name})") - return false unless has_disk?(disk_name) - storage_account_name = get_storage_account_name(disk_name) + def has_data_disk?(disk_id) + @logger.info("has_data_disk?(#{disk_id})") + storage_account_name = disk_id.storage_account_name() + disk_name = disk_id.disk_name() + has_disk?(storage_account_name, disk_name) + end + + def is_migrated?(disk_id) + @logger.info("is_migrated?(#{disk_id})") + storage_account_name = disk_id.storage_account_name() + disk_name = disk_id.disk_name() + return false unless has_disk?(storage_account_name, disk_name) metadata = @blob_manager.get_blob_metadata(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd") (METADATA_FOR_MIGRATED_BLOB_DISK.to_a - metadata.to_a).empty? end - def get_disk_uri(disk_name) - @logger.info("get_disk_uri(#{disk_name})") - storage_account_name = get_storage_account_name(disk_name) + def get_disk_uri(storage_account_name, disk_name) + @logger.info("get_disk_uri(#{storage_account_name}, #{disk_name})") @blob_manager.get_blob_uri(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd") end - def get_data_disk_caching(disk_name) - @logger.info("get_data_disk_caching(#{disk_name})") - storage_account_name, caching = parse_data_disk_name(disk_name) - caching + def get_data_disk_uri(disk_id) + @logger.info("get_data_disk_uri(#{disk_id})") + storage_account_name = disk_id.storage_account_name() + disk_name = disk_id.disk_name() + get_disk_uri(storage_account_name, disk_name) end - def get_disk_size_in_gb(disk_name) - @logger.info("get_disk_size_in_gb(#{disk_name})") - storage_account_name = get_storage_account_name(disk_name) + def get_disk_size_in_gb(disk_id) + @logger.info("get_disk_size_in_gb(#{disk_id})") + storage_account_name = disk_id.storage_account_name() + disk_name = disk_id.disk_name() @blob_manager.get_blob_size_in_bytes(storage_account_name, DISK_CONTAINER, "#{disk_name}.vhd") / 1024 / 1024 / 1024 end - # bosh-os-STORAGEACCOUNTNAME-AGENTID - def generate_os_disk_name(instance_id) - "#{OS_DISK_PREFIX}-#{instance_id}" + # bosh-os-[VM-NAME] + def generate_os_disk_name(vm_name) + "#{OS_DISK_PREFIX}-#{vm_name}" end - # bosh-os-STORAGEACCOUNTNAME-AGENTID-ephemeral - def generate_ephemeral_disk_name(instance_id) - "#{OS_DISK_PREFIX}-#{instance_id}-#{EPHEMERAL_DISK_POSTFIX}" + # bosh-os-[VM-NAME]-ephemeral + def generate_ephemeral_disk_name(vm_name) + "#{OS_DISK_PREFIX}-#{vm_name}-#{EPHEMERAL_DISK_POSTFIX}" end - def os_disk(instance_id, minimum_disk_size) - disk_name = generate_os_disk_name(instance_id) - disk_uri = get_disk_uri(disk_name) + def os_disk(storage_account_name, vm_name, minimum_disk_size) + disk_name = generate_os_disk_name(vm_name) + disk_uri = get_disk_uri(storage_account_name, disk_name) disk_size = nil root_disk = @resource_pool.fetch('root_disk', {}) @@ -124,7 +137,7 @@ def os_disk(instance_id, minimum_disk_size) # When using OS disk to store the ephemeral data and root_disk.size is not set, # resize it to the minimum disk size if the minimum disk size is larger than 30 GiB; # resize it to 30 GiB if the minimum disk size is smaller than 30 GiB. - if disk_size.nil? && ephemeral_disk(instance_id).nil? + if disk_size.nil? && ephemeral_disk(storage_account_name, vm_name).nil? disk_size = (minimum_disk_size/1024.0).ceil < 30 ? 30 : (minimum_disk_size/1024.0).ceil end @@ -136,7 +149,7 @@ def os_disk(instance_id, minimum_disk_size) } end - def ephemeral_disk(instance_id) + def ephemeral_disk(storage_account_name, vm_name) ephemeral_disk = @resource_pool.fetch('ephemeral_disk', {}) use_root_disk = ephemeral_disk.fetch('use_root_disk', false) return nil if use_root_disk @@ -151,7 +164,7 @@ def ephemeral_disk(instance_id) return { :disk_name => EPHEMERAL_DISK_POSTFIX, - :disk_uri => get_disk_uri(generate_ephemeral_disk_name(instance_id)), + :disk_uri => get_disk_uri(storage_account_name, generate_ephemeral_disk_name(vm_name)), :disk_size => disk_size, :disk_caching => 'ReadWrite' } @@ -174,56 +187,14 @@ def list_disks(storage_account_name) private - def parse_os_disk_name(disk_name) - # For backwards compatibility - # Use default storage account name if the disk name does not contain a storage account name - storage_account_name = @azure_properties['storage_account_name'] - - ret = disk_name.match("^#{OS_DISK_PREFIX}-([^-]*)-(.*)$") - unless ret.nil? - storage_account_name = ret[1] - end - storage_account_name - end - - def parse_data_disk_name(disk_name) - # For backwards compatibility - # Use default storage account name if the disk name does not contain a storage account name - storage_account_name = @azure_properties['storage_account_name'] - caching = 'None' - - ret = disk_name.match("^#{DATA_DISK_PREFIX}-([^-]*)-(.*)-([^-]*)$") - unless ret.nil? - storage_account_name = ret[1] - caching = ret[3] - end - return storage_account_name, caching - end - - # bosh-data-STORAGEACCOUNTNAME-UUID-CACHING - def generate_data_disk_name(storage_account_name, caching) - "#{DATA_DISK_PREFIX}-#{storage_account_name}-#{SecureRandom.uuid}-#{caching}" - end - - def get_storage_account_name(disk_name) - if disk_name.start_with?(OS_DISK_PREFIX) - parse_os_disk_name(disk_name) - elsif disk_name.start_with?(DATA_DISK_PREFIX) - storage_account_name, caching = parse_data_disk_name(disk_name) - storage_account_name - else - cloud_error("Invalid disk name #{disk_name}") - end - end - # bosh-data-STORAGEACCOUNTNAME-UUID-CACHING--SNAPSHOTTIME - def generate_snapshot_id(disk_name, snapshot_time) + def generate_snapshot_name(disk_name, snapshot_time) "#{disk_name}--#{snapshot_time}" end - def parse_snapshot_id(snapshot_id) - ret = snapshot_id.match("^(.*)--(.*)$") - cloud_error("Invalid snapshot id #{snapshot_id}") if ret.nil? + def parse_snapshot_name(snapshot_name) + ret = snapshot_name.match("^(.*)--(.*)$") + cloud_error("Invalid snapshot id #{snapshot_name}") if ret.nil? return ret[1], ret[2] end end diff --git a/src/bosh_azure_cpi/lib/cloud/azure/disk_manager2.rb b/src/bosh_azure_cpi/lib/cloud/azure/disk_manager2.rb index dca666125..71e30c51b 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure/disk_manager2.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure/disk_manager2.rb @@ -13,15 +13,17 @@ def initialize(azure_client2) ## # Creates a disk (possibly lazily) that will be attached later to a VM. # + # @param [string] disk_id instance of DiskId # @param [string] location location of the disk # @param [Integer] size disk size in GiB # @param [string] storage_account_type the storage account type. Possible values: Standard_LRS or Premium_LRS. - # @param [string] caching the disk caching type. Possible values: None, ReadOnly or ReadWrite. # - # @return [String] disk name - def create_disk(location, size, storage_account_type, caching) - @logger.info("create_disk(#{location}, #{size}, #{storage_account_type}, #{caching}") - disk_name = generate_data_disk_name(caching) + # @return [void] + def create_disk(disk_id, location, size, storage_account_type) + @logger.info("create_disk(#{disk_id}, #{location}, #{size}, #{storage_account_type})") + resource_group_name = disk_id.resource_group_name() + disk_name = disk_id.disk_name() + caching = disk_id.caching() tags = AZURE_TAGS.merge({ "caching" => caching }) @@ -32,13 +34,15 @@ def create_disk(location, size, storage_account_type, caching) :disk_size => size, :account_type => storage_account_type } - @logger.info("Start to create an empty managed disk `#{disk_name}'") - @azure_client2.create_empty_managed_disk(disk_params) - disk_name + @logger.info("Start to create an empty managed disk `#{disk_name}' in resource group `#{resource_group_name}'") + @azure_client2.create_empty_managed_disk(resource_group_name, disk_params) end - def create_disk_from_blob(disk_name, blob_uri, location, storage_account_type) - caching = get_data_disk_caching(disk_name) + def create_disk_from_blob(disk_id, blob_uri, location, storage_account_type) + @logger.info("create_disk_from_blob(#{disk_id}, #{blob_uri}, #{location}, #{storage_account_type})") + resource_group_name = disk_id.resource_group_name() + disk_name = disk_id.disk_name() + caching = disk_id.caching() tags = AZURE_TAGS.merge({ "caching" => caching, "original_blob" => blob_uri @@ -50,16 +54,15 @@ def create_disk_from_blob(disk_name, blob_uri, location, storage_account_type) :source_uri => blob_uri, :account_type => storage_account_type } - @logger.info("Start to create a managed disk `#{disk_name}' from the source uri `#{blob_uri}'") - @azure_client2.create_managed_disk_from_blob(disk_params) - disk_name + @logger.info("Start to create a managed disk `#{disk_name}' in resource group `#{resource_group_name}' from the source uri `#{blob_uri}'") + @azure_client2.create_managed_disk_from_blob(resource_group_name, disk_params) end - def delete_disk(disk_name) - @logger.info("delete_disk(#{disk_name})") + def delete_disk(resource_group_name, disk_name) + @logger.info("delete_disk(#{resource_group_name}, #{disk_name})") retried = false begin - @azure_client2.delete_managed_disk(disk_name) if has_disk?(disk_name) + @azure_client2.delete_managed_disk(resource_group_name, disk_name) if has_disk?(resource_group_name, disk_name) rescue Bosh::AzureCloud::AzureConflictError => e # Workaround: Do one retry for AzureConflictError, and give up if it still fails. # After Managed Disks add "retry-after" in the response header, @@ -74,21 +77,42 @@ def delete_disk(disk_name) end end - def has_disk?(disk_name) - @logger.info("has_disk?(#{disk_name})") - disk = get_disk(disk_name) + def delete_data_disk(disk_id) + @logger.info("delete_data_disk(#{disk_id})") + resource_group_name = disk_id.resource_group_name() + disk_name = disk_id.disk_name() + delete_disk(resource_group_name, disk_name) + end + + def has_disk?(resource_group_name, disk_name) + @logger.info("has_disk?(#{resource_group_name}, #{disk_name})") + disk = get_disk(resource_group_name, disk_name) !disk.nil? end - def get_disk(disk_name) - @logger.info("get_disk(#{disk_name})") - disk = @azure_client2.get_managed_disk_by_name(disk_name) + def has_data_disk?(disk_id) + @logger.info("has_data_disk?(#{disk_id})") + resource_group_name = disk_id.resource_group_name() + disk_name = disk_id.disk_name() + has_disk?(resource_group_name, disk_name) + end + + def get_disk(resource_group_name, disk_name) + @logger.info("get_disk(#{resource_group_name}, #{disk_name})") + disk = @azure_client2.get_managed_disk_by_name(resource_group_name, disk_name) + end + + def get_data_disk(disk_id) + @logger.info("get_data_disk(#{disk_id})") + resource_group_name = disk_id.resource_group_name() + disk_name = disk_id.disk_name() + get_disk(resource_group_name, disk_name) end - def snapshot_disk(disk_name, metadata) - @logger.info("snapshot_disk(#{disk_name}, #{metadata})") - caching = get_data_disk_caching(disk_name) - snapshot_name = generate_data_disk_name(caching) + def snapshot_disk(snapshot_id, disk_name, metadata) + @logger.info("snapshot_disk(#{snapshot_id}, #{disk_name}, #{metadata})") + resource_group_name = snapshot_id.resource_group_name() + snapshot_name = snapshot_id.disk_name() snapshot_params = { :name => snapshot_name, :tags => metadata.merge({ @@ -97,26 +121,27 @@ def snapshot_disk(disk_name, metadata) :disk_name => disk_name } @logger.info("Start to create a snapshot `#{snapshot_name}' from a managed disk `#{disk_name}'") - @azure_client2.create_managed_snapshot(snapshot_params) - snapshot_name + @azure_client2.create_managed_snapshot(resource_group_name, snapshot_params) end def delete_snapshot(snapshot_id) @logger.info("delete_snapshot(#{snapshot_id})") - @azure_client2.delete_managed_snapshot(snapshot_id) + resource_group_name = snapshot_id.resource_group_name() + snapshot_name = snapshot_id.disk_name() + @azure_client2.delete_managed_snapshot(resource_group_name, snapshot_name) end - # bosh-disk-os-INSTANCEID - def generate_os_disk_name(instance_id) - "#{MANAGED_OS_DISK_PREFIX}-#{instance_id}" + # bosh-disk-os-[VM-NAME] + def generate_os_disk_name(vm_name) + "#{MANAGED_OS_DISK_PREFIX}-#{vm_name}" end - # bosh-disk-os-INSTANCEID-ephemeral - def generate_ephemeral_disk_name(instance_id) - "#{MANAGED_OS_DISK_PREFIX}-#{instance_id}-#{EPHEMERAL_DISK_POSTFIX}" + # bosh-disk-os-[VM-NAME]-ephemeral + def generate_ephemeral_disk_name(vm_name) + "#{MANAGED_OS_DISK_PREFIX}-#{vm_name}-#{EPHEMERAL_DISK_POSTFIX}" end - def os_disk(instance_id, minimum_disk_size) + def os_disk(vm_name, minimum_disk_size) disk_size = nil root_disk = @resource_pool.fetch('root_disk', {}) size = root_disk.fetch('size', nil) @@ -134,18 +159,18 @@ def os_disk(instance_id, minimum_disk_size) # When using OS disk to store the ephemeral data and root_disk.size is not set, # resize it to the minimum disk size if the minimum disk size is larger than 30 GiB; # resize it to 30 GiB if the minimum disk size is smaller than 30 GiB. - if disk_size.nil? && ephemeral_disk(instance_id).nil? + if disk_size.nil? && ephemeral_disk(vm_name).nil? disk_size = (minimum_disk_size/1024.0).ceil < 30 ? 30 : (minimum_disk_size/1024.0).ceil end return { - :disk_name => generate_os_disk_name(instance_id), + :disk_name => generate_os_disk_name(vm_name), :disk_size => disk_size, :disk_caching => disk_caching } end - def ephemeral_disk(instance_id) + def ephemeral_disk(vm_name) ephemeral_disk = @resource_pool.fetch('ephemeral_disk', {}) use_root_disk = ephemeral_disk.fetch('use_root_disk', false) return nil if use_root_disk @@ -159,24 +184,10 @@ def ephemeral_disk(instance_id) end return { - :disk_name => generate_ephemeral_disk_name(instance_id), + :disk_name => generate_ephemeral_disk_name(vm_name), :disk_size => disk_size, :disk_caching => 'ReadWrite' } end - - def get_data_disk_caching(disk_name) - @logger.info("get_data_disk_caching(#{disk_name})") - caching = disk_name.split('-')[-1] - validate_disk_caching(caching) - caching - end - - private - - # bosh-disk-data-INSTANCEID-caching - def generate_data_disk_name(caching) - "#{MANAGED_DATA_DISK_PREFIX}-#{SecureRandom.uuid}-#{caching}" - end end end diff --git a/src/bosh_azure_cpi/lib/cloud/azure/helpers.rb b/src/bosh_azure_cpi/lib/cloud/azure/helpers.rb index dfd9fd88b..7914c5155 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure/helpers.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure/helpers.rb @@ -104,6 +104,7 @@ module Helpers EPHEMERAL_DISK_POSTFIX = 'ephemeral-disk' STEMCELL_PREFIX = 'bosh-stemcell' LIGHT_STEMCELL_PREFIX = 'bosh-light-stemcell' + DISK_ID_TAG_PREFIX = 'disk-id' LIGHT_STEMCELL_PROPERTY = 'image' AZURE_SCSI_HOST_DEVICE_ID = '{f8b3781b-1e82-4818-a1c3-63d806ec15bb}' METADATA_FOR_MIGRATED_BLOB_DISK = { @@ -150,18 +151,6 @@ def encode_metadata(metadata) ret end - def get_storage_account_name_from_instance_id(instance_id) - ret = instance_id.match('^([^-]*)-(.*)$') - cloud_error("Invalid instance id #{instance_id}") if ret.nil? - return ret[1] - end - - def get_storage_account_name_from_disk_id(disk_id) - ret = disk_id.match('^bosh-data-([^-]*)-(.*)$') - cloud_error("Invalid disk id #{disk_id}") if ret.nil? - return ret[1] - end - def validate_disk_caching(caching) valid_caching = ['None', 'ReadOnly', 'ReadWrite'] unless valid_caching.include?(caching) @@ -549,11 +538,6 @@ def get_storage_account_type_by_instance_type(instance_type) storage_account_type end - def is_managed_vm?(instance_id) - # The instance id of a Managed VM is GUID whose length is 36 - instance_id.length == UUID_LENGTH - end - def is_stemcell_storage_account?(tags) (STEMCELL_STORAGE_ACCOUNT_TAGS.to_a - tags.to_a).empty? end diff --git a/src/bosh_azure_cpi/lib/cloud/azure/instance_id.rb b/src/bosh_azure_cpi/lib/cloud/azure/instance_id.rb new file mode 100644 index 000000000..5cda281d9 --- /dev/null +++ b/src/bosh_azure_cpi/lib/cloud/azure/instance_id.rb @@ -0,0 +1,114 @@ +module Bosh::AzureCloud + class InstanceId + include Helpers + + # V1 format: + # With unmanaged disks: "[STORAGE-ACCOUNT-NAME]-[AGENT-ID]" + # With managed disks: "[AGENT-ID]" + # V2 format: + # With unmanaged disks: "resource_group_name:[RESOURCE-GROUP-NAME];agent_id:[AGENT-ID];storage_account_name:[STORAGE-ACCOUNT-NAME]" + # With managed disks: "resource_group_name:[RESOURCE-GROUP-NAME];agent_id:[AGENT-ID]" + # + # Usage: + # Creating id for a new VM + # instance_id = InstanceId.create(resource_group_name, agent_id, storage_account_name) # Create V2 instance id with unmanaged disks + # instance_id = InstanceId.create(resource_group_name, agent_id) # Create V2 instance id with managed disks + # Paring id for an existing VM + # instance_id = InstanceId.parse(id, azure_properties) + + VERSION1 = 'v1' # class properties: version (string), id (string), default_resource_group_name (string) + VERSION2 = 'v2' # class properties: version (string), id (json) + + private_class_method :new + + def initialize(version, options = {}) + @version = version + @id = options[:id] + + if version == VERSION1 + @default_resource_group_name = options[:default_resource_group_name] + end + end + + def self.create(resource_group_name, agent_id, storage_account_name = nil) + id = { + 'resource_group_name' => resource_group_name, + 'agent_id' => agent_id + } + id['storage_account_name'] = storage_account_name unless storage_account_name.nil? + new(VERSION2, { :id => id }) + end + + def self.parse(id, azure_properties) + instance_id = nil + + if id.include?(';') + id_hash = Hash.new + array = id.split(';') + array.each do |item| + ret = item.match("^([^:]*):(.*)$") + id_hash[ret[1]] = ret[2] + end + instance_id = new(VERSION2, { :id => id_hash }) + else + instance_id = new(VERSION1, { :id => id, :default_resource_group_name => azure_properties['resource_group_name'] }) + end + + instance_id.validate() + instance_id + end + + def to_s() + return @id if @version == VERSION1 + array = Array.new + @id.each {|key, value| array << "#{key}:#{value}"} + array.sort.join(';') + end + + def resource_group_name() + return @default_resource_group_name if @version == VERSION1 + @id['resource_group_name'] + end + + def vm_name() + return @id if @version == VERSION1 + @id['agent_id'] + end + + def storage_account_name() + if @version == VERSION1 + return nil if use_managed_disks?() + return parse_v1_with_unmanaged_disks(@id)[0] + end + @id['storage_account_name'] + end + + def use_managed_disks?() + return @id.length == UUID_LENGTH if @version == VERSION1 + @id['storage_account_name'].nil? + end + + def validate() + if @version ==VERSION1 + if @id.length != UUID_LENGTH && parse_v1_with_unmanaged_disks(@id)[1].length != UUID_LENGTH + cloud_error("Invalid instance id (version 1) `#{@id}'") + end + else + cloud_error("Invalid resource_group_name in instance id (version 2) `#{@id}'") if resource_group_name().nil? || resource_group_name().empty? + cloud_error("Invalid vm_name in instance id (version 2)' `#{@id}'") if vm_name().nil? || vm_name().empty? + unless storage_account_name().nil? + cloud_error("Invalid storage_account_name in instance id (version 2) `#{@id}'") if storage_account_name().empty? + end + end + end + + private + + # @Return [storage_account_name, agent_id] + def parse_v1_with_unmanaged_disks(id) + ret = id.match('^([^-]*)-(.*)$') + cloud_error("Invalid instance id (version 1) `#{id}'") if ret.nil? + return ret[1], ret[2] + end + end +end diff --git a/src/bosh_azure_cpi/lib/cloud/azure/storage_account_manager.rb b/src/bosh_azure_cpi/lib/cloud/azure/storage_account_manager.rb index 72ecfb1e7..da35ca68d 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure/storage_account_manager.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure/storage_account_manager.rb @@ -137,7 +137,7 @@ def default_storage_account() @logger.debug("The default storage account is not specified in global settings.") storage_accounts = @azure_client2.list_storage_accounts() - location = @azure_client2.get_resource_group()[:location] + location = @azure_client2.get_resource_group(@azure_properties['resource_group_name'])[:location] @logger.debug("Will look for an existing storage account with the tags `#{STEMCELL_STORAGE_ACCOUNT_TAGS}' in the location `#{location}'") storage_account = storage_accounts.find{ |s| s[:location] == location && is_stemcell_storage_account?(s[:tags]) diff --git a/src/bosh_azure_cpi/lib/cloud/azure/vm_manager.rb b/src/bosh_azure_cpi/lib/cloud/azure/vm_manager.rb index edf46db6b..693fc04e3 100644 --- a/src/bosh_azure_cpi/lib/cloud/azure/vm_manager.rb +++ b/src/bosh_azure_cpi/lib/cloud/azure/vm_manager.rb @@ -15,27 +15,31 @@ def initialize(azure_properties, registry_endpoint, disk_manager, disk_manager2, def create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) # network_configurator contains service principal in azure_properties so we must not log it. @logger.info("create(#{instance_id}, #{location}, #{stemcell_info.inspect}, #{resource_pool}, ..., ...)") - + resource_group_name = instance_id.resource_group_name() + vm_name = instance_id.vm_name() vm_size = resource_pool.fetch('instance_type', nil) cloud_error("missing required cloud property `instance_type'.") if vm_size.nil? - network_interfaces = create_network_interfaces(instance_id, location, resource_pool, network_configurator) - availability_set = create_availability_set(location, resource_pool, env) + check_resource_group(resource_group_name, location) + + network_interfaces = create_network_interfaces(resource_group_name, vm_name, location, resource_pool, network_configurator) + availability_set = create_availability_set(resource_group_name, location, resource_pool, env) @disk_manager.resource_pool = resource_pool @disk_manager2.resource_pool = resource_pool # Raise errors if the properties are not valid before doing others. if @use_managed_disks - os_disk = @disk_manager2.os_disk(instance_id, stemcell_info.disk_size) - ephemeral_disk = @disk_manager2.ephemeral_disk(instance_id) + os_disk = @disk_manager2.os_disk(vm_name, stemcell_info.disk_size) + ephemeral_disk = @disk_manager2.ephemeral_disk(vm_name) else - os_disk = @disk_manager.os_disk(instance_id, stemcell_info.disk_size) - ephemeral_disk = @disk_manager.ephemeral_disk(instance_id) + storage_account_name = instance_id.storage_account_name() + os_disk = @disk_manager.os_disk(storage_account_name, vm_name, stemcell_info.disk_size) + ephemeral_disk = @disk_manager.ephemeral_disk(storage_account_name, vm_name) end vm_params = { - :name => instance_id, + :name => vm_name, :location => location, :tags => AZURE_TAGS, :vm_size => vm_size, @@ -58,7 +62,7 @@ def create(instance_id, location, stemcell_info, resource_pool, network_configur when 'linux' vm_params[:ssh_username] = @azure_properties['ssh_user'] vm_params[:ssh_cert_data] = @azure_properties['ssh_public_key'] - vm_params[:custom_data] = get_user_data(instance_id, network_configurator.default_dns) + vm_params[:custom_data] = get_user_data(instance_id.to_s, network_configurator.default_dns) when 'windows' # Generate secure random strings as username and password for Windows VMs # Users do not use this credential to logon to Windows VMs @@ -80,10 +84,10 @@ def create(instance_id, location, stemcell_info, resource_pool, network_configur vm_params[:windows_password] = "#{SecureRandom.uuid}#{SecureRandom.uuid.upcase}".split('').shuffle.join computer_name = generate_windows_computer_name() vm_params[:computer_name] = computer_name - vm_params[:custom_data] = get_user_data(instance_id, network_configurator.default_dns, computer_name) + vm_params[:custom_data] = get_user_data(instance_id.to_s, network_configurator.default_dns, computer_name) end - create_virtual_machine(vm_params, network_interfaces, availability_set) + create_virtual_machine(instance_id, vm_params, network_interfaces, availability_set) vm_params rescue => e @@ -92,39 +96,40 @@ def create(instance_id, location, stemcell_info, resource_pool, network_configur # Including undeleted resources in error message to ask users to delete them manually later error_message = 'This VM fails in provisioning after multiple retries.\n' error_message += 'You need to delete below resource manually after finishing investigation.\n' - error_message += "\t Virtual Machine: #{instance_id}\n" + error_message += "\t Resource Group: #{resource_group_name}\n" + error_message += "\t Virtual Machine: #{vm_name}\n" if @use_managed_disks - os_disk_name = @disk_manager2.generate_os_disk_name(instance_id) + os_disk_name = @disk_manager2.generate_os_disk_name(vm_name) error_message += "\t Managed OS Disk: #{os_disk_name}\n" unless vm_params[:ephemeral_disk].nil? - ephemeral_disk_name = @disk_manager2.generate_ephemeral_disk_name(instance_id) + ephemeral_disk_name = @disk_manager2.generate_ephemeral_disk_name(vm_name) error_message += "\t Managed Ephemeral Disk: #{ephemeral_disk_name}\n" end else - storage_account_name = get_storage_account_name_from_instance_id(instance_id) - os_disk_name = @disk_manager.generate_os_disk_name(instance_id) - error_message += "\t OS disk blob: #{os_disk_name}.vhd in the container #{DISK_CONTAINER} in the storage account #{storage_account_name}\n" + storage_account_name = instance_id.storage_account_name() + os_disk_name = @disk_manager.generate_os_disk_name(vm_name) + error_message += "\t OS disk blob: #{os_disk_name}.vhd in the container #{DISK_CONTAINER} in the storage account #{storage_account_name} in default resource group\n" unless vm_params[:ephemeral_disk].nil? - ephemeral_disk_name = @disk_manager.generate_ephemeral_disk_name(instance_id) - error_message += "\t Ephemeral disk blob: #{ephemeral_disk_name}.vhd in the container #{DISK_CONTAINER} in the storage account #{storage_account_name}\n" + ephemeral_disk_name = @disk_manager.generate_ephemeral_disk_name(vm_name) + error_message += "\t Ephemeral disk blob: #{ephemeral_disk_name}.vhd in the container #{DISK_CONTAINER} in the storage account #{storage_account_name} in default resource group\n" end - error_message += "\t VM status blobs: All blobs which matches the pattern /^#{instance_id}.*status$/ in the container #{DISK_CONTAINER} in the storage account #{storage_account_name}\n" + error_message += "\t VM status blobs: All blobs which matches the pattern /^#{vm_name}.*status$/ in the container #{DISK_CONTAINER} in the storage account #{storage_account_name} in default resource group\n" end else begin if network_interfaces network_interfaces.each do |network_interface| - @azure_client2.delete_network_interface(network_interface[:name]) + @azure_client2.delete_network_interface(resource_group_name, network_interface[:name]) end else - delete_possible_network_interfaces(instance_id) + delete_possible_network_interfaces(resource_group_name, vm_name) end - dynamic_public_ip = @azure_client2.get_public_ip_by_name(instance_id) - @azure_client2.delete_public_ip(instance_id) unless dynamic_public_ip.nil? + dynamic_public_ip = @azure_client2.get_public_ip_by_name(resource_group_name, vm_name) + @azure_client2.delete_public_ip(resource_group_name, vm_name) unless dynamic_public_ip.nil? rescue => error error_message = 'The VM fails in creating but an error is thrown in cleanuping network interfaces or dynamic public IP.\n' error_message += "#{error.inspect}\n#{error.backtrace.join("\n")}" @@ -139,85 +144,106 @@ def create(instance_id, location, stemcell_info, resource_pool, network_configur end def find(instance_id) - @azure_client2.get_virtual_machine_by_name(instance_id) + @azure_client2.get_virtual_machine_by_name(instance_id.resource_group_name(), instance_id.vm_name()) end def delete(instance_id) @logger.info("delete(#{instance_id})") - vm = @azure_client2.get_virtual_machine_by_name(instance_id) + resource_group_name = instance_id.resource_group_name() + vm_name = instance_id.vm_name() + vm = @azure_client2.get_virtual_machine_by_name(resource_group_name, vm_name) unless vm.nil? - @azure_client2.delete_virtual_machine(instance_id) + @azure_client2.delete_virtual_machine(resource_group_name, vm_name) vm[:network_interfaces].each do |network_interface| - @azure_client2.delete_network_interface(network_interface[:name]) + @azure_client2.delete_network_interface(resource_group_name, network_interface[:name]) end else - delete_possible_network_interfaces(instance_id) + delete_possible_network_interfaces(resource_group_name, vm_name) end - dynamic_public_ip = @azure_client2.get_public_ip_by_name(instance_id) - @azure_client2.delete_public_ip(instance_id) unless dynamic_public_ip.nil? + dynamic_public_ip = @azure_client2.get_public_ip_by_name(resource_group_name, vm_name) + @azure_client2.delete_public_ip(resource_group_name, vm_name) unless dynamic_public_ip.nil? - if @use_managed_disks - os_disk_name = @disk_manager2.generate_os_disk_name(instance_id) - @disk_manager2.delete_disk(os_disk_name) + if instance_id.use_managed_disks?() + os_disk_name = @disk_manager2.generate_os_disk_name(vm_name) + @disk_manager2.delete_disk(resource_group_name, os_disk_name) - ephemeral_disk_name = @disk_manager2.generate_ephemeral_disk_name(instance_id) - @disk_manager2.delete_disk(ephemeral_disk_name) + ephemeral_disk_name = @disk_manager2.generate_ephemeral_disk_name(vm_name) + @disk_manager2.delete_disk(resource_group_name, ephemeral_disk_name) else - os_disk_name = @disk_manager.generate_os_disk_name(instance_id) - @disk_manager.delete_disk(os_disk_name) + storage_account_name = instance_id.storage_account_name() + os_disk_name = @disk_manager.generate_os_disk_name(vm_name) + @disk_manager.delete_disk(storage_account_name, os_disk_name) - ephemeral_disk_name = @disk_manager.generate_ephemeral_disk_name(instance_id) - @disk_manager.delete_disk(ephemeral_disk_name) + ephemeral_disk_name = @disk_manager.generate_ephemeral_disk_name(vm_name) + @disk_manager.delete_disk(storage_account_name, ephemeral_disk_name) # Cleanup invalid VM status file - storage_account_name = get_storage_account_name_from_instance_id(instance_id) - @disk_manager.delete_vm_status_files(storage_account_name, instance_id) + @disk_manager.delete_vm_status_files(storage_account_name, vm_name) end end def reboot(instance_id) @logger.info("reboot(#{instance_id})") - @azure_client2.restart_virtual_machine(instance_id) + @azure_client2.restart_virtual_machine( + instance_id.resource_group_name(), + instance_id.vm_name() + ) end def set_metadata(instance_id, metadata) @logger.info("set_metadata(#{instance_id}, #{metadata})") - @azure_client2.update_tags_of_virtual_machine(instance_id, metadata.merge(AZURE_TAGS)) + @azure_client2.update_tags_of_virtual_machine( + instance_id.resource_group_name(), + instance_id.vm_name(), + metadata.merge(AZURE_TAGS) + ) end ## # Attach a disk to the Vm # - # @param [String] instance_id Instance id - # @param [String] disk_name disk name + # @param [InstanceId] instance_id Instance id + # @param [DiskId] disk_id disk id # @return [String] lun - def attach_disk(instance_id, disk_name) - @logger.info("attach_disk(#{instance_id}, #{disk_name})") - if @use_managed_disks && is_managed_vm?(instance_id) + def attach_disk(instance_id, disk_id) + @logger.info("attach_disk(#{instance_id}, #{disk_id})") + disk_name = disk_id.disk_name() + disk_id_tag = {"#{DISK_ID_TAG_PREFIX}-#{disk_name}" => disk_id} + if instance_id.use_managed_disks?() disk_params = { - :disk_name => disk_name, - :caching => @disk_manager2.get_data_disk_caching(disk_name), - :disk_id => @azure_client2.get_managed_disk_by_name(disk_name)[:id], - :managed => true + :disk_name => disk_name, + :caching => disk_id.caching(), + :disk_bosh_id => disk_id.to_s, + :disk_id => @azure_client2.get_managed_disk_by_name(disk_id.resource_group_name(), disk_name)[:id], + :managed => true } else disk_params = { - :disk_name => disk_name, - :caching => @disk_manager.get_data_disk_caching(disk_name), - :disk_uri => @disk_manager.get_disk_uri(disk_name), - :disk_size => @disk_manager.get_disk_size_in_gb(disk_name), - :managed => false + :disk_name => disk_name, + :caching => disk_id.caching(), + :disk_bosh_id => disk_id.to_s, + :disk_uri => @disk_manager.get_data_disk_uri(disk_id), + :disk_size => @disk_manager.get_disk_size_in_gb(disk_id), + :managed => false } end - lun = @azure_client2.attach_disk_to_virtual_machine(instance_id, disk_params) + lun = @azure_client2.attach_disk_to_virtual_machine( + instance_id.resource_group_name(), + instance_id.vm_name(), + disk_params + ) "#{lun}" end - def detach_disk(instance_id, disk_name) - @logger.info("detach_disk(#{instance_id}, #{disk_name})") - @azure_client2.detach_disk_from_virtual_machine(instance_id, disk_name) + def detach_disk(instance_id, disk_id) + @logger.info("detach_disk(#{instance_id}, #{disk_id})") + @azure_client2.detach_disk_from_virtual_machine( + instance_id.resource_group_name(), + instance_id.vm_name(), + disk_id.disk_name() + ) end private @@ -225,13 +251,13 @@ def detach_disk(instance_id, disk_name) # Example - # For Linux: {"registry":{"endpoint":"http://registry:ba42b9e9-fe2c-4d7d-47fb-3eeb78ff49b1@127.0.0.1:6901"},"server":{"name":""},"dns":{"nameserver":["168.63.129.16","8.8.8.8"]}} # For Windows: {"registry":{"endpoint":"http://registry:ba42b9e9-fe2c-4d7d-47fb-3eeb78ff49b1@127.0.0.1:6901"},"instance-id":"","server":{"name":""},"dns":{"nameserver":["168.63.129.16","8.8.8.8"]}} - def get_user_data(vm_name, dns, computer_name = nil) + def get_user_data(instance_id, dns, computer_name = nil) user_data = {registry: {endpoint: @registry_endpoint}} if computer_name - user_data[:'instance-id'] = vm_name + user_data[:'instance-id'] = instance_id user_data[:server] = {name: computer_name} else - user_data[:server] = {name: vm_name} + user_data[:server] = {name: instance_id} end user_data[:dns] = {nameserver: dns} if dns Base64.strict_encode64(JSON.dump(user_data)) @@ -284,7 +310,7 @@ def get_load_balancer(resource_pool) load_balancer end - def create_network_interfaces(instance_id, location, resource_pool, network_configurator) + def create_network_interfaces(resource_group_name, vm_name, location, resource_pool, network_configurator) network_interfaces = [] load_balancer = get_load_balancer(resource_pool) public_ip = get_public_ip(network_configurator.vip_network) @@ -292,13 +318,13 @@ def create_network_interfaces(instance_id, location, resource_pool, network_conf # create dynamic public ip idle_timeout_in_minutes = @azure_properties.fetch('pip_idle_timeout_in_minutes', 4) validate_idle_timeout(idle_timeout_in_minutes) - @azure_client2.create_public_ip(instance_id, location, false, idle_timeout_in_minutes) - public_ip = @azure_client2.get_public_ip_by_name(instance_id) + @azure_client2.create_public_ip(resource_group_name, vm_name, location, false, idle_timeout_in_minutes) + public_ip = @azure_client2.get_public_ip_by_name(resource_group_name, vm_name) end networks = network_configurator.networks networks.each_with_index do |network, index| security_group = get_network_security_group(resource_pool, network) - nic_name = "#{instance_id}-#{index}" + nic_name = "#{vm_name}-#{index}" nic_params = { :name => nic_name, :location => location, @@ -309,20 +335,20 @@ def create_network_interfaces(instance_id, location, resource_pool, network_conf } subnet = get_network_subnet(network) - @azure_client2.create_network_interface(nic_params, subnet, AZURE_TAGS, load_balancer) - network_interfaces.push(@azure_client2.get_network_interface_by_name(nic_name)) + @azure_client2.create_network_interface(resource_group_name, nic_params, subnet, AZURE_TAGS, load_balancer) + network_interfaces.push(@azure_client2.get_network_interface_by_name(resource_group_name, nic_name)) end network_interfaces end - def delete_possible_network_interfaces(instance_id) - network_interfaces = @azure_client2.list_network_interfaces_by_instance_id(instance_id) + def delete_possible_network_interfaces(resource_group_name, vm_name) + network_interfaces = @azure_client2.list_network_interfaces_by_keyword(resource_group_name, vm_name) network_interfaces.each do |network_interface| - @azure_client2.delete_network_interface(network_interface[:name]) + @azure_client2.delete_network_interface(resource_group_name, network_interface[:name]) end end - def create_availability_set(location, resource_pool, env) + def create_availability_set(resource_group_name, location, resource_pool, env) availability_set = nil availability_set_name = resource_pool.fetch('availability_set', nil) @@ -343,7 +369,7 @@ def create_availability_set(location, resource_pool, env) end unless availability_set_name.nil? - availability_set = @azure_client2.get_availability_set_by_name(availability_set_name) + availability_set = @azure_client2.get_availability_set_by_name(resource_group_name, availability_set_name) if availability_set.nil? # In some regions, the max fault domain count of a managed availability set is 2 avset_params = { @@ -356,13 +382,13 @@ def create_availability_set(location, resource_pool, env) } begin @logger.debug("create_availability_set - Creating an availability set `#{avset_params[:name]}'") - @azure_client2.create_availability_set(avset_params) - availability_set = @azure_client2.get_availability_set_by_name(avset_params[:name]) + @azure_client2.create_availability_set(resource_group_name, avset_params) + availability_set = @azure_client2.get_availability_set_by_name(resource_group_name, avset_params[:name]) rescue AzureConflictError => e @logger.debug("create_availability_set - Another process is creating the same availability set `#{avset_params[:name]}'") loop do # TODO: has to sleep to avoid throttling - availability_set = @azure_client2.get_availability_set_by_name(avset_params[:name]) + availability_set = @azure_client2.get_availability_set_by_name(resource_group_name, avset_params[:name]) break unless availability_set.nil? end end @@ -379,13 +405,13 @@ def create_availability_set(location, resource_pool, env) } begin @logger.debug("create_availability_set - Updating the availability set `#{avset_params[:name]}' to a managed one") - @azure_client2.create_availability_set(avset_params) - availability_set = @azure_client2.get_availability_set_by_name(avset_params[:name]) + @azure_client2.create_availability_set(resource_group_name, avset_params) + availability_set = @azure_client2.get_availability_set_by_name(resource_group_name, avset_params[:name]) rescue AzureConflictError => e @logger.debug("create_availability_set - Another process is updating the same availability set `#{avset_params[:name]}'") loop do # TODO: has to sleep to avoid throttling - availability_set = @azure_client2.get_availability_set_by_name(avset_params[:name]) + availability_set = @azure_client2.get_availability_set_by_name(resource_group_name, avset_params[:name]) break unless availability_set[:managed] == @use_managed_disks end end @@ -395,18 +421,19 @@ def create_availability_set(location, resource_pool, env) availability_set end - def create_virtual_machine(vm_params, network_interfaces, availability_set) - instance_id = vm_params[:name] + def create_virtual_machine(instance_id, vm_params, network_interfaces, availability_set) + resource_group_name = instance_id.resource_group_name() + vm_name = instance_id.vm_name() provisioning_fail_retries = 2 retry_count = 0 begin @keep_failed_vm = false - @azure_client2.create_virtual_machine(vm_params, network_interfaces, availability_set) + @azure_client2.create_virtual_machine(resource_group_name, vm_params, network_interfaces, availability_set) rescue => e retry_create = false if e.instance_of?(AzureAsynchronousError) && e.status == PROVISIONING_STATE_FAILED if (retry_count += 1) <= provisioning_fail_retries - @logger.info("create_virtual_machine - Retry #{retry_count}: will retry to create the virtual machine #{instance_id} which failed in provisioning") + @logger.info("create_virtual_machine - Retry #{retry_count}: will retry to create the virtual machine #{vm_name} which failed in provisioning") retry_create = true else # Keep failed VM for advanced investigation only if the VM fails in provisioning after multiple retries @@ -416,27 +443,27 @@ def create_virtual_machine(vm_params, network_interfaces, availability_set) unless @keep_failed_vm begin - @logger.info("create_virtual_machine - cleanup resources of the failed virtual machine #{instance_id}") - @azure_client2.delete_virtual_machine(instance_id) + @logger.info("create_virtual_machine - cleanup resources of the failed virtual machine #{vm_name} from resource group #{resource_group_name}") + @azure_client2.delete_virtual_machine(resource_group_name, vm_name) if @use_managed_disks - os_disk_name = @disk_manager2.generate_os_disk_name(instance_id) - @disk_manager2.delete_disk(os_disk_name) + os_disk_name = @disk_manager2.generate_os_disk_name(vm_name) + @disk_manager2.delete_disk(resource_group_name, os_disk_name) else - os_disk_name = @disk_manager.generate_os_disk_name(instance_id) - @disk_manager.delete_disk(os_disk_name) + storage_account_name = instance_id.storage_account_name() + os_disk_name = @disk_manager.generate_os_disk_name(vm_name) + @disk_manager.delete_disk(storage_account_name, os_disk_name) # Cleanup invalid VM status file - storage_account_name = get_storage_account_name_from_instance_id(instance_id) - @disk_manager.delete_vm_status_files(storage_account_name, instance_id) + @disk_manager.delete_vm_status_files(storage_account_name, vm_name) end unless vm_params[:ephemeral_disk].nil? if @use_managed_disks - ephemeral_disk_name = @disk_manager2.generate_ephemeral_disk_name(instance_id) - @disk_manager2.delete_disk(ephemeral_disk_name) + ephemeral_disk_name = @disk_manager2.generate_ephemeral_disk_name(vm_name) + @disk_manager2.delete_disk(resource_group_name, ephemeral_disk_name) else - ephemeral_disk_name = @disk_manager.generate_ephemeral_disk_name(instance_id) - @disk_manager.delete_disk(ephemeral_disk_name) + ephemeral_disk_name = @disk_manager.generate_ephemeral_disk_name(vm_name) + @disk_manager.delete_disk(storage_account_name, ephemeral_disk_name) end end rescue => error @@ -452,5 +479,12 @@ def create_virtual_machine(vm_params, network_interfaces, availability_set) raise e end end + + def check_resource_group(resource_group_name, location) + resource_group = @azure_client2.get_resource_group(resource_group_name) + return true unless resource_group.nil? + # If resource group does not exist, create it + @azure_client2.create_resource_group(resource_group_name, location) + end end end diff --git a/src/bosh_azure_cpi/spec/integration/azure_cpi_spec.rb b/src/bosh_azure_cpi/spec/integration/azure_cpi_spec.rb index ce7c2173b..f6d2365b4 100644 --- a/src/bosh_azure_cpi/spec/integration/azure_cpi_spec.rb +++ b/src/bosh_azure_cpi/spec/integration/azure_cpi_spec.rb @@ -7,7 +7,7 @@ before(:all) do @subscription_id = ENV['BOSH_AZURE_SUBSCRIPTION_ID'] || raise("Missing BOSH_AZURE_SUBSCRIPTION_ID") - @resource_group_name = ENV['BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_VMS'] || raise("Missing BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_VMS") + @resource_group_name = ENV['BOSH_AZURE_DEFAULT_RESOURCE_GROUP_NAME'] || raise("Missing BOSH_AZURE_DEFAULT_RESOURCE_GROUP_NAME") @tenant_id = ENV['BOSH_AZURE_TENANT_ID'] || raise("Missing BOSH_AZURE_TENANT_ID") @client_id = ENV['BOSH_AZURE_CLIENT_ID'] || raise("Missing BOSH_AZURE_CLIENT_ID") @client_secret = ENV['BOSH_AZURE_CLIENT_SECRET'] || raise("Missing BOSH_AZURE_CLIENT_SECRET") @@ -192,7 +192,7 @@ } } it 'merges the context into the cloud_properties' do - result = run_cpi({'method'=>'has_vm', 'arguments'=>['fake-instance-id'], 'context'=> context}) + result = run_cpi({'method'=>'has_vm', 'arguments'=>["#{SecureRandom.uuid}"], 'context'=> context}) expect(result.keys).to eq(%w(result error log)) diff --git a/src/bosh_azure_cpi/spec/integration/lifecycle_spec.rb b/src/bosh_azure_cpi/spec/integration/lifecycle_spec.rb index f0dd3bc87..deb19fd32 100644 --- a/src/bosh_azure_cpi/spec/integration/lifecycle_spec.rb +++ b/src/bosh_azure_cpi/spec/integration/lifecycle_spec.rb @@ -13,8 +13,8 @@ @stemcell_id = ENV['BOSH_AZURE_STEMCELL_ID'] || raise("Missing BOSH_AZURE_STEMCELL_ID") @ssh_public_key = ENV['BOSH_AZURE_SSH_PUBLIC_KEY'] || raise("Missing BOSH_AZURE_SSH_PUBLIC_KEY") @default_security_group = ENV['BOSH_AZURE_DEFAULT_SECURITY_GROUP'] || raise("Missing BOSH_AZURE_DEFAULT_SECURITY_GROUP") - @resource_group_name_for_vms = ENV['BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_VMS'] || raise("Missing BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_VMS") - @resource_group_name_for_network = ENV['BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_NETWORK'] || raise("Missing BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_NETWORK") + @default_resource_group_name = ENV['BOSH_AZURE_DEFAULT_RESOURCE_GROUP_NAME'] || raise("Missing BOSH_AZURE_DEFAULT_RESOURCE_GROUP_NAME") + @additional_resource_group_name = ENV['BOSH_AZURE_ADDITIONAL_RESOURCE_GROUP_NAME'] || raise("Missing BOSH_AZURE_ADDITIONAL_RESOURCE_GROUP_NAME") @primary_public_ip = ENV['BOSH_AZURE_PRIMARY_PUBLIC_IP'] || raise("Missing BOSH_AZURE_PRIMARY_PUBLIC_IP") @secondary_public_ip = ENV['BOSH_AZURE_SECONDARY_PUBLIC_IP'] || raise("Missing BOSH_AZURE_SECONDARY_PUBLIC_IP") end @@ -35,7 +35,7 @@ 'azure' => { 'environment' => azure_environment, 'subscription_id' => @subscription_id, - 'resource_group_name' => @resource_group_name_for_vms, + 'resource_group_name' => @default_resource_group_name, 'tenant_id' => @tenant_id, 'client_id' => @client_id, 'client_secret' => @client_secret, @@ -215,7 +215,7 @@ end context 'multiple nics' do - let(:instance_type) { 'Standard_D2' } + let(:instance_type) { 'Standard_D2_v2' } let(:network_spec) { { 'network_a' => { @@ -305,7 +305,7 @@ 'network_a' => { 'type' => 'dynamic', 'cloud_properties' => { - 'resource_group_name' => @resource_group_name_for_network, + 'resource_group_name' => @additional_resource_group_name, 'virtual_network_name' => vnet_name, 'subnet_name' => subnet_name } @@ -332,7 +332,7 @@ 'type' => 'vip', 'ip' => @secondary_public_ip, 'cloud_properties' => { - 'resource_group_name' => @resource_group_name_for_network + 'resource_group_name' => @additional_resource_group_name } } } @@ -343,6 +343,61 @@ end end + context 'When the resource group name is specified for the vm' do + let(:resource_pool) { + { + 'instance_type' => instance_type, + 'resource_group_name' => @additional_resource_group_name, + 'availability_set' => SecureRandom.uuid, + 'ephemeral_disk' => { + 'size' => 20480 + } + } + } + + let(:network_spec) { + { + 'network_a' => { + 'type' => 'dynamic', + 'cloud_properties' => { + 'virtual_network_name' => vnet_name, + 'subnet_name' => subnet_name + } + } + } + } + + it 'should exercise the vm lifecycle' do + vm_lifecycle(2) do |instance_id| + disk_id = cpi.create_disk(2048, {}, instance_id) + expect(disk_id).not_to be_nil + @disk_id_pool.push(disk_id) + + cpi.attach_disk(instance_id, disk_id) + + snapshot_metadata = vm_metadata.merge( + bosh_data: 'bosh data', + instance_id: 'instance', + agent_id: 'agent', + director_name: 'Director', + director_uuid: SecureRandom.uuid + ) + + snapshot_id = cpi.snapshot_disk(disk_id, snapshot_metadata) + expect(snapshot_id).not_to be_nil + + cpi.delete_snapshot(snapshot_id) + Bosh::Common.retryable(tries: 20, on: Bosh::Clouds::DiskNotAttached, sleep: lambda { |n, _| [2**(n-1), 30].min }) do + cpi.detach_disk(instance_id, disk_id) + true + end + cpi.delete_disk(disk_id) + @disk_id_pool.delete(disk_id) + end + end + + end + context 'when assigning dynamic public IP to VM' do let(:network_spec) { { diff --git a/src/bosh_azure_cpi/spec/integration/managed_disks_migration_spec.rb b/src/bosh_azure_cpi/spec/integration/managed_disks_migration_spec.rb index 241e87091..ff9666079 100644 --- a/src/bosh_azure_cpi/spec/integration/managed_disks_migration_spec.rb +++ b/src/bosh_azure_cpi/spec/integration/managed_disks_migration_spec.rb @@ -13,7 +13,8 @@ @stemcell_id = ENV['BOSH_AZURE_STEMCELL_ID'] || raise("Missing BOSH_AZURE_STEMCELL_ID") @ssh_public_key = ENV['BOSH_AZURE_SSH_PUBLIC_KEY'] || raise("Missing BOSH_AZURE_SSH_PUBLIC_KEY") @default_security_group = ENV['BOSH_AZURE_DEFAULT_SECURITY_GROUP'] || raise("Missing BOSH_AZURE_DEFAULT_SECURITY_GROUP") - @resource_group_name_for_vms = ENV['BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_VMS'] || raise("Missing BOSH_AZURE_RESOURCE_GROUP_NAME_FOR_VMS") + @default_resource_group_name = ENV['BOSH_AZURE_DEFAULT_RESOURCE_GROUP_NAME'] || raise("Missing BOSH_AZURE_DEFAULT_RESOURCE_GROUP_NAME") + @additional_resource_group_name = ENV['BOSH_AZURE_ADDITIONAL_RESOURCE_GROUP_NAME'] || raise("Missing BOSH_AZURE_ADDITIONAL_RESOURCE_GROUP_NAME") end let(:azure_environment) { ENV.fetch('BOSH_AZURE_ENVIRONMENT', 'AzureCloud') } @@ -23,7 +24,12 @@ let(:instance_type) { ENV.fetch('BOSH_AZURE_INSTANCE_TYPE', 'Standard_D1_v2') } let(:vm_metadata) { { deployment: 'deployment', job: 'cpi_spec', index: '0', delete_me: 'please' } } let(:network_spec) { {} } - let(:resource_pool) { { 'instance_type' => instance_type } } + let(:resource_pool) { + { + 'instance_type' => instance_type, + 'resource_group_name' => @additional_resource_group_name + } + } let(:snapshot_metadata) { vm_metadata.merge( bosh_data: 'bosh data', @@ -39,7 +45,7 @@ 'azure' => { 'environment' => azure_environment, 'subscription_id' => @subscription_id, - 'resource_group_name' => @resource_group_name_for_vms, + 'resource_group_name' => @default_resource_group_name, 'storage_account_name' => storage_account_name, 'tenant_id' => @tenant_id, 'client_id' => @client_id, @@ -174,6 +180,7 @@ { 'instance_type' => instance_type, 'availability_set' => SecureRandom.uuid, + 'platform_fault_domain_count' => 2, 'ephemeral_disk' => { 'size' => 20480 } diff --git a/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/README.md b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/README.md new file mode 100644 index 000000000..1a3581df4 --- /dev/null +++ b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/README.md @@ -0,0 +1,22 @@ +# Manual test + +## Purpose + +To verify the feature of `multiple resource group` for VMs, make sure it is compatible with old versions. + +## Environment setup + +1. setup bosh registry following [this guidance](../../../../../docs/development.md). + +1. prepare bosh environment. If you have deployed a bosh director by this [guidance](../../../../../docs/get-started/via-arm-templates/deploy-bosh-via-arm-templates.md) and uploaded a stemcell, you have everything prepared. + +1. fill related information in ./cpi.cfg to use resource created by previous step. + +1. change `stemcell_id` in ./test.cfg to use the stemcell you have uploaded in previous step. + +## Run test + +```bash + ruby ./migrate_to_new_rg.rb +``` + diff --git a/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/cpi.cfg b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/cpi.cfg new file mode 100644 index 000000000..23d20a8dd --- /dev/null +++ b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/cpi.cfg @@ -0,0 +1,18 @@ +--- +azure: + environment: AzureCloud + subscription_id: replace-me + storage_account_name: replace-me + resource_group_name: replace-me + tenant_id: replace-me + client_id: replace-me + client_secret: replace-me + ssh_user: vcap + ssh_public_key: replace-me + default_security_group: nsg-bosh + debug_mode: false + use_managed_disks: false +registry: + endpoint: http://127.0.0.1:25695 + user: admin + password: admin diff --git a/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/helpers.rb b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/helpers.rb new file mode 100644 index 000000000..65c582306 --- /dev/null +++ b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/helpers.rb @@ -0,0 +1,128 @@ +#!/usr/bin/env ruby +require "irb" +require "irb/completion" +require "ostruct" +require "optparse" +require "psych" +require "git" +require 'fileutils' + + +test_config_file = File.expand_path('../test.cfg', __FILE__) +test_config = Psych.load_file(test_config_file) +@additional_rg_name = test_config['additional_rg_name'] +@upstream_repo = test_config['upstream_repo'] +@test_repo = test_config['test_repo'] +@test_branch = test_config['test_branch'] +@stemcell_id = test_config['stemcell_id'] +@vm_storage_account_name = test_config['vm_storage_account_name'] + +cpi_config_file = File.expand_path('../cpi.cfg', __FILE__) +@base_config = Psych.load_file(cpi_config_file) + +def checkout_repo(repo, dir: '/tmp/cpi-test', branch: 'master', force_renew: false) + name = "#{File.basename(repo)}-#{branch}" + dest_dir = File.join(dir, name) + return dest_dir if File.exist?(dest_dir) && !force_renew + + FileUtils.rm_rf(dest_dir) if File.exist?(dest_dir) + Dir.mkdir(dir) unless File.exist?(dir) + + g = Git.clone(repo, name, :path => dir) + g.checkout(branch) + g.dir.to_s +end + +def load_bosh_azure_cpi(cpi_dir, config) + $LOAD_PATH.unshift File.join(cpi_dir, 'src/bosh_azure_cpi/lib') + path = File.join(cpi_dir, 'src/bosh_azure_cpi/lib/bosh_azure_cpi.rb') + + Dir[File.join(cpi_dir, 'src/bosh_azure_cpi/lib/**/**/**')]. + select { |f| File.extname(f) == '.rb' }. + each { |p| load p } + + $LOAD_PATH.shift + + cloud_config = OpenStruct.new(:logger => Logger.new(STDOUT)) + Bosh::Clouds::Config.configure(cloud_config) + + cpi = Bosh::AzureCloud::Cloud.new(config) + + cpi +end + +# return instance of cpi +def get_cpi(repo, branch, managed, force_renew: false) + cpi_dir = checkout_repo(repo, branch: branch, force_renew: force_renew) + config = @base_config.clone + if managed + config['azure']['use_managed_disks'] = true + else + config['azure']['use_managed_disks'] = false + end + + load_bosh_azure_cpi(cpi_dir, config) +end + +def create_vm(cpi, resource_pool) + stemcell_id = @stemcell_id + + agent_id = SecureRandom.uuid + + networks = JSON('{"private":{"cloud_properties":{"subnet_name":"Bosh","virtual_network_name":"boshvnet-crp"},"default":["dns","gateway"],"dns":["168.63.129.16","8.8.8.8"],"gateway":"10.0.0.1","ip":"10.0.0.57","netmask":"255.255.255.0","type":"manual"}}') + + instance_id = cpi.create_vm(agent_id, stemcell_id, resource_pool, networks) + check_vm(cpi, instance_id) + + instance_id +end + +def delete_vm(cpi, instance_id) + cpi.delete_vm(instance_id) +end + +def check_vm(cpi, instance_id) + has_vm = cpi.has_vm?(instance_id) + raise "vm #{instance_id} not found" unless has_vm + cpi.reboot_vm(instance_id) + cpi.set_vm_metadata(instance_id, {"key" => "value"}) +end + + +def create_disk(cpi, disk_pool: {}, instance_id: nil) + disk_id = cpi.create_disk(1024, {},instance_id) + check_disk(cpi, disk_id) + + disk_id +end + +def check_disk(cpi, disk_id, instance_id: nil) + has_disk = cpi.has_disk?(disk_id) + raise "disk #{disk_id} not found" unless has_disk + + unless instance_id.nil? + disks = cpi.get_disks(instance_id) + raise "get_disks error - not found #{disk_id} in #{disks}" unless disks.include?(disk_id) + end +end + +def attach_disk(cpi, instance_id, disk_id) + cpi.attach_disk(instance_id, disk_id) + check_disk(cpi, disk_id, instance_id: instance_id) +end + +def detach_disk(cpi, instance_id, disk_id) + cpi.detach_disk(instance_id, disk_id) +end + +def delete_disk(cpi, disk_id) + cpi.delete_disk(disk_id) +end + +def create_snapshot(cpi, disk_id) + cpi.snapshot_disk(disk_id) +end + +def delete_snapshot(cpi, snapshot_id) + cpi.snapshot_disk(snapshot_id) +end diff --git a/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/migrate_to_new_rg.rb b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/migrate_to_new_rg.rb new file mode 100644 index 000000000..10ea1d067 --- /dev/null +++ b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/migrate_to_new_rg.rb @@ -0,0 +1,445 @@ +#!/usr/bin/env ruby +load 'helpers.rb' + +# --------------------------------- test ------------------------------------# +# 1. migrate: unmanaged v24 -> unmanaged vNext + +# 1.1 create resources using cpi v24 +cpi = get_cpi(@upstream_repo, 'v24', false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS' +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +# 1.2 check and delete resources using new cpi +cpi = get_cpi(@test_repo, @test_branch, false) + +check_vm(cpi, instance_id) +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + + + +# 2. migrate: managed v24 -> managed vNext + +# 2.1 create resources using cpi v24 +cpi = get_cpi(@upstream_repo, 'v24', true) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset' +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +# 2.2 check and delete resources using new cpi +cpi = get_cpi(@test_repo, @test_branch, true) + +check_vm(cpi, instance_id) +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +# 3. migrate: unmanaged v24 -> managed vNext + +# 3.1 create resources using cpi v24 +cpi = get_cpi(@upstream_repo, 'v24', false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS' +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +# 3.2 check and delete resources using new cpi +cpi = get_cpi(@test_repo, @test_branch, true) + +check_vm(cpi, instance_id) +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + + +# 4. attach v24 unmanaged disk to vNext unmanaged vm +# 4.1 create resources using cpi v24 +cpi = get_cpi(@upstream_repo, 'v24', false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS' +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) + +delete_vm(cpi, instance_id) + +# 4.2 check if the disks created by v24 is workable with the vm created by vNext +cpi = get_cpi(@test_repo, @test_branch, false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +# 5. attach v24 managed disk to vNext managed vm +# 5.1 create resources using cpi v24 +cpi = get_cpi(@upstream_repo, 'v24', true) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset' +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) + +delete_vm(cpi, instance_id) + +# 5.2 check if the disks created by v24 is workable with the vm created by vNext +cpi = get_cpi(@test_repo, @test_branch, true) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +# 6. attach v24 unmanaged disk to vNext managed vm +# 6.1 create resources using cpi v24 +cpi = get_cpi(@upstream_repo, 'v24', false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS' +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) + +delete_vm(cpi, instance_id) + +# 6.2 check if the disks created by v24 is workable with the vm created by vNext +cpi = get_cpi(@test_repo, @test_branch, true) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +# 7. attach a migrated disk (v21 unmanaged to v24 managed) to vNext managed vm +# 7.1 create resources using cpi v21 +cpi = get_cpi(@upstream_repo, 'v21', false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS' +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) + +delete_vm(cpi, instance_id) + +# 7.2 migrate v21 unmanaged disk to v24 managed disk +cpi = get_cpi(@upstream_repo, 'v24', true) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset' +} + +instance_id = create_vm(cpi, resource_pool) + +attach_disk(cpi, instance_id, disk_id_1) # migrate disk_id_x to managed disk +attach_disk(cpi, instance_id, disk_id_2) + +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_vm(cpi, instance_id) + +# 7.3 check if the migrated disks are workable with the vm created by vNext +cpi = get_cpi(@test_repo, @test_branch, true) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +# 8. attach vNext unmanged disk to v24 unmanaged vm +# 8.1 create resources using cpi v24 +cpi = get_cpi(@upstream_repo, 'v24', false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) + +# 8.2 check if the disks created by vNext is workable with the vm created by v24 +cpi = get_cpi(@test_repo, @test_branch, false) + +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +# 9. attach vNext managed disk to v24 managed vm +# 9.1 create resources using cpi vNext +cpi = get_cpi(@upstream_repo, 'v24', true) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) + +# 9.2 check if the disks created by vNext is workable with the vm created by v24 +cpi = get_cpi(@test_repo, @test_branch, true) + +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +# 10. migrate: unmanaged vNext -> managed vNext + +# 10.1 create unmanaged resources +cpi = get_cpi(@test_repo, @test_branch, false) + +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'unmanaged-avset', + 'storage_account_name' => @vm_storage_account_name, + 'storage_account_type' => 'Standard_LRS', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) +disk_id_1 = create_disk(cpi, instance_id: instance_id) +disk_id_2 = create_disk(cpi, instance_id: nil) +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +# 10.2 check and delete vm +cpi = get_cpi(@test_repo, @test_branch, true) + +check_vm(cpi, instance_id) +check_disk(cpi, disk_id_1, instance_id: instance_id) +check_disk(cpi, disk_id_2, instance_id: instance_id) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_vm(cpi, instance_id) + +# 10.3 create new managed vm and attach existed disk to it. +resource_pool = { + 'instance_type' => 'Standard_F2', + 'assign_dynamic_public_ip' => true, + 'availability_set' => 'managed-avset', + 'resource_group_name' => @additional_rg_name +} + +instance_id = create_vm(cpi, resource_pool) + +attach_disk(cpi, instance_id, disk_id_1) +attach_disk(cpi, instance_id, disk_id_2) + +detach_disk(cpi, instance_id, disk_id_1) +detach_disk(cpi, instance_id, disk_id_2) + +delete_disk(cpi, disk_id_1) +delete_disk(cpi, disk_id_2) + +delete_vm(cpi, instance_id) + +puts 'PASS' diff --git a/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/test.cfg b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/test.cfg new file mode 100644 index 000000000..bcaf216ba --- /dev/null +++ b/src/bosh_azure_cpi/spec/manual_tests/resource_group_name/test.cfg @@ -0,0 +1,10 @@ +--- +upstream_repo: https://github.com/cloudfoundry-incubator/bosh-azure-cpi-release + +test_repo: https://github.com/gossion/bosh-azure-cpi-release +test_branch: rg-for-vms + +stemcell_id: replace-me # e.g. bosh-stemcell-8abbb5f1-2c59-4fc2-94d8-bf557f9f2cb4 + +vm_storage_account_name: replace-me # e.g. cpivmstorageaccount +additional_rg_name: replace-me #e.g. cpi-additional-resource-group diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/attach_disk_to_virtual_machine_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/attach_disk_to_virtual_machine_spec.rb index aa5f0989a..8f3b4e0ae 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/attach_disk_to_virtual_machine_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/attach_disk_to_virtual_machine_spec.rb @@ -15,7 +15,7 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -32,15 +32,17 @@ let(:disk_name) { "fake-disk-name" } let(:caching) { "ReadWrite" } let(:vm_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Compute/virtualMachines/#{vm_name}?api-version=#{api_version_compute}" } + let(:disk_bosh_id) { "fake-bosh-id" } context "when attaching a managed disk" do let(:disk_id) { "fake-disk-id" } let(:disk_params) { { - :disk_name => disk_name, - :caching => caching, - :disk_id => disk_id, - :managed => true + :disk_name => disk_name, + :caching => caching, + :disk_id => disk_id, + :managed => true, + :disk_bosh_id => disk_bosh_id } } let(:response_body) { @@ -48,7 +50,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => {}, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -69,7 +71,9 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => { + "disk-id-#{disk_name}" => disk_bosh_id + }, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -116,7 +120,7 @@ :headers => {}) expect( - azure_client2.attach_disk_to_virtual_machine(vm_name, disk_params) + azure_client2.attach_disk_to_virtual_machine(resource_group, vm_name, disk_params) ).to eq(lun) end end @@ -126,11 +130,12 @@ let(:disk_size) { 42 } let(:disk_params) { { - :disk_name => disk_name, - :caching => caching, - :disk_uri => disk_uri, - :disk_size => disk_size, - :managed => false + :disk_name => disk_name, + :caching => caching, + :disk_uri => disk_uri, + :disk_size => disk_size, + :managed => false, + :disk_bosh_id => disk_bosh_id } } let(:lun) { 2 } @@ -139,7 +144,9 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => { + "disk-id-#{disk_name}" => disk_bosh_id + }, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -169,7 +176,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => {}, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -209,7 +216,7 @@ :headers => {}) expect( - azure_client2.attach_disk_to_virtual_machine(vm_name, disk_params) + azure_client2.attach_disk_to_virtual_machine(resource_group, vm_name, disk_params) ).to eq(2) end end @@ -220,7 +227,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => {}, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -269,7 +276,7 @@ :headers => {}) expect( - azure_client2.attach_disk_to_virtual_machine(vm_name, disk_params) + azure_client2.attach_disk_to_virtual_machine(resource_group, vm_name, disk_params) ).to eq(2) end end @@ -289,7 +296,7 @@ :headers => {}) expect { - azure_client2.attach_disk_to_virtual_machine(vm_name, disk_params) + azure_client2.attach_disk_to_virtual_machine(resource_group, vm_name, disk_params) }.to raise_error /attach_disk_to_virtual_machine - cannot find the virtual machine by name/ end end @@ -300,7 +307,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => {}, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -330,7 +337,7 @@ :headers => {}) expect { - azure_client2.attach_disk_to_virtual_machine(vm_name, disk_params) + azure_client2.attach_disk_to_virtual_machine(resource_group, vm_name, disk_params) }.to raise_error /attach_disk_to_virtual_machine - cannot find an available lun in the virtual machine/ end end @@ -341,7 +348,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => {}, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -379,7 +386,7 @@ ) expect { - azure_client2.attach_disk_to_virtual_machine(vm_name, disk_params) + azure_client2.attach_disk_to_virtual_machine(resource_group, vm_name, disk_params) }.to raise_error Bosh::AzureCloud::AzureInternalError end @@ -416,7 +423,7 @@ :headers => {}) expect { - azure_client2.attach_disk_to_virtual_machine(vm_name, disk_params) + azure_client2.attach_disk_to_virtual_machine(resource_group, vm_name, disk_params) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/availability_set_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/availability_set_spec.rb index 409382f52..0c193789b 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/availability_set_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/availability_set_spec.rb @@ -15,7 +15,7 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -52,7 +52,7 @@ } } } - + context "When managed is null" do it "should raise no error" do stub_request(:post, token_uri).to_return( @@ -74,7 +74,7 @@ :headers => {}) expect { - azure_client2.create_availability_set(avset_params) + azure_client2.create_availability_set(resource_group, avset_params) }.not_to raise_error end end @@ -104,7 +104,7 @@ :headers => {}) expect { - azure_client2.create_availability_set(avset_params) + azure_client2.create_availability_set(resource_group, avset_params) }.not_to raise_error end end @@ -137,7 +137,7 @@ :headers => {}) expect { - azure_client2.create_availability_set(avset_params) + azure_client2.create_availability_set(resource_group, avset_params) }.not_to raise_error end end @@ -195,7 +195,7 @@ :headers => {}) expect( - azure_client2.get_availability_set_by_name(avset_name) + azure_client2.get_availability_set_by_name(resource_group, avset_name) ).to eq(avset) end end @@ -227,7 +227,7 @@ :headers => {}) expect( - azure_client2.get_availability_set_by_name(avset_name) + azure_client2.get_availability_set_by_name(resource_group, avset_name) ).to eq(avset) end end @@ -247,7 +247,7 @@ :headers => {}) expect( - azure_client2.get_availability_set_by_name(avset_name) + azure_client2.get_availability_set_by_name(resource_group, avset_name) ).to eq(avset) end end @@ -272,7 +272,7 @@ :headers => {}) expect( - azure_client2.get_availability_set_by_name(avset_name) + azure_client2.get_availability_set_by_name(resource_group, avset_name) ).to eq(avset) end end @@ -297,7 +297,7 @@ :headers => {}) expect( - azure_client2.get_availability_set_by_name(avset_name) + azure_client2.get_availability_set_by_name(resource_group, avset_name) ).to eq(avset) end end @@ -306,7 +306,7 @@ describe "#delete_availability_set" do let(:avset_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Compute/availabilitySets/#{avset_name}?api-version=#{api_version_compute}" } - + context "when token is valid, delete operation is accepted and completed" do it "should delete the availability set without error" do stub_request(:post, token_uri).to_return( @@ -322,7 +322,7 @@ :headers => {}) expect { - azure_client2.delete_availability_set(avset_name) + azure_client2.delete_availability_set(resource_group, avset_name) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/azure_client2_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/azure_client2_spec.rb index 22149173f..261d56065 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/azure_client2_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/azure_client2_spec.rb @@ -14,7 +14,8 @@ let(:subscription_id) { mock_azure_properties['subscription_id'] } let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:default_resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -50,7 +51,7 @@ resource_type, name: name, others: others) - ).to eq("/subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/a/b/c/d") + ).to eq("/subscriptions/#{subscription_id}/resourceGroups/#{default_resource_group}/providers/a/b/c/d") end it "returns the right url if name is not provided" do @@ -85,7 +86,7 @@ expect(azure_client2.rest_api_url( resource_provider, resource_type) - ).to eq("/subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/a/b") + ).to eq("/subscriptions/#{subscription_id}/resourceGroups/#{default_resource_group}/providers/a/b") end end @@ -523,8 +524,8 @@ describe "#get_resource_group" do let(:url) { "/subscriptions/#{subscription_id}/resourceGroups/#{resource_group}" } - let(:api_version_1) { AZURE_RESOURCE_PROVIDER_GROUP } - let(:resource_uri) { "https://management.azure.com/#{url}?api-version=#{api_version_1}" } + let(:group_api_version) { AZURE_RESOURCE_PROVIDER_GROUP } + let(:resource_uri) { "https://management.azure.com/#{url}?api-version=#{group_api_version}" } let(:response_body) { { "id" => "fake-id", @@ -560,7 +561,7 @@ :body => '', :headers => {}) expect( - azure_client2.get_resource_group() + azure_client2.get_resource_group(resource_group) ).to be_nil end @@ -577,13 +578,13 @@ :body => response_body, :headers => {}) expect( - azure_client2.get_resource_group() + azure_client2.get_resource_group(resource_group) ).to eq(fake_resource_group) end end end - describe "#list_network_interfaces_by_instance_id" do + describe "#list_network_interfaces_by_keyword" do let(:network_interfaces_url) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Network/networkInterfaces?api-version=#{api_version}" } let(:instance_id) { "fake-instance-id" } let(:result) { @@ -661,7 +662,7 @@ }) expect( - azure_client2.list_network_interfaces_by_instance_id(instance_id) + azure_client2.list_network_interfaces_by_keyword(resource_group, instance_id) ).to eq([network_interface]) end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/create_load_balancer_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/create_load_balancer_spec.rb index 8c56db24e..9c1915879 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/create_load_balancer_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/create_load_balancer_spec.rb @@ -51,7 +51,7 @@ describe "#create_load_balancer" do let(:load_balancer_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Network/loadBalancers/#{load_balancer_name}?api-version=#{api_version}" } - + context "when token is valid, create operation is accepted and completed" do it "should create a load balancer without error" do stub_request(:post, token_uri).to_return( diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/create_network_interface_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/create_network_interface_spec.rb index ac93f304e..d7cb78304 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/create_network_interface_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/create_network_interface_spec.rb @@ -14,7 +14,7 @@ let(:subscription_id) { mock_azure_properties['subscription_id'] } let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -28,7 +28,7 @@ describe "#create_network_interface" do let(:network_interface_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Network/networkInterfaces/#{nic_name}?api-version=#{api_version}" } - + context "when token is valid, create operation is accepted and completed" do it "should create a network interface without error" do nic_params = { @@ -69,7 +69,7 @@ :headers => {}) expect { - azure_client2.create_network_interface(nic_params, subnet, load_balancer) + azure_client2.create_network_interface(resource_group, nic_params, subnet, load_balancer) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/create_public_ip_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/create_public_ip_spec.rb index 9c773e26e..d110e86b7 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/create_public_ip_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/create_public_ip_spec.rb @@ -14,7 +14,7 @@ let(:subscription_id) { mock_azure_properties['subscription_id'] } let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -27,7 +27,7 @@ describe "#create_public_ip" do let(:public_ip_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Network/publicIPAddresses/#{public_ip_name}?api-version=#{api_version}" } - + let(:location) { "fake-location" } context "when token is valid, create operation is accepted and completed" do @@ -52,12 +52,12 @@ is_static = true expect { - azure_client2.create_public_ip(public_ip_name, location, is_static) + azure_client2.create_public_ip(resource_group, public_ip_name, location, is_static) }.not_to raise_error is_static = false expect { - azure_client2.create_public_ip(public_ip_name, location, is_static) + azure_client2.create_public_ip(resource_group, public_ip_name, location, is_static) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/create_resource_group_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/create_resource_group_spec.rb new file mode 100644 index 000000000..672a5a2b6 --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/create_resource_group_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' +require 'webmock/rspec' + +WebMock.disable_net_connect!(allow_localhost: true) + +describe Bosh::AzureCloud::AzureClient2 do + let(:logger) { Bosh::Clouds::Config.logger } + let(:azure_client2) { + Bosh::AzureCloud::AzureClient2.new( + mock_cloud_options["properties"]["azure"], + logger + ) + } + let(:subscription_id) { mock_azure_properties['subscription_id'] } + let(:tenant_id) { mock_azure_properties['tenant_id'] } + let(:token_api_version) { AZURE_API_VERSION } + let(:group_api_version) { AZURE_RESOURCE_PROVIDER_GROUP } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:request_id) { "fake-request-id" } + + let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{token_api_version}" } + + let(:valid_access_token) { "valid-access-token" } + + let(:expires_on) { (Time.now+1800).to_i.to_s } + + describe "#create_resource_group" do + let(:resource_group_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group_name}?api-version=#{group_api_version}" } + + let(:location) { "fake-location" } + + context "when token is valid, create operation is accepted and completed" do + context "when it returns 200" do + it "should create a resource group without error" do + stub_request(:post, token_uri).to_return( + :status => 200, + :body => { + "access_token"=>valid_access_token, + "expires_on"=>expires_on + }.to_json, + :headers => {}) + stub_request(:put, resource_group_uri).to_return( + :status => 200, + :body => '', + :headers => { + }) + + expect { + azure_client2.create_resource_group(resource_group_name, location) + }.not_to raise_error + end + end + + context "when it returns 201" do + it "should create a resource group without error" do + stub_request(:post, token_uri).to_return( + :status => 200, + :body => { + "access_token"=>valid_access_token, + "expires_on"=>expires_on + }.to_json, + :headers => {}) + stub_request(:put, resource_group_uri).to_return( + :status => 201, + :body => '', + :headers => { + }) + + expect { + azure_client2.create_resource_group(resource_group_name, location) + }.not_to raise_error + end + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/create_virtual_machine_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/create_virtual_machine_spec.rb index 0ceac0874..5c6e3a66b 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/create_virtual_machine_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/create_virtual_machine_spec.rb @@ -15,7 +15,7 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -188,7 +188,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error end end @@ -307,7 +307,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params_managed, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params_managed, network_interfaces) }.not_to raise_error end end @@ -434,7 +434,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error end end @@ -544,7 +544,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error end end @@ -681,7 +681,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces, availability_set) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces, availability_set) }.not_to raise_error end end @@ -822,7 +822,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error end end @@ -935,7 +935,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error logs = logger_strio.string @@ -973,7 +973,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error logs = logger_strio.string @@ -1008,7 +1008,7 @@ it "should reaise error" do expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error /Unsupported os type/ end end @@ -1136,7 +1136,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error end end @@ -1150,7 +1150,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error /get_token - http code: 404/ end @@ -1161,7 +1161,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error /get_token - http code: 401. Azure authentication failed: Invalid tenant id, client id or client secret./ end @@ -1179,7 +1179,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error /Azure authentication failed: Token is invalid./ end end @@ -1213,7 +1213,7 @@ it "should not raise an error" do expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error end end @@ -1240,7 +1240,7 @@ it "should raise an error if authentication retry fails" do expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error /get_token - http code: 401. Azure authentication failed: Invalid tenant id, client id or client secret./ end end @@ -1261,7 +1261,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error Bosh::AzureCloud::AzureConflictError end end @@ -1281,7 +1281,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error /The number of network interfaces for virtual machine xxx exceeds the maximum/ end end @@ -1307,7 +1307,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error { |error| expect(error.error).to match(/check_completion - http code: 404/) } end @@ -1331,7 +1331,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.to raise_error { |error| expect(error.status).to eq('Cancelled') } end end @@ -1357,7 +1357,7 @@ :headers => {}) expect { - azure_client2.create_virtual_machine(vm_params, network_interfaces) + azure_client2.create_virtual_machine(resource_group, vm_params, network_interfaces) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_load_balancer_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_load_balancer_spec.rb index 4ef13e96f..b055bc309 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_load_balancer_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_load_balancer_spec.rb @@ -28,7 +28,7 @@ describe "#delete_load_balancer" do let(:load_balancer_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Network/loadBalancers/#{load_balancer_name}?api-version=#{api_version}" } - + context "when token is valid, create operation is accepted and completed" do it "should delete a load balancer without error" do stub_request(:post, token_uri).to_return( diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_network_interface_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_network_interface_spec.rb index 524bdfa65..eaf3f6eeb 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_network_interface_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_network_interface_spec.rb @@ -14,7 +14,7 @@ let(:subscription_id) { mock_azure_properties['subscription_id'] } let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -28,7 +28,7 @@ describe "#delete_network_interface" do let(:network_interface_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Network/networkInterfaces/#{nic_name}?api-version=#{api_version}" } - + context "when token is valid, delete operation is accepted and completed" do it "should delete a network interface without error" do stub_request(:post, token_uri).to_return( @@ -45,7 +45,7 @@ }) expect { - azure_client2.delete_network_interface(nic_name) + azure_client2.delete_network_interface(resource_group, nic_name) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_public_ip_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_public_ip_spec.rb index 123d1cdeb..e9a690ff5 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_public_ip_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_public_ip_spec.rb @@ -14,7 +14,7 @@ let(:subscription_id) { mock_azure_properties['subscription_id'] } let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -25,7 +25,7 @@ describe "#delete_public_ip" do let(:public_ip_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Network/publicIPAddresses/#{public_ip_name}?api-version=#{api_version}" } - + context "when token is valid, delete operation is accepted and completed" do it "should delete a public ip without error" do stub_request(:post, token_uri).to_return( @@ -41,7 +41,7 @@ :headers => {}) expect { - azure_client2.delete_public_ip(public_ip_name) + azure_client2.delete_public_ip(resource_group, public_ip_name) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_virtual_machine_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_virtual_machine_spec.rb index dcd06c3d2..a90690b5e 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/delete_virtual_machine_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/delete_virtual_machine_spec.rb @@ -15,7 +15,7 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -48,7 +48,7 @@ }) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error Bosh::AzureCloud::AzureNotFoundError end @@ -60,7 +60,7 @@ }) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.not_to raise_error end @@ -72,7 +72,7 @@ }) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.not_to raise_error end @@ -89,7 +89,7 @@ }) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error Bosh::AzureCloud::AzureInternalError end @@ -110,7 +110,7 @@ ) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.not_to raise_error end end @@ -129,7 +129,7 @@ :headers => {}) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.not_to raise_error end @@ -154,7 +154,7 @@ ) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.not_to raise_error end @@ -179,7 +179,7 @@ ) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.not_to raise_error end @@ -199,7 +199,7 @@ ) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error { |error| expect(error.status).to eq('Failed') } end @@ -218,7 +218,7 @@ ) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error { |error| expect(error.error).to match(/The body of the asynchronous response is empty/) } end @@ -238,7 +238,7 @@ ) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error { |error| expect(error.error).to match(/The body of the asynchronous response does not contain `status'/) } end @@ -255,7 +255,7 @@ :headers => {}) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error { |error| expect(error.error).to match(/check_completion - http code: 404/) } end @@ -272,7 +272,7 @@ :headers => {}) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error { |error| expect(error.status).to eq('Cancelled') } end end @@ -286,7 +286,7 @@ :headers => {}) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error /get_token - http code: 404/ end @@ -297,7 +297,7 @@ :headers => {}) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error /get_token - http code: 401. Azure authentication failed: Invalid tenant id, client id or client secret./ end @@ -315,7 +315,7 @@ :headers => {}) expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error /Azure authentication failed: Token is invalid./ end end @@ -348,7 +348,7 @@ it "should not raise an error" do expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.not_to raise_error end end @@ -374,7 +374,7 @@ it "should raise an error" do expect { - azure_client2.delete_virtual_machine(vm_name) + azure_client2.delete_virtual_machine(resource_group, vm_name) }.to raise_error /get_token - http code: 401. Azure authentication failed: Invalid tenant id, client id or client secret./ end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/detach_disk_from_virtual_machine_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/detach_disk_from_virtual_machine_spec.rb index 49ccc6daa..e5df4dd40 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/detach_disk_from_virtual_machine_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/detach_disk_from_virtual_machine_spec.rb @@ -15,20 +15,20 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } let(:operation_status_link) { "https://management.azure.com/subscriptions/#{subscription_id}/operations/#{request_id}" } let(:vm_name) { "fake-vm-name" } - let(:tags) { {} } + let(:tags) { { "fake-key" => "fake-value" } } let(:valid_access_token) { "valid-access-token" } let(:expires_on) { (Time.now+1800).to_i.to_s } - describe "#detach_disk_to_virtual_machine" do + describe "#detach_disk_from_virtual_machine" do disk_name = "fake-disk-name" let(:vm_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Compute/virtualMachines/#{vm_name}?api-version=#{api_version_compute}" } let(:response_body) { @@ -36,7 +36,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => tags, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -61,7 +61,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => tags, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -101,7 +101,7 @@ :headers => {}) expect { - azure_client2.detach_disk_from_virtual_machine(vm_name, disk_name) + azure_client2.detach_disk_from_virtual_machine(resource_group, vm_name, disk_name) }.not_to raise_error end end @@ -112,7 +112,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "fake-tags", + "tags" => tags, "properties" => { "provisioningState" => "fake-state", "storageProfile" => { @@ -164,7 +164,7 @@ :headers => {}) expect { - azure_client2.detach_disk_from_virtual_machine(vm_name, disk_name) + azure_client2.detach_disk_from_virtual_machine(resource_group, vm_name, disk_name) }.not_to raise_error end end @@ -195,7 +195,7 @@ :headers => {}) expect { - azure_client2.detach_disk_from_virtual_machine(vm_name, disk_name) + azure_client2.detach_disk_from_virtual_machine(resource_group, vm_name, disk_name) }.to raise_error /detach_disk_from_virtual_machine - cannot find the virtual machine by name/ end end @@ -226,9 +226,70 @@ disk_name = "another-disk-name" expect { - azure_client2.detach_disk_from_virtual_machine(vm_name, disk_name) + azure_client2.detach_disk_from_virtual_machine(resource_group, vm_name, disk_name) }.to raise_error /The disk #{disk_name} is not attached to the virtual machine #{vm_name}/ end end + + context "when VM has a tag for bosh_disk_id" do + let(:tags) { + { + "fake-key" => "fake-value", + "disk-id-#{disk_name}" => "fake-disk-bosh-id" + } + } + let(:tags_without_bosh_disk_id) { + { + "fake-key" => "fake-value" + } + } + let(:request_body) { + { + "id" => "fake-id", + "name" => "fake-name", + "location" => "fake-location", + "tags" => tags_without_bosh_disk_id, + "properties" => { + "provisioningState" => "fake-state", + "storageProfile" => { + "dataDisks" => [ + { + "name" => "wrong name", + "lun" => 0 + } + ] + } + } + } + } + + it "should should remove the tag" do + stub_request(:post, token_uri).to_return( + :status => 200, + :body => { + "access_token" => valid_access_token, + "expires_on" => expires_on + }.to_json, + :headers => {}) + stub_request(:get, vm_uri).to_return( + :status => 200, + :body => response_body, + :headers => {}) + stub_request(:put, vm_uri).with(body: request_body).to_return( + :status => 200, + :body => '', + :headers => { + "azure-asyncoperation" => operation_status_link + }) + stub_request(:get, operation_status_link).to_return( + :status => 200, + :body => '{"status":"Succeeded"}', + :headers => {}) + + expect { + azure_client2.detach_disk_from_virtual_machine(resource_group, vm_name, disk_name) + }.not_to raise_error + end + end end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/get_operation_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/get_operation_spec.rb index 616b4171c..f656081ba 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/get_operation_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/get_operation_spec.rb @@ -14,7 +14,8 @@ let(:subscription_id) { mock_azure_properties['subscription_id'] } let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } - let(:resource_group_name) { mock_azure_properties['resource_group_name'] } + let(:default_resource_group_name) { mock_azure_properties['resource_group_name'] } + let(:resource_group_name) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -70,7 +71,7 @@ # Load Balancer let(:load_balancer_name) { "fake-name" } - let(:load_balancer_id) { "/subscriptions/#{subscription_id}/resourceGroups/#{resource_group_name}/providers/Microsoft.Network/loadBalancers/#{load_balancer_name}" } + let(:load_balancer_id) { "/subscriptions/#{subscription_id}/resourceGroups/#{default_resource_group_name}/providers/Microsoft.Network/loadBalancers/#{load_balancer_name}" } let(:load_balancer_uri) { "https://management.azure.com/#{load_balancer_id}?api-version=#{api_version}" } let(:load_balancer_response_body) { { @@ -130,7 +131,7 @@ ] } } - + # Network Interface let(:nic_name) { "fake-name" } let(:nic_id) { "/subscriptions/#{subscription_id}/resourceGroups/#{resource_group_name}/providers/Microsoft.Network/networkInterfaces/#{nic_name}" } @@ -332,7 +333,7 @@ :body => '', :headers => {}) expect( - azure_client2.get_public_ip_by_name(public_ip_name) + azure_client2.get_public_ip_by_name(resource_group_name, public_ip_name) ).to be_nil end @@ -342,7 +343,7 @@ :body => public_ip_response_body.to_json, :headers => {}) expect( - azure_client2.get_public_ip_by_name(public_ip_name) + azure_client2.get_public_ip_by_name(resource_group_name, public_ip_name) ).to eq(fake_public_ip) end end @@ -417,7 +418,7 @@ :body => '', :headers => {}) expect( - azure_client2.get_network_interface_by_name(nic_name) + azure_client2.get_network_interface_by_name(resource_group_name, nic_name) ).to be_nil end @@ -435,7 +436,7 @@ :body => nic_response_body, :headers => {}) expect( - azure_client2.get_network_interface_by_name(nic_name) + azure_client2.get_network_interface_by_name(resource_group_name, nic_name) ).to eq(fake_nic) end end @@ -492,7 +493,7 @@ end describe "#get_storage_account_by_name" do - let(:storage_account_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group_name}/providers/Microsoft.Storage/storageAccounts/#{storage_account_name}?api-version=#{api_version}" } + let(:storage_account_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{default_resource_group_name}/providers/Microsoft.Storage/storageAccounts/#{storage_account_name}?api-version=#{api_version}" } context "if get operation returns retryable error code (returns 429)" do it "should raise error if it always returns 429" do @@ -840,7 +841,7 @@ end describe "#list_storage_accounts" do - let(:storage_accounts_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group_name}/providers/Microsoft.Storage/storageAccounts?api-version=#{api_version}" } + let(:storage_accounts_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{default_resource_group_name}/providers/Microsoft.Storage/storageAccounts?api-version=#{api_version}" } context "when token is valid, getting response succeeds" do context "if response body is null" do @@ -959,7 +960,7 @@ :body => '', :headers => {}) expect( - azure_client2.get_virtual_machine_by_name(vm_name) + azure_client2.get_virtual_machine_by_name(resource_group_name, vm_name) ).to be_nil end end @@ -1022,7 +1023,8 @@ :lun => 0, :uri => "foo", :caching => "bar", - :size => 1024 + :size => 1024, + :disk_bosh_id => "foo" }], :network_interfaces => [fake_nic] } @@ -1046,7 +1048,7 @@ :body => response_body, :headers => {}) expect( - azure_client2.get_virtual_machine_by_name(vm_name) + azure_client2.get_virtual_machine_by_name(resource_group_name, vm_name) ).to eq(fake_vm) end end @@ -1120,7 +1122,8 @@ :managed_disk => { :id => "fake-disk-id", :storage_account_type => "fake-storage-account-type" - } + }, + :disk_bosh_id => "foo" }], :network_interfaces => [fake_nic] } @@ -1144,7 +1147,110 @@ :body => response_body, :headers => {}) expect( - azure_client2.get_virtual_machine_by_name(vm_name) + azure_client2.get_virtual_machine_by_name(resource_group_name, vm_name) + ).to eq(fake_vm) + end + end + + context "when the vm has tags for bosh_disk_id" do + let(:response_body) { + { + "id" => "fake-id", + "name" => "fake-name", + "location" => "fake-location", + "tags" => { + "disk-id-foo" => "fake-disk-bosh-id" + }, + "properties" => { + "provisioningState" => "foo", + "hardwareProfile" => { "vmSize" => "bar" }, + "storageProfile" => { + "osDisk" => { + "name" => "foo", + "caching" => "bar", + "diskSizeGb" => 1024, + "managedDisk" => { + "id" => "fake-disk-id", + "storageAccountType" => "fake-storage-account-type" + } + }, + "dataDisks" => [ + { + "name" => "foo", + "lun" => 0, + "caching" => "bar", + "diskSizeGb" => 1024, + "managedDisk" => { + "id" => "fake-disk-id", + "storageAccountType" => "fake-storage-account-type" + } + } + ] + }, + "networkProfile" => { + "networkInterfaces" => [ + { + "id" => nic_id + } + ] + } + } + }.to_json + } + + let(:fake_vm) { + { + :id => "fake-id", + :name => "fake-name", + :location => "fake-location", + :tags => { + "disk-id-foo" => "fake-disk-bosh-id" + }, + :provisioning_state => "foo", + :vm_size => "bar", + :os_disk => { + :name => "foo", + :caching => "bar", + :size => 1024, + :managed_disk => { + :id => "fake-disk-id", + :storage_account_type => "fake-storage-account-type" + } + }, + :data_disks => [{ + :name => "foo", + :lun => 0, + :caching => "bar", + :size => 1024, + :managed_disk => { + :id => "fake-disk-id", + :storage_account_type => "fake-storage-account-type" + }, + :disk_bosh_id => "fake-disk-bosh-id" + }], + :network_interfaces => [fake_nic] + } + } + + it "should return the resource using using tag as disk_bosh_id" do + stub_request(:get, public_ip_uri).to_return( + :status => 200, + :body => public_ip_response_body.to_json, + :headers => {}) + stub_request(:get, load_balancer_uri).to_return( + :status => 200, + :body => load_balancer_response_body, + :headers => {}) + stub_request(:get, nic_uri).to_return( + :status => 200, + :body => nic_response_body, + :headers => {}) + stub_request(:get, vm_uri).to_return( + :status => 200, + :body => response_body, + :headers => {}) + expect( + azure_client2.get_virtual_machine_by_name(resource_group_name, vm_name) ).to eq(fake_vm) end end @@ -1176,7 +1282,7 @@ end describe "#get_storage_account_keys_by_name" do - let(:storage_account_list_keys_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group_name}/providers/Microsoft.Storage/storageAccounts/#{storage_account_name}/listKeys?api-version=#{api_version}" } + let(:storage_account_list_keys_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{default_resource_group_name}/providers/Microsoft.Storage/storageAccounts/#{storage_account_name}/listKeys?api-version=#{api_version}" } let(:storage_account_list_keys_response_body) { { "key1" => "fake-key-1", diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/managed_disks_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/managed_disks_spec.rb index dd47d6397..956c9cd1c 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/managed_disks_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/managed_disks_spec.rb @@ -15,7 +15,7 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -74,7 +74,7 @@ :headers => {}) expect { - azure_client2.create_empty_managed_disk(disk_params) + azure_client2.create_empty_managed_disk(resource_group, disk_params) }.not_to raise_error end end @@ -128,7 +128,7 @@ :headers => {}) expect { - azure_client2.create_managed_disk_from_blob(disk_params) + azure_client2.create_managed_disk_from_blob(resource_group, disk_params) }.not_to raise_error end end @@ -179,14 +179,14 @@ :headers => {}) expect( - azure_client2.get_managed_disk_by_name(disk_name) + azure_client2.get_managed_disk_by_name(resource_group, disk_name) ).to eq(disk) end end describe "#delete_managed_disk" do let(:disk_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Compute/disks/#{disk_name}?api-version=#{api_version_compute}" } - + context "when token is valid, delete operation is accepted and completed" do it "should delete the managed disk without error" do stub_request(:post, token_uri).to_return( @@ -202,7 +202,7 @@ :headers => {}) expect { - azure_client2.delete_managed_disk(disk_name) + azure_client2.delete_managed_disk(resource_group, disk_name) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/managed_images_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/managed_images_spec.rb index f0997dbb8..d52ff4037 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/managed_images_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/managed_images_spec.rb @@ -206,7 +206,7 @@ describe "#delete_user_image" do let(:image_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Compute/images/#{image_name}?api-version=#{api_version_compute}" } - + context "when token is valid, delete operation is accepted and completed" do it "should delete the managed image without error" do stub_request(:post, token_uri).to_return( diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/managed_snapshots_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/managed_snapshots_spec.rb index b8f8754bf..bc6a84c1c 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/managed_snapshots_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/managed_snapshots_spec.rb @@ -15,7 +15,7 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -96,14 +96,14 @@ :headers => {}) expect { - azure_client2.create_managed_snapshot(snapshot_params) + azure_client2.create_managed_snapshot(resource_group, snapshot_params) }.not_to raise_error end end describe "#delete_managed_snapshot" do let(:snapshot_uri) { "https://management.azure.com//subscriptions/#{subscription_id}/resourceGroups/#{resource_group}/providers/Microsoft.Compute/snapshots/#{snapshot_name}?api-version=#{api_version_compute}" } - + context "when token is valid, delete operation is accepted and completed" do it "should delete the managed snapshot without error" do stub_request(:post, token_uri).to_return( @@ -119,7 +119,7 @@ :headers => {}) expect { - azure_client2.delete_managed_snapshot(snapshot_name) + azure_client2.delete_managed_snapshot(resource_group, snapshot_name) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/restart_virtual_machine_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/restart_virtual_machine_spec.rb index 5fc7fb7a3..602cedbb0 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/restart_virtual_machine_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/restart_virtual_machine_spec.rb @@ -15,7 +15,7 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } @@ -50,7 +50,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.not_to raise_error end @@ -82,7 +82,7 @@ ) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.not_to raise_error end end @@ -95,7 +95,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error /get_token - http code: 404/ end @@ -106,7 +106,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error /get_token - http code: 401. Azure authentication failed: Invalid tenant id, client id or client secret./ end @@ -124,7 +124,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error /Azure authentication failed: Token is invalid./ end end @@ -144,7 +144,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error Bosh::AzureCloud::AzureNotFoundError end end @@ -170,7 +170,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error { |error| expect(error.error).to match(/check_completion - http code: 404/) } end @@ -194,7 +194,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error { |error| expect(error.status).to eq('Cancelled') } end @@ -231,7 +231,7 @@ it "should not raise an error" do expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.not_to raise_error end end @@ -258,7 +258,7 @@ it "should raise an error" do expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error /get_token - http code: 401. Azure authentication failed: Invalid tenant id, client id or client secret./ end end @@ -282,7 +282,7 @@ ) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.to raise_error Bosh::AzureCloud::AzureInternalError end @@ -314,7 +314,7 @@ :headers => {}) expect { - azure_client2.restart_virtual_machine(vm_name) + azure_client2.restart_virtual_machine(resource_group, vm_name) }.not_to raise_error end end diff --git a/src/bosh_azure_cpi/spec/unit/azure_client2/update_tags_of_virtual_machine_spec.rb b/src/bosh_azure_cpi/spec/unit/azure_client2/update_tags_of_virtual_machine_spec.rb index 672d7a0a7..987b579e8 100644 --- a/src/bosh_azure_cpi/spec/unit/azure_client2/update_tags_of_virtual_machine_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/azure_client2/update_tags_of_virtual_machine_spec.rb @@ -12,14 +12,14 @@ let(:tenant_id) { mock_azure_properties['tenant_id'] } let(:api_version) { AZURE_API_VERSION } let(:api_version_compute) { AZURE_RESOURCE_PROVIDER_COMPUTE } - let(:resource_group) { mock_azure_properties['resource_group_name'] } + let(:resource_group) { "fake-resource-group-name" } let(:request_id) { "fake-request-id" } let(:token_uri) { "https://login.microsoftonline.com/#{tenant_id}/oauth2/token?api-version=#{api_version}" } let(:operation_status_link) { "https://management.azure.com/subscriptions/#{subscription_id}/operations/#{request_id}" } let(:vm_name) { "fake-vm-name" } - let(:tags) { 'fake-tags' } + let(:tags) { { 'fake-key' => 'fake-value' } } let(:valid_access_token) { "valid-access-token" } @@ -47,7 +47,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "", + "tags" => {}, "properties" => { "provisioningState" => "fake-state" } @@ -78,7 +78,7 @@ :headers => {}) expect { - azure_client2.update_tags_of_virtual_machine(vm_name, tags) + azure_client2.update_tags_of_virtual_machine(resource_group, vm_name, tags) }.not_to raise_error end end @@ -89,7 +89,7 @@ "id" => "fake-id", "name" => "fake-name", "location" => "fake-location", - "tags" => "", + "tags" => {}, "properties" => { "provisioningState" => "fake-state" }, @@ -129,7 +129,75 @@ :headers => {}) expect { - azure_client2.update_tags_of_virtual_machine(vm_name, tags) + azure_client2.update_tags_of_virtual_machine(resource_group, vm_name, tags) + }.not_to raise_error + end + end + + context "when VM's information contains tags of disk_bosh_id" do + let(:disk_bosh_id_tag) { + { + "disk-id-1" => "fake-disk-bosh-id-1", + "disk-id-2" => "fake-disk-bosh-id-2" + } + } + let(:request_body) { + { + "id" => "fake-id", + "name" => "fake-name", + "location" => "fake-location", + "tags" => tags.merge(disk_bosh_id_tag), + "properties" => { + "provisioningState" => "fake-state" + } + } + } + let(:response_body) { + { + "id" => "fake-id", + "name" => "fake-name", + "location" => "fake-location", + "tags" => disk_bosh_id_tag, + "properties" => { + "provisioningState" => "fake-state" + }, + "resources" => [ + { + "properties": {}, + "id": "fake-id", + "name": "fake-name", + "type": "fake-type", + "location": "fake-location" + } + ] + }.to_json + } + + it "should keep tags of disk_bosh_id" do + stub_request(:post, token_uri).to_return( + :status => 200, + :body => { + "access_token" => valid_access_token, + "expires_on" => expires_on + }.to_json, + :headers => {}) + stub_request(:get, vm_uri).to_return( + :status => 200, + :body => response_body, + :headers => {}) + stub_request(:put, vm_uri).with(body: request_body).to_return( + :status => 200, + :body => '', + :headers => { + "azure-asyncoperation" => operation_status_link + }) + stub_request(:get, operation_status_link).to_return( + :status => 200, + :body => '{"status":"Succeeded"}', + :headers => {}) + + expect { + azure_client2.update_tags_of_virtual_machine(resource_group, vm_name, tags) }.not_to raise_error end end @@ -160,7 +228,7 @@ :headers => {}) expect { - azure_client2.update_tags_of_virtual_machine(vm_name, tags) + azure_client2.update_tags_of_virtual_machine(resource_group, vm_name, tags) }.to raise_error /update_tags_of_virtual_machine - cannot find the virtual machine by name/ end end diff --git a/src/bosh_azure_cpi/spec/unit/blob_manager_spec.rb b/src/bosh_azure_cpi/spec/unit/blob_manager_spec.rb index 66cffac24..4d53db902 100644 --- a/src/bosh_azure_cpi/spec/unit/blob_manager_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/blob_manager_spec.rb @@ -72,7 +72,7 @@ blob_manager.get_blob_uri(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, container_name, blob_name) ).to eq("#{blob_host}/#{container_name}/#{blob_name}") end - end + end describe "#delete_blob_snapshot" do it "delete the blob snapshot" do @@ -88,7 +88,7 @@ blob_manager.delete_blob_snapshot(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, container_name, blob_name, snapshot_time) }.not_to raise_error end - end + end describe "#get_blob_size_in_bytes" do let(:blob) { instance_double("Blob") } @@ -96,7 +96,7 @@ before do allow(blob_service).to receive(:get_blob_properties). with(container_name, blob_name). - and_return(blob) + and_return(blob) allow(blob).to receive(:properties).and_return({:content_length => 1024}) end @@ -105,7 +105,7 @@ blob_manager.get_blob_size_in_bytes(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, container_name, blob_name) ).to eq(1024) end - end + end describe "#create_page_blob" do let(:metadata) { @@ -156,7 +156,7 @@ }.to raise_error /Failed to upload page blob/ end end - end + end describe "#create_empty_page_blob" do let(:metadata) { @@ -194,7 +194,7 @@ }.to raise_error /Failed to create empty page blob/ end end - end + end describe "#create_empty_vhd_blob" do context "when creating empty vhd blob succeeds" do @@ -205,7 +205,7 @@ it "raise no error" do expect { - blob_manager.create_empty_vhd_blob(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, container_name, blob_name, 1) + blob_manager.create_empty_vhd_blob(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, container_name, blob_name, 1) }.not_to raise_error end end @@ -220,7 +220,7 @@ expect(blob_service).not_to receive(:delete_blob) expect { - blob_manager.create_empty_vhd_blob(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, container_name, blob_name, 1) + blob_manager.create_empty_vhd_blob(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, container_name, blob_name, 1) }.to raise_error /Failed to create empty vhd blob/ end end @@ -240,7 +240,7 @@ end end end - end + end describe "#get_blob_properties" do context "when blob exists" do @@ -362,7 +362,7 @@ context "when the container is not empty" do context "without continuation_token" do - let(:tmp_blobs) { + let(:tmp_blobs) { Azure::Service::EnumerationResults.new( [ 'fake-blob' @@ -411,7 +411,7 @@ end end - end + end describe "#snapshot_blob" do it "snapshots the blob" do diff --git a/src/bosh_azure_cpi/spec/unit/cloud/attach_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/attach_disk_spec.rb index ba690fe65..bca01585c 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/attach_disk_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/attach_disk_spec.rb @@ -6,7 +6,6 @@ describe "#attach_disk" do let(:storage_account_name) { "fakestorageaccountname" } - let(:disk_id) { "bosh-data-#{storage_account_name}-guid-None" } let(:lun) { '1' } let(:volume_name) { '/dev/sdd' } let(:host_device_id) { '{f8b3781b-1e82-4818-a1c3-63d806ec15bb}' } @@ -25,19 +24,45 @@ } } } + let(:disk_name) { "fake-disk-name" } + let(:disk_id) { "fake-disk-id" } + let(:disk_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + + let(:vm_name) { "fake-vm-name" } + let(:instance_id) { "fake-instance-id" } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } + + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + and_return(disk_id_object) + allow(Bosh::AzureCloud::InstanceId).to receive(:parse). + and_return(instance_id_object) + allow(instance_id_object).to receive(:to_s). + and_return(instance_id) + allow(disk_id_object).to receive(:to_s). + and_return(disk_id) + + allow(disk_id_object).to receive(:disk_name). + and_return(disk_name) + allow(instance_id_object).to receive(:vm_name). + and_return(vm_name) + end context "when use_managed_disks is true" do context "when the disk is a managed disk" do let(:disk) { double("disk") } before do - allow(disk_manager2).to receive(:get_disk).with(disk_id).and_return(disk) + allow(disk_manager2).to receive(:get_data_disk).with(disk_id_object).and_return(disk) end context "when the vm is a vm with managed disks" do - let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + before do + allow(instance_id_object).to receive(:use_managed_disks?). + and_return(true) + end it "attaches the managed disk to the vm" do - expect(vm_manager).to receive(:attach_disk).with(instance_id, disk_id). + expect(vm_manager).to receive(:attach_disk).with(instance_id_object, disk_id_object). and_return(lun) expect(registry).to receive(:read_settings).with(instance_id). and_return(old_settings) @@ -51,7 +76,10 @@ end context "when the vm is a vm with unmanaged disks" do - let(:instance_id) { "not-36-length" } + before do + allow(instance_id_object).to receive(:use_managed_disks?). + and_return(false) + end it "can't attach a managed disk to a VM with unmanaged disks" do expect { @@ -63,11 +91,10 @@ context "when the disk is an unmanaged disk" do before do - allow(disk_manager2).to receive(:get_disk).with(disk_id).and_return(nil) + allow(disk_manager2).to receive(:get_data_disk).with(disk_id_object).and_return(nil) end context "when the vm is a vm with managed disks" do - let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } let(:blob_uri) { "fake-blob-uri" } let(:location) { "fake-location" } let(:account_type) { "Premium_LRS" } @@ -79,16 +106,25 @@ } before do - allow(disk_manager).to receive(:get_disk_uri).with(disk_id).and_return(blob_uri) - allow(client2).to receive(:get_storage_account_by_name).with(storage_account_name).and_return(storage_account) + allow(instance_id_object).to receive(:use_managed_disks?). + and_return(true) + allow(disk_manager).to receive(:get_data_disk_uri). + with(disk_id_object). + and_return(blob_uri) + allow(client2).to receive(:get_storage_account_by_name). + with(storage_account_name). + and_return(storage_account) end context "a managed disk is created successfully from the unmanage disk" do it "attaches the managed disk to the vm" do - expect(disk_manager2).to receive(:create_disk_from_blob).with(disk_id, blob_uri, location, account_type) + expect(disk_id_object).to receive(:storage_account_name). + and_return(storage_account_name) + expect(disk_manager2).to receive(:create_disk_from_blob). + with(disk_id_object, blob_uri, location, account_type) expect(blob_manager).to receive(:set_blob_metadata) - expect(vm_manager).to receive(:attach_disk).with(instance_id, disk_id). + expect(vm_manager).to receive(:attach_disk).with(instance_id_object, disk_id_object). and_return(lun) expect(registry).to receive(:read_settings).with(instance_id). and_return(old_settings) @@ -104,16 +140,18 @@ context "a managed disk fails to be created from the unmanage disk" do before do allow(disk_manager2).to receive(:create_disk_from_blob).and_raise(StandardError) + allow(disk_id_object).to receive(:storage_account_name). + and_return(storage_account_name) end context "the managed disk is cleaned up" do before do - allow(disk_manager2).to receive(:delete_disk).with(disk_id) + allow(disk_manager2).to receive(:delete_data_disk).with(disk_id_object) end it "fails to attach the managed disk to the vm, but successfully cleanup the managed disk" do expect(blob_manager).not_to receive(:set_blob_metadata) - + expect { managed_cloud.attach_disk(instance_id, disk_id) }.to raise_error /attach_disk - Failed to create the managed disk/ @@ -122,12 +160,12 @@ context "the managed disk is not cleaned up" do before do - allow(disk_manager2).to receive(:delete_disk).with(disk_id).and_raise(StandardError) + allow(disk_manager2).to receive(:delete_data_disk).with(disk_id_object).and_raise(StandardError) end it "fails to attach the managed disk to the vm and cleanup the managed disk" do expect(blob_manager).not_to receive(:set_blob_metadata) - + expect { managed_cloud.attach_disk(instance_id, disk_id) }.to raise_error /attach_disk - Failed to create the managed disk/ @@ -137,10 +175,13 @@ end context "when the vm is a vm with unmanaged disks" do - let(:instance_id) { "not-36-length" } + before do + allow(instance_id_object).to receive(:use_managed_disks?). + and_return(false) + end it "attaches the unmanaged disk to the vm" do - expect(vm_manager).to receive(:attach_disk).with(instance_id, disk_id). + expect(vm_manager).to receive(:attach_disk).with(instance_id_object, disk_id_object). and_return(lun) expect(registry).to receive(:read_settings).with(instance_id). and_return(old_settings) @@ -156,10 +197,8 @@ end context "when use_managed_disks is false" do - let(:instance_id) { "not-36-length" } - it "attaches the unmanaged disk to the vm" do - expect(vm_manager).to receive(:attach_disk).with(instance_id, disk_id). + expect(vm_manager).to receive(:attach_disk).with(instance_id_object, disk_id_object). and_return(lun) expect(registry).to receive(:read_settings).with(instance_id). and_return(old_settings) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/create_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/create_disk_spec.rb index 5f26c231a..48f60dc69 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/create_disk_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/create_disk_spec.rb @@ -7,6 +7,20 @@ describe '#create_disk' do let(:cloud_properties) { {} } let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } + let(:disk_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + let(:default_resource_group_name) { MOCK_RESOURCE_GROUP_NAME } + let(:resource_group_name) { "fake-resource-group-name" } + let(:vm_name) { "fake-vm-name" } + + before do + allow(Bosh::AzureCloud::InstanceId).to receive(:parse). + and_return(instance_id_object) + allow(instance_id_object).to receive(:resource_group_name). + and_return(resource_group_name) + allow(instance_id_object).to receive(:vm_name). + and_return(vm_name) + end context 'validating disk size' do context 'when disk size is not an integer' do @@ -84,7 +98,11 @@ end it "should create a managed disk with the default location and storage account type" do - expect(disk_manager2).to receive(:create_disk).with(rg_location, disk_size_in_gib, "Standard_LRS", caching) + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, true, resource_group_name:default_resource_group_name). + and_return(disk_id_object) + expect(disk_manager2).to receive(:create_disk). + with(disk_id_object, rg_location, disk_size_in_gib, "Standard_LRS") expect { managed_cloud.create_disk(disk_size, cloud_properties, instance_id) @@ -94,17 +112,19 @@ context "when instance_id is not nil" do context "when the instance is an unmanaged vm" do - let(:instance_id) { "fake-instance-id" } + before do + allow(instance_id_object).to receive(:use_managed_disks?). + and_return(false) + end it "can't create a managed disk for a VM with unmanaged disks" do expect { managed_cloud.create_disk(disk_size, cloud_properties, instance_id) - }.to raise_error /Cannot create a managed disk for a VM with unmanaged disks/ + }.to raise_error /Cannot create a managed disk for a VM with unmanaged disks/ end end context "when the instance is a managed vm" do - let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } let(:vm_location) { "fake-vm-location" } let(:vm) { { @@ -114,12 +134,20 @@ } before do - allow(client2).to receive(:get_virtual_machine_by_name).with(instance_id).and_return(vm) + allow(instance_id_object).to receive(:use_managed_disks?). + and_return(true) + allow(client2).to receive(:get_virtual_machine_by_name). + with(resource_group_name, vm_name). + and_return(vm) end context "when storage_account_type is not specified" do it "should create a managed disk in the same location with the vm and use the default storage account type" do - expect(disk_manager2).to receive(:create_disk).with(vm_location, disk_size_in_gib, "Premium_LRS", caching) + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, true, resource_group_name:resource_group_name). + and_return(disk_id_object) + expect(disk_manager2).to receive(:create_disk). + with(disk_id_object, vm_location, disk_size_in_gib, "Premium_LRS") expect { managed_cloud.create_disk(disk_size, cloud_properties, instance_id) @@ -135,7 +163,11 @@ } } it "should create a managed disk in the same location with the vm and use the specified storage account type" do - expect(disk_manager2).to receive(:create_disk).with(vm_location, disk_size_in_gib, "Standard_LRS", caching) + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, true, resource_group_name:resource_group_name). + and_return(disk_id_object) + expect(disk_manager2).to receive(:create_disk). + with(disk_id_object, vm_location, disk_size_in_gib, "Standard_LRS") expect { managed_cloud.create_disk(disk_size, cloud_properties, instance_id) @@ -159,10 +191,18 @@ context "when instance_id is not nil" do let(:vm_storage_account_name) { "vmstorageaccountname" } - let(:instance_id) { "#{vm_storage_account_name}-guid" } + + before do + allow(instance_id_object).to receive(:storage_account_name). + and_return(vm_storage_account_name) + end it "should create an unmanaged disk in the same storage account of the vm" do - expect(disk_manager).to receive(:create_disk).with(disk_size_in_gib, vm_storage_account_name, caching) + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, false, storage_account_name:vm_storage_account_name). + and_return(disk_id_object) + expect(disk_manager).to receive(:create_disk). + with(disk_id_object, disk_size_in_gib) expect { cloud.create_disk(disk_size, cloud_properties, instance_id) @@ -174,7 +214,11 @@ let(:instance_id) { nil } it "should create an unmanaged disk in the default storage account of global configuration" do - expect(disk_manager).to receive(:create_disk).with(disk_size_in_gib, MOCK_DEFAULT_STORAGE_ACCOUNT_NAME, caching) + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, false, storage_account_name:MOCK_DEFAULT_STORAGE_ACCOUNT_NAME). + and_return(disk_id_object) + expect(disk_manager).to receive(:create_disk). + with(disk_id_object, disk_size_in_gib) expect { cloud.create_disk(disk_size, cloud_properties, instance_id) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/create_vm_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/create_vm_spec.rb index d6b3766db..eb67cdf68 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/create_vm_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/create_vm_spec.rb @@ -13,11 +13,11 @@ let(:networks_spec) { {} } let(:disk_locality) { double("disk locality") } let(:environment) { double("environment") } - let(:resource_group_name) { MOCK_RESOURCE_GROUP_NAME } + let(:default_resource_group_name) { MOCK_RESOURCE_GROUP_NAME } let(:virtual_network_name) { "fake-virual-network-name" } let(:location) { "fake-location" } let(:vnet) { {:location => location} } - let(:network_configurator) { instance_double(Bosh::AzureCloud::NetworkConfigurator) } + let(:network_configurator) { instance_double(Bosh::AzureCloud::NetworkConfigurator) } let(:network) { instance_double(Bosh::AzureCloud::ManualNetwork) } let(:network_configurator) { double("network configurator") } let(:stemcell_info) { instance_double(Bosh::AzureCloud::Helpers::StemcellInfo) } @@ -26,11 +26,11 @@ allow(network_configurator).to receive(:networks). and_return([network]) allow(network).to receive(:resource_group_name). - and_return(resource_group_name) + and_return(default_resource_group_name) allow(network).to receive(:virtual_network_name). and_return(virtual_network_name) allow(client2).to receive(:get_virtual_network_by_name). - with(resource_group_name, virtual_network_name). + with(default_resource_group_name, virtual_network_name). and_return(vnet) end @@ -40,7 +40,7 @@ with(azure_properties, networks_spec). and_return(network_configurator) allow(client2).to receive(:get_virtual_network_by_name). - with(resource_group_name, virtual_network_name). + with(default_resource_group_name, virtual_network_name). and_return(nil) end @@ -59,11 +59,11 @@ end context 'when use_managed_disks is not set' do - # The return value of create_vm - let(:instance_id) { "#{MOCK_DEFAULT_STORAGE_ACCOUNT_NAME}-#{agent_id}" } + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + let(:instance_id_string) { "fake-instance-id" } let(:vm_params) { { - :name => instance_id + :name => "fake-vm-name" } } @@ -93,6 +93,12 @@ allow(Bosh::AzureCloud::NetworkConfigurator).to receive(:new). with(azure_properties, networks_spec). and_return(network_configurator) + + allow(Bosh::AzureCloud::InstanceId).to receive(:create). + with(default_resource_group_name, agent_id, storage_account_name). + and_return(instance_id) + allow(instance_id).to receive(:to_s). + and_return(instance_id_string) end context 'when everything is OK' do @@ -116,7 +122,7 @@ disk_locality, environment ) - ).to eq(instance_id) + ).to eq(instance_id_string) end end @@ -149,30 +155,43 @@ disk_locality, environment ) - ).to eq(instance_id) + ).to eq(instance_id_string) end end - end - context 'when it failed to get the user image info' do - before do - allow(Bosh::AzureCloud::NetworkConfigurator).to receive(:new). - with(azure_properties_managed, networks_spec). - and_return(network_configurator) - allow(stemcell_manager2).to receive(:get_user_image_info).and_raise(StandardError) - end + context 'when resource group is specified' do + let(:resource_group_name) { 'fake-resource-group-name' } + let(:resource_pool) { + { + 'instance_type' => 'fake-vm-size', + 'resource_group_name' => resource_group_name + } + } + + it 'should create the VM in the specified resource group' do + expect(Bosh::AzureCloud::InstanceId).to receive(:create). + with(resource_group_name, agent_id, storage_account_name). + and_return(instance_id) + expect(vm_manager).to receive(:create). + with(instance_id, location, stemcell_info, resource_pool, network_configurator, environment). + and_return(vm_params) + expect(registry).to receive(:update_settings) - it 'should raise an error' do - expect { - managed_cloud.create_vm( - agent_id, - stemcell_id, - resource_pool, - networks_spec, - disk_locality, - environment - ) - }.to raise_error(/Failed to get the user image information for the stemcell `#{stemcell_id}'/) + expect(stemcell_manager).to receive(:get_stemcell_info) + expect(light_stemcell_manager).not_to receive(:has_stemcell?) + expect(light_stemcell_manager).not_to receive(:get_stemcell_info) + + expect( + cloud.create_vm( + agent_id, + stemcell_id, + resource_pool, + networks_spec, + disk_locality, + environment + ) + ).to eq(instance_id_string) + end end end @@ -260,11 +279,11 @@ end context 'when use_managed_disks is set' do - # The return value of create_vm - let(:instance_id) { agent_id } + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + let(:instance_id_string) { "fake-instance-id" } let(:vm_params) { { - :name => instance_id + :name => "fake-vm-name" } } @@ -272,6 +291,34 @@ allow(Bosh::AzureCloud::NetworkConfigurator).to receive(:new). with(azure_properties_managed, networks_spec). and_return(network_configurator) + + allow(Bosh::AzureCloud::InstanceId).to receive(:create). + with(default_resource_group_name, agent_id). + and_return(instance_id) + allow(instance_id).to receive(:to_s). + and_return(instance_id_string) + end + + context 'when it failed to get the user image info' do + before do + allow(Bosh::AzureCloud::NetworkConfigurator).to receive(:new). + with(azure_properties_managed, networks_spec). + and_return(network_configurator) + allow(stemcell_manager2).to receive(:get_user_image_info).and_raise(StandardError) + end + + it 'should raise an error' do + expect { + managed_cloud.create_vm( + agent_id, + stemcell_id, + resource_pool, + networks_spec, + disk_locality, + environment + ) + }.to raise_error(/Failed to get the user image information for the stemcell `#{stemcell_id}'/) + end end context 'when a heavy stemcell is used' do @@ -295,7 +342,7 @@ disk_locality, environment ) - ).to eq(instance_id) + ).to eq(instance_id_string) end end @@ -327,7 +374,43 @@ disk_locality, environment ) - ).to eq(instance_id) + ).to eq(instance_id_string) + end + end + + context 'when resource group is specified' do + let(:resource_group_name) { 'fake-resource-group-name' } + let(:resource_pool) { + { + 'instance_type' => 'fake-vm-size', + 'resource_group_name' => resource_group_name + } + } + + before do + allow(stemcell_manager2).to receive(:get_user_image_info). + and_return(stemcell_info) + end + + it 'should create the VM in the specified resource group' do + expect(Bosh::AzureCloud::InstanceId).to receive(:create). + with(resource_group_name, agent_id). + and_return(instance_id) + expect(vm_manager).to receive(:create). + with(instance_id, location, stemcell_info, resource_pool, network_configurator, environment). + and_return(vm_params) + expect(registry).to receive(:update_settings) + + expect( + managed_cloud.create_vm( + agent_id, + stemcell_id, + resource_pool, + networks_spec, + disk_locality, + environment + ) + ).to eq(instance_id_string) end end end diff --git a/src/bosh_azure_cpi/spec/unit/cloud/delete_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/delete_disk_spec.rb index 0780fc069..f2b76ede3 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/delete_disk_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/delete_disk_spec.rb @@ -5,12 +5,26 @@ include_context "shared stuff" describe "#delete_disk" do + let(:disk_id) { "fake-disk-id" } + let(:disk_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + context "when use_managed_disks is true" do + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + with(disk_id, azure_properties_managed). + and_return(disk_id_object) + end + context "when the disk is a newly-created managed disk" do - let(:disk_id) { "bosh-disk-data-guid" } + let(:disk_name) { "bosh-disk-data-guid" } + + before do + allow(disk_id_object).to receive(:disk_name). + and_return(disk_name) + end it "should delete the managed disk" do - expect(disk_manager2).to receive(:delete_disk).with(disk_id) + expect(disk_manager2).to receive(:delete_data_disk).with(disk_id_object) expect { managed_cloud.delete_disk(disk_id) }.not_to raise_error @@ -18,16 +32,18 @@ end context "when the disk is a managed disk which is created from a blob disk" do - let(:disk_id) { "bosh-data-guid" } + let(:disk_name) { "bosh-data-guid" } let(:disk) { double("disk") } before do - allow(disk_manager2).to receive(:get_disk).with(disk_id).and_return(disk) + allow(disk_manager2).to receive(:get_data_disk).with(disk_id_object).and_return(disk) + allow(disk_id_object).to receive(:disk_name). + and_return(disk_name) end it "should delete the managed disk" do - expect(disk_manager2).to receive(:delete_disk).with(disk_id) - expect(disk_manager).not_to receive(:delete_disk) + expect(disk_manager2).to receive(:delete_data_disk).with(disk_id_object) + expect(disk_manager).not_to receive(:delete_data_disk) expect { managed_cloud.delete_disk(disk_id) }.not_to raise_error @@ -35,15 +51,17 @@ end context "when the disk is an unmanaged disk" do - let(:disk_id) { "bosh-data-guid" } + let(:disk_name) { "bosh-data-guid" } before do - allow(disk_manager2).to receive(:get_disk).with(disk_id).and_return(nil) + allow(disk_manager2).to receive(:get_data_disk).with(disk_id_object).and_return(nil) + allow(disk_id_object).to receive(:disk_name). + and_return(disk_name) end it "should delete the unmanaged disk" do - expect(disk_manager2).not_to receive(:delete_disk) - expect(disk_manager).to receive(:delete_disk).with(disk_id) + expect(disk_manager2).not_to receive(:delete_data_disk) + expect(disk_manager).to receive(:delete_data_disk).with(disk_id_object) expect { managed_cloud.delete_disk(disk_id) }.not_to raise_error @@ -53,10 +71,14 @@ end context "when use_managed_disks is false" do - let(:disk_id) { "bosh-data-guid" } + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + with(disk_id, azure_properties). + and_return(disk_id_object) + end it "should delete the unmanaged disk" do - expect(disk_manager).to receive(:delete_disk).with(disk_id) + expect(disk_manager).to receive(:delete_data_disk).with(disk_id_object) expect { cloud.delete_disk(disk_id) }.not_to raise_error diff --git a/src/bosh_azure_cpi/spec/unit/cloud/delete_snapshot_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/delete_snapshot_spec.rb index c97280010..2f5e74f1e 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/delete_snapshot_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/delete_snapshot_spec.rb @@ -6,10 +6,19 @@ describe "#delete_snapshot" do context "when the snapshot is a managed snapshot" do - let(:snapshot_id) { 'bosh-disk-data-fake-guid' } + let(:snapshot_id) { 'fake-snapshot-id' } + let(:snapshot_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + let(:snapshot_name) { 'bosh-disk-data-fake-guid' } + + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + and_return(snapshot_id_object) + allow(snapshot_id_object).to receive(:disk_name). + and_return(snapshot_name) + end it 'should delete the managed snapshot' do - expect(disk_manager2).to receive(:delete_snapshot).with(snapshot_id) + expect(disk_manager2).to receive(:delete_snapshot).with(snapshot_id_object) expect { cloud.delete_snapshot(snapshot_id) @@ -19,9 +28,18 @@ context "when the snapshot is an unmanaged snapshot" do let(:snapshot_id) { 'fake-snapshot-id' } + let(:snapshot_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + let(:snapshot_name) { 'fake-snapshot-name' } + + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + and_return(snapshot_id_object) + allow(snapshot_id_object).to receive(:disk_name). + and_return(snapshot_name) + end it 'should delete the unmanaged snapshot' do - expect(disk_manager).to receive(:delete_snapshot).with(snapshot_id) + expect(disk_manager).to receive(:delete_snapshot).with(snapshot_id_object) expect { cloud.delete_snapshot(snapshot_id) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/delete_vm_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/delete_vm_spec.rb index 0c7be4b40..75b8b299b 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/delete_vm_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/delete_vm_spec.rb @@ -7,9 +7,14 @@ describe "#delete_vm" do # Parameters let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } it 'should delete an instance' do - expect(vm_manager).to receive(:delete).with(instance_id) + expect(Bosh::AzureCloud::InstanceId).to receive(:parse). + with(instance_id, azure_properties). + and_return(instance_id_object) + + expect(vm_manager).to receive(:delete).with(instance_id_object) expect { cloud.delete_vm(instance_id) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/detach_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/detach_disk_spec.rb index 4203d8ca6..0ddb3481b 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/detach_disk_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/detach_disk_spec.rb @@ -5,10 +5,19 @@ include_context "shared stuff" describe "#detach_disk" do - let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + let(:instance_id) { "fake-instance-id" } let(:disk_id) { "fake-disk-id" } let(:host_device_id) { 'fake-host-device-id' } - + let(:disk_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } + + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + and_return(disk_id_object) + allow(Bosh::AzureCloud::InstanceId).to receive(:parse). + and_return(instance_id_object) + end + it 'detaches the disk from the vm' do old_settings = { "foo" => "bar", @@ -47,7 +56,7 @@ expect(registry).to receive(:update_settings). with(instance_id, new_settings) - expect(vm_manager).to receive(:detach_disk).with(instance_id, disk_id) + expect(vm_manager).to receive(:detach_disk).with(instance_id_object, disk_id_object) expect { cloud.detach_disk(instance_id, disk_id) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/get_disks_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/get_disks_spec.rb index 545208064..364fbe2d3 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/get_disks_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/get_disks_spec.rb @@ -5,16 +5,20 @@ include_context "shared stuff" describe "#get_disks" do - let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + let(:instance_id) { "fake-instance-id" } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } let(:data_disks) { [ { :name => "fake-data-disk-1", + :disk_bosh_id => "fake-id-1", }, { :name => "fake-data-disk-2", + :disk_bosh_id => "fake-id-2", }, { :name => "fake-data-disk-3", + :disk_bosh_id => "fake-id-3", } ] } @@ -28,21 +32,26 @@ :data_disks => {}, } } - + + before do + allow(Bosh::AzureCloud::InstanceId).to receive(:parse). + and_return(instance_id_object) + end + context 'when the instance has data disks' do it 'should get a list of disk id' do expect(vm_manager).to receive(:find). - with(instance_id). + with(instance_id_object). and_return(instance) - expect(cloud.get_disks(instance_id)).to eq(["fake-data-disk-1", "fake-data-disk-2", "fake-data-disk-3"]) + expect(cloud.get_disks(instance_id)).to eq(["fake-id-1", "fake-id-2", "fake-id-3"]) end end context 'when the instance has no data disk' do it 'should get a empty list' do expect(vm_manager).to receive(:find). - with(instance_id). + with(instance_id_object). and_return(instance_no_disks) expect(cloud.get_disks(instance_id)).to eq([]) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/has_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/has_disk_spec.rb index 816cd133d..05b0bda84 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/has_disk_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/has_disk_spec.rb @@ -6,11 +6,18 @@ describe "#has_disk?" do let(:disk_id) { "fake-disk-id" } + let(:disk_id_object) { instance_double(Bosh::AzureCloud::DiskId) } context "when use_managed_disks is true" do + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + with(disk_id, azure_properties_managed). + and_return(disk_id_object) + end + context 'when the managed disk exists' do before do - allow(disk_manager2).to receive(:has_disk?).with(disk_id).and_return(true) + allow(disk_manager2).to receive(:has_data_disk?).with(disk_id_object).and_return(true) end it 'should return true' do @@ -20,28 +27,28 @@ context 'when the managed disk does not exist' do before do - allow(disk_manager2).to receive(:has_disk?).with(disk_id).and_return(false) + allow(disk_manager2).to receive(:has_data_disk?).with(disk_id_object).and_return(false) end context 'when the disk has been migrated from unmanaged to managed' do before do - allow(disk_manager).to receive(:is_migrated?).with(disk_id).and_return(true) + allow(disk_manager).to receive(:is_migrated?).with(disk_id_object).and_return(true) end it 'should return false' do - expect(disk_manager).not_to receive(:has_disk?) + expect(disk_manager).not_to receive(:has_data_disk?) expect(managed_cloud.has_disk?(disk_id)).to be(false) end end context 'when the disk is not migrated from unmanaged to managed' do before do - allow(disk_manager).to receive(:is_migrated?).with(disk_id).and_return(false) + allow(disk_manager).to receive(:is_migrated?).with(disk_id_object).and_return(false) end context 'when the unmanaged disk exists' do before do - allow(disk_manager).to receive(:has_disk?).with(disk_id).and_return(true) + allow(disk_manager).to receive(:has_data_disk?).with(disk_id_object).and_return(true) end it 'should return true' do @@ -51,7 +58,7 @@ context 'when the unmanaged disk does not exist' do before do - allow(disk_manager).to receive(:has_disk?).with(disk_id).and_return(false) + allow(disk_manager).to receive(:has_data_disk?).with(disk_id_object).and_return(false) end it 'should return false' do @@ -63,9 +70,15 @@ end context "when use_managed_disks is false" do + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + with(disk_id, azure_properties). + and_return(disk_id_object) + end + context 'when the unmanaged disk exists' do before do - allow(disk_manager).to receive(:has_disk?).with(disk_id).and_return(true) + allow(disk_manager).to receive(:has_data_disk?).with(disk_id_object).and_return(true) end it 'should return true' do @@ -75,7 +88,7 @@ context 'when the unmanaged disk does not exist' do before do - allow(disk_manager).to receive(:has_disk?).with(disk_id).and_return(false) + allow(disk_manager).to receive(:has_data_disk?).with(disk_id_object).and_return(false) end it 'should return false' do diff --git a/src/bosh_azure_cpi/spec/unit/cloud/has_vm_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/has_vm_spec.rb index 64d354eac..ba61f4af1 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/has_vm_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/has_vm_spec.rb @@ -6,11 +6,18 @@ describe '#has_vm?' do let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } let(:instance) { double("instance") } + before do + allow(Bosh::AzureCloud::InstanceId).to receive(:parse). + with(instance_id, azure_properties). + and_return(instance_id_object) + end + context "when the instance exists" do before do - allow(vm_manager).to receive(:find).with(instance_id). + allow(vm_manager).to receive(:find).with(instance_id_object). and_return(instance) allow(instance).to receive(:[]).with(:provisioning_state). and_return('Running') @@ -23,7 +30,7 @@ context "when the instance doesn't exists" do before do - allow(vm_manager).to receive(:find).with(instance_id).and_return(nil) + allow(vm_manager).to receive(:find).with(instance_id_object).and_return(nil) end it "should return false" do @@ -33,7 +40,7 @@ context "when the instance state is Deleting" do before do - allow(vm_manager).to receive(:find).with(instance_id). + allow(vm_manager).to receive(:find).with(instance_id_object). and_return(instance) allow(instance).to receive(:[]).with(:provisioning_state). and_return('Deleting') diff --git a/src/bosh_azure_cpi/spec/unit/cloud/reboot_vm_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/reboot_vm_spec.rb index a0b889555..647372fc1 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/reboot_vm_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/reboot_vm_spec.rb @@ -6,9 +6,16 @@ describe "#reboot_vm" do let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } + + before do + allow(Bosh::AzureCloud::InstanceId).to receive(:parse). + with(instance_id, azure_properties). + and_return(instance_id_object) + end it 'reboot an instance' do - expect(vm_manager).to receive(:reboot).with(instance_id) + expect(vm_manager).to receive(:reboot).with(instance_id_object) expect { cloud.reboot_vm(instance_id) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/set_vm_metadata_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/set_vm_metadata_spec.rb index 5afb1d405..8daf41c3d 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/set_vm_metadata_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/set_vm_metadata_spec.rb @@ -6,12 +6,19 @@ describe '#set_vm_metadata' do let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } + let(:instance_id_object) { instance_double(Bosh::AzureCloud::InstanceId) } + + before do + allow(Bosh::AzureCloud::InstanceId).to receive(:parse). + with(instance_id, azure_properties). + and_return(instance_id_object) + end context "when the metadata is not encoded" do let(:metadata) { {"user-agent"=>"bosh"} } it 'should set the vm metadata' do - expect(vm_manager).to receive(:set_metadata).with(instance_id, metadata) + expect(vm_manager).to receive(:set_metadata).with(instance_id_object, metadata) expect { cloud.set_vm_metadata(instance_id, metadata) @@ -34,7 +41,7 @@ } it 'should set the vm metadata' do - expect(vm_manager).to receive(:set_metadata).with(instance_id, encoded_metadata) + expect(vm_manager).to receive(:set_metadata).with(instance_id_object, encoded_metadata) expect { cloud.set_vm_metadata(instance_id, metadata) diff --git a/src/bosh_azure_cpi/spec/unit/cloud/snapshot_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/cloud/snapshot_disk_spec.rb index c9bc908b1..9583b40ce 100644 --- a/src/bosh_azure_cpi/spec/unit/cloud/snapshot_disk_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/cloud/snapshot_disk_spec.rb @@ -7,33 +7,62 @@ describe "#snapshot_disk" do let(:metadata) { {} } let(:snapshot_id) { 'fake-snapshot-id' } + let(:snapshot_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + let(:resource_group_name) { "fake-resource-group-name" } + let(:caching) { "fake-cacing" } + let(:disk_id) { "fake-disk-id" } + let(:disk_id_object) { instance_double(Bosh::AzureCloud::DiskId) } + + before do + allow(Bosh::AzureCloud::DiskId).to receive(:parse). + and_return(disk_id_object) + + allow(snapshot_id_object).to receive(:to_s). + and_return(snapshot_id) + + allow(disk_id_object).to receive(:resource_group_name). + and_return(resource_group_name) + allow(disk_id_object).to receive(:caching). + and_return(caching) + end context "when the disk is a managed disk" do context "when the disk starts with bosh-disk-data" do - let(:disk_id) { "bosh-disk-data-fake-guid" } + let(:disk_name) { "bosh-disk-data-fake-guid" } + + before do + allow(disk_id_object).to receive(:disk_name). + and_return(disk_name) + end it 'should take a managed snapshot of the disk' do + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, true, resource_group_name: resource_group_name). + and_return(snapshot_id_object) expect(disk_manager2).to receive(:snapshot_disk). - with(disk_id, metadata). - and_return(snapshot_id) + with(snapshot_id_object, disk_name, metadata) expect(cloud.snapshot_disk(disk_id, metadata)).to eq(snapshot_id) end end - context "when the disk starts with bosh-disk-data" do - let(:disk_id) { "fakestorageaccountname-fake-guid" } + context "when the disk NOT start with bosh-disk-data" do + let(:disk_name) { "fakestorageaccountname-fake-guid" } before do - expect(disk_manager2).to receive(:get_disk). - with(disk_id). + allow(disk_id_object).to receive(:disk_name). + and_return(disk_name) + expect(disk_manager2).to receive(:get_data_disk). + with(disk_id_object). and_return({:name=>disk_id}) end it 'should take a managed snapshot of the disk' do + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, true, resource_group_name: resource_group_name). + and_return(snapshot_id_object) expect(disk_manager2).to receive(:snapshot_disk). - with(disk_id, metadata). - and_return(snapshot_id) + with(snapshot_id_object, disk_name, metadata) expect(cloud.snapshot_disk(disk_id, metadata)).to eq(snapshot_id) end @@ -41,18 +70,27 @@ end context "when the disk is an unmanaged disk" do - let(:disk_id) { "fakestorageaccountname-fake-guid" } + let(:storage_account_name) { "fake-storage-account-name" } + let(:disk_name) { "fake-disk-name" } + let(:snapshot_name) { "fake-snapshot-name" } before do - expect(disk_manager2).to receive(:get_disk). - with(disk_id). + allow(disk_id_object).to receive(:disk_name). + and_return(disk_name) + allow(disk_id_object).to receive(:storage_account_name). + and_return(storage_account_name) + allow(disk_manager2).to receive(:get_data_disk). + with(disk_id_object). and_return(nil) end it 'should take an unmanaged snapshot of the disk' do expect(disk_manager).to receive(:snapshot_disk). - with(disk_id, metadata). - and_return(snapshot_id) + with(storage_account_name, disk_name, metadata). + and_return(snapshot_name) + expect(Bosh::AzureCloud::DiskId).to receive(:create). + with(caching, false, disk_name: snapshot_name, storage_account_name: storage_account_name). + and_return(snapshot_id_object) expect(cloud.snapshot_disk(disk_id, metadata)).to eq(snapshot_id) end diff --git a/src/bosh_azure_cpi/spec/unit/disk_id_spec.rb b/src/bosh_azure_cpi/spec/unit/disk_id_spec.rb new file mode 100644 index 000000000..bac8f570d --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/disk_id_spec.rb @@ -0,0 +1,422 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::DiskId do + describe '#self.create' do + let(:caching) { 'None' } + let(:use_managed_disks) { true } + + context 'when creating a new disk' do + let(:disk_name) { 'fake-disk-name' } + let(:id) { + { + 'disk_name' => disk_name, + 'caching' => caching + } + } + + before do + allow(Bosh::AzureCloud::DiskId).to receive(:generate_data_disk_name). + with(use_managed_disks). + and_return(disk_name) + end + + it 'should generate a disk name and initialize the disk_id' do + expect(Bosh::AzureCloud::DiskId).to receive(:new). + with('v2', {:id => id}) + expect { + Bosh::AzureCloud::DiskId.create(caching, use_managed_disks) + }.not_to raise_error + end + end + + context 'when creating a new disk with a specified name' do + let(:disk_name) { 'fake-disk-name' } + let(:id) { + { + 'disk_name' => disk_name, + 'caching' => caching + } + } + + it 'should not generate a disk name and initialize the disk_id' do + disk_id = Bosh::AzureCloud::DiskId.create(caching, use_managed_disks, disk_name: disk_name) + expect(disk_id.instance_variable_get("@version")).to eq('v2') + expect(disk_id.instance_variable_get("@id")).to eq(id) + end + end + + context 'when resource_group_name is NOT nil' do + let(:disk_name) { 'fake-disk-name' } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:id) { + { + 'disk_name' => disk_name, + 'caching' => caching, + 'resource_group_name' => resource_group_name + } + } + + it 'should initialize the disk_id' do + expect(Bosh::AzureCloud::DiskId).not_to receive(:generate_data_disk_name) + + disk_id = Bosh::AzureCloud::DiskId.create(caching, use_managed_disks, disk_name: disk_name, resource_group_name: resource_group_name) + expect(disk_id.instance_variable_get("@version")).to eq('v2') + expect(disk_id.instance_variable_get("@id")).to eq(id) + end + end + + context 'when storage_account_name is NOT nil' do + let(:disk_name) { 'fake-disk-name' } + let(:storage_account_name) { 'fake-storage-account-name' } + let(:id) { + { + 'disk_name' => disk_name, + 'caching' => caching, + 'storage_account_name' => storage_account_name + } + } + + it 'should initialize the disk_id' do + expect(Bosh::AzureCloud::DiskId).not_to receive(:generate_data_disk_name) + disk_id = Bosh::AzureCloud::DiskId.create(caching, use_managed_disks, disk_name: disk_name, storage_account_name: storage_account_name) + expect(disk_id.instance_variable_get("@version")).to eq('v2') + expect(disk_id.instance_variable_get("@id")).to eq(id) + end + end + end + + describe '#self.parse' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:disk_id) { instance_double(Bosh::AzureCloud::DiskId) } + + before do + allow(disk_id).to receive(:validate) + end + + context 'when id contains ":"' do + let(:id) { 'a:a;b:b' } + let(:id_hash) { + { + 'a' => 'a', + 'b' => 'b' + } + } + let(:options) { + { + :id => id_hash, + :default_resource_group_name => 'default-resource-group-name' + } + } + + it 'should initialize a v2 disk_id' do + expect(Bosh::AzureCloud::DiskId).to receive(:new). + with('v2', options). + and_return(disk_id) + expect { + Bosh::AzureCloud::DiskId.parse(id, azure_properties) + }.not_to raise_error + end + end + + context 'when id does not contain ":"' do + let(:id) { 'fake-id' } + let(:options) { + { + :id => id, + :default_resource_group_name => 'default-resource-group-name' + } + } + + it 'should initialize a v1 disk_id' do + expect(Bosh::AzureCloud::DiskId).to receive(:new). + with('v1', options). + and_return(disk_id) + expect { + Bosh::AzureCloud::DiskId.parse(id, azure_properties) + }.not_to raise_error + end + end + end + + describe '#self.generate_data_disk_name' do + context 'when use_managed_disks is true' do + it 'should generate a disk name with prefix bosh-disk-data' do + expect(Bosh::AzureCloud::DiskId.generate_data_disk_name(true)).to start_with('bosh-disk-data') + end + end + + context 'when use_managed_disks is false' do + it 'should generate a disk name with prefix bosh-data' do + expect(Bosh::AzureCloud::DiskId.generate_data_disk_name(false)).to start_with('bosh-data') + end + end + end + + describe '#to_s' do + context 'when disk id is a v1 id' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:disk_id_string) { 'fake-disk-id' } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the v1 string' do + expect(disk_id.to_s).to eq(disk_id_string) + end + end + + context 'when disk id is a v2 id' do + context 'when disk id is initialized by self.parse' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:disk_id_string) { 'caching:c;disk_name:bosh-disk-data-d;resource_group_name:r' } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the v2 string' do + expect(disk_id.to_s).to eq(disk_id_string) + end + end + + context 'when disk id is initialized by self.create' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:caching) { 'None' } + let(:disk_name) { 'bosh-disk-data-fake-disk-name' } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:disk_id_string) { "caching:#{caching};disk_name:#{disk_name};resource_group_name:#{resource_group_name}" } + let(:disk_id) { Bosh::AzureCloud::DiskId.create(caching, true, disk_name: disk_name, resource_group_name: resource_group_name) } + + it 'should return the v2 string' do + expect(disk_id.to_s).to eq(disk_id_string) + end + end + + context 'when the same disk id is initialized by self.create and self.parse' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:caching) { 'None' } + let(:disk_name) { 'bosh-disk-data-fake-disk-name' } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:disk_id_1) { Bosh::AzureCloud::DiskId.create(caching, true, disk_name: disk_name, resource_group_name: resource_group_name) } + let(:disk_id_2) { Bosh::AzureCloud::DiskId.parse(disk_id_1.to_s, azure_properties) } + + it 'should have same output string' do + expect(disk_id_1.to_s).to eq(disk_id_2.to_s) + end + end + end + end + + describe '#resource_group_name' do + context 'when disk id is a v1 id' do + let(:default_resource_group_name) { 'fake-resource-group-name' } + let(:azure_properties) { { 'resource_group_name' => default_resource_group_name } } + let(:disk_id_string) { "bosh-disk-data-#{SecureRandom.uuid}-None" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the default resource group' do + expect(disk_id.resource_group_name).to eq(default_resource_group_name) + end + end + + context 'when disk id is a v2 id' do + context 'when disk id contains resource_group_name' do + let(:default_resource_group_name) { 'fake-resource-group-name' } + let(:azure_properties) { { 'resource_group_name' => default_resource_group_name } } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:disk_id_string) { "disk_name:bosh-disk-data-fake-uuid;caching:None;resource_group_name:#{resource_group_name}" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the resource group specified in disk id' do + expect(disk_id.resource_group_name).to eq(resource_group_name) + end + end + + context 'when disk id does not contain resource_group_name' do + let(:default_resource_group_name) { 'fake-resource-group-name' } + let(:azure_properties) { { 'resource_group_name' => default_resource_group_name } } + let(:disk_id_string) { 'disk_name:bosh-data-fake-uuid;caching:None;storage_account_name:fake-storage-account-name' } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the default resource group' do + expect(disk_id.resource_group_name).to eq(default_resource_group_name) + end + end + end + end + + describe '#disk_name' do + context 'when disk id is a v1 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:disk_id_string) { "bosh-disk-data-#{SecureRandom.uuid}-None" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return v1 id' do + expect(disk_id.disk_name).to eq(disk_id_string) + end + end + + context 'when disk id is a v2 id' do + context 'when disk_name contains ":"' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:disk_name) { 'bosh-data-fake-uuid--a:b:c' } + let(:disk_id_string) { "disk_name:#{disk_name};caching:cc;storage_account_name:ss" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the disk name specified in disk id' do + expect(disk_id.disk_name).to eq(disk_name) + end + end + + context 'when disk_name does not contain ":"' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:disk_name) { 'bosh-disk-data-fake-uuid' } + let(:disk_id_string) { "disk_name:#{disk_name};caching:cc;resource_group_name:rr" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the disk name specified in disk id' do + expect(disk_id.disk_name).to eq(disk_name) + end + end + end + end + + describe '#caching' do + context 'when disk id is a v1 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:caching) { 'None' } + let(:disk_id_string) { "bosh-disk-data-#{SecureRandom.uuid}-#{caching}" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should get caching from v1 disk name' do + expect(disk_id.caching).to eq(caching) + end + end + + context 'when disk id is a v2 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:caching) { 'None' } + let(:disk_id_string) { "disk_name:bosh-disk-data-uuid;caching:#{caching};resource_group_name:rr" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return caching specified in disk id' do + expect(disk_id.caching).to eq(caching) + end + end + + context 'when disk name does not start with bosh-disk-data or bosh-data' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:caching) { 'None' } + let(:disk_name) { "dd" } + let(:disk_id) { Bosh::AzureCloud::DiskId.create(caching, true, disk_name: disk_name, resource_group_name: 'rr') } + + it 'should raise an error' do + expect { + disk_id.caching() + }.to raise_error /This function should only be called for data disks/ + end + end + end + + describe '#storage_account_name' do + context 'when disk id is a v1 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:caching) { 'None' } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:disk_id_string) { "bosh-data-#{storage_account_name}-#{SecureRandom.uuid}-#{caching}" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should get storage account from v1 disk name' do + expect(disk_id.storage_account_name).to eq(storage_account_name) + end + end + + context 'when disk id is a v2 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:disk_id_string) { "disk_name:bosh-data-uuid;caching:cc;storage_account_name:#{storage_account_name}" } + let(:disk_id) { Bosh::AzureCloud::DiskId.parse(disk_id_string, azure_properties) } + + it 'should return the resource group specified in disk id' do + expect(disk_id.storage_account_name).to eq(storage_account_name) + end + end + + context 'when disk name starts with bosh-disk-data (managed)' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:caching) { 'None' } + let(:disk_id) { Bosh::AzureCloud::DiskId.create(caching, true, resource_group_name: 'rr') } + + it 'should raise an error' do + expect { + disk_id.storage_account_name() + }.to raise_error /This function should only be called for unmanaged disks/ + end + end + end + + describe '#validate' do + context 'disk name' do + context 'when it is empty' do + let(:disk_id) { Bosh::AzureCloud::DiskId.create('None', true, disk_name: '', resource_group_name: 'r') } + + it 'should raise an error' do + expect { + disk_id.validate() + }.to raise_error /Invalid disk_name in disk id \(version 2\)/ + end + end + end + + context 'caching' do + context 'when it is nil' do + let(:disk_id) { Bosh::AzureCloud::DiskId.create(nil, true, resource_group_name: 'r') } + + it 'should raise an error' do + expect { + disk_id.validate() + }.to raise_error /Invalid caching in disk id \(version 2\)/ + end + end + + context 'when it is empty' do + let(:disk_id) { Bosh::AzureCloud::DiskId.create('', true, resource_group_name: 'r') } + + it 'should raise an error' do + expect { + disk_id.validate() + }.to raise_error /Invalid caching in disk id \(version 2\)/ + end + end + end + + context 'resource_group_name' do + context 'when it is empty' do + let(:disk_id) { Bosh::AzureCloud::DiskId.create('None', true, resource_group_name: '') } + + it 'should raise an error' do + expect { + disk_id.validate() + }.to raise_error /Invalid resource_group_name in disk id \(version 2\)/ + end + end + end + + context 'storage_account_name' do + context 'when it is nil' do + let(:disk_id) { Bosh::AzureCloud::DiskId.create('None', false) } + + it 'should raise an error' do + expect { + disk_id.validate() + }.to raise_error /Invalid storage_account_name in disk id \(version 2\)/ + end + end + + context 'when it is empty' do + let(:disk_id) { Bosh::AzureCloud::DiskId.create('None', false, storage_account_name: '') } + + it 'should raise an error' do + expect { + disk_id.validate() + }.to raise_error /Invalid storage_account_name in disk id \(version 2\)/ + end + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/disk_manager2_spec.rb b/src/bosh_azure_cpi/spec/unit/disk_manager2_spec.rb index e88f365d8..4e406e66c 100644 --- a/src/bosh_azure_cpi/spec/unit/disk_manager2_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/disk_manager2_spec.rb @@ -3,14 +3,27 @@ describe Bosh::AzureCloud::DiskManager2 do let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } let(:disk_manager2) { Bosh::AzureCloud::DiskManager2.new(client2) } + let(:disk_id) { instance_double(Bosh::AzureCloud::DiskId) } + let(:snapshot_id) { instance_double(Bosh::AzureCloud::DiskId) } let(:managed_os_disk_prefix) { "bosh-disk-os" } let(:managed_data_disk_prefix) { "bosh-disk-data" } let(:uuid) { "c691bf30-b72c-44de-907e-8b80823ec848" } - let(:disk_name) { "#{managed_data_disk_prefix}-#{uuid}-None" } + let(:disk_name) { "fake-disk-name" } + let(:caching) { "fake-caching" } + let(:resource_group_name) { "fake-resource-group-name" } + + let(:snapshot_name) { "fake-snapshot-name" } before do allow(SecureRandom).to receive(:uuid).and_return(uuid) + allow(disk_id).to receive(:disk_name).and_return(disk_name) + allow(disk_id).to receive(:caching).and_return(caching) + allow(disk_id).to receive(:resource_group_name).and_return(resource_group_name) + + allow(snapshot_id).to receive(:disk_name).and_return(snapshot_name) + allow(snapshot_id).to receive(:caching).and_return(caching) + allow(snapshot_id).to receive(:resource_group_name).and_return(resource_group_name) end describe "#create_disk" do @@ -18,9 +31,7 @@ let(:location) { "SouthEastAsia" } let(:size) { 100 } let(:storage_account_type) { "fake-storage-account-type" } - let(:caching) { "ReadOnly" } - let(:disk_name) { "#{managed_data_disk_prefix}-#{uuid}-#{caching}" } let(:disk_params) { { :name => disk_name, @@ -35,17 +46,16 @@ } it "creates the disk with the specified caching and storage account type" do - expect(client2).to receive(:create_empty_managed_disk).with(disk_params) + expect(client2).to receive(:create_empty_managed_disk). + with(resource_group_name, disk_params) expect { - disk_manager2.create_disk(location, size, storage_account_type, caching) + disk_manager2.create_disk(disk_id, location, size, storage_account_type) }.not_to raise_error end - end + end describe "#create_disk_from_blob" do - let(:storage_account_name) { MOCK_DEFAULT_STORAGE_ACCOUNT_NAME } let(:blob_data_disk_prefix) { "bosh-data" } - let(:disk_name) { "#{blob_data_disk_prefix}-#{storage_account_name}-#{uuid}-None" } let(:blob_uri) { "fake-blob-uri" } let(:location) { "SouthEastAsia" } let(:storage_account_type) { "Standard_LRS" } @@ -56,37 +66,38 @@ :location => location, :tags => { "user-agent" => "bosh", - "caching" => "None", + "caching" => caching, "original_blob" => blob_uri }, :source_uri => blob_uri, - :account_type => "Standard_LRS" + :account_type => storage_account_type } } it "creates the managed disk from the blob uri" do - expect(client2).to receive(:create_managed_disk_from_blob).with(disk_params) + expect(client2).to receive(:create_managed_disk_from_blob). + with(resource_group_name, disk_params) expect { - disk_manager2.create_disk_from_blob(disk_name, blob_uri, location, storage_account_type) + disk_manager2.create_disk_from_blob(disk_id, blob_uri, location, storage_account_type) }.not_to raise_error end - end + end describe "#delete_disk" do context "when the disk exists" do before do allow(client2).to receive(:get_managed_disk_by_name). - with(disk_name). + with(resource_group_name, disk_name). and_return({}) end context "when AzureConflictError is not thrown" do it "deletes the disk" do expect(client2).to receive(:delete_managed_disk). - with(disk_name).once + with(resource_group_name, disk_name).once expect { - disk_manager2.delete_disk(disk_name) + disk_manager2.delete_disk(resource_group_name, disk_name) }.not_to raise_error end end @@ -94,13 +105,13 @@ context "when AzureConflictError is thrown only one time" do it "do one retry and deletes the disk" do expect(client2).to receive(:delete_managed_disk). - with(disk_name). + with(resource_group_name, disk_name). and_raise(Bosh::AzureCloud::AzureConflictError) expect(client2).to receive(:delete_managed_disk). - with(disk_name).once + with(resource_group_name, disk_name).once expect { - disk_manager2.delete_disk(disk_name) + disk_manager2.delete_disk(resource_group_name, disk_name) }.not_to raise_error end end @@ -108,13 +119,13 @@ context "when AzureConflictError is thrown every time" do before do allow(client2).to receive(:delete_managed_disk). - with(disk_name). + with(resource_group_name, disk_name). and_raise(Bosh::AzureCloud::AzureConflictError) end it "raise an error because the retry still fails" do expect { - disk_manager2.delete_disk(disk_name) + disk_manager2.delete_disk(resource_group_name, disk_name) }.to raise_error Bosh::AzureCloud::AzureConflictError end end @@ -123,65 +134,96 @@ context "when the disk does not exist" do before do allow(client2).to receive(:get_managed_disk_by_name). - with(disk_name). + with(resource_group_name, disk_name). and_return(nil) end it "does not delete the disk" do expect(client2).not_to receive(:delete_managed_disk). - with(disk_name) + with(resource_group_name, disk_name) expect { - disk_manager2.delete_disk(disk_name) + disk_manager2.delete_disk(resource_group_name, disk_name) }.not_to raise_error end end - end + end + + describe "#delete_data_disk" do + it "should delete the disk" do + expect(disk_manager2).to receive(:delete_disk). + with(resource_group_name, disk_name) + + expect { + disk_manager2.delete_data_disk(disk_id) + }.not_to raise_error + end + end describe "#has_disk?" do context "when the disk exists" do before do allow(client2).to receive(:get_managed_disk_by_name). - with(disk_name). + with(resource_group_name, disk_name). and_return({}) end it "should return true" do - expect(disk_manager2.has_disk?(disk_name)).to be(true) + expect(disk_manager2.has_disk?(resource_group_name, disk_name)).to be(true) end end context "when the disk does not exist" do before do allow(client2).to receive(:get_managed_disk_by_name). - with(disk_name). + with(resource_group_name, disk_name). and_return(nil) end it "should return false" do - expect(disk_manager2.has_disk?(disk_name)).to be(false) + expect(disk_manager2.has_disk?(resource_group_name, disk_name)).to be(false) end end end + describe "#has_data_disk?" do + it "should check the disk" do + expect(disk_manager2).to receive(:has_disk?). + with(resource_group_name, disk_name). + and_return(true) + + expect(disk_manager2.has_data_disk?(disk_id)).to be(true) + end + end + describe "#get_disk" do let(:disk) { { :name => "fake-name" } } before do allow(client2).to receive(:get_managed_disk_by_name). - with(disk_name). + with(resource_group_name, disk_name). and_return(disk) end it "should get the disk" do - expect(disk_manager2.get_disk(disk_name)).to be(disk) + expect(disk_manager2.get_disk(resource_group_name, disk_name)).to be(disk) + end + end + + describe "#get_data_disk" do + it "should get the disk" do + expect(disk_manager2).to receive(:get_disk). + with(resource_group_name, disk_name) + + expect { + disk_manager2.get_data_disk(disk_id) + }.not_to raise_error end end describe "#snapshot_disk" do let(:metadata) { {"foo" => "bar"} } - let(:snapshot_name) { "#{managed_data_disk_prefix}-#{uuid}-None" } let(:snapshot_params) { { :name => snapshot_name, @@ -194,43 +236,40 @@ } it "creates the managed snapshot" do - expect(client2).to receive(:create_managed_snapshot).with(snapshot_params) + expect(client2).to receive(:create_managed_snapshot).with(resource_group_name, snapshot_params) expect { - disk_manager2.snapshot_disk(disk_name, metadata) + disk_manager2.snapshot_disk(snapshot_id, disk_name, metadata) }.not_to raise_error end - end + end describe "#delete_snapshot" do - let(:snapshot_name) { "#{managed_data_disk_prefix}-#{uuid}-None" } - it "deletes the snapshot" do - expect(client2).to receive(:delete_managed_snapshot).with(snapshot_name) + expect(client2).to receive(:delete_managed_snapshot).with(resource_group_name, snapshot_name) - disk_manager2.delete_snapshot(snapshot_name) + disk_manager2.delete_snapshot(snapshot_id) end - end + end describe "#generate_os_disk_name" do - let(:instance_id) { "fake-instance-id" } + let(:vm_name) { "fake-vm-name" } it "returns the right os disk name" do - expect(disk_manager2.generate_os_disk_name(instance_id)).to eq("#{managed_os_disk_prefix}-fake-instance-id") + expect(disk_manager2.generate_os_disk_name(vm_name)).to eq("#{managed_os_disk_prefix}-#{vm_name}") end end describe "#generate_ephemeral_disk_name" do - let(:instance_id) { "fake-instance-id" } + let(:vm_name) { "fake-vm-name" } it "returns the right ephemeral disk name" do - expect(disk_manager2.generate_ephemeral_disk_name(instance_id)).to eq("#{managed_os_disk_prefix}-fake-instance-id-ephemeral-disk") + expect(disk_manager2.generate_ephemeral_disk_name(vm_name)).to eq("#{managed_os_disk_prefix}-#{vm_name}-ephemeral-disk") end end describe "#os_disk" do - let(:disk_name) { 'fake-disk-name' } - let(:instance_id) { 'fake-instance-id' } + let(:vm_name) { 'fake-vm-name' } let(:minimum_disk_size) { 3072 } before do @@ -249,7 +288,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -274,7 +313,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -297,7 +336,7 @@ disk_manager2.resource_pool = resource_pool expect { - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) }.to raise_error /Unknown disk caching/ end end @@ -317,7 +356,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -343,7 +382,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -369,7 +408,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -395,7 +434,7 @@ disk_manager2.resource_pool = resource_pool expect { - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) }.to raise_error /root_disk.size `2048' is smaller than the default OS disk size `3072' MiB/ end end @@ -415,7 +454,7 @@ disk_manager2.resource_pool = resource_pool expect { - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) }.to raise_error /root_disk.size `2048' is smaller than the default OS disk size `4096' MiB/ end end @@ -434,7 +473,7 @@ disk_manager2.resource_pool = resource_pool expect { - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) }.to raise_error ArgumentError, "The disk size needs to be an integer. The current value is `invalid-size'." end end @@ -453,7 +492,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.os_disk(instance_id, minimum_disk_size) + disk_manager2.os_disk(vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -468,8 +507,8 @@ end describe "#ephemeral_disk" do - let(:instance_id) { 'fake-instance-id' } - let(:disk_name) { "#{managed_os_disk_prefix}-#{instance_id}-ephemeral-disk" } + let(:vm_name) { 'fake-vm-name' } + let(:disk_name) { "#{managed_os_disk_prefix}-#{vm_name}-ephemeral-disk" } context "without ephemeral_disk" do context "with a valid instance_type" do @@ -483,7 +522,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.ephemeral_disk(instance_id) + disk_manager2.ephemeral_disk(vm_name) ).to eq( { :disk_name => disk_name, @@ -505,7 +544,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.ephemeral_disk(instance_id) + disk_manager2.ephemeral_disk(vm_name) ).to eq( { :disk_name => disk_name, @@ -533,7 +572,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.ephemeral_disk(instance_id) + disk_manager2.ephemeral_disk(vm_name) ).to eq( { :disk_name => disk_name, @@ -558,7 +597,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.ephemeral_disk(instance_id) + disk_manager2.ephemeral_disk(vm_name) ).to be_nil end end @@ -577,7 +616,7 @@ disk_manager2.resource_pool = resource_pool expect( - disk_manager2.ephemeral_disk(instance_id) + disk_manager2.ephemeral_disk(vm_name) ).to eq( { :disk_name => disk_name, @@ -598,7 +637,7 @@ } } } - + end context "when the size is not an integer" do @@ -615,7 +654,7 @@ disk_manager2.resource_pool = resource_pool expect { - disk_manager2.ephemeral_disk(instance_id) + disk_manager2.ephemeral_disk(vm_name) }.to raise_error ArgumentError, "The disk size needs to be an integer. The current value is `invalid-size'." end end @@ -623,11 +662,4 @@ end end end - - describe "#get_data_disk_caching" do - it "returns the right caching" do - expect(disk_manager2.get_data_disk_caching(disk_name)).to eq("None") - end - end - end diff --git a/src/bosh_azure_cpi/spec/unit/disk_manager_spec.rb b/src/bosh_azure_cpi/spec/unit/disk_manager_spec.rb index e08748b33..83a211ff1 100644 --- a/src/bosh_azure_cpi/spec/unit/disk_manager_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/disk_manager_spec.rb @@ -4,12 +4,22 @@ let(:azure_properties) { mock_azure_properties } let(:blob_manager) { instance_double(Bosh::AzureCloud::BlobManager) } let(:disk_manager) { Bosh::AzureCloud::DiskManager.new(azure_properties, blob_manager) } + let(:disk_id) { instance_double(Bosh::AzureCloud::DiskId) } + let(:snapshot_id) { instance_double(Bosh::AzureCloud::DiskId) } + + let(:storage_account_name) { "fake_storage_account_name" } + let(:disk_name) { "fake-disk-name" } + let(:caching) { "fake-caching" } - let(:storage_account_name) { MOCK_DEFAULT_STORAGE_ACCOUNT_NAME } let(:disk_container) { "bosh" } let(:os_disk_prefix) { "bosh-os" } let(:data_disk_prefix) { "bosh-data" } - let(:disk_name) { "#{data_disk_prefix}-#{storage_account_name}-#{SecureRandom.uuid}-None" } + + before do + allow(disk_id).to receive(:disk_name).and_return(disk_name) + allow(disk_id).to receive(:caching).and_return(caching) + allow(disk_id).to receive(:storage_account_name).and_return(storage_account_name) + end describe "#delete_disk" do context "when the disk exists" do @@ -23,7 +33,7 @@ with(storage_account_name, disk_container, "#{disk_name}.vhd") expect { - disk_manager.delete_disk(disk_name) + disk_manager.delete_disk(storage_account_name, disk_name) }.not_to raise_error end end @@ -38,11 +48,22 @@ expect(blob_manager).not_to receive(:delete_blob) expect { - disk_manager.delete_disk(disk_name) + disk_manager.delete_disk(storage_account_name, disk_name) }.not_to raise_error end end - end + end + + describe "#delete_data_disk" do + it "should delete the disk" do + expect(disk_manager).to receive(:delete_disk). + with(storage_account_name, disk_name) + + expect { + disk_manager.delete_data_disk(disk_id) + }.not_to raise_error + end + end describe "#delete_vm_status_files" do it "deletes vm status files" do @@ -62,7 +83,7 @@ disk_manager.delete_vm_status_files(storage_account_name, "") }.not_to raise_error end - end + end describe "#snapshot_disk" do let(:metadata) { {} } @@ -73,38 +94,61 @@ with(storage_account_name, disk_container, "#{disk_name}.vhd", metadata). and_return(snapshot_time) - snapshot_id = disk_manager.snapshot_disk(disk_name, metadata) - expect(snapshot_id).to include(disk_name) - expect(snapshot_id).to include(snapshot_time) + snapshot_name = disk_manager.snapshot_disk(storage_account_name, disk_name, metadata) + expect(snapshot_name).to include(disk_name) + expect(snapshot_name).to include(snapshot_time) end - end + end describe "#delete_snapshot" do - let(:snapshot_time) { "fake-snapshot-time" } - let(:snapshot_id) { "#{disk_name}--#{snapshot_time}" } + context "when snapshot id is in-valid" do + let(:snapshot_name) { "invalide-snapshot-name" } - it "deletes the snapshot" do - expect(blob_manager).to receive(:delete_blob_snapshot). - with(storage_account_name, disk_container, "#{disk_name}.vhd", snapshot_time) + before do + allow(snapshot_id).to receive(:storage_account_name).and_return(storage_account_name) + allow(snapshot_id).to receive(:disk_name).and_return(snapshot_name) + end - expect { - disk_manager.delete_snapshot(snapshot_id) - }.not_to raise_error + it "should raise an error" do + expect { + disk_manager.delete_snapshot(snapshot_id) + }.to raise_error /Invalid snapshot id/ + end + end + + context "when snapshot id is valid" do + let(:snapshot_time) { "fake-snapshot-time" } + let(:snapshot_name) { "#{disk_name}--#{snapshot_time}" } + + before do + allow(snapshot_id).to receive(:storage_account_name).and_return(storage_account_name) + allow(snapshot_id).to receive(:disk_name).and_return(snapshot_name) + end + + it "deletes the snapshot" do + expect(blob_manager).to receive(:delete_blob_snapshot). + with(storage_account_name, disk_container, "#{disk_name}.vhd", snapshot_time) + + expect { + disk_manager.delete_snapshot(snapshot_id) + }.not_to raise_error + end end - end + end describe "#create_disk" do let(:size) { 100 } let(:caching) { 'ReadOnly' } it "returns the disk name with the specified caching" do - allow(blob_manager).to receive(:create_empty_vhd_blob) + expect(blob_manager).to receive(:create_empty_vhd_blob). + with(storage_account_name, disk_container, "#{disk_name}.vhd", size) - disk_name = disk_manager.create_disk(size, storage_account_name, caching) - expect(disk_name).to include(storage_account_name) - expect(disk_name).to include(caching) + expect { + disk_manager.create_disk(disk_id, size) + }.not_to raise_error end - end + end describe "#has_disk?" do context "when the disk exists" do @@ -114,7 +158,7 @@ end it "should return true" do - expect(disk_manager.has_disk?(disk_name)).to be(true) + expect(disk_manager.has_disk?(storage_account_name, disk_name)).to be(true) end end @@ -125,11 +169,21 @@ end it "should return false" do - expect(disk_manager.has_disk?(disk_name)).to be(false) + expect(disk_manager.has_disk?(storage_account_name, disk_name)).to be(false) end end end + describe "#has_data_disk?" do + it "should delete the disk" do + expect(disk_manager).to receive(:has_disk?). + with(storage_account_name, disk_name). + and_return(true) + + expect(disk_manager.has_data_disk?(disk_id)).to be(true) + end + end + describe "#is_migrated?" do context "when the disk does not exist" do before do @@ -138,7 +192,7 @@ end it "should return false" do - expect(disk_manager.is_migrated?(disk_name)).to be(false) + expect(disk_manager.is_migrated?(disk_id)).to be(false) end end @@ -161,7 +215,7 @@ end it "should return true" do - expect(disk_manager.is_migrated?(disk_name)).to be(true) + expect(disk_manager.is_migrated?(disk_id)).to be(true) end end @@ -173,47 +227,29 @@ end it "should return false" do - expect(disk_manager.is_migrated?(disk_name)).to be(false) + expect(disk_manager.is_migrated?(disk_id)).to be(false) end end end end describe "#get_disk_uri" do - context "when the disk name is invalid" do - let(:disk_name) { "invalid-disk-name" } - - it "raises an error" do - expect { - disk_manager.get_disk_uri(disk_name) - }.to raise_error /Invalid disk name #{disk_name}/ - end - end - - context "when the disk is a data disk" do - it "returns the right disk uri" do - expect(blob_manager).to receive(:get_blob_uri). - with(storage_account_name, disk_container, "#{disk_name}.vhd"). - and_return("fake-uri") - expect(disk_manager.get_disk_uri(disk_name)).to eq("fake-uri") - end - end - - context "when the disk is an OS disk" do - let(:disk_name) { "bosh-os-#{storage_account_name}-#{SecureRandom.uuid}-None" } - - it "returns the right disk uri" do - expect(blob_manager).to receive(:get_blob_uri). - with(storage_account_name, disk_container, "#{disk_name}.vhd"). - and_return("fake-uri") - expect(disk_manager.get_disk_uri(disk_name)).to eq("fake-uri") - end + it "returns the right disk uri" do + expect(blob_manager).to receive(:get_blob_uri). + with(storage_account_name, disk_container, "#{disk_name}.vhd"). + and_return("fake-uri") + expect(disk_manager.get_disk_uri(storage_account_name, disk_name)).to eq("fake-uri") end end - describe "#get_data_disk_caching" do - it "returns the right caching" do - expect(disk_manager.get_data_disk_caching(disk_name)).to eq("None") + describe "#get_data_disk_uri" do + it "should get disk uri" do + expect(disk_manager).to receive(:get_disk_uri). + with(storage_account_name, disk_name) + + expect { + disk_manager.get_data_disk_uri(disk_id) + }.not_to raise_error end end @@ -227,30 +263,29 @@ end it "returns the disk size" do - expect(disk_manager.get_disk_size_in_gb(disk_name)).to eq(42) + expect(disk_manager.get_disk_size_in_gb(disk_id)).to eq(42) end end describe "#generate_os_disk_name" do - let(:instance_id) { "fake-instance-id" } + let(:vm_name) { "fake-vm-name" } it "returns the right os disk name" do - expect(disk_manager.generate_os_disk_name(instance_id)).to eq("#{os_disk_prefix}-fake-instance-id") + expect(disk_manager.generate_os_disk_name(vm_name)).to eq("#{os_disk_prefix}-fake-vm-name") end end describe "#generate_ephemeral_disk_name" do - let(:instance_id) { "fake-instance-id" } + let(:vm_name) { "fake-vm-name" } it "returns the right ephemeral disk name" do - expect(disk_manager.generate_ephemeral_disk_name(instance_id)).to eq("#{os_disk_prefix}-fake-instance-id-ephemeral-disk") + expect(disk_manager.generate_ephemeral_disk_name(vm_name)).to eq("#{os_disk_prefix}-fake-vm-name-ephemeral-disk") end end describe "#os_disk" do - let(:disk_name) { 'fake-disk-name' } let(:disk_uri) { 'fake-disk-uri' } - let(:instance_id) { 'fake-instance-id' } + let(:vm_name) { 'fake-vm-name' } let(:minimum_disk_size) { 3072 } before do @@ -271,7 +306,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -297,7 +332,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -321,7 +356,7 @@ disk_manager.resource_pool = resource_pool expect { - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) }.to raise_error /Unknown disk caching/ end end @@ -341,7 +376,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -368,7 +403,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -395,7 +430,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -422,7 +457,7 @@ disk_manager.resource_pool = resource_pool expect { - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) }.to raise_error /root_disk.size `2048' is smaller than the default OS disk size `3072' MiB/ end end @@ -442,7 +477,7 @@ disk_manager.resource_pool = resource_pool expect { - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) }.to raise_error /root_disk.size `2048' is smaller than the default OS disk size `4096' MiB/ end end @@ -461,7 +496,7 @@ disk_manager.resource_pool = resource_pool expect { - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) }.to raise_error ArgumentError, "The disk size needs to be an integer. The current value is `invalid-size'." end end @@ -480,7 +515,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.os_disk(instance_id, minimum_disk_size) + disk_manager.os_disk(storage_account_name, vm_name, minimum_disk_size) ).to eq( { :disk_name => disk_name, @@ -496,9 +531,9 @@ end describe "#ephemeral_disk" do - let(:disk_name) { 'ephemeral-disk' } + let(:disk_name) { 'ephemeral-disk' } #EPHEMERAL_DISK_POSTFIX let(:disk_uri) { 'fake-disk-uri' } - let(:instance_id) { 'fake-instance-id' } + let(:vm_name) { 'fake-vm-name' } before do allow(disk_manager).to receive(:get_disk_uri). @@ -517,7 +552,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.ephemeral_disk(instance_id) + disk_manager.ephemeral_disk(storage_account_name, vm_name) ).to eq( { :disk_name => disk_name, @@ -540,7 +575,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.ephemeral_disk(instance_id) + disk_manager.ephemeral_disk(storage_account_name, vm_name) ).to eq( { :disk_name => disk_name, @@ -569,7 +604,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.ephemeral_disk(instance_id) + disk_manager.ephemeral_disk(storage_account_name, vm_name) ).to eq( { :disk_name => disk_name, @@ -595,7 +630,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.ephemeral_disk(instance_id) + disk_manager.ephemeral_disk(storage_account_name, vm_name) ).to be_nil end end @@ -614,7 +649,7 @@ disk_manager.resource_pool = resource_pool expect( - disk_manager.ephemeral_disk(instance_id) + disk_manager.ephemeral_disk(storage_account_name, vm_name) ).to eq( { :disk_name => disk_name, @@ -636,12 +671,12 @@ } } } - + it "should return correct values" do disk_manager.resource_pool = resource_pool expect( - disk_manager.ephemeral_disk(instance_id) + disk_manager.ephemeral_disk(storage_account_name, vm_name) ).to eq( { :disk_name => disk_name, @@ -667,7 +702,7 @@ disk_manager.resource_pool = resource_pool expect { - disk_manager.ephemeral_disk(instance_id) + disk_manager.ephemeral_disk(storage_account_name, vm_name) }.to raise_error ArgumentError, "The disk size needs to be an integer. The current value is `invalid-size'." end end diff --git a/src/bosh_azure_cpi/spec/unit/helpers_spec.rb b/src/bosh_azure_cpi/spec/unit/helpers_spec.rb index e13613519..ee23c58db 100644 --- a/src/bosh_azure_cpi/spec/unit/helpers_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/helpers_spec.rb @@ -86,30 +86,6 @@ def set_logger(logger) end end - describe "#get_storage_account_name_from_instance_id" do - context "when instance id is valid" do - let(:storage_account_name) { "foostorageaccount" } - let(:instance_id) { "#{storage_account_name}-12345688-1234" } - - it "should return the storage account name" do - expect( - helpers_tester.get_storage_account_name_from_instance_id(instance_id) - ).to eq(storage_account_name) - end - end - - context "when instance id is invalid" do - let(:storage_account_name) { "foostorageaccount" } - let(:instance_id) { "#{storage_account_name}123456881234" } - - it "should raise an error" do - expect { - helpers_tester.get_storage_account_name_from_instance_id(instance_id) - }.to raise_error /Invalid instance id/ - end - end - end - describe "#validate_disk_caching" do context "when disk caching is invalid" do let(:caching) { "Invalid" } @@ -710,7 +686,7 @@ def set_logger(logger) }.not_to raise_error end end - + context "when the lock exists and timeouts" do before do File.open(file_path, "w") {|f| f.write("test") } @@ -729,7 +705,7 @@ def set_logger(logger) }.to raise_error(/timeout/) end end - + context "when the lock exists initially and is released before timeout" do before do File.open(file_path, "w") {|f| f.write("test") } diff --git a/src/bosh_azure_cpi/spec/unit/instance_id_spec.rb b/src/bosh_azure_cpi/spec/unit/instance_id_spec.rb new file mode 100644 index 000000000..2a95c6ff5 --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/instance_id_spec.rb @@ -0,0 +1,362 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::InstanceId do + describe '#self.create' do + let(:resource_group_name) { 'fake-resource-group-name' } + let(:agent_id) { 'fake-agent-id' } + + context 'when storage_account_name is nil' do + let(:id) { + { + 'resource_group_name' => resource_group_name, + 'agent_id' => agent_id + } + } + + it 'should initialize the instance_id' do + instance_id = Bosh::AzureCloud::InstanceId.create(resource_group_name, agent_id) + expect(instance_id.instance_variable_get("@version")).to eq('v2') + expect(instance_id.instance_variable_get("@id")).to eq(id) + end + end + + context 'when storage_account_name is NOT nil' do + let(:storage_account_name) { 'fakestorageaccountname' } + let(:id) { + { + 'resource_group_name' => resource_group_name, + 'agent_id' => agent_id, + 'storage_account_name' => storage_account_name + } + } + + it 'should initialize the instance_id' do + instance_id = Bosh::AzureCloud::InstanceId.create(resource_group_name, agent_id, storage_account_name) + expect(instance_id.instance_variable_get("@version")).to eq('v2') + expect(instance_id.instance_variable_get("@id")).to eq(id) + end + end + end + + describe '#self.parse' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + + before do + allow(instance_id).to receive(:validate) + end + + context 'when id contains ":"' do + let(:id) { 'a:a;b:b' } + let(:id_hash) { + { + 'a' => 'a', + 'b' => 'b' + } + } + let(:options) { + { + :id => id_hash + } + } + + it 'should initialize a v2 instance_id' do + expect(Bosh::AzureCloud::InstanceId).to receive(:new). + with('v2', options). + and_return(instance_id) + expect { + Bosh::AzureCloud::InstanceId.parse(id, azure_properties) + }.not_to raise_error + end + end + + context 'when id does not contain ":"' do + let(:id) { 'fake-id' } + let(:options) { + { + :id => id, + :default_resource_group_name => 'default-resource-group-name' + } + } + + it 'should initialize a v1 instance_id' do + expect(Bosh::AzureCloud::InstanceId).to receive(:new). + with('v1', options). + and_return(instance_id) + expect { + Bosh::AzureCloud::InstanceId.parse(id, azure_properties) + }.not_to raise_error + end + end + end + + describe '#to_s' do + context 'when instance id is a v1 id' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:instance_id_string) { "#{SecureRandom.uuid}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return the v1 string' do + expect(instance_id.to_s).to eq(instance_id_string) + end + end + + context 'when instance id is a v2 id' do + context 'when instance id is initialized by self.parse' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:instance_id_string) { 'agent_id:a;resource_group_name:r;storage_account_name:s' } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return the v2 string' do + expect(instance_id.to_s).to eq(instance_id_string) + end + end + + context 'when instance id is initialized by self.create' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:agent_id) { 'fake-agent-id' } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:instance_id_string) { "agent_id:#{agent_id};resource_group_name:#{resource_group_name};storage_account_name:#{storage_account_name}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.create(resource_group_name, agent_id, storage_account_name) } + + it 'should return the v2 string' do + expect(instance_id.to_s).to eq(instance_id_string) + end + end + + context 'when the same instance id is initialized by self.create and self.parse' do + let(:azure_properties) { { 'resource_group_name' => 'default-resource-group-name' } } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:agent_id) { 'fake-agent-id' } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:instance_id_string) { "agent_id:#{agent_id};resource_group_name:#{resource_group_name};storage_account_name:#{storage_account_name}" } + let(:instance_id_1) { Bosh::AzureCloud::InstanceId.create(resource_group_name, agent_id, storage_account_name) } + let(:instance_id_2) { Bosh::AzureCloud::InstanceId.parse(instance_id_1.to_s, azure_properties) } + + it 'should have same output string' do + expect(instance_id_1.to_s).to eq(instance_id_2.to_s) + end + end + end + end + + describe '#resource_group_name' do + context 'when instance id is a v1 id' do + let(:default_resource_group_name) { 'fake-resource-group-name' } + let(:azure_properties) { { 'resource_group_name' => default_resource_group_name } } + let(:instance_id_string) { "#{SecureRandom.uuid}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return the default resource group' do + expect(instance_id.resource_group_name).to eq(default_resource_group_name) + end + end + + context 'when instance id is a v2 id' do + context 'when instance id contains resource_group_name' do + let(:default_resource_group_name) { 'fake-resource-group-name' } + let(:azure_properties) { { 'resource_group_name' => default_resource_group_name } } + let(:resource_group_name) { 'fake-resource-group-name' } + let(:instance_id_string) { "resource_group_name:#{resource_group_name};agent_id:a;storage_account_name:s" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return the resource group specified in instance id' do + expect(instance_id.resource_group_name).to eq(resource_group_name) + end + end + end + end + + describe '#vm_name' do + context 'when instance id is a v1 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:instance_id_string) { "fakestorageaccountname-#{SecureRandom.uuid}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return v1 id' do + expect(instance_id.vm_name).to eq(instance_id_string) + end + end + + context 'when instance id is a v2 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:agent_id) { SecureRandom.uuid } + let(:instance_id_string) { "resource_group_name:r;agent_id:#{agent_id};storage_account_name:s" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return the agent_id specified in instance id' do + expect(instance_id.vm_name).to eq(agent_id) + end + end + end + + describe '#storage_account_name' do + context 'when instance id is a v1 id' do + context 'when it is a managed disk vm' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:instance_id_string) { "#{SecureRandom.uuid}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return nil' do + expect(instance_id.storage_account_name).to be(nil) + end + end + + context 'when it is a unmanaged disk vm' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:instance_id_string) { "#{storage_account_name}-#{SecureRandom.uuid}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should get storage account from v1 vm name' do + expect(instance_id.storage_account_name).to eq(storage_account_name) + end + end + end + + context 'when instance id is a v2 id' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:instance_id_string) { "resource_group_name:r;agent_id:None;storage_account_name:#{storage_account_name}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return the storage account specified in instance id' do + expect(instance_id.storage_account_name).to eq(storage_account_name) + end + end + end + + describe 'use_managed_disks?' do + context 'when instance id is a v1 id' do + context 'when it is a unmanaged disk vm' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:instance_id_string) { "#{storage_account_name}-#{SecureRandom.uuid}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return false' do + expect(instance_id.use_managed_disks?).to be(false) + end + end + + context 'when it is a managed disk vm' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:instance_id_string) { "#{SecureRandom.uuid}" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return true' do + expect(instance_id.use_managed_disks?).to be(true) + end + end + end + + context 'when instance id is a v2 id' do + context 'when it is a unmanaged disk vm' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:instance_id_string) { "resource_group_name:r;agent_id:None;storage_account_name:s" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return false' do + expect(instance_id.use_managed_disks?).to be(false) + end + end + + context 'when it is a managed disk vm' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:instance_id_string) { "resource_group_name:r;agent_id:None" } + let(:instance_id) { Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) } + + it 'should return true' do + expect(instance_id.use_managed_disks?).to be(true) + end + end + end + end + + describe '#validate' do + context 'when instance id is a v1 id' do + context 'when it is a unmanaged disk vm and length of agent id is not 36' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:storage_account_name) { 'fakestorageaccountname' } + let(:instance_id_string) { "#{storage_account_name}-length-not-equal-to-36" } + let(:instance_id) { } + + it 'should raise an error' do + expect { + Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) + }.to raise_error /Invalid instance id \(version 1\)/ + end + end + + context 'when it is a managed disk vm and length of agent id is not 36' do + let(:azure_properties) { { 'resource_group_name' => 'fake-resource-group-name' } } + let(:instance_id_string) { "length-not-equal-to-36" } + + it 'should raise an error' do + expect { + Bosh::AzureCloud::InstanceId.parse(instance_id_string, azure_properties) + }.to raise_error /Invalid instance id \(version 1\)/ + end + end + end + + context 'when instance id is a v2 id' do + context 'when validating resource_group_name' do + context 'when it is nil' do + let(:instancd_id) { Bosh::AzureCloud::InstanceId.create(nil, 'agent-id', 'storage-account-name') } + + it 'should raise an error' do + expect { + instancd_id.validate() + }.to raise_error /Invalid resource_group_name in instance id \(version 2\)/ + end + end + + context 'when it is empty' do + let(:instancd_id) { Bosh::AzureCloud::InstanceId.create('', 'agent-id', 'storage-account-name') } + + it 'should raise an error' do + expect { + instancd_id.validate() + }.to raise_error /Invalid resource_group_name in instance id \(version 2\)/ + end + end + end + + context 'when validating vm_name' do + context 'when it is nil' do + let(:instancd_id) { Bosh::AzureCloud::InstanceId.create('resource-group-name', nil, 'storage-account-name') } + + it 'should raise an error' do + expect { + instancd_id.validate() + }.to raise_error /Invalid vm_name in instance id \(version 2\)/ + end + end + + context 'when it is empty' do + let(:instancd_id) { Bosh::AzureCloud::InstanceId.create('resource-group-name', '', 'storage-account-name') } + + it 'should raise an error' do + expect { + instancd_id.validate() + }.to raise_error /Invalid vm_name in instance id \(version 2\)/ + end + end + end + + context 'when validating storage_account_name' do + context 'when it is empty' do + let(:instancd_id) { Bosh::AzureCloud::InstanceId.create('resource-group-name', 'agent-id', '') } + + it 'should raise an error' do + expect { + instancd_id.validate() + }.to raise_error /Invalid storage_account_name in instance id \(version 2\)/ + end + end + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/light_stemcell_manager_spec.rb b/src/bosh_azure_cpi/spec/unit/light_stemcell_manager_spec.rb index 181c5e189..3668f160d 100644 --- a/src/bosh_azure_cpi/spec/unit/light_stemcell_manager_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/light_stemcell_manager_spec.rb @@ -109,7 +109,7 @@ light_stemcell_manager.delete_stemcell(stemcell_name) end end - end + end describe "#create_stemcell" do context "when the platform image exists" do @@ -157,7 +157,7 @@ }.to raise_error /Cannot find the light stemcell/ end end - end + end describe "#has_stemcell?" do context "when the blob does not exist in the default storage account" do diff --git a/src/bosh_azure_cpi/spec/unit/stemcell_manager2_spec.rb b/src/bosh_azure_cpi/spec/unit/stemcell_manager2_spec.rb index c9fcb6921..5f076a4c1 100644 --- a/src/bosh_azure_cpi/spec/unit/stemcell_manager2_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/stemcell_manager2_spec.rb @@ -69,7 +69,7 @@ stemcell_manager2.delete_stemcell(stemcell_name) end - end + end describe "#has_stemcell?" do context "when the storage account has the stemcell" do diff --git a/src/bosh_azure_cpi/spec/unit/stemcell_manager_spec.rb b/src/bosh_azure_cpi/spec/unit/stemcell_manager_spec.rb index 19fe50cff..d430f20ee 100644 --- a/src/bosh_azure_cpi/spec/unit/stemcell_manager_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/stemcell_manager_spec.rb @@ -62,7 +62,7 @@ stemcell_manager.delete_stemcell(stemcell_name) end end - end + end describe "#create_stemcell" do before do @@ -74,7 +74,7 @@ expect(stemcell_manager.create_stemcell("",{})).not_to be_empty end - end + end describe "#has_stemcell?" do context "when the storage account is the default one" do diff --git a/src/bosh_azure_cpi/spec/unit/storage_account_manager_spec.rb b/src/bosh_azure_cpi/spec/unit/storage_account_manager_spec.rb index b88ce91c8..f84e87c3c 100644 --- a/src/bosh_azure_cpi/spec/unit/storage_account_manager_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/storage_account_manager_spec.rb @@ -7,6 +7,7 @@ let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } let(:storage_account_manager) { Bosh::AzureCloud::StorageAccountManager.new(azure_properties, blob_manager, disk_manager, client2) } let(:azure_client) { instance_double(Azure::Storage::Client) } + let(:default_resource_group_name) { MOCK_RESOURCE_GROUP_NAME } before do allow(Azure::Storage::Client).to receive(:create). @@ -620,7 +621,9 @@ } before do allow(client2).to receive(:list_storage_accounts).and_return(storage_accounts) - allow(client2).to receive(:get_resource_group).and_return(resource_group) + allow(client2).to receive(:get_resource_group). + with(default_resource_group_name). + and_return(resource_group) end it 'should return the storage account' do @@ -676,7 +679,9 @@ before do allow(client2).to receive(:list_storage_accounts).and_return(storage_accounts) - allow(client2).to receive(:get_resource_group).and_return(resource_group) + allow(client2).to receive(:get_resource_group). + with(default_resource_group_name). + and_return(resource_group) allow(client2).to receive(:get_storage_account_by_name). with(targeted_storage_account[:name]). and_return(targeted_storage_account) @@ -695,7 +700,7 @@ azure_properties.delete('storage_account_name') expect(client2).not_to receive(:get_storage_account_by_name).with(MOCK_DEFAULT_STORAGE_ACCOUNT_NAME) expect(client2).to receive(:update_tags_of_storage_account).with(targeted_storage_account[:name], tags) - + expect(storage_account_manager.default_storage_account).to eq(targeted_storage_account) end end @@ -718,7 +723,9 @@ before do allow(client2).to receive(:list_storage_accounts).and_return(storage_accounts) - allow(client2).to receive(:get_resource_group).and_return(resource_group) + allow(client2).to receive(:get_resource_group). + with(default_resource_group_name). + and_return(resource_group) allow(client2).to receive(:get_storage_account_by_name). with(targeted_storage_account[:name]). and_return(targeted_storage_account) @@ -760,7 +767,9 @@ before do allow(client2).to receive(:list_storage_accounts).and_return(storage_accounts) - allow(client2).to receive(:get_resource_group).and_return(resource_group) + allow(client2).to receive(:get_resource_group). + with(default_resource_group_name). + and_return(resource_group) allow(client2).to receive(:get_storage_account_by_name). with(targeted_storage_account[:name]). and_return(targeted_storage_account) @@ -808,7 +817,9 @@ before do allow(client2).to receive(:list_storage_accounts).and_return(storage_accounts) - allow(client2).to receive(:get_resource_group).and_return(resource_group) + allow(client2).to receive(:get_resource_group). + with(default_resource_group_name). + and_return(resource_group) allow(client2).to receive(:get_storage_account_by_name). with(targeted_storage_account[:name]). and_return(targeted_storage_account) @@ -861,7 +872,9 @@ before do allow(client2).to receive(:list_storage_accounts).and_return([]) - allow(client2).to receive(:get_resource_group).and_return(resource_group) + allow(client2).to receive(:get_resource_group). + with(default_resource_group_name). + and_return(resource_group) allow(SecureRandom).to receive(:hex).and_return(random_postfix) allow(client2).to receive(:check_storage_account_name_availability).with(new_storage_account_name).and_return(result) allow(blob_manager).to receive(:prepare).with(new_storage_account_name, {:is_default_storage_account=>true}) diff --git a/src/bosh_azure_cpi/spec/unit/vm_manager/attach_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/vm_manager/attach_disk_spec.rb new file mode 100644 index 000000000..9796437d1 --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/vm_manager/attach_disk_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::VMManager do + describe "#attach_disk" do + let(:registry_endpoint) { mock_registry.endpoint } + let(:disk_manager) { instance_double(Bosh::AzureCloud::DiskManager) } + let(:disk_manager2) { instance_double(Bosh::AzureCloud::DiskManager2) } + let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } + let(:azure_properties) { mock_azure_properties } + let(:vm_manager) { Bosh::AzureCloud::VMManager.new(azure_properties, registry_endpoint, disk_manager, disk_manager2, client2) } + + let(:caching) { "fake-caching" } + let(:lun) { 1 } + let(:vm_resource_group_name) { "fake-vm-resource-group-name" } + let(:disk_resource_group_name) { "fake-disk-resource-group-name" } + let(:storage_account_name) { "fake-storage-account-name" } + + let(:vm_name) { "fake-vm-name" } + let(:disk_name) { "bosh-data-#{storage_account_name}-fake-disk-name-#{caching}" } + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + let(:disk_id) { instance_double(Bosh::AzureCloud::DiskId) } + let(:disk_id_string) { "fake-disk-id" } + + before do + allow(instance_id).to receive(:resource_group_name). + and_return(vm_resource_group_name) + allow(instance_id).to receive(:vm_name). + and_return(vm_name) + + allow(disk_id).to receive(:resource_group_name). + and_return(disk_resource_group_name) + allow(disk_id).to receive(:disk_name). + and_return(disk_name) + allow(disk_id).to receive(:caching). + and_return(caching) + allow(disk_id).to receive(:to_s). + and_return(disk_id_string) + end + + context "When the disk is unmanaged disk" do + let(:disk_uri) { "fake-disk-uri" } + let(:disk_size) { 42 } + let(:disk_params) { + { + :disk_name => disk_name, + :caching => caching, + :disk_uri => disk_uri, + :disk_size => disk_size, + :managed => false, + :disk_bosh_id => disk_id_string + } + } + + before do + allow(instance_id).to receive(:use_managed_disks?). + and_return(false) + allow(disk_manager).to receive(:get_data_disk_uri). + with(disk_id).and_return(disk_uri) + allow(disk_manager).to receive(:get_disk_size_in_gb). + with(disk_id).and_return(disk_size) + end + + it "attaches the disk to an instance" do + expect(client2).to receive(:attach_disk_to_virtual_machine). + with(vm_resource_group_name, vm_name, disk_params). + and_return(lun) + expect(vm_manager.attach_disk(instance_id, disk_id)).to eq("#{lun}") + end + end + + context "When the disk is managed disk" do + let(:managed_disk_id) { "fake-id" } + let(:managed_disk) { {:id => managed_disk_id} } + let(:disk_params) { + { + :disk_name => disk_name, + :caching => caching, + :disk_id => managed_disk_id, + :managed => true, + :disk_bosh_id => disk_id_string + } + } + + before do + allow(instance_id).to receive(:use_managed_disks?). + and_return(true) + allow(client2).to receive(:get_managed_disk_by_name). + with(disk_resource_group_name, disk_name). + and_return(managed_disk) + end + + it "attaches the disk to an instance" do + expect(client2).to receive(:attach_disk_to_virtual_machine). + with(vm_resource_group_name, vm_name, disk_params). + and_return(lun) + expect(vm_manager.attach_disk(instance_id, disk_id)).to eq("#{lun}") + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/vm_manager_spec.rb b/src/bosh_azure_cpi/spec/unit/vm_manager/create_spec.rb similarity index 80% rename from src/bosh_azure_cpi/spec/unit/vm_manager_spec.rb rename to src/bosh_azure_cpi/spec/unit/vm_manager/create_spec.rb index 2b771534d..d7f55e67d 100644 --- a/src/bosh_azure_cpi/spec/unit/vm_manager_spec.rb +++ b/src/bosh_azure_cpi/spec/unit/vm_manager/create_spec.rb @@ -1,9 +1,11 @@ require 'spec_helper' describe Bosh::AzureCloud::VMManager do - let(:instance_id) { "#{MOCK_DEFAULT_STORAGE_ACCOUNT_NAME}-e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } - let(:managed_instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } - let(:storage_account_name) { MOCK_DEFAULT_STORAGE_ACCOUNT_NAME } + let(:vm_name) { "fake-vm-name" } + let(:resource_group_name) { "fake-resource-group-name" } + let(:storage_account_name) { "fake-storage-acount-name" } + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + let(:instance_id_string) { "fake-instance-id" } let(:os_disk_name) { "fake-os-disk-name" } let(:ephemeral_disk_name) { "fake-ephemeral-disk-name" } let(:location) { "fake-location" } @@ -106,6 +108,15 @@ let(:env) { {} } before do + allow(instance_id).to receive(:resource_group_name). + and_return(resource_group_name) + allow(instance_id).to receive(:vm_name). + and_return(vm_name) + allow(instance_id).to receive(:storage_account_name). + and_return(storage_account_name) + allow(instance_id).to receive(:to_s). + and_return(instance_id_string) + allow(stemcell_info).to receive(:uri). and_return(stemcell_uri) allow(stemcell_info).to receive(:os_type). @@ -126,8 +137,10 @@ with(MOCK_RESOURCE_GROUP_NAME, MOCK_DEFAULT_SECURITY_GROUP). and_return(security_group) allow(client2).to receive(:get_public_ip_by_name). - with(instance_id). + with(resource_group_name, vm_name). and_return(nil) + allow(client2).to receive(:get_resource_group). + and_return({}) allow(network_configurator).to receive(:vip_network). and_return(vip_network) @@ -192,11 +205,11 @@ it "should raise an error" do expect(client2).not_to receive(:delete_virtual_machine) expect(client2).not_to receive(:delete_network_interface) - expect(client2).to receive(:list_network_interfaces_by_instance_id).with(instance_id).and_return([]) + expect(client2).to receive(:list_network_interfaces_by_keyword).with(resource_group_name, vm_name).and_return([]) expect(client2).to receive(:get_public_ip_by_name). - with(instance_id). + with(resource_group_name, vm_name). and_return({ :ip_address => "public-ip" }) - expect(client2).to receive(:delete_public_ip).with(instance_id) + expect(client2).to receive(:delete_public_ip).with(resource_group_name, vm_name) expect { vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) @@ -209,15 +222,15 @@ before do allow(client2).to receive(:get_public_ip_by_name). - with(instance_id). + with(resource_group_name, vm_name). and_return({ :ip_address => "public-ip" }) - allow(client2).to receive(:delete_public_ip).with(instance_id).and_raise("Error during cleanup") + allow(client2).to receive(:delete_public_ip).with(resource_group_name, vm_name).and_raise("Error during cleanup") end it "should raise an error" do expect(client2).not_to receive(:delete_virtual_machine) expect(client2).not_to receive(:delete_network_interface) - expect(client2).to receive(:list_network_interfaces_by_instance_id).with(instance_id).and_return([]) + expect(client2).to receive(:list_network_interfaces_by_keyword).with(resource_group_name, vm_name).and_return([]) expect { vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) @@ -228,8 +241,8 @@ context "when the resource group name is not specified in the network spec" do context "when subnet is not found in the default resource group" do before do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) allow(client2).to receive(:get_load_balancer_by_name). with(resource_pool['load_balancer']) @@ -252,8 +265,8 @@ context "when network security group is not found in the default resource group" do before do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) allow(client2).to receive(:get_load_balancer_by_name). with(resource_pool['load_balancer']) @@ -293,8 +306,8 @@ context "when subnet is not found in the specified resource group" do it "should raise an error" do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) allow(client2).to receive(:get_network_subnet_by_name). with("fake-resource-group-name", "fake-virtual-network-name", "fake-subnet-name"). @@ -307,8 +320,8 @@ context "when network security group is not found in the specified resource group nor the default resource group" do before do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) allow(client2).to receive(:get_network_security_group_by_name). with(MOCK_RESOURCE_GROUP_NAME, MOCK_DEFAULT_SECURITY_GROUP). @@ -335,8 +348,8 @@ context "when the public ip list azure returns is empty" do it "should raise an error" do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) allow(client2).to receive(:list_public_ips). and_return([]) @@ -362,8 +375,8 @@ } it "should raise an error" do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) allow(client2).to receive(:list_public_ips). and_return(public_ips) @@ -381,8 +394,8 @@ context "when load balancer can not be found" do before do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) end @@ -417,8 +430,8 @@ context "when none of network interface is created" do before do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) end @@ -434,14 +447,14 @@ context "when one network interface is created and the another one is not" do let(:network_interface) { { - :id => "/subscriptions/fake-subscription/resourceGroups/fake-resource-group/providers/Microsoft.Network/networkInterfaces/#{instance_id}-x", - :name => "#{instance_id}-x" + :id => "/subscriptions/fake-subscription/resourceGroups/fake-resource-group/providers/Microsoft.Network/networkInterfaces/#{vm_name}-x", + :name => "#{vm_name}-x" } } before do - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([network_interface]) allow(client2).to receive(:get_network_subnet_by_name). and_return(subnet) @@ -468,14 +481,14 @@ before do resource_pool['assign_dynamic_public_ip'] = true allow(client2).to receive(:get_public_ip_by_name). - with(instance_id).and_return(dynamic_public_ip) - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id). + with(resource_group_name, vm_name).and_return(dynamic_public_ip) + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name). and_return([]) end it "should delete the dynamic public IP" do - expect(client2).to receive(:delete_public_ip).with(instance_id) + expect(client2).to receive(:delete_public_ip).with(resource_group_name, vm_name) expect { vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) }.to raise_error /network interface is not created/ @@ -540,10 +553,10 @@ it "should delete vm and nics and then raise an error" do expect(client2).to receive(:delete_virtual_machine).once - expect(disk_manager).to receive(:delete_disk).with(os_disk_name).once - expect(disk_manager).to receive(:delete_disk).with(ephemeral_disk_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, os_disk_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name).once expect(disk_manager).to receive(:delete_vm_status_files). - with(storage_account_name, instance_id).once + with(storage_account_name, vm_name).once expect(client2).to receive(:delete_network_interface).twice expect { @@ -562,10 +575,10 @@ it "should delete vm and nics and then raise an error" do expect(client2).to receive(:delete_virtual_machine).once - expect(disk_manager).to receive(:delete_disk).with(os_disk_name).once - expect(disk_manager).to receive(:delete_disk).with(ephemeral_disk_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, os_disk_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name).once expect(disk_manager).to receive(:delete_vm_status_files). - with(storage_account_name, instance_id).once + with(storage_account_name, vm_name).once expect(client2).to receive(:delete_network_interface).once expect { @@ -584,10 +597,10 @@ it "should delete vm and nics and then raise an error" do expect(client2).to receive(:delete_virtual_machine).once - expect(disk_manager).to receive(:delete_disk).with(os_disk_name).once - expect(disk_manager).to receive(:delete_disk).with(ephemeral_disk_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, os_disk_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name).once expect(disk_manager).to receive(:delete_vm_status_files). - with(storage_account_name, instance_id).once + with(storage_account_name, vm_name).once expect(client2).to receive(:delete_network_interface).twice expect { @@ -615,10 +628,10 @@ it "should not delete vm and then raise an error" do expect(client2).to receive(:create_virtual_machine).exactly(3).times expect(client2).to receive(:delete_virtual_machine).twice - expect(disk_manager).to receive(:delete_disk).with(os_disk_name).twice + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, os_disk_name).twice expect(disk_manager).to receive(:delete_vm_status_files). - with(storage_account_name, instance_id).twice - expect(disk_manager).not_to receive(:delete_disk).with(ephemeral_disk_name) + with(storage_account_name, vm_name).twice + expect(disk_manager).not_to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name) expect(client2).not_to receive(:delete_network_interface) expect { @@ -635,10 +648,10 @@ it "should not delete vm and then raise an error" do expect(client2).to receive(:create_virtual_machine).exactly(3).times expect(client2).to receive(:delete_virtual_machine).twice - expect(disk_manager).to receive(:delete_disk).with(os_disk_name).twice - expect(disk_manager).to receive(:delete_disk).with(ephemeral_disk_name).twice + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, os_disk_name).twice + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name).twice expect(disk_manager).to receive(:delete_vm_status_files). - with(storage_account_name, instance_id).twice + with(storage_account_name, vm_name).twice expect(client2).not_to receive(:delete_network_interface) expect { @@ -659,10 +672,10 @@ it "should not delete vm and then raise an error" do expect(client2).to receive(:create_virtual_machine).once expect(client2).to receive(:delete_virtual_machine).once - expect(disk_manager).not_to receive(:delete_disk).with(os_disk_name) - expect(disk_manager).not_to receive(:delete_disk).with(ephemeral_disk_name) + expect(disk_manager).not_to receive(:delete_disk).with(storage_account_name, os_disk_name) + expect(disk_manager).not_to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name) expect(disk_manager).not_to receive(:delete_vm_status_files). - with(storage_account_name, instance_id) + with(storage_account_name, vm_name) expect(client2).not_to receive(:delete_network_interface) expect { @@ -683,8 +696,8 @@ it "should not delete vm and then raise an error" do expect(client2).to receive(:create_virtual_machine).exactly(3).times expect(client2).to receive(:delete_virtual_machine).twice - expect(disk_manager2).to receive(:delete_disk).with(os_disk_name).twice - expect(disk_manager2).not_to receive(:delete_disk).with(ephemeral_disk_name) + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, os_disk_name).twice + expect(disk_manager2).not_to receive(:delete_disk).with(resource_group_name, ephemeral_disk_name) expect(client2).not_to receive(:delete_network_interface) expect { @@ -700,8 +713,8 @@ it "should not delete vm and then raise an error" do expect(client2).to receive(:create_virtual_machine).exactly(3).times expect(client2).to receive(:delete_virtual_machine).twice - expect(disk_manager2).to receive(:delete_disk).with(os_disk_name).twice - expect(disk_manager2).to receive(:delete_disk).with(ephemeral_disk_name).twice + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, os_disk_name).twice + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, ephemeral_disk_name).twice expect(client2).not_to receive(:delete_network_interface) expect { @@ -722,6 +735,32 @@ allow(client2).to receive(:create_virtual_machine) end + # Resource group + context "when resource group does not exist" do + let(:resource_pool) { + { + 'instance_type' => 'Standard_D1', + 'storage_account_name' => 'dfe03ad623f34d42999e93ca', + 'caching' => 'ReadWrite', + } + } + + before do + allow(client2).to receive(:get_resource_group). + with(resource_group_name). + and_return(nil) + allow(client2).to receive(:create_network_interface) + end + + it "should create the resource group" do + expect(client2).to receive(:create_resource_group). + with(resource_group_name, location) + + vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) + expect(vm_params[:name]).to eq(vm_name) + end + end + # Network Security Group context "#network_security_group" do context "with the network security group provided in resource_pool" do @@ -751,7 +790,7 @@ expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) expect(vm_params[:image_uri]).to eq(stemcell_uri) expect(vm_params[:os_type]).to eq(os_type) end @@ -783,7 +822,7 @@ expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end end @@ -792,7 +831,7 @@ let(:nsg_name) { "fake-nsg-name-specified-in-network-spec" } let(:security_group) { { - :name => nsg_name + :name => nsg_name } } @@ -812,9 +851,9 @@ expect(client2).not_to receive(:delete_network_interface) expect(client2).to receive(:create_network_interface). - with(hash_including(:security_group => security_group), any_args).twice + with(resource_group_name, hash_including(:security_group => security_group), any_args).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -824,7 +863,7 @@ expect(client2).not_to receive(:delete_network_interface) vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -847,7 +886,7 @@ expect(client2).not_to receive(:delete_network_interface) expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end end @@ -874,7 +913,7 @@ expect(client2).not_to receive(:delete_network_interface) expect(client2).to receive(:create_network_interface).exactly(2).times vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -890,7 +929,7 @@ expect(client2).not_to receive(:delete_network_interface) expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end end @@ -915,7 +954,7 @@ expect(client2).to receive(:create_network_interface).exactly(2).times vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) expect(vm_params[:image_uri]).to eq(stemcell_uri) expect(vm_params[:os_type]).to eq(os_type) end @@ -944,7 +983,7 @@ expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) expect(vm_params[:os_type]).to eq(os_type) end end @@ -967,7 +1006,7 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(availability_set_name). + with(resource_group_name, availability_set_name). and_return(nil) allow(client2).to receive(:create_availability_set). and_raise("availability set is not created") @@ -1007,17 +1046,17 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(nil) end it "should create availability set and use value of availability_set as its name" do expect(client2).to receive(:create_availability_set). - with(avset_params) + with(resource_group_name, avset_params) expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -1052,16 +1091,16 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(nil) end it "should create availability set and use value of availability_set as its name" do expect(client2).to receive(:create_availability_set). - with(avset_params) + with(resource_group_name, avset_params) vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -1091,16 +1130,16 @@ before do avset_params[:name] = env['bosh']['group'] allow(client2).to receive(:get_availability_set_by_name). - with(env['bosh']['group']). + with(resource_group_name, env['bosh']['group']). and_return(nil) end it "should create availability set and use value of env.bosh.group as its name" do expect(client2).to receive(:create_availability_set). - with(avset_params) + with(resource_group_name, avset_params) vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -1119,10 +1158,10 @@ end it "should create availability set with a truncated value of env.bosh.group as its name" do - expect(client2).to receive(:create_availability_set).with(avset_params) + expect(client2).to receive(:create_availability_set).with(resource_group_name, avset_params) vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end end @@ -1151,7 +1190,7 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(availability_set) end @@ -1159,7 +1198,7 @@ expect(client2).not_to receive(:create_availability_set) vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -1187,16 +1226,16 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(nil) end it "should create the unmanaged availability set" do - expect(client2).to receive(:create_availability_set).with(avset_params) + expect(client2).to receive(:create_availability_set).with(resource_group_name, avset_params) expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -1221,16 +1260,16 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(nil) end it "should create the managed availability set" do - expect(client2).to receive(:create_availability_set).with(avset_params) + expect(client2).to receive(:create_availability_set).with(resource_group_name, avset_params) expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager2.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -1255,15 +1294,15 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(nil) end it "should create the availability set with the default values" do - expect(client2).to receive(:create_availability_set).with(avset_params) + expect(client2).to receive(:create_availability_set).with(resource_group_name, avset_params) vm_params = vm_manager2.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end @@ -1290,16 +1329,16 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(nil) end it "should create the availability set with the specified values" do - expect(client2).to receive(:create_availability_set).with(avset_params) + expect(client2).to receive(:create_availability_set).with(resource_group_name, avset_params) expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager2.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end end @@ -1336,16 +1375,16 @@ before do allow(client2).to receive(:get_availability_set_by_name). - with(resource_pool['availability_set']). + with(resource_group_name, resource_pool['availability_set']). and_return(existing_avset) end it "should update the managed property of the availability set" do - expect(client2).to receive(:create_availability_set).with(avset_params) + expect(client2).to receive(:create_availability_set).with(resource_group_name, avset_params) expect(client2).to receive(:create_network_interface).twice vm_params = vm_manager2.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end end @@ -1354,7 +1393,7 @@ let(:dynamic_public_ip) { 'fake-dynamic-public-ip' } let(:nic0_params) { { - :name => "#{instance_id}-0", + :name => "#{vm_name}-0", :location => location, :private_ip => nil, :public_ip => dynamic_public_ip, @@ -1369,7 +1408,7 @@ allow(network_configurator).to receive(:vip_network). and_return(nil) allow(client2).to receive(:get_public_ip_by_name). - with(instance_id).and_return(dynamic_public_ip) + with(resource_group_name, vm_name).and_return(dynamic_public_ip) end context "and pip_idle_timeout_in_minutes is set" do @@ -1381,24 +1420,24 @@ it "creates a public IP and assigns it to the NIC" do expect(client2).to receive(:create_public_ip). - with(instance_id, location, false, 20) + with(resource_group_name, vm_name, location, false, 20) expect(client2).to receive(:create_network_interface). - with(nic0_params, subnet, tags, load_balancer) + with(resource_group_name, nic0_params, subnet, tags, load_balancer) vm_params = vm_manager_for_pip.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end context "and pip_idle_timeout_in_minutes is not set" do it "creates a public IP and assigns it to the NIC" do expect(client2).to receive(:create_public_ip). - with(instance_id, location, false, 4) + with(resource_group_name, vm_name, location, false, 4) expect(client2).to receive(:create_network_interface). - with(nic0_params, subnet, tags, load_balancer) + with(resource_group_name, nic0_params, subnet, tags, load_balancer) vm_params = vm_manager.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(vm_params[:name]).to eq(instance_id) + expect(vm_params[:name]).to eq(vm_name) end end end @@ -1417,13 +1456,13 @@ let(:user_data) { { :registry => { :endpoint => registry_endpoint }, - :server => { :name => instance_id }, + :server => { :name => instance_id_string }, :dns => { :nameserver => 'fake-dns'} } } let(:vm_params) { { - :name => instance_id, + :name => vm_name, :location => location, :tags => { 'user-agent' => 'bosh' }, :vm_size => "Standard_D1", @@ -1446,9 +1485,9 @@ expect(client2).not_to receive(:delete_virtual_machine) expect(client2).not_to receive(:delete_network_interface) expect(client2).to receive(:create_virtual_machine). - with(vm_params, network_interfaces, nil) + with(resource_group_name, vm_params, network_interfaces, nil) result = vm_manager2.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) - expect(result[:name]).to eq(instance_id) + expect(result[:name]).to eq(vm_name) end end @@ -1458,14 +1497,14 @@ let(:user_data) { { :registry => { :endpoint => registry_endpoint }, - :'instance-id' => instance_id, + :'instance-id' => instance_id_string, :server => { :name => computer_name }, :dns => { :nameserver => 'fake-dns'} } } let(:vm_params) { { - :name => instance_id, + :name => vm_name, :location => location, :tags => { 'user-agent' => 'bosh' }, :vm_size => "Standard_D1", @@ -1490,7 +1529,7 @@ it "should succeed" do expect(client2).to receive(:create_virtual_machine). - with(vm_params, network_interfaces, nil) + with(resource_group_name, vm_params, network_interfaces, nil) expect(SecureRandom).to receive(:uuid).exactly(3).times expect { vm_manager2.create(instance_id, location, stemcell_info, resource_pool, network_configurator, env) @@ -1510,12 +1549,12 @@ expect(client2).to receive(:create_virtual_machine).twice expect(client2).to receive(:delete_virtual_machine).once - expect(disk_manager).to receive(:generate_os_disk_name).with(instance_id).once - expect(disk_manager).to receive(:delete_disk).with(os_disk_name).once - expect(disk_manager).to receive(:generate_ephemeral_disk_name).with(instance_id).once - expect(disk_manager).to receive(:delete_disk).with(ephemeral_disk_name).once + expect(disk_manager).to receive(:generate_os_disk_name).with(vm_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, os_disk_name).once + expect(disk_manager).to receive(:generate_ephemeral_disk_name).with(vm_name).once + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name).once expect(disk_manager).to receive(:delete_vm_status_files). - with(storage_account_name, instance_id).once + with(storage_account_name, vm_name).once expect(client2).not_to receive(:delete_network_interface) expect { @@ -1534,10 +1573,10 @@ expect(client2).to receive(:create_virtual_machine).twice expect(client2).to receive(:delete_virtual_machine).once - expect(disk_manager2).to receive(:generate_os_disk_name).with(instance_id).once - expect(disk_manager2).to receive(:delete_disk).with(os_disk_name).once - expect(disk_manager2).to receive(:generate_ephemeral_disk_name).with(instance_id).once - expect(disk_manager2).to receive(:delete_disk).with(ephemeral_disk_name).once + expect(disk_manager2).to receive(:generate_os_disk_name).with(vm_name).once + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, os_disk_name).once + expect(disk_manager2).to receive(:generate_ephemeral_disk_name).with(vm_name).once + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, ephemeral_disk_name).once expect(client2).not_to receive(:delete_network_interface) expect { @@ -1549,278 +1588,4 @@ end end end - - describe "#find" do - it "finds the instance by id" do - expect(client2).to receive(:get_virtual_machine_by_name).with(instance_id) - vm_manager.find(instance_id) - end - end - - describe "#delete" do - let(:load_balancer) { double("load_balancer") } - let(:network_interface) { - { - :tags => {} - } - } - let(:os_disk_name) { "fake-os-disk-name" } - let(:public_ip) { "fake-public-ip" } - - before do - allow(client2).to receive(:get_load_balancer_by_name). - with(instance_id).and_return(load_balancer) - allow(client2).to receive(:get_network_interface_by_name). - with(instance_id).and_return(network_interface) - allow(client2).to receive(:get_public_ip_by_name). - with(instance_id).and_return(public_ip) - end - - context "When vm is not nil" do - let(:availability_set_name) { "#{SecureRandom.uuid}" } - let(:availability_set) { - { - :name => availability_set_name, - :virtual_machines => [ - "fake-vm-id-1", - "fake-vm-id-2" - ] - } - } - let(:vm) { - { - :availability_set => availability_set, - :network_interfaces => [ - {:name => "fake-nic-1"}, - {:name => "fake-nic-2"} - ] - } - } - - before do - allow(client2).to receive(:get_virtual_machine_by_name). - with(instance_id).and_return(vm) - allow(client2).to receive(:get_availability_set_by_name). - with(availability_set_name). - and_return(availability_set) - end - - context "When use_managed_disks is false" do - before do - allow(disk_manager).to receive(:generate_os_disk_name). - with(instance_id). - and_return(os_disk_name) - allow(disk_manager).to receive(:generate_ephemeral_disk_name). - with(instance_id). - and_return(ephemeral_disk_name) - end - - it "should delete the instance by id" do - expect(client2).to receive(:delete_virtual_machine).with(instance_id) - expect(client2).to receive(:delete_network_interface).with("fake-nic-1") - expect(client2).to receive(:delete_network_interface).with("fake-nic-2") - expect(client2).to receive(:delete_public_ip).with(instance_id) - expect(disk_manager).to receive(:delete_disk).with(os_disk_name) - expect(disk_manager).to receive(:delete_disk).with(ephemeral_disk_name) - expect(disk_manager).to receive(:delete_vm_status_files). - with(storage_account_name, instance_id) - - vm_manager.delete(instance_id) - end - end - - context "When use_managed_disks is true" do - before do - allow(disk_manager2).to receive(:generate_os_disk_name). - with(instance_id). - and_return(os_disk_name) - allow(disk_manager2).to receive(:generate_ephemeral_disk_name). - with(instance_id). - and_return(ephemeral_disk_name) - end - - it "should delete the instance by id" do - expect(client2).to receive(:delete_virtual_machine).with(instance_id) - expect(client2).to receive(:delete_network_interface).with("fake-nic-1") - expect(client2).to receive(:delete_network_interface).with("fake-nic-2") - expect(client2).to receive(:delete_public_ip).with(instance_id) - - expect(disk_manager2).to receive(:delete_disk).with(os_disk_name) - expect(disk_manager2).to receive(:delete_disk).with(ephemeral_disk_name) - - vm_manager2.delete(instance_id) - end - end - end - - context "When vm is nil" do - before do - # It does NOT matter whether use_managed_disks is enabled for this case - allow(disk_manager2).to receive(:generate_os_disk_name). - with(instance_id). - and_return(os_disk_name) - allow(disk_manager2).to receive(:generate_ephemeral_disk_name). - with(instance_id). - and_return(ephemeral_disk_name) - end - - context "When the tags of network interfaces don't include availability set name" do - let(:network_interfaces) { - [ - { - :name => "fake-possible-nic-1", - :tags => {} - }, - { - :name => "fake-possible-nic-2", - :tags => {} - } - ] - } - - before do - allow(client2).to receive(:get_virtual_machine_by_name). - with(instance_id).and_return(nil) - allow(client2).to receive(:list_network_interfaces_by_instance_id). - with(instance_id).and_return(network_interfaces) - end - - it "should delete other resources but not delete the vm and the availability set" do - expect(client2).not_to receive(:delete_virtual_machine).with(instance_id) - expect(client2).to receive(:delete_network_interface).with("fake-possible-nic-1") - expect(client2).to receive(:delete_network_interface).with("fake-possible-nic-2") - expect(client2).to receive(:delete_public_ip).with(instance_id) - - expect(disk_manager2).to receive(:delete_disk).with(os_disk_name) - expect(disk_manager2).to receive(:delete_disk).with(ephemeral_disk_name) - - vm_manager2.delete(instance_id) - end - end - end - end - - describe "#reboot" do - it "reboots the instance by id" do - expect(client2).to receive(:restart_virtual_machine).with(instance_id) - vm_manager.reboot(instance_id) - end - end - - describe "#set_metadata" do - it "sets the metadata of the instance by id" do - expect(client2).to receive(:update_tags_of_virtual_machine). - with(instance_id, {'user-agent' => 'bosh'}) - vm_manager.set_metadata(instance_id, {}) - end - end - - describe "#attach_disk" do - let(:caching) { "None" } - let(:disk_name) { "fake-disk-name-#{caching}" } - let(:lun) { 1 } - - context "When the disk is unmanaged disk" do - let(:instance_id) { "#{MOCK_DEFAULT_STORAGE_ACCOUNT_NAME}-e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } - let(:disk_uri) { "fake-disk-uri" } - let(:disk_size) { 42 } - let(:disk_params) { - { - :disk_name => disk_name, - :caching => caching, - :disk_uri => disk_uri, - :disk_size => disk_size, - :managed => false - } - } - - before do - allow(disk_manager).to receive(:get_disk_uri). - with(disk_name).and_return(disk_uri) - allow(disk_manager).to receive(:get_data_disk_caching). - with(disk_name). - and_return(caching) - allow(disk_manager).to receive(:get_disk_size_in_gb). - with(disk_name).and_return(disk_size) - end - - it "attaches the disk to an instance" do - expect(client2).to receive(:attach_disk_to_virtual_machine). - with(instance_id, disk_params). - and_return(lun) - expect(vm_manager.attach_disk(instance_id, disk_name)).to eq("#{lun}") - end - end - - context "When the disk is managed disk" do - let(:instance_id) { "e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } - let(:managed_disk_id) { "fake-id" } - let(:managed_disk) { {:id => managed_disk_id} } - let(:disk_params) { - { - :disk_name => disk_name, - :caching => caching, - :disk_id => managed_disk_id, - :managed => true - } - } - - before do - allow(client2).to receive(:get_managed_disk_by_name). - with(disk_name). - and_return(managed_disk) - allow(disk_manager2).to receive(:get_data_disk_caching). - with(disk_name). - and_return(caching) - end - - it "attaches the disk to an instance" do - expect(client2).to receive(:attach_disk_to_virtual_machine). - with(instance_id, disk_params). - and_return(lun) - expect(vm_manager2.attach_disk(instance_id, disk_name)).to eq("#{lun}") - end - end - - context "When the vm is unmanaged vm and use_managed_disks is true" do - let(:instance_id) { "#{MOCK_DEFAULT_STORAGE_ACCOUNT_NAME}-e55144a3-0c06-4240-8f15-9a7bc7b35d1f" } - let(:disk_uri) { "fake-disk-uri" } - let(:disk_size) { 42 } - let(:disk_params) { - { - :disk_name => disk_name, - :caching => caching, - :disk_uri => disk_uri, - :disk_size => disk_size, - :managed => false - } - } - - before do - allow(disk_manager).to receive(:get_disk_uri). - with(disk_name).and_return(disk_uri) - allow(disk_manager).to receive(:get_data_disk_caching). - with(disk_name). - and_return(caching) - allow(disk_manager).to receive(:get_disk_size_in_gb). - with(disk_name).and_return(disk_size) - end - - it "attaches the disk to an instance" do - expect(client2).to receive(:attach_disk_to_virtual_machine). - with(instance_id, disk_params). - and_return(lun) - expect(vm_manager2.attach_disk(instance_id, disk_name)).to eq("#{lun}") - end - end - end - - describe "#detach_disk" do - let(:disk_name) { "fake-disk-name" } - it "detaches the disk from an instance" do - expect(client2).to receive(:detach_disk_from_virtual_machine). - with(instance_id, disk_name) - vm_manager.detach_disk(instance_id, disk_name) - end - end end diff --git a/src/bosh_azure_cpi/spec/unit/vm_manager/delete_spec.rb b/src/bosh_azure_cpi/spec/unit/vm_manager/delete_spec.rb new file mode 100644 index 000000000..f9b2bef1d --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/vm_manager/delete_spec.rb @@ -0,0 +1,178 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::VMManager do + describe "#delete" do + let(:registry_endpoint) { mock_registry.endpoint } + let(:disk_manager) { instance_double(Bosh::AzureCloud::DiskManager) } + let(:disk_manager2) { instance_double(Bosh::AzureCloud::DiskManager2) } + let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } + let(:azure_properties) { mock_azure_properties } + let(:vm_manager) { Bosh::AzureCloud::VMManager.new(azure_properties, registry_endpoint, disk_manager, disk_manager2, client2) } + + let(:resource_group_name) { "fake-resource-group-name" } + let(:storage_account_name) { "fake-storage-account-name" } + let(:vm_name) { "fake-vm-name" } + + let(:load_balancer) { double("load_balancer") } + let(:network_interface) { + { + :tags => {} + } + } + let(:os_disk_name) { "fake-os-disk-name" } + let(:ephemeral_disk_name) { "fake-ephemeral-disk-name" } + let(:public_ip) { "fake-public-ip" } + + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + + before do + allow(instance_id).to receive(:resource_group_name). + and_return(resource_group_name) + allow(instance_id).to receive(:vm_name). + and_return(vm_name) + + allow(client2).to receive(:get_load_balancer_by_name). + with(vm_name).and_return(load_balancer) + allow(client2).to receive(:get_network_interface_by_name). + with(resource_group_name, vm_name).and_return(network_interface) + allow(client2).to receive(:get_public_ip_by_name). + with(resource_group_name, vm_name).and_return(public_ip) + end + + context "When vm is not nil" do + let(:availability_set_name) { "#{SecureRandom.uuid}" } + let(:availability_set) { + { + :name => availability_set_name, + :virtual_machines => [ + "fake-vm-id-1", + "fake-vm-id-2" + ] + } + } + let(:vm) { + { + :availability_set => availability_set, + :network_interfaces => [ + {:name => "fake-nic-1"}, + {:name => "fake-nic-2"} + ] + } + } + + context "When vm is with unmanaged disk" do + before do + allow(instance_id).to receive(:use_managed_disks?). + and_return(false) + allow(instance_id).to receive(:storage_account_name). + and_return(storage_account_name) + + allow(client2).to receive(:get_virtual_machine_by_name). + with(resource_group_name, vm_name).and_return(vm) + allow(disk_manager).to receive(:generate_os_disk_name). + with(vm_name). + and_return(os_disk_name) + allow(disk_manager).to receive(:generate_ephemeral_disk_name). + with(vm_name). + and_return(ephemeral_disk_name) + end + + it "should delete all resources" do + expect(client2).to receive(:delete_virtual_machine).with(resource_group_name, vm_name) + expect(client2).to receive(:delete_network_interface).with(resource_group_name, "fake-nic-1") + expect(client2).to receive(:delete_network_interface).with(resource_group_name, "fake-nic-2") + expect(client2).to receive(:delete_public_ip).with(resource_group_name, vm_name) + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, os_disk_name) + expect(disk_manager).to receive(:delete_disk).with(storage_account_name, ephemeral_disk_name) + expect(disk_manager).to receive(:delete_vm_status_files). + with(storage_account_name, vm_name) + + expect { + vm_manager.delete(instance_id) + }.not_to raise_error + end + end + + context "When vm is with managed disk" do + before do + allow(instance_id).to receive(:use_managed_disks?). + and_return(true) + + allow(client2).to receive(:get_virtual_machine_by_name). + with(resource_group_name, vm_name).and_return(vm) + allow(disk_manager2).to receive(:generate_os_disk_name). + with(vm_name). + and_return(os_disk_name) + allow(disk_manager2).to receive(:generate_ephemeral_disk_name). + with(vm_name). + and_return(ephemeral_disk_name) + end + + it "should delete all resources" do + expect(client2).to receive(:delete_virtual_machine).with(resource_group_name, vm_name) + expect(client2).to receive(:delete_network_interface).with(resource_group_name, "fake-nic-1") + expect(client2).to receive(:delete_network_interface).with(resource_group_name, "fake-nic-2") + expect(client2).to receive(:delete_public_ip).with(resource_group_name, vm_name) + + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, os_disk_name) + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, ephemeral_disk_name) + + expect { + vm_manager.delete(instance_id) + }.not_to raise_error + end + end + end + + context "When vm is nil" do + before do + # It does NOT matter whether the vm is with managed disk or not. + allow(instance_id).to receive(:use_managed_disks?). + and_return(true) + + allow(disk_manager2).to receive(:generate_os_disk_name). + with(vm_name). + and_return(os_disk_name) + allow(disk_manager2).to receive(:generate_ephemeral_disk_name). + with(vm_name). + and_return(ephemeral_disk_name) + end + + context "When the tags of network interfaces don't include availability set name" do + let(:network_interfaces) { + [ + { + :name => "fake-possible-nic-1", + :tags => {} + }, + { + :name => "fake-possible-nic-2", + :tags => {} + } + ] + } + + before do + allow(client2).to receive(:get_virtual_machine_by_name). + with(resource_group_name, vm_name).and_return(nil) + allow(client2).to receive(:list_network_interfaces_by_keyword). + with(resource_group_name, vm_name).and_return(network_interfaces) + end + + it "should delete other resources but not delete the vm and the availability set" do + expect(client2).not_to receive(:delete_virtual_machine).with(resource_group_name, vm_name) + expect(client2).to receive(:delete_network_interface).with(resource_group_name, "fake-possible-nic-1") + expect(client2).to receive(:delete_network_interface).with(resource_group_name, "fake-possible-nic-2") + expect(client2).to receive(:delete_public_ip).with(resource_group_name, vm_name) + + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, os_disk_name) + expect(disk_manager2).to receive(:delete_disk).with(resource_group_name, ephemeral_disk_name) + + expect { + vm_manager.delete(instance_id) + }.not_to raise_error + end + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/vm_manager/detach_disk_spec.rb b/src/bosh_azure_cpi/spec/unit/vm_manager/detach_disk_spec.rb new file mode 100644 index 000000000..ae8ede53e --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/vm_manager/detach_disk_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::VMManager do + describe "#detach_disk" do + let(:registry_endpoint) { mock_registry.endpoint } + let(:disk_manager) { instance_double(Bosh::AzureCloud::DiskManager) } + let(:disk_manager2) { instance_double(Bosh::AzureCloud::DiskManager2) } + let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } + let(:azure_properties) { mock_azure_properties } + let(:vm_manager) { Bosh::AzureCloud::VMManager.new(azure_properties, registry_endpoint, disk_manager, disk_manager2, client2) } + + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + let(:disk_id) { instance_double(Bosh::AzureCloud::DiskId) } + + let(:vm_name) { "fake-vm-name" } + let(:resource_group_name) { "fake-resource-group-name" } + let(:disk_name) { "fake-disk-name" } + + before do + allow(instance_id).to receive(:resource_group_name). + and_return(resource_group_name) + allow(instance_id).to receive(:vm_name). + and_return(vm_name) + + allow(disk_id).to receive(:disk_name). + and_return(disk_name) + end + + context "when everything is ok" do + it "detach_disks the instance by id" do + expect(client2).to receive(:detach_disk_from_virtual_machine). + with(resource_group_name, vm_name, disk_name) + expect { + vm_manager.detach_disk(instance_id, disk_id) + }.not_to raise_error + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/vm_manager/find_spec.rb b/src/bosh_azure_cpi/spec/unit/vm_manager/find_spec.rb new file mode 100644 index 000000000..53739f732 --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/vm_manager/find_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::VMManager do + describe "#find" do + let(:registry_endpoint) { mock_registry.endpoint } + let(:disk_manager) { instance_double(Bosh::AzureCloud::DiskManager) } + let(:disk_manager2) { instance_double(Bosh::AzureCloud::DiskManager2) } + let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } + let(:azure_properties) { mock_azure_properties } + let(:vm_manager) { Bosh::AzureCloud::VMManager.new(azure_properties, registry_endpoint, disk_manager, disk_manager2, client2) } + + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + + let(:vm_name) { "fake-vm-name" } + let(:resource_group_name) { "fake-resource-group-name" } + + before do + allow(instance_id).to receive(:resource_group_name). + and_return(resource_group_name) + allow(instance_id).to receive(:vm_name). + and_return(vm_name) + end + + context "when everything is ok" do + it "finds the instance by id" do + expect(client2).to receive(:get_virtual_machine_by_name). + with(resource_group_name, vm_name) + expect { + vm_manager.find(instance_id) + }.not_to raise_error + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/vm_manager/reboot_spec.rb b/src/bosh_azure_cpi/spec/unit/vm_manager/reboot_spec.rb new file mode 100644 index 000000000..c499fef26 --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/vm_manager/reboot_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::VMManager do + describe "#reboot" do + let(:registry_endpoint) { mock_registry.endpoint } + let(:disk_manager) { instance_double(Bosh::AzureCloud::DiskManager) } + let(:disk_manager2) { instance_double(Bosh::AzureCloud::DiskManager2) } + let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } + let(:azure_properties) { mock_azure_properties } + let(:vm_manager) { Bosh::AzureCloud::VMManager.new(azure_properties, registry_endpoint, disk_manager, disk_manager2, client2) } + + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + + let(:vm_name) { "fake-vm-name" } + let(:resource_group_name) { "fake-resource-group-name" } + + before do + allow(instance_id).to receive(:resource_group_name). + and_return(resource_group_name) + allow(instance_id).to receive(:vm_name). + and_return(vm_name) + end + + context "when everything is ok" do + it "reboots the instance by id" do + expect(client2).to receive(:restart_virtual_machine). + with(resource_group_name, vm_name) + expect { + vm_manager.reboot(instance_id) + }.not_to raise_error + end + end + end +end diff --git a/src/bosh_azure_cpi/spec/unit/vm_manager/set_metadata_spec.rb b/src/bosh_azure_cpi/spec/unit/vm_manager/set_metadata_spec.rb new file mode 100644 index 000000000..503e456e6 --- /dev/null +++ b/src/bosh_azure_cpi/spec/unit/vm_manager/set_metadata_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Bosh::AzureCloud::VMManager do + describe "#set_metadata" do + let(:registry_endpoint) { mock_registry.endpoint } + let(:disk_manager) { instance_double(Bosh::AzureCloud::DiskManager) } + let(:disk_manager2) { instance_double(Bosh::AzureCloud::DiskManager2) } + let(:client2) { instance_double(Bosh::AzureCloud::AzureClient2) } + let(:azure_properties) { mock_azure_properties } + let(:vm_manager) { Bosh::AzureCloud::VMManager.new(azure_properties, registry_endpoint, disk_manager, disk_manager2, client2) } + + let(:instance_id) { instance_double(Bosh::AzureCloud::InstanceId) } + + let(:vm_name) { "fake-vm-name" } + let(:resource_group_name) { "fake-resource-group-name" } + + before do + allow(instance_id).to receive(:resource_group_name). + and_return(resource_group_name) + allow(instance_id).to receive(:vm_name). + and_return(vm_name) + end + + context "when everything is ok" do + it "set_metadatas the instance by id" do + expect(client2).to receive(:update_tags_of_virtual_machine). + with(resource_group_name, vm_name, {'user-agent' => 'bosh'}) + expect { + vm_manager.set_metadata(instance_id, {}) + }.not_to raise_error + end + end + end +end