Commit 89ea97e1 authored by Stavros Sachtouris's avatar Stavros Sachtouris
Browse files

Impement basic/custom filters for server list

Refs: #4220

New filters: name[-like/-suffix/-prefix], flavor_id, image_id, metadata[-like]
parent 466636c9
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
from kamaki.cli import command from kamaki.cli import command
from kamaki.cli.command_tree import CommandTree from kamaki.cli.command_tree import CommandTree
from kamaki.cli.utils import print_dict, remove_from_items from kamaki.cli.utils import (
print_dict, remove_from_items, filter_dicts_by_dict)
from kamaki.cli.errors import raiseCLIError, CLISyntaxError, CLIBaseUrlError from kamaki.cli.errors import raiseCLIError, CLISyntaxError, CLIBaseUrlError
from kamaki.clients.cyclades import CycladesClient, ClientError from kamaki.clients.cyclades import CycladesClient, ClientError
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
...@@ -157,6 +158,8 @@ class _init_cyclades(_command_init): ...@@ -157,6 +158,8 @@ class _init_cyclades(_command_init):
class server_list(_init_cyclades, _optional_json): class server_list(_init_cyclades, _optional_json):
"""List Virtual Machines accessible by user""" """List Virtual Machines accessible by user"""
PERMANENTS = ('id', 'name')
__doc__ += about_authentication __doc__ += about_authentication
arguments = dict( arguments = dict(
...@@ -168,17 +171,89 @@ class server_list(_init_cyclades, _optional_json): ...@@ -168,17 +171,89 @@ class server_list(_init_cyclades, _optional_json):
more=FlagArgument( more=FlagArgument(
'output results in pages (-n to set items per page, default 10)', 'output results in pages (-n to set items per page, default 10)',
'--more'), '--more'),
enum=FlagArgument('Enumerate results', '--enumerate') enum=FlagArgument('Enumerate results', '--enumerate'),
name=ValueArgument('filter by name', '--name'),
name_pref=ValueArgument(
'filter by name prefix (case insensitive)', '--name-prefix'),
name_suff=ValueArgument(
'filter by name suffix (case insensitive)', '--name-suffix'),
name_like=ValueArgument(
'print only if name contains this (case insensitive)',
'--name-like'),
flavor_id=ValueArgument('filter by flavor id', ('--flavor-id')),
image_id=ValueArgument('filter by image id', ('--image-id')),
meta=KeyValueArgument('filter by metadata key=values', ('--metadata')),
meta_like=KeyValueArgument(
'print only if in key=value, the value is part of actual value',
('--metadata-like')),
) )
def _filtered_by_name(self, servers):
if self['name']:
servers = filter_dicts_by_dict(servers, dict(name=self['name']))
np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
return [img for img in servers if (
(not np) or img['name'].lower().startswith(np.lower())) and (
(not ns) or img['name'].lower().endswith(ns.lower())) and (
(not nl) or nl.lower() in img['name'].lower())]
def _filtered_by_image(self, servers):
iid = self['image_id']
new_servers = []
for srv in servers:
if srv['image']['id'] == iid:
new_servers.append(srv)
return new_servers
def _filtered_by_flavor(self, servers):
fid = self['flavor_id']
new_servers = []
for srv in servers:
if '%s' % srv['flavor']['id'] == '%s' % fid:
new_servers.append(srv)
return new_servers
def _filtered_by_metadata(self, servers):
new_servers = []
for srv in servers:
if not 'metadata' in srv:
continue
meta = [dict(srv['metadata'])]
if self['meta']:
meta = filter_dicts_by_dict(meta, self['meta'])
if meta and self['meta_like']:
meta = filter_dicts_by_dict(
meta, self['meta_like'], exact_match=False)
if meta:
new_servers.append(srv)
return new_servers
@errors.generic.all @errors.generic.all
@errors.cyclades.connection @errors.cyclades.connection
@errors.cyclades.date @errors.cyclades.date
def _run(self): def _run(self):
servers = self.client.list_servers(self['detail'], self['since']) withimage = bool(self['image_id'])
withflavor = bool(self['flavor_id'])
withmeta = bool(self['meta'] or self['meta_like'])
detail = self['detail'] or withimage or withflavor or withmeta
servers = self.client.list_servers(detail, self['since'])
servers = self._filtered_by_name(servers)
if withimage:
servers = self._filtered_by_image(servers)
if withflavor:
servers = self._filtered_by_flavor(servers)
if withmeta:
servers = self._filtered_by_metadata(servers)
if not (self['detail'] or self['json_output']): if not (self['detail'] or self['json_output']):
remove_from_items(servers, 'links') remove_from_items(servers, 'links')
#if self['detail'] and not self['json_output']:
# servers = self._add_owner_name(servers)
if detail and not self['detail']:
for srv in servers:
for key in set(srv).difference(self.PERMANENTS):
srv.pop(key)
kwargs = dict(with_enumeration=self['enum']) kwargs = dict(with_enumeration=self['enum'])
if self['more']: if self['more']:
kwargs['page_size'] = self['limit'] if self['limit'] else 10 kwargs['page_size'] = self['limit'] if self['limit'] else 10
......
...@@ -187,11 +187,9 @@ class image_list(_init_image, _optional_json): ...@@ -187,11 +187,9 @@ class image_list(_init_image, _optional_json):
disk_format=ValueArgument('filter by disk format', '--disk-format'), disk_format=ValueArgument('filter by disk format', '--disk-format'),
name=ValueArgument('filter by name', '--name'), name=ValueArgument('filter by name', '--name'),
name_pref=ValueArgument( name_pref=ValueArgument(
'filter by name prefix (case insensitive)', 'filter by name prefix (case insensitive)', '--name-prefix'),
'--name-prefix'),
name_suff=ValueArgument( name_suff=ValueArgument(
'filter by name suffix (case insensitive)', 'filter by name suffix (case insensitive)', '--name-suffix'),
'--name-suffix'),
name_like=ValueArgument( name_like=ValueArgument(
'print only if name contains this (case insensitive)', 'print only if name contains this (case insensitive)',
'--name-like'), '--name-like'),
...@@ -813,13 +811,14 @@ class image_compute_properties_set(_init_cyclades, _optional_json): ...@@ -813,13 +811,14 @@ class image_compute_properties_set(_init_cyclades, _optional_json):
def _run(self, image_id, keyvals): def _run(self, image_id, keyvals):
meta = dict() meta = dict()
for keyval in keyvals: for keyval in keyvals:
key, val = keyval.split('=') key, sep, val = keyval.partition('=')
meta[key] = val meta[key] = val
self._print( self._print(
self.client.update_image_metadata(image_id, **meta), print_dict) self.client.update_image_metadata(image_id, **meta), print_dict)
def main(self, image_id, *key_equals_value): def main(self, image_id, *key_equals_value):
super(self.__class__, self)._run() super(self.__class__, self)._run()
print key_equals_value
self._run(image_id=image_id, keyvals=key_equals_value) self._run(image_id=image_id, keyvals=key_equals_value)
......
...@@ -73,8 +73,8 @@ def _flush(): ...@@ -73,8 +73,8 @@ def _flush():
def _readline(): def _readline():
"""stdout.readline wrapper is used to help unittests""" """raw_input wrapper is used to help unittests"""
return stdout.readline() return raw_input()
def suggest_missing(miss=None, exclude=[]): def suggest_missing(miss=None, exclude=[]):
...@@ -283,7 +283,7 @@ def print_items( ...@@ -283,7 +283,7 @@ def print_items(
_print('%s' % items) _print('%s' % items)
return return
page_size = int(page_size) page_size = int(page_size or 0)
try: try:
page_size = page_size if page_size > 0 else len(items) page_size = page_size if page_size > 0 else len(items)
except: except:
......
...@@ -413,6 +413,7 @@ class UtilsMethods(TestCase): ...@@ -413,6 +413,7 @@ class UtilsMethods(TestCase):
def test_split_input(self): def test_split_input(self):
from kamaki.cli.utils import split_input from kamaki.cli.utils import split_input
for line, expected in ( for line, expected in (
('set key="v1"', ['set', 'key=v1']),
('unparsable', ['unparsable']), ('unparsable', ['unparsable']),
('"parsable"', ['parsable']), ('"parsable"', ['parsable']),
('"parse" out', ['parse', 'out']), ('"parse" out', ['parse', 'out']),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment