Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / volume / management / commands / volume-import.py @ 1040b85b

History | View | Annotate | Download (5.4 kB)

1 1040b85b Christos Stavrakakis
# Copyright 2013 GRNET S.A. All rights reserved.
2 1040b85b Christos Stavrakakis
#
3 1040b85b Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 1040b85b Christos Stavrakakis
# without modification, are permitted provided that the following
5 1040b85b Christos Stavrakakis
# conditions are met:
6 1040b85b Christos Stavrakakis
#
7 1040b85b Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 1040b85b Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 1040b85b Christos Stavrakakis
#      disclaimer.
10 1040b85b Christos Stavrakakis
#
11 1040b85b Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 1040b85b Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 1040b85b Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 1040b85b Christos Stavrakakis
#      provided with the distribution.
15 1040b85b Christos Stavrakakis
#
16 1040b85b Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 1040b85b Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 1040b85b Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1040b85b Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 1040b85b Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 1040b85b Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 1040b85b Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 1040b85b Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 1040b85b Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1040b85b Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 1040b85b Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1040b85b Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 1040b85b Christos Stavrakakis
#
29 1040b85b Christos Stavrakakis
# The views and conclusions contained in the software and
30 1040b85b Christos Stavrakakis
# documentation are those of the authors and should not be
31 1040b85b Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 1040b85b Christos Stavrakakis
# or implied, of GRNET S.A.
33 1040b85b Christos Stavrakakis
34 1040b85b Christos Stavrakakis
from optparse import make_option
35 1040b85b Christos Stavrakakis
36 1040b85b Christos Stavrakakis
from snf_django.management.commands import SynnefoCommand, CommandError
37 1040b85b Christos Stavrakakis
38 1040b85b Christos Stavrakakis
from synnefo.management import common, pprint
39 1040b85b Christos Stavrakakis
from synnefo.logic import backend as backend_mod, reconciliation, utils
40 1040b85b Christos Stavrakakis
from synnefo.db.models import Volume
41 1040b85b Christos Stavrakakis
42 1040b85b Christos Stavrakakis
HELP_MSG = """Import an existing Ganeti disk to Cyclades
43 1040b85b Christos Stavrakakis

44 1040b85b Christos Stavrakakis
Create a Cyclades Volume from an existing Ganeti disk. This command is useful
45 1040b85b Christos Stavrakakis
to handle disks that have been created directly in the Ganeti backend (instead
46 1040b85b Christos Stavrakakis
of being created by Cyclades). The command will not create/delete/modify the
47 1040b85b Christos Stavrakakis
specified disk in the Ganeti backend. Instead, it will create a Volume in
48 1040b85b Christos Stavrakakis
Cyclades DB, and rename the Ganeti disk with the Volume name.
49 1040b85b Christos Stavrakakis

50 1040b85b Christos Stavrakakis
"""
51 1040b85b Christos Stavrakakis
52 1040b85b Christos Stavrakakis
53 1040b85b Christos Stavrakakis
class Command(SynnefoCommand):
54 1040b85b Christos Stavrakakis
    help = HELP_MSG
55 1040b85b Christos Stavrakakis
56 1040b85b Christos Stavrakakis
    option_list = SynnefoCommand.option_list + (
57 1040b85b Christos Stavrakakis
        make_option(
58 1040b85b Christos Stavrakakis
            "--name",
59 1040b85b Christos Stavrakakis
            dest="name",
60 1040b85b Christos Stavrakakis
            default=None,
61 1040b85b Christos Stavrakakis
            help="Display name of the volume."),
62 1040b85b Christos Stavrakakis
        make_option(
63 1040b85b Christos Stavrakakis
            "--description",
64 1040b85b Christos Stavrakakis
            dest="description",
65 1040b85b Christos Stavrakakis
            default=None,
66 1040b85b Christos Stavrakakis
            help="Display description of the volume."),
67 1040b85b Christos Stavrakakis
        make_option(
68 1040b85b Christos Stavrakakis
            "--server",
69 1040b85b Christos Stavrakakis
            dest="server_id",
70 1040b85b Christos Stavrakakis
            default=None,
71 1040b85b Christos Stavrakakis
            help="The ID of the server that the volume is currently attached"),
72 1040b85b Christos Stavrakakis
        make_option(
73 1040b85b Christos Stavrakakis
            "--disk",
74 1040b85b Christos Stavrakakis
            dest="disk_uuid",
75 1040b85b Christos Stavrakakis
            default=None,
76 1040b85b Christos Stavrakakis
            help="The UUID of the disk to be imported"),
77 1040b85b Christos Stavrakakis
    )
78 1040b85b Christos Stavrakakis
79 1040b85b Christos Stavrakakis
    @common.convert_api_faults
80 1040b85b Christos Stavrakakis
    def handle(self, *args, **options):
81 1040b85b Christos Stavrakakis
        if args:
82 1040b85b Christos Stavrakakis
            raise CommandError("Command doesn't accept any arguments")
83 1040b85b Christos Stavrakakis
84 1040b85b Christos Stavrakakis
        display_name = options.get("name", "")
85 1040b85b Christos Stavrakakis
        display_description = options.get("description", "")
86 1040b85b Christos Stavrakakis
87 1040b85b Christos Stavrakakis
        server_id = options.get("server_id")
88 1040b85b Christos Stavrakakis
        if server_id is None:
89 1040b85b Christos Stavrakakis
            raise CommandError("Please specify the server that the disk is"
90 1040b85b Christos Stavrakakis
                               " currently attached.")
91 1040b85b Christos Stavrakakis
92 1040b85b Christos Stavrakakis
        disk_uuid = options.get("disk_uuid")
93 1040b85b Christos Stavrakakis
        if disk_uuid is None:
94 1040b85b Christos Stavrakakis
            raise CommandError("Please specify the UUID of the Ganeti disk")
95 1040b85b Christos Stavrakakis
96 1040b85b Christos Stavrakakis
        vm = common.get_vm(server_id)
97 1040b85b Christos Stavrakakis
98 1040b85b Christos Stavrakakis
        instance_info = backend_mod.get_instance_info(vm)
99 1040b85b Christos Stavrakakis
        instance_disks = reconciliation.disks_from_instance(instance_info)
100 1040b85b Christos Stavrakakis
        try:
101 1040b85b Christos Stavrakakis
            disk = filter(lambda d: d["uuid"] == disk_uuid, instance_disks)[0]
102 1040b85b Christos Stavrakakis
        except IndexError:
103 1040b85b Christos Stavrakakis
            raise CommandError("Instance '%s' does not have a disk with"
104 1040b85b Christos Stavrakakis
                               " UUID '%s" % (vm.id, disk_uuid))
105 1040b85b Christos Stavrakakis
106 1040b85b Christos Stavrakakis
        # Check that the instance disk is not already a Cyclades Volume
107 1040b85b Christos Stavrakakis
        try:
108 1040b85b Christos Stavrakakis
            disk_id = utils.id_from_disk_name(disk["name"])
109 1040b85b Christos Stavrakakis
        except:
110 1040b85b Christos Stavrakakis
            pass
111 1040b85b Christos Stavrakakis
        else:
112 1040b85b Christos Stavrakakis
            raise CommandError("Disk '%s' of instance '%s' is already a"
113 1040b85b Christos Stavrakakis
                               " Cyclades Volume. Volume ID: %s"
114 1040b85b Christos Stavrakakis
                               % (disk_uuid, vm.id, disk_id))
115 1040b85b Christos Stavrakakis
116 1040b85b Christos Stavrakakis
        size = disk["size"] >> 10  # Convert to GB
117 1040b85b Christos Stavrakakis
118 1040b85b Christos Stavrakakis
        self.stdout.write("Import disk/%s of instance %s, size: %s GB\n"
119 1040b85b Christos Stavrakakis
                          % (disk["index"], vm.id, size))
120 1040b85b Christos Stavrakakis
121 1040b85b Christos Stavrakakis
        volume = Volume.objects.create(
122 1040b85b Christos Stavrakakis
            userid=vm.userid,
123 1040b85b Christos Stavrakakis
            size=size,
124 1040b85b Christos Stavrakakis
            machine_id=server_id,
125 1040b85b Christos Stavrakakis
            name=display_name,
126 1040b85b Christos Stavrakakis
            description=display_description,
127 1040b85b Christos Stavrakakis
            index=disk["index"])
128 1040b85b Christos Stavrakakis
129 1040b85b Christos Stavrakakis
        self.stdout.write("Created Volume '%s' in DB\n" % volume.id)
130 1040b85b Christos Stavrakakis
        pprint.pprint_volume(volume, stdout=self.stdout)
131 1040b85b Christos Stavrakakis
        self.stdout.write("\n")
132 1040b85b Christos Stavrakakis
133 1040b85b Christos Stavrakakis
        client = vm.get_client()
134 1040b85b Christos Stavrakakis
        jobId = client.ModifyInstance(
135 1040b85b Christos Stavrakakis
            instance=vm.backend_vm_id,
136 1040b85b Christos Stavrakakis
            disks=[("modify", disk["index"],
137 1040b85b Christos Stavrakakis
                    {"name": volume.backend_volume_uuid})])
138 1040b85b Christos Stavrakakis
        (status, error) = backend_mod.wait_for_job(client, jobId)
139 1040b85b Christos Stavrakakis
        vm.put_client(client)
140 1040b85b Christos Stavrakakis
        if status == "success":
141 1040b85b Christos Stavrakakis
            self.stdout.write("Successfully imported disk\n")
142 1040b85b Christos Stavrakakis
        else:
143 1040b85b Christos Stavrakakis
            self.stdout.write("Failed to imported disk:\n %s\n" % error)