-
Notifications
You must be signed in to change notification settings - Fork 95
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Just one comment which is just refactoring the code - you can decide if you want to address it in a separate change or not.
esx_service/vmdk_ops.py
Outdated
@@ -786,9 +786,23 @@ def executeRequest(vm_uuid, vm_name, config_path, cmd, full_vol_name, opts): | |||
vm_datastore_url = vmdk_utils.get_datastore_url_from_config_path(config_path) | |||
vm_datastore = get_datastore_name(vm_datastore_url) | |||
|
|||
# Detach is implicity allowed if a disk has been attached | |||
# Do not find tenant or privileges; just detach the disk | |||
if cmd == "detach": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we introduce an enum to define all the commands?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestion, but outside of scope for this PR. @shaominchen - Please file an issue (or code it up and submit a PR)
Generally, executeRequest() became too messy. It was a small function with a switch for 5 simple commands, now it's quite complex. Would be nice to clean up. Certainly not in this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed issue #1070.
esx_service/vmdk_ops.py
Outdated
@@ -656,11 +656,11 @@ def attachVMDK(vmdk_path, vm_uuid): | |||
|
|||
|
|||
# Return error, or None for OK. | |||
def detachVMDK(vmdk_path, vm_uuid): | |||
def detachVMDK(full_vol_name, vm_uuid): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer full_vmdk_path rather than full_vol_name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so is it a name (vol@DS) or a path?
A comment (in a dockstring) would be good
esx_service/vmdk_ops.py
Outdated
return err(error_info) | ||
# For docker volume ls, docker prints a list of cached volume names in case | ||
# of error(in this case, orphan VM). | ||
# Explicity providing empty list of volumes to avoid misleading output. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you differentiate between genuine error versus VM not member of any tenant?
Please add link to issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest using if err_info and tenant_uuid: <read_error>
and if erron_info and !tenant_uuid
- no tenant
But yes, this one hides all real errors from get_tenant, if any. (mainly DB errors/file IO I guess)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
esx_service/vmdk_ops.py
Outdated
@@ -1297,16 +1311,20 @@ def err(string): | |||
return {u'Error': string} | |||
|
|||
|
|||
def disk_detach(vmdk_path, vm): | |||
"""detach disk (by full path) from a vm amd return None or err(msg)""" | |||
def disk_detach(full_vol_name, vm): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. Since we are manipulating VMDK, I would refer this as full_vmdk_path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the content of param 'full_vol_name' is qualified volume name in format volume@datastore
Calling it full_vmdk_path would be confusing.
I will update the param comment though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments inline. The main one - I do not understand how it will behave if there are two volumes with identical (short) names on different datastores, both attached. Which one will detach ?
@@ -832,6 +832,7 @@ def test_tenant_access(self): | |||
rows[0][3]] | |||
self.assertEqual(expected_output, actual_output) | |||
|
|||
print("[Negative test case]: Expected invalid values for allow-create option") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks !
esx_service/vmdk_ops.py
Outdated
@@ -656,11 +656,11 @@ def attachVMDK(vmdk_path, vm_uuid): | |||
|
|||
|
|||
# Return error, or None for OK. | |||
def detachVMDK(vmdk_path, vm_uuid): | |||
def detachVMDK(full_vol_name, vm_uuid): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so is it a name (vol@DS) or a path?
A comment (in a dockstring) would be good
esx_service/vmdk_ops.py
Outdated
@@ -786,9 +786,23 @@ def executeRequest(vm_uuid, vm_name, config_path, cmd, full_vol_name, opts): | |||
vm_datastore_url = vmdk_utils.get_datastore_url_from_config_path(config_path) | |||
vm_datastore = get_datastore_name(vm_datastore_url) | |||
|
|||
# Detach is implicity allowed if a disk has been attached | |||
# Do not find tenant or privileges; just detach the disk | |||
if cmd == "detach": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestion, but outside of scope for this PR. @shaominchen - Please file an issue (or code it up and submit a PR)
Generally, executeRequest() became too messy. It was a small function with a switch for 5 simple commands, now it's quite complex. Would be nice to clean up. Certainly not in this PR
esx_service/vmdk_ops.py
Outdated
if cmd == "detach": | ||
with lockManager.get_lock(vm_uuid): | ||
response = detachVMDK(full_vol_name, vm_uuid) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit (can be ignored): generally I'd prefer to have a simple dict-driven code, with something like {"attach": ["auth_needed": True, "func": "code", ,,} ...} to drive the execution for commands. (this is the same note as the above reply to @shaominchen ).
esx_service/vmdk_ops.py
Outdated
return err(error_info) | ||
# For docker volume ls, docker prints a list of cached volume names in case | ||
# of error(in this case, orphan VM). | ||
# Explicity providing empty list of volumes to avoid misleading output. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest using if err_info and tenant_uuid: <read_error>
and if erron_info and !tenant_uuid
- no tenant
But yes, this one hides all real errors from get_tenant, if any. (mainly DB errors/file IO I guess)
esx_service/vmdk_ops.py
Outdated
logging.debug("findDeviceByName: datastore = %s, backing_disk_name = %s", | ||
datastore, backing_disk_name) | ||
|
||
if backing_disk_name == vol_name: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what if there are 2 Docker volumes with the same names on different datastores. both attached ? Which one will be detached? I do not see DS names used in matching.... not 'dockvols' part of the path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@msterin
Fixing it to compare both volume name and datastore name with backing disk name and backing disk datastore.
Confirmed that we always get a qualified volume name i.e. volumename@datastore; from docker -> vmdk_plugin -> esx host.
esx_service/vmdk_ops.py
Outdated
@@ -1071,7 +1084,8 @@ def handle_stale_attach(vmdk_path, kv_uuid): | |||
if cur_vm.runtime.powerState == VM_POWERED_OFF: | |||
logging.info("Detaching disk %s from VM(powered off) - %s\n", | |||
vmdk_path, cur_vm.config.name) | |||
device = findDeviceByPath(vmdk_path, cur_vm) | |||
vol_name = vmdk_utils.strip_vmdk_extension(os.path.basename(vmdk_path)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strip extension should be responsibility of the caller, but instead done in findDeviceByName (if needed)
@pshahzeb Is it ready for review? Looks like you are still addressing review comments? |
Yes. This fix fails to detach volumes with two same short names but on different DS. we get short name for volume for detach during volume create process. |
d14432c
to
2e48603
Compare
esx_service/utils/vmdk_utils.py
Outdated
# Filename format is as follows: | ||
# "[<datastore name>] <parent-directory>/tenant/<vmdk-descriptor-name>" | ||
# Trim the datastore name and keep disk path. | ||
_, disk_path = d.backing.fileName.split(None, 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cannot trim the datastore correctly if whitespaces are included in the datastore name.
fileName = "[datastor e1] /dockvols/tenant1/vol1.vmdk"
_, disk_path = fileName.split(None, 1)
print disk_path
e1] /dockvols/tenant1/vol1.vmdk
Use "]" as a separator.
esx_service/vmdk_ops.py
Outdated
def disk_detach(full_vol_name, vm): | ||
"""detach disk (by full_vol_name) from a vm and return None or err(msg)""" | ||
def disk_detach(vmdk_path, vm): | ||
"""detach disk (by full path) from a vm amd return None or err(msg)""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: amd -> and
1. Disallowing tenant-vm membership change when volumes are mounted and in use by VMs 2. Send empty list as output to docker volume ls command to forcefully make docker print emtpy list and not the cached volume names 3. Minor print to indicate negative test case and avoid CI output confusion Fixes #990 #1045
fe64c8d
to
d1eb652
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. A few nits.
esx_service/utils/auth_api.py
Outdated
@@ -409,6 +409,17 @@ def _tenant_rm(name, remove_volumes=False): | |||
error_info = error_code.generate_error_info(ErrorCode.TENANT_NOT_EXIST, name) | |||
return error_info | |||
|
|||
# check if vms that are a part if this tenant have any volumes mounted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "if this tenant" => "of this tenant"
esx_service/utils/auth_api.py
Outdated
# check if vms that are a part if this tenant have any volumes mounted. | ||
# If they have, can't delete the tenant. | ||
if tenant.vms: | ||
logging.info("tenant rm. VMs in tenant are %s", tenant.vms) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "tenant rm" => "_tenant_rm", just for consistency.
esx_service/utils/error_code.py
Outdated
@@ -75,6 +76,7 @@ class ErrorCode: | |||
ErrorCode.VM_IN_ANOTHER_TENANT : "VM '{0}' has already been associated with tenant '{1}', can't add it", | |||
ErrorCode.VM_LIST_EMPTY : "VM list cannot be empty", | |||
ErrorCode.VM_DUPLICATE : "VMs {0} contain duplicates, they should be unique", | |||
ErrorCode.VM_WITH_MOUNTED_VOLUMES :"VM '{0}' has volumes mounted.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: add a space after ":"
esx_service/utils/vmdk_utils.py
Outdated
@@ -307,6 +311,32 @@ def get_vm_config_path(vm_name): | |||
vm_config_path = os.path.join(datastore_path, path) | |||
return vm_config_path | |||
|
|||
def check_volumes_mounted(vm_list): | |||
""" | |||
Return error_info any vm in @param vm_list have docker volume mounted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: add an "if" before "any vm"
esx_service/utils/vmdk_utils.py
Outdated
# Trim the datastore name and keep disk path. | ||
_, disk_path = d.backing.fileName.rsplit("]", 1) | ||
logging.info("backing disk name is %s", disk_path) | ||
# If disk path start with "dockvols", the disk is a docker volume |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we extract the logic of checking whether a disk is a docker volume (322-332) to a separate method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Disallow tenant rm, tenant vm rm, tenant vm replace when VMs which are part of the given tenant have any volumes currently mounted and being used. Safe approach to alert the user so that he can complete the ongoing jobs and then manipulate the tenancy membership changes.
Send empty list as output to docker volume ls command to forcefully make docker
print emtpy list and not the cached volume names
[Minor] print to indicate negative test case and avoid CI output confusion
Fixes #1045
Create tenant1 and add a vm to it.
Create a volume and attach it to a container inside this VM. Keep the container running.
Try to remove the VM from tenant, replace the VM with another VM and try to delete the tenant.
Error with appropriate message
VM is orphan now. docker volume ls shows empty list of volumes
Fixes #990
Create a volume from a VM and then delete the VM's tenant
docker volume ls from the VM gives empty list