Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / db / models.py @ b050e382

History | View | Annotate | Download (31.3 kB)

1 244c552b Giorgos Verigakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 48130e66 Georgios Gousios
#
3 48130e66 Georgios Gousios
# Redistribution and use in source and binary forms, with or without
4 48130e66 Georgios Gousios
# modification, are permitted provided that the following conditions
5 48130e66 Georgios Gousios
# are met:
6 48130e66 Georgios Gousios
#
7 48130e66 Georgios Gousios
#   1. Redistributions of source code must retain the above copyright
8 48130e66 Georgios Gousios
#      notice, this list of conditions and the following disclaimer.
9 48130e66 Georgios Gousios
#
10 48130e66 Georgios Gousios
#  2. Redistributions in binary form must reproduce the above copyright
11 48130e66 Georgios Gousios
#     notice, this list of conditions and the following disclaimer in the
12 48130e66 Georgios Gousios
#     documentation and/or other materials provided with the distribution.
13 48130e66 Georgios Gousios
#
14 48130e66 Georgios Gousios
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 48130e66 Georgios Gousios
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 48130e66 Georgios Gousios
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 48130e66 Georgios Gousios
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 48130e66 Georgios Gousios
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 48130e66 Georgios Gousios
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 48130e66 Georgios Gousios
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 48130e66 Georgios Gousios
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 48130e66 Georgios Gousios
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 48130e66 Georgios Gousios
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 48130e66 Georgios Gousios
# SUCH DAMAGE.
25 48130e66 Georgios Gousios
#
26 48130e66 Georgios Gousios
# The views and conclusions contained in the software and documentation are
27 48130e66 Georgios Gousios
# those of the authors and should not be interpreted as representing official
28 48130e66 Georgios Gousios
# policies, either expressed or implied, of GRNET S.A.
29 48130e66 Georgios Gousios
30 c4e55622 Christos Stavrakakis
import datetime
31 c4e55622 Christos Stavrakakis
32 bd87213f Christos Stavrakakis
from copy import deepcopy
33 9dbe70f8 Markos Gogoulos
from django.conf import settings
34 17935f41 Vassilios Karakoidas
from django.db import models
35 aed9b901 Christos Stavrakakis
from django.db import IntegrityError
36 3165f027 Christos Stavrakakis
37 3165f027 Christos Stavrakakis
import utils
38 3524241a Christos Stavrakakis
from contextlib import contextmanager
39 aed9b901 Christos Stavrakakis
from hashlib import sha1
40 bd40abfa Christos Stavrakakis
from snf_django.lib.api import faults
41 e6a42a96 Christos Stavrakakis
from synnefo import settings as snf_settings
42 30e0ed74 Christos Stavrakakis
from aes_encrypt import encrypt_db_charfield, decrypt_db_charfield
43 aed9b901 Christos Stavrakakis
44 864bed43 Christos Stavrakakis
from synnefo.db.managers import ForUpdateManager, ProtectedDeleteManager
45 03992c72 Christos Stavrakakis
from synnefo.db import pools
46 864bed43 Christos Stavrakakis
47 3524241a Christos Stavrakakis
from synnefo.logic.rapi_pool import (get_rapi_client,
48 3524241a Christos Stavrakakis
                                     put_rapi_client)
49 aed9b901 Christos Stavrakakis
50 b533e9b2 Christos Stavrakakis
import logging
51 b533e9b2 Christos Stavrakakis
log = logging.getLogger(__name__)
52 b533e9b2 Christos Stavrakakis
53 aed9b901 Christos Stavrakakis
54 e7164ebc Vassilios Karakoidas
class Flavor(models.Model):
55 13b3c5ff Vassilios Karakoidas
    cpu = models.IntegerField('Number of CPUs', default=0)
56 c909cbbd Giorgos Verigakis
    ram = models.IntegerField('RAM size in MiB', default=0)
57 c909cbbd Giorgos Verigakis
    disk = models.IntegerField('Disk size in GiB', default=0)
58 c802789d Christos Stavrakakis
    disk_template = models.CharField('Disk template', max_length=32)
59 2c60cbef Giorgos Verigakis
    deleted = models.BooleanField('Deleted', default=False)
60 ce55f211 Kostas Papadimitriou
61 be7b8d37 Vassilios Karakoidas
    class Meta:
62 dcfc6c2d Vangelis Koukis
        verbose_name = u'Virtual machine flavor'
63 b1af40e2 Giorgos Verigakis
        unique_together = ('cpu', 'ram', 'disk', 'disk_template')
64 ce55f211 Kostas Papadimitriou
65 9ff7ca6f Giorgos Verigakis
    @property
66 9ff7ca6f Giorgos Verigakis
    def name(self):
67 f0f4edac Vassilios Karakoidas
        """Returns flavor name (generated)"""
68 b65a3b04 Christos Stavrakakis
        return u'C%dR%dD%d%s' % (self.cpu, self.ram, self.disk,
69 b65a3b04 Christos Stavrakakis
                                 self.disk_template)
70 ce55f211 Kostas Papadimitriou
71 46547e14 Faidon Liambotis
    def __unicode__(self):
72 df36a125 Christos Stavrakakis
        return "<%s:%s>" % (str(self.id), self.name)
73 452d2391 Vassilios Karakoidas
74 46547e14 Faidon Liambotis
75 aed9b901 Christos Stavrakakis
class Backend(models.Model):
76 aed9b901 Christos Stavrakakis
    clustername = models.CharField('Cluster Name', max_length=128, unique=True)
77 aed9b901 Christos Stavrakakis
    port = models.PositiveIntegerField('Port', default=5080)
78 aed9b901 Christos Stavrakakis
    username = models.CharField('Username', max_length=64, blank=True,
79 aed9b901 Christos Stavrakakis
                                null=True)
80 2a8a60d5 Christos Stavrakakis
    password_hash = models.CharField('Password', max_length=128, blank=True,
81 68b952f9 Christos Stavrakakis
                                     null=True)
82 aed9b901 Christos Stavrakakis
    # Sha1 is up to 40 characters long
83 aed9b901 Christos Stavrakakis
    hash = models.CharField('Hash', max_length=40, editable=False, null=False)
84 3165f027 Christos Stavrakakis
    # Unique index of the Backend, used for the mac-prefixes of the
85 3165f027 Christos Stavrakakis
    # BackendNetworks
86 3165f027 Christos Stavrakakis
    index = models.PositiveIntegerField('Index', null=False, unique=True,
87 3165f027 Christos Stavrakakis
                                        default=0)
88 aed9b901 Christos Stavrakakis
    drained = models.BooleanField('Drained', default=False, null=False)
89 aed9b901 Christos Stavrakakis
    offline = models.BooleanField('Offline', default=False, null=False)
90 bd87213f Christos Stavrakakis
    # Type of hypervisor
91 bd87213f Christos Stavrakakis
    hypervisor = models.CharField('Hypervisor', max_length=32, default="kvm",
92 bd87213f Christos Stavrakakis
                                  null=False)
93 aed9b901 Christos Stavrakakis
    # Last refresh of backend resources
94 aed9b901 Christos Stavrakakis
    updated = models.DateTimeField(auto_now_add=True)
95 aed9b901 Christos Stavrakakis
    # Backend resources
96 aed9b901 Christos Stavrakakis
    mfree = models.PositiveIntegerField('Free Memory', default=0, null=False)
97 aed9b901 Christos Stavrakakis
    mtotal = models.PositiveIntegerField('Total Memory', default=0, null=False)
98 aed9b901 Christos Stavrakakis
    dfree = models.PositiveIntegerField('Free Disk', default=0, null=False)
99 aed9b901 Christos Stavrakakis
    dtotal = models.PositiveIntegerField('Total Disk', default=0, null=False)
100 aed9b901 Christos Stavrakakis
    pinst_cnt = models.PositiveIntegerField('Primary Instances', default=0,
101 aed9b901 Christos Stavrakakis
                                            null=False)
102 aed9b901 Christos Stavrakakis
    ctotal = models.PositiveIntegerField('Total number of logical processors',
103 aed9b901 Christos Stavrakakis
                                         default=0, null=False)
104 aed9b901 Christos Stavrakakis
    # Custom object manager to protect from cascade delete
105 864bed43 Christos Stavrakakis
    objects = ProtectedDeleteManager()
106 aed9b901 Christos Stavrakakis
107 4c9ac139 Christos Stavrakakis
    HYPERVISORS = (
108 4c9ac139 Christos Stavrakakis
        ("kvm", "Linux KVM hypervisor"),
109 4c9ac139 Christos Stavrakakis
        ("xen-pvm", "Xen PVM hypervisor"),
110 4c9ac139 Christos Stavrakakis
        ("xen-hvm", "Xen KVM hypervisor"),
111 4c9ac139 Christos Stavrakakis
    )
112 4c9ac139 Christos Stavrakakis
113 aed9b901 Christos Stavrakakis
    class Meta:
114 aed9b901 Christos Stavrakakis
        verbose_name = u'Backend'
115 aed9b901 Christos Stavrakakis
        ordering = ["clustername"]
116 aed9b901 Christos Stavrakakis
117 aed9b901 Christos Stavrakakis
    def __unicode__(self):
118 bf5c82dc Christos Stavrakakis
        return self.clustername + "(id=" + str(self.id) + ")"
119 aed9b901 Christos Stavrakakis
120 aed9b901 Christos Stavrakakis
    @property
121 aed9b901 Christos Stavrakakis
    def backend_id(self):
122 aed9b901 Christos Stavrakakis
        return self.id
123 aed9b901 Christos Stavrakakis
124 3524241a Christos Stavrakakis
    def get_client(self):
125 aed9b901 Christos Stavrakakis
        """Get or create a client. """
126 3524241a Christos Stavrakakis
        if self.offline:
127 bd40abfa Christos Stavrakakis
            raise faults.ServiceUnavailable
128 3524241a Christos Stavrakakis
        return get_rapi_client(self.id, self.hash,
129 cc50e51a Christos Stavrakakis
                               self.clustername,
130 cc50e51a Christos Stavrakakis
                               self.port,
131 3524241a Christos Stavrakakis
                               self.username,
132 3524241a Christos Stavrakakis
                               self.password)
133 3524241a Christos Stavrakakis
134 3524241a Christos Stavrakakis
    @staticmethod
135 3524241a Christos Stavrakakis
    def put_client(client):
136 3524241a Christos Stavrakakis
            put_rapi_client(client)
137 aed9b901 Christos Stavrakakis
138 aed9b901 Christos Stavrakakis
    def create_hash(self):
139 aed9b901 Christos Stavrakakis
        """Create a hash for this backend. """
140 68b952f9 Christos Stavrakakis
        sha = sha1('%s%s%s%s' %
141 68b952f9 Christos Stavrakakis
                   (self.clustername, self.port, self.username, self.password))
142 68b952f9 Christos Stavrakakis
        return sha.hexdigest()
143 aed9b901 Christos Stavrakakis
144 30e0ed74 Christos Stavrakakis
    @property
145 30e0ed74 Christos Stavrakakis
    def password(self):
146 30e0ed74 Christos Stavrakakis
        return decrypt_db_charfield(self.password_hash)
147 30e0ed74 Christos Stavrakakis
148 30e0ed74 Christos Stavrakakis
    @password.setter
149 30e0ed74 Christos Stavrakakis
    def password(self, value):
150 30e0ed74 Christos Stavrakakis
        self.password_hash = encrypt_db_charfield(value)
151 30e0ed74 Christos Stavrakakis
152 aed9b901 Christos Stavrakakis
    def save(self, *args, **kwargs):
153 aed9b901 Christos Stavrakakis
        # Create a new hash each time a Backend is saved
154 aed9b901 Christos Stavrakakis
        old_hash = self.hash
155 aed9b901 Christos Stavrakakis
        self.hash = self.create_hash()
156 aed9b901 Christos Stavrakakis
        super(Backend, self).save(*args, **kwargs)
157 aed9b901 Christos Stavrakakis
        if self.hash != old_hash:
158 aed9b901 Christos Stavrakakis
            # Populate the new hash to the new instances
159 68b952f9 Christos Stavrakakis
            self.virtual_machines.filter(deleted=False)\
160 68b952f9 Christos Stavrakakis
                                 .update(backend_hash=self.hash)
161 aed9b901 Christos Stavrakakis
162 aed9b901 Christos Stavrakakis
    def delete(self, *args, **kwargs):
163 aed9b901 Christos Stavrakakis
        # Integrity Error if non-deleted VMs are associated with Backend
164 aed9b901 Christos Stavrakakis
        if self.virtual_machines.filter(deleted=False).count():
165 aed9b901 Christos Stavrakakis
            raise IntegrityError("Non-deleted virtual machines are associated "
166 aed9b901 Christos Stavrakakis
                                 "with backend: %s" % self)
167 aed9b901 Christos Stavrakakis
        else:
168 aed9b901 Christos Stavrakakis
            # ON_DELETE = SET NULL
169 ce9abd26 Christos Stavrakakis
            for vm in self.virtual_machines.all():
170 ce9abd26 Christos Stavrakakis
                vm.backend = None
171 ce9abd26 Christos Stavrakakis
                vm.save()
172 fd65ab41 Christos Stavrakakis
            self.virtual_machines.all().backend = None
173 82c1c610 Christos Stavrakakis
            # Remove BackendNetworks of this Backend.
174 82c1c610 Christos Stavrakakis
            # Do not use networks.all().delete(), since delete() method of
175 82c1c610 Christos Stavrakakis
            # BackendNetwork will not be called!
176 82c1c610 Christos Stavrakakis
            for net in self.networks.all():
177 82c1c610 Christos Stavrakakis
                net.delete()
178 aed9b901 Christos Stavrakakis
            super(Backend, self).delete(*args, **kwargs)
179 aed9b901 Christos Stavrakakis
180 3165f027 Christos Stavrakakis
    def __init__(self, *args, **kwargs):
181 3165f027 Christos Stavrakakis
        super(Backend, self).__init__(*args, **kwargs)
182 3165f027 Christos Stavrakakis
        if not self.pk:
183 3165f027 Christos Stavrakakis
            # Generate a unique index for the Backend
184 3165f027 Christos Stavrakakis
            indexes = Backend.objects.all().values_list('index', flat=True)
185 ce9abd26 Christos Stavrakakis
            try:
186 ce9abd26 Christos Stavrakakis
                first_free = [x for x in xrange(0, 16) if x not in indexes][0]
187 ce9abd26 Christos Stavrakakis
                self.index = first_free
188 ce9abd26 Christos Stavrakakis
            except IndexError:
189 ce9abd26 Christos Stavrakakis
                raise Exception("Can not create more than 16 backends")
190 3165f027 Christos Stavrakakis
191 bd87213f Christos Stavrakakis
    def use_hotplug(self):
192 bd87213f Christos Stavrakakis
        return self.hypervisor == "kvm" and snf_settings.GANETI_USE_HOTPLUG
193 bd87213f Christos Stavrakakis
194 bd87213f Christos Stavrakakis
    def get_create_params(self):
195 bd87213f Christos Stavrakakis
        params = deepcopy(snf_settings.GANETI_CREATEINSTANCE_KWARGS)
196 bd87213f Christos Stavrakakis
        params["hvparams"] = params.get("hvparams", {})\
197 bd87213f Christos Stavrakakis
                                   .get(self.hypervisor, {})
198 bd87213f Christos Stavrakakis
        return params
199 bd87213f Christos Stavrakakis
200 aed9b901 Christos Stavrakakis
201 fd65ab41 Christos Stavrakakis
# A backend job may be in one of the following possible states
202 fd65ab41 Christos Stavrakakis
BACKEND_STATUSES = (
203 fd65ab41 Christos Stavrakakis
    ('queued', 'request queued'),
204 fd65ab41 Christos Stavrakakis
    ('waiting', 'request waiting for locks'),
205 fd65ab41 Christos Stavrakakis
    ('canceling', 'request being canceled'),
206 fd65ab41 Christos Stavrakakis
    ('running', 'request running'),
207 fd65ab41 Christos Stavrakakis
    ('canceled', 'request canceled'),
208 fd65ab41 Christos Stavrakakis
    ('success', 'request completed successfully'),
209 fd65ab41 Christos Stavrakakis
    ('error', 'request returned error')
210 fd65ab41 Christos Stavrakakis
)
211 fd65ab41 Christos Stavrakakis
212 fd65ab41 Christos Stavrakakis
213 3416e629 Christos Stavrakakis
class QuotaHolderSerial(models.Model):
214 97fffe10 Christos Stavrakakis
    """Model representing a serial for a Quotaholder Commission.
215 97fffe10 Christos Stavrakakis

216 97fffe10 Christos Stavrakakis
    serial:   The serial that Quotaholder assigned to this commission
217 97fffe10 Christos Stavrakakis
    pending:  Whether it has been decided to accept or reject this commission
218 97fffe10 Christos Stavrakakis
    accept:   If pending is False, this attribute indicates whether to accept
219 97fffe10 Christos Stavrakakis
              or reject this commission
220 97fffe10 Christos Stavrakakis
    resolved: Whether this commission has been accepted or rejected to
221 97fffe10 Christos Stavrakakis
              Quotaholder.
222 97fffe10 Christos Stavrakakis

223 97fffe10 Christos Stavrakakis
    """
224 68b952f9 Christos Stavrakakis
    serial = models.BigIntegerField(null=False, primary_key=True,
225 68b952f9 Christos Stavrakakis
                                    db_index=True)
226 3416e629 Christos Stavrakakis
    pending = models.BooleanField(default=True, db_index=True)
227 97fffe10 Christos Stavrakakis
    accept = models.BooleanField(default=False)
228 97fffe10 Christos Stavrakakis
    resolved = models.BooleanField(default=False)
229 3416e629 Christos Stavrakakis
230 3416e629 Christos Stavrakakis
    class Meta:
231 3416e629 Christos Stavrakakis
        verbose_name = u'Quota Serial'
232 3416e629 Christos Stavrakakis
        ordering = ["serial"]
233 3416e629 Christos Stavrakakis
234 41a7fae7 Christos Stavrakakis
    def __unicode__(self):
235 41a7fae7 Christos Stavrakakis
        return u"<serial: %s>" % self.serial
236 41a7fae7 Christos Stavrakakis
237 3416e629 Christos Stavrakakis
238 07f3219d Vassilios Karakoidas
class VirtualMachine(models.Model):
239 c92af313 Vangelis Koukis
    # The list of possible actions for a VM
240 d08a5f6f Vangelis Koukis
    ACTIONS = (
241 68b952f9 Christos Stavrakakis
        ('CREATE', 'Create VM'),
242 68b952f9 Christos Stavrakakis
        ('START', 'Start VM'),
243 68b952f9 Christos Stavrakakis
        ('STOP', 'Shutdown VM'),
244 68b952f9 Christos Stavrakakis
        ('SUSPEND', 'Admin Suspend VM'),
245 68b952f9 Christos Stavrakakis
        ('REBOOT', 'Reboot VM'),
246 1af851fd Christos Stavrakakis
        ('DESTROY', 'Destroy VM'),
247 1af851fd Christos Stavrakakis
        ('RESIZE', 'Resize a VM'),
248 9ba6bb95 Christos Stavrakakis
        ('ADDFLOATINGIP', 'Add floating IP to VM'),
249 9ba6bb95 Christos Stavrakakis
        ('REMOVEFLOATINGIP', 'Add floating IP to VM'),
250 d08a5f6f Vangelis Koukis
    )
251 ce55f211 Kostas Papadimitriou
252 c92af313 Vangelis Koukis
    # The internal operating state of a VM
253 d08a5f6f Vangelis Koukis
    OPER_STATES = (
254 d08a5f6f Vangelis Koukis
        ('BUILD', 'Queued for creation'),
255 d08a5f6f Vangelis Koukis
        ('ERROR', 'Creation failed'),
256 d08a5f6f Vangelis Koukis
        ('STOPPED', 'Stopped'),
257 d08a5f6f Vangelis Koukis
        ('STARTED', 'Started'),
258 1af851fd Christos Stavrakakis
        ('DESTROYED', 'Destroyed'),
259 1af851fd Christos Stavrakakis
        ('RESIZE', 'Resizing')
260 d08a5f6f Vangelis Koukis
    )
261 ce55f211 Kostas Papadimitriou
262 c92af313 Vangelis Koukis
    # The list of possible operations on the backend
263 d08a5f6f Vangelis Koukis
    BACKEND_OPCODES = (
264 d08a5f6f Vangelis Koukis
        ('OP_INSTANCE_CREATE', 'Create Instance'),
265 d08a5f6f Vangelis Koukis
        ('OP_INSTANCE_REMOVE', 'Remove Instance'),
266 d08a5f6f Vangelis Koukis
        ('OP_INSTANCE_STARTUP', 'Startup Instance'),
267 d08a5f6f Vangelis Koukis
        ('OP_INSTANCE_SHUTDOWN', 'Shutdown Instance'),
268 26fef2b9 Vangelis Koukis
        ('OP_INSTANCE_REBOOT', 'Reboot Instance'),
269 26fef2b9 Vangelis Koukis
270 26fef2b9 Vangelis Koukis
        # These are listed here for completeness,
271 26fef2b9 Vangelis Koukis
        # and are ignored for the time being
272 26fef2b9 Vangelis Koukis
        ('OP_INSTANCE_SET_PARAMS', 'Set Instance Parameters'),
273 26fef2b9 Vangelis Koukis
        ('OP_INSTANCE_QUERY_DATA', 'Query Instance Data'),
274 21d8adbf Vangelis Koukis
        ('OP_INSTANCE_REINSTALL', 'Reinstall Instance'),
275 21d8adbf Vangelis Koukis
        ('OP_INSTANCE_ACTIVATE_DISKS', 'Activate Disks'),
276 21d8adbf Vangelis Koukis
        ('OP_INSTANCE_DEACTIVATE_DISKS', 'Deactivate Disks'),
277 21d8adbf Vangelis Koukis
        ('OP_INSTANCE_REPLACE_DISKS', 'Replace Disks'),
278 21d8adbf Vangelis Koukis
        ('OP_INSTANCE_MIGRATE', 'Migrate Instance'),
279 21d8adbf Vangelis Koukis
        ('OP_INSTANCE_CONSOLE', 'Get Instance Console'),
280 41303ed0 Vangelis Koukis
        ('OP_INSTANCE_RECREATE_DISKS', 'Recreate Disks'),
281 41303ed0 Vangelis Koukis
        ('OP_INSTANCE_FAILOVER', 'Failover Instance')
282 d08a5f6f Vangelis Koukis
    )
283 ce55f211 Kostas Papadimitriou
284 d08a5f6f Vangelis Koukis
    # The operating state of a VM,
285 d08a5f6f Vangelis Koukis
    # upon the successful completion of a backend operation.
286 21d8adbf Vangelis Koukis
    # IMPORTANT: Make sure all keys have a corresponding
287 21d8adbf Vangelis Koukis
    # entry in BACKEND_OPCODES if you update this field, see #1035, #1111.
288 d08a5f6f Vangelis Koukis
    OPER_STATE_FROM_OPCODE = {
289 d08a5f6f Vangelis Koukis
        'OP_INSTANCE_CREATE': 'STARTED',
290 d08a5f6f Vangelis Koukis
        'OP_INSTANCE_REMOVE': 'DESTROYED',
291 d08a5f6f Vangelis Koukis
        'OP_INSTANCE_STARTUP': 'STARTED',
292 d08a5f6f Vangelis Koukis
        'OP_INSTANCE_SHUTDOWN': 'STOPPED',
293 26fef2b9 Vangelis Koukis
        'OP_INSTANCE_REBOOT': 'STARTED',
294 26fef2b9 Vangelis Koukis
        'OP_INSTANCE_SET_PARAMS': None,
295 8490bf84 Georgios Gousios
        'OP_INSTANCE_QUERY_DATA': None,
296 1bce82c0 Christos Stavrakakis
        'OP_INSTANCE_REINSTALL': None,
297 1bce82c0 Christos Stavrakakis
        'OP_INSTANCE_ACTIVATE_DISKS': None,
298 8490bf84 Georgios Gousios
        'OP_INSTANCE_DEACTIVATE_DISKS': None,
299 1bce82c0 Christos Stavrakakis
        'OP_INSTANCE_REPLACE_DISKS': None,
300 8490bf84 Georgios Gousios
        'OP_INSTANCE_MIGRATE': None,
301 8490bf84 Georgios Gousios
        'OP_INSTANCE_CONSOLE': None,
302 41303ed0 Vangelis Koukis
        'OP_INSTANCE_RECREATE_DISKS': None,
303 41303ed0 Vangelis Koukis
        'OP_INSTANCE_FAILOVER': None
304 d08a5f6f Vangelis Koukis
    }
305 d08a5f6f Vangelis Koukis
306 c92af313 Vangelis Koukis
    # This dictionary contains the correspondence between
307 c92af313 Vangelis Koukis
    # internal operating states and Server States as defined
308 c92af313 Vangelis Koukis
    # by the Rackspace API.
309 d08a5f6f Vangelis Koukis
    RSAPI_STATE_FROM_OPER_STATE = {
310 d08a5f6f Vangelis Koukis
        "BUILD": "BUILD",
311 d08a5f6f Vangelis Koukis
        "ERROR": "ERROR",
312 d08a5f6f Vangelis Koukis
        "STOPPED": "STOPPED",
313 d08a5f6f Vangelis Koukis
        "STARTED": "ACTIVE",
314 41a7fae7 Christos Stavrakakis
        'RESIZE': 'RESIZE',
315 41a7fae7 Christos Stavrakakis
        'DESTROYED': 'DELETED',
316 d08a5f6f Vangelis Koukis
    }
317 d08a5f6f Vangelis Koukis
318 4daac449 Vassilios Karakoidas
    name = models.CharField('Virtual Machine Name', max_length=255)
319 190d155f Christos Stavrakakis
    userid = models.CharField('User ID of the owner', max_length=100,
320 e18c1749 Christos Stavrakakis
                              db_index=True, null=False)
321 aed9b901 Christos Stavrakakis
    backend = models.ForeignKey(Backend, null=True,
322 aed9b901 Christos Stavrakakis
                                related_name="virtual_machines",)
323 aed9b901 Christos Stavrakakis
    backend_hash = models.CharField(max_length=128, null=True, editable=False)
324 d174b105 Vassilios Karakoidas
    created = models.DateTimeField(auto_now_add=True)
325 d174b105 Vassilios Karakoidas
    updated = models.DateTimeField(auto_now=True)
326 936afb7b Giorgos Verigakis
    imageid = models.CharField(max_length=100, null=False)
327 22571df6 Vassilios Karakoidas
    hostid = models.CharField(max_length=100)
328 46547e14 Faidon Liambotis
    flavor = models.ForeignKey(Flavor)
329 190d155f Christos Stavrakakis
    deleted = models.BooleanField('Deleted', default=False, db_index=True)
330 9ff7ca6f Giorgos Verigakis
    suspended = models.BooleanField('Administratively Suspended',
331 244c552b Giorgos Verigakis
                                    default=False)
332 004967e4 Christos Stavrakakis
    serial = models.ForeignKey(QuotaHolderSerial,
333 68b952f9 Christos Stavrakakis
                               related_name='virtual_machine', null=True)
334 d08a5f6f Vangelis Koukis
335 ce55f211 Kostas Papadimitriou
    # VM State
336 52194743 Vangelis Koukis
    # The following fields are volatile data, in the sense
337 52194743 Vangelis Koukis
    # that they need not be persistent in the DB, but rather
338 52194743 Vangelis Koukis
    # get generated at runtime by quering Ganeti and applying
339 52194743 Vangelis Koukis
    # updates received from Ganeti.
340 ce55f211 Kostas Papadimitriou
341 73b2b65e Vassilios Karakoidas
    # In the future they could be moved to a separate caching layer
342 73b2b65e Vassilios Karakoidas
    # and removed from the database.
343 73b2b65e Vassilios Karakoidas
    # [vkoukis] after discussion with [faidon].
344 1cfd5d4d Christos Stavrakakis
    action = models.CharField(choices=ACTIONS, max_length=30, null=True,
345 1cfd5d4d Christos Stavrakakis
                              default=None)
346 1cfd5d4d Christos Stavrakakis
    operstate = models.CharField(choices=OPER_STATES, max_length=30,
347 1cfd5d4d Christos Stavrakakis
                                 null=False, default="BUILD")
348 dfd19c2d Vassilios Karakoidas
    backendjobid = models.PositiveIntegerField(null=True)
349 f533f224 Vangelis Koukis
    backendopcode = models.CharField(choices=BACKEND_OPCODES, max_length=30,
350 aed9b901 Christos Stavrakakis
                                     null=True)
351 9ff7ca6f Giorgos Verigakis
    backendjobstatus = models.CharField(choices=BACKEND_STATUSES,
352 aed9b901 Christos Stavrakakis
                                        max_length=30, null=True)
353 dfd19c2d Vassilios Karakoidas
    backendlogmsg = models.TextField(null=True)
354 19da4325 Vangelis Koukis
    buildpercentage = models.IntegerField(default=0)
355 c4e55622 Christos Stavrakakis
    backendtime = models.DateTimeField(default=datetime.datetime.min)
356 9068cd85 Georgios Gousios
357 41a7fae7 Christos Stavrakakis
    # Latest action and corresponding Ganeti job ID, for actions issued
358 41a7fae7 Christos Stavrakakis
    # by the API
359 41a7fae7 Christos Stavrakakis
    task = models.CharField(max_length=64, null=True)
360 41a7fae7 Christos Stavrakakis
    task_job_id = models.BigIntegerField(max_length=64, null=True)
361 41a7fae7 Christos Stavrakakis
362 7f2dbcad Christos Stavrakakis
    objects = ForUpdateManager()
363 7f2dbcad Christos Stavrakakis
364 3524241a Christos Stavrakakis
    def get_client(self):
365 3524241a Christos Stavrakakis
        if self.backend:
366 2cea7f38 Christos Stavrakakis
            return self.backend.get_client()
367 aed9b901 Christos Stavrakakis
        else:
368 bd40abfa Christos Stavrakakis
            raise faults.ServiceUnavailable
369 aed9b901 Christos Stavrakakis
370 6ce1fc56 Kostas Papadimitriou
    def get_last_diagnostic(self, **filters):
371 6ce1fc56 Kostas Papadimitriou
        try:
372 6ce1fc56 Kostas Papadimitriou
            return self.diagnostics.filter()[0]
373 6ce1fc56 Kostas Papadimitriou
        except IndexError:
374 6ce1fc56 Kostas Papadimitriou
            return None
375 6ce1fc56 Kostas Papadimitriou
376 3524241a Christos Stavrakakis
    @staticmethod
377 3524241a Christos Stavrakakis
    def put_client(client):
378 3524241a Christos Stavrakakis
            put_rapi_client(client)
379 3524241a Christos Stavrakakis
380 aed9b901 Christos Stavrakakis
    def save(self, *args, **kwargs):
381 aed9b901 Christos Stavrakakis
        # Store hash for first time saved vm
382 aed9b901 Christos Stavrakakis
        if (self.id is None or self.backend_hash == '') and self.backend:
383 aed9b901 Christos Stavrakakis
            self.backend_hash = self.backend.hash
384 aed9b901 Christos Stavrakakis
        super(VirtualMachine, self).save(*args, **kwargs)
385 aed9b901 Christos Stavrakakis
386 9ff7ca6f Giorgos Verigakis
    @property
387 924d8085 Christos Stavrakakis
    def backend_vm_id(self):
388 224b5e19 Markos Gogoulos
        """Returns the backend id for this VM by prepending backend-prefix."""
389 76ba77c1 Vangelis Koukis
        if not self.id:
390 76ba77c1 Vangelis Koukis
            raise VirtualMachine.InvalidBackendIdError("self.id is None")
391 d30f29aa Christos Stavrakakis
        return "%s%s" % (settings.BACKEND_PREFIX_ID, str(self.id))
392 ce55f211 Kostas Papadimitriou
393 d08a5f6f Vangelis Koukis
    class Meta:
394 d08a5f6f Vangelis Koukis
        verbose_name = u'Virtual machine instance'
395 d08a5f6f Vangelis Koukis
        get_latest_by = 'created'
396 ce55f211 Kostas Papadimitriou
397 d08a5f6f Vangelis Koukis
    def __unicode__(self):
398 cfd70896 Christos Stavrakakis
        return str(self.id)
399 d08a5f6f Vangelis Koukis
400 048fab1e Christos Stavrakakis
    # Error classes
401 048fab1e Christos Stavrakakis
    class InvalidBackendIdError(Exception):
402 048fab1e Christos Stavrakakis
        def __init__(self, value):
403 048fab1e Christos Stavrakakis
            self.value = value
404 048fab1e Christos Stavrakakis
405 048fab1e Christos Stavrakakis
        def __str__(self):
406 048fab1e Christos Stavrakakis
            return repr(self.value)
407 048fab1e Christos Stavrakakis
408 048fab1e Christos Stavrakakis
    class InvalidBackendMsgError(Exception):
409 048fab1e Christos Stavrakakis
        def __init__(self, opcode, status):
410 048fab1e Christos Stavrakakis
            self.opcode = opcode
411 048fab1e Christos Stavrakakis
            self.status = status
412 048fab1e Christos Stavrakakis
413 048fab1e Christos Stavrakakis
        def __str__(self):
414 048fab1e Christos Stavrakakis
            return repr('<opcode: %s, status: %s>' % (self.opcode,
415 048fab1e Christos Stavrakakis
                        self.status))
416 048fab1e Christos Stavrakakis
417 048fab1e Christos Stavrakakis
    class InvalidActionError(Exception):
418 048fab1e Christos Stavrakakis
        def __init__(self, action):
419 048fab1e Christos Stavrakakis
            self._action = action
420 048fab1e Christos Stavrakakis
421 048fab1e Christos Stavrakakis
        def __str__(self):
422 048fab1e Christos Stavrakakis
            return repr(str(self._action))
423 048fab1e Christos Stavrakakis
424 4ffb82dc Vassilios Karakoidas
425 be7b8d37 Vassilios Karakoidas
class VirtualMachineMetadata(models.Model):
426 be7b8d37 Vassilios Karakoidas
    meta_key = models.CharField(max_length=50)
427 be7b8d37 Vassilios Karakoidas
    meta_value = models.CharField(max_length=500)
428 7cc3c7d9 Giorgos Verigakis
    vm = models.ForeignKey(VirtualMachine, related_name='metadata')
429 ce55f211 Kostas Papadimitriou
430 be7b8d37 Vassilios Karakoidas
    class Meta:
431 1bd24df6 Giorgos Verigakis
        unique_together = (('meta_key', 'vm'),)
432 dcfc6c2d Vangelis Koukis
        verbose_name = u'Key-value pair of metadata for a VM.'
433 ce55f211 Kostas Papadimitriou
434 be7b8d37 Vassilios Karakoidas
    def __unicode__(self):
435 9ff7ca6f Giorgos Verigakis
        return u'%s: %s' % (self.meta_key, self.meta_value)
436 be7b8d37 Vassilios Karakoidas
437 be7b8d37 Vassilios Karakoidas
438 0269afd6 Giorgos Verigakis
class Network(models.Model):
439 e6a42a96 Christos Stavrakakis
    OPER_STATES = (
440 99af08a4 Christos Stavrakakis
        ('PENDING', 'Pending'),  # Unused because of lazy networks
441 f533f224 Vangelis Koukis
        ('ACTIVE', 'Active'),
442 e6a42a96 Christos Stavrakakis
        ('DELETED', 'Deleted'),
443 e6a42a96 Christos Stavrakakis
        ('ERROR', 'Error')
444 e6a42a96 Christos Stavrakakis
    )
445 e6a42a96 Christos Stavrakakis
446 e6a42a96 Christos Stavrakakis
    ACTIONS = (
447 68b952f9 Christos Stavrakakis
        ('CREATE', 'Create Network'),
448 68b952f9 Christos Stavrakakis
        ('DESTROY', 'Destroy Network'),
449 ece5581b Christos Stavrakakis
        ('ADD', 'Add server to Network'),
450 ece5581b Christos Stavrakakis
        ('REMOVE', 'Remove server from Network'),
451 e6a42a96 Christos Stavrakakis
    )
452 e6a42a96 Christos Stavrakakis
453 e6a42a96 Christos Stavrakakis
    RSAPI_STATE_FROM_OPER_STATE = {
454 e6a42a96 Christos Stavrakakis
        'PENDING': 'PENDING',
455 e6a42a96 Christos Stavrakakis
        'ACTIVE': 'ACTIVE',
456 e6a42a96 Christos Stavrakakis
        'DELETED': 'DELETED',
457 e6a42a96 Christos Stavrakakis
        'ERROR': 'ERROR'
458 e6a42a96 Christos Stavrakakis
    }
459 e6a42a96 Christos Stavrakakis
460 b7d38981 Dimitris Aragiorgis
    FLAVORS = {
461 b7d38981 Dimitris Aragiorgis
        'CUSTOM': {
462 68b952f9 Christos Stavrakakis
            'mode': 'bridged',
463 68b952f9 Christos Stavrakakis
            'link': settings.DEFAULT_BRIDGE,
464 68b952f9 Christos Stavrakakis
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
465 68b952f9 Christos Stavrakakis
            'tags': None,
466 68b952f9 Christos Stavrakakis
            'desc': "Basic flavor used for a bridged network",
467 b7d38981 Dimitris Aragiorgis
        },
468 b7d38981 Dimitris Aragiorgis
        'IP_LESS_ROUTED': {
469 68b952f9 Christos Stavrakakis
            'mode': 'routed',
470 68b952f9 Christos Stavrakakis
            'link': settings.DEFAULT_ROUTING_TABLE,
471 68b952f9 Christos Stavrakakis
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
472 68b952f9 Christos Stavrakakis
            'tags': 'ip-less-routed',
473 68b952f9 Christos Stavrakakis
            'desc': "Flavor used for an IP-less routed network using"
474 68b952f9 Christos Stavrakakis
                    " Proxy ARP",
475 b7d38981 Dimitris Aragiorgis
        },
476 b7d38981 Dimitris Aragiorgis
        'MAC_FILTERED': {
477 68b952f9 Christos Stavrakakis
            'mode': 'bridged',
478 68b952f9 Christos Stavrakakis
            'link': settings.DEFAULT_MAC_FILTERED_BRIDGE,
479 68b952f9 Christos Stavrakakis
            'mac_prefix': 'pool',
480 68b952f9 Christos Stavrakakis
            'tags': 'private-filtered',
481 68b952f9 Christos Stavrakakis
            'desc': "Flavor used for bridged networks that offer isolation"
482 68b952f9 Christos Stavrakakis
                    " via filtering packets based on their src "
483 68b952f9 Christos Stavrakakis
                    " MAC (ebtables)",
484 b7d38981 Dimitris Aragiorgis
        },
485 b7d38981 Dimitris Aragiorgis
        'PHYSICAL_VLAN': {
486 68b952f9 Christos Stavrakakis
            'mode': 'bridged',
487 68b952f9 Christos Stavrakakis
            'link': 'pool',
488 68b952f9 Christos Stavrakakis
            'mac_prefix': settings.DEFAULT_MAC_PREFIX,
489 68b952f9 Christos Stavrakakis
            'tags': 'physical-vlan',
490 68b952f9 Christos Stavrakakis
            'desc': "Flavor used for bridged network that offer isolation"
491 68b952f9 Christos Stavrakakis
                    " via dedicated physical vlan",
492 b7d38981 Dimitris Aragiorgis
        },
493 b7d38981 Dimitris Aragiorgis
    }
494 ce55f211 Kostas Papadimitriou
495 e6a42a96 Christos Stavrakakis
    name = models.CharField('Network Name', max_length=128)
496 190d155f Christos Stavrakakis
    userid = models.CharField('User ID of the owner', max_length=128,
497 190d155f Christos Stavrakakis
                              null=True, db_index=True)
498 e6a42a96 Christos Stavrakakis
    subnet = models.CharField('Subnet', max_length=32, default='10.0.0.0/24')
499 cc3f266e Christos Stavrakakis
    subnet6 = models.CharField('IPv6 Subnet', max_length=64, null=True)
500 e6a42a96 Christos Stavrakakis
    gateway = models.CharField('Gateway', max_length=32, null=True)
501 cc3f266e Christos Stavrakakis
    gateway6 = models.CharField('IPv6 Gateway', max_length=64, null=True)
502 e6a42a96 Christos Stavrakakis
    dhcp = models.BooleanField('DHCP', default=True)
503 b7d38981 Dimitris Aragiorgis
    flavor = models.CharField('Flavor', max_length=32, null=False)
504 b7d38981 Dimitris Aragiorgis
    mode = models.CharField('Network Mode', max_length=16, null=True)
505 b7d38981 Dimitris Aragiorgis
    link = models.CharField('Network Link', max_length=32, null=True)
506 3165f027 Christos Stavrakakis
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=False)
507 b7d38981 Dimitris Aragiorgis
    tags = models.CharField('Network Tags', max_length=128, null=True)
508 190d155f Christos Stavrakakis
    public = models.BooleanField(default=False, db_index=True)
509 0269afd6 Giorgos Verigakis
    created = models.DateTimeField(auto_now_add=True)
510 0269afd6 Giorgos Verigakis
    updated = models.DateTimeField(auto_now=True)
511 190d155f Christos Stavrakakis
    deleted = models.BooleanField('Deleted', default=False, db_index=True)
512 fd65ab41 Christos Stavrakakis
    state = models.CharField(choices=OPER_STATES, max_length=32,
513 fd65ab41 Christos Stavrakakis
                             default='PENDING')
514 f533f224 Vangelis Koukis
    machines = models.ManyToManyField(VirtualMachine,
515 244c552b Giorgos Verigakis
                                      through='NetworkInterface')
516 fd65ab41 Christos Stavrakakis
    action = models.CharField(choices=ACTIONS, max_length=32, null=True,
517 fd65ab41 Christos Stavrakakis
                              default=None)
518 6dafedf6 Christos Stavrakakis
    drained = models.BooleanField("Drained", default=False, null=False)
519 9115d567 Christos Stavrakakis
    floating_ip_pool = models.BooleanField('Floating IP Pool', null=False,
520 9115d567 Christos Stavrakakis
                                          default=False)
521 fdc94944 Christos Stavrakakis
    pool = models.OneToOneField('IPPoolTable', related_name='network',
522 941992c4 Christos Stavrakakis
                default=lambda: IPPoolTable.objects.create(available_map='',
523 941992c4 Christos Stavrakakis
                                                           reserved_map='',
524 941992c4 Christos Stavrakakis
                                                           size=0),
525 941992c4 Christos Stavrakakis
                null=True)
526 004967e4 Christos Stavrakakis
    serial = models.ForeignKey(QuotaHolderSerial, related_name='network',
527 004967e4 Christos Stavrakakis
                               null=True)
528 77f0fa63 Christos Stavrakakis
529 864bed43 Christos Stavrakakis
    objects = ForUpdateManager()
530 77f0fa63 Christos Stavrakakis
531 cfd70896 Christos Stavrakakis
    def __unicode__(self):
532 cfd70896 Christos Stavrakakis
        return str(self.id)
533 cfd70896 Christos Stavrakakis
534 e6a42a96 Christos Stavrakakis
    @property
535 e6a42a96 Christos Stavrakakis
    def backend_id(self):
536 fd65ab41 Christos Stavrakakis
        """Return the backend id by prepending backend-prefix."""
537 e6a42a96 Christos Stavrakakis
        if not self.id:
538 e6a42a96 Christos Stavrakakis
            raise Network.InvalidBackendIdError("self.id is None")
539 d30f29aa Christos Stavrakakis
        return "%snet-%s" % (settings.BACKEND_PREFIX_ID, str(self.id))
540 e6a42a96 Christos Stavrakakis
541 e6a42a96 Christos Stavrakakis
    @property
542 e6a42a96 Christos Stavrakakis
    def backend_tag(self):
543 e6a42a96 Christos Stavrakakis
        """Return the network tag to be used in backend
544 e6a42a96 Christos Stavrakakis

545 e6a42a96 Christos Stavrakakis
        """
546 b7d38981 Dimitris Aragiorgis
        if self.tags:
547 b7d38981 Dimitris Aragiorgis
            return self.tags.split(',')
548 b7d38981 Dimitris Aragiorgis
        else:
549 b7d38981 Dimitris Aragiorgis
            return []
550 e6a42a96 Christos Stavrakakis
551 7cfbbf32 Christos Stavrakakis
    def create_backend_network(self, backend=None):
552 7cfbbf32 Christos Stavrakakis
        """Create corresponding BackendNetwork entries."""
553 7cfbbf32 Christos Stavrakakis
554 0816cd46 Christos Stavrakakis
        backends = [backend] if backend\
555 0816cd46 Christos Stavrakakis
                             else Backend.objects.filter(offline=False)
556 7cfbbf32 Christos Stavrakakis
        for backend in backends:
557 68b952f9 Christos Stavrakakis
            backend_exists =\
558 68b952f9 Christos Stavrakakis
                BackendNetwork.objects.filter(backend=backend, network=self)\
559 68b952f9 Christos Stavrakakis
                                      .exists()
560 68b952f9 Christos Stavrakakis
            if not backend_exists:
561 ce9abd26 Christos Stavrakakis
                BackendNetwork.objects.create(backend=backend, network=self)
562 fd65ab41 Christos Stavrakakis
563 fdc94944 Christos Stavrakakis
    def get_pool(self):
564 3718c0f1 Christos Stavrakakis
        if not self.pool_id:
565 3718c0f1 Christos Stavrakakis
            self.pool = IPPoolTable.objects.create(available_map='',
566 3718c0f1 Christos Stavrakakis
                                                   reserved_map='',
567 3718c0f1 Christos Stavrakakis
                                                   size=0)
568 3718c0f1 Christos Stavrakakis
            self.save()
569 048fab1e Christos Stavrakakis
        return IPPoolTable.objects.select_for_update().get(id=self.pool_id)\
570 048fab1e Christos Stavrakakis
                                                      .pool
571 77f0fa63 Christos Stavrakakis
572 fdc94944 Christos Stavrakakis
    def reserve_address(self, address):
573 fdc94944 Christos Stavrakakis
        pool = self.get_pool()
574 77f0fa63 Christos Stavrakakis
        pool.reserve(address)
575 fdc94944 Christos Stavrakakis
        pool.save()
576 77f0fa63 Christos Stavrakakis
577 fdc94944 Christos Stavrakakis
    def release_address(self, address):
578 fdc94944 Christos Stavrakakis
        pool = self.get_pool()
579 fdc94944 Christos Stavrakakis
        pool.put(address)
580 fdc94944 Christos Stavrakakis
        pool.save()
581 77f0fa63 Christos Stavrakakis
582 048fab1e Christos Stavrakakis
    class InvalidBackendIdError(Exception):
583 048fab1e Christos Stavrakakis
        def __init__(self, value):
584 048fab1e Christos Stavrakakis
            self.value = value
585 048fab1e Christos Stavrakakis
586 048fab1e Christos Stavrakakis
        def __str__(self):
587 048fab1e Christos Stavrakakis
            return repr(self.value)
588 048fab1e Christos Stavrakakis
589 048fab1e Christos Stavrakakis
    class InvalidBackendMsgError(Exception):
590 048fab1e Christos Stavrakakis
        def __init__(self, opcode, status):
591 048fab1e Christos Stavrakakis
            self.opcode = opcode
592 048fab1e Christos Stavrakakis
            self.status = status
593 048fab1e Christos Stavrakakis
594 048fab1e Christos Stavrakakis
        def __str__(self):
595 68b952f9 Christos Stavrakakis
            return repr('<opcode: %s, status: %s>'
596 68b952f9 Christos Stavrakakis
                        % (self.opcode, self.status))
597 048fab1e Christos Stavrakakis
598 048fab1e Christos Stavrakakis
    class InvalidActionError(Exception):
599 048fab1e Christos Stavrakakis
        def __init__(self, action):
600 048fab1e Christos Stavrakakis
            self._action = action
601 048fab1e Christos Stavrakakis
602 048fab1e Christos Stavrakakis
        def __str__(self):
603 048fab1e Christos Stavrakakis
            return repr(str(self._action))
604 048fab1e Christos Stavrakakis
605 864bed43 Christos Stavrakakis
606 fd65ab41 Christos Stavrakakis
class BackendNetwork(models.Model):
607 fd65ab41 Christos Stavrakakis
    OPER_STATES = (
608 fd65ab41 Christos Stavrakakis
        ('PENDING', 'Pending'),
609 fd65ab41 Christos Stavrakakis
        ('ACTIVE', 'Active'),
610 fd65ab41 Christos Stavrakakis
        ('DELETED', 'Deleted'),
611 fd65ab41 Christos Stavrakakis
        ('ERROR', 'Error')
612 fd65ab41 Christos Stavrakakis
    )
613 fd65ab41 Christos Stavrakakis
614 fd65ab41 Christos Stavrakakis
    # The list of possible operations on the backend
615 fd65ab41 Christos Stavrakakis
    BACKEND_OPCODES = (
616 fd65ab41 Christos Stavrakakis
        ('OP_NETWORK_ADD', 'Create Network'),
617 fd65ab41 Christos Stavrakakis
        ('OP_NETWORK_CONNECT', 'Activate Network'),
618 fd65ab41 Christos Stavrakakis
        ('OP_NETWORK_DISCONNECT', 'Deactivate Network'),
619 fd65ab41 Christos Stavrakakis
        ('OP_NETWORK_REMOVE', 'Remove Network'),
620 fd65ab41 Christos Stavrakakis
        # These are listed here for completeness,
621 fd65ab41 Christos Stavrakakis
        # and are ignored for the time being
622 fd65ab41 Christos Stavrakakis
        ('OP_NETWORK_SET_PARAMS', 'Set Network Parameters'),
623 fd65ab41 Christos Stavrakakis
        ('OP_NETWORK_QUERY_DATA', 'Query Network Data')
624 fd65ab41 Christos Stavrakakis
    )
625 fd65ab41 Christos Stavrakakis
626 fd65ab41 Christos Stavrakakis
    # The operating state of a Netowork,
627 fd65ab41 Christos Stavrakakis
    # upon the successful completion of a backend operation.
628 fd65ab41 Christos Stavrakakis
    # IMPORTANT: Make sure all keys have a corresponding
629 fd65ab41 Christos Stavrakakis
    # entry in BACKEND_OPCODES if you update this field, see #1035, #1111.
630 fd65ab41 Christos Stavrakakis
    OPER_STATE_FROM_OPCODE = {
631 fd65ab41 Christos Stavrakakis
        'OP_NETWORK_ADD': 'PENDING',
632 fd65ab41 Christos Stavrakakis
        'OP_NETWORK_CONNECT': 'ACTIVE',
633 fd65ab41 Christos Stavrakakis
        'OP_NETWORK_DISCONNECT': 'PENDING',
634 fd65ab41 Christos Stavrakakis
        'OP_NETWORK_REMOVE': 'DELETED',
635 fd65ab41 Christos Stavrakakis
        'OP_NETWORK_SET_PARAMS': None,
636 fd65ab41 Christos Stavrakakis
        'OP_NETWORK_QUERY_DATA': None
637 fd65ab41 Christos Stavrakakis
    }
638 fd65ab41 Christos Stavrakakis
639 fd65ab41 Christos Stavrakakis
    network = models.ForeignKey(Network, related_name='backend_networks')
640 fd65ab41 Christos Stavrakakis
    backend = models.ForeignKey(Backend, related_name='networks')
641 fd65ab41 Christos Stavrakakis
    created = models.DateTimeField(auto_now_add=True)
642 fd65ab41 Christos Stavrakakis
    updated = models.DateTimeField(auto_now=True)
643 fd65ab41 Christos Stavrakakis
    deleted = models.BooleanField('Deleted', default=False)
644 3165f027 Christos Stavrakakis
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=False)
645 fd65ab41 Christos Stavrakakis
    operstate = models.CharField(choices=OPER_STATES, max_length=30,
646 fd65ab41 Christos Stavrakakis
                                 default='PENDING')
647 fd65ab41 Christos Stavrakakis
    backendjobid = models.PositiveIntegerField(null=True)
648 fd65ab41 Christos Stavrakakis
    backendopcode = models.CharField(choices=BACKEND_OPCODES, max_length=30,
649 fd65ab41 Christos Stavrakakis
                                     null=True)
650 fd65ab41 Christos Stavrakakis
    backendjobstatus = models.CharField(choices=BACKEND_STATUSES,
651 fd65ab41 Christos Stavrakakis
                                        max_length=30, null=True)
652 fd65ab41 Christos Stavrakakis
    backendlogmsg = models.TextField(null=True)
653 fd65ab41 Christos Stavrakakis
    backendtime = models.DateTimeField(null=False,
654 fd65ab41 Christos Stavrakakis
                                       default=datetime.datetime.min)
655 fd65ab41 Christos Stavrakakis
656 7cfbbf32 Christos Stavrakakis
    class Meta:
657 7cfbbf32 Christos Stavrakakis
        # Ensure one entry for each network in each backend
658 7cfbbf32 Christos Stavrakakis
        unique_together = (("network", "backend"))
659 7cfbbf32 Christos Stavrakakis
660 3165f027 Christos Stavrakakis
    def __init__(self, *args, **kwargs):
661 3165f027 Christos Stavrakakis
        """Initialize state for just created BackendNetwork instances."""
662 3165f027 Christos Stavrakakis
        super(BackendNetwork, self).__init__(*args, **kwargs)
663 3165f027 Christos Stavrakakis
        if not self.mac_prefix:
664 3165f027 Christos Stavrakakis
            # Generate the MAC prefix of the BackendNetwork, by combining
665 3165f027 Christos Stavrakakis
            # the Network prefix with the index of the Backend
666 3165f027 Christos Stavrakakis
            net_prefix = self.network.mac_prefix
667 3165f027 Christos Stavrakakis
            backend_suffix = hex(self.backend.index).replace('0x', '')
668 3165f027 Christos Stavrakakis
            mac_prefix = net_prefix + backend_suffix
669 3165f027 Christos Stavrakakis
            try:
670 3165f027 Christos Stavrakakis
                utils.validate_mac(mac_prefix + ":00:00:00")
671 3165f027 Christos Stavrakakis
            except utils.InvalidMacAddress:
672 68b952f9 Christos Stavrakakis
                raise utils.InvalidMacAddress("Invalid MAC prefix '%s'" %
673 68b952f9 Christos Stavrakakis
                                              mac_prefix)
674 3165f027 Christos Stavrakakis
            self.mac_prefix = mac_prefix
675 3165f027 Christos Stavrakakis
676 99af08a4 Christos Stavrakakis
    def __unicode__(self):
677 99af08a4 Christos Stavrakakis
        return '<%s@%s>' % (self.network, self.backend)
678 99af08a4 Christos Stavrakakis
679 f533f224 Vangelis Koukis
680 f533f224 Vangelis Koukis
class NetworkInterface(models.Model):
681 f533f224 Vangelis Koukis
    FIREWALL_PROFILES = (
682 f533f224 Vangelis Koukis
        ('ENABLED', 'Enabled'),
683 26563957 Giorgos Verigakis
        ('DISABLED', 'Disabled'),
684 26563957 Giorgos Verigakis
        ('PROTECTED', 'Protected')
685 f533f224 Vangelis Koukis
    )
686 ce55f211 Kostas Papadimitriou
687 939d71dd Christos Stavrakakis
    STATES = (
688 939d71dd Christos Stavrakakis
        ("ACTIVE", "Active"),
689 939d71dd Christos Stavrakakis
        ("BUILDING", "Building"),
690 939d71dd Christos Stavrakakis
    )
691 939d71dd Christos Stavrakakis
692 f533f224 Vangelis Koukis
    machine = models.ForeignKey(VirtualMachine, related_name='nics')
693 f533f224 Vangelis Koukis
    network = models.ForeignKey(Network, related_name='nics')
694 f533f224 Vangelis Koukis
    created = models.DateTimeField(auto_now_add=True)
695 f533f224 Vangelis Koukis
    updated = models.DateTimeField(auto_now=True)
696 3b56bbe4 Christos Stavrakakis
    index = models.IntegerField(null=False)
697 939d71dd Christos Stavrakakis
    mac = models.CharField(max_length=32, null=True, unique=True)
698 f533f224 Vangelis Koukis
    ipv4 = models.CharField(max_length=15, null=True)
699 f533f224 Vangelis Koukis
    ipv6 = models.CharField(max_length=100, null=True)
700 f533f224 Vangelis Koukis
    firewall_profile = models.CharField(choices=FIREWALL_PROFILES,
701 244c552b Giorgos Verigakis
                                        max_length=30, null=True)
702 0196d9a3 Christos Stavrakakis
    dirty = models.BooleanField(default=False)
703 ef54eee4 Christos Stavrakakis
    state = models.CharField(max_length=32, null=False, default="ACTIVE",
704 939d71dd Christos Stavrakakis
                             choices=STATES)
705 ce55f211 Kostas Papadimitriou
706 2987cd8a Giorgos Verigakis
    def __unicode__(self):
707 bc343480 Christos Stavrakakis
        return "<%s:vm:%s network:%s ipv4:%s ipv6:%s>" % \
708 bc343480 Christos Stavrakakis
            (self.index, self.machine_id, self.network_id, self.ipv4,
709 bc343480 Christos Stavrakakis
             self.ipv6)
710 f533f224 Vangelis Koukis
711 0c50c760 Christos Stavrakakis
    @property
712 0c50c760 Christos Stavrakakis
    def is_floating_ip(self):
713 0c50c760 Christos Stavrakakis
        network = self.network
714 0c50c760 Christos Stavrakakis
        if self.ipv4 and network.floating_ip_pool:
715 0c50c760 Christos Stavrakakis
            return network.floating_ips.filter(machine=self.machine,
716 0c50c760 Christos Stavrakakis
                                               ipv4=self.ipv4,
717 0c50c760 Christos Stavrakakis
                                               deleted=False).exists()
718 0c50c760 Christos Stavrakakis
        return False
719 0c50c760 Christos Stavrakakis
720 f533f224 Vangelis Koukis
721 c2876228 Christos Stavrakakis
class FloatingIP(models.Model):
722 c2876228 Christos Stavrakakis
    userid = models.CharField("UUID of the owner", max_length=128,
723 c2876228 Christos Stavrakakis
                              null=False, db_index=True)
724 c2876228 Christos Stavrakakis
    ipv4 = models.IPAddressField(null=False, unique=True, db_index=True)
725 c2876228 Christos Stavrakakis
    network = models.ForeignKey(Network, related_name="floating_ips",
726 c2876228 Christos Stavrakakis
                                null=False)
727 c2876228 Christos Stavrakakis
    machine = models.ForeignKey(VirtualMachine, related_name="floating_ips",
728 c2876228 Christos Stavrakakis
                                null=True)
729 c2876228 Christos Stavrakakis
    created = models.DateTimeField(auto_now_add=True)
730 c2876228 Christos Stavrakakis
    deleted = models.BooleanField(default=False, null=False)
731 c2876228 Christos Stavrakakis
    serial = models.ForeignKey(QuotaHolderSerial,
732 c2876228 Christos Stavrakakis
                               related_name="floating_ips", null=True)
733 c2876228 Christos Stavrakakis
734 c2876228 Christos Stavrakakis
    objects = ForUpdateManager()
735 c2876228 Christos Stavrakakis
736 c2876228 Christos Stavrakakis
    def __unicode__(self):
737 c2876228 Christos Stavrakakis
        return "<%s@%s>" % (self.ipv4, self.network.id)
738 c2876228 Christos Stavrakakis
739 c2876228 Christos Stavrakakis
    def in_use(self):
740 c2876228 Christos Stavrakakis
        if self.machine is None:
741 c2876228 Christos Stavrakakis
            return False
742 c2876228 Christos Stavrakakis
        else:
743 c2876228 Christos Stavrakakis
            return (not self.machine.deleted)
744 c2876228 Christos Stavrakakis
745 c2876228 Christos Stavrakakis
746 03992c72 Christos Stavrakakis
class PoolTable(models.Model):
747 03992c72 Christos Stavrakakis
    available_map = models.TextField(default="", null=False)
748 03992c72 Christos Stavrakakis
    reserved_map = models.TextField(default="", null=False)
749 03992c72 Christos Stavrakakis
    size = models.IntegerField(null=False)
750 e1334eb6 Christos Stavrakakis
751 03992c72 Christos Stavrakakis
    # Optional Fields
752 03992c72 Christos Stavrakakis
    base = models.CharField(null=True, max_length=32)
753 03992c72 Christos Stavrakakis
    offset = models.IntegerField(null=True)
754 ce55f211 Kostas Papadimitriou
755 e1334eb6 Christos Stavrakakis
    objects = ForUpdateManager()
756 e1334eb6 Christos Stavrakakis
757 e6a42a96 Christos Stavrakakis
    class Meta:
758 e6a42a96 Christos Stavrakakis
        abstract = True
759 e6a42a96 Christos Stavrakakis
760 e6a42a96 Christos Stavrakakis
    @classmethod
761 03992c72 Christos Stavrakakis
    def get_pool(cls):
762 e6a42a96 Christos Stavrakakis
        try:
763 21c9042c Christos Stavrakakis
            pool_row = cls.objects.select_for_update().get()
764 03992c72 Christos Stavrakakis
            return pool_row.pool
765 3bdfc1be Christos Stavrakakis
        except cls.DoesNotExist:
766 03992c72 Christos Stavrakakis
            raise pools.EmptyPool
767 e6a42a96 Christos Stavrakakis
768 03992c72 Christos Stavrakakis
    @property
769 03992c72 Christos Stavrakakis
    def pool(self):
770 03992c72 Christos Stavrakakis
        return self.manager(self)
771 e6a42a96 Christos Stavrakakis
772 e6a42a96 Christos Stavrakakis
773 03992c72 Christos Stavrakakis
class BridgePoolTable(PoolTable):
774 03992c72 Christos Stavrakakis
    manager = pools.BridgePool
775 e6a42a96 Christos Stavrakakis
776 fdc94944 Christos Stavrakakis
777 03992c72 Christos Stavrakakis
class MacPrefixPoolTable(PoolTable):
778 03992c72 Christos Stavrakakis
    manager = pools.MacPrefixPool
779 fdc94944 Christos Stavrakakis
780 fdc94944 Christos Stavrakakis
781 fdc94944 Christos Stavrakakis
class IPPoolTable(PoolTable):
782 fdc94944 Christos Stavrakakis
    manager = pools.IPPool
783 3524241a Christos Stavrakakis
784 3524241a Christos Stavrakakis
785 3524241a Christos Stavrakakis
@contextmanager
786 3524241a Christos Stavrakakis
def pooled_rapi_client(obj):
787 3524241a Christos Stavrakakis
        if isinstance(obj, VirtualMachine):
788 3524241a Christos Stavrakakis
            backend = obj.backend
789 3524241a Christos Stavrakakis
        else:
790 3524241a Christos Stavrakakis
            backend = obj
791 3524241a Christos Stavrakakis
792 3524241a Christos Stavrakakis
        if backend.offline:
793 99af08a4 Christos Stavrakakis
            log.warning("Trying to connect with offline backend: %s", backend)
794 bd40abfa Christos Stavrakakis
            raise faults.ServiceUnavailable
795 3524241a Christos Stavrakakis
796 3524241a Christos Stavrakakis
        b = backend
797 3524241a Christos Stavrakakis
        client = get_rapi_client(b.id, b.hash, b.clustername, b.port,
798 3524241a Christos Stavrakakis
                                 b.username, b.password)
799 4216cd83 Christos Stavrakakis
        try:
800 4216cd83 Christos Stavrakakis
            yield client
801 4216cd83 Christos Stavrakakis
        finally:
802 4216cd83 Christos Stavrakakis
            put_rapi_client(client)
803 6ce1fc56 Kostas Papadimitriou
804 6ce1fc56 Kostas Papadimitriou
805 6ce1fc56 Kostas Papadimitriou
class VirtualMachineDiagnosticManager(models.Manager):
806 6ce1fc56 Kostas Papadimitriou
    """
807 6ce1fc56 Kostas Papadimitriou
    Custom manager for :class:`VirtualMachineDiagnostic` model.
808 6ce1fc56 Kostas Papadimitriou
    """
809 6ce1fc56 Kostas Papadimitriou
810 6ce1fc56 Kostas Papadimitriou
    # diagnostic creation helpers
811 6ce1fc56 Kostas Papadimitriou
    def create_for_vm(self, vm, level, message, **kwargs):
812 6ce1fc56 Kostas Papadimitriou
        attrs = {'machine': vm, 'level': level, 'message': message}
813 6ce1fc56 Kostas Papadimitriou
        attrs.update(kwargs)
814 6ce1fc56 Kostas Papadimitriou
        # update instance updated time
815 6ce1fc56 Kostas Papadimitriou
        self.create(**attrs)
816 6ce1fc56 Kostas Papadimitriou
        vm.save()
817 6ce1fc56 Kostas Papadimitriou
818 6ce1fc56 Kostas Papadimitriou
    def create_error(self, vm, **kwargs):
819 6ce1fc56 Kostas Papadimitriou
        self.create_for_vm(vm, 'ERROR', **kwargs)
820 6ce1fc56 Kostas Papadimitriou
821 6ce1fc56 Kostas Papadimitriou
    def create_debug(self, vm, **kwargs):
822 6ce1fc56 Kostas Papadimitriou
        self.create_for_vm(vm, 'DEBUG', **kwargs)
823 6ce1fc56 Kostas Papadimitriou
824 6ce1fc56 Kostas Papadimitriou
    def since(self, vm, created_since, **kwargs):
825 6ce1fc56 Kostas Papadimitriou
        return self.get_query_set().filter(vm=vm, created__gt=created_since,
826 68b952f9 Christos Stavrakakis
                                           **kwargs)
827 6ce1fc56 Kostas Papadimitriou
828 6ce1fc56 Kostas Papadimitriou
829 6ce1fc56 Kostas Papadimitriou
class VirtualMachineDiagnostic(models.Model):
830 6ce1fc56 Kostas Papadimitriou
    """
831 6ce1fc56 Kostas Papadimitriou
    Model to store backend information messages that relate to the state of
832 6ce1fc56 Kostas Papadimitriou
    the virtual machine.
833 6ce1fc56 Kostas Papadimitriou
    """
834 6ce1fc56 Kostas Papadimitriou
835 6ce1fc56 Kostas Papadimitriou
    TYPES = (
836 6ce1fc56 Kostas Papadimitriou
        ('ERROR', 'Error'),
837 6ce1fc56 Kostas Papadimitriou
        ('WARNING', 'Warning'),
838 6ce1fc56 Kostas Papadimitriou
        ('INFO', 'Info'),
839 6ce1fc56 Kostas Papadimitriou
        ('DEBUG', 'Debug'),
840 6ce1fc56 Kostas Papadimitriou
    )
841 6ce1fc56 Kostas Papadimitriou
842 6ce1fc56 Kostas Papadimitriou
    objects = VirtualMachineDiagnosticManager()
843 6ce1fc56 Kostas Papadimitriou
844 6ce1fc56 Kostas Papadimitriou
    created = models.DateTimeField(auto_now_add=True)
845 6ce1fc56 Kostas Papadimitriou
    machine = models.ForeignKey('VirtualMachine', related_name="diagnostics")
846 6ce1fc56 Kostas Papadimitriou
    level = models.CharField(max_length=20, choices=TYPES)
847 6ce1fc56 Kostas Papadimitriou
    source = models.CharField(max_length=100)
848 6ce1fc56 Kostas Papadimitriou
    source_date = models.DateTimeField(null=True)
849 6ce1fc56 Kostas Papadimitriou
    message = models.CharField(max_length=255)
850 6ce1fc56 Kostas Papadimitriou
    details = models.TextField(null=True)
851 6ce1fc56 Kostas Papadimitriou
852 6ce1fc56 Kostas Papadimitriou
    class Meta:
853 6ce1fc56 Kostas Papadimitriou
        ordering = ['-created']