Commit 00336c85 authored by Stavros Sachtouris's avatar Stavros Sachtouris
Browse files

Store image properties after image registration

Log of changes:
- Properties are stored in a remote file on Pithos+
- File name is <image-file>.meta
- Feature can be switched off with --no-property-file-upload
- If remote property file exists, registration is aborted
- If remote property file exists, force with -f, --fforce-upload-property-file
- Location is given as container:path
- User id can be aquired internaly with an astakos call

Refs: #3769, #3778
parent 623a4ceb
...@@ -54,4 +54,7 @@ Features: ...@@ -54,4 +54,7 @@ Features:
- Add a download_to_string method in pithos client [#3608] - Add a download_to_string method in pithos client [#3608]
- Add an upload_from_string method in pithos client [#3608] - Add an upload_from_string method in pithos client [#3608]
- Add pithos client method create_container [#3756] - Add pithos client method create_container [#3756]
- Store image properties on remote location after image registration [#3769]
- Add runtime args to image register for forcing or unsettitng property
storage [#3769]
...@@ -39,10 +39,14 @@ from kamaki.cli import command ...@@ -39,10 +39,14 @@ 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, print_items, print_json from kamaki.cli.utils import print_dict, print_items, print_json
from kamaki.clients.image import ImageClient from kamaki.clients.image import ImageClient
from kamaki.clients.pithos import PithosClient
from kamaki.clients.astakos import AstakosClient
from kamaki.clients import ClientError
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
from kamaki.cli.argument import IntArgument from kamaki.cli.argument import IntArgument
from kamaki.cli.commands.cyclades import _init_cyclades from kamaki.cli.commands.cyclades import _init_cyclades
from kamaki.cli.commands import _command_init, errors, _optional_output_cmd from kamaki.cli.commands import _command_init, errors, _optional_output_cmd
from kamaki.cli.errors import raiseCLIError
image_cmds = CommandTree( image_cmds = CommandTree(
...@@ -262,26 +266,77 @@ class image_register(_init_image): ...@@ -262,26 +266,77 @@ class image_register(_init_image):
# ('-u', '--update')), # ('-u', '--update')),
json_output=FlagArgument('Show results in json', ('-j', '--json')), json_output=FlagArgument('Show results in json', ('-j', '--json')),
property_file=ValueArgument( property_file=ValueArgument(
'Load properties from a json-formated file. Contents:' 'Load properties from a json-formated file <img-file>.meta :'
'{"key1": "val1", "key2": "val2", ...}', '{"key1": "val1", "key2": "val2", ...}',
('--property-file')) ('--property-file')),
prop_file_force=FlagArgument(
'Store remote property object, even it already exists',
('-f', '--force-upload-property-file')),
no_prop_file_upload=FlagArgument(
'Do not store properties in remote property file',
('--no-property-file-upload')),
container=ValueArgument(
'Remote image container', ('-C', '--container')),
fileowner=ValueArgument(
'UUID of the user who owns the image file', ('--fileowner'))
) )
def _get_uuid(self):
uuid = self['fileowner'] or self.config.get('image', 'fileowner')
if uuid:
return uuid
atoken = self.client.token
user = AstakosClient(self.config.get('user', 'url'), atoken)
return user.term('uuid')
def _get_pithos_client(self, uuid, container):
purl = self.config.get('file', 'url')
ptoken = self.client.token
return PithosClient(purl, ptoken, uuid, container)
def _store_remote_property_file(self, pclient, remote_path, properties):
return pclient.upload_from_string(
remote_path, _validate_image_props(properties, return_str=True))
def _get_container_path(self, container_path):
container = self['container'] or self.config.get('image', 'container')
if container:
return container, container_path
container, sep, path = container_path.partition(':')
if not sep or not container or not path:
raiseCLIError(
'%s is not a valid pithos remote location' % container_path,
details=[
'To set "image" as container and "my_dir/img.diskdump" as',
'the image path, try one of the following as '
'container:path',
'- <image container>:<remote path>',
' e.g. image:/my_dir/img.diskdump',
'- <remote path> -C <image container>',
' e.g. /my_dir/img.diskdump -C image'])
return container, path
@errors.generic.all @errors.generic.all
@errors.plankton.connection @errors.plankton.connection
def _run(self, name, location): def _run(self, name, container_path):
if not location.startswith('pithos://'): container, path = self._get_container_path(container_path)
account = self.config.get('file', 'account') \ uuid = self._get_uuid()
or self.config.get('global', 'account') prop_path = '%s.meta' % path
assert account, 'No user account provided'
if account[-1] == '/': pclient = None if (
account = account[:-1] self['no_prop_file_upload']) else self._get_pithos_client(
container = self.config.get('file', 'container') \ uuid, container)
or self.config.get('global', 'container') if pclient and not self['prop_file_force']:
if not container: try:
location = 'pithos://%s/%s' % (account, location) pclient.get_object_info(prop_path)
else: raiseCLIError('Property file %s: %s already exists' % (
location = 'pithos://%s/%s/%s' % (account, container, location) container, prop_path))
except ClientError as ce:
if ce.status != 404:
raise
location = 'pithos://%s/%s/%s' % (uuid, container, path)
params = {} params = {}
for key in set([ for key in set([
...@@ -301,9 +356,15 @@ class image_register(_init_image): ...@@ -301,9 +356,15 @@ class image_register(_init_image):
printer = print_json if self['json_output'] else print_dict printer = print_json if self['json_output'] else print_dict
printer(self.client.register(name, location, params, properties)) printer(self.client.register(name, location, params, properties))
def main(self, name, location): if pclient:
prop_headers = pclient.upload_from_string(
prop_path, _validate_image_props(properties, return_str=True))
print('Property file location is %s: %s' % (container, prop_path))
print('\twith version %s' % prop_headers['x-object-version'])
def main(self, name, container___path):
super(self.__class__, self)._run() super(self.__class__, self)._run()
self._run(name, location) self._run(name, container___path)
@command(image_cmds) @command(image_cmds)
......
...@@ -1645,7 +1645,7 @@ class file_permissions_set(_file_container_command, _optional_output_cmd): ...@@ -1645,7 +1645,7 @@ class file_permissions_set(_file_container_command, _optional_output_cmd):
""" """
@errors.generic.all @errors.generic.all
def format_permition_dict(self, permissions): def format_permission_dict(self, permissions):
read = False read = False
write = False write = False
for perms in permissions: for perms in permissions:
...@@ -1666,13 +1666,13 @@ class file_permissions_set(_file_container_command, _optional_output_cmd): ...@@ -1666,13 +1666,13 @@ class file_permissions_set(_file_container_command, _optional_output_cmd):
def _run(self, read, write): def _run(self, read, write):
self._optional_output(self.client.set_object_sharing( self._optional_output(self.client.set_object_sharing(
self.path, self.path,
read_permition=read, write_permition=write)) read_permission=read, write_permission=write))
def main(self, container___path, *permissions): def main(self, container___path, *permissions):
super(self.__class__, self)._run( super(self.__class__, self)._run(
container___path, container___path,
path_is_optional=False) path_is_optional=False)
(read, write) = self.format_permition_dict(permissions) (read, write) = self.format_permission_dict(permissions)
self._run(read, write) self._run(read, write)
......
...@@ -1236,23 +1236,23 @@ class PithosClient(PithosRestClient): ...@@ -1236,23 +1236,23 @@ class PithosClient(PithosRestClient):
def set_object_sharing( def set_object_sharing(
self, obj, self, obj,
read_permition=False, write_permition=False): read_permission=False, write_permission=False):
"""Give read/write permisions to an object. """Give read/write permisions to an object.
:param obj: (str) remote object path :param obj: (str) remote object path
:param read_permition: (list - bool) users and user groups that get :param read_permission: (list - bool) users and user groups that get
read permition for this object - False means all previous read read permission for this object - False means all previous read
permissions will be removed permissions will be removed
:param write_perimition: (list - bool) of users and user groups to get :param write_permission: (list - bool) of users and user groups to get
write permition for this object - False means all previous write write permission for this object - False means all previous write
permissions will be removed permissions will be removed
:returns: (dict) response headers :returns: (dict) response headers
""" """
perms = dict(read=read_permition or '', write=write_permition or '') perms = dict(read=read_permission or '', write=write_permission or '')
r = self.object_post(obj, update=True, permissions=perms) r = self.object_post(obj, update=True, permissions=perms)
return r.headers return r.headers
......
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