Commit c736bef3 authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

cyclades: Update volume and snapshots commands

Create new management commands:

* snapshot-modify
* snapshot-show
* volume-modify

Also, fix various small issues in other commands.
parent a3bc4db2
......@@ -1163,7 +1163,7 @@ def attach_volume(vm, volume, depends=[]):
disk = {"size": int(volume.size) << 10,
"name": volume.backend_volume_uuid}
disk_provider = volume.disk_provider
disk_provider = volume.provider
if disk_provider is not None:
disk["provider"] = disk_provider
......
......@@ -421,14 +421,15 @@ def pprint_volume(volume, display_mails=False, stdout=None, title=None):
volume_dict = OrderedDict([
("id", volume.id),
("size", volume.size),
("disk_template", volume.disk_template),
("disk_provider", volume.disk_provider),
("disk_template", volume.template),
("disk_provider", volume.provider),
("server_id", volume.machine_id),
("userid", volume.userid),
("username", ucache.get_name(userid) if display_mails else None),
("index", volume.index),
("name", volume.name),
("state", volume.status),
("delete_on_termination", volume.delete_on_termination),
("deleted", volume.deleted),
("backendjobid", volume.backendjobid),
])
......
......@@ -28,22 +28,34 @@
# policies, either expressed or implied, of GRNET S.A.
#
from optparse import make_option
from django.core.management.base import CommandError
from snf_django.management.commands import SynnefoCommand
from synnefo.plankton.backend import PlanktonBackend
from synnefo.management import common
from snf_django.management import utils
class Command(SynnefoCommand):
args = "<image_id>"
help = "Display available information about an image"
option_list = SynnefoCommand.option_list + (
make_option(
'--user-id',
dest='userid',
default=None,
help="The UUID of the owner of the image. Required"
" if image is not public"),
)
@common.convert_api_faults
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Please provide an image ID")
image_id = args[0]
#user_id = options["userid"]
with PlanktonBackend(None) as backend:
image = backend.get_image(image_id)
......
......@@ -68,7 +68,7 @@ class Command(BaseCommand):
if len(args) != 1:
raise CommandError("Please provide a volume ID")
volume = common.get_volume(args[0])
volume = common.get_resource("volume", args[0], for_update=True)
name = options.get("name")
if name is None:
......
# Copyright 2011-2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of GRNET S.A.
#
from optparse import make_option
from django.core.management.base import CommandError
from synnefo.volume import snapshots, util
from synnefo.management import common
from snf_django.management.commands import SynnefoCommand
class Command(SynnefoCommand):
args = "<Snapshot ID>"
help = "Modify a snapshot"
option_list = SynnefoCommand.option_list + (
make_option(
"--user_id",
dest="user_id",
default=None,
help="UUID of the owner of the snapshot"),
make_option(
"--name",
dest="name",
default=None,
help="Update snapshot's name"),
make_option(
"--description",
dest="description",
default=None,
help="Update snapshot's description"),
)
@common.convert_api_faults
def handle(self, *args, **options):
if not args:
raise CommandError("Please provide a snapshot ID")
snapshot_id = args[0]
user_id = self.options["user_id"]
name = self.options["name"]
description = self.options["description"]
snapshot = util.get_snapshot(user_id, snapshot_id)
snapshots.modify(snapshot, name=name, description=description)
self.stdout.write("Successfully updated snapshot %s\n"
% snapshot)
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of GRNET S.A.
#
from django.core.management.base import BaseCommand, CommandError
from optparse import make_option
from synnefo.management import common
from synnefo.plankton.utils import image_backend
from snf_django.management import utils
class Command(BaseCommand):
args = "<snapshot_id>"
help = "Display available information about a snapshot"
option_list = BaseCommand.option_list + (
make_option(
'--user-id',
dest='userid',
default=None,
help="The UUID of the owner of the snapshot. Required"
"if snapshot is not public"),
)
@common.convert_api_faults
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Please provide a snapshot ID")
snapshot_id = args[0]
user_id = options["userid"]
with image_backend(userid) as backend:
snapshot = backend.get_snapshot(userid, snapshot_id)
utils.pprint_table(out=self.stdout, table=[snapshot.values()],
headers=snapshot.keys(), vertical=True)
......@@ -93,7 +93,7 @@ class Command(SynnefoCommand):
if disk_uuid is None:
raise CommandError("Please specify the UUID of the Ganeti disk")
vm = common.get_vm(server_id)
vm = common.get_resource("server", server_id)
instance_info = backend_mod.get_instance_info(vm)
instance_disks = reconciliation.disks_from_instance(instance_info)
......@@ -114,17 +114,21 @@ class Command(SynnefoCommand):
% (disk_uuid, vm.id, disk_id))
size = disk["size"] >> 10 # Convert to GB
index = disk["index"]
self.stdout.write("Import disk/%s of instance %s, size: %s GB\n"
% (disk["index"], vm.id, size))
% (index, vm.id, size))
volume = Volume.objects.create(
userid=vm.userid,
disk_template=vm.flavor.disk_template,
size=size,
machine_id=server_id,
machine_id=vm.id,
name=display_name,
description=display_description,
index=disk["index"])
delete_on_termination=True,
status="IN_USE",
index=index)
self.stdout.write("Created Volume '%s' in DB\n" % volume.id)
pprint.pprint_volume(volume, stdout=self.stdout)
......
......@@ -56,7 +56,7 @@ class Command(BaseCommand):
if len(args) != 1:
raise CommandError("Please provide a volume ID")
volume = common.get_volume("volume", args[0])
volume = common.get_resource("volume", args[0])
pprint.pprint_volume(volume, stdout=self.stdout)
self.stdout.write('\n\n')
......
......@@ -56,11 +56,15 @@ class Command(ListCommand):
"id": ("id", "ID of the server"),
"name": ("name", "Name of the server"),
"user.uuid": ("userid", "The UUID of the server's owner"),
"server_id": ("machine_id", ""),
"source": ("source", ""),
"status": ("status", ""),
"size": ("size", "The size of the volume (GB)"),
"server_id": ("machine_id", "The UUID of the server that the volume"
" is currently attached"),
"source": ("source", "The source of the volume"),
"status": ("status", "The status of the volume"),
"created": ("created", "The date the server was created"),
"deleted": ("deleted", "Whether the server is deleted or not"),
"disk_template": ("disk_template", "The disk template of the volume")
}
fields = ["id", "name", "user.uuid", "status", "source", "server_id"]
fields = ["id", "user.uuid", "size", "status", "source", "disk_template",
"server_id"]
# Copyright 2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from snf_django.management.utils import parse_bool
from synnefo.management.common import convert_api_faults
from synnefo.management import pprint, common
from synnefo.volume import volumes
class Command(BaseCommand):
help = "Modify a volume"
args = "<volume ID>"
option_list = BaseCommand.option_list + (
make_option(
'--name',
dest='name',
help="Modify a volume's display name"),
make_option(
'--description',
dest='description',
help="Modify a volume's display description"),
make_option(
'--delete-on-termination',
dest='delete_on_termination',
default="True",
choices=["True", "False"],
metavar="True|False",
help="Set whether volume will be preserved when the server"
" the volume is attached will be deleted"),
)
@convert_api_faults
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Please provide a volume ID")
volume = common.get_resource("volume", args[0], for_update=True)
name = options.get("name")
description = options.get("description")
delete_on_termination = options.get("delete_on_termination")
if delete_on_termination is not None:
delete_on_termination = parse_bool(delete_on_termination)
volume = volumes.update(volume, name, description,
delete_on_termination)
pprint.pprint_volume(volume, stdout=self.stdout)
self.stdout.write('\n\n')
......@@ -132,11 +132,18 @@ def delete(snapshot):
return snapshot
def rename(snapshot, new_name):
# user_id = snapshot["owner"]
raise NotImplemented("Renaming a snapshot is not implemented!")
def update(snapshot, name=None, description=None):
"""Update a snapshot
def update_description(snapshot, new_description):
# user_id = snapshot["owner"]
raise NotImplemented("Updating snapshot's description is not implemented!")
Update the name or description of a snapshot.
"""
metadata = {}
if name is not None:
metadata["name"] = name
if description is not None:
metadata["description"] = description
if not metadata:
return
user_id = snapshot["owner"]
with image_backend(user_id) as b:
return b.update_metadata(snapshot["id"], metadata)
......@@ -202,14 +202,15 @@ def update_volume(request, volume_id):
new_name = req.get("display_name")
description = req.get("display_description")
delete_on_termination = req.get("delete_on_termination")
if new_name is None and description is None:
if new_name is None and description is None and\
delete_on_termination is None:
raise faults.BadRequest("Nothing to update.")
else:
volume = volumes.update(volume, new_name, description,
delete_on_termination)
if new_name is not None:
volume = volumes.rename(volume, new_name)
if description is not None:
volume = volumes.update_description(volume, description)
data = json.dumps({'volume': volume_to_dict(volume, detail=True)})
return HttpResponse(data, content_type="application/json", status=200)
......@@ -334,10 +335,8 @@ def update_snapshot(request, snapshot_id):
if new_name is None and new_description is None:
raise faults.BadRequest("Nothing to update.")
if new_name is not None:
snapshot = snapshots.rename(snapshot, new_name)
if new_description is not None:
snapshot = snapshots.update_description(snapshot, new_description)
snapshot = snapshots.update(snapshot, name=new_name,
description=new_description)
data = json.dumps({'snapshot': snapshot_to_dict(snapshot, detail=True)})
return HttpResponse(data, content_type="application/json", status=200)
......@@ -37,7 +37,8 @@ def create(user_id, size, server_id, name=None, description=None,
source_type = "image"
source_uuid = source_image_id
else:
source_type = source_uuid = None
source_type = "blank"
source_uuid = None
volume = _create_volume(server, user_id, size, source_type, source_uuid,
name, description, index=None)
......@@ -151,14 +152,13 @@ def delete(volume):
@transaction.commit_on_success
def rename(volume, new_name):
volume.name = new_name
volume.save()
return volume
def update(volume, name=None, description=None, delete_on_termination=None):
if name is not None:
volume.name = name
if description is not None:
volume.description = description
if delete_on_termination is not None:
volume.delete_on_termination = delete_on_termination
@transaction.commit_on_success
def update_description(volume, new_description):
volume.description = new_description
volume.save()
return volume
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