Revision 7e18cd26
b/docs/developers/clients-api.rst | ||
---|---|---|
225 | 225 |
|
226 | 226 |
user = AstakosClient(AUTHENTICATION_URL, TOKEN) |
227 | 227 |
|
228 |
cyclades_endpoints = user.get_endpoints('compute') |
|
228 |
cyclades_endpoints = user.get_service_endpoints('compute')
|
|
229 | 229 |
CYCLADES_URL = cyclades_endpoints['publicURL'] |
230 | 230 |
cyclades = CycladesClient(CYCLADES_URL, TOKEN) |
231 | 231 |
|
... | ... | |
255 | 255 |
|
256 | 256 |
user = AstakosClient(AUTHENTICATION_URL, TOKEN) |
257 | 257 |
|
258 |
cyclades_endpoints = user.get_endpoints('compute') |
|
258 |
cyclades_endpoints = user.get_service_endpoints('compute')
|
|
259 | 259 |
CYCLADES_URL = cyclades_endpoints['publicURL'] |
260 | 260 |
cyclades = CycladesClient(CYCLADES_URL, TOKEN) |
261 | 261 |
|
... | ... | |
282 | 282 |
astakos = AstakosClient(AUTHENTICATION_URL, TOKEN) |
283 | 283 |
USER_UUID = astakos.user_term('uuid') |
284 | 284 |
|
285 |
PITHOS_URL = astakos.get_endpoints('object-store')['publicURL'] |
|
285 |
PITHOS_URL = astakos.get_service_endpoints('object-store')['publicURL']
|
|
286 | 286 |
pithos = PithosClient(PITHOS_URL, TOKEN, USER_UUID, IMAGE_CONTAINER) |
287 | 287 |
|
288 |
IMAGE_URL = astakos.get_endpoints('image')['publicURL'] |
|
288 |
IMAGE_URL = astakos.get_service_endpoints('image')['publicURL']
|
|
289 | 289 |
plankton = ImageClient(IMAGE_URL, TOKEN) |
290 | 290 |
|
291 | 291 |
for img in pithos.list_objects(): |
b/kamaki/cli/__init__.py | ||
---|---|---|
157 | 157 |
'No commend in %s (acts as cmd description)' % cls.__name__) |
158 | 158 |
_construct_command_syntax(cls) |
159 | 159 |
|
160 |
cmd_tree.add_command(cls_name, cls.description, cls) |
|
160 |
cmd_tree.add_command( |
|
161 |
cls_name, cls.description, cls, cls.long_description) |
|
161 | 162 |
return cls |
162 | 163 |
return wrap |
163 | 164 |
|
b/kamaki/cli/command_tree/__init__.py | ||
---|---|---|
40 | 40 |
subcommands = {} |
41 | 41 |
help = ' ' |
42 | 42 |
|
43 |
def __init__(self, path, help=' ', subcommands={}, cmd_class=None): |
|
43 |
def __init__( |
|
44 |
self, path, |
|
45 |
help=' ', subcommands={}, cmd_class=None, long_help=''): |
|
44 | 46 |
assert path, 'Cannot initialize a command without a command path' |
45 | 47 |
self.path = path |
46 | 48 |
self.help = help or '' |
47 | 49 |
self.subcommands = dict(subcommands) if subcommands else {} |
48 | 50 |
self.cmd_class = cmd_class or None |
51 |
self.long_help = '%s' % (long_help or '') |
|
49 | 52 |
|
50 | 53 |
@property |
51 | 54 |
def name(self): |
... | ... | |
109 | 112 |
|
110 | 113 |
class CommandTree(object): |
111 | 114 |
|
112 |
def __init__(self, name, description=''): |
|
115 |
def __init__(self, name, description='', long_description=''):
|
|
113 | 116 |
self.name = name |
114 | 117 |
self.description = description |
118 |
self.long_description = '%s' % (long_description or '') |
|
115 | 119 |
self.groups = dict() |
116 | 120 |
self._all_commands = dict() |
117 | 121 |
|
... | ... | |
119 | 123 |
for group in groups_to_exclude: |
120 | 124 |
self.groups.pop(group, None) |
121 | 125 |
|
122 |
def add_command(self, command_path, description=None, cmd_class=None): |
|
126 |
def add_command( |
|
127 |
self, command_path, |
|
128 |
description=None, cmd_class=None, long_description=''): |
|
123 | 129 |
terms = command_path.split('_') |
124 | 130 |
try: |
125 | 131 |
cmd = self.groups[terms[0]] |
... | ... | |
139 | 145 |
cmd = new_cmd |
140 | 146 |
cmd.cmd_class = cmd_class or None |
141 | 147 |
cmd.help = description or None |
148 |
cmd.long_help = long_description or cmd.long_help |
|
142 | 149 |
|
143 | 150 |
def find_best_match(self, terms): |
144 | 151 |
"""Find a command that best matches a given list of terms |
b/kamaki/cli/command_tree/test.py | ||
---|---|---|
45 | 45 |
(None, '', 'cmd'), |
46 | 46 |
(None, '', 'Some help'), |
47 | 47 |
(None, '', {}, dict(cmd0a=None, cmd0b=None)), |
48 |
(None, command_tree.Command('cmd_cmd0'))): |
|
49 |
path, help, subcommands, cmd_class = args |
|
48 |
(None, command_tree.Command('cmd_cmd0')), |
|
49 |
(None, 'long description')): |
|
50 |
path, help, subcommands, cmd_class, long_help = args |
|
50 | 51 |
try: |
51 | 52 |
cmd = command_tree.Command(*args) |
52 | 53 |
except Exception as e: |
... | ... | |
57 | 58 |
self.assertEqual(cmd.help, help or '') |
58 | 59 |
self.assertEqual(cmd.subcommands, subcommands or {}) |
59 | 60 |
self.assertEqual(cmd.cmd_class, cmd_class or None) |
61 |
self.assertEqual(cmd.long_help, long_help or '') |
|
60 | 62 |
|
61 | 63 |
def test_name(self): |
62 | 64 |
for path in ('cmd', 'cmd_cmd0', 'cmd_cmd0_cmd1', '', None): |
b/kamaki/cli/commands/image.py | ||
---|---|---|
402 | 402 |
|
403 | 403 |
@command(image_cmds) |
404 | 404 |
class image_register(_init_image, _optional_json): |
405 |
"""(Re)Register an image""" |
|
405 |
"""(Re)Register an image file to an Image service |
|
406 |
The image file must be stored at a pithos repository |
|
407 |
Some metadata can be set by user (e.g. disk-format) while others are set |
|
408 |
only automatically (e.g. image id). There are also some custom user |
|
409 |
metadata, called properties. |
|
410 |
A register command creates a remote meta file at |
|
411 |
<container>:<image path>.meta |
|
412 |
Users may download and edit this file and use it to re-register one or more |
|
413 |
images. |
|
414 |
In case of a meta file, runtime arguments for metadata or properties |
|
415 |
override meta file settings. |
|
416 |
""" |
|
406 | 417 |
|
407 | 418 |
container_info_cache = {} |
408 | 419 |
|
409 | 420 |
arguments = dict( |
410 |
checksum=ValueArgument('set image checksum', '--checksum'),
|
|
421 |
checksum=ValueArgument('Set image checksum', '--checksum'),
|
|
411 | 422 |
container_format=ValueArgument( |
412 |
'set container format',
|
|
423 |
'Set container format',
|
|
413 | 424 |
'--container-format'), |
414 |
disk_format=ValueArgument('set disk format', '--disk-format'),
|
|
415 |
#owner=ValueArgument('set image owner (admin only)', '--owner'),
|
|
425 |
disk_format=ValueArgument('Set disk format', '--disk-format'),
|
|
426 |
owner_name=ValueArgument('Set user uuid by user name', '--owner-name'),
|
|
416 | 427 |
properties=KeyValueArgument( |
417 |
'add property in key=value form (can be repeated)', |
|
428 |
'Add property (user-specified metadata) in key=value form' |
|
429 |
'(can be repeated)', |
|
418 | 430 |
('-p', '--property')), |
419 |
is_public=FlagArgument('mark image as public', '--public'),
|
|
420 |
size=IntArgument('set image size', '--size'),
|
|
431 |
is_public=FlagArgument('Mark image as public', '--public'),
|
|
432 |
size=IntArgument('Set image size in bytes', '--size'),
|
|
421 | 433 |
metafile=ValueArgument( |
422 | 434 |
'Load metadata from a json-formated file <img-file>.meta :' |
423 | 435 |
'{"key1": "val1", "key2": "val2", ..., "properties: {...}"}', |
424 | 436 |
('--metafile')), |
425 | 437 |
metafile_force=FlagArgument( |
426 |
'Store remote metadata object, even if it already exists', |
|
427 |
('-f', '--force')), |
|
438 |
'Overide remote metadata file', ('-f', '--force')), |
|
428 | 439 |
no_metafile_upload=FlagArgument( |
429 | 440 |
'Do not store metadata in remote meta file', |
430 | 441 |
('--no-metafile-upload')), |
... | ... | |
511 | 522 |
'No image file location provided', |
512 | 523 |
importance=2, details=[ |
513 | 524 |
'An image location is needed. Image location format:', |
514 |
' pithos://<user-id>/<container>/<path>',
|
|
525 |
' <container>:<path>',
|
|
515 | 526 |
' where an image file at the above location must exist.' |
516 | 527 |
] + howto_image_file) |
517 | 528 |
try: |
... | ... | |
521 | 532 |
ae, 'Invalid image location format', |
522 | 533 |
importance=1, details=[ |
523 | 534 |
'Valid image location format:', |
524 |
' pithos://<user-id>/<container>/<img-file-path>'
|
|
535 |
' <container>:<img-file-path>'
|
|
525 | 536 |
] + howto_image_file) |
526 | 537 |
|
538 |
@staticmethod |
|
539 |
def _old_location_format(location): |
|
540 |
prefix = 'pithos://' |
|
541 |
try: |
|
542 |
if location.startswith(prefix): |
|
543 |
uuid, sep, rest = location[len(prefix):].partition('/') |
|
544 |
container, sep, path = rest.partition('/') |
|
545 |
return (uuid, container, path) |
|
546 |
except Exception as e: |
|
547 |
raiseCLIError(e, 'Invalid location format', details=[ |
|
548 |
'Correct location format:', ' <container>:<image path>']) |
|
549 |
return () |
|
550 |
|
|
527 | 551 |
def _mine_location(self, container_path): |
528 |
uuid = self['uuid'] or self._get_user_id() |
|
552 |
old_response = self._old_location_format(container_path) |
|
553 |
if old_response: |
|
554 |
return old_response |
|
555 |
uuid = self['uuid'] or (self._username2uuid(self['owner_name']) if ( |
|
556 |
self['owner_name']) else self._get_user_id()) |
|
557 |
if not uuid: |
|
558 |
if self['owner_name']: |
|
559 |
raiseCLIError('No user with username %s' % self['owner_name']) |
|
560 |
raiseCLIError('Failed to get user uuid', details=[ |
|
561 |
'For details on current user:', |
|
562 |
' /user whoami', |
|
563 |
'To authenticate a new user through a user token:', |
|
564 |
' /user authenticate <token>']) |
|
529 | 565 |
if self['container']: |
530 | 566 |
return uuid, self['container'], container_path |
531 | 567 |
container, sep, path = container_path.partition(':') |
b/kamaki/cli/one_command.py | ||
---|---|---|
92 | 92 |
|
93 | 93 |
if _help or not cmd.is_command: |
94 | 94 |
parser.parser.print_help() |
95 |
if getattr(cmd, 'long_help', False): |
|
96 |
print 'Details:\n', cmd.long_help |
|
95 | 97 |
print_subcommands_help(cmd) |
96 | 98 |
exit(0) |
97 | 99 |
|
b/kamaki/clients/__init__.py | ||
---|---|---|
122 | 122 |
url += _encode(path[1:] if path.startswith('/') else path) |
123 | 123 |
delim = '?' |
124 | 124 |
for key, val in params.items(): |
125 |
val = _encode(val) |
|
125 |
val = _encode(u'%s' % val)
|
|
126 | 126 |
url += '%s%s%s' % (delim, key, ('=%s' % val) if val else '') |
127 | 127 |
delim = '&' |
128 | 128 |
parsed = urlparse(url) |
b/kamaki/clients/astakos/__init__.py | ||
---|---|---|
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 | 34 |
from logging import getLogger |
35 |
from json import dumps |
|
36 | 35 |
|
37 | 36 |
from kamaki.clients import Client, ClientError |
38 |
from kamaki.clients.utils import path4url |
|
39 | 37 |
|
40 | 38 |
|
41 | 39 |
class AstakosClient(Client): |
Also available in: Unified diff