Create _id/name_filter methods for all listings
authorStavros Sachtouris <saxtouri@admin.grnet.gr>
Mon, 26 Aug 2013 11:13:52 +0000 (14:13 +0300)
committerStavros Sachtouris <saxtouri@admin.grnet.gr>
Mon, 26 Aug 2013 11:13:52 +0000 (14:13 +0300)
Refs: #4220

kamaki/cli/commands/__init__.py
kamaki/cli/commands/cyclades.py
kamaki/cli/commands/image.py
kamaki/cli/commands/pithos.py

index 10eee8e..590e5b2 100644 (file)
@@ -32,8 +32,8 @@
 # or implied, of GRNET S.A.command
 
 from kamaki.cli.logger import get_logger
-from kamaki.cli.utils import print_json, print_items
-from kamaki.cli.argument import FlagArgument
+from kamaki.cli.utils import print_json, print_items, filter_dicts_by_dict
+from kamaki.cli.argument import FlagArgument, ValueArgument
 
 log = get_logger(__name__)
 
@@ -66,6 +66,10 @@ class _command_init(object):
             arguments.update(self.oo_arguments)
         if isinstance(self, _optional_json):
             arguments.update(self.oj_arguments)
+        if isinstance(self, _name_filter):
+            arguments.update(self.nf_arguments)
+        if isinstance(self, _id_filter):
+            arguments.update(self.if_arguments)
         try:
             arguments.update(self.wait_arguments)
         except AttributeError:
@@ -209,3 +213,60 @@ class _optional_json(object):
             print_json(output)
         else:
             print_method(output, **print_method_kwargs)
+
+
+class _name_filter(object):
+
+    nf_arguments = dict(
+        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')
+    )
+
+    def _non_exact_name_filter(self, items):
+        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
+        return [item for item in items if (
+            (not np) or item['name'].lower().startswith(np.lower())) and (
+            (not ns) or item['name'].lower().endswith(ns.lower())) and (
+            (not nl) or nl.lower() in item['name'].lower())]
+
+    def _exact_name_filter(self, items):
+        return filter_dicts_by_dict(items, dict(name=self['name'])) if (
+            self['name']) else items
+
+    def _filter_by_name(self, items):
+        return self._non_exact_name_filter(self._exact_name_filter(items))
+
+
+class _id_filter(object):
+
+    if_arguments = dict(
+        id=ValueArgument('filter by id', '--id'),
+        id_pref=ValueArgument(
+            'filter by id prefix (case insensitive)', '--id-prefix'),
+        id_suff=ValueArgument(
+            'filter by id suffix (case insensitive)', '--id-suffix'),
+        id_like=ValueArgument(
+            'print only if id contains this (case insensitive)',
+            '--id-like')
+    )
+
+    def _non_exact_id_filter(self, items):
+        np, ns, nl = self['id_pref'], self['id_suff'], self['id_like']
+        return [item for item in items if (
+            (not np) or (
+                '%s' % item['id']).lower().startswith(np.lower())) and (
+            (not ns) or ('%s' % item['id']).lower().endswith(ns.lower())) and (
+            (not nl) or nl.lower() in ('%s' % item['id']).lower())]
+
+    def _exact_id_filter(self, items):
+        return filter_dicts_by_dict(items, dict(id=self['id'])) if (
+            self['id']) else items
+
+    def _filter_by_id(self, items):
+        return self._non_exact_id_filter(self._exact_id_filter(items))
index 88c33dc..fd388ff 100644 (file)
@@ -40,7 +40,8 @@ from kamaki.clients.cyclades import CycladesClient, ClientError
 from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
 from kamaki.cli.argument import ProgressBarArgument, DateArgument, IntArgument
 from kamaki.cli.commands import _command_init, errors, addLogSettings
-from kamaki.cli.commands import _optional_output_cmd, _optional_json
+from kamaki.cli.commands import (
+    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
 
 from base64 import b64encode
 from os.path import exists
@@ -155,7 +156,7 @@ class _init_cyclades(_command_init):
 
 
 @command(server_cmds)
-class server_list(_init_cyclades, _optional_json):
+class server_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
     """List Virtual Machines accessible by user"""
 
     PERMANENTS = ('id', 'name')
@@ -172,14 +173,6 @@ class server_list(_init_cyclades, _optional_json):
             'output results in pages (-n to set items per page, default 10)',
             '--more'),
         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')),
@@ -188,15 +181,6 @@ class server_list(_init_cyclades, _optional_json):
             ('--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 _add_user_name(self, servers):
         uuids = self._uuids2usernames(list(set(
                 [srv['user_id'] for srv in servers] +
@@ -206,7 +190,7 @@ class server_list(_init_cyclades, _optional_json):
             srv['tenant_id'] += ' (%s)' % uuids[srv['tenant_id']]
         return servers
 
-    def _filtered_by_image(self, servers):
+    def _filter_by_image(self, servers):
         iid = self['image_id']
         new_servers = []
         for srv in servers:
@@ -214,7 +198,7 @@ class server_list(_init_cyclades, _optional_json):
                 new_servers.append(srv)
         return new_servers
 
-    def _filtered_by_flavor(self, servers):
+    def _filter_by_flavor(self, servers):
         fid = self['flavor_id']
         new_servers = []
         for srv in servers:
@@ -222,7 +206,7 @@ class server_list(_init_cyclades, _optional_json):
                 new_servers.append(srv)
         return new_servers
 
-    def _filtered_by_metadata(self, servers):
+    def _filter_by_metadata(self, servers):
         new_servers = []
         for srv in servers:
             if not 'metadata' in srv:
@@ -247,13 +231,14 @@ class server_list(_init_cyclades, _optional_json):
         detail = self['detail'] or withimage or withflavor or withmeta
         servers = self.client.list_servers(detail, self['since'])
 
-        servers = self._filtered_by_name(servers)
+        servers = self._filter_by_name(servers)
+        servers = self._filter_by_id(servers)
         if withimage:
-            servers = self._filtered_by_image(servers)
+            servers = self._filter_by_image(servers)
         if withflavor:
-            servers = self._filtered_by_flavor(servers)
+            servers = self._filter_by_flavor(servers)
         if withmeta:
-            servers = self._filtered_by_metadata(servers)
+            servers = self._filter_by_metadata(servers)
 
         if self['detail'] and not self['json_output']:
             servers = self._add_user_name(servers)
@@ -700,7 +685,7 @@ class server_wait(_init_cyclades, _server_wait):
 
 
 @command(flavor_cmds)
-class flavor_list(_init_cyclades, _optional_json):
+class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
     """List available hardware flavors"""
 
     arguments = dict(
@@ -716,6 +701,8 @@ class flavor_list(_init_cyclades, _optional_json):
     @errors.cyclades.connection
     def _run(self):
         flavors = self.client.list_flavors(self['detail'])
+        flavors = self._filter_by_name(flavors)
+        flavors = self._filter_by_id(flavors)
         if not (self['detail'] or self['json_output']):
             remove_from_items(flavors, 'links')
         pg_size = 10 if self['more'] and not self['limit'] else self['limit']
@@ -767,7 +754,7 @@ class network_info(_init_cyclades, _optional_json):
 
 
 @command(network_cmds)
-class network_list(_init_cyclades, _optional_json):
+class network_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
     """List networks"""
 
     arguments = dict(
@@ -783,6 +770,8 @@ class network_list(_init_cyclades, _optional_json):
     @errors.cyclades.connection
     def _run(self):
         networks = self.client.list_networks(self['detail'])
+        networks = self._filter_by_name(networks)
+        networks = self._filter_by_id(networks)
         if not (self['detail'] or self['json_output']):
             remove_from_items(networks, 'links')
         kwargs = dict(with_enumeration=self['enum'])
index 3838656..11ba32c 100644 (file)
@@ -47,7 +47,8 @@ from kamaki.cli.argument import IntArgument, ProgressBarArgument
 from kamaki.cli.commands.cyclades import _init_cyclades
 from kamaki.cli.errors import raiseCLIError, CLIBaseUrlError
 from kamaki.cli.commands import _command_init, errors, addLogSettings
-from kamaki.cli.commands import _optional_output_cmd, _optional_json
+from kamaki.cli.commands import (
+    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
 
 
 image_cmds = CommandTree(
@@ -172,7 +173,7 @@ def _validate_image_location(location):
 
 
 @command(image_cmds)
-class image_list(_init_image, _optional_json):
+class image_list(_init_image, _optional_json, _name_filter, _id_filter):
     """List images accessible by user"""
 
     PERMANENTS = (
@@ -185,14 +186,6 @@ class image_list(_init_image, _optional_json):
             'filter by container format',
             '--container-format'),
         disk_format=ValueArgument('filter by disk format', '--disk-format'),
-        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'),
         size_min=IntArgument('filter by minimum size', '--size-min'),
         size_max=IntArgument('filter by maximum size', '--size-max'),
         status=ValueArgument('filter by status', '--status'),
@@ -213,17 +206,10 @@ class image_list(_init_image, _optional_json):
             ('--property-like')),
     )
 
-    def _filtered_by_owner(self, images):
+    def _filter_by_owner(self, images):
         ouuid = self['owner'] or self._username2uuid(self['owner_name'])
         return filter_dicts_by_dict(images, dict(owner=ouuid))
 
-    def _filtered_by_name(self, images):
-        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
-        return [img for img in images 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 _add_owner_name(self, images):
         uuids = self._uuids2usernames(
             list(set([img['owner'] for img in images])))
@@ -231,7 +217,7 @@ class image_list(_init_image, _optional_json):
             img['owner'] += ' (%s)' % uuids[img['owner']]
         return images
 
-    def _filtered_by_properties(self, images):
+    def _filter_by_properties(self, images):
         new_images = []
         for img in images:
             props = [dict(img['properties'])]
@@ -266,10 +252,11 @@ class image_list(_init_image, _optional_json):
         images = self.client.list_public(detail, filters, order)
 
         if self['owner'] or self['owner_name']:
-            images = self._filtered_by_owner(images)
+            images = self._filter_by_owner(images)
         if self['prop'] or self['prop_like']:
-            images = self._filtered_by_properties(images)
-        images = self._filtered_by_name(images)
+            images = self._filter_by_properties(images)
+        images = self._filter_by_id(images)
+        images = self._non_exact_name_filter(images)
 
         if self['detail'] and not self['json_output']:
             images = self._add_owner_name(images)
@@ -622,7 +609,8 @@ class image_compute(_init_cyclades):
 
 
 @command(image_cmds)
-class image_compute_list(_init_cyclades, _optional_json):
+class image_compute_list(
+        _init_cyclades, _optional_json, _name_filter, _id_filter):
     """List images"""
 
     PERMANENTS = ('id', 'name')
@@ -634,16 +622,6 @@ class image_compute_list(_init_cyclades, _optional_json):
             'output results in pages (-n to set items per page, default 10)',
             '--more'),
         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'),
         user_id=ValueArgument('filter by user_id', '--user-id'),
         user_name=ValueArgument('filter by username', '--user-name'),
         meta=KeyValueArgument(
@@ -653,13 +631,6 @@ class image_compute_list(_init_cyclades, _optional_json):
             ('--metadata-like'))
     )
 
-    def _filtered_by_name(self, images):
-        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
-        return [img for img in images 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 _filter_by_metadata(self, images):
         new_images = []
         for img in images:
@@ -691,7 +662,8 @@ class image_compute_list(_init_cyclades, _optional_json):
         withuser = bool(self['user_id'] or self['user_name'])
         detail = self['detail'] or withmeta or withuser
         images = self.client.list_images(detail)
-        images = self._filtered_by_name(images)
+        images = self._filter_by_name(images)
+        images = self._filter_by_id(images)
         if withuser:
             images = self._filter_by_user(images)
         if withmeta:
index 4cdd73c..a592b20 100644 (file)
@@ -46,7 +46,8 @@ from kamaki.cli.argument import KeyValueArgument, DateArgument
 from kamaki.cli.argument import ProgressBarArgument
 from kamaki.cli.commands import _command_init, errors
 from kamaki.cli.commands import addLogSettings, DontRaiseKeyError
-from kamaki.cli.commands import _optional_output_cmd, _optional_json
+from kamaki.cli.commands import (
+    _optional_output_cmd, _optional_json, _name_filter)
 from kamaki.clients.pithos import PithosClient, ClientError
 from kamaki.clients.astakos import AstakosClient
 
@@ -326,7 +327,7 @@ class _file_container_command(_file_account_command):
 
 
 @command(pithos_cmds)
-class file_list(_file_container_command, _optional_json):
+class file_list(_file_container_command, _optional_json, _name_filter):
     """List containers, object trees or objects in a directory
     Use with:
     1 no parameters : containers in current account
@@ -439,9 +440,10 @@ class file_list(_file_container_command, _optional_json):
                 if_unmodified_since=self['if_unmodified_since'],
                 until=self['until'],
                 show_only_shared=self['shared'])
-            self._print(r.json, self.print_containers)
+            files = self._filter_by_name(r.json)
+            self._print(files, self.print_containers)
         else:
-            prefix = self.path or self['prefix']
+            prefix = self.path or self['prefix'] or self['name_prefix']
             r = self.client.container_get(
                 limit=False if self['more'] else self['limit'],
                 marker=self['marker'],
@@ -453,7 +455,8 @@ class file_list(_file_container_command, _optional_json):
                 until=self['until'],
                 meta=self['meta'],
                 show_only_shared=self['shared'])
-            self._print(r.json, self.print_objects)
+            files = self._filter_by_name(r.json)
+            self._print(files, self.print_objects)
 
     def main(self, container____path__=None):
         super(self.__class__, self)._run(container____path__)