Revision aed9b901
b/snf-cyclades-app/synnefo/db/migrations/0034_auto__add_backend__add_field_virtualmachine_backend_hash__add_field_vi.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 'Backend' |
|
12 |
db.create_table('db_backend', ( |
|
13 |
('username', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)), |
|
14 |
('pinst_cnt', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), |
|
15 |
('updated', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), |
|
16 |
('mtotal', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), |
|
17 |
('hash', self.gf('django.db.models.fields.CharField')(max_length=40)), |
|
18 |
('drained', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)), |
|
19 |
('clustername', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128)), |
|
20 |
('dtotal', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), |
|
21 |
('mfree', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), |
|
22 |
('port', self.gf('django.db.models.fields.PositiveIntegerField')(default=5080)), |
|
23 |
('dfree', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), |
|
24 |
('ctotal', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), |
|
25 |
('offline', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)), |
|
26 |
('password', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)), |
|
27 |
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), |
|
28 |
)) |
|
29 |
db.send_create_signal('db', ['Backend']) |
|
30 |
|
|
31 |
# Adding field 'VirtualMachine.backend_hash' |
|
32 |
db.add_column('db_virtualmachine', 'backend_hash', self.gf('django.db.models.fields.CharField')(max_length=128, null=True), keep_default=False) |
|
33 |
|
|
34 |
# Adding field 'VirtualMachine.backend' |
|
35 |
db.add_column('db_virtualmachine', 'backend', self.gf('django.db.models.fields.related.ForeignKey')(related_name='virtual_machines', null=True, to=orm['db.Backend']), keep_default=False) |
|
36 |
|
|
37 |
|
|
38 |
def backwards(self, orm): |
|
39 |
|
|
40 |
# Deleting model 'Backend' |
|
41 |
db.delete_table('db_backend') |
|
42 |
|
|
43 |
# Deleting field 'VirtualMachine.backend_hash' |
|
44 |
db.delete_column('db_virtualmachine', 'backend_hash') |
|
45 |
|
|
46 |
# Deleting field 'VirtualMachine.backend' |
|
47 |
db.delete_column('db_virtualmachine', 'backend_id') |
|
48 |
|
|
49 |
|
|
50 |
models = { |
|
51 |
'db.backend': { |
|
52 |
'Meta': {'object_name': 'Backend'}, |
|
53 |
'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}), |
|
54 |
'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
55 |
'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
56 |
'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
57 |
'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
58 |
'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}), |
|
59 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
60 |
'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
61 |
'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
62 |
'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
63 |
'password': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), |
|
64 |
'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
65 |
'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}), |
|
66 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
67 |
'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) |
|
68 |
}, |
|
69 |
'db.flavor': { |
|
70 |
'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'}, |
|
71 |
'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
72 |
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
73 |
'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
74 |
'disk_template': ('django.db.models.fields.CharField', [], {'default': "'drbd'", 'max_length': '32'}), |
|
75 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
76 |
'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'}) |
|
77 |
}, |
|
78 |
'db.network': { |
|
79 |
'Meta': {'object_name': 'Network'}, |
|
80 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
81 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
82 |
'link': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['db.NetworkLink']"}), |
|
83 |
'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}), |
|
84 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
85 |
'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
86 |
'state': ('django.db.models.fields.CharField', [], {'max_length': '30'}), |
|
87 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
|
88 |
'userid': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}) |
|
89 |
}, |
|
90 |
'db.networkinterface': { |
|
91 |
'Meta': {'object_name': 'NetworkInterface'}, |
|
92 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
93 |
'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
94 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
95 |
'index': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), |
|
96 |
'ipv4': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True'}), |
|
97 |
'ipv6': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}), |
|
98 |
'mac': ('django.db.models.fields.CharField', [], {'max_length': '17', 'null': 'True'}), |
|
99 |
'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.VirtualMachine']"}), |
|
100 |
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}), |
|
101 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) |
|
102 |
}, |
|
103 |
'db.networklink': { |
|
104 |
'Meta': {'object_name': 'NetworkLink'}, |
|
105 |
'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), |
|
106 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
107 |
'index': ('django.db.models.fields.IntegerField', [], {}), |
|
108 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
109 |
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': "orm['db.Network']"}) |
|
110 |
}, |
|
111 |
'db.virtualmachine': { |
|
112 |
'Meta': {'object_name': 'VirtualMachine'}, |
|
113 |
'action': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
114 |
'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machines'", 'null': 'True', 'to': "orm['db.Backend']"}), |
|
115 |
'backend_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), |
|
116 |
'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), |
|
117 |
'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
118 |
'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}), |
|
119 |
'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
120 |
'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}), |
|
121 |
'buildpercentage': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
122 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
123 |
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
124 |
'flavor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.Flavor']"}), |
|
125 |
'hostid': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
126 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
127 |
'imageid': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
128 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
129 |
'operstate': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
130 |
'suspended': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
131 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
|
132 |
'userid': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
|
133 |
}, |
|
134 |
'db.virtualmachinemetadata': { |
|
135 |
'Meta': {'unique_together': "(('meta_key', 'vm'),)", 'object_name': 'VirtualMachineMetadata'}, |
|
136 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
137 |
'meta_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}), |
|
138 |
'meta_value': ('django.db.models.fields.CharField', [], {'max_length': '500'}), |
|
139 |
'vm': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': "orm['db.VirtualMachine']"}) |
|
140 |
} |
|
141 |
} |
|
142 |
|
|
143 |
complete_apps = ['db'] |
b/snf-cyclades-app/synnefo/db/migrations/0035_default_backend.py | ||
---|---|---|
1 |
# encoding: utf-8 |
|
2 |
import datetime |
|
3 |
from south.db import db |
|
4 |
from south.v2 import DataMigration |
|
5 |
from django.db import models |
|
6 |
|
|
7 |
from synnefo import settings |
|
8 |
|
|
9 |
class Migration(DataMigration): |
|
10 |
|
|
11 |
def forwards(self, orm): |
|
12 |
"Write your forwards methods here." |
|
13 |
(ip, port, username, password) = settings.GANETI_CLUSTER_INFO |
|
14 |
backend = orm.Backend.objects.create(clustername = ip, |
|
15 |
port = port, |
|
16 |
username = username, |
|
17 |
password = password) |
|
18 |
for vm in orm.VirtualMachine.objects.all(): |
|
19 |
vm.backend = backend |
|
20 |
vm.save() |
|
21 |
|
|
22 |
|
|
23 |
|
|
24 |
|
|
25 |
def backwards(self, orm): |
|
26 |
"Write your backwards methods here." |
|
27 |
for vm in orm.VirtualMachine.objects.all(): |
|
28 |
vm.backend = None |
|
29 |
vm.save() |
|
30 |
|
|
31 |
|
|
32 |
|
|
33 |
models = { |
|
34 |
'db.backend': { |
|
35 |
'Meta': {'object_name': 'Backend'}, |
|
36 |
'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}), |
|
37 |
'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
38 |
'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
39 |
'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
40 |
'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
41 |
'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}), |
|
42 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
43 |
'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
44 |
'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
45 |
'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
46 |
'password': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), |
|
47 |
'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
48 |
'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}), |
|
49 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
50 |
'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) |
|
51 |
}, |
|
52 |
'db.flavor': { |
|
53 |
'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'}, |
|
54 |
'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
55 |
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
56 |
'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
57 |
'disk_template': ('django.db.models.fields.CharField', [], {'default': "'drbd'", 'max_length': '32'}), |
|
58 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
59 |
'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'}) |
|
60 |
}, |
|
61 |
'db.network': { |
|
62 |
'Meta': {'object_name': 'Network'}, |
|
63 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
64 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
65 |
'link': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['db.NetworkLink']"}), |
|
66 |
'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}), |
|
67 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
68 |
'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
69 |
'state': ('django.db.models.fields.CharField', [], {'max_length': '30'}), |
|
70 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
|
71 |
'userid': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}) |
|
72 |
}, |
|
73 |
'db.networkinterface': { |
|
74 |
'Meta': {'object_name': 'NetworkInterface'}, |
|
75 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
76 |
'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
77 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
78 |
'index': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), |
|
79 |
'ipv4': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True'}), |
|
80 |
'ipv6': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}), |
|
81 |
'mac': ('django.db.models.fields.CharField', [], {'max_length': '17', 'null': 'True'}), |
|
82 |
'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.VirtualMachine']"}), |
|
83 |
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}), |
|
84 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) |
|
85 |
}, |
|
86 |
'db.networklink': { |
|
87 |
'Meta': {'object_name': 'NetworkLink'}, |
|
88 |
'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), |
|
89 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
90 |
'index': ('django.db.models.fields.IntegerField', [], {}), |
|
91 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
92 |
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': "orm['db.Network']"}) |
|
93 |
}, |
|
94 |
'db.virtualmachine': { |
|
95 |
'Meta': {'object_name': 'VirtualMachine'}, |
|
96 |
'action': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
97 |
'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machines'", 'null': 'True', 'to': "orm['db.Backend']"}), |
|
98 |
'backend_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), |
|
99 |
'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), |
|
100 |
'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
101 |
'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}), |
|
102 |
'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
103 |
'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}), |
|
104 |
'buildpercentage': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
105 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
106 |
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
107 |
'flavor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.Flavor']"}), |
|
108 |
'hostid': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
109 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
110 |
'imageid': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
111 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
112 |
'operstate': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}), |
|
113 |
'suspended': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), |
|
114 |
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
|
115 |
'userid': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
|
116 |
}, |
|
117 |
'db.virtualmachinemetadata': { |
|
118 |
'Meta': {'unique_together': "(('meta_key', 'vm'),)", 'object_name': 'VirtualMachineMetadata'}, |
|
119 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
120 |
'meta_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}), |
|
121 |
'meta_value': ('django.db.models.fields.CharField', [], {'max_length': '500'}), |
|
122 |
'vm': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': "orm['db.VirtualMachine']"}) |
|
123 |
} |
|
124 |
} |
|
125 |
|
|
126 |
complete_apps = ['db'] |
b/snf-cyclades-app/synnefo/db/models.py | ||
---|---|---|
31 | 31 |
|
32 | 32 |
from django.conf import settings |
33 | 33 |
from django.db import models |
34 |
from django.db import IntegrityError |
|
35 |
|
|
36 |
from hashlib import sha1 |
|
37 |
from synnefo.api.faults import ServiceUnavailable |
|
38 |
from synnefo.util.rapi import GanetiRapiClient |
|
39 |
|
|
40 |
|
|
41 |
BACKEND_CLIENTS = {} #{hash:Backend client} |
|
42 |
BACKEND_HASHES = {} #{Backend.id:hash} |
|
43 |
|
|
44 |
def get_client(hash, backend): |
|
45 |
"""Get a cached backend client or create a new one. |
|
46 |
|
|
47 |
@param hash: The hash of the backend |
|
48 |
@param backend: Either a backend object or backend ID |
|
49 |
""" |
|
50 |
|
|
51 |
if backend is None: |
|
52 |
raise Exception("Backend is None. Cannot create a client.") |
|
53 |
|
|
54 |
if hash in BACKEND_CLIENTS: |
|
55 |
# Return cached client |
|
56 |
return BACKEND_CLIENTS[hash] |
|
57 |
|
|
58 |
# Always get a new instance to ensure latest credentials |
|
59 |
if isinstance(backend, Backend): |
|
60 |
backend = backend.id |
|
61 |
(credentials,) = Backend.objects.filter(id=backend).values_list('hash', |
|
62 |
'clustername', 'port', 'username', 'password') |
|
63 |
|
|
64 |
hash, clustername, port, user, password = credentials |
|
65 |
|
|
66 |
# Check client for updated hash |
|
67 |
if hash in BACKEND_CLIENTS: |
|
68 |
return BACKEND_CLIENTS[hash] |
|
69 |
|
|
70 |
# Delete old version of the client |
|
71 |
if backend in BACKEND_HASHES: |
|
72 |
del BACKEND_CLIENTS[BACKEND_HASHES[backend]] |
|
73 |
|
|
74 |
# Create the new client |
|
75 |
client = GanetiRapiClient(clustername, port, user, password) |
|
76 |
|
|
77 |
# Store the client and the hash |
|
78 |
BACKEND_CLIENTS[hash] = client |
|
79 |
BACKEND_HASHES[backend] = hash |
|
80 |
|
|
81 |
return client |
|
82 |
|
|
83 |
|
|
84 |
def clear_client_cache(): |
|
85 |
BACKEND_CLIENTS.clear() |
|
86 |
BACKEND_HASHES.clear() |
|
34 | 87 |
|
35 | 88 |
|
36 | 89 |
class Flavor(models.Model): |
... | ... | |
54 | 107 |
return self.name |
55 | 108 |
|
56 | 109 |
|
110 |
class BackendQuerySet(models.query.QuerySet): |
|
111 |
def delete(self): |
|
112 |
for backend in self._clone(): |
|
113 |
backend.delete() |
|
114 |
|
|
115 |
class ProtectDeleteManager(models.Manager): |
|
116 |
def get_query_set(self): |
|
117 |
return BackendQuerySet(self.model, using=self._db) |
|
118 |
|
|
119 |
|
|
120 |
class Backend(models.Model): |
|
121 |
clustername = models.CharField('Cluster Name', max_length=128, unique=True) |
|
122 |
port = models.PositiveIntegerField('Port', default=5080) |
|
123 |
username = models.CharField('Username', max_length=64, blank=True, |
|
124 |
null=True) |
|
125 |
password = models.CharField('Password', max_length=64, blank=True, |
|
126 |
null=True) |
|
127 |
# Sha1 is up to 40 characters long |
|
128 |
hash = models.CharField('Hash', max_length=40, editable=False, null=False) |
|
129 |
drained = models.BooleanField('Drained', default=False, null=False) |
|
130 |
offline = models.BooleanField('Offline', default=False, null=False) |
|
131 |
# Last refresh of backend resources |
|
132 |
updated = models.DateTimeField(auto_now_add=True) |
|
133 |
# Backend resources |
|
134 |
mfree = models.PositiveIntegerField('Free Memory', default=0, null=False) |
|
135 |
mtotal = models.PositiveIntegerField('Total Memory', default=0, null=False) |
|
136 |
dfree = models.PositiveIntegerField('Free Disk', default=0, null=False) |
|
137 |
dtotal = models.PositiveIntegerField('Total Disk', default=0, null=False) |
|
138 |
pinst_cnt = models.PositiveIntegerField('Primary Instances', default=0, |
|
139 |
null=False) |
|
140 |
ctotal = models.PositiveIntegerField('Total number of logical processors', |
|
141 |
default=0, null=False) |
|
142 |
# Custom object manager to protect from cascade delete |
|
143 |
objects = ProtectDeleteManager() |
|
144 |
|
|
145 |
class Meta: |
|
146 |
verbose_name = u'Backend' |
|
147 |
ordering = ["clustername"] |
|
148 |
|
|
149 |
def __unicode__(self): |
|
150 |
return self.clustername |
|
151 |
|
|
152 |
@property |
|
153 |
def backend_id(self): |
|
154 |
return self.id |
|
155 |
|
|
156 |
@property |
|
157 |
def client(self): |
|
158 |
"""Get or create a client. """ |
|
159 |
if not self.offline: |
|
160 |
return get_client(self.hash, self) |
|
161 |
else: |
|
162 |
raise ServiceUnavailable |
|
163 |
|
|
164 |
def create_hash(self): |
|
165 |
"""Create a hash for this backend. """ |
|
166 |
return sha1('%s%s%s%s' % \ |
|
167 |
(self.clustername, self.port, self.username, self.password)) \ |
|
168 |
.hexdigest() |
|
169 |
|
|
170 |
def save(self, *args, **kwargs): |
|
171 |
# Create a new hash each time a Backend is saved |
|
172 |
old_hash = self.hash |
|
173 |
self.hash = self.create_hash() |
|
174 |
super(Backend, self).save(*args, **kwargs) |
|
175 |
if self.hash != old_hash: |
|
176 |
# Populate the new hash to the new instances |
|
177 |
self.virtual_machines.filter(deleted=False).update(backend_hash=self.hash) |
|
178 |
|
|
179 |
def delete(self, *args, **kwargs): |
|
180 |
# Integrity Error if non-deleted VMs are associated with Backend |
|
181 |
if self.virtual_machines.filter(deleted=False).count(): |
|
182 |
raise IntegrityError("Non-deleted virtual machines are associated " |
|
183 |
"with backend: %s" % self) |
|
184 |
else: |
|
185 |
# ON_DELETE = SET NULL |
|
186 |
self.virtual_machines.all().backend=None |
|
187 |
super(Backend, self).delete(*args, **kwargs) |
|
188 |
|
|
189 |
|
|
57 | 190 |
class VirtualMachine(models.Model): |
58 | 191 |
# The list of possible actions for a VM |
59 | 192 |
ACTIONS = ( |
... | ... | |
142 | 275 |
|
143 | 276 |
name = models.CharField('Virtual Machine Name', max_length=255) |
144 | 277 |
userid = models.CharField('User ID of the owner', max_length=100) |
278 |
backend = models.ForeignKey(Backend, null=True, |
|
279 |
related_name="virtual_machines",) |
|
280 |
backend_hash = models.CharField(max_length=128, null=True, editable=False) |
|
145 | 281 |
created = models.DateTimeField(auto_now_add=True) |
146 | 282 |
updated = models.DateTimeField(auto_now=True) |
147 | 283 |
imageid = models.CharField(max_length=100, null=False) |
... | ... | |
164 | 300 |
operstate = models.CharField(choices=OPER_STATES, max_length=30, null=True) |
165 | 301 |
backendjobid = models.PositiveIntegerField(null=True) |
166 | 302 |
backendopcode = models.CharField(choices=BACKEND_OPCODES, max_length=30, |
167 |
null=True) |
|
303 |
null=True)
|
|
168 | 304 |
backendjobstatus = models.CharField(choices=BACKEND_STATUSES, |
169 |
max_length=30, null=True) |
|
305 |
max_length=30, null=True)
|
|
170 | 306 |
backendlogmsg = models.TextField(null=True) |
171 | 307 |
buildpercentage = models.IntegerField(default=0) |
172 | 308 |
backendtime = models.DateTimeField(default=datetime.datetime.min) |
173 | 309 |
|
310 |
@property |
|
311 |
def client(self): |
|
312 |
if not self.backend.offline: |
|
313 |
return get_client(self.backend_hash, self.backend_id) |
|
314 |
else: |
|
315 |
raise ServiceUnavailable |
|
316 |
|
|
174 | 317 |
# Error classes |
175 | 318 |
class InvalidBackendIdError(Exception): |
176 | 319 |
def __init__(self, value): |
... | ... | |
214 | 357 |
self.backendlogmsg = None |
215 | 358 |
self.operstate = 'BUILD' |
216 | 359 |
|
360 |
def save(self, *args, **kwargs): |
|
361 |
# Store hash for first time saved vm |
|
362 |
if (self.id is None or self.backend_hash == '') and self.backend: |
|
363 |
self.backend_hash = self.backend.hash |
|
364 |
super(VirtualMachine, self).save(*args, **kwargs) |
|
365 |
|
|
217 | 366 |
@property |
218 | 367 |
def backend_vm_id(self): |
219 | 368 |
"""Returns the backend id for this VM by prepending backend-prefix.""" |
Also available in: Unified diff