Commit 58863f91 authored by Giorgos Korfiatis's avatar Giorgos Korfiatis

Merge branch 'develop' into feature-quotas

Conflicts:
	astakosclient/astakosclient/__init__.py
	astakosclient/astakosclient/errors.py
	astakosclient/astakosclient/tests.py
	docs/index.rst
parents a6855022 cde1fb80
......@@ -47,7 +47,7 @@ intersphinx_mapping = {
'https://docs.djangoproject.com/en/dev/_objects/')
}
SYNNEFO_DOCS_BASE_URL = 'http://docs.dev.grnet.gr/'
SYNNEFO_DOCS_BASE_URL = 'http://www.synnefo.org/docs'
SYNNEFO_PROJECTS = {
'synnefo': 'dev',
'pithos': 'dev',
......
......@@ -187,7 +187,7 @@ setup(
package_data=find_package_data('.'),
zip_safe=False,
dependency_links=['http://docs.dev.grnet.gr/pypi/'],
dependency_links=['http://www.synnefo.org/packages/pypi'],
install_requires=INSTALL_REQUIRES,
extras_require=EXTRAS_REQUIRES,
......
......@@ -834,7 +834,7 @@ The "kamaki" API client
To upload, register or modify an image you will need the **kamaki** tool.
Before proceeding make sure that it is configured properly. Verify that
*image_url*, *storage_url*, and *token* are set as needed:
*image.url*, *file.url*, *user.url* and *token* are set as needed:
.. code-block:: console
......@@ -844,39 +844,53 @@ To chage a setting use ``kamaki config set``:
.. code-block:: console
$ kamaki config set image_url https://cyclades.example.com/plankton
$ kamaki config set storage_url https://pithos.example.com/v1
$ kamaki config set image.url https://cyclades.example.com/plankton
$ kamaki config set file.url https://pithos.example.com/v1
$ kamaki config set user.url https://accounts.example.com
$ kamaki config set token ...
To test that everything works, try authenticating the current account with
kamaki:
.. code-block:: console
$ kamaki user authenticate
This will output user information.
Upload Image
------------
As a shortcut, you can configure a default account and container that will be
used by the ``kamaki store`` commands:
By convention, images are stored in a container called ``images``. Check if the
container exists, by listing all containers in your account:
.. code-block:: console
$ kamaki config set storage_account images@example.com
$ kamaki config set storage_container images
$ kamaki file list
If the container does not exist, you will have to create it before uploading
any images:
If the container ``images`` does not exist, create it:
.. code-block:: console
$ kamaki store create images
$ kamaki file create images
You are now ready to upload an image. You can upload it with a Pithos+ client,
or use kamaki directly:
You are now ready to upload an image to container ``images``. You can upload it
with a Pithos+ client, or use kamaki directly:
.. code-block:: console
$ kamaki store upload ubuntu.iso
$ kamaki file upload ubuntu.iso images
You can use any Pithos+ client to verify that the image was uploaded correctly.
The full Pithos URL for the previous example will be
``pithos://images@example.com/images/ubuntu.iso``.
You can use any Pithos+ client to verify that the image was uploaded correctly,
or you can list the contents of the container with kamaki:
.. code-block:: console
$ kamaki file list images
The full Pithos URL for the previous example will be
``pithos://u53r-un1qu3-1d/images/ubuntu.iso`` where ``u53r-un1qu3-1d`` is the
unique user id (uuid).
Register Image
--------------
......@@ -886,25 +900,24 @@ a public image the one from the previous example use:
.. code-block:: console
$ kamaki glance register Ubuntu pithos://images@example.com/images/ubuntu.iso --public
$ kamaki image register Ubuntu pithos://u53r-un1qu3-1d/images/ubuntu.iso --public
The ``--public`` flag is important, if missing the registered image will not
be listed by ``kamaki glance list``.
be listed by ``kamaki image list``.
Use ``kamaki glance register`` with no arguments to see a list of available
Use ``kamaki image register`` with no arguments to see a list of available
options. A more complete example would be the following:
.. code-block:: console
$ kamaki glance register Ubuntu pithos://images@example.com/images/ubuntu.iso \
$ kamaki image register Ubuntu pithos://u53r-un1qu3-1d/images/ubuntu.iso \
--public --disk-format diskdump --property kernel=3.1.2
To verify that the image was registered successfully use:
.. code-block:: console
$ kamaki glance list -l
$ kamaki image list --name-like=ubuntu
Miscellaneous
......
......@@ -46,7 +46,7 @@ intersphinx_mapping = {
'https://docs.djangoproject.com/en/dev/_objects/')
}
SYNNEFO_DOCS_BASE_URL = 'http://docs.dev.grnet.gr/'
SYNNEFO_DOCS_BASE_URL = 'http://www.synnefo.org/docs'
SYNNEFO_PROJECTS = {
'synnefo': 'dev',
'pithos': 'dev',
......
......@@ -8,9 +8,9 @@ API Guide
This is the guide to the REST API of the synnefo Compute Service.
It is meant for users wishing to make calls to the REST API directly.
The :ref:`kamaki <http://docs.dev.grnet.gr/kamaki>` command-line client
and associated python library can be used instead of making direct calls to
:ref:`cyclades <cyclades>`.
The `kamaki <http://www.synnefo.org/docs/kamaki/latest/index.html>`_
command-line client and associated python library can be used instead of making
direct calls to :ref:`cyclades <cyclades>`.
Overview
========
......
......@@ -31,9 +31,9 @@ There are also the following tools:
.. toctree::
:maxdepth: 1
kamaki: Command-line client <http://docs.dev.grnet.gr/kamaki/latest/index.html>
kamaki: Command-line client <http://www.synnefo.org/docs/kamaki/latest/index.html>
snf-deploy: Synnefo deployment tool <snf-deploy>
snf-image-creator: Image bundling/uploading/registering tool <http://docs.dev.grnet.gr/snf-image-creator/latest/index.html>
snf-image-creator: Image bundling/uploading/registering tool <http://www.synnefo.org/docs/snf-image-creator/latest/index.html>
snf-image: Secure image deployment tool <snf-image>
snf-burnin: Integration testing tool for a running Synnefo deployment <snf-burnin>
......@@ -115,20 +115,20 @@ List of all Synnefo components
They are also available from our apt repository: ``apt.okeanos.grnet.gr``
* `snf-common <http://docs.dev.grnet.gr/snf-common/latest/index.html>`_
* `snf-webproject <http://docs.dev.grnet.gr/snf-webproject/latest/index.html>`_
* `snf-astakos-app <http://docs.dev.grnet.gr/astakos/latest/index.html>`_
* `snf-pithos-backend <http://docs.dev.grnet.gr/pithos/latest/backends.html>`_
* `snf-pithos-app <http://docs.dev.grnet.gr/pithos/latest/index.html>`_
* `snf-pithos-webclient <http://docs.dev.grnet.gr/pithos-webclient/latest/index.html>`_
* `snf-cyclades-app <http://docs.dev.grnet.gr/snf-cyclades-app/latest/index.html>`_
* `snf-cyclades-gtools <http://docs.dev.grnet.gr/snf-cyclades-gtools/latest/index.html>`_
* `astakosclient <http://docs.dev.grnet.gr/astakosclient/latest/index.html>`_
* `snf-common <http://www.synnefo.org/docs/snf-common/latest/index.html>`_
* `snf-webproject <http://www.synnefo.org/docs/snf-webproject/latest/index.html>`_
* `snf-astakos-app <http://www.synnefo.org/docs/astakos/latest/index.html>`_
* `snf-pithos-backend <http://www.synnefo.org/docs/pithos/latest/backends.html>`_
* `snf-pithos-app <http://www.synnefo.org/docs/pithos/latest/index.html>`_
* `snf-pithos-webclient <http://www.synnefo.org/docs/pithos-webclient/latest/index.html>`_
* `snf-cyclades-app <http://www.synnefo.org/docs/snf-cyclades-app/latest/index.html>`_
* `snf-cyclades-gtools <http://www.synnefo.org/docs/snf-cyclades-gtools/latest/index.html>`_
* `astakosclient <http://www.synnefo.org/docs/astakosclient/latest/index.html>`_
* `snf-vncauthproxy <https://code.grnet.gr/projects/vncauthproxy>`_
* `snf-image <https://code.grnet.gr/projects/snf-image/wiki/>`_
* `snf-image-creator <http://docs.dev.grnet.gr/snf-image-creator/latest/index.html>`_
* `snf-occi <http://docs.dev.grnet.gr/snf-occi/latest/index.html>`_
* `snf-cloudcms <http://docs.dev.grnet.gr/snf-cloudcms/latest/index.html>`_
* `snf-image-creator <http://www.synnefo.org/docs/snf-image-creator/latest/index.html>`_
* `snf-occi <http://www.synnefo.org/docs/snf-occi/latest/index.html>`_
* `snf-cloudcms <http://www.synnefo.org/docs/snf-cloudcms/latest/index.html>`_
* `nfdhcpd <https://code.grnet.gr/projects/nfdhcpd>`_
......
......@@ -3,8 +3,8 @@ Changelog
v0.14.0
------
(* Unreleased *)
* settings *PITHOS_BACKEND_POOL_SIZE*
* new settings *PITHOS_BACKEND_POOL_SIZE*, *PITHOS_BACKEND_ACCOUNT_QUOTA*, *PITHOS_BACKEND_CONTAINER_QUOTA*
* setting *PITHOS_BACKEND_QUOTA* is substituted by the setting *PITHOS_BACKEND_ACCOUNT_QUOTA*
* setting *PITHOS_UPDATE_MD5* is set to False by default
* Remove PITHOS_AUTHENTICATION_USERS setting
......
......@@ -364,4 +364,4 @@ The code can also be accessed from its source repository:
https://code.grnet.gr/git/pithos/
More information and documentation is available at:
http://docs.dev.grnet.gr/pithos/latest/index.html
http://www.synnefo.org/docs/pithos/latest/index.html
......@@ -58,9 +58,8 @@ and are related to all the services (Astakos, Pithos+, Cyclades, Plankton).
To be able to download all synnefo components you need to add the following
lines in your ``/etc/apt/sources.list`` file:
| ``deb http://apt.dev.grnet.gr squeeze main``
| ``deb-src http://apt.dev.grnet.gr squeeze main``
| ``deb http://apt.dev.grnet.gr squeeze-backports main``
| ``deb http://apt2.dev.grnet.gr stable/``
| ``deb-src http://apt2.dev.grnet.gr stable/``
and import the repo's GPG key:
......@@ -848,12 +847,11 @@ this options:
.. code-block:: console
PITHOS_BACKEND_DB_CONNECTION = 'postgresql://synnefo:example_passw0rd@node1.example.com:5432/snf_pithos'
ASTAKOS_URL = 'https://node1.example.com/'
PITHOS_BACKEND_DB_CONNECTION = 'postgresql://synnefo:example_passw0rd@node1.example.com:5432/snf_pithos'
PITHOS_BACKEND_BLOCK_PATH = '/srv/pithos/data'
PITHOS_AUTHENTICATION_URL = 'https://node1.example.com/im/authenticate'
PITHOS_AUTHENTICATION_USERS = None
PITHOS_SERVICE_TOKEN = 'pithos_service_token22w=='
PITHOS_USER_CATALOG_URL = 'https://node1.example.com/user_catalogs'
......@@ -879,9 +877,8 @@ the pithos+ backend data. Above we tell pithos+ to store its data under
``/srv/pithos/data``, which is visible by both nodes. We have already setup this
directory at node1's "Pithos+ data directory setup" section.
The ``PITHOS_AUTHENTICATION_URL`` option tells to the pithos+ app in which URI
is available the astakos authentication api. If not set, pithos+ tries to
authenticate using the ``PITHOS_AUTHENTICATION_USERS`` user pool.
The ``ASTAKOS_URL`` option tells to the pithos+ app in which URI
is available the astakos authentication api.
The ``PITHOS_SERVICE_TOKEN`` should be the Pithos+ token returned by running on
the Astakos node (node1 in our case):
......@@ -1240,7 +1237,7 @@ a) Download the Image from the official snf-image page.
b) Upload the Image to your Pithos+ installation, either using the Pithos+ Web
UI or the command line client `kamaki
<http://docs.dev.grnet.gr/kamaki/latest/index.html>`_.
<http://www.synnefo.org/docs/kamaki/latest/index.html>`_.
Once the Image is uploaded successfully, download the Image's metadata file
from the official snf-image page. You will need it, for spawning a VM from
......@@ -1706,14 +1703,14 @@ Edit ``/etc/synnefo/20-snf-cyclades-app-api.conf``:
.. code-block:: console
ASTAKOS_URL = 'https://node1.example.com/im/authenticate'
ASTAKOS_URL = 'https://node1.example.com/'
# Set to False if astakos & cyclades are on the same host
CYCLADES_PROXY_USER_SERVICES = False
The ``ASTAKOS_URL`` denotes the authentication endpoint for Cyclades and is set
to point to Astakos (this should have the same value with Pithos+'s
``PITHOS_AUTHENTICATION_URL``, setup :ref:`previously <conf-pithos>`).
``ASTAKOS_URL``, setup :ref:`previously <conf-pithos>`).
.. warning::
......@@ -2060,7 +2057,7 @@ steps, even though you may already have uploaded an Image on Pithos+ from a
* Register that Image file to Plankton
* Spawn a new VM from that Image from the Cyclades Web UI
We will use the `kamaki <http://docs.dev.grnet.gr/kamaki/latest/index.html>`_
We will use the `kamaki <http://www.synnefo.org/docs/kamaki/latest/index.html>`_
command line client to do the uploading and registering of the Image.
Installation of `kamaki`
......@@ -2085,27 +2082,31 @@ installation. We do this by running:
.. code-block:: console
$ kamaki config set astakos.url "https://node1.example.com"
$ kamaki config set user.url "https://node1.example.com"
$ kamaki config set compute.url "https://node1.example.com/api/v1.1"
$ kamaki config set image.url "https://node1.example.com/plankton"
$ kamaki config set store.url "https://node2.example.com/v1"
$ kamaki config set global.account "user@example.com"
$ kamaki config set store.enable on
$ kamaki config set store.pithos_extensions on
$ kamaki config set store.url "https://node2.example.com/v1"
$ kamaki config set store.account USER_UUID
$ kamaki config set global.token USER_TOKEN
$ kamaki config set file.url "https://node2.example.com/v1"
$ kamaki config set token USER_TOKEN
The USER_TOKEN and USER_UUID appear on the user's (``user@example.com``)
`Profile` web page on the Astakos Web UI.
The USER_TOKEN appears on the user's `Profile` web page on the Astakos Web UI.
You can see that the new configuration options have been applied correctly, by
running:
You can see that the new configuration options have been applied correctly,
either by checking the editable file ``~/.kamakirc`` or by running:
.. code-block:: console
$ kamaki config list
A quick test to check that kamaki is configured correctly, is to try to
authenticate a user based on his/her token (in this case the user is you):
.. code-block:: console
$ kamaki user authenticate
The above operation provides various user information, e.g. UUID (the unique
user id) which might prove useful in some operations.
Upload an Image file to Pithos+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -2125,30 +2126,43 @@ We create the new ``images`` container by running:
.. code-block:: console
$ kamaki store create images
$ kamaki file create images
To check if the container has been created, list all containers of your
account:
.. code-block:: console
$ kamaki file list
Then, we upload the Image file to that container:
.. code-block:: console
$ kamaki store upload --container images \
/srv/images/debian_base-6.0-7-x86_64.diskdump \
debian_base-6.0-7-x86_64.diskdump
$ kamaki file upload /srv/images/debian_base-6.0-7-x86_64.diskdump images
The first is the local path and the second is the remote container on Pithos+.
Check if the file has been uploaded, by listing the container contents:
.. code-block:: console
$ kamaki file list images
The first is the local path and the second is the remote path on Pithos+. If
the new container and the file appears on the Pithos+ Web UI, then you have
successfully created the container and uploaded the Image file.
Alternatively check if the new container and file appear on the Pithos+ Web UI.
Register an existing Image file to Plankton
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once the Image file has been successfully uploaded on Pithos+, then we register
For the purposes of the following example, we assume that the user UUID is
``u53r-un1qu3-1d``.
Once the Image file has been successfully uploaded on Pithos+ then we register
it to Plankton (so that it becomes visible to Cyclades), by running:
.. code-block:: console
$ kamaki image register "Debian Base" \
pithos://USER_UUID/images/debian_base-6.0-7-x86_64.diskdump \
pithos://u53r-un1qu3-1d/images/debian_base-6.0-7-x86_64.diskdump \
--public \
--disk-format=diskdump \
--property OSFAMILY=linux --property ROOT_PARTITION=1 \
......@@ -2157,7 +2171,7 @@ it to Plankton (so that it becomes visible to Cyclades), by running:
--property sortorder=1 --property USERS=root --property OS=debian
This command registers the Pithos+ file
``pithos://user@example.com/images/debian_base-6.0-7-x86_64.diskdump`` as an
``pithos://u53r-un1qu3-1d/images/debian_base-6.0-7-x86_64.diskdump`` as an
Image in Plankton. This Image will be public (``--public``), so all users will
be able to spawn VMs from it and is of type ``diskdump``. The first two
properties (``OSFAMILY`` and ``ROOT_PARTITION``) are mandatory. All the rest
......
......@@ -29,10 +29,8 @@ lines in `/etc/apt/sources.list.d/synnefo.list` file:
.. code-block:: console
deb http://apt.dev.grnet.gr squeeze main
deb-src http://apt.dev.grnet.gr squeeze main
deb http://apt.dev.grnet.gr squeeze-backports main
deb-src http://apt.dev.grnet.gr squeeze-backports main
deb http://apt2.dev.grnet.gr stable/
deb-src http://apt2.dev.grnet.gr stable/
deb http://backports.debian.org/debian-backports squeeze-backports main
deb http://www.rabbitmq.com/debian/ testing main
......
......@@ -59,7 +59,7 @@ In `/etc/synnefo/cyclades.conf` add:
GANETI_DISK_TEMPLATES = ('blockdev', 'diskless', 'drbd', 'file', 'plain',
'rbd', 'sharedfile', 'ext')
ASTAKOS_URL = 'https://accounts.example.com/im/authenticate'
ASTAKOS_URL = 'https://accounts.example.com/'
SECRET_ENCRYPTION_KEY= "oEs0pt7Di1mkxA0P6FiK"
......
......@@ -57,15 +57,14 @@ In `/etc/synnefo/pithos.conf` add:
.. code-block:: console
PITHOS_AUTHENTICATION_URL = 'https:/accounts.example.com/im/authenticate'
PITHOS_AUTHENTICATION_USERS = None
ASTAKOS_URL = 'https:/accounts.example.com/'
PITHOS_USER_CATALOG_URL = 'https://accounts.example.com/user_catalogs'
PITHOS_USER_FEEDBACK_URL = 'https://accounts.example.com/feedback'
PITHOS_USER_LOGIN_URL = 'https://accounts.example.com/login'
PITHOS_BACKEND_DB_CONNECTION = 'postgresql://synnefo:example_passw0rd@db.example.com:5432/snf_pithos'
PITHOS_BACKEND_BLOCK_PATH = '/srv/pithos/data'
PITHOS_BACKEND_QUOTA = 20 * 1024 * 1024 * 1024
PITHOS_BACKEND_ACCOUNT_QUOTA = 20 * 1024 * 1024 * 1024
PITHOS_UPDATE_MD5 = False
PITHOS_SERVICE_TOKEN = 'XXXXXXXXXXX'
......
......@@ -285,7 +285,7 @@ On the Pithos host, edit ``/etc/synnefo/20-snf-pithos-app-settings.conf``:
RewriteRule ^/login(.*) /im/login/redirect$1 [PT,NE]
(see `<http://docs.dev.grnet.gr/synnefo/latest/quick-install-admin-guide.html#apache2-setup>`_)
(see `<http://www.synnefo.org/docs/synnefo/latest/quick-install-admin-guide.html#apache2-setup>`_)
- Enable users to change their contact email. Edit
``/etc/synnefo/20-snf-astakos-app-settings.conf`` ::
......
......@@ -72,7 +72,8 @@ $(document).ready(function() {
// prevent extra actions if it is checked
if ( $(this).hasClass('selected')){
group_form_toggle_resources($(this));
e.preventDefault();
//group_form_toggle_resources($(this));
} else {
// show the relevant fieldsets
......
......@@ -174,6 +174,6 @@
<a href="{% url project_list %}">&lt; Back to Projects</a>
</p>
</div>
</div>
{% endwith %}
{% endblock %}
......@@ -46,7 +46,7 @@ intersphinx_mapping = {
'https://docs.djangoproject.com/en/dev/_objects/')
}
SYNNEFO_DOCS_BASE_URL = 'http://docs.dev.grnet.gr/'
SYNNEFO_DOCS_BASE_URL = 'http://www.synnefo.org/docs'
SYNNEFO_PROJECTS = {
'synnefo': 'dev',
'pithos': 'dev',
......
......@@ -39,7 +39,7 @@ from time import sleep
import logging
import socket
from synnefo import settings
from ordereddict import OrderedDict
from synnefo.lib.ordereddict import OrderedDict
import gevent
from gevent import monkey
from functools import wraps
......
......@@ -49,7 +49,7 @@ from socket import error as socket_error
from time import sleep
from random import shuffle
from functools import wraps
from ordereddict import OrderedDict
from synnefo.lib.ordereddict import OrderedDict
from synnefo import settings
......
......@@ -110,7 +110,7 @@
#DEFAULT_GANETI_DISK_TEMPLATE = 'drbd'
#
## The URL of an astakos instance that will be used for user authentication
#ASTAKOS_URL = 'https://astakos.okeanos.grnet.gr/im/authenticate'
#ASTAKOS_URL = 'https://accounts.example.org/'
#
## Key for password encryption-decryption. After changing this setting, synnefo
## will be unable to decrypt all existing Backend passwords. You will need to
......
......@@ -46,7 +46,7 @@ intersphinx_mapping = {
'https://docs.djangoproject.com/en/dev/_objects/')
}
SYNNEFO_DOCS_BASE_URL = 'http://docs.dev.grnet.gr/'
SYNNEFO_DOCS_BASE_URL = 'http://www.synnefo.org/docs'
SYNNEFO_PROJECTS = {
'synnefo': 'dev',
'pithos': 'dev',
......
......@@ -44,7 +44,7 @@ or request a specific version as ``snf-cyclades-app==x.y.z``.
.. code-block:: console
$ pip install snf-cyclades-app -f https://docs.dev.grnet.gr/pypi
$ pip install snf-cyclades-app -f https://www.synnefo.org/packages/pypi
On Debian Squeeze, install the ``snf-cyclades-app`` Debian package.
......
......@@ -32,6 +32,7 @@
# or implied, of GRNET S.A.
from logging import getLogger
from itertools import ifilter
from dateutil.parser import parse as date_parse
......@@ -118,18 +119,14 @@ def list_images(request, detail=False):
# overLimit (413)
log.debug('list_images detail=%s', detail)
since = utils.isoparse(request.GET.get('changes-since'))
with image_backend(request.user_uniq) as backend:
since = utils.isoparse(request.GET.get('changes-since'))
images = backend.list_images()
if since:
images = []
for image in backend.iter():
updated = date_parse(image['updated_at'])
if updated >= since:
images.append(image)
updated_since = lambda img: date_parse(img["updated_at"]) >= since
images = ifilter(updated_since, images)
if not images:
return HttpResponse(status=304)
else:
images = backend.list()
images = sorted(images, key=lambda x: x['id'])
reply = [image_to_dict(image, detail) for image in images]
......@@ -172,7 +169,8 @@ def get_image_details(request, image_id):
# overLimit (413)
log.debug('get_image_details %s', image_id)
image = util.get_image(image_id, request.user_uniq)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
reply = image_to_dict(image)
if request.serialization == 'xml':
......@@ -209,7 +207,8 @@ def list_metadata(request, image_id):
# overLimit (413)
log.debug('list_image_metadata %s', image_id)
image = util.get_image(image_id, request.user_uniq)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
metadata = image['properties']
return util.render_metadata(request, metadata, use_values=True, status=200)
......@@ -227,18 +226,18 @@ def update_metadata(request, image_id):
req = utils.get_request_dict(request)
log.info('update_image_metadata %s %s', image_id, req)
image = util.get_image(image_id, request.user_uniq)
try:
metadata = req['metadata']
assert isinstance(metadata, dict)
except (KeyError, AssertionError):
raise faults.BadRequest('Malformed request.')
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
try:
metadata = req['metadata']
assert isinstance(metadata, dict)
except (KeyError, AssertionError):
raise faults.BadRequest('Malformed request.')
properties = image['properties']
properties.update(metadata)
properties = image['properties']
properties.update(metadata)
with image_backend(request.user_uniq) as backend:
backend.update(image_id, dict(properties=properties))
backend.update_metadata(image_id, dict(properties=properties))
return util.render_metadata(request, properties, status=201)
......@@ -254,7 +253,8 @@ def get_metadata_item(request, image_id, key):
# overLimit (413)
log.debug('get_image_metadata_item %s %s', image_id, key)
image = util.get_image(image_id, request.user_uniq)
with image_backend(request.user_uniq) as backend:
image = backend.get_image(image_id)
val = image['properties'].get(key)
if val is None:
raise faults.ItemNotFound('Metadata key not found.')
......@@ -284,12 +284,12 @@ def create_metadata_item(request, image_id, key):
raise faults.BadRequest('Malformed request.')
val = metadict[key]
image = util.get_image(image_id, request.user_uniq)
properties = image['properties']
properties[key] = val
with image_backend(request.user_uniq) as backend:
backend.update(image_id, dict(properties=properties))
image = backend.get_image(image_id)
properties = image['properties']
properties[key] = val
backend.update_metadata(image_id, dict(properties=properties))
return util.render_meta(request, {key: val}, status=201)
......@@ -307,11 +307,11 @@ def delete_metadata_item(request, image_id, key):
# overLimit (413),
log.info('delete_image_metadata_item %s %s', image_id, key)
image = util.get_image(image_id, request.user_uniq)
properties = image['properties']
properties.pop(key, None)
with image_backend(request.user_uniq) as backend:
backend.update(image_id, dict(properties=properties))
image = backend.get_image(image_id)
properties = image['properties']
properties.pop(key, None)
backend.update_metadata(image_id, dict(properties=properties))