1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import sys
20 import difflib
21 from spacewalk.common.rhnLog import log_debug
22 from spacewalk.common.usix import raise_with_tb, next
23 from spacewalk.common.rhnException import rhnFault
24 from spacewalk.server import rhnSQL, configFilesHandler
25 from spacewalk.common.fileutils import f_date, ostr_to_sym
26
27
29
31 log_debug(3)
32 configFilesHandler.ConfigFilesHandler.__init__(self)
33 self.functions.update({
34 'management.get_file': 'management_get_file',
35 'management.list_config_channels': 'management_list_channels',
36 'management.create_config_channel': 'management_create_channel',
37 'management.remove_config_channel': 'management_remove_channel',
38 'management.list_file_revisions': 'management_list_file_revisions',
39 'management.list_files': 'management_list_files',
40 'management.has_file': 'management_has_file',
41 'management.put_file': 'management_put_file',
42 'management.remove_file': 'management_remove_file',
43 'management.diff': 'management_diff',
44 'management.get_default_delimiters': 'management_get_delimiters',
45 'management.get_maximum_file_size': 'management_get_maximum_file_size',
46 })
47 self.user = None
48 self.default_delimiter = '@'
49
50 _query_list_config_channels = rhnSQL.Statement("""
51 select cc.name,
52 cc.label,
53 cct.label channel_type
54 from rhnConfigChannelType cct,
55 rhnConfigChannel cc
56 where cc.org_id = :org_id
57 and cc.confchan_type_id = cct.id
58 and cct.label = 'normal'
59 order by cc.label, cc.name
60 """)
61
65
71
72 _query_lookup_config_channel = rhnSQL.Statement("""
73 select id
74 from rhnConfigChannel
75 where org_id = :org_id
76 and label = :config_channel
77 """)
78
105
106 _query_config_channel_by_label = rhnSQL.Statement("""
107 select id
108 from rhnConfigChannel
109 where org_id = :org_id
110 and label = :label
111 """)
112
141
142 _query_management_list_files = rhnSQL.Statement("""
143 select cc.label config_channel,
144 cfn.path
145 from rhnConfigFileName cfn,
146 rhnConfigFileState cfs,
147 rhnConfigFile cf,
148 rhnConfigChannel cc
149 where cc.org_id = :org_id
150 and cc.label = :config_channel
151 and cc.id = cf.config_channel_id
152 and cf.state_id = cfs.id
153 and cfs.label = 'alive'
154 and cf.config_file_name_id = cfn.id
155 """)
156
158 log_debug(1)
159 self._get_and_validate_session(dict)
160
161 config_channel = dict.get('config_channel')
162
163
164 log_debug(3, "Org id", self.org_id, "Config channel", config_channel)
165
166 h = rhnSQL.prepare(self._query_management_list_files)
167 h.execute(org_id=self.org_id, config_channel=config_channel)
168
169 retval = []
170 while 1:
171 row = h.fetchone_dict()
172 if not row:
173 break
174 val = {}
175
176 for f in ['config_channel', 'path']:
177 val[f] = row[f]
178
179 retval.append(val)
180 log_debug(4, "pre sort", retval)
181 retval.sort(lambda x, y: cmp(x['path'], y['path']))
182 log_debug(4, "Return value", retval)
183 return retval
184
200
201 _query_list_file_revisions = rhnSQL.Statement("""
202 select cr.revision
203 from rhnConfigChannel cc,
204 rhnConfigRevision cr,
205 rhnConfigFile cf
206 where cf.config_channel_id = cc.id
207 and cc.label = :config_channel
208 and cc.org_id = :org_id
209 and cf.config_file_name_id = lookup_config_filename(:path)
210 and cr.config_file_id = cf.id
211 order by revision desc
212 """)
213
229
243
244 _query_get_file = """
245 select :path path,
246 cc.label config_channel,
247 ccont.contents file_contents,
248 ccont.is_binary,
249 c.checksum_type,
250 c.checksum,
251 ccont.delim_start, ccont.delim_end,
252 cr.revision,
253 cf.modified,
254 ci.username,
255 ci.groupname,
256 ci.filemode,
257 cft.label,
258 ci.selinux_ctx,
259 case
260 when cft.label='symlink' then (select path from rhnConfigFileName where id = ci.SYMLINK_TARGET_FILENAME_ID)
261 else ''
262 end as symlink
263 from rhnConfigChannel cc,
264 rhnConfigInfo ci,
265 rhnConfigRevision cr
266 left join rhnConfigContent ccont
267 on cr.config_content_id = ccont.id
268 left join rhnChecksumView c
269 on ccont.checksum_id = c.id,
270 rhnConfigFile cf,
271 rhnConfigFileType cft
272 where cf.config_channel_id = cc.id
273 and cc.label = :config_channel
274 and cc.org_id = :org_id
275 and cf.config_file_name_id = lookup_config_filename(:path)
276 and cr.config_file_id = cf.id
277 and cr.config_info_id = ci.id
278 and cr.config_file_type_id = cft.id
279 """
280 _query_get_file_latest = rhnSQL.Statement(_query_get_file + """
281 and cf.latest_config_revision_id = cr.id
282 """)
283 _query_get_file_revision = rhnSQL.Statement(_query_get_file + """
284 and cr.revision = :revision
285 """)
286
287 - def _get_file(self, config_channel, path, revision=None):
302
303 _query_lookup_config_file_by_channel = rhnSQL.Statement("""
304 select cf.id,
305 cf.state_id
306 from rhnConfigFile cf,
307 rhnConfigChannel cc
308 where cc.org_id = :org_id
309 and cf.config_channel_id = cc.id
310 and cc.label = :config_channel
311 and cf.config_file_name_id = lookup_config_filename(:path)
312 """)
313
336
337 _query_update_file_state = rhnSQL.Statement("""
338 update rhnConfigFile
339 set state_id = :state_id
340 where id = :config_file_id
341 """)
342
364
383
389
395
397 """ Returns true if acl, ownership, type or selinux context differ. """
398 return (fsrc['filemode'] != fdst['filemode']) or (fsrc['label'] != fdst['label']) or \
399 (fsrc['username'] != fdst['username']) or (fsrc['groupname'] != fdst['groupname']) or \
400 (fsrc['selinux_ctx'] != fdst['selinux_ctx'])
401
403 """ Returns diff like header for this two files. """
404 template = "--- %s\t%s\tattributes: %s %s %s %s\tconfig channel: %s\trevision: %s"
405 first_row = template % (path, f_date(fsrc['modified']), ostr_to_sym(fsrc['filemode'], fsrc['label']),
406 fsrc['username'], fsrc['groupname'], fsrc['selinux_ctx'], config_channel_src,
407 fsrc['revision'],
408 )
409 second_row = template % (path, f_date(fdst['modified']), ostr_to_sym(fdst['filemode'], fdst['label']),
410 fdst['username'], fdst['groupname'], fdst['selinux_ctx'], config_channel_dst,
411 fdst['revision'],
412 )
413 return (first_row, second_row)
414
416 log_debug(1)
417 self._get_and_validate_session(dict)
418
419 param_names = ['config_channel_src', 'revision_src', 'path', ]
420 for p in param_names:
421 val = dict.get(p)
422 if val is None:
423 raise rhnFault(4007, "No content sent for `%s'" % p)
424
425 log_debug(4, "Params sent", dict)
426 path = dict['path']
427
428 config_channel_src = dict['config_channel_src']
429 revision_src = dict.get('revision_src')
430 fsrc = self._get_file_revision(config_channel_src, revision_src, path)
431
432 config_channel_dst = dict.get('config_channel_dst')
433 if config_channel_dst is None:
434 config_channel_dst = config_channel_src
435 revision_dst = dict.get('revision_dst')
436 fdst = self._get_file_revision(config_channel_dst, revision_dst, path)
437
438 if fsrc['label'] != fdst['label']:
439 raise rhnFault(4017,
440 "Path %s is a %s in channel %s while it is a %s in channel %s"
441 % (path, fsrc['label'],
442 config_channel_src, fdst['label'], config_channel_dst),
443 explain=0)
444
445 if fsrc['label'] == 'symlink':
446 if (fsrc["symlink"] != fdst['symlink']) or self.__attributes_differ(fsrc, fdst):
447 (first_row, second_row) = self.__header(path, fsrc, config_channel_src, fdst, config_channel_dst)
448 first_row += ' target: %s' % fsrc["symlink"]
449 second_row += ' target: %s' % fdst["symlink"]
450 return first_row + "\n" + second_row + "\n"
451 return ""
452
453 diff = difflib.unified_diff(
454 fsrc['file_content'], fdst['file_content'], path, path, fsrc['modified'], fdst['modified'], lineterm='')
455 try:
456 first_row = next(diff)
457 except StopIteration:
458 return ""
459
460 if not first_row.startswith('---'):
461
462 return first_row + '\n'.join(list(diff))
463
464 try:
465 second_row = next(diff)
466 except StopIteration:
467 second_row = ''
468
469 if not second_row.startswith('+++'):
470
471 return second_row + '\n'.join(list(diff))
472
473 (first_row, second_row) = self.__header(path, fsrc, config_channel_src, fdst, config_channel_dst)
474 return first_row + "\n" + second_row + '\n' + '\n'.join(list(diff))
475
477 if revision and not revision.isdigit():
478 raise rhnFault(4016, "Invalid revision number '%s' specified for path %s "
479 "in channel %s" % (revision, path, config_channel),
480 explain=0)
481
482 f = self._get_file(config_channel, path, revision=revision)
483 if not f:
484 raise rhnFault(4011, "File %s (revision %s) does not exist "
485 "in channel %s" % (path, revision, config_channel),
486 explain=0)
487 if f['label'] == 'file' and f['is_binary'] == 'Y':
488 raise rhnFault(4004, "File %s (revision %s) seems to contain "
489 "binary data" % (path, revision),
490 explain=0)
491
492
493
494
495
496
497 fc_lob = f.get('file_contents')
498 if fc_lob:
499 f['file_content'] = rhnSQL.read_lob(fc_lob).splitlines()
500 else:
501 f['file_content'] = ''
502 return f
503
504
505 _query_org_config_channels = rhnSQL.Statement("""
506 select cc.id, cc.label, cc.name, cct.label channel_type
507 from rhnConfigChannelType cct, rhnConfigChannel cc
508 where cc.label = :config_channel
509 and cc.org_id = :org_id
510 and cc.confchan_type_id = cct.id
511 """)
512
520
522 user_roles = self.user.get_roles()
523 if 'config_admin' in user_roles or 'org_admin' in user_roles:
524
525 return
526
527 raise rhnFault(4006,
528 "User is not a allowed to manage config files")
529