Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / management / commands / server-create.py @ 39a6388d

History | View | Annotate | Download (6.2 kB)

1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from optparse import make_option
35

    
36
from django.core.management.base import BaseCommand, CommandError
37

    
38
from synnefo.db.models import VirtualMachine, Backend, Flavor
39
from synnefo.logic.backend import create_instance
40
from synnefo.logic.backend_allocator import BackendAllocator
41
from synnefo.api.util import get_image, allocate_public_address
42
from synnefo.api.faults import ItemNotFound
43

    
44
HELP_MSG = """
45

46
Create a new VM without authenticating the user or checking the resource
47
limits of the user. Also the allocator can be bypassed by specifing a
48
backend-id.
49
"""
50

    
51

    
52
class Command(BaseCommand):
53
    help = "Create a new VM." + HELP_MSG
54

    
55
    output_transaction = True
56

    
57
    option_list = BaseCommand.option_list + (
58
            make_option("--backend-id", dest="backend_id",
59
                        help="Unique identifier of the Ganeti backend."
60
                             " Use snf-manage backend-list to find out"
61
                             " available backends."),
62
            make_option("--name", dest="name",
63
                        help="An arbitrary string for naming the server"),
64
            make_option("--user-id", dest="user_id",
65
                        help="Unique identifier of the owner of the server"),
66
            make_option("--image-id", dest="image_id",
67
                        help="Unique identifier of the image."
68
                             " Use snf-manage image-list to find out"
69
                             " available images."),
70
            make_option("--flavor-id", dest="flavor_id",
71
                        help="Unique identifier of the flavor"
72
                             " Use snf-manage flavor-list to find out"
73
                             " available flavors."),
74
            make_option("--password", dest="password",
75
                        help="Password for the new server")
76
        )
77

    
78
    def handle(self, *args, **options):
79
        if args:
80
            raise CommandError("Command doesn't accept any arguments")
81

    
82
        name = options['name']
83
        user_id = options['user_id']
84
        backend_id = options['backend_id']
85
        image_id = options['image_id']
86
        flavor_id = options['flavor_id']
87
        password = options['password']
88

    
89
        if not name:
90
            raise CommandError("name is mandatory")
91
        if not user_id:
92
            raise CommandError("user-id is mandatory")
93
        if not password:
94
            raise CommandError("password is mandatory")
95

    
96
        # Get Flavor
97
        if flavor_id:
98
            try:
99
                flavor_id = int(flavor_id)
100
                flavor = Flavor.objects.get(id=flavor_id)
101
            except ValueError:
102
                raise CommandError("Invalid flavor-id")
103
            except Flavor.DoesNotExist:
104
                raise CommandError("Flavor not found")
105
        else:
106
            raise CommandError("flavor-id is mandatory")
107

    
108
        # Get Image
109
        if image_id:
110
            try:
111
                img = get_image(image_id, user_id)
112
            except ItemNotFound:
113
                raise CommandError("Image not found")
114

    
115
            properties = img.get('properties', {})
116
            image = {}
117
            image['backend_id'] = img['location']
118
            image['format'] = img['disk_format']
119
            image['metadata'] = dict((key.upper(), val) \
120
                                     for key, val in properties.items())
121
        else:
122
            raise CommandError("image-id is mandatory")
123

    
124
        # Get Backend
125
        if backend_id:
126
            try:
127
                backend_id = int(backend_id)
128
                backend = Backend.objects.get(id=backend_id)
129
            except (ValueError, Backend.DoesNotExist):
130
                raise CommandError("Invalid Backend ID")
131
        else:
132
            ballocator = BackendAllocator()
133
            backend = ballocator.allocate(user_id, flavor)
134
            if not backend:
135
                raise CommandError("Can not allocate VM")
136

    
137
        # Get Public address
138
        (network, address) = allocate_public_address(backend)
139
        if address is None:
140
            raise CommandError("Can not allocate a public address."\
141
                               " No available public network.")
142
        nic = {'ip': address, 'network': network.backend_id}
143

    
144
        # Create the VM in DB
145
        vm = VirtualMachine.objects.create(name=name,
146
                                           backend=backend,
147
                                           userid=user_id,
148
                                           imageid=image_id,
149
                                           flavor=flavor)
150

    
151
        # Create the instance in Backend
152
        jobID = create_instance(vm, nic, flavor, image, password, [])
153

    
154
        self.stdout.write("Creating VM %s with IP %s in Backend %s. JobID: %s\n" % \
155
                          (vm, address, backend, jobID))