Revision 6d190dd1

b/kamaki/cli/commands/__init__.py
32 32
# or implied, of GRNET S.A.command
33 33

  
34 34
from kamaki.cli.logger import get_logger
35
from kamaki.cli.utils import print_json, print_items
36
from kamaki.cli.argument import FlagArgument
35
from kamaki.cli.utils import print_json, print_items, filter_dicts_by_dict
36
from kamaki.cli.argument import FlagArgument, ValueArgument
37 37

  
38 38
log = get_logger(__name__)
39 39

  
......
66 66
            arguments.update(self.oo_arguments)
67 67
        if isinstance(self, _optional_json):
68 68
            arguments.update(self.oj_arguments)
69
        if isinstance(self, _name_filter):
70
            arguments.update(self.nf_arguments)
71
        if isinstance(self, _id_filter):
72
            arguments.update(self.if_arguments)
69 73
        try:
70 74
            arguments.update(self.wait_arguments)
71 75
        except AttributeError:
......
209 213
            print_json(output)
210 214
        else:
211 215
            print_method(output, **print_method_kwargs)
216

  
217

  
218
class _name_filter(object):
219

  
220
    nf_arguments = dict(
221
        name=ValueArgument('filter by name', '--name'),
222
        name_pref=ValueArgument(
223
            'filter by name prefix (case insensitive)', '--name-prefix'),
224
        name_suff=ValueArgument(
225
            'filter by name suffix (case insensitive)', '--name-suffix'),
226
        name_like=ValueArgument(
227
            'print only if name contains this (case insensitive)',
228
            '--name-like')
229
    )
230

  
231
    def _non_exact_name_filter(self, items):
232
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
233
        return [item for item in items if (
234
            (not np) or item['name'].lower().startswith(np.lower())) and (
235
            (not ns) or item['name'].lower().endswith(ns.lower())) and (
236
            (not nl) or nl.lower() in item['name'].lower())]
237

  
238
    def _exact_name_filter(self, items):
239
        return filter_dicts_by_dict(items, dict(name=self['name'])) if (
240
            self['name']) else items
241

  
242
    def _filter_by_name(self, items):
243
        return self._non_exact_name_filter(self._exact_name_filter(items))
244

  
245

  
246
class _id_filter(object):
247

  
248
    if_arguments = dict(
249
        id=ValueArgument('filter by id', '--id'),
250
        id_pref=ValueArgument(
251
            'filter by id prefix (case insensitive)', '--id-prefix'),
252
        id_suff=ValueArgument(
253
            'filter by id suffix (case insensitive)', '--id-suffix'),
254
        id_like=ValueArgument(
255
            'print only if id contains this (case insensitive)',
256
            '--id-like')
257
    )
258

  
259
    def _non_exact_id_filter(self, items):
260
        np, ns, nl = self['id_pref'], self['id_suff'], self['id_like']
261
        return [item for item in items if (
262
            (not np) or (
263
                '%s' % item['id']).lower().startswith(np.lower())) and (
264
            (not ns) or ('%s' % item['id']).lower().endswith(ns.lower())) and (
265
            (not nl) or nl.lower() in ('%s' % item['id']).lower())]
266

  
267
    def _exact_id_filter(self, items):
268
        return filter_dicts_by_dict(items, dict(id=self['id'])) if (
269
            self['id']) else items
270

  
271
    def _filter_by_id(self, items):
272
        return self._non_exact_id_filter(self._exact_id_filter(items))
b/kamaki/cli/commands/cyclades.py
40 40
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
41 41
from kamaki.cli.argument import ProgressBarArgument, DateArgument, IntArgument
42 42
from kamaki.cli.commands import _command_init, errors, addLogSettings
43
from kamaki.cli.commands import _optional_output_cmd, _optional_json
43
from kamaki.cli.commands import (
44
    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
44 45

  
45 46
from base64 import b64encode
46 47
from os.path import exists
......
155 156

  
156 157

  
157 158
@command(server_cmds)
158
class server_list(_init_cyclades, _optional_json):
159
class server_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
159 160
    """List Virtual Machines accessible by user"""
160 161

  
161 162
    PERMANENTS = ('id', 'name')
......
172 173
            'output results in pages (-n to set items per page, default 10)',
173 174
            '--more'),
174 175
        enum=FlagArgument('Enumerate results', '--enumerate'),
175
        name=ValueArgument('filter by name', '--name'),
176
        name_pref=ValueArgument(
177
            'filter by name prefix (case insensitive)', '--name-prefix'),
178
        name_suff=ValueArgument(
179
            'filter by name suffix (case insensitive)', '--name-suffix'),
180
        name_like=ValueArgument(
181
            'print only if name contains this (case insensitive)',
182
            '--name-like'),
183 176
        flavor_id=ValueArgument('filter by flavor id', ('--flavor-id')),
184 177
        image_id=ValueArgument('filter by image id', ('--image-id')),
185 178
        meta=KeyValueArgument('filter by metadata key=values', ('--metadata')),
......
188 181
            ('--metadata-like')),
189 182
    )
190 183

  
191
    def _filtered_by_name(self, servers):
192
        if self['name']:
193
            servers = filter_dicts_by_dict(servers, dict(name=self['name']))
194
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
195
        return [img for img in servers if (
196
            (not np) or img['name'].lower().startswith(np.lower())) and (
197
            (not ns) or img['name'].lower().endswith(ns.lower())) and (
198
            (not nl) or nl.lower() in img['name'].lower())]
199

  
200 184
    def _add_user_name(self, servers):
201 185
        uuids = self._uuids2usernames(list(set(
202 186
                [srv['user_id'] for srv in servers] +
......
206 190
            srv['tenant_id'] += ' (%s)' % uuids[srv['tenant_id']]
207 191
        return servers
208 192

  
209
    def _filtered_by_image(self, servers):
193
    def _filter_by_image(self, servers):
210 194
        iid = self['image_id']
211 195
        new_servers = []
212 196
        for srv in servers:
......
214 198
                new_servers.append(srv)
215 199
        return new_servers
216 200

  
217
    def _filtered_by_flavor(self, servers):
201
    def _filter_by_flavor(self, servers):
218 202
        fid = self['flavor_id']
219 203
        new_servers = []
220 204
        for srv in servers:
......
222 206
                new_servers.append(srv)
223 207
        return new_servers
224 208

  
225
    def _filtered_by_metadata(self, servers):
209
    def _filter_by_metadata(self, servers):
226 210
        new_servers = []
227 211
        for srv in servers:
228 212
            if not 'metadata' in srv:
......
247 231
        detail = self['detail'] or withimage or withflavor or withmeta
248 232
        servers = self.client.list_servers(detail, self['since'])
249 233

  
250
        servers = self._filtered_by_name(servers)
234
        servers = self._filter_by_name(servers)
235
        servers = self._filter_by_id(servers)
251 236
        if withimage:
252
            servers = self._filtered_by_image(servers)
237
            servers = self._filter_by_image(servers)
253 238
        if withflavor:
254
            servers = self._filtered_by_flavor(servers)
239
            servers = self._filter_by_flavor(servers)
255 240
        if withmeta:
256
            servers = self._filtered_by_metadata(servers)
241
            servers = self._filter_by_metadata(servers)
257 242

  
258 243
        if self['detail'] and not self['json_output']:
259 244
            servers = self._add_user_name(servers)
......
700 685

  
701 686

  
702 687
@command(flavor_cmds)
703
class flavor_list(_init_cyclades, _optional_json):
688
class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
704 689
    """List available hardware flavors"""
705 690

  
706 691
    arguments = dict(
......
716 701
    @errors.cyclades.connection
717 702
    def _run(self):
718 703
        flavors = self.client.list_flavors(self['detail'])
704
        flavors = self._filter_by_name(flavors)
705
        flavors = self._filter_by_id(flavors)
719 706
        if not (self['detail'] or self['json_output']):
720 707
            remove_from_items(flavors, 'links')
721 708
        pg_size = 10 if self['more'] and not self['limit'] else self['limit']
......
767 754

  
768 755

  
769 756
@command(network_cmds)
770
class network_list(_init_cyclades, _optional_json):
757
class network_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
771 758
    """List networks"""
772 759

  
773 760
    arguments = dict(
......
783 770
    @errors.cyclades.connection
784 771
    def _run(self):
785 772
        networks = self.client.list_networks(self['detail'])
773
        networks = self._filter_by_name(networks)
774
        networks = self._filter_by_id(networks)
786 775
        if not (self['detail'] or self['json_output']):
787 776
            remove_from_items(networks, 'links')
788 777
        kwargs = dict(with_enumeration=self['enum'])
b/kamaki/cli/commands/image.py
47 47
from kamaki.cli.commands.cyclades import _init_cyclades
48 48
from kamaki.cli.errors import raiseCLIError, CLIBaseUrlError
49 49
from kamaki.cli.commands import _command_init, errors, addLogSettings
50
from kamaki.cli.commands import _optional_output_cmd, _optional_json
50
from kamaki.cli.commands import (
51
    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
51 52

  
52 53

  
53 54
image_cmds = CommandTree(
......
172 173

  
173 174

  
174 175
@command(image_cmds)
175
class image_list(_init_image, _optional_json):
176
class image_list(_init_image, _optional_json, _name_filter, _id_filter):
176 177
    """List images accessible by user"""
177 178

  
178 179
    PERMANENTS = (
......
185 186
            'filter by container format',
186 187
            '--container-format'),
187 188
        disk_format=ValueArgument('filter by disk format', '--disk-format'),
188
        name=ValueArgument('filter by name', '--name'),
189
        name_pref=ValueArgument(
190
            'filter by name prefix (case insensitive)', '--name-prefix'),
191
        name_suff=ValueArgument(
192
            'filter by name suffix (case insensitive)', '--name-suffix'),
193
        name_like=ValueArgument(
194
            'print only if name contains this (case insensitive)',
195
            '--name-like'),
196 189
        size_min=IntArgument('filter by minimum size', '--size-min'),
197 190
        size_max=IntArgument('filter by maximum size', '--size-max'),
198 191
        status=ValueArgument('filter by status', '--status'),
......
213 206
            ('--property-like')),
214 207
    )
215 208

  
216
    def _filtered_by_owner(self, images):
209
    def _filter_by_owner(self, images):
217 210
        ouuid = self['owner'] or self._username2uuid(self['owner_name'])
218 211
        return filter_dicts_by_dict(images, dict(owner=ouuid))
219 212

  
220
    def _filtered_by_name(self, images):
221
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
222
        return [img for img in images if (
223
            (not np) or img['name'].lower().startswith(np.lower())) and (
224
            (not ns) or img['name'].lower().endswith(ns.lower())) and (
225
            (not nl) or nl.lower() in img['name'].lower())]
226

  
227 213
    def _add_owner_name(self, images):
228 214
        uuids = self._uuids2usernames(
229 215
            list(set([img['owner'] for img in images])))
......
231 217
            img['owner'] += ' (%s)' % uuids[img['owner']]
232 218
        return images
233 219

  
234
    def _filtered_by_properties(self, images):
220
    def _filter_by_properties(self, images):
235 221
        new_images = []
236 222
        for img in images:
237 223
            props = [dict(img['properties'])]
......
266 252
        images = self.client.list_public(detail, filters, order)
267 253

  
268 254
        if self['owner'] or self['owner_name']:
269
            images = self._filtered_by_owner(images)
255
            images = self._filter_by_owner(images)
270 256
        if self['prop'] or self['prop_like']:
271
            images = self._filtered_by_properties(images)
272
        images = self._filtered_by_name(images)
257
            images = self._filter_by_properties(images)
258
        images = self._filter_by_id(images)
259
        images = self._non_exact_name_filter(images)
273 260

  
274 261
        if self['detail'] and not self['json_output']:
275 262
            images = self._add_owner_name(images)
......
622 609

  
623 610

  
624 611
@command(image_cmds)
625
class image_compute_list(_init_cyclades, _optional_json):
612
class image_compute_list(
613
        _init_cyclades, _optional_json, _name_filter, _id_filter):
626 614
    """List images"""
627 615

  
628 616
    PERMANENTS = ('id', 'name')
......
634 622
            'output results in pages (-n to set items per page, default 10)',
635 623
            '--more'),
636 624
        enum=FlagArgument('Enumerate results', '--enumerate'),
637
        name=ValueArgument('filter by name', '--name'),
638
        name_pref=ValueArgument(
639
            'filter by name prefix (case insensitive)',
640
            '--name-prefix'),
641
        name_suff=ValueArgument(
642
            'filter by name suffix (case insensitive)',
643
            '--name-suffix'),
644
        name_like=ValueArgument(
645
            'print only if name contains this (case insensitive)',
646
            '--name-like'),
647 625
        user_id=ValueArgument('filter by user_id', '--user-id'),
648 626
        user_name=ValueArgument('filter by username', '--user-name'),
649 627
        meta=KeyValueArgument(
......
653 631
            ('--metadata-like'))
654 632
    )
655 633

  
656
    def _filtered_by_name(self, images):
657
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
658
        return [img for img in images if (
659
            (not np) or img['name'].lower().startswith(np.lower())) and (
660
            (not ns) or img['name'].lower().endswith(ns.lower())) and (
661
            (not nl) or nl.lower() in img['name'].lower())]
662

  
663 634
    def _filter_by_metadata(self, images):
664 635
        new_images = []
665 636
        for img in images:
......
691 662
        withuser = bool(self['user_id'] or self['user_name'])
692 663
        detail = self['detail'] or withmeta or withuser
693 664
        images = self.client.list_images(detail)
694
        images = self._filtered_by_name(images)
665
        images = self._filter_by_name(images)
666
        images = self._filter_by_id(images)
695 667
        if withuser:
696 668
            images = self._filter_by_user(images)
697 669
        if withmeta:
b/kamaki/cli/commands/pithos.py
46 46
from kamaki.cli.argument import ProgressBarArgument
47 47
from kamaki.cli.commands import _command_init, errors
48 48
from kamaki.cli.commands import addLogSettings, DontRaiseKeyError
49
from kamaki.cli.commands import _optional_output_cmd, _optional_json
49
from kamaki.cli.commands import (
50
    _optional_output_cmd, _optional_json, _name_filter)
50 51
from kamaki.clients.pithos import PithosClient, ClientError
51 52
from kamaki.clients.astakos import AstakosClient
52 53

  
......
326 327

  
327 328

  
328 329
@command(pithos_cmds)
329
class file_list(_file_container_command, _optional_json):
330
class file_list(_file_container_command, _optional_json, _name_filter):
330 331
    """List containers, object trees or objects in a directory
331 332
    Use with:
332 333
    1 no parameters : containers in current account
......
439 440
                if_unmodified_since=self['if_unmodified_since'],
440 441
                until=self['until'],
441 442
                show_only_shared=self['shared'])
442
            self._print(r.json, self.print_containers)
443
            files = self._filter_by_name(r.json)
444
            self._print(files, self.print_containers)
443 445
        else:
444
            prefix = self.path or self['prefix']
446
            prefix = self.path or self['prefix'] or self['name_prefix']
445 447
            r = self.client.container_get(
446 448
                limit=False if self['more'] else self['limit'],
447 449
                marker=self['marker'],
......
453 455
                until=self['until'],
454 456
                meta=self['meta'],
455 457
                show_only_shared=self['shared'])
456
            self._print(r.json, self.print_objects)
458
            files = self._filter_by_name(r.json)
459
            self._print(files, self.print_objects)
457 460

  
458 461
    def main(self, container____path__=None):
459 462
        super(self.__class__, self)._run(container____path__)

Also available in: Unified diff