Revision fd65ab41

b/snf-cyclades-app/synnefo/db/migrations/0039_auto__add_backendnetwork__del_field_network_backendtime__del_field_net.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8
    
9
    def forwards(self, orm):
10
        
11
        # Adding model 'BackendNetwork'
12
        db.create_table('db_backendnetwork', (
13
            ('backendtime', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(1, 1, 1, 0, 0))),
14
            ('updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
15
            ('network', self.gf('django.db.models.fields.related.ForeignKey')(related_name='backend_networks', to=orm['db.Network'])),
16
            ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
17
            ('deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
18
            ('backendopcode', self.gf('django.db.models.fields.CharField')(max_length=30, null=True)),
19
            ('operstate', self.gf('django.db.models.fields.CharField')(default='PENDING', max_length=30)),
20
            ('backendjobid', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)),
21
            ('backendlogmsg', self.gf('django.db.models.fields.TextField')(null=True)),
22
            ('backendjobstatus', self.gf('django.db.models.fields.CharField')(max_length=30, null=True)),
23
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
24
            ('backend', self.gf('django.db.models.fields.related.ForeignKey')(related_name='networks', to=orm['db.Backend'])),
25
        ))
26
        db.send_create_signal('db', ['BackendNetwork'])
27

  
28
        # Deleting field 'Network.backendtime'
29
        db.delete_column('db_network', 'backendtime')
30

  
31
        # Deleting field 'Network.backendopcode'
32
        db.delete_column('db_network', 'backendopcode')
33

  
34
        # Deleting field 'Network.backendlogmsg'
35
        db.delete_column('db_network', 'backendlogmsg')
36

  
37
        # Deleting field 'Network.backendjobid'
38
        db.delete_column('db_network', 'backendjobid')
39

  
40
        # Deleting field 'Network.backendjobstatus'
41
        db.delete_column('db_network', 'backendjobstatus')
42

  
43
        # Changing field 'Network.mac_prefix'
44
        db.alter_column('db_network', 'mac_prefix', self.gf('django.db.models.fields.CharField')(max_length=32, null=True))
45

  
46
        # Changing field 'Network.state'
47
        db.alter_column('db_network', 'state', self.gf('django.db.models.fields.CharField')(max_length=32))
48

  
49
        # Changing field 'Network.action'
50
        db.alter_column('db_network', 'action', self.gf('django.db.models.fields.CharField')(max_length=32, null=True))
51
    
52
    
53
    def backwards(self, orm):
54
        
55
        # Deleting model 'BackendNetwork'
56
        db.delete_table('db_backendnetwork')
57

  
58
        # Adding field 'Network.backendtime'
59
        db.add_column('db_network', 'backendtime', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(1, 1, 1, 0, 0)), keep_default=False)
60

  
61
        # Adding field 'Network.backendopcode'
62
        db.add_column('db_network', 'backendopcode', self.gf('django.db.models.fields.CharField')(max_length=30, null=True), keep_default=False)
63

  
64
        # Adding field 'Network.backendlogmsg'
65
        db.add_column('db_network', 'backendlogmsg', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False)
66

  
67
        # Adding field 'Network.backendjobid'
68
        db.add_column('db_network', 'backendjobid', self.gf('django.db.models.fields.PositiveIntegerField')(null=True), keep_default=False)
69

  
70
        # Adding field 'Network.backendjobstatus'
71
        db.add_column('db_network', 'backendjobstatus', self.gf('django.db.models.fields.CharField')(max_length=30, null=True), keep_default=False)
72

  
73
        # Changing field 'Network.mac_prefix'
74
        db.alter_column('db_network', 'mac_prefix', self.gf('django.db.models.fields.CharField')(max_length=128, null=True))
75

  
76
        # Changing field 'Network.state'
77
        db.alter_column('db_network', 'state', self.gf('django.db.models.fields.CharField')(max_length=30))
78

  
79
        # Changing field 'Network.action'
80
        db.alter_column('db_network', 'action', self.gf('django.db.models.fields.CharField')(max_length=30, null=True))
81
    
82
    
83
    models = {
84
        'db.backend': {
85
            'Meta': {'object_name': 'Backend'},
86
            'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
87
            'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
88
            'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
89
            'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
90
            'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
91
            'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
92
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
93
            'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
94
            'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
95
            'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
96
            'password': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
97
            'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
98
            'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}),
99
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
100
            'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'})
101
        },
102
        'db.backendnetwork': {
103
            'Meta': {'object_name': 'BackendNetwork'},
104
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'networks'", 'to': "orm['db.Backend']"}),
105
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
106
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
107
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
108
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
109
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
110
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
111
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
112
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
113
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backend_networks'", 'to': "orm['db.Network']"}),
114
            'operstate': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '30'}),
115
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
116
        },
117
        'db.bridgepool': {
118
            'Meta': {'object_name': 'BridgePool'},
119
            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
120
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
121
            'index': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
122
            'value': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
123
        },
124
        'db.flavor': {
125
            'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'},
126
            'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
127
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
128
            'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
129
            'disk_template': ('django.db.models.fields.CharField', [], {'default': "'drbd'", 'max_length': '32'}),
130
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
131
            'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'})
132
        },
133
        'db.macprefixpool': {
134
            'Meta': {'object_name': 'MacPrefixPool'},
135
            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
136
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
137
            'index': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
138
            'value': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
139
        },
140
        'db.network': {
141
            'Meta': {'object_name': 'Network'},
142
            'action': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '32', 'null': 'True'}),
143
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
144
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
145
            'dhcp': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
146
            'gateway': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
147
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
148
            'link': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
149
            'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
150
            'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}),
151
            'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
152
            'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
153
            'state': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '32'}),
154
            'subnet': ('django.db.models.fields.CharField', [], {'default': "'10.0.0.0/24'", 'max_length': '32'}),
155
            'type': ('django.db.models.fields.CharField', [], {'default': "'PRIVATE_VLAN'", 'max_length': '50'}),
156
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
157
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'})
158
        },
159
        'db.networkinterface': {
160
            'Meta': {'object_name': 'NetworkInterface'},
161
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
162
            'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
163
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
164
            'index': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
165
            'ipv4': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True'}),
166
            'ipv6': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
167
            'mac': ('django.db.models.fields.CharField', [], {'max_length': '17', 'null': 'True'}),
168
            'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.VirtualMachine']"}),
169
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}),
170
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
171
        },
172
        'db.virtualmachine': {
173
            'Meta': {'object_name': 'VirtualMachine'},
174
            'action': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
175
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machines'", 'null': 'True', 'to': "orm['db.Backend']"}),
176
            'backend_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
177
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
178
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
179
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
180
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
181
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
182
            'buildpercentage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
183
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
184
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
185
            'flavor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.Flavor']"}),
186
            'hostid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
187
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
188
            'imageid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
189
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
190
            'operstate': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
191
            'suspended': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
192
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
193
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '100'})
194
        },
195
        'db.virtualmachinemetadata': {
196
            'Meta': {'unique_together': "(('meta_key', 'vm'),)", 'object_name': 'VirtualMachineMetadata'},
197
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
198
            'meta_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
199
            'meta_value': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
200
            'vm': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': "orm['db.VirtualMachine']"})
201
        }
202
    }
203
    
204
    complete_apps = ['db']
b/snf-cyclades-app/synnefo/db/models.py
184 184
                                 "with backend: %s" % self)
185 185
        else:
186 186
            # ON_DELETE = SET NULL
187
            self.virtual_machines.all().backend=None
187
            self.virtual_machines.all().backend = None
188 188
            super(Backend, self).delete(*args, **kwargs)
189 189

  
190 190

  
191
# A backend job may be in one of the following possible states
192
BACKEND_STATUSES = (
193
    ('queued', 'request queued'),
194
    ('waiting', 'request waiting for locks'),
195
    ('canceling', 'request being canceled'),
196
    ('running', 'request running'),
197
    ('canceled', 'request canceled'),
198
    ('success', 'request completed successfully'),
199
    ('error', 'request returned error')
200
)
201

  
202

  
191 203
class VirtualMachine(models.Model):
192 204
    # The list of possible actions for a VM
193 205
    ACTIONS = (
......
230 242
        ('OP_INSTANCE_FAILOVER', 'Failover Instance')
231 243
    )
232 244

  
233
    # A backend job may be in one of the following possible states
234
    BACKEND_STATUSES = (
235
        ('queued', 'request queued'),
236
        ('waiting', 'request waiting for locks'),
237
        ('canceling', 'request being canceled'),
238
        ('running', 'request running'),
239
        ('canceled', 'request canceled'),
240
        ('success', 'request completed successfully'),
241
        ('error', 'request returned error')
242
    )
243 245

  
244 246
    # The operating state of a VM,
245 247
    # upon the successful completion of a backend operation.
......
406 408
       ('DESTROY', 'Destroy Network'),
407 409
    )
408 410

  
409
    # The list of possible operations on the backend
410
    BACKEND_OPCODES = (
411
        ('OP_NETWORK_ADD', 'Create Network'),
412
        ('OP_NETWORK_CONNECT', 'Activate Network'),
413
        ('OP_NETWORK_DISCONNECT', 'Deactivate Network'),
414
        ('OP_NETWORK_REMOVE', 'Remove Network')
415
    )
416

  
417
    # A backend job may be in one of the following possible states
418
    BACKEND_STATUSES = (
419
        ('success', 'request completed successfully'),
420
        ('error', 'request returned error')
421
    )
422

  
423
    # The operating state of a Network,
424
    # upon the successful completion of a backend operation.
425
    # IMPORTANT: Make sure all keys have a corresponding
426
    # entry in BACKEND_OPCODES if you update this field, see #1035, #1111.
427
    OPER_STATE_FROM_OPCODE = {
428
        'OP_NETWORK_ADD': 'PENDING',
429
        'OP_NETWORK_CONNECT': 'ACTIVE',
430
        'OP_NETWORK_DISCONNECT': 'PENDING',
431
        'OP_NETWORK_REMOVE': 'DELETED'
432
    }
433

  
434 411
    RSAPI_STATE_FROM_OPER_STATE = {
435 412
        'PENDING': 'PENDING',
436 413
        'ACTIVE': 'ACTIVE',
......
445 422
    )
446 423

  
447 424
    NETWORK_TAGS = {
448
        'PUBLIC_ROUTED': ['public-routed'],
449
        'PRIVATE_VLAN': ['private-vlan'],
450
        'PRIVATE_FILTERED': ['private-filtered']
425
        'PUBLIC_ROUTED': ['ip-less-routed'],
426
        'PRIVATE_VLAN': ['physical-vlan'],
427
        'PRIVATE_FILTERED': ['mac-filtered']
451 428
    }
452 429

  
453 430
    name = models.CharField('Network Name', max_length=128)
......
457 434
    dhcp = models.BooleanField('DHCP', default=True)
458 435
    type = models.CharField(choices=NETWORK_TYPES, max_length=50, default='PRIVATE_VLAN')
459 436
    link = models.CharField('Network Link', max_length=128, null=True)
460
    mac_prefix = models.CharField('MAC Prefix', max_length=128, null=True)
437
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=True)
461 438
    public = models.BooleanField(default=False)
462 439
    created = models.DateTimeField(auto_now_add=True)
463 440
    updated = models.DateTimeField(auto_now=True)
464 441
    deleted = models.BooleanField('Deleted', default=False)
465
    state = models.CharField(choices=OPER_STATES, max_length=30, default='PENDING')
442
    state = models.CharField(choices=OPER_STATES, max_length=32,
443
                             default='PENDING')
466 444
    machines = models.ManyToManyField(VirtualMachine,
467 445
                                      through='NetworkInterface')
468

  
469
    action = models.CharField(choices=ACTIONS, max_length=30, null=True)
470
    backendjobid = models.PositiveIntegerField(null=True)
471
    backendopcode = models.CharField(choices=BACKEND_OPCODES, max_length=30,
472
                                     null=True)
473
    backendjobstatus = models.CharField(choices=BACKEND_STATUSES,
474
                                        max_length=30, null=True)
475
    backendlogmsg = models.TextField(null=True)
476
    backendtime = models.DateTimeField(default=datetime.datetime.min)
477

  
446
    action = models.CharField(choices=ACTIONS, max_length=32, null=True,
447
                              default=None)
478 448

  
479 449
    class InvalidBackendIdError(Exception):
480
         def __init__(self, value):
450
        def __init__(self, value):
481 451
            self.value = value
482
         def __str__(self):
452

  
453
        def __str__(self):
483 454
            return repr(self.value)
484 455

  
485 456

  
486 457
    class InvalidBackendMsgError(Exception):
487
         def __init__(self, opcode, status):
458
        def __init__(self, opcode, status):
488 459
            self.opcode = opcode
489 460
            self.status = status
490
         def __str__(self):
461

  
462
        def __str__(self):
491 463
            return repr('<opcode: %s, status: %s>' % (self.opcode,
492 464
                    self.status))
493 465

  
494 466
    class InvalidActionError(Exception):
495
         def __init__(self, action):
467
        def __init__(self, action):
496 468
            self._action = action
497
         def __str__(self):
498
            return repr(str(self._action))
499 469

  
500
    def __init__(self, *args, **kw):
501
        """Initialize state for just created Network instances."""
502
        super(Network, self).__init__(*args, **kw)
503
        # This gets called BEFORE an instance gets save()d for
504
        # the first time.
505
        if not self.pk:
506
            self.action = None
507
            self.backendjobid = None
508
            self.backendjobstatus = None
509
            self.backendopcode = None
510
            self.backendlogmsg = None
511
            self.backendtime = datetime.datetime.min
470
        def __str__(self):
471
            return repr(str(self._action))
512 472

  
513 473
    @property
514 474
    def backend_id(self):
515
        """Returns the backend id for this Network by prepending backend-prefix."""
475
        """Return the backend id by prepending backend-prefix."""
516 476
        if not self.id:
517 477
            raise Network.InvalidBackendIdError("self.id is None")
518 478
        return '%s%s' % (settings.BACKEND_PREFIX_ID, self.id)
......
527 487
    def __unicode__(self):
528 488
        return self.name
529 489

  
490
    def update_oper_state(self):
491
        """Update operstate of the Network.
492

  
493
        Update the operstate of the Network depending on the related
494
        backend_networks. When backend networks do not have the same operstate,
495
        the Network's operstate is PENDING. Otherwise it is the same with
496
        the BackendNetworks operstate.
497

  
498
        """
499
        backend_states = [s.operstate for s in self.backend_networks.all()]
500
        if not backend_states:
501
            self.operstate = 'PENDING'
502
            self.save()
503
            return
504

  
505
        all_equal = len(set(backend_states)) <= 1
506
        self.operstate = all_equal and backend_states[0] or 'PENDING'
507

  
508
        if self.operstate == 'DELETED':
509
            self.deleted = True
510

  
511
        self.save()
512

  
513
    def save(self, *args, **kwargs):
514
        pk = self.pk
515
        super(Network, self).save(*args, **kwargs)
516
        if not pk:
517
            # In case of a new Network, corresponding BackendNetwork's must
518
            # be created!
519
            for back in Backend.objects.all():
520
                BackendNetwork.objects.create(backend=back, network=self)
521

  
522

  
523
class BackendNetwork(models.Model):
524
    OPER_STATES = (
525
        ('PENDING', 'Pending'),
526
        ('ACTIVE', 'Active'),
527
        ('DELETED', 'Deleted'),
528
        ('ERROR', 'Error')
529
    )
530

  
531
    # The list of possible operations on the backend
532
    BACKEND_OPCODES = (
533
        ('OP_NETWORK_ADD', 'Create Network'),
534
        ('OP_NETWORK_CONNECT', 'Activate Network'),
535
        ('OP_NETWORK_DISCONNECT', 'Deactivate Network'),
536
        ('OP_NETWORK_REMOVE', 'Remove Network'),
537
        # These are listed here for completeness,
538
        # and are ignored for the time being
539
        ('OP_NETWORK_SET_PARAMS', 'Set Network Parameters'),
540
        ('OP_NETWORK_QUERY_DATA', 'Query Network Data')
541
    )
542

  
543
    # The operating state of a Netowork,
544
    # upon the successful completion of a backend operation.
545
    # IMPORTANT: Make sure all keys have a corresponding
546
    # entry in BACKEND_OPCODES if you update this field, see #1035, #1111.
547
    OPER_STATE_FROM_OPCODE = {
548
        'OP_NETWORK_ADD': 'PENDING',
549
        'OP_NETWORK_CONNECT': 'ACTIVE',
550
        'OP_NETWORK_DISCONNECT': 'PENDING',
551
        'OP_NETWORK_REMOVE': 'DELETED',
552
        'OP_NETWORK_SET_PARAMS': None,
553
        'OP_NETWORK_QUERY_DATA': None
554
    }
555

  
556
    network = models.ForeignKey(Network, related_name='backend_networks')
557
    backend = models.ForeignKey(Backend, related_name='networks')
558
    created = models.DateTimeField(auto_now_add=True)
559
    updated = models.DateTimeField(auto_now=True)
560
    deleted = models.BooleanField('Deleted', default=False)
561
    operstate = models.CharField(choices=OPER_STATES, max_length=30,
562
                                 default='PENDING')
563
    backendjobid = models.PositiveIntegerField(null=True)
564
    backendopcode = models.CharField(choices=BACKEND_OPCODES, max_length=30,
565
                                     null=True)
566
    backendjobstatus = models.CharField(choices=BACKEND_STATUSES,
567
                                        max_length=30, null=True)
568
    backendlogmsg = models.TextField(null=True)
569
    backendtime = models.DateTimeField(null=False,
570
                                       default=datetime.datetime.min)
571

  
572
    def save(self, *args, **kwargs):
573
        super(BackendNetwork, self).save(*args, **kwargs)
574
        self.network.update_oper_state()
575

  
576
    def delete(self, *args, **kwargs):
577
        super(BackendNetwork, self).delete(*args, **kwargs)
578
        self.network.update_oper_state()
579

  
530 580

  
531 581
class NetworkInterface(models.Model):
532 582
    FIREWALL_PROFILES = (
b/snf-cyclades-app/synnefo/logic/backend.py
38 38
from django.db import transaction
39 39
from datetime import datetime
40 40

  
41
from synnefo.db.models import (Backend, VirtualMachine, Network, NetworkLink)
41
from synnefo.db.models import (Backend, VirtualMachine, Network, NetworkLink,
42
                               BACKEND_STATUSES)
42 43
from synnefo.logic import utils
43 44
from synnefo.util.rapi import GanetiRapiClient
44 45

  
......
69 70
    """
70 71
    # See #1492, #1031, #1111 why this line has been removed
71 72
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
72
    if status not in [x[0] for x in VirtualMachine.BACKEND_STATUSES]:
73
    if status not in [x[0] for x in BACKEND_STATUSES]:
73 74
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)
74 75

  
75 76
    vm.backendjobid = jobid

Also available in: Unified diff