/
publishers.py
332 lines (297 loc) · 10.9 KB
/
publishers.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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# -*- coding: utf-8 -*-
import logging
from functools import wraps
import pyhermes
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from ralph.assets.models import (
AssetModel,
ConfigurationClass,
ConfigurationModule
)
from ralph.data_center.models import Cluster, DataCenterAsset, Rack
from ralph.data_importer.models import (
ImportedObjectDoesNotExist,
ImportedObjects
)
from ralph.lib.custom_fields.models import CustomField, CustomFieldTypes
from ralph.networks.models import Network
from ralph.virtual.models import VirtualServer
logger = logging.getLogger(__name__)
def _get_venture_and_role_from_configuration_path(configuration_path):
venture_id, venture_role_id = None, None
if configuration_path is None:
return None, None
venture_id = _get_obj_id_ralph_2(configuration_path.module)
venture_role_id = _get_obj_id_ralph_2(configuration_path)
if venture_id is None:
logger.error('ConfigurationModule {} not found when syncing'.format(
configuration_path.module.id
))
if venture_role_id is None:
logger.error('ConfigurationClass {} not found when syncing'.format(
configuration_path.id
))
return venture_id, venture_role_id
def ralph2_sync(model):
"""
Decorator for synchronizers with Ralph2. Decorated function should return
dict with event data. Decorated function name is used as a topic name and
dispatch_uid for post_save signal.
"""
def wrap(func):
@wraps(func)
# connect to post_save signal for a model
@receiver(
post_save, sender=model, dispatch_uid=func.__name__,
)
# register publisher
@pyhermes.publisher(topic=func.__name__)
def wrapped_func(sender, instance=None, created=False, **kwargs):
# publish only if sync enabled (globally and for particular
# function)
if (
settings.RALPH2_HERMES_SYNC_ENABLED and
func.__name__ in settings.RALPH2_HERMES_SYNC_FUNCTIONS and
# process the signal only if instance has not attribute
# `_handle_post_save` set to False
getattr(instance, '_handle_post_save', True)
):
try:
result = func(sender, instance, created, **kwargs)
if result:
pyhermes.publish(func.__name__, result)
except:
logger.exception('Error during Ralph2 sync')
else:
return result
# store additional info about signal
wrapped_func._signal_model = model
wrapped_func._signal_dispatch_uid = func.__name__
wrapped_func._signal_type = post_save
return wrapped_func
return wrap
def _get_obj_id_ralph_2(obj):
"""
Returns ID of object in Ralph2 or None if not found.
"""
if not obj:
return None
pk = None
try:
pk = ImportedObjects.get_imported_id(obj)
except ImportedObjectDoesNotExist:
pass
return pk
def _add_custom_fields(obj):
return {'custom_fields': obj.custom_fields_as_dict}
def _add_ips(obj):
ips = []
for ip in obj.ipaddresses.all():
ips.append({
'ip': ip.address,
'hostname': ip.hostname,
'is_management': ip.is_management,
'mac': ip.ethernet.mac if ip.ethernet else None,
'dhcp_expose': ip.dhcp_expose,
})
return {'ips': ips}
@ralph2_sync(DataCenterAsset)
def sync_dc_asset_to_ralph2(sender, instance=None, created=False, **kwargs):
"""
Publish information about DataCenterAsset after change to sync it in Ralph2.
Known situations when this sync will not work:
* new rack/server room/data center added (it's not synced with Ralph2)
"""
asset = instance
venture_id, venture_role_id = _get_venture_and_role_from_configuration_path( # noqa
instance.configuration_path
)
data = {
'ralph2_id': _get_obj_id_ralph_2(asset),
'service': asset.service_env.service.uid,
'environment': _get_obj_id_ralph_2(
asset.service_env.environment
),
'force_depreciation': asset.force_depreciation,
# location
'data_center': _get_obj_id_ralph_2(
asset.rack.server_room.data_center
) if asset.rack else None,
'server_room': (
_get_obj_id_ralph_2(asset.rack.server_room)
if asset.rack else None
),
'rack': _get_obj_id_ralph_2(asset.rack),
'venture': venture_id,
'venture_role': venture_role_id,
}
# simple fields
for field in [
'id', 'orientation', 'position', 'sn', 'barcode', 'slot_no',
'price', 'niw', 'task_url', 'remarks', 'order_no', 'invoice_date',
'invoice_no', 'provider', 'source', 'status', 'depreciation_rate',
'depreciation_end_date', 'management_ip', 'management_hostname',
'hostname'
]:
data[field] = str(getattr(asset, field, '') or '')
# foreign key fields
for field in [
'model', 'property_of',
]:
data[field] = _get_obj_id_ralph_2(getattr(asset, field, None))
data.update(_add_custom_fields(instance))
data.update(_add_ips(instance))
return data
@ralph2_sync(AssetModel)
def sync_model_to_ralph2(sender, instance=None, created=False, **kwargs):
"""
Publish AssetModel info to sync it in Ralph3.
"""
model = instance
return {
'id': model.id,
'ralph2_id': _get_obj_id_ralph_2(model),
'name': model.name,
'category': _get_obj_id_ralph_2(model.category),
'cores_count': model.cores_count,
'power_consumption': model.power_consumption,
'height_of_device': model.height_of_device,
'manufacturer': _get_obj_id_ralph_2(model.manufacturer),
}
@ralph2_sync(Rack)
def sync_rack_to_ralph2(sender, instance=None, created=False, **kwargs):
"""
Publish Rack info to sync it in Ralph3.
"""
rack = instance
return {
'id': rack.id,
'ralph2_id': _get_obj_id_ralph_2(rack),
'name': rack.name,
'description': rack.description,
'orientation': rack.orientation,
'max_u_height': rack.max_u_height,
'visualization_col': rack.visualization_col,
'visualization_row': rack.visualization_row,
'server_room': _get_obj_id_ralph_2(rack.server_room),
'data_center': _get_obj_id_ralph_2(rack.server_room.data_center) if rack.server_room else None, # noqa
}
@ralph2_sync(ConfigurationModule)
def sync_configuration_module_to_ralph2(sender, instance=None, created=False, **kwargs): # noqa
"""
ConfigurationModule -> Venture
"""
return {
'id': instance.id,
'ralph2_id': _get_obj_id_ralph_2(instance),
'ralph2_parent_id': _get_obj_id_ralph_2(instance.parent) if instance.parent else None, # noqa
'symbol': instance.name,
'department': instance.support_team.name if instance.support_team else None, # noqa
}
@ralph2_sync(ConfigurationClass)
def sync_configuration_class_to_ralph2(sender, instance=None, created=False, **kwargs): # noqa
"""
ConfigurationClass -> VentureRole
"""
return {
'id': instance.id,
'ralph2_id': _get_obj_id_ralph_2(instance),
'ralph2_parent_id': _get_obj_id_ralph_2(instance.module) if instance.module else None, # noqa
'symbol': instance.class_name,
}
@ralph2_sync(VirtualServer)
def sync_virtual_server_to_ralph2(sender, instance=None, created=False, **kwargs): # noqa
"""
VirtualServer -> Device (virtual server)
"""
# TODO: custom fields
venture_id, venture_role_id = _get_venture_and_role_from_configuration_path( # noqa
instance.configuration_path
)
data = {
'id': instance.id,
'ralph2_id': _get_obj_id_ralph_2(instance),
'ralph2_parent_id': _get_obj_id_ralph_2(instance.parent) if instance.parent else None, # noqa
'hostname': instance.hostname,
'sn': instance.sn,
'type': instance.type.name,
'service_uid': instance.service_env.service.uid if instance.service_env else None, # noqa
'environment_id': _get_obj_id_ralph_2(
instance.service_env.environment
) if instance.service_env else None,
'venture_id': venture_id,
'venture_role_id': venture_role_id
}
data.update(_add_custom_fields(instance))
data.update(_add_ips(instance))
return data
@ralph2_sync(CustomField)
def sync_custom_field_to_ralph2(sender, instance=None, created=False, **kwargs): # noqa
"""
CustomField -> RoleProperty
"""
choices = None
if instance.type == CustomFieldTypes.CHOICE:
choices = instance._get_choices()
return {
'symbol': instance.attribute_name,
'default': instance.default_value,
'choices': choices
}
@ralph2_sync(Cluster)
def sync_stacked_switch_to_ralph2(sender, instance=None, created=False, **kwargs): # noqa
"""
Cluster -> Device (switch stack)
"""
venture_id, venture_role_id = _get_venture_and_role_from_configuration_path(
instance.configuration_path
)
ralph2_id = _get_obj_id_ralph_2(instance)
if not ralph2_id:
return {}
data = {
'id': instance.id,
'ralph2_id': ralph2_id,
'hostname': instance.hostname,
'type': instance.type.name,
'service_uid': instance.service_env.service.uid if instance.service_env else None, # noqa
'environment_id': _get_obj_id_ralph_2(
instance.service_env.environment
) if instance.service_env else None,
'venture_id': venture_id,
'venture_role_id': venture_role_id,
'children': list(map(_get_obj_id_ralph_2, instance.base_objects.all())),
}
data.update(_add_custom_fields(instance))
data.update(_add_ips(instance))
return data
@ralph2_sync(Network)
def sync_network_to_ralph2(sender, instance=None, created=False, **kwargs):
"""
Network publisher
"""
ralph2_id = _get_obj_id_ralph_2(instance)
data = {
'id': instance.id,
'ralph2_id': ralph2_id,
'name': instance.name,
'address': str(instance.address),
'gateway': str(instance.gateway.address) if instance.gateway else None,
'vlan': instance.vlan,
'remarks': instance.remarks,
'dhcp_broadcast': instance.dhcp_broadcast,
'reserved_bottom': instance.reserved_bottom,
'reserved_top': instance.reserved_top,
'network_environment': _get_obj_id_ralph_2(
instance.network_environment
),
'kind': _get_obj_id_ralph_2(instance.kind),
'dns_servers': [dns.ip_address for dns in instance.dns_servers.all()],
'terminators': [
bo.last_descendant.hostname for bo in instance.terminators.all()
],
'racks': list(map(_get_obj_id_ralph_2, instance.racks.all())),
}
return data