This repository has been archived by the owner on Sep 22, 2019. It is now read-only.
forked from osuosl/ganeti_webmgr
/
models.py
215 lines (169 loc) · 7.34 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# coding: utf-8
# Copyright (C) 2010 Oregon State University et al.
# Copyright (C) 2010 Greek Research and Technology Network
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
import sys
from django.contrib.auth.models import User, Group
from django.contrib.sites import models as sites_app
from django.contrib.sites.management import create_default_site
from django.db.models.signals import post_save, post_syncdb
from django.db.utils import DatabaseError
from utils.logs import register_log_actions
from object_log.models import LogItem
log_action = LogItem.objects.log_action
from object_permissions.registration import register
from muddle_users import signals as muddle_user_signals
from authentication.models import Organization
from clusters.models import Cluster
from nodes.models import Node
from virtualmachines.models import VirtualMachine
from utils.client import GanetiApiError
# from ganeti_web import constants, management, permissions
from .management import update_sites_module
import permissions
from authentication.models import Profile
from south.signals import post_migrate
from migrations import db_table_exists
# XXX: am I wrong or is it not used anywhere?
FINISHED_JOBS = 'success', 'unknown', 'error'
def create_profile(sender, instance, **kwargs):
"""
Create a profile object whenever a new user is created, also keeps the
profile name synchronized with the username
"""
try:
profile, new = Profile.objects.get_or_create(user=instance)
if profile.name != instance.username:
profile.name = instance.username
profile.save()
except DatabaseError:
# XXX - since we're using south to track migrations the Profile table
# won't be available the first time syncdb is run. Catch the error
# here and let the south migration handle it.
pass
def update_cluster_hash(sender, instance, **kwargs):
"""
Updates the Cluster hash for all of it's VirtualMachines, Nodes, and Jobs
"""
instance.virtual_machines.all().update(cluster_hash=instance.hash)
instance.jobs.all().update(cluster_hash=instance.hash)
instance.nodes.all().update(cluster_hash=instance.hash)
def update_organization(sender, instance, **kwargs):
"""
Creates a Organizations whenever a contrib.auth.models.Group is created
"""
org, new = Organization.objects.get_or_create(group=instance)
org.name = instance.name
org.save()
post_save.connect(create_profile, sender=User)
post_save.connect(update_cluster_hash, sender=Cluster)
post_save.connect(update_organization, sender=Group)
# Disconnect create_default_site from django.contrib.sites so that
# the useless table for sites is not created. This will be
# reconnected for other apps to use in update_sites_module.
post_syncdb.disconnect(create_default_site, sender=sites_app)
post_syncdb.connect(update_sites_module, sender=sites_app,
dispatch_uid="ganeti.management.update_sites_module")
def regenerate_cu_children(sender, **kwargs):
"""
Resets may destroy Profiles and/or Organizations. We need to regenerate
them.
"""
# So. What are we actually doing here?
# Whenever a User or Group is saved, the associated Profile or
# Organization is also updated. This means that, if a Profile for a User
# is absent, it will be created.
# More importantly, *why* might a Profile be missing? Simple. Resets of
# the ganeti app destroy them. This shouldn't happen in production, and
# only occasionally in development, but it's good to explicitly handle
# this particular case so that missing Profiles not resulting from a reset
# are easier to diagnose.
try:
for user in User.objects.filter(profile__isnull=True):
user.save()
for group in Group.objects.filter(organization__isnull=True):
group.save()
except DatabaseError:
# XXX - since we're using south to track migrations the Profile table
# won't be available the first time syncdb is run. Catch the error
# here and let the south migration handle it.
pass
post_syncdb.connect(regenerate_cu_children)
def log_group_create(sender, editor, **kwargs):
""" log group creation signal """
log_action('CREATE', editor, sender)
def log_group_edit(sender, editor, **kwargs):
""" log group edit signal """
log_action('EDIT', editor, sender)
muddle_user_signals.view_group_created.connect(log_group_create)
muddle_user_signals.view_group_edited.connect(log_group_edit)
def refresh_objects(sender, **kwargs):
"""
This was originally the code in the 0009
and then 0010 'force_object_refresh' migration
Force a refresh of all Cluster, Nodes, and VirtualMachines, and
import any new Nodes.
"""
if kwargs.get('app', False) and kwargs['app'] == 'ganeti_web':
write = sys.stdout.write
flush = sys.stdout.flush
def wf(str, newline=False):
if newline:
write('\n')
write(str)
flush()
wf('- Refresh Cached Cluster Objects')
# these if-conditionals are here to bypass 0019 migration's database
# error (after refactoring this refresh function gets called before
# proper new tables exist)
if db_table_exists(Cluster._meta.db_table):
wf(' > Synchronizing Cluster Nodes ', True)
flush()
Cluster.objects.all().update(mtime=None)
for cluster in Cluster.objects.all().iterator():
try:
cluster.sync_nodes()
wf('.')
except GanetiApiError:
wf('E')
if db_table_exists(Node._meta.db_table):
Node.objects.all().update(mtime=None)
wf(' > Refreshing Node Caches ', True)
for node in Node.objects.all().iterator():
try:
wf('.')
except GanetiApiError:
wf('E')
if db_table_exists(VirtualMachine._meta.db_table):
VirtualMachine.objects.all().update(mtime=None)
wf(' > Refreshing Instance Caches ', True)
for instance in VirtualMachine.objects.all().iterator():
try:
wf('.')
except GanetiApiError:
wf('E')
wf('\n')
# Set this as post_migrate hook.
post_migrate.connect(refresh_objects)
# Register permissions on our models.
# These are part of the DB schema and should not be changed without serious
# forethought.
# You *must* syncdb after you change these.
register(permissions.CLUSTER_PARAMS, Cluster, 'ganeti_web')
register(permissions.VIRTUAL_MACHINE_PARAMS, VirtualMachine, 'ganeti_web')
# register log actions
register_log_actions()