Skip to content
This repository has been archived by the owner on Nov 9, 2020. It is now read-only.

Commit

Permalink
Add column "Tenant" in admincCLI ls output.
Browse files Browse the repository at this point in the history
  • Loading branch information
lipingxue committed Mar 8, 2017
1 parent 289cfc3 commit f242f22
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 27 deletions.
55 changes: 43 additions & 12 deletions docs/user-guide/admin-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,22 +428,31 @@ optional arguments:
List all properties for all Docker volumes that exist on datastores accessible to the host.
```bash
Volume Datastore Created By VM Created Attached To VM Policy Capacity Used Filesystem Type Access Attach As
-------------- ------------- ------------- ------------------------ -------------- -------------- -------- -------- --------------- ---------- ----------------------
MyVol vsanDatastore photon.vsan.1 Mon Jul 4 17:44:28 2016 detached [VSAN default] 100.00MB 40.00MB ext4 read-write independent_persistent
unt vsanDatastore photon.vsan.1 Mon Jul 4 19:55:26 2016 detached [VSAN default] 100.00MB 40.00MB ext4 read-write independent_persistent
iland vsanDatastore photon.vsan.1 Mon Jul 4 20:11:42 2016 detached [VSAN default] 100.00MB 40.00MB ext4 read-write independent_persistent
foo vsanDatastore photon.vsan.1 Mon Jul 11 03:17:09 2016 detached [VSAN default] 20.00GB 228.00MB ext4 read-write independent_persistent
MyVolume vsanDatastore photon.vsan.1 Mon Jul 11 10:25:45 2016 detached [VSAN default] 10.00GB 192.00MB ext4 read-write independent_persistent
storage-meetup vsanDatastore photon.vsan.1 Mon Jul 11 10:50:20 2016 detached [VSAN default] 10.00GB 348.00MB ext4 read-write independent_persistent
storage vsanDatastore photon.vsan.1 Tue Jul 12 12:53:07 2016 detached [VSAN default] 10.00GB 192.00MB ext4 read-write independent_persistent
storage2 vsanDatastore photon.vsan.1 Tue Jul 12 13:00:11 2016 detached [VSAN default] 10.00GB 192.00MB ext4 read-write independent_persistent
[root@localhost:~] /usr/lib/vmware/vmdkops/bin/vmdkops_admin.py ls
Tenant Volume Datastore Created By VM Created Attached To VM (name/uuid) Policy Capacity Used Disk Format Filesystem Type Access Attach As
-------- -------- ---------- ------------- ------------------------ -------------------------- ------ -------- ---- ----------- --------------- ---------- ----------------------
_DEFAULT vol1 datastore1 photon-6 Sat Sep 10 01:11:07 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT testvol datastore1 photon-6 Sat Sep 10 04:21:02 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT Vol100MB datastore1 photon-6 Sat Sep 10 08:36:29 2016 detached N/A 100MB 13MB thin ext4 read-write persistent
tenant1 vol1 datastore1 photon-6 Sat Sep 10 09:36:51 2016 detached N/A 500MB 23MB thin ext4 read-write independent_persistent
```
Note that the `Policy` column shows the named VSAN storage policy created with the same tool
(vmdkops_admin.py). Since these example virtual disks live on a VMFS datastore they do not have a storage
policy and show up as `N/A'.
Note that the `Tenant` column shows the tenant by which the volume was created. If the tenant which created the volume has been removed, the `Tenant` column shows up as 'N/A'. See the following example:
```bash
[root@localhost:~] /usr/lib/vmware/vmdkops/bin/vmdkops_admin.py ls
Tenant Volume Datastore Created By VM Created Attached To VM (name/uuid) Policy Capacity Used Disk Format Filesystem Type Access Attach As
-------- -------- ---------- ------------- ------------------------ -------------------------- ------ -------- ---- ----------- --------------- ---------- ----------------------
_DEFAULT vol1 datastore1 photon-6 Sat Sep 10 01:11:07 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT testvol datastore1 photon-6 Sat Sep 10 04:21:02 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT Vol100MB datastore1 photon-6 Sat Sep 10 08:36:29 2016 detached N/A 100MB 13MB thin ext4 read-write persistent
N/A vol1 datastore1 photon-6 Sat Sep 10 09:36:51 2016 detached N/A 500MB 23MB thin ext4 read-write independent_persistent
```
#### List selected columns
Show only the selected columns.
Expand All @@ -460,13 +469,13 @@ Note that the that the choices are given in a comma separated list with no space
the help given above with `vmdkops_admin ls -h`.
### Set
Modify attribute settings on a given volume. The volume is identified by its name and datastore,
Modify attribute settings on a given volume. The volume is identified by its name, tenant_name which the volume belongs to and datastore,
for example if the volume name is `container-vol` then the volume is specified as "container-vol@datastore-name".
The attributes to set/modify are specified as a comma separated list as "<attr1>=<value>, <attr2>=<value>....". For example,
a command line would look like this.
```bash
$ vmdkops-admin set --volume=<volume@datastore> --options="<attr1>=<value>, <attr2>=<value>, ..."
$ vmdkops-admin set --volume=<volume@datastore> --tenant=<tenant_name> --options="<attr1>=<value>, <attr2>=<value>, ..."
```
The volume attributes are set and take effect only the next time the volume attached to a VM. The changes do not impact any VM
Expand All @@ -485,6 +494,28 @@ A sample use case:

The container images themselves can be smaller as they share the libs and possibly binaries from read-only volumes.

Example:
```bash
[root@localhost:~] /usr/lib/vmware/vmdkops/bin/vmdkops_admin.py ls
Tenant Volume Datastore Created By VM Created Attached To VM (name/uuid) Policy Capacity Used Disk Format Filesystem Type Access Attach As
-------- -------- ---------- ------------- ------------------------ -------------------------- ------ -------- ---- ----------- --------------- ---------- ----------------------
_DEFAULT vol1 datastore1 photon-6 Sat Sep 10 01:11:07 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT testvol datastore1 photon-6 Sat Sep 10 04:21:02 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT Vol100MB datastore1 photon-6 Sat Sep 10 08:36:29 2016 detached N/A 100MB 13MB thin ext4 read-write persistent
N/A vol1 datastore1 photon-6 Sat Sep 10 09:36:51 2016 detached N/A 500MB 23MB thin ext4 read-write independent_persistent
[root@localhost:~] /usr/lib/vmware/vmdkops/bin/vmdkops_admin.py set --volume=Vol100MB@datastore1 --tenant=_DEFAULT --options="access=read-only"
Successfully updated settings for : Vol100MB@datastore1
[root@localhost:~] /usr/lib/vmware/vmdkops/bin/vmdkops_admin.py ls
Tenant Volume Datastore Created By VM Created Attached To VM (name/uuid) Policy Capacity Used Disk Format Filesystem Type Access Attach As
-------- -------- ---------- ------------- ------------------------ -------------------------- ------ -------- ---- ----------- --------------- ---------- ----------------------
_DEFAULT vol1 datastore1 photon-6 Sat Sep 10 01:11:07 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT testvol datastore1 photon-6 Sat Sep 10 04:21:02 2016 detached N/A 100MB 13MB thin ext4 read-write independent_persistent
_DEFAULT Vol100MB datastore1 photon-6 Sat Sep 10 08:36:29 2016 detached N/A 100MB 13MB thin ext4 read-only persistent
N/A vol1 datastore1 photon-6 Sat Sep 10 09:36:51 2016 detached N/A 500MB 23MB thin ext4 read-write independent_persistent
```


## Policy

Expand Down
8 changes: 6 additions & 2 deletions esx_service/cli/vmdkops_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,14 +531,18 @@ def ls_dash_c(columns, tenant_reg):

def all_ls_headers():
""" Return a list of all header for ls -l """
return ['Volume', 'Datastore', 'Created By VM', 'Created',
return ['Tenant', 'Volume', 'Datastore', 'Created By VM', 'Created',
'Attached To VM (name/uuid)', 'Policy', 'Capacity', 'Used',
'Disk Format', 'Filesystem Type', 'Access', 'Attach As']

def generate_ls_rows(tenant_reg):
""" Gather all volume metadata into rows that can be used to format a table """
rows = []
for v in vmdk_utils.get_volumes(tenant_reg):
if 'tenant' not in v or v['tenant'] == auth.ORPHAN_TENANT:
tenant = 'N/A'
else:
tenant = v['tenant']
path = os.path.join(v['path'], v['filename'])
name = vmdk_utils.strip_vmdk_extension(v['filename'])
metadata = get_metadata(path)
Expand All @@ -550,7 +554,7 @@ def generate_ls_rows(tenant_reg):
fstype = get_fstype(metadata)
access = get_access(metadata)
attach_as = get_attach_as(metadata)
rows.append([name, v['datastore'], created_by, created, attached_to,
rows.append([tenant, name, v['datastore'], created_by, created, attached_to,
policy, size_info['capacity'], size_info['used'],
diskformat, fstype, access, attach_as])
return rows
Expand Down
2 changes: 1 addition & 1 deletion esx_service/cli/vmdkops_admin_sanity_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
ADMIN_CLI = '/usr/lib/vmware/vmdkops/bin/vmdkops_admin.py'

# Number of expected columns in ADMIN_CLI ls
EXPECTED_COLUMN_COUNT = 12
EXPECTED_COLUMN_COUNT = 13

class TestVmdkopsAdminSanity(unittest.TestCase):
""" Test output from running vmdkops_admin.py """
Expand Down
21 changes: 14 additions & 7 deletions esx_service/cli/vmdkops_admin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import convert

# Number of expected columns in ADMIN_CLI ls
EXPECTED_COLUMN_COUNT = 12
EXPECTED_COLUMN_COUNT = 13

# Number of expected columns in "tenant ls"
TENANT_LS_EXPECTED_COLUMN_COUNT = 5
Expand Down Expand Up @@ -255,19 +255,22 @@ def test_set_no_options(self):
self.assert_parse_error('set --volume=volume_name')

def test_set(self):
args = self.parser.parse_args('set --volume=vol_name@datastore --options="access=read-only"'.split())
args = self.parser.parse_args('set --volume=vol_name@datastore --tenant=tenant1 --options="access=read-only"'.split())
self.assertEqual(args.func, vmdkops_admin.set_vol_opts)
self.assertEqual(args.volume, 'vol_name@datastore')
self.assertEqual(args.tenant, 'tenant1')
self.assertEqual(args.options, '"access=read-only"')

args = self.parser.parse_args('set --volume=vol_name@datastore --options="attach-as=persistent"'.split())
args = self.parser.parse_args('set --volume=vol_name@datastore --tenant=tenant1 --options="attach-as=persistent"'.split())
self.assertEqual(args.func, vmdkops_admin.set_vol_opts)
self.assertEqual(args.volume, 'vol_name@datastore')
self.assertEqual(args.tenant, 'tenant1')
self.assertEqual(args.options, '"attach-as=persistent"')

args = self.parser.parse_args('set --volume=vol_name@datastore --options="attach-as=independent_persistent"'.split())
args = self.parser.parse_args('set --volume=vol_name@datastore --tenant=tenant1 --options="attach-as=independent_persistent"'.split())
self.assertEqual(args.func, vmdkops_admin.set_vol_opts)
self.assertEqual(args.volume, 'vol_name@datastore')
self.assertEqual(args.tenant, 'tenant1')
self.assertEqual(args.options, '"attach-as=independent_persistent"')

# Usage is always printed on a parse error. It's swallowed to prevent clutter.
Expand Down Expand Up @@ -339,7 +342,7 @@ def test_ls_no_args(self):
self.assertEqual(EXPECTED_COLUMN_COUNT, len(header))
self.assertEqual(len(volumes), len(rows))
for i in range(len(volumes)):
self.assertEqual(volumes[i]['filename'], rows[i][0] + '.vmdk')
self.assertEqual(volumes[i]['filename'], rows[i][1] + '.vmdk')

class TestSet(unittest.TestCase):
""" Test set functionality """
Expand Down Expand Up @@ -393,7 +396,9 @@ def test_set_attach_as(self):
vol_arg = '@'.join([v['filename'].replace('.vmdk', ''), v['datastore']])

attach_as_arg = 'attach-as={}'.format(attach_as_opt)
set_ok = vmdk_ops.set_vol_opts(vol_arg, attach_as_arg)
set_ok = vmdk_ops.set_vol_opts(name=vol_arg,
tenant_name=None,
options=attach_as_arg)
self.assertTrue(set_ok)

metadata = vmdkops_admin.get_metadata(os.path.join(v['path'], v[
Expand All @@ -411,7 +416,9 @@ def test_set_access(self):
# generate string like "testvol0@datastore1"
vol_arg = '@'.join([v['filename'].replace('.vmdk', ''), v['datastore']])
access_arg = 'access={}'.format(access_opt)
set_ok = vmdk_ops.set_vol_opts(vol_arg, access_arg)
set_ok = vmdk_ops.set_vol_opts(name=vol_arg,
tenant_name=None,
options=access_arg)
self.assertTrue(set_ok)

metadata = vmdkops_admin.get_metadata(os.path.join(v['path'], v[
Expand Down
1 change: 1 addition & 0 deletions esx_service/utils/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
DEFAULT_TENANT_UUID = '11111111-1111-1111-1111-111111111111'
DEFAULT_DS = '_DEFAULT'
DEFAULT_DS_URL = DEFAULT_DS + "_URL"
ORPHAN_TENANT = "_ORPHAN"

# thread local storage in this module namespace
thread_local = threadutils.get_local_storage()
Expand Down
12 changes: 11 additions & 1 deletion esx_service/utils/vmdk_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,19 @@ def get_volumes(tenant_re):
for file_name in list_vmdks(root):
volumes.append({'path': root,
'filename': file_name,
'datastore': datastore})
'datastore': datastore,
'tenant' : tenant_name})
else:
# cannot find this tenant, this tenant was removed
# mark those volumes created by "orphan" tenant
logging.debug("get_volumes: cannot find tenant_name for tenant_uuid=%s", sub_dir_name)
logging.debug("get_volumes: path=%s root=%s sub_dir_name=%s",
path, root, sub_dir_name)
for file_name in list_vmdks(root):
volumes.append({'path': root,
'filename': file_name,
'datastore': datastore,
'tenant' : auth.ORPHAN_TENANT})
logging.debug("volumes %s", volumes)
return volumes

Expand Down
10 changes: 6 additions & 4 deletions esx_service/vmdk_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1349,10 +1349,12 @@ def set_vol_opts(name, tenant_name, options):

# try to set opts on a volume which was created by a non-exist tenant
# fail the request
error_info = auth_api.check_tenant_exist(tenant_name)
if not error_info:
logging.warning(error_code.error_code_to_message[ErrorCode.TENANT_NOT_EXIST].format(tenant_name))
return False
if tenant_name:
# if tenant_name is "None", which means the function is called without multi-tenancy
error_info = auth_api.check_tenant_exist(tenant_name)
if not error_info:
logging.warning(error_code.error_code_to_message[ErrorCode.TENANT_NOT_EXIST].format(tenant_name))
return False

# get /vmfs/volumes/<datastore_url>/dockvols path on ESX:
path, errMsg = get_vol_path(datastore, tenant_name)
Expand Down

0 comments on commit f242f22

Please sign in to comment.