Merge lp:~fehwalker/ubuntu/precise/cobbler/lp1001846 into lp:ubuntu/precise/cobbler

Proposed by Bryan Fullerton
Status: Work in progress
Proposed branch: lp:~fehwalker/ubuntu/precise/cobbler/lp1001846
Merge into: lp:ubuntu/precise/cobbler
Diff against target: 1587 lines (+1458/-24)
13 files modified
.pc/.quilt_patches (+1/-0)
.pc/.quilt_series (+1/-0)
.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/api.py (+1029/-0)
.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/cobblerd.py (+145/-0)
.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/serializer.py (+165/-0)
.pc/applied-patches (+1/-0)
cobbler/api.py (+3/-5)
cobbler/cobblerd.py (+6/-9)
cobbler/serializer.py (+3/-5)
debian/changelog (+15/-0)
debian/cobbler.config (+6/-5)
debian/patches/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch (+82/-0)
debian/patches/series (+1/-0)
To merge this branch: bzr merge lp:~fehwalker/ubuntu/precise/cobbler/lp1001846
Reviewer Review Type Date Requested Status
James Page Needs Fixing
Ubuntu branches Pending
Review via email: mp+151352@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

Hi Bryan

Thanks for preparing this merge proposal.

Unfortunately the fix for bug 1027219 is currently in precise-proposed; so we need to put this update on hold until that fix has been released into updates (its been verified so that should not be to long).

At that point please could you rebase you branch against lp:ubuntu/precise-updates/cobbler.

Thanks!

review: Needs Fixing
Revision history for this message
Dmitry Shachnev (mitya57) wrote :

Note: the package migrated to -updates, but neither lp:ubuntu/precise-updates/cobbler nor lp:ubuntu/precise-proposed/cobbler have been updated, so you should probably manually merge the update into your branch (or maybe a sponsor can do that while uploading).

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Now that -proposed is clear, Please update the bug description as per https://wiki.ubuntu.com/StableReleaseUpdates#SRU_Bug_Template

Specifically please list exact steps to reproduce the problem such that it is easy to test that proposed patch resolves the issue on precise as well.

Revision history for this message
Steve Langasek (vorlon) wrote :

Please note that lp:ubuntu/precise-updates/cobbler *is* up to date, so the branch can be rebased against that.

Revision history for this message
Sebastien Bacher (seb128) wrote :

(setting as work in progress, please set it back to needs review once it's updated)

Unmerged revisions

102. By Bryan Fullerton

debian/cobbler.config: Do not fail to install if cannot determine
default IP address. (LP: #1001846)

101. By C de-Avillez

debian/patches/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch:
correct wrong usage of os.umask() on cobbler/api.py, cobbler/cobblerd.py, and
cobbler/serializer.py. Imported from Upstream. (LP: #967815)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.pc/.quilt_patches'
2--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
3+++ .pc/.quilt_patches 2013-03-02 07:56:21 +0000
4@@ -0,0 +1,1 @@
5+debian/patches
6
7=== added file '.pc/.quilt_series'
8--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
9+++ .pc/.quilt_series 2013-03-02 07:56:21 +0000
10@@ -0,0 +1,1 @@
11+series
12
13=== added directory '.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch'
14=== added directory '.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler'
15=== added file '.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/api.py'
16--- .pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/api.py 1970-01-01 00:00:00 +0000
17+++ .pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/api.py 2013-03-02 07:56:21 +0000
18@@ -0,0 +1,1029 @@
19+"""
20+python API module for Cobbler
21+see source for cobbler.py, or pydoc, for example usage.
22+CLI apps and daemons should import api.py, and no other cobbler code.
23+
24+Copyright 2006-2009, Red Hat, Inc
25+Michael DeHaan <mdehaan@redhat.com>
26+
27+This program is free software; you can redistribute it and/or modify
28+it under the terms of the GNU General Public License as published by
29+the Free Software Foundation; either version 2 of the License, or
30+(at your option) any later version.
31+
32+This program is distributed in the hope that it will be useful,
33+but WITHOUT ANY WARRANTY; without even the implied warranty of
34+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35+GNU General Public License for more details.
36+
37+You should have received a copy of the GNU General Public License
38+along with this program; if not, write to the Free Software
39+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40+02110-1301 USA
41+"""
42+
43+import sys
44+import yaml
45+import config
46+import utils
47+import action_sync
48+import action_check
49+import action_reposync
50+import action_status
51+import action_validate
52+import action_buildiso
53+import action_replicate
54+import action_acl
55+import action_report
56+import action_power
57+import action_log
58+import action_hardlink
59+import action_dlcontent
60+from cexceptions import *
61+import module_loader
62+import kickgen
63+import yumgen
64+import pxegen
65+from utils import _
66+
67+import logging
68+import time
69+import random
70+import os
71+import xmlrpclib
72+import traceback
73+import exceptions
74+import clogger
75+
76+import item_distro
77+import item_profile
78+import item_system
79+import item_repo
80+import item_image
81+import item_mgmtclass
82+import item_package
83+import item_file
84+
85+ERROR = 100
86+INFO = 10
87+DEBUG = 5
88+
89+# FIXME: add --quiet depending on if not --verbose?
90+RSYNC_CMD = "rsync -a %s '%s' %s --exclude-from=/etc/cobbler/rsync.exclude --progress"
91+
92+# notes on locking:
93+# BootAPI is a singleton object
94+# the XMLRPC variants allow 1 simultaneous request
95+# therefore we flock on /etc/cobbler/settings for now
96+# on a request by request basis.
97+
98+class BootAPI:
99+
100+ __shared_state = {}
101+ __has_loaded = False
102+
103+ # ===========================================================
104+
105+ def __init__(self, is_cobblerd=False):
106+ """
107+ Constructor
108+ """
109+
110+ # FIXME: this should be switchable through some simple system
111+
112+ self.__dict__ = BootAPI.__shared_state
113+ self.perms_ok = False
114+ if not BootAPI.__has_loaded:
115+
116+ if os.path.exists("/etc/cobbler/use.couch"):
117+ self.use_couch = True
118+ else:
119+ self.use_couch = False
120+
121+ # NOTE: we do not log all API actions, because
122+ # a simple CLI invocation may call adds and such
123+ # to load the config, which would just fill up
124+ # the logs, so we'll do that logging at CLI
125+ # level (and remote.py web service level) instead.
126+
127+ random.seed()
128+ self.is_cobblerd = is_cobblerd
129+
130+ try:
131+ self.logger = clogger.Logger("/var/log/cobbler/cobbler.log")
132+ except CX:
133+ # return to CLI/other but perms are not valid
134+ # perms_ok is False
135+ return
136+
137+ # FIMXE: conslidate into 1 server instance
138+
139+ self.selinux_enabled = utils.is_selinux_enabled()
140+ self.dist = utils.check_dist()
141+ self.os_version = utils.os_release()
142+
143+ BootAPI.__has_loaded = True
144+
145+ module_loader.load_modules()
146+
147+ self._config = config.Config(self)
148+ self.deserialize()
149+
150+ self.authn = self.get_module_from_file(
151+ "authentication",
152+ "module",
153+ "authn_configfile"
154+ )
155+ self.authz = self.get_module_from_file(
156+ "authorization",
157+ "module",
158+ "authz_allowall"
159+ )
160+
161+ # FIXME: pass more loggers around, and also see that those
162+ # using things via tasks construct their own kickgen/yumgen/
163+ # pxegen versus reusing this one, which has the wrong logger
164+ # (most likely) for background tasks.
165+
166+ self.kickgen = kickgen.KickGen(self._config)
167+ self.yumgen = yumgen.YumGen(self._config)
168+ self.pxegen = pxegen.PXEGen(self._config, logger=self.logger)
169+ self.logger.debug("API handle initialized")
170+ self.perms_ok = True
171+
172+ # ==========================================================
173+
174+ def is_selinux_enabled(self):
175+ """
176+ Returns whether selinux is enabled on the cobbler server.
177+ We check this just once at cobbler API init time, because
178+ a restart is required to change this; this does /not/ check
179+ enforce/permissive, nor does it need to.
180+ """
181+ return self.selinux_enabled
182+
183+ def is_selinux_supported(self):
184+ """
185+ Returns whether or not the OS is sufficient enough
186+ to run with SELinux enabled (currently EL 5 or later).
187+ """
188+ self.dist
189+ if self.dist == "redhat" and self.os_version < 5:
190+ # doesn't support public_content_t
191+ return False
192+ return True
193+
194+ # ==========================================================
195+
196+ def last_modified_time(self):
197+ """
198+ Returns the time of the last modification to cobbler, made by any
199+ API instance, regardless of the serializer type.
200+ """
201+ if not os.path.exists("/var/lib/cobbler/.mtime"):
202+ old = os.umask(0x777)
203+ fd = open("/var/lib/cobbler/.mtime","w")
204+ fd.write("0")
205+ fd.close()
206+ os.umask(old)
207+ return 0
208+ fd = open("/var/lib/cobbler/.mtime")
209+ data = fd.read().strip()
210+ return float(data)
211+
212+ # ==========================================================
213+
214+ def log(self,msg,args=None,debug=False):
215+ if debug:
216+ logger = self.logger.debug
217+ else:
218+ logger = self.logger.info
219+ if args is None:
220+ logger("%s" % msg)
221+ else:
222+ logger("%s; %s" % (msg, str(args)))
223+
224+ # ==========================================================
225+
226+ def version(self, extended=False):
227+ """
228+ What version is cobbler?
229+
230+ If extended == False, returns a float for backwards compatibility
231+
232+ If extended == True, returns a dict:
233+
234+ gitstamp -- the last git commit hash
235+ gitdate -- the last git commit date on the builder machine
236+ builddate -- the time of the build
237+ version -- something like "1.3.2"
238+ version_tuple -- something like [ 1, 3, 2 ]
239+ """
240+ fd = open("/etc/cobbler/version")
241+ ydata = fd.read()
242+ fd.close()
243+ data = yaml.safe_load(ydata)
244+ if not extended:
245+ # for backwards compatibility and use with koan's comparisons
246+ elems = data["version_tuple"]
247+ return int(elems[0]) + 0.1*int(elems[1]) + 0.001*int(elems[2])
248+ else:
249+ return data
250+
251+ # ==========================================================
252+
253+ def clear(self):
254+ """
255+ Forget about current list of profiles, distros, and systems
256+ # FIXME: is this used anymore?
257+ """
258+ return self._config.clear()
259+
260+ def __cmp(self,a,b):
261+ return cmp(a.name,b.name)
262+ # ==========================================================
263+
264+ def get_item(self, what, name):
265+ self.log("get_item",[what,name],debug=True)
266+ item = self._config.get_items(what).get(name)
267+ self.log("done with get_item",[what,name],debug=True)
268+ return item #self._config.get_items(what).get(name)
269+
270+ # =============================================================
271+
272+ def get_items(self, what):
273+ self.log("get_items",[what],debug=True)
274+ items = self._config.get_items(what)
275+ self.log("done with get_items",[what],debug=True)
276+ return items #self._config.get_items(what)
277+
278+ def distros(self):
279+ """
280+ Return the current list of distributions
281+ """
282+ return self.get_items("distro")
283+
284+ def profiles(self):
285+ """
286+ Return the current list of profiles
287+ """
288+ return self.get_items("profile")
289+
290+ def systems(self):
291+ """
292+ Return the current list of systems
293+ """
294+ return self.get_items("system")
295+
296+ def repos(self):
297+ """
298+ Return the current list of repos
299+ """
300+ return self.get_items("repo")
301+
302+ def images(self):
303+ """
304+ Return the current list of images
305+ """
306+ return self.get_items("image")
307+
308+ def settings(self):
309+ """
310+ Return the application configuration
311+ """
312+ return self._config.settings()
313+
314+ def mgmtclasses(self):
315+ """
316+ Return the current list of mgmtclasses
317+ """
318+ return self.get_items("mgmtclass")
319+
320+ def packages(self):
321+ """
322+ Return the current list of packages
323+ """
324+ return self.get_items("package")
325+
326+ def files(self):
327+ """
328+ Return the current list of files
329+ """
330+ return self.get_items("file")
331+
332+ # =======================================================================
333+
334+ def update(self):
335+ """
336+ This can be called is no longer used by cobbler.
337+ And is here to just avoid breaking older scripts.
338+ """
339+ return True
340+
341+ # ========================================================================
342+
343+ def copy_item(self, what, ref, newname, logger=None):
344+ self.log("copy_item(%s)"%what,[ref.name, newname])
345+ return self.get_items(what).copy(ref,newname,logger=logger)
346+
347+ def copy_distro(self, ref, newname):
348+ return self.copy_item("distro", ref, newname, logger=None)
349+
350+ def copy_profile(self, ref, newname):
351+ return self.copy_item("profile", ref, newname, logger=None)
352+
353+ def copy_system(self, ref, newname):
354+ return self.copy_item("system", ref, newname, logger=None)
355+
356+ def copy_repo(self, ref, newname):
357+ return self.copy_item("repo", ref, newname, logger=None)
358+
359+ def copy_image(self, ref, newname):
360+ return self.copy_item("image", ref, newname, logger=None)
361+
362+ def copy_mgmtclass(self, ref, newname):
363+ return self.copy_item("mgmtclass", ref, newname, logger=None)
364+
365+ def copy_package(self, ref, newname):
366+ return self.copy_item("package", ref, newname, logger=None)
367+
368+ def copy_file(self, ref, newname):
369+ return self.copy_item("file", ref, newname, logger=None)
370+
371+ # ==========================================================================
372+
373+ def remove_item(self, what, ref, recursive=False, delete=True, with_triggers=True, logger=None):
374+ if isinstance(what, basestring):
375+ if isinstance(ref, basestring):
376+ ref = self.get_item(what, ref)
377+ if ref is None:
378+ return # nothing to remove
379+ self.log("remove_item(%s)" % what, [ref.name])
380+ return self.get_items(what).remove(ref.name, recursive=recursive, with_delete=delete, with_triggers=with_triggers, logger=logger)
381+
382+ def remove_distro(self, ref, recursive=False, delete=True, with_triggers=True, logger=None):
383+ return self.remove_item("distro", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
384+
385+ def remove_profile(self,ref, recursive=False, delete=True, with_triggers=True, logger=None):
386+ return self.remove_item("profile", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
387+
388+ def remove_system(self, ref, recursive=False, delete=True, with_triggers=True, logger=None):
389+ return self.remove_item("system", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
390+
391+ def remove_repo(self, ref, recursive=False, delete=True, with_triggers=True, logger=None):
392+ return self.remove_item("repo", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
393+
394+ def remove_image(self, ref, recursive=False, delete=True, with_triggers=True, logger=None):
395+ return self.remove_item("image", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
396+
397+ def remove_mgmtclass(self, ref, recursive=False, delete=True, with_triggers=True, logger=None):
398+ return self.remove_item("mgmtclass", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
399+
400+ def remove_package(self, ref, recursive=False, delete=True, with_triggers=True, logger=None):
401+ return self.remove_item("package", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
402+
403+ def remove_file(self, ref, recursive=False, delete=True, with_triggers=True, logger=None):
404+ return self.remove_item("file", ref, recursive=recursive, delete=delete, with_triggers=with_triggers, logger=logger)
405+
406+ # ==========================================================================
407+
408+ def rename_item(self, what, ref, newname, logger=None):
409+ self.log("rename_item(%s)"%what,[ref.name,newname])
410+ return self.get_items(what).rename(ref,newname,logger=logger)
411+
412+ def rename_distro(self, ref, newname, logger=None):
413+ return self.rename_item("distro", ref, newname, logger=logger)
414+
415+ def rename_profile(self, ref, newname, logger=None):
416+ return self.rename_item("profile", ref, newname, logger=logger)
417+
418+ def rename_system(self, ref, newname, logger=None):
419+ return self.rename_item("system", ref, newname, logger=logger)
420+
421+ def rename_repo(self, ref, newname, logger=None):
422+ return self.rename_item("repo", ref, newname, logger=logger)
423+
424+ def rename_image(self, ref, newname, logger=None):
425+ return self.rename_item("image", ref, newname, logger=logger)
426+
427+ def rename_mgmtclass(self, ref, newname, logger=None):
428+ return self.rename_item("mgmtclass", ref, newname, logger=logger)
429+
430+ def rename_package(self, ref, newname, logger=None):
431+ return self.rename_item("package", ref, newname, logger=logger)
432+
433+ def rename_file(self, ref, newname, logger=None):
434+ return self.rename_item("file", ref, newname, logger=logger)
435+
436+ # ==========================================================================
437+
438+ # FIXME: add a new_item method
439+
440+ def new_distro(self,is_subobject=False):
441+ self.log("new_distro",[is_subobject])
442+ return self._config.new_distro(is_subobject=is_subobject)
443+
444+ def new_profile(self,is_subobject=False):
445+ self.log("new_profile",[is_subobject])
446+ return self._config.new_profile(is_subobject=is_subobject)
447+
448+ def new_system(self,is_subobject=False):
449+ self.log("new_system",[is_subobject])
450+ return self._config.new_system(is_subobject=is_subobject)
451+
452+ def new_repo(self,is_subobject=False):
453+ self.log("new_repo",[is_subobject])
454+ return self._config.new_repo(is_subobject=is_subobject)
455+
456+ def new_image(self,is_subobject=False):
457+ self.log("new_image",[is_subobject])
458+ return self._config.new_image(is_subobject=is_subobject)
459+
460+ def new_mgmtclass(self,is_subobject=False):
461+ self.log("new_mgmtclass",[is_subobject])
462+ return self._config.new_mgmtclass(is_subobject=is_subobject)
463+
464+ def new_package(self,is_subobject=False):
465+ self.log("new_package",[is_subobject])
466+ return self._config.new_package(is_subobject=is_subobject)
467+
468+ def new_file(self,is_subobject=False):
469+ self.log("new_file",[is_subobject])
470+ return self._config.new_file(is_subobject=is_subobject)
471+
472+ # ==========================================================================
473+
474+ def add_item(self, what, ref, check_for_duplicate_names=False, save=True,logger=None):
475+ self.log("add_item(%s)"%what,[ref.name])
476+ return self.get_items(what).add(ref,check_for_duplicate_names=check_for_duplicate_names,save=save,logger=logger)
477+
478+ def add_distro(self, ref, check_for_duplicate_names=False, save=True, logger=None):
479+ return self.add_item("distro", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
480+
481+ def add_profile(self, ref, check_for_duplicate_names=False,save=True, logger=None):
482+ return self.add_item("profile", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
483+
484+ def add_system(self, ref, check_for_duplicate_names=False, check_for_duplicate_netinfo=False, save=True, logger=None):
485+ return self.add_item("system", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
486+
487+ def add_repo(self, ref, check_for_duplicate_names=False,save=True,logger=None):
488+ return self.add_item("repo", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
489+
490+ def add_image(self, ref, check_for_duplicate_names=False,save=True, logger=None):
491+ return self.add_item("image", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
492+
493+ def add_mgmtclass(self, ref, check_for_duplicate_names=False,save=True, logger=None):
494+ return self.add_item("mgmtclass", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
495+
496+ def add_package(self, ref, check_for_duplicate_names=False,save=True, logger=None):
497+ return self.add_item("package", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
498+
499+ def add_file(self, ref, check_for_duplicate_names=False,save=True, logger=None):
500+ return self.add_item("file", ref, check_for_duplicate_names=check_for_duplicate_names, save=save,logger=logger)
501+
502+ # ==========================================================================
503+
504+ # FIXME: find_items should take all the arguments the other find
505+ # methods do.
506+
507+ def find_items(self, what, criteria=None):
508+ self.log("find_items",[what])
509+ # defaults
510+ if criteria is None:
511+ criteria={}
512+ items=self._config.get_items(what)
513+ # empty criteria returns everything
514+ if criteria == {}:
515+ res=items
516+ else:
517+ res=items.find(return_list=True, no_errors=False, **criteria)
518+ return res
519+
520+
521+ def find_distro(self, name=None, return_list=False, no_errors=False, **kargs):
522+ return self._config.distros().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
523+
524+ def find_profile(self, name=None, return_list=False, no_errors=False, **kargs):
525+ return self._config.profiles().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
526+
527+ def find_system(self, name=None, return_list=False, no_errors=False, **kargs):
528+ return self._config.systems().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
529+
530+ def find_repo(self, name=None, return_list=False, no_errors=False, **kargs):
531+ return self._config.repos().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
532+
533+ def find_image(self, name=None, return_list=False, no_errors=False, **kargs):
534+ return self._config.images().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
535+
536+ def find_mgmtclass(self, name=None, return_list=False, no_errors=False, **kargs):
537+ return self._config.mgmtclasses().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
538+
539+ def find_package(self, name=None, return_list=False, no_errors=False, **kargs):
540+ return self._config.packages().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
541+
542+ def find_file(self, name=None, return_list=False, no_errors=False, **kargs):
543+ return self._config.files().find(name=name, return_list=return_list, no_errors=no_errors, **kargs)
544+
545+ # ==========================================================================
546+
547+ def __since(self,mtime,collector,collapse=False):
548+ """
549+ Called by get_*_since functions.
550+ """
551+ results1 = collector()
552+ results2 = []
553+ for x in results1:
554+ if x.mtime == 0 or x.mtime >= mtime:
555+ if not collapse:
556+ results2.append(x)
557+ else:
558+ results2.append(x.to_datastruct())
559+ return results2
560+
561+ def get_distros_since(self,mtime,collapse=False):
562+ """
563+ Returns distros modified since a certain time (in seconds since Epoch)
564+ collapse=True specifies returning a hash instead of objects.
565+ """
566+ return self.__since(mtime,self.distros,collapse=collapse)
567+
568+ def get_profiles_since(self,mtime,collapse=False):
569+ return self.__since(mtime,self.profiles,collapse=collapse)
570+
571+ def get_systems_since(self,mtime,collapse=False):
572+ return self.__since(mtime,self.systems,collapse=collapse)
573+
574+ def get_repos_since(self,mtime,collapse=False):
575+ return self.__since(mtime,self.repos,collapse=collapse)
576+
577+ def get_images_since(self,mtime,collapse=False):
578+ return self.__since(mtime,self.images,collapse=collapse)
579+
580+ def get_mgmtclasses_since(self,mtime,collapse=False):
581+ return self.__since(mtime,self.mgmtclasses,collapse=collapse)
582+
583+ def get_packages_since(self,mtime,collapse=False):
584+ return self.__since(mtime,self.packages,collapse=collapse)
585+
586+ def get_files_since(self,mtime,collapse=False):
587+ return self.__since(mtime,self.files,collapse=collapse)
588+
589+ # ==========================================================================
590+
591+ def dump_vars(self, obj, format=False):
592+ return obj.dump_vars(format)
593+
594+ # ==========================================================================
595+
596+ def auto_add_repos(self):
597+ """
598+ Import any repos this server knows about and mirror them.
599+ Credit: Seth Vidal.
600+ """
601+ self.log("auto_add_repos")
602+ try:
603+ import yum
604+ except:
605+ raise CX(_("yum is not installed"))
606+
607+ version = yum.__version__
608+ (a,b,c) = version.split(".")
609+ version = a* 1000 + b*100 + c
610+ if version < 324:
611+ raise CX(_("need yum > 3.2.4 to proceed"))
612+
613+ base = yum.YumBase()
614+ base.doRepoSetup()
615+ repos = base.repos.listEnabled()
616+ if len(repos) == 0:
617+ raise CX(_("no repos enabled/available -- giving up."))
618+
619+ for repo in repos:
620+ url = repo.urls[0]
621+ cobbler_repo = self.new_repo()
622+ auto_name = repo.name.replace(" ","")
623+ # FIXME: probably doesn't work for yum-rhn-plugin ATM
624+ cobbler_repo.set_mirror(url)
625+ cobbler_repo.set_name(auto_name)
626+ print "auto adding: %s (%s)" % (auto_name, url)
627+ self._config.repos().add(cobbler_repo,save=True)
628+
629+ # run cobbler reposync to apply changes
630+ return True
631+
632+ # ==========================================================================
633+
634+ def get_repo_config_for_profile(self,obj):
635+ return self.yumgen.get_yum_config(obj,True)
636+
637+ def get_repo_config_for_system(self,obj):
638+ return self.yumgen.get_yum_config(obj,False)
639+
640+ # ==========================================================================
641+
642+ def get_template_file_for_profile(self,obj,path):
643+ template_results = self.pxegen.write_templates(obj,False,path)
644+ if template_results.has_key(path):
645+ return template_results[path]
646+ else:
647+ return "# template path not found for specified profile"
648+
649+ def get_template_file_for_system(self,obj,path):
650+ template_results = self.pxegen.write_templates(obj,False,path)
651+ if template_results.has_key(path):
652+ return template_results[path]
653+ else:
654+ return "# template path not found for specified system"
655+
656+ # ==========================================================================
657+
658+ def generate_kickstart(self,profile,system):
659+ self.log("generate_kickstart")
660+ if system:
661+ return self.kickgen.generate_kickstart_for_system(system)
662+ else:
663+ return self.kickgen.generate_kickstart_for_profile(profile)
664+
665+ # ==========================================================================
666+
667+ def check(self, logger=None):
668+ """
669+ See if all preqs for network booting are valid. This returns
670+ a list of strings containing instructions on things to correct.
671+ An empty list means there is nothing to correct, but that still
672+ doesn't mean there are configuration errors. This is mainly useful
673+ for human admins, who may, for instance, forget to properly set up
674+ their TFTP servers for PXE, etc.
675+ """
676+ self.log("check")
677+ check = action_check.BootCheck(self._config, logger=logger)
678+ return check.run()
679+
680+ # ==========================================================================
681+
682+ def dlcontent(self,force=False,logger=None):
683+ """
684+ Downloads bootloader content that may not be avialable in packages
685+ for the given arch, ex: if installing on PPC, get syslinux. If installing
686+ on x86_64, get elilo, etc.
687+ """
688+ # FIXME: teach code that copies it to grab from the right place
689+ self.log("dlcontent")
690+ grabber = action_dlcontent.ContentDownloader(self._config, logger=logger)
691+ return grabber.run(force)
692+
693+ # ==========================================================================
694+
695+ def validateks(self, logger=None):
696+ """
697+ Use ksvalidator (from pykickstart, if available) to determine
698+ whether the cobbler kickstarts are going to be (likely) well
699+ accepted by Anaconda. Presence of an error does not indicate
700+ the kickstart is bad, only that the possibility exists. ksvalidator
701+ is not available on all platforms and can not detect "future"
702+ kickstart format correctness.
703+ """
704+ self.log("validateks")
705+ validator = action_validate.Validate(self._config, logger=logger)
706+ return validator.run()
707+
708+ # ==========================================================================
709+
710+ def sync(self,verbose=False, logger=None):
711+ """
712+ Take the values currently written to the configuration files in
713+ /etc, and /var, and build out the information tree found in
714+ /tftpboot. Any operations done in the API that have not been
715+ saved with serialize() will NOT be synchronized with this command.
716+ """
717+ self.log("sync")
718+ sync = self.get_sync(verbose=verbose, logger=logger)
719+ return sync.run()
720+
721+ # ==========================================================================
722+
723+ def get_sync(self,verbose=False,logger=None):
724+ self.dhcp = self.get_module_from_file(
725+ "dhcp",
726+ "module",
727+ "manage_isc"
728+ ).get_manager(self._config,logger)
729+ self.dns = self.get_module_from_file(
730+ "dns",
731+ "module",
732+ "manage_bind"
733+ ).get_manager(self._config,logger)
734+ self.tftpd = self.get_module_from_file(
735+ "tftpd",
736+ "module",
737+ "in_tftpd",
738+ ).get_manager(self._config,logger)
739+
740+ return action_sync.BootSync(self._config,dhcp=self.dhcp,dns=self.dns,tftpd=self.tftpd,verbose=verbose,logger=logger)
741+
742+ # ==========================================================================
743+
744+ def reposync(self, name=None, tries=1, nofail=False, logger=None):
745+ """
746+ Take the contents of /var/lib/cobbler/repos and update them --
747+ or create the initial copy if no contents exist yet.
748+ """
749+ self.log("reposync",[name])
750+ reposync = action_reposync.RepoSync(self._config, tries=tries, nofail=nofail, logger=logger)
751+ return reposync.run(name)
752+
753+ # ==========================================================================
754+
755+ def status(self,mode,logger=None):
756+ statusifier = action_status.BootStatusReport(self._config,mode,logger=logger)
757+ return statusifier.run()
758+
759+ # ==========================================================================
760+
761+ def import_tree(self,mirror_url,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None,breed=None,os_version=None,logger=None):
762+ """
763+ Automatically import a directory tree full of distribution files.
764+ mirror_url can be a string that represents a path, a user@host
765+ syntax for SSH, or an rsync:// address. If mirror_url is a
766+ filesystem path and mirroring is not desired, set network_root
767+ to something like "nfs://path/to/mirror_url/root"
768+ """
769+ self.log("import_tree",[mirror_url, mirror_name, network_root, kickstart_file, rsync_flags])
770+
771+ # both --path and --name are required arguments
772+ if mirror_url is None:
773+ self.log("import failed. no --path specified")
774+ return False
775+ if mirror_name is None:
776+ self.log("import failed. no --name specified")
777+ return False
778+
779+ path = os.path.normpath("%s/ks_mirror/%s" % (self.settings().webdir, mirror_name))
780+ if arch is not None:
781+ arch = arch.lower()
782+ if arch == "x86":
783+ # be consistent
784+ arch = "i386"
785+ if path.split("-")[-1] != arch:
786+ path += ("-%s" % arch)
787+
788+ # we need to mirror (copy) the files
789+ self.log("importing from a network location, running rsync to fetch the files first")
790+
791+ utils.mkdir(path)
792+
793+ # prevent rsync from creating the directory name twice
794+ # if we are copying via rsync
795+
796+ if not mirror_url.endswith("/"):
797+ mirror_url = "%s/" % mirror_url
798+
799+ if mirror_url.startswith("http://") or mirror_url.startswith("ftp://") or mirror_url.startswith("nfs://"):
800+ # http mirrors are kind of primative. rsync is better.
801+ # that's why this isn't documented in the manpage and we don't support them.
802+ # TODO: how about adding recursive FTP as an option?
803+ self.log("unsupported protocol")
804+ return False
805+ else:
806+ # good, we're going to use rsync..
807+ # we don't use SSH for public mirrors and local files.
808+ # presence of user@host syntax means use SSH
809+ spacer = ""
810+ if not mirror_url.startswith("rsync://") and not mirror_url.startswith("/"):
811+ spacer = ' -e "ssh" '
812+ rsync_cmd = RSYNC_CMD
813+ if rsync_flags:
814+ rsync_cmd = rsync_cmd + " " + rsync_flags
815+
816+ # kick off the rsync now
817+ utils.run_this(rsync_cmd, (spacer, mirror_url, path), self.logger)
818+
819+ if network_root is not None:
820+ # in addition to mirroring, we're going to assume the path is available
821+ # over http, ftp, and nfs, perhaps on an external filer. scanning still requires
822+ # --mirror is a filesystem path, but --available-as marks the network path.
823+ # this allows users to point the path at a directory containing just the network
824+ # boot files while the rest of the distro files are available somewhere else.
825+
826+ # find the filesystem part of the path, after the server bits, as each distro
827+ # URL needs to be calculated relative to this.
828+
829+ if not network_root.endswith("/"):
830+ network_root = network_root + "/"
831+ valid_roots = [ "nfs://", "ftp://", "http://" ]
832+ for valid_root in valid_roots:
833+ if network_root.startswith(valid_root):
834+ break
835+ else:
836+ self.log("Network root given to --available-as must be nfs://, ftp://, or http://")
837+ return False
838+
839+ if network_root.startswith("nfs://"):
840+ try:
841+ (a,b,rest) = network_root.split(":",3)
842+ except:
843+ self.log("Network root given to --available-as is missing a colon, please see the manpage example.")
844+ return False
845+
846+ importer_modules = self.get_modules_in_category("manage/import")
847+ for importer_module in importer_modules:
848+ manager = importer_module.get_import_manager(self._config,logger)
849+ try:
850+ (found,pkgdir) = manager.check_for_signature(path,breed)
851+ if found:
852+ self.log("running import manager: %s" % manager.what())
853+ return manager.run(pkgdir,mirror_name,path,network_root,kickstart_file,rsync_flags,arch,breed,os_version)
854+ except:
855+ self.log("an exception occured while running the import manager")
856+ self.log("error was: %s" % sys.exc_info()[1])
857+ continue
858+ self.log("No import managers found a valid signature at the location specified")
859+ # FIXME: since we failed, we should probably remove the
860+ # path tree we created above so we don't leave cruft around
861+ return False
862+
863+ # ==========================================================================
864+
865+ def acl_config(self,adduser=None,addgroup=None,removeuser=None,removegroup=None, logger=None):
866+ """
867+ Configures users/groups to run the cobbler CLI as non-root.
868+ Pass in only one option at a time. Powers "cobbler aclconfig"
869+ """
870+ acl = action_acl.AclConfig(self._config, logger)
871+ return acl.run(
872+ adduser=adduser,
873+ addgroup=addgroup,
874+ removeuser=removeuser,
875+ removegroup=removegroup
876+ )
877+
878+ # ==========================================================================
879+
880+ def serialize(self):
881+ """
882+ Save the config file(s) to disk.
883+ Cobbler internal use only.
884+ """
885+ return self._config.serialize()
886+
887+ def deserialize(self):
888+ """
889+ Load the current configuration from config file(s)
890+ Cobbler internal use only.
891+ """
892+ return self._config.deserialize()
893+
894+ def deserialize_raw(self,collection_name):
895+ """
896+ Get the collection back just as raw data.
897+ Cobbler internal use only.
898+ """
899+ return self._config.deserialize_raw(collection_name)
900+
901+ def deserialize_item_raw(self,collection_name,obj_name):
902+ """
903+ Get an object back as raw data.
904+ Can be very fast for shelve or catalog serializers
905+ Cobbler internal use only.
906+ """
907+ return self._config.deserialize_item_raw(collection_name,obj_name)
908+
909+ # ==========================================================================
910+
911+ def get_module_by_name(self,module_name):
912+ """
913+ Returns a loaded cobbler module named 'name', if one exists, else None.
914+ Cobbler internal use only.
915+ """
916+ return module_loader.get_module_by_name(module_name)
917+
918+ def get_module_from_file(self,section,name,fallback=None):
919+ """
920+ Looks in /etc/cobbler/modules.conf for a section called 'section'
921+ and a key called 'name', and then returns the module that corresponds
922+ to the value of that key.
923+ Cobbler internal use only.
924+ """
925+ return module_loader.get_module_from_file(section,name,fallback)
926+
927+ def get_modules_in_category(self,category):
928+ """
929+ Returns all modules in a given category, for instance "serializer", or "cli".
930+ Cobbler internal use only.
931+ """
932+ return module_loader.get_modules_in_category(category)
933+
934+ # ==========================================================================
935+
936+ def authenticate(self,user,password):
937+ """
938+ (Remote) access control.
939+ Cobbler internal use only.
940+ """
941+ rc = self.authn.authenticate(self,user,password)
942+ self.log("authenticate",[user,rc])
943+ return rc
944+
945+ def authorize(self,user,resource,arg1=None,arg2=None):
946+ """
947+ (Remote) access control.
948+ Cobbler internal use only.
949+ """
950+ rc = self.authz.authorize(self,user,resource,arg1,arg2)
951+ self.log("authorize",[user,resource,arg1,arg2,rc],debug=True)
952+ return rc
953+
954+ # ==========================================================================
955+
956+ def build_iso(self,iso=None,profiles=None,systems=None,buildisodir=None,distro=None,standalone=None,source=None, exclude_dns=None, logger=None):
957+ builder = action_buildiso.BuildIso(self._config, logger=logger)
958+ return builder.run(
959+ iso=iso, profiles=profiles, systems=systems, buildisodir=buildisodir, distro=distro, standalone=standalone, source=source, exclude_dns=exclude_dns
960+ )
961+
962+ # ==========================================================================
963+
964+ def hardlink(self, logger=None):
965+ linker = action_hardlink.HardLinker(self._config, logger=logger)
966+ return linker.run()
967+
968+ # ==========================================================================
969+
970+ def replicate(self, cobbler_master = None, distro_patterns="", profile_patterns="", system_patterns="", repo_patterns="", image_patterns="",
971+ mgmtclass_patterns=None, package_patterns=None, file_patterns=None, prune=False, omit_data=False, sync_all=False, logger=None):
972+ """
973+ Pull down data/configs from a remote cobbler server that is a master to this server.
974+ """
975+ replicator = action_replicate.Replicate(self._config, logger=logger)
976+ return replicator.run(
977+ cobbler_master = cobbler_master,
978+ distro_patterns = distro_patterns,
979+ profile_patterns = profile_patterns,
980+ system_patterns = system_patterns,
981+ repo_patterns = repo_patterns,
982+ image_patterns = image_patterns,
983+ mgmtclass_patterns = mgmtclass_patterns,
984+ package_patterns = package_patterns,
985+ file_patterns = file_patterns,
986+ prune = prune,
987+ omit_data = omit_data,
988+ sync_all = sync_all
989+ )
990+
991+ # ==========================================================================
992+
993+ def report(self, report_what = None, report_name = None, report_type = None, report_fields = None, report_noheaders = None):
994+ """
995+ Report functionality for cobbler
996+ """
997+ reporter = action_report.Report(self._config)
998+ return reporter.run(report_what = report_what, report_name = report_name,\
999+ report_type = report_type, report_fields = report_fields,\
1000+ report_noheaders = report_noheaders)
1001+
1002+ # ==========================================================================
1003+
1004+ def get_kickstart_templates(self):
1005+ return utils.get_kickstar_templates(self)
1006+
1007+ # ==========================================================================
1008+
1009+ def power_on(self, system, user=None, password=None, logger=None):
1010+ """
1011+ Powers up a system that has power management configured.
1012+ """
1013+ return action_power.PowerTool(self._config,system,self,user,password,logger=logger).power("on")
1014+
1015+ def power_off(self, system, user=None, password=None, logger=None):
1016+ """
1017+ Powers down a system that has power management configured.
1018+ """
1019+ return action_power.PowerTool(self._config,system,self,user,password,logger=logger).power("off")
1020+
1021+ def reboot(self,system, user=None, password=None, logger=None):
1022+ """
1023+ Cycles power on a system that has power management configured.
1024+ """
1025+ self.power_off(system, user, password, logger=logger)
1026+ time.sleep(5)
1027+ return self.power_on(system, user, password, logger=logger)
1028+
1029+ def power_status(self, system, user=None, password=None, logger=None):
1030+ """
1031+ Returns the power status for a system that has power management configured.
1032+
1033+ @return: 0 the system is powered on, False if it's not or None on error
1034+ """
1035+ return action_power.PowerTool(self._config, system, self, user, password, logger = logger).power("status")
1036+
1037+
1038+ # ==========================================================================
1039+
1040+ def clear_logs(self, system, logger=None):
1041+ """
1042+ Clears console and anamon logs for system
1043+ """
1044+ return action_log.LogTool(self._config,system,self, logger=logger).clear()
1045+
1046+ def get_os_details(self):
1047+ return (self.dist, self.os_version)
1048
1049=== added file '.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/cobblerd.py'
1050--- .pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/cobblerd.py 1970-01-01 00:00:00 +0000
1051+++ .pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/cobblerd.py 2013-03-02 07:56:21 +0000
1052@@ -0,0 +1,145 @@
1053+"""
1054+cobbler daemon for logging remote syslog traffic during kickstart
1055+
1056+Copyright 2007-2009, Red Hat, Inc
1057+Michael DeHaan <mdehaan@redhat.com>
1058+
1059+This program is free software; you can redistribute it and/or modify
1060+it under the terms of the GNU General Public License as published by
1061+the Free Software Foundation; either version 2 of the License, or
1062+(at your option) any later version.
1063+
1064+This program is distributed in the hope that it will be useful,
1065+but WITHOUT ANY WARRANTY; without even the implied warranty of
1066+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1067+GNU General Public License for more details.
1068+
1069+You should have received a copy of the GNU General Public License
1070+along with this program; if not, write to the Free Software
1071+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1072+02110-1301 USA
1073+"""
1074+
1075+import sys
1076+import socket
1077+import time
1078+import os
1079+import SimpleXMLRPCServer
1080+import glob
1081+from utils import _
1082+import xmlrpclib
1083+import binascii
1084+import utils
1085+
1086+import api as cobbler_api
1087+import yaml # Howell Clark version
1088+import utils
1089+import remote
1090+
1091+
1092+def main():
1093+ core(logger=None)
1094+
1095+def core(api):
1096+
1097+ bootapi = api
1098+ settings = bootapi.settings()
1099+ xmlrpc_port = settings.xmlrpc_port
1100+
1101+ regen_ss_file()
1102+ do_xmlrpc_tasks(bootapi, settings, xmlrpc_port)
1103+
1104+def regen_ss_file():
1105+ # this is only used for Kerberos auth at the moment.
1106+ # it identifies XMLRPC requests from Apache that have already
1107+ # been cleared by Kerberos.
1108+ ssfile = "/var/lib/cobbler/web.ss"
1109+ fd = open("/dev/urandom")
1110+ data = fd.read(512)
1111+ fd.close()
1112+ if not os.path.isfile(ssfile):
1113+ um = os.umask(int('0027',16))
1114+ fd = open(ssfile,"w+")
1115+ fd.write(binascii.hexlify(data))
1116+ fd.close()
1117+ os.umask(um)
1118+ utils.os_system("chmod 700 /var/lib/cobbler/web.ss")
1119+ http_user = "apache"
1120+ if utils.check_dist() in [ "debian", "ubuntu" ]:
1121+ http_user = "www-data"
1122+ utils.os_system("chown %s /var/lib/cobbler/web.ss"%http_user )
1123+ else:
1124+ fd = open(ssfile,"w+")
1125+ fd.write(binascii.hexlify(data))
1126+ fd.close()
1127+
1128+ return 1
1129+
1130+def do_xmlrpc_tasks(bootapi, settings, xmlrpc_port):
1131+ do_xmlrpc_rw(bootapi, settings, xmlrpc_port)
1132+
1133+#def do_other_tasks(bootapi, settings, syslog_port, logger):
1134+#
1135+# # FUTURE: this should also start the Web UI, if the dependencies
1136+# # are available.
1137+#
1138+# if os.path.exists("/usr/bin/avahi-publish-service"):
1139+# pid2 = os.fork()
1140+# if pid2 == 0:
1141+# do_syslog(bootapi, settings, syslog_port, logger)
1142+# else:
1143+# do_avahi(bootapi, settings, logger)
1144+# os.waitpid(pid2, 0)
1145+# else:
1146+# do_syslog(bootapi, settings, syslog_port, logger)
1147+
1148+
1149+def log(logger,msg):
1150+ if logger is not None:
1151+ logger.info(msg)
1152+ else:
1153+ print >>sys.stderr, msg
1154+
1155+#def do_avahi(bootapi, settings, logger):
1156+# # publish via zeroconf. This command will not terminate
1157+# log(logger, "publishing avahi service")
1158+# cmd = [ "/usr/bin/avahi-publish-service",
1159+# "cobblerd",
1160+# "_http._tcp",
1161+# "%s" % settings.xmlrpc_port ]
1162+# proc = sub_process.Popen(cmd, shell=False, stderr=sub_process.PIPE, stdout=sub_process.PIPE, close_fds=True)
1163+# proc.communicate()[0]
1164+# log(logger, "avahi service terminated")
1165+
1166+
1167+def do_xmlrpc_rw(bootapi,settings,port):
1168+
1169+ xinterface = remote.ProxiedXMLRPCInterface(bootapi,remote.CobblerXMLRPCInterface)
1170+ server = remote.CobblerXMLRPCServer(('127.0.0.1', port))
1171+ server.logRequests = 0 # don't print stuff
1172+ xinterface.logger.debug("XMLRPC running on %s" % port)
1173+ server.register_instance(xinterface)
1174+
1175+ while True:
1176+ try:
1177+ print "SERVING!"
1178+ server.serve_forever()
1179+ except IOError:
1180+ # interrupted? try to serve again
1181+ time.sleep(0.5)
1182+
1183+if __name__ == "__main__":
1184+
1185+ #main()
1186+
1187+ #bootapi = cobbler_api.BootAPI()
1188+ #settings = bootapi.settings()
1189+ #syslog_port = settings.syslog_port
1190+ #xmlrpc_port = settings.xmlrpc_port
1191+ #xmlrpc_port2 = settings.xmlrpc_rw_port
1192+ #logger = bootapi.logger_remote
1193+ #do_xmlrpc_unix(bootapi, settings, logger)
1194+
1195+ regen_ss_file()
1196+
1197+
1198
1199=== added file '.pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/serializer.py'
1200--- .pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/serializer.py 1970-01-01 00:00:00 +0000
1201+++ .pc/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch/cobbler/serializer.py 2013-03-02 07:56:21 +0000
1202@@ -0,0 +1,165 @@
1203+"""
1204+Serializer code for cobbler
1205+Now adapted to support different storage backends
1206+
1207+Copyright 2006-2009, Red Hat, Inc
1208+Michael DeHaan <mdehaan@redhat.com>
1209+
1210+This program is free software; you can redistribute it and/or modify
1211+it under the terms of the GNU General Public License as published by
1212+the Free Software Foundation; either version 2 of the License, or
1213+(at your option) any later version.
1214+
1215+This program is distributed in the hope that it will be useful,
1216+but WITHOUT ANY WARRANTY; without even the implied warranty of
1217+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1218+GNU General Public License for more details.
1219+
1220+You should have received a copy of the GNU General Public License
1221+along with this program; if not, write to the Free Software
1222+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1223+02110-1301 USA
1224+"""
1225+
1226+import errno
1227+import os
1228+from utils import _
1229+import fcntl
1230+import traceback
1231+import sys
1232+import signal
1233+import time
1234+
1235+from cexceptions import *
1236+import api as cobbler_api
1237+
1238+LOCK_ENABLED = True
1239+LOCK_HANDLE = None
1240+
1241+def handler(num,frame):
1242+ print >> sys.stderr, "Ctrl-C not allowed during writes. Please wait."
1243+ return True
1244+
1245+def __grab_lock():
1246+ """
1247+ Dual purpose locking:
1248+ (A) flock to avoid multiple process access
1249+ (B) block signal handler to avoid ctrl+c while writing YAML
1250+ """
1251+ try:
1252+ if LOCK_ENABLED:
1253+ if not os.path.exists("/var/lib/cobbler/lock"):
1254+ fd = open("/var/lib/cobbler/lock","w+")
1255+ fd.close()
1256+ LOCK_HANDLE = open("/var/lib/cobbler/lock","r")
1257+ fcntl.flock(LOCK_HANDLE.fileno(), fcntl.LOCK_EX)
1258+ return True
1259+ except:
1260+ # this is pretty much FATAL, avoid corruption and quit now.
1261+ traceback.print_exc()
1262+ sys.exit(7)
1263+
1264+def __release_lock(with_changes=False):
1265+ if with_changes:
1266+ # this file is used to know when the last config change
1267+ # was made -- allowing the API to work more smoothly without
1268+ # a lot of unneccessary reloads.
1269+ old = os.umask(0x777)
1270+ fd = open("/var/lib/cobbler/.mtime","w")
1271+ fd.write("%f" % time.time())
1272+ fd.close()
1273+ os.umask(old)
1274+ if LOCK_ENABLED:
1275+ LOCK_HANDLE = open("/var/lib/cobbler/lock","r")
1276+ fcntl.flock(LOCK_HANDLE.fileno(), fcntl.LOCK_UN)
1277+ LOCK_HANDLE.close()
1278+ return True
1279+
1280+def serialize(obj):
1281+ """
1282+ Save a collection to disk or other storage.
1283+ """
1284+ __grab_lock()
1285+ storage_module = __get_storage_module(obj.collection_type())
1286+ storage_module.serialize(obj)
1287+ __release_lock()
1288+ return True
1289+
1290+def serialize_item(collection, item):
1291+ """
1292+ Save an item.
1293+ """
1294+ __grab_lock()
1295+ storage_module = __get_storage_module(collection.collection_type())
1296+ save_fn = getattr(storage_module, "serialize_item", None)
1297+ if save_fn is None:
1298+ rc = storage_module.serialize(collection)
1299+ else:
1300+ rc = save_fn(collection,item)
1301+ __release_lock(with_changes=True)
1302+ return rc
1303+
1304+def serialize_delete(collection, item):
1305+ """
1306+ Delete an object from a saved state.
1307+ """
1308+ __grab_lock()
1309+ storage_module = __get_storage_module(collection.collection_type())
1310+ delete_fn = getattr(storage_module, "serialize_delete", None)
1311+ if delete_fn is None:
1312+ rc = storage_module.serialize(collection)
1313+ else:
1314+ rc = delete_fn(collection,item)
1315+ __release_lock(with_changes=True)
1316+ return rc
1317+
1318+def deserialize(obj,topological=True):
1319+ """
1320+ Fill in an empty collection from disk or other storage
1321+ """
1322+ __grab_lock()
1323+ storage_module = __get_storage_module(obj.collection_type())
1324+ rc = storage_module.deserialize(obj,topological)
1325+ __release_lock()
1326+ return rc
1327+
1328+def deserialize_raw(collection_type):
1329+ """
1330+ Return the datastructure corresponding to the serialized
1331+ disk state, without going through the Cobbler object system.
1332+ Much faster, when you don't need the objects.
1333+ """
1334+ __grab_lock()
1335+ storage_module = __get_storage_module(collection_type)
1336+ rc = storage_module.deserialize_raw(collection_type)
1337+ __release_lock()
1338+ return rc
1339+
1340+def deserialize_item(collection_type, item_name):
1341+ """
1342+ Get a specific record.
1343+ """
1344+ __grab_lock()
1345+ storage_module = __get_storage_module(collection_type)
1346+ rc = storage_module.deserialize_item(collection_type, item_name)
1347+ __release_lock()
1348+ return rc
1349+
1350+def deserialize_item_raw(collection_type, item_name):
1351+ __grab_lock()
1352+ storage_module = __get_storage_module(collection_type)
1353+ rc = storage_module.deserialize_item_raw(collection_type, item_name)
1354+ __release_lock()
1355+ return rc
1356+
1357+def __get_storage_module(collection_type):
1358+ """
1359+ Look up serializer in /etc/cobbler/modules.conf
1360+ """
1361+ capi = cobbler_api.BootAPI()
1362+ return capi.get_module_from_file("serializers",collection_type,"serializer_catalog")
1363+
1364+if __name__ == "__main__":
1365+ __grab_lock()
1366+ __release_lock()
1367+
1368
1369=== modified file '.pc/applied-patches'
1370--- .pc/applied-patches 2012-04-10 12:33:17 +0000
1371+++ .pc/applied-patches 2013-03-02 07:56:21 +0000
1372@@ -30,3 +30,4 @@
1373 69_issue93_fix_trace_in_write_pxe_file.patch
1374 70_replace_pxe_menu_title.patch
1375 71_fix_tftp_bin_name.patch
1376+72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch
1377
1378=== modified file 'cobbler/api.py'
1379--- cobbler/api.py 2012-02-01 11:04:11 +0000
1380+++ cobbler/api.py 2013-03-02 07:56:21 +0000
1381@@ -181,11 +181,9 @@
1382 API instance, regardless of the serializer type.
1383 """
1384 if not os.path.exists("/var/lib/cobbler/.mtime"):
1385- old = os.umask(0x777)
1386- fd = open("/var/lib/cobbler/.mtime","w")
1387- fd.write("0")
1388- fd.close()
1389- os.umask(old)
1390+ fd = os.open("/var/lib/cobbler/.mtime", os.O_CREAT|os.O_RDWR, 0200)
1391+ os.write(fd, "0")
1392+ os.close(fd)
1393 return 0
1394 fd = open("/var/lib/cobbler/.mtime")
1395 data = fd.read().strip()
1396
1397=== modified file 'cobbler/cobblerd.py'
1398--- cobbler/cobblerd.py 2011-03-11 07:59:55 +0000
1399+++ cobbler/cobblerd.py 2013-03-02 07:56:21 +0000
1400@@ -58,20 +58,17 @@
1401 data = fd.read(512)
1402 fd.close()
1403 if not os.path.isfile(ssfile):
1404- um = os.umask(int('0027',16))
1405- fd = open(ssfile,"w+")
1406- fd.write(binascii.hexlify(data))
1407- fd.close()
1408- os.umask(um)
1409- utils.os_system("chmod 700 /var/lib/cobbler/web.ss")
1410+ fd = os.open(ssfile,os.O_CREAT|os.O_RDWR,0600)
1411+ os.write(fd,binascii.hexlify(data))
1412+ os.close(fd)
1413 http_user = "apache"
1414 if utils.check_dist() in [ "debian", "ubuntu" ]:
1415 http_user = "www-data"
1416 utils.os_system("chown %s /var/lib/cobbler/web.ss"%http_user )
1417 else:
1418- fd = open(ssfile,"w+")
1419- fd.write(binascii.hexlify(data))
1420- fd.close()
1421+ fd = os.open(ssfile,os.O_CREAT|os.O_RDWR,0600)
1422+ os.write(fd,binascii.hexlify(data))
1423+ os.close(fd)
1424
1425 return 1
1426
1427
1428=== modified file 'cobbler/serializer.py'
1429--- cobbler/serializer.py 2011-11-15 12:35:40 +0000
1430+++ cobbler/serializer.py 2013-03-02 07:56:21 +0000
1431@@ -64,11 +64,9 @@
1432 # this file is used to know when the last config change
1433 # was made -- allowing the API to work more smoothly without
1434 # a lot of unneccessary reloads.
1435- old = os.umask(0x777)
1436- fd = open("/var/lib/cobbler/.mtime","w")
1437- fd.write("%f" % time.time())
1438- fd.close()
1439- os.umask(old)
1440+ fd = os.open("/var/lib/cobbler/.mtime", os.O_CREAT|os.O_RDWR, 0200)
1441+ os.write(fd, "%f" % time.time())
1442+ os.close(fd)
1443 if LOCK_ENABLED:
1444 LOCK_HANDLE = open("/var/lib/cobbler/lock","r")
1445 fcntl.flock(LOCK_HANDLE.fileno(), fcntl.LOCK_UN)
1446
1447=== modified file 'debian/changelog'
1448--- debian/changelog 2012-04-10 12:33:17 +0000
1449+++ debian/changelog 2013-03-02 07:56:21 +0000
1450@@ -1,3 +1,18 @@
1451+cobbler (2.2.2-0ubuntu33.2) UNRELEASED; urgency=low
1452+
1453+ * debian/cobbler.config: Do not fail to install if cannot determine
1454+ default IP address. (LP: #1001846)
1455+
1456+ -- Bryan Fullerton <fehwalker@gmail.com> Mon, 25 Feb 2013 23:24:10 -0500
1457+
1458+cobbler (2.2.2-0ubuntu33.1) precise-proposed; urgency=low
1459+
1460+ * debian/patches/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch:
1461+ correct wrong usage of os.umask() on cobbler/api.py, cobbler/cobblerd.py, and
1462+ cobbler/serializer.py. Imported from Upstream. (LP: #967815)
1463+
1464+ -- C de-Avillez <hggdh2@ubuntu.com> Sun, 09 Sep 2012 11:17:13 -0500
1465+
1466 cobbler (2.2.2-0ubuntu33) precise; urgency=low
1467
1468 * debian/patches/71_fix_tftp_bin_name.patch: Specify the correct name of
1469
1470=== modified file 'debian/cobbler.config'
1471--- debian/cobbler.config 2012-03-16 15:21:59 +0000
1472+++ debian/cobbler.config 2013-03-02 07:56:21 +0000
1473@@ -11,12 +11,13 @@
1474 # Sanitize some ip settings, so as to make cobbler more useful out of the box
1475 # This interface/ipaddr code was stolen from /usr/lib/byobu/ip_address
1476 while read Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT; do
1477- [ "$Mask" = "00000000" ] && break
1478+ [ "$Mask" = "00000000" ] && \
1479+ interface="$Iface" && \
1480+ ipaddr=$(LC_ALL=C /sbin/ip -4 addr list dev "$interface" scope global) && \
1481+ ipaddr=${ipaddr#* inet } && \
1482+ ipaddr=${ipaddr%%/*} && \
1483+ break
1484 done < /proc/net/route
1485- interface="$Iface"
1486- ipaddr=$(LC_ALL=C /sbin/ip -4 addr list dev "$interface" scope global)
1487- ipaddr=${ipaddr#* inet }
1488- ipaddr=${ipaddr%%/*}
1489
1490 db_get cobbler/server_and_next_server || true
1491 if ([ -n "$RET" ] && [ "$RET" != "127.0.0.1" ]); then
1492
1493=== added file 'debian/patches/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch'
1494--- debian/patches/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch 1970-01-01 00:00:00 +0000
1495+++ debian/patches/72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch 2013-03-02 07:56:21 +0000
1496@@ -0,0 +1,82 @@
1497+From: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
1498+Description: Corrects creation of some files with specific permissions in
1499+ /var/lib/cobbler
1500+Origin: upstream, https://github.com/jimi1283/cobbler/commit/ba1fc849135955ea8659f57218c44e6745a42ba5
1501+Bug: https://github.com/cobbler/cobbler/issues/117
1502+Bug-Ubuntu: https://launchpad.net/bugs/967815
1503+
1504+---
1505+ cobbler/api.py | 8 +++-----
1506+ cobbler/cobblerd.py | 15 ++++++---------
1507+ cobbler/serializer.py | 8 +++-----
1508+ 3 files changed, 12 insertions(+), 19 deletions(-)
1509+
1510+diff --git a/cobbler/api.py b/cobbler/api.py
1511+index 6745967..4cbf5cf 100644
1512+--- a/cobbler/api.py
1513++++ b/cobbler/api.py
1514+@@ -181,11 +181,9 @@ class BootAPI:
1515+ API instance, regardless of the serializer type.
1516+ """
1517+ if not os.path.exists("/var/lib/cobbler/.mtime"):
1518+- old = os.umask(0x777)
1519+- fd = open("/var/lib/cobbler/.mtime","w")
1520+- fd.write("0")
1521+- fd.close()
1522+- os.umask(old)
1523++ fd = os.open("/var/lib/cobbler/.mtime", os.O_CREAT|os.O_RDWR, 0200)
1524++ os.write(fd, "0")
1525++ os.close(fd)
1526+ return 0
1527+ fd = open("/var/lib/cobbler/.mtime")
1528+ data = fd.read().strip()
1529+diff --git a/cobbler/cobblerd.py b/cobbler/cobblerd.py
1530+index a6bc24e..c4ed16e 100644
1531+--- a/cobbler/cobblerd.py
1532++++ b/cobbler/cobblerd.py
1533+@@ -58,20 +58,17 @@ def regen_ss_file():
1534+ data = fd.read(512)
1535+ fd.close()
1536+ if not os.path.isfile(ssfile):
1537+- um = os.umask(int('0027',16))
1538+- fd = open(ssfile,"w+")
1539+- fd.write(binascii.hexlify(data))
1540+- fd.close()
1541+- os.umask(um)
1542+- utils.os_system("chmod 700 /var/lib/cobbler/web.ss")
1543++ fd = os.open(ssfile,os.O_CREAT|os.O_RDWR,0600)
1544++ os.write(fd,binascii.hexlify(data))
1545++ os.close(fd)
1546+ http_user = "apache"
1547+ if utils.check_dist() in [ "debian", "ubuntu" ]:
1548+ http_user = "www-data"
1549+ utils.os_system("chown %s /var/lib/cobbler/web.ss"%http_user )
1550+ else:
1551+- fd = open(ssfile,"w+")
1552+- fd.write(binascii.hexlify(data))
1553+- fd.close()
1554++ fd = os.open(ssfile,os.O_CREAT|os.O_RDWR,0600)
1555++ os.write(fd,binascii.hexlify(data))
1556++ os.close(fd)
1557+
1558+ return 1
1559+
1560+diff --git a/cobbler/serializer.py b/cobbler/serializer.py
1561+index 0f67dbe..f78c994 100644
1562+--- a/cobbler/serializer.py
1563++++ b/cobbler/serializer.py
1564+@@ -64,11 +64,9 @@ def __release_lock(with_changes=False):
1565+ # this file is used to know when the last config change
1566+ # was made -- allowing the API to work more smoothly without
1567+ # a lot of unneccessary reloads.
1568+- old = os.umask(0x777)
1569+- fd = open("/var/lib/cobbler/.mtime","w")
1570+- fd.write("%f" % time.time())
1571+- fd.close()
1572+- os.umask(old)
1573++ fd = os.open("/var/lib/cobbler/.mtime", os.O_CREAT|os.O_RDWR, 0200)
1574++ os.write(fd, "%f" % time.time())
1575++ os.close(fd)
1576+ if LOCK_ENABLED:
1577+ LOCK_HANDLE = open("/var/lib/cobbler/lock","r")
1578+ fcntl.flock(LOCK_HANDLE.fileno(), fcntl.LOCK_UN)
1579
1580=== modified file 'debian/patches/series'
1581--- debian/patches/series 2012-04-10 12:33:17 +0000
1582+++ debian/patches/series 2013-03-02 07:56:21 +0000
1583@@ -30,3 +30,4 @@
1584 69_issue93_fix_trace_in_write_pxe_file.patch
1585 70_replace_pxe_menu_title.patch
1586 71_fix_tftp_bin_name.patch
1587+72-BUGFIX-issue-117-incorrect-permissions-on-files-in-v.patch

Subscribers

People subscribed via source and target branches