From 134f6113711e8ced404ac24f66b5e4e6aa6c56d4 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 10 Mar 2008 11:40:33 -0400
Subject: Patch to allow overriding gpgcheck, +version bump
---
AUTHORS | 1 +
CHANGELOG | 3 ++-
MANIFEST.in | 1 -
cobbler.spec | 4 ++--
cobbler/action_reposync.py | 12 ++++++++++--
setup.py | 2 +-
6 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index a73f8a0..9a0fe8b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,6 +13,7 @@ Patches and other contributions from:
Tru Huynh
Matt Hyclak
Mihai Ibanescu
+ Vito Laurenza
Adrian Likins
David Lutterkort
Jim Meyering
diff --git a/CHANGELOG b/CHANGELOG
index c4d3bab..6cc350f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,9 @@
Cobbler CHANGELOG
(all entries mdehaan@redhat.com unless noted otherwise)
-* Fri Feb 22 2008 - 0.8.3
+- Mon Mar 10 2008 - 0.9.0
- Make createrepo get run for local cobbler reposync invocations as needed
+- patch to allow yumopts to override gpgcheck
* Fri Feb 22 2008 - 0.8.2
- fix to webui to allow repos to be edited there on profile page
diff --git a/MANIFEST.in b/MANIFEST.in
index 357cdcc..ed1d412 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -21,7 +21,6 @@ include scripts/index.py
include scripts/cobblerd
include scripts/findks.cgi
include scripts/nopxe.cgi
-include scripts/webui.cgi
include scripts/gateway.py
include scripts/post_install_trigger.cgi
include scripts/cobbler_auth_help
diff --git a/cobbler.spec b/cobbler.spec
index e56d298..4b90755 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -2,7 +2,7 @@
Summary: Boot server configurator
Name: cobbler
AutoReq: no
-Version: 0.8.2
+Version: 0.9.0
Release: 1%{?dist}
Source0: %{name}-%{version}.tar.gz
License: GPLv2+
@@ -190,7 +190,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
-* Fri Mar 07 2008 Michael DeHaan - 0.8.2-1
+* Fri Mar 07 2008 Michael DeHaan - 0.9.0-1
- Upstream changes (see CHANGELOG)
* Wed Feb 20 2008 Michael DeHaan - 0.8.1-1
diff --git a/cobbler/action_reposync.py b/cobbler/action_reposync.py
index 32d38bd..c86e0be 100644
--- a/cobbler/action_reposync.py
+++ b/cobbler/action_reposync.py
@@ -235,6 +235,8 @@ class RepoSync:
config_file = open(fname, "w+")
config_file.write("[%s]\n" % repo.name)
config_file.write("name=%s\n" % repo.name)
+ optenabled = False
+ optgpgcheck = False
if output:
line = "baseurl=http://${server}/cobbler/repo_mirror/%s\n" % (repo.name)
config_file.write(line)
@@ -242,15 +244,21 @@ class RepoSync:
# add them to the file
for x in repo.yumopts:
config_file.write("%s=%s\n" % (x, repo.yumopts[x]))
+ if x == "enabled":
+ optenabled = True
+ if x == "gpgcheck":
+ optgpgcheck = True
else:
line = "baseurl=%s\n" % repo.mirror
http_server = "%s:%s" % (self.settings.server, self.settings.http_port)
line = line.replace("@@server@@",http_server)
config_file.write(line)
- config_file.write("enabled=1\n")
+ if not optenabled:
+ config_file.write("enabled=1\n")
config_file.write("priority=%s\n" % repo.priority)
# FIXME: potentially might want a way to turn this on/off on a per-repo basis
- config_file.write("gpgcheck=0\n")
+ if not optgpgcheck:
+ config_file.write("gpgcheck=0\n")
config_file.close()
return fname
diff --git a/setup.py b/setup.py
index cc4eb12..39bba40 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ import sys
from distutils.core import setup, Extension
import string
-VERSION = "0.8.2"
+VERSION = "0.9.0"
SHORT_DESC = "Network Boot and Update Server"
LONG_DESC = """
Cobbler is a network boot and update server. Cobbler supports PXE, provisioning virtualized images, and reinstalling existing Linux machines. The last two modes require a helper tool called 'koan' that integrates with cobbler. Cobbler's advanced features include importing distributions from DVDs and rsync mirrors, kickstart templating, integrated yum mirroring, and built-in DHCP Management. Cobbler has a Python API for integration with other GPL systems management applications.
--
cgit
From 73857cbd67b62fda81398ba95c81df3abb59f1b1 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 12 Mar 2008 15:33:35 -0400
Subject: Adding patch to send hostname
---
AUTHORS | 1 +
CHANGELOG | 1 +
cobbler/action_sync.py | 2 ++
cobbler/settings.py | 1 +
4 files changed, 5 insertions(+)
diff --git a/AUTHORS b/AUTHORS
index 9a0fe8b..bcb8137 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,6 +12,7 @@ Patches and other contributions from:
Máirín Duffy
Tru Huynh
Matt Hyclak
+ Pablo Iranzo Gómez
Mihai Ibanescu
Vito Laurenza
Adrian Likins
diff --git a/CHANGELOG b/CHANGELOG
index 4b1a203..db1303e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@ Cobbler CHANGELOG
- Mon Mar 10 2008 - 0.9.0
- Make createrepo get run for local cobbler reposync invocations as needed
- patch to allow yumopts to override gpgcheck
+- applied patch to send hostname from ISC
- ??? - 0.8.3
- fix WebUI documentation URL
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 139066e..d6ea178 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -163,6 +163,8 @@ class BootSync:
# the label the entry after the hostname if possible
if host is not None and host != "":
systxt = "\nhost %s {\n" % host
+ if self.settings.isc_set_host_name:
+ systxt = systxt + " option host-name = %s;\n" % host
else:
systxt = "\nhost generic%d {\n" % counter
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 581403c..e89f254 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -39,6 +39,7 @@ DEFAULTS = {
"dnsmasq_conf" : "/etc/dnsmasq.conf",
"httpd_bin" : "/usr/sbin/httpd",
"http_port" : "80",
+ "isc_set_host_name" : 0,
"kerberos_realm" : "example.org",
"kernel_options" : {
"lang" : " ",
--
cgit
From dcdeba285768a48b56121bbdde0f628ba6793dae Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 12 Mar 2008 15:36:59 -0400
Subject: Fix authors file.
---
AUTHORS | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/AUTHORS b/AUTHORS
index bcb8137..2481c67 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,7 +12,7 @@ Patches and other contributions from:
Máirín Duffy
Tru Huynh
Matt Hyclak
- Pablo Iranzo Gómez
+ Pablo Iranzo Gómez
Mihai Ibanescu
Vito Laurenza
Adrian Likins
--
cgit
From 0268b337a80d6e910166d444be49b9be328328d0 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 13 Mar 2008 14:11:17 -0400
Subject: Added patch to allow kopts/ksmeta to be cleared with --kopts=delete
on the command line.
---
AUTHORS | 1 +
CHANGELOG | 1 +
cobbler/utils.py | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/AUTHORS b/AUTHORS
index 2481c67..b464d5b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,6 +7,7 @@ Cobbler is written & maintained by:
Patches and other contributions from:
+ David Brown
James Bowes
C. Daniel Chase
Máirín Duffy
diff --git a/CHANGELOG b/CHANGELOG
index db1303e..39e858c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ Cobbler CHANGELOG
- Make createrepo get run for local cobbler reposync invocations as needed
- patch to allow yumopts to override gpgcheck
- applied patch to send hostname from ISC
+- added patch to allow --kopts/--ksmeta items to be cleared with --kopts=delete
- ??? - 0.8.3
- fix WebUI documentation URL
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 069d440..c6a6154 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -240,7 +240,7 @@ def input_string_or_hash(options,delim=","):
if options == "<>":
options = {}
- if options is None:
+ if options is None or options == "delete":
return (True, {})
elif type(options) == list:
raise CX(_("No idea what to do with list: %s") % options)
--
cgit
From 6d8f6541c02bfb83630b10795a33500fa96e30c4 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 17 Mar 2008 16:59:19 -0400
Subject: Apply patch to make disabled repos (using new --yumopts feature) not
be used during install.
---
cobbler/action_sync.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index d6ea178..2596906 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -30,6 +30,7 @@ import errno
import item_distro
import item_profile
+import item_repo
import item_system
from Cheetah.Template import Template
@@ -430,13 +431,16 @@ class BootSync:
buf = ""
blended = utils.blender(self.api, False, obj, self.blend_cache)
-
configs = self.get_repo_filenames(obj,is_profile)
+ repos = self.repos
+
for c in configs:
name = c.split("/")[-1].replace(".repo","")
(is_core, baseurl) = self.analyze_repo_config(c)
- buf = buf + "repo --name=%s --baseurl=%s\n" % (name, baseurl)
-
+ for repo in repos:
+ if repo.name == name:
+ if not repo.yumopts.has_key('enabled') or repo.yumopts['enabled'] == '1':
+ buf = buf + "repo --name=%s --baseurl=%s\n" % (name, baseurl)
return buf
def analyze_repo_config(self, filename):
--
cgit
From 0ceedaa6657d4b31267a3a7224d3c9db3bd124aa Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 25 Mar 2008 15:55:18 -0400
Subject: tftpboot location discovery for F9
---
CHANGELOG | 1 +
cobbler/action_check.py | 11 +++++------
cobbler/settings.py | 9 ++++++++-
cobbler/utils.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
config/settings | 1 -
5 files changed, 62 insertions(+), 8 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index dcb8b96..28b45ca 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,7 @@ Cobbler CHANGELOG
- patch to allow yumopts to override gpgcheck
- applied patch to send hostname from ISC
- added patch to allow --kopts/--ksmeta items to be cleared with --kopts=delete
+- tftpboot location is now inferred from xinetd config (added for F9 compat)
- ??? - 0.8.3
- fix WebUI documentation URL
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index f7bc9d9..a4a09f6 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -17,6 +17,7 @@ import os
import re
import sub_process
import action_sync
+import utils
from rhpl.translate import _, N_, textdomain, utf8
class BootCheck:
@@ -152,17 +153,15 @@ class BootCheck:
if os.path.exists(self.settings.tftpd_conf):
f = open(self.settings.tftpd_conf)
re_disable = re.compile(r'disable.*=.*yes')
- found_bootdir = False
for line in f.readlines():
if re_disable.search(line):
status.append(_("change 'disable' to 'no' in %(file)s") % { "file" : self.settings.tftpd_conf })
- if line.find("-s %s" % self.settings.tftpboot) != -1:
- found_bootdir = True
- if not found_bootdir:
- status.append(_("change 'server_args' to '-s %(args)s' in %(file)s") % { "file" : "/etc/xinetd.d/tftp", "args" : self.settings.tftpboot })
-
else:
status.append(_("file %(file)s does not exist") % { "file" : self.settings.tftpd_conf })
+
+ bootloc = utils.tftpboot_location()
+ if not os.path.exists(bootloc):
+ status.append(_("directory needs to be created: %s" % bootloc))
def check_dhcpd_conf(self,status):
diff --git a/cobbler/settings.py b/cobbler/settings.py
index ccaf04d..cdbcabd 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -54,7 +54,7 @@ DEFAULTS = {
"server" : "127.0.0.1",
"snippetsdir" : "/var/lib/cobbler/snippets",
"syslog_port" : 25150,
- "tftpboot" : "/tftpboot",
+ "tftpboot" : -1, # special, see note below
"tftpd_bin" : "/usr/sbin/in.tftpd",
"tftpd_conf" : "/etc/xinetd.d/tftp",
"webdir" : "/var/www/cobbler",
@@ -102,7 +102,14 @@ class Settings(serializable.Serializable):
if datastruct is None:
print _("warning: not loading empty structure for %s") % self.filename()
return
+
self._attributes = datastruct
+
+ # this last attribute is special. In F9, the tftpboot location moves, so
+ # what we have in settings is not (neccessarily) correct. So instead
+ # of using settings we determine it by looking at the OS.
+ self._attributes["tftpboot"] = utils.tftpboot_location()
+
return self
def __getattr__(self,name):
diff --git a/cobbler/utils.py b/cobbler/utils.py
index c6a6154..86ff41d 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -468,3 +468,51 @@ def fix_mod_python_select_submission(repos):
repos = repos.lstrip().rstrip()
return repos
+def redhat_release():
+ if not os.path.exists("/bin/rpm"):
+ return ("unknown", 0)
+ args = ["/bin/rpm", "-q", "--whatprovides", "redhat-release"]
+ cmd = sub_process.Popen(args,shell=False,stdout=sub_process.PIPE)
+ data = cmd.communicate()[0]
+ data = data.rstrip().lower()
+ make = "other"
+ if data.find("redhat") != -1:
+ make = "redhat"
+ elif data.find("centos") != -1:
+ make = "centos"
+ elif data.find("fedora") != -1:
+ make = "fedora"
+ version = data.split("release-")[-1]
+ rest = 0
+ if version.find("-"):
+ parts = version.split("-")
+ version = parts[0]
+ rest = parts[1]
+ return (make, float(version), rest)
+
+def tftpboot_location():
+
+ # if possible, read from TFTP config file to get the location
+ if os.path.exists("/etc/xinetd.d/tftp"):
+ fd = open("/etc/xinetd.d/tftp")
+ lines = fd.read().split("\n")
+ for line in lines:
+ if line.find("server_args") != -1:
+ tokens = line.split(None)
+ mark = False
+ for t in tokens:
+ if t == "-s":
+ mark = True
+ elif mark:
+ return t
+
+ # otherwise, guess based on the distro
+ (make,version,rest) = redhat_release()
+ if make == "fedora" and version >= 9:
+ return "/var/lib/tftpboot"
+ return "/tftpboot"
+
+if __name__ == "__main__":
+ # print redhat_release()
+ print tftpboot_location()
+
diff --git a/config/settings b/config/settings
index ba709ae..19e8b6b 100644
--- a/config/settings
+++ b/config/settings
@@ -28,7 +28,6 @@ run_post_install_trigger: 0
server: '127.0.0.1'
snippetsdir: /var/lib/cobbler/snippets
syslog_port: 25150
-tftpboot: /tftpboot
tftpd_bin: /usr/sbin/in.tftpd
tftpd_conf: /etc/xinetd.d/tftp
webdir: /var/www/cobbler
--
cgit
From 25a743c875c6af64e51769f7a78d028dd2594aac Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 25 Mar 2008 18:06:32 -0400
Subject: Preliminary support for authentication against LDAP
---
CHANGELOG | 1 +
cobbler/modules/authn_ldap.py | 105 ++++++++++++++++++++++++++++++++++++
cobbler/modules/authz_configfile.py | 42 +++++++++++++++
cobbler/settings.py | 6 ++-
4 files changed, 153 insertions(+), 1 deletion(-)
create mode 100644 cobbler/modules/authn_ldap.py
create mode 100644 cobbler/modules/authz_configfile.py
diff --git a/CHANGELOG b/CHANGELOG
index 28b45ca..e0e7f05 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,7 @@ Cobbler CHANGELOG
- applied patch to send hostname from ISC
- added patch to allow --kopts/--ksmeta items to be cleared with --kopts=delete
- tftpboot location is now inferred from xinetd config (added for F9 compat)
+- added authn_ldap and stub for authz_configfile
- ??? - 0.8.3
- fix WebUI documentation URL
diff --git a/cobbler/modules/authn_ldap.py b/cobbler/modules/authn_ldap.py
new file mode 100644
index 0000000..e228db3
--- /dev/null
+++ b/cobbler/modules/authn_ldap.py
@@ -0,0 +1,105 @@
+"""
+Authentication module that uses ldap
+Settings in /etc/cobbler/authn_ldap.conf
+Choice of authentication module is in /etc/cobbler/modules.conf
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+#import ConfigParser
+import sys
+import os
+from rhpl.translate import _, N_, textdomain, utf8
+import md5
+import traceback
+import ldap
+import traceback
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+import cexceptions
+import utils
+import api as cobbler_api
+
+#CONFIG_FILE='/etc/cobbler/auth_ldap.conf'
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+
+ return "authn"
+
+def authenticate(api_handle,username,password):
+ """
+ Validate an ldap bind, returning True/False
+ """
+
+ server = api_handle.settings().ldap_server
+ basedn = api_handle.settings().ldap_base_dn
+ port = api_handle.settings().ldap_port
+ tls = api_handle.settings().ldap_tls
+
+ # parse CONFIG_FILE
+ # server,basedn,port,tls = __parse_config()
+
+ # form our ldap uri based on connection port
+ if port == '389':
+ uri = 'ldap://' + server
+ elif port == '636':
+ uri = 'ldaps://' + server
+ else:
+ uri = 'ldap://' + "%s:%s" % (server,port)
+
+ # connect to LDAP host
+ dir = ldap.initialize(uri)
+
+ # start_tls if tls is 'on', 'true' or 'yes'
+ # and we're not already using old-SSL
+ tls = str(tls).lower()
+ if port != '636':
+ if tls in [ "on", "true", "yes", "1" ]:
+ try:
+ dir.start_tls_s()
+ except:
+ traceback.print_exc()
+ return False
+
+ # perform a subtree search in basedn to find the full dn of the user
+ # TODO: what if username is a CN? maybe it goes into the config file as well?
+ filter = "uid=" + username
+ result = dir.search_s(basedn, ldap.SCOPE_SUBTREE, filter, [])
+ if result:
+ for dn,entry in result:
+ # uid should be unique so we should only have one result
+ # ignore entry; we don't need it
+ pass
+ else:
+ print "FAIL 2"
+ return False
+
+ try:
+ # attempt to bind as the user
+ dir.simple_bind_s(dn,password)
+ dir.unbind()
+ print "FAIL 1"
+ return True
+ except:
+ traceback.print_exc()
+ return False
+ # catch-all
+ return False
+
+if __name__ == "__main__":
+ api_handle = cobbler_api.BootAPI()
+ # print authenticate(api_handle, "mdehaan", "test1")
+ print authenticate(api_handle, "mdehaan", "dog8code")
+
diff --git a/cobbler/modules/authz_configfile.py b/cobbler/modules/authz_configfile.py
new file mode 100644
index 0000000..0d41cce
--- /dev/null
+++ b/cobbler/modules/authz_configfile.py
@@ -0,0 +1,42 @@
+"""
+Authorization module that allow users listed in
+the auth_ldap.conf config file
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+import ConfigParser
+import sys
+import os
+from rhpl.translate import _, N_, textdomain, utf8
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+import cexceptions
+import utils
+
+CONFIG_FILE='/etc/cobbler/auth_ldap.conf'
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "authz"
+
+def authorize(api_handle,user,resource,arg1=None,arg2=None):
+ """
+ Validate a user against a resource.
+ """
+
+ # FIXME: implement this, only users in /etc/cobbler/users.conf
+ # will return 1. Later we'll do authz_ownership.py
+
+ return 0
diff --git a/cobbler/settings.py b/cobbler/settings.py
index cdbcabd..495a4b5 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -40,7 +40,11 @@ DEFAULTS = {
"httpd_bin" : "/usr/sbin/httpd",
"http_port" : "80",
"isc_set_host_name" : 0,
- "kerberos_realm" : "example.org",
+ "ldap_server" : "grimlock.devel.redhat.com",
+ "ldap_base_dn" : "DC=devel,DC=redhat,DC=com",
+ "ldap_port" : 389,
+ "ldap_tls" : "on",
+ "kerberos_realm" : "EXAMPLE.COM",
"kernel_options" : {
"lang" : " ",
"text" : None,
--
cgit
From b100b25105b45b196190cff6e89fce402c85e0dd Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 25 Mar 2008 18:08:40 -0400
Subject: Add LDAP settings to /var/lib/cobbler/settings
---
config/settings | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/config/settings b/config/settings
index 19e8b6b..d9b1785 100644
--- a/config/settings
+++ b/config/settings
@@ -20,6 +20,10 @@ kernel_options:
ksdevice: eth0
lang: ' '
text: ~
+ldap_server: "ldap.example.com",
+ldap_base_dn: "DC=example,DC=com",
+ldap_port: 389,
+ldap_tls: 1,
manage_dhcp: 0
manage_dhcp_mode: isc
next_server: '127.0.0.1'
--
cgit
From 297805a2c498e57556348f3bb28e8f054c2556aa Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 25 Mar 2008 18:28:51 -0400
Subject: Remove test data from git
---
cobbler/modules/authn_ldap.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/cobbler/modules/authn_ldap.py b/cobbler/modules/authn_ldap.py
index e228db3..4597f3c 100644
--- a/cobbler/modules/authn_ldap.py
+++ b/cobbler/modules/authn_ldap.py
@@ -100,6 +100,5 @@ def authenticate(api_handle,username,password):
if __name__ == "__main__":
api_handle = cobbler_api.BootAPI()
- # print authenticate(api_handle, "mdehaan", "test1")
- print authenticate(api_handle, "mdehaan", "dog8code")
+ print authenticate(api_handle, "guest", "guest")
--
cgit
From a6a82750ac3cab01fbafdd689a7ea1f5f6dc0bf7 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 26 Mar 2008 12:49:35 -0400
Subject: Updated LDAP and authorization code, plus packaging
---
CHANGELOG | 1 +
MANIFEST.in | 1 +
Makefile | 2 ++
cobbler.spec | 9 +++++----
cobbler/cobblerd.py | 4 ++--
cobbler/demo_connect.py | 16 ++++++++++++----
cobbler/modules/authn_ldap.py | 1 -
cobbler/modules/authz_configfile.py | 32 +++++++++++++++++++++++++++-----
cobbler/remote.py | 29 +++++++++++++++++------------
config/modules.conf | 2 +-
setup.py | 1 +
11 files changed, 69 insertions(+), 29 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index e0e7f05..804254a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,7 @@ Cobbler CHANGELOG
- added patch to allow --kopts/--ksmeta items to be cleared with --kopts=delete
- tftpboot location is now inferred from xinetd config (added for F9 compat)
- added authn_ldap and stub for authz_configfile
+- authz_configfile allows filtering ldap/other users by config file
- ??? - 0.8.3
- fix WebUI documentation URL
diff --git a/MANIFEST.in b/MANIFEST.in
index ed1d412..4c8ed20 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -10,6 +10,7 @@ include config/modules.conf
include config/auth.conf
include config/settings
include config/users.digest
+include config/users.conf
recursive-include templates *.template
recursive-include kickstarts *.ks
include docs/cobbler.1.gz
diff --git a/Makefile b/Makefile
index c40b4ed..e742e39 100644
--- a/Makefile
+++ b/Makefile
@@ -38,10 +38,12 @@ install: clean manpage
devinstall:
cp /var/lib/cobbler/settings /tmp/cobbler_settings
cp /etc/cobbler/modules.conf /tmp/cobbler_modules.conf
+ cp /etc/cobbler/users.conf /tmp/cobbler_users.conf
-cp /etc/cobbler/users.digest /tmp/cobbler_users.digest
make install
cp /tmp/cobbler_settings /var/lib/cobbler/settings
cp /tmp/cobbler_modules.conf /etc/cobbler/modules.conf
+ cp /tmp/cobbler_users.conf /etc/cobbler/users.conf
-cp /tmp/cobbler_users.digest /etc/cobbler/users.digest
find /var/lib/cobbler/triggers | xargs chmod +x
chown -R apache /var/www/cobbler
diff --git a/cobbler.spec b/cobbler.spec
index aa61bd9..c4cc5a0 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -128,6 +128,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%config(noreplace) /etc/cobbler/rsync.exclude
%config(noreplace) /etc/logrotate.d/cobblerd_rotate
%config(noreplace) /etc/cobbler/modules.conf
+%config(noreplace) /etc/cobbler/users.conf
%dir %{python_sitelib}/cobbler
%dir %{python_sitelib}/cobbler/yaml
%dir %{python_sitelib}/cobbler/modules
@@ -190,14 +191,14 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
-<<<<<<< HEAD:cobbler.spec
-* Fri Mar 07 2008 Michael DeHaan - 0.9.0-1
-=======
+* Wed Mar 26 2008 Michael DeHaan - 0.9.0-1
+- Upstream changes (see CHANGELOG)
+- packaged /etc/cobbler/users.conf
+
* Mon Mar 10 2008 Michael DeHaan - 0.8.3-1
- Upstream changes (see CHANGELOG)
* Fri Mar 07 2008 Michael DeHaan - 0.8.2-1
->>>>>>> master:cobbler.spec
- Upstream changes (see CHANGELOG)
* Wed Feb 20 2008 Michael DeHaan - 0.8.1-1
diff --git a/cobbler/cobblerd.py b/cobbler/cobblerd.py
index 3c06723..5640aec 100644
--- a/cobbler/cobblerd.py
+++ b/cobbler/cobblerd.py
@@ -108,7 +108,7 @@ def do_xmlrpc(bootapi, settings, port, logger):
# This is the simple XMLRPC API we provide to koan and other
# apps that do not need to manage Cobbler's config
- xinterface = remote.ProxiedXMLRPCInterface(bootapi,logger,remote.CobblerXMLRPCInterface,True)
+ xinterface = remote.ProxiedXMLRPCInterface(bootapi,logger,remote.CobblerXMLRPCInterface,False)
server = remote.CobblerXMLRPCServer(('', port))
server.logRequests = 0 # don't print stuff
@@ -124,7 +124,7 @@ def do_xmlrpc(bootapi, settings, port, logger):
def do_xmlrpc_rw(bootapi,settings,port,logger):
- xinterface = remote.ProxiedXMLRPCInterface(bootapi,logger,remote.CobblerReadWriteXMLRPCInterface,False)
+ xinterface = remote.ProxiedXMLRPCInterface(bootapi,logger,remote.CobblerReadWriteXMLRPCInterface,True)
server = remote.CobblerReadWriteXMLRPCServer(('127.0.0.1', port))
server.logRequests = 0 # don't print stuff
logger.debug("XMLRPC (read-write variant) running on %s" % port)
diff --git a/cobbler/demo_connect.py b/cobbler/demo_connect.py
index 0fa058b..6397a6b 100644
--- a/cobbler/demo_connect.py
+++ b/cobbler/demo_connect.py
@@ -11,12 +11,20 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""
-from server.xmlrpcclient import ServerProxy
+from xmlrpclib import ServerProxy
+import optparse
if __name__ == "__main__":
- sp = ServerProxy("httpu:///var/lib/cobbler/sock")
- print sp.login("","")
-
+ p = optparse.OptionParser()
+ p.add_option("-u","--user",dest="user",default="test")
+ p.add_option("-p","--pass",dest="password",default="test")
+ sp = ServerProxy("http://127.0.0.1/cobbler_api_rw")
+ (options, args) = p.parse_args()
+ print "- trying to login with user=%s" % options.user
+ token = sp.login(options.user,options.password)
+ print "- token: %s" % token
+ check = sp.check_access(token,"imaginary_method_name")
+ print "- access ok? %s" % check
diff --git a/cobbler/modules/authn_ldap.py b/cobbler/modules/authn_ldap.py
index 4597f3c..6d190bd 100644
--- a/cobbler/modules/authn_ldap.py
+++ b/cobbler/modules/authn_ldap.py
@@ -90,7 +90,6 @@ def authenticate(api_handle,username,password):
# attempt to bind as the user
dir.simple_bind_s(dn,password)
dir.unbind()
- print "FAIL 1"
return True
except:
traceback.print_exc()
diff --git a/cobbler/modules/authz_configfile.py b/cobbler/modules/authz_configfile.py
index 0d41cce..c183721 100644
--- a/cobbler/modules/authz_configfile.py
+++ b/cobbler/modules/authz_configfile.py
@@ -1,6 +1,8 @@
"""
Authorization module that allow users listed in
-the auth_ldap.conf config file
+/etc/cobbler/users.conf to be permitted to access resources.
+For instance, when using authz_ldap, you want to use authn_configfile,
+not authz_allowall, which will most likely NOT do what you want.
This software may be freely redistributed under the terms of the GNU
general public license.
@@ -23,7 +25,7 @@ sys.path.insert(0, mod_path)
import cexceptions
import utils
-CONFIG_FILE='/etc/cobbler/auth_ldap.conf'
+CONFIG_FILE='/etc/cobbler/users.conf'
def register():
"""
@@ -31,12 +33,32 @@ def register():
"""
return "authz"
+def __parse_config():
+ if not os.path.exists(CONFIG_FILE):
+ return []
+ config = ConfigParser.SafeConfigParser()
+ config.read(CONFIG_FILE)
+ alldata = {}
+ groups = config.sections()
+ for g in groups:
+ alldata[str(g)] = {}
+ opts = config.options(g)
+ for o in opts:
+ alldata[g][o] = 1
+ return alldata
+
+
def authorize(api_handle,user,resource,arg1=None,arg2=None):
"""
Validate a user against a resource.
+ All users in the file are permitted by this module.
"""
- # FIXME: implement this, only users in /etc/cobbler/users.conf
- # will return 1. Later we'll do authz_ownership.py
-
+ data = __parse_config()
+ for g in data:
+ if user in data[g]:
+ return 1
return 0
+
+if __name__ == "__main__":
+ print __parse_config()
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 5131323..4b04fcb 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -561,10 +561,6 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
FIXME: currently looks for users in /etc/cobbler/auth.conf
Would be very nice to allow for PAM and/or just Kerberos.
"""
- if not self.auth_enabled and input_user == "":
- return True
- if self.auth_enabled and input_user == "":
- return False
return self.api.authenticate(input_user,input_password)
def __validate_token(self,token):
@@ -579,11 +575,12 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.__invalidate_expired_tokens()
self.__invalidate_expired_objects()
- if not self.auth_enabled:
- user = self.get_user_from_token(token)
- if user == "":
- self.token_cache[token] = (time.time(), user) # update to prevent timeout
- return True
+ #if not self.auth_enabled:
+ # user = self.get_user_from_token(token)
+ # # old stuff, preserving for future usage
+ # # if user == "":
+ # # self.token_cache[token] = (time.time(), user) # update to prevent timeout
+ # # return True
if self.token_cache.has_key(token):
user = self.get_user_from_token(token)
@@ -598,10 +595,16 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
def check_access(self,token,resource,arg1=None,arg2=None):
validated = self.__validate_token(token)
+ user = self.get_user_from_token(token)
if not self.auth_enabled:
+ # for public read-only XMLRPC, permit access
+ self.log("permitting read-only access")
return True
- return self.__authorize(token,resource,arg1,arg2)
-
+ rc = self.__authorize(token,resource,arg1,arg2)
+ self.log("authorization result: %s" % rc)
+ if not rc:
+ raise CX(_("authorization failure for user %s" % user))
+ return rc
def login(self,login_user,login_password):
"""
@@ -621,7 +624,9 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
def __authorize(self,token,resource,arg1=None,arg2=None):
user = self.get_user_from_token(token)
- if self.api.authorize(user,resource,arg1,arg2):
+ self.log("calling authorize for resource %s" % resource, user=user)
+ rc = self.api.authorize(user,resource,arg1,arg2)
+ if rc:
return True
else:
raise CX(_("user does not have access to resource: %s") % resource)
diff --git a/config/modules.conf b/config/modules.conf
index 2d60d21..2daf0e4 100644
--- a/config/modules.conf
+++ b/config/modules.conf
@@ -9,4 +9,4 @@ repo = serializer_yaml
module = authn_configfile
[authorization]
-module = authn_allowall
+module = authz_allowall
diff --git a/setup.py b/setup.py
index 39bba40..8253216 100644
--- a/setup.py
+++ b/setup.py
@@ -74,6 +74,7 @@ if __name__ == "__main__":
(etcpath, ['config/modules.conf']),
(etcpath, ['config/users.digest']),
(etcpath, ['config/rsync.exclude']),
+ (etcpath, ['config/users.conf']),
(initpath, ['config/cobblerd']),
(cobpath, ['config/settings']),
--
cgit
From 602591cae12323012693f49de3ba59516b40c3f5 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 26 Mar 2008 16:02:48 -0400
Subject: Add a --owner to all the objects, plus associated API calls and
backend stuff, for use with the (pending real soon now) authz_ownership
module. Also updated docs. Incidentally, self.settings.tftpboot is now
utils.tftpboot_location() -- which is required because tftpboot moves around.
Previously this was masked to still look like a settings variable but I
decided to remove the hack. All code using that location has been updated
appropriately.
---
cobbler/action_check.py | 5 +++--
cobbler/action_litesync.py | 8 +++++---
cobbler/action_sync.py | 23 ++++++++++++-----------
cobbler/item.py | 12 +++++++++++-
cobbler/item_distro.py | 9 +++++++--
cobbler/item_profile.py | 10 ++++++++--
cobbler/item_repo.py | 5 ++++-
cobbler/item_system.py | 7 ++++++-
cobbler/modules/cli_distro.py | 5 +++++
cobbler/modules/cli_profile.py | 5 +++++
cobbler/modules/cli_repo.py | 5 +++++
cobbler/modules/cli_system.py | 4 ++++
cobbler/settings.py | 6 ------
cobbler/utils.py | 16 +++++++++++++++-
cobbler/webui/master.py | 4 ++--
docs/cobbler.pod | 4 ++++
tests/tests.py | 35 +++++++++++++++++++++++++++++++++++
17 files changed, 131 insertions(+), 32 deletions(-)
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index a4a09f6..1fb4734 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -141,8 +141,9 @@ class BootCheck:
"""
Check if cobbler.conf's tftpboot directory exists
"""
- if not os.path.exists(self.settings.tftpboot):
- status.append(_("please create directory: %(dirname)s") % { "dirname" : self.settings.tftpboot })
+ bootloc = utils.tftpboot_location()
+ if not os.path.exists(bootloc):
+ status.append(_("please create directory: %(dirname)s") % { "dirname" : bootloc })
def check_tftpd_conf(self,status):
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index 457f3af..9200a3e 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -66,12 +66,13 @@ class BootLiteSync:
self.add_single_profile(k.name)
def remove_single_distro(self, name):
+ bootloc = utils.tftpboot_location()
# delete distro YAML file in distros/$name in webdir
self.sync.rmfile(os.path.join(self.settings.webdir, "distros", name))
# delete contents of images/$name directory in webdir
self.sync.rmtree(os.path.join(self.settings.webdir, "images", name))
# delete contents of images/$name in tftpboot
- self.sync.rmtree(os.path.join(self.settings.tftpboot, "images", name))
+ self.sync.rmtree(os.path.join(bootloc, "images", name))
# delete potential symlink to tree in webdir/links
self.sync.rmfile(os.path.join(self.settings.webdir, "links", name))
@@ -127,6 +128,7 @@ class BootLiteSync:
self.sync.retemplate_yum_repos(system,False)
def remove_single_system(self, name):
+ bootloc = utils.tftpboot_location()
system_record = self.systems.find(name=name)
# rebuild system_list file in webdir
self.sync.write_listings()
@@ -152,7 +154,7 @@ class BootLiteSync:
if distro is not None and distro in [ "ia64", "IA64"]:
itanic = True
if not itanic:
- self.sync.rmfile(os.path.join(self.settings.tftpboot, "pxelinux.cfg", filename))
+ self.sync.rmfile(os.path.join(bootloc, "pxelinux.cfg", filename))
else:
- self.sync.rmfile(os.path.join(self.settings.tftpboot, filename))
+ self.sync.rmfile(os.path.join(bootloc, filename))
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 2596906..8a0eadf 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -57,14 +57,15 @@ class BootSync:
self.repos = config.repos()
self.blend_cache = {}
self.load_snippet_cache()
+ self.bootloc = utils.tftpboot_location()
def run(self):
"""
Syncs the current configuration file with the config tree.
Using the Check().run_ functions previously is recommended
"""
- if not os.path.exists(self.settings.tftpboot):
- raise CX(_("cannot find directory: %s") % self.settings.tftpboot)
+ if not os.path.exists(self.bootloc):
+ raise CX(_("cannot find directory: %s") % self.bootloc)
# run pre-triggers...
utils.run_triggers(None, "/var/lib/cobbler/triggers/sync/pre/*")
@@ -104,9 +105,9 @@ class BootSync:
for loader in self.settings.bootloaders.keys():
path = self.settings.bootloaders[loader]
newname = os.path.basename(path)
- destpath = os.path.join(self.settings.tftpboot, newname)
+ destpath = os.path.join(self.bootloc, newname)
self.copyfile(path, destpath)
- self.copyfile("/var/lib/cobbler/menu.c32", os.path.join(self.settings.tftpboot, "menu.c32"))
+ self.copyfile("/var/lib/cobbler/menu.c32", os.path.join(self.bootloc, "menu.c32"))
def write_dhcp_file(self):
"""
@@ -278,8 +279,8 @@ class BootSync:
if x in ["kickstarts","kickstarts_sys","images","systems","distros","profiles","repo_profile","repo_system"]:
# clean out directory contents
self.rmtree_contents(path)
- self.rmtree_contents(os.path.join(self.settings.tftpboot, "pxelinux.cfg"))
- self.rmtree_contents(os.path.join(self.settings.tftpboot, "images"))
+ self.rmtree_contents(os.path.join(self.bootloc, "pxelinux.cfg"))
+ self.rmtree_contents(os.path.join(self.bootloc, "images"))
def copy_distros(self):
"""
@@ -297,7 +298,7 @@ class BootSync:
self.copy_single_distro_files(d)
def copy_single_distro_files(self, d):
- for dirtree in [self.settings.tftpboot, self.settings.webdir]:
+ for dirtree in [self.bootloc, self.settings.webdir]:
distros = os.path.join(dirtree, "images")
distro_dir = os.path.join(distros,d.name)
self.mkdir(distro_dir)
@@ -763,7 +764,7 @@ class BootSync:
# for tftp only ...
if distro.arch in [ "x86", "x86_64", "standard"]:
# pxelinux wants a file named $name under pxelinux.cfg
- f2 = os.path.join(self.settings.tftpboot, "pxelinux.cfg", f1)
+ f2 = os.path.join(self.bootloc, "pxelinux.cfg", f1)
if distro.arch == "ia64":
# elilo expects files to be named "$name.conf" in the root
# and can not do files based on the MAC address
@@ -771,7 +772,7 @@ class BootSync:
print _("Warning: Itanium system object (%s) needs an IP address to PXE") % system.name
filename = "%s.conf" % utils.get_config_filename(system,interface=name)
- f2 = os.path.join(self.settings.tftpboot, filename)
+ f2 = os.path.join(self.bootloc, filename)
f3 = os.path.join(self.settings.webdir, "systems", f1)
@@ -798,7 +799,7 @@ class BootSync:
if default is not None:
return
- fname = os.path.join(self.settings.tftpboot, "pxelinux.cfg", "default")
+ fname = os.path.join(self.bootloc, "pxelinux.cfg", "default")
# read the default template file
template_src = open("/etc/cobbler/pxedefault.template")
@@ -820,7 +821,7 @@ class BootSync:
# save the template.
metadata = { "pxe_menu_items" : pxe_menu_items }
- outfile = os.path.join(self.settings.tftpboot, "pxelinux.cfg", "default")
+ outfile = os.path.join(self.bootloc, "pxelinux.cfg", "default")
self.apply_template(template_data, metadata, outfile)
template_src.close()
diff --git a/cobbler/item.py b/cobbler/item.py
index dadcd23..f51f959 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -51,7 +51,7 @@ class Item(serializable.Serializable):
self.clear(is_subobject) # reset behavior differs for inheritance cases
self.parent = '' # all objects by default are not subobjects
self.children = {} # caching for performance reasons, not serialized
-
+ self.owners = []
self.log_func = self.config.api.log
def clear(self):
@@ -117,6 +117,16 @@ class Item(serializable.Serializable):
self.name = name
return True
+ def set_owners(self,data):
+ """
+ The owners field is a comment unless using an authz module that pays attention to it,
+ like authz_ownership, which ships with Cobbler but is off by default. Consult the Wiki
+ docs for more info on CustomizableAuthorization.
+ """
+ owners = utils.input_string_or_list(data)
+ self.owners = owners
+ return True
+
def set_kernel_options(self,options):
"""
Kernel options are a space delimited list,
diff --git a/cobbler/item_distro.py b/cobbler/item_distro.py
index f52ad0b..c40f002 100644
--- a/cobbler/item_distro.py
+++ b/cobbler/item_distro.py
@@ -32,6 +32,7 @@ class Distro(item.Item):
Reset this object.
"""
self.name = None
+ self.owners = []
self.kernel = (None, '<>')[is_subobject]
self.initrd = (None, '<>')[is_subobject]
self.kernel_options = ({}, '<>')[is_subobject]
@@ -60,6 +61,7 @@ class Distro(item.Item):
"""
self.parent = self.load_item(seed_data,'parent')
self.name = self.load_item(seed_data,'name')
+ self.owners = self.load_item(seed_data,'owners',[])
self.kernel = self.load_item(seed_data,'kernel')
self.initrd = self.load_item(seed_data,'initrd')
self.kernel_options = self.load_item(seed_data,'kernel_options')
@@ -165,7 +167,8 @@ class Distro(item.Item):
'breed' : self.breed,
'source_repos' : self.source_repos,
'parent' : self.parent,
- 'depth' : self.depth
+ 'depth' : self.depth,
+ 'owners' : self.owners
}
def printable(self):
@@ -181,6 +184,7 @@ class Distro(item.Item):
buf = buf + _("architecture : %s\n") % self.arch
buf = buf + _("ks metadata : %s\n") % self.ks_meta
buf = buf + _("breed : %s\n") % self.breed
+ buf = buf + _("owners : %s\n") % self.owners
return buf
def remote_methods(self):
@@ -191,7 +195,8 @@ class Distro(item.Item):
'kopts' : self.set_kernel_options,
'arch' : self.set_arch,
'ksmeta' : self.set_ksmeta,
- 'breed' : self.set_breed
+ 'breed' : self.set_breed,
+ 'owners' : self.set_owners
}
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index f229d4c..3145b82 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -34,6 +34,7 @@ class Profile(item.Item):
Reset this object.
"""
self.name = None
+ self.owners = [] # should not be inheritable
self.distro = (None, '<>')[is_subobject]
self.kickstart = (self.settings.default_kickstart , '<>')[is_subobject]
self.kernel_options = ({}, '<>')[is_subobject]
@@ -57,6 +58,7 @@ class Profile(item.Item):
self.parent = self.load_item(seed_data,'parent','')
self.name = self.load_item(seed_data,'name')
+ self.owners = self.load_item(seed_data,'owners',[])
self.distro = self.load_item(seed_data,'distro')
self.kickstart = self.load_item(seed_data,'kickstart')
self.kernel_options = self.load_item(seed_data,'kernel_options')
@@ -328,6 +330,7 @@ class Profile(item.Item):
"""
return {
'name' : self.name,
+ 'owners' : self.owners,
'distro' : self.distro,
'kickstart' : self.kickstart,
'kernel_options' : self.kernel_options,
@@ -342,7 +345,8 @@ class Profile(item.Item):
'virt_type' : self.virt_type,
'virt_path' : self.virt_path,
'dhcp_tag' : self.dhcp_tag,
- 'server' : self.server
+ 'server' : self.server,
+
}
def printable(self):
@@ -366,6 +370,7 @@ class Profile(item.Item):
buf = buf + _("repos : %s\n") % self.repos
buf = buf + _("dhcp tag : %s\n") % self.dhcp_tag
buf = buf + _("server : %s\n") % self.server
+ buf = buf + _("owners : %s\n") % self.owners
return buf
def remote_methods(self):
@@ -385,6 +390,7 @@ class Profile(item.Item):
'virt-bridge' : self.set_virt_bridge,
'virt-cpus' : self.set_virt_cpus,
'dhcp-tag' : self.set_dhcp_tag,
- 'server' : self.set_server
+ 'server' : self.set_server,
+ 'owners' : self.set_owners
}
diff --git a/cobbler/item_repo.py b/cobbler/item_repo.py
index a7b1f3b..d65d09b 100644
--- a/cobbler/item_repo.py
+++ b/cobbler/item_repo.py
@@ -161,6 +161,7 @@ class Repo(item.Item):
def to_datastruct(self):
return {
'name' : self.name,
+ 'owners' : self.owners,
'mirror' : self.mirror,
'keep_updated' : self.keep_updated,
'priority' : self.priority,
@@ -174,6 +175,7 @@ class Repo(item.Item):
def printable(self):
buf = _("repo : %s\n") % self.name
+ buf = buf + _("owners : %s\n") % self.owners
buf = buf + _("mirror : %s\n") % self.mirror
buf = buf + _("keep updated : %s\n") % self.keep_updated
buf = buf + _("priority : %s\n") % self.priority
@@ -210,6 +212,7 @@ class Repo(item.Item):
'priority' : self.set_priority,
'rpm-list' : self.set_rpm_list,
'createrepo-flags' : self.set_createrepo_flags,
- 'yumopts' : self.set_yumopts
+ 'yumopts' : self.set_yumopts,
+ 'owners' : self.set_owners
}
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 936f1dd..51dd063 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -30,6 +30,7 @@ class System(item.Item):
def clear(self,is_subobject=False):
self.name = None
+ self.owners = None
self.profile = None
self.kernel_options = {}
self.ks_meta = {}
@@ -80,6 +81,7 @@ class System(item.Item):
self.parent = self.load_item(seed_data, 'parent')
self.name = self.load_item(seed_data, 'name')
+ self.owners = self.load_item(seed_data, 'owners')
self.profile = self.load_item(seed_data, 'profile')
self.kernel_options = self.load_item(seed_data, 'kernel_options', {})
self.ks_meta = self.load_item(seed_data, 'ks_meta', {})
@@ -336,6 +338,7 @@ class System(item.Item):
def to_datastruct(self):
return {
'name' : self.name,
+ 'owners' : self.set_owners,
'profile' : self.profile,
'kernel_options' : self.kernel_options,
'ks_meta' : self.ks_meta,
@@ -360,6 +363,7 @@ class System(item.Item):
buf = buf + _("virt type : %s\n") % self.virt_type
buf = buf + _("virt path : %s\n") % self.virt_path
buf = buf + _("server : %s\n") % self.server
+ buf = buf + _("owners : %s\n") % self.owners
counter = 0
for (name,x) in self.interfaces.iteritems():
@@ -405,6 +409,7 @@ class System(item.Item):
'virt-type' : self.set_virt_type,
'modify-interface' : self.modify_interface,
'delete-interface' : self.delete_interface,
- 'server' : self.set_server
+ 'server' : self.set_server,
+ 'owners' : self.set_owners
}
diff --git a/cobbler/modules/cli_distro.py b/cobbler/modules/cli_distro.py
index 35f5a4b..9e0637f 100644
--- a/cobbler/modules/cli_distro.py
+++ b/cobbler/modules/cli_distro.py
@@ -47,12 +47,15 @@ class DistroFunction(commands.CobblerFunction):
p.add_option("--name", dest="name", help="ex: 'RHEL-5-i386' (REQUIRED)")
+
if self.matches_args(args,["copy","rename"]):
p.add_option("--newname", dest="newname", help="for copy/rename commands")
if not self.matches_args(args,["remove","report","list"]):
p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
if not self.matches_args(args,["report","list"]):
p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
+ if not self.matches_args(args,["remove","report","list"]):
+ p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
if self.matches_args(args,["remove"]):
p.add_option("--recursive", action="store_true", dest="recursive", help="also delete child objects")
@@ -73,6 +76,8 @@ class DistroFunction(commands.CobblerFunction):
obj.set_ksmeta(self.options.ksmeta)
if self.options.breed:
obj.set_breed(self.options.breed)
+ if self.options.owners:
+ obj.set_owners(self.options.owners)
return self.object_manipulator_finish(obj, self.api.distros, self.options)
diff --git a/cobbler/modules/cli_profile.py b/cobbler/modules/cli_profile.py
index e9d1d23..9912607 100644
--- a/cobbler/modules/cli_profile.py
+++ b/cobbler/modules/cli_profile.py
@@ -46,6 +46,7 @@ class ProfileFunction(commands.CobblerFunction):
p.add_option("--kopts", dest="kopts", help="ex: 'noipv6'")
p.add_option("--name", dest="name", help="a name for the profile (REQUIRED)")
+
if "copy" in args or "rename" in args:
p.add_option("--newname", dest="newname")
@@ -53,6 +54,7 @@ class ProfileFunction(commands.CobblerFunction):
p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
if not self.matches_args(args,["report", "list"]):
p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
+ p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
if self.matches_args(args,["remove"]):
p.add_option("--recursive", action="store_true", dest="recursive", help="also delete child objects")
@@ -93,6 +95,9 @@ class ProfileFunction(commands.CobblerFunction):
if self.options.dhcp_tag: obj.set_dhcp_tag(self.options.dhcp_tag)
if self.options.server_override: obj.set_server(self.options.server)
+ if self.options.owners:
+ obj.set_owners(self.options.owners)
+
return self.object_manipulator_finish(obj, self.api.profiles, self.options)
diff --git a/cobbler/modules/cli_repo.py b/cobbler/modules/cli_repo.py
index 96afa6f..88e45dd 100644
--- a/cobbler/modules/cli_repo.py
+++ b/cobbler/modules/cli_repo.py
@@ -59,6 +59,8 @@ class RepoFunction(commands.CobblerFunction):
p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
if not self.matches_args(args,["report","list"]):
p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
+ if not self.matches_args(args,["remove","report","list"]):
+ p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
def run(self):
@@ -75,6 +77,9 @@ class RepoFunction(commands.CobblerFunction):
if self.options.mirror: obj.set_mirror(self.options.mirror)
if self.options.yumopts: obj.set_yumopts(self.options.yumopts)
+ if self.options.owners:
+ obj.set_owners(self.options.owners)
+
return self.object_manipulator_finish(obj, self.api.repos, self.options)
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index c463b8c..01ead35 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -63,6 +63,7 @@ class SystemFunction(commands.CobblerFunction):
if not self.matches_args(args,["remove","report","list"]):
+ p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
p.add_option("--profile", dest="profile", help="name of cobbler profile (REQUIRED)")
p.add_option("--server-override", dest="server_override", help="overrides server value in settings file")
p.add_option("--subnet", dest="subnet", help="for static IP / templating usage")
@@ -99,6 +100,9 @@ class SystemFunction(commands.CobblerFunction):
if self.options.dhcp_tag: obj.set_dhcp_tag(self.options.dhcp_tag, my_interface)
if self.options.virt_bridge: obj.set_virt_bridge(self.options.virt_bridge, my_interface)
+ if self.options.owners:
+ obj.set_owners(self.options.owners)
+
return self.object_manipulator_finish(obj, self.api.systems, self.options)
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 495a4b5..e3d8a46 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -58,7 +58,6 @@ DEFAULTS = {
"server" : "127.0.0.1",
"snippetsdir" : "/var/lib/cobbler/snippets",
"syslog_port" : 25150,
- "tftpboot" : -1, # special, see note below
"tftpd_bin" : "/usr/sbin/in.tftpd",
"tftpd_conf" : "/etc/xinetd.d/tftp",
"webdir" : "/var/www/cobbler",
@@ -109,11 +108,6 @@ class Settings(serializable.Serializable):
self._attributes = datastruct
- # this last attribute is special. In F9, the tftpboot location moves, so
- # what we have in settings is not (neccessarily) correct. So instead
- # of using settings we determine it by looking at the OS.
- self._attributes["tftpboot"] = utils.tftpboot_location()
-
return self
def __getattr__(self,name):
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 86ff41d..9c770d0 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -230,6 +230,20 @@ def find_kickstart(url):
return url
return None
+def input_string_or_list(options,delim=","):
+ """
+ Accepts a delimited list of stuff or a list, but always returns a list.
+ """
+ if options is None or options == "delete":
+ return []
+ elif type(options) == list:
+ return options
+ elif type(options) == str:
+ tokens = options.split(",")
+ return tokens
+ else:
+ raise CX(_("invalid input type"))
+
def input_string_or_hash(options,delim=","):
"""
Older cobbler files stored configurations in a flat way, such that all values for strings.
@@ -261,7 +275,7 @@ def input_string_or_hash(options,delim=","):
options.pop('',None)
return (True, options)
else:
- raise CX(_("Foreign options type"))
+ raise CX(_("invalid input type"))
def grab_tree(api_handle, obj):
"""
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index b2abf09..157b156 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -33,8 +33,8 @@ VFN=valueForName
currentTime=time.time
__CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1205174715.425076
-__CHEETAH_genTimestamp__ = 'Mon Mar 10 14:45:15 2008'
+__CHEETAH_genTime__ = 1206550188.6649311
+__CHEETAH_genTimestamp__ = 'Wed Mar 26 12:49:48 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
__CHEETAH_srcLastModified__ = 'Fri Feb 15 14:47:43 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index a1f174f..719850d 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -102,6 +102,10 @@ arguments appropriately. Support for other types of distributions is possible
The file used for the answer file, regardless of the breed setting, is the value used for --kickstart when creating the profile.
+=item owners
+
+Users with small sites and a limited number of admins can probably ignore this option. All cobbler objects (distros, profiles, systems, and repos) can take a --owners parameter to specify what cobbler users can edit particular objects. This only applies to the Cobbler WebUI and XMLRPC interface, not the "cobbler" command line tool run from the shell. Furthermore, this is only respected by the "authz_ownership" module which must be enabled in /etc/cobbler/modules.conf. The value for --owners is a comma seperated list of users and groups as specified in /etc/cobbler/users.conf. For more information see the users.conf file as well as the Cobbler Wiki. In the default Cobbler configuration, this value is completely ignored, as is users.conf.
+
=back
=head2 ADDING A PROFILE
diff --git a/tests/tests.py b/tests/tests.py
index 99ba0b9..3fb4177 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -100,6 +100,41 @@ class BootTest(unittest.TestCase):
self.assertTrue(self.api.add_system(system))
self.assertTrue(self.api.find_system(name="drwily.rdu.redhat.com"))
+ repo = self.api.new_repo()
+ try:
+ os.makedirs("/tmp/test_example_cobbler_repo")
+ except:
+ pass
+ fd = open("/tmp/test_example_cobbler_repo/test.file", "w+")
+ fd.write("hello!")
+ fd.close()
+ self.assertTrue(repo.set_name("test_repo"))
+ self.assertTrue(repo.set_mirror("/tmp/test_example_cobbler_repo"))
+ self.assertTrue(self.api.repos().add(repo))
+
+
+class Ownership(BootTest):
+
+ def test_ownership_params(self):
+ return # FIXME
+
+ # NOTE: these tests are relaeively weak because they only test
+ # that the options are usable, not that they work, since cobbler
+ # as a command line tool ignores them, and cobblerd only cares
+ # in certain modes.
+ distro = self.api.find_distro(name="testdistro0")
+ profile = self.api.find_distro(name="testprofile0")
+ system = self.api.find_distro(name="drwily.rdu.redhat.com")
+ repo = self.api.find_repo(name="test_repo")
+ self.assertTrue(distro.set_owners("a,b"))
+ self.assertTrue(profile.set_owners("c,d"))
+ self.assertTrue(system.set_owners("e"))
+ self.assertTrue(repo.set_owners("f,g"))
+ self.api.add_distro(distro)
+ self.api.add_profile(profile)
+ self.api.add_system(system)
+ self.api.add_repo(repo)
+
class MultiNIC(BootTest):
def test_multi_nic_support(self):
--
cgit
From 0be993e430bfe2c7c742f7f4d100fb73cb3e317c Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 26 Mar 2008 17:45:01 -0400
Subject: Missing file
---
config/users.conf | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 config/users.conf
diff --git a/config/users.conf b/config/users.conf
new file mode 100644
index 0000000..94a3566
--- /dev/null
+++ b/config/users.conf
@@ -0,0 +1,26 @@
+# Cobbler WebUI / Web Services authorization config file
+#
+# NOTICE:
+# this file is only used when /etc/cobbler/modules.conf
+# specifies an authorization mode of either:
+#
+# (A) authz_configfile
+# (B) authz_ownership
+#
+# For (A), any user in this file, in any group, are allowed
+# full access to any object in cobbler configuration.
+#
+# For (B), users in the "admins" group are allowed full access
+# to any object, otherwise users can only edit an object if
+# their username/group is listed as an owner of that object. If a
+# user is not listed in this file they will have no access.
+#
+# cobbler command line example:
+#
+# cobbler system edit --name=server1 --owner=dbas,mac,pete,jack
+
+
+[admins]
+admin
+cobbler
+
--
cgit
From 5b2e32746600a45af8ce85f645cb3c0d8ae2d084 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 27 Mar 2008 16:50:58 -0400
Subject: Adding ownership module + tests and associated changes to cobblerd to
make it work a little better. This module is not fully tested yet, so don't
use it yet in production.
---
cobbler/modules/authz_ownership.py | 155 +++++++++++++++++++++++++++++++++++++
cobbler/remote.py | 8 +-
tests/tests.py | 109 +++++++++++++++++++-------
3 files changed, 238 insertions(+), 34 deletions(-)
create mode 100644 cobbler/modules/authz_ownership.py
diff --git a/cobbler/modules/authz_ownership.py b/cobbler/modules/authz_ownership.py
new file mode 100644
index 0000000..9b271f4
--- /dev/null
+++ b/cobbler/modules/authz_ownership.py
@@ -0,0 +1,155 @@
+"""
+Authorization module that allow users listed in
+/etc/cobbler/users.conf to be permitted to access resources, with
+the further restriction that cobbler objects can be edited to only
+allow certain users/groups to access those specific objects.
+
+Copyright 2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+import ConfigParser
+import sys
+import os
+from rhpl.translate import _, N_, textdomain, utf8
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+import cexceptions
+import utils
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "authz"
+
+def __parse_config(debug=False):
+ etcfile='/etc/cobbler/users.conf'
+ if not os.path.exists(etcfile):
+ raise CX(_("/etc/cobbler/users.conf does not exist"))
+ config = ConfigParser.ConfigParser()
+ config.read(etcfile)
+ alldata = {}
+ sections = config.sections()
+ if debug:
+ print "[OWNERSHIP] sections=%s" % sections
+ for g in sections:
+ alldata[str(g)] = {}
+ opts = config.options(g)
+ if debug:
+ print "[OWNERSHIP] for group %s, users: %s" % (g,opts)
+ for o in opts:
+ alldata[g][o] = 1
+ return alldata
+
+
+def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
+ """
+ Validate a user against a resource.
+ All users in the file are permitted by this module.
+ """
+
+ user_groups = __parse_config(debug)
+ if debug:
+ print "[OWNERSHIP] ------------"
+ print "can user %s do %s (arg1=%s)?" % (user,resource,arg1)
+ print "consult db: %s" % user_groups
+
+ # classify the type of operation
+ save_or_remove = False
+ for criteria in ["save","remove","modify"]:
+ if resource.find(criteria) != -1:
+ save_or_remove = True
+
+ # FIXME: is everyone allowed to copy? I think so.
+ # FIXME: deal with the problem of deleted parents and promotion
+
+ found_user = False
+ for g in user_groups:
+ if user in user_groups[g]:
+ found_user = True
+ # if user is in the admin group, always authorize
+ # regardless of the ownership of the object.
+ if g == "admin":
+ if debug:
+ print "[OWNERSHIP] user % is an admin, PASS" % user
+ return 1
+ break
+
+ if not found_user:
+ # if the user isn't anywhere in the file, reject regardless
+ # they can still use read-only XMLRPC
+ if debug:
+ print "[OWNERSHIP] user %s not found in list, FAIL" % user
+ return 0
+ if not save_or_remove:
+ # sufficient to allow access for non save/remove ops to all
+ # users for now, may want to refine later.
+ if debug:
+ print "[OWNERSHIP] user %s is cleared for non-edit ops, PASS" % user
+ return 1
+
+ # now we have a save_or_remove op, so we must check ownership
+ # of the object. remove ops pass in arg1 as a string name,
+ # saves pass in actual objects, so we must treat them differently.
+
+ obj = None
+ if resource.find("remove") != -1:
+ if resource == "remove_distro":
+ obj = api_handle.find_distro(arg1)
+ elif resource == "remove_profile":
+ obj = api_handle.find_profile(arg1)
+ elif resource == "remove_system":
+ obj = api_handle.find_system(arg1)
+ elif resource == "remove_repo":
+ obj = api_handle.find_system(arg1)
+ else:
+ obj = arg1
+
+ # if the object has no ownership data, allow access regardless
+ if obj.owners is None or obj.owners == []:
+ if debug:
+ print "[OWNERSHIP] user %s is cleared, object is not owned, PASS" % user
+ return 1
+
+ # otherwise, ownership by user/group
+ for allowed in obj.owners:
+ if user == allowed:
+ # user match
+ if debug:
+ print "[OWNERSHIP] user %s in match list, PASS" % user
+ return 1
+ for group in user_groups:
+ if user in user_groups[group]:
+ if debug:
+ print "[OWNERSHIP] user %s matched by group, PASS" % user
+ return 1
+
+ # can't find user or group in ownership list and ownership is defined
+ # so reject the operation
+ if debug:
+ print "[OWNERSHIP] user %s rejected by default policy, FAIL" % user
+ return 0
+
+
+if __name__ == "__main__":
+ import api as cobbler_api
+ api = cobbler_api.BootAPI()
+ print __parse_config()
+ print authorize(api, "admin1", "sync")
+ d = api.find_distro("F9B-i386")
+ print authorize(api, "admin1", "save_distro", d, debug=True)
+
+ # real tests are contained in tests/tests.py
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 4b04fcb..76ffbcf 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -777,8 +777,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Saves a newly created or modified distro object to disk.
"""
self.log("save_distro",object_id=object_id,token=token)
- self.check_access(token,"save_distro")
obj = self.__get_object(object_id)
+ self.check_access(token,"save_distro",obj)
return self.api.distros().add(obj,save=True)
def save_profile(self,object_id,token):
@@ -786,8 +786,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Saves a newly created or modified profile object to disk.
"""
self.log("save_profile",token=token,object_id=object_id)
- self.check_access(token,"save_profile")
obj = self.__get_object(object_id)
+ self.check_access(token,"save_profile",obj)
return self.api.profiles().add(obj,save=True)
def save_system(self,object_id,token):
@@ -795,8 +795,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Saves a newly created or modified system object to disk.
"""
self.log("save_system",token=token,object_id=object_id)
- self.check_access(token,"save_system")
obj = self.__get_object(object_id)
+ self.check_access(token,"save_system",obj)
return self.api.systems().add(obj,save=True)
def save_repo(self,object_id,token=None):
@@ -804,8 +804,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Saves a newly created or modified repo object to disk.
"""
self.log("save_repo",object_id=object_id,token=token)
- self.check_access(token,"save_repo")
obj = self.__get_object(object_id)
+ self.check_access(token,"save_repo",obj)
return self.api.repos().add(obj,save=True)
def copy_distro(self,object_id,newname,token=None):
diff --git a/tests/tests.py b/tests/tests.py
index 3fb4177..546c83f 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -2,16 +2,6 @@
#
# Michael DeHaan
-TRY_GRAPH = False
-HAS_GRAPH = False
-
-if TRY_GRAPH:
- try:
- import pycallgraph_mod as pycallgraph
- HAS_GRAPH = True
- except:
- pass
-
import sys
import unittest
import os
@@ -25,6 +15,7 @@ from cobbler import settings
from cobbler import collection_distros
from cobbler import collection_profiles
from cobbler import collection_systems
+import cobbler.modules.authz_ownership as authz_module
from cobbler import api
@@ -54,11 +45,11 @@ class BootTest(unittest.TestCase):
except:
pass
- self.fk_initrd = os.path.join(self.topdir, FAKE_INITRD)
+ self.fk_initrd = os.path.join(self.topdir, FAKE_INITRD)
self.fk_initrd2 = os.path.join(self.topdir, FAKE_INITRD2)
self.fk_initrd3 = os.path.join(self.topdir, FAKE_INITRD3)
- self.fk_kernel = os.path.join(self.topdir, FAKE_KERNEL)
+ self.fk_kernel = os.path.join(self.topdir, FAKE_KERNEL)
self.fk_kernel2 = os.path.join(self.topdir, FAKE_KERNEL2)
self.fk_kernel3 = os.path.join(self.topdir, FAKE_KERNEL3)
@@ -75,9 +66,6 @@ class BootTest(unittest.TestCase):
shutil.rmtree(self.topdir,ignore_errors=True)
self.api = None
- if HAS_GRAPH:
- pycallgraph.save_dot("%s.dot" % self.__class__.__name__)
-
def make_basic_config(self):
distro = self.api.new_distro()
self.assertTrue(distro.set_name("testdistro0"))
@@ -116,25 +104,90 @@ class BootTest(unittest.TestCase):
class Ownership(BootTest):
def test_ownership_params(self):
- return # FIXME
- # NOTE: these tests are relaeively weak because they only test
- # that the options are usable, not that they work, since cobbler
- # as a command line tool ignores them, and cobblerd only cares
- # in certain modes.
+ # initially just test that we can set ownership on various components
+
distro = self.api.find_distro(name="testdistro0")
- profile = self.api.find_distro(name="testprofile0")
- system = self.api.find_distro(name="drwily.rdu.redhat.com")
+ profile = self.api.find_profile(name="testprofile0")
+ system = self.api.find_system(name="drwily.rdu.redhat.com")
repo = self.api.find_repo(name="test_repo")
- self.assertTrue(distro.set_owners("a,b"))
- self.assertTrue(profile.set_owners("c,d"))
- self.assertTrue(system.set_owners("e"))
- self.assertTrue(repo.set_owners("f,g"))
+ self.assertTrue(distro.set_owners("superlab,basement1"))
+ self.assertTrue(profile.set_owners("superlab,basement1"))
+ self.assertTrue(system.set_owners("superlab,basement1"))
+ self.assertTrue(repo.set_owners([]))
self.api.add_distro(distro)
self.api.add_profile(profile)
self.api.add_system(system)
self.api.add_repo(repo)
+ # now edit the groups file. We won't test the full XMLRPC
+ # auth stack here, but just the module in question
+
+ authorize = authz_module.authorize
+
+ # if the users.conf file exists, back it up for the tests
+ #if os.path.exists("/etc/cobbler/users.conf"):
+ # shutil.copyfile("/etc/cobbler/users.conf","/tmp/cobbler_ubak")
+
+ fd = open("/etc/cobbler/users.conf","w+")
+ fd.write("\n")
+ fd.write("[admins]\n")
+ fd.write("admin1 = 1\n")
+ fd.write("\n")
+ fd.write("[superlab]\n")
+ fd.write("superlab1 = 1\n")
+ fd.write("\n")
+ fd.write("[basement]\n")
+ fd.write("basement1 = 1\n")
+ fd.write("basement2 = 1\n")
+ fd.close()
+
+ xo = self.api.find_distro("testdistro0")
+ xn = "testdistro0"
+ ro = self.api.find_repo("testrepo0")
+ rn = "testrepo0"
+
+ # ensure admin1 can edit (he's an admin) and do other tasks
+ # same applies to basement1 who is explicitly added as a user
+ # and superlab1 who is in a group in the ownership list
+ for user in ["admin1","superlab1","basement1"]:
+ self.assertTrue(1==authorize(self.api, user, "save_distro", xo, debug=True),"%s can save_distro" % user)
+ self.assertTrue(1==authorize(self.api, user, "modify_distro", xo, debug=True),"%s can modify_distro" % user)
+ self.assertTrue(1==authorize(self.api, user, "copy_distro", xo, debug=True),"%s can copy_distro" % user)
+ self.assertTrue(1==authorize(self.api, user, "remove_distro", xn, debug=True),"%s can remove_distro" % user)
+
+ # ensure all users in the file can sync
+ for user in [ "admin1", "superlab1", "basement1", "basement2" ]:
+ self.assertTrue(1==authorize(self.api, user, "sync", debug=True))
+
+ # make sure basement2 can't edit (not in group)
+ # and same goes for "dne" (does not exist in users.conf)
+
+ for user in [ "basement2", "dne" ]:
+ self.assertTrue(0==authorize(self.api, user, "save_distro", xo, debug=True), "user %s cannot save_distro" % user)
+ self.assertTrue(0==authorize(self.api, user, "modify_distro", xo, debug=True), "user %s cannot modify_distro" % user)
+ self.assertTrue(0==authorize(self.api, user, "remove_distro", xn, debug=True), "user %s cannot remove_distro" % user)
+
+ # basement2 is in the file so he can still copy
+ self.assertTrue(1==authorize(self.api, "basement2", "copy_distro", xo, debug=True), "basement2 can copy_distro")
+
+ # dne can not copy or sync either (not in the users.conf)
+ self.assertTrue(0==authorize(self.api, "dne", "copy_distro", xo, debug=True), "dne cannot copy_distro")
+ self.assertTrue(0==authorize(self.api, "dne", "sync", debug=True), "dne cannot sync")
+
+ # unlike the distro testdistro0, testrepo0 is unowned
+ # so any user in the file will be able to edit it.
+ for user in [ "admin1", "superlab1", "basement1", "basement2" ]:
+ self.assertTrue(1==authorize(self.api, user, "save_repo", ro, debug=True), "user %s can save_repo" % user)
+
+ # though dne is still not listed and will be denied
+ self.assertTrue(0==authorize(self.api, "dne", "save_repo", ro, debug=True), "dne cannot save_repo")
+
+ # if we survive, restore the users file as module testing is done
+ #if os.path.exists("/tmp/cobbler_ubak"):
+ # shutil.copyfile("/etc/cobbler/users.conf","/tmp/cobbler_ubak")
+
+
class MultiNIC(BootTest):
def test_multi_nic_support(self):
@@ -612,14 +665,10 @@ if __name__ == "__main__":
if not os.path.exists("setup.py"):
print "tests: must invoke from top level directory"
sys.exit(1)
- if HAS_GRAPH:
- pycallgraph.start_trace()
loader = unittest.defaultTestLoader
test_module = __import__("tests") # self import considered harmful?
tests = loader.loadTestsFromModule(test_module)
runner = unittest.TextTestRunner()
runner.run(tests)
- if HAS_GRAPH:
- pycallgraph.make_graph('cg_dot.png', tool='dot')
sys.exit(0)
--
cgit
From 9e7e5953469db24a22710f68dd6c5c337e5c0365 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 27 Mar 2008 17:42:45 -0400
Subject: Fixes to authz_ownership module, tests pass now.
---
cobbler/modules/authz_ownership.py | 39 +++++++++++++++++++++++---------------
tests/tests.py | 10 +++++-----
2 files changed, 29 insertions(+), 20 deletions(-)
diff --git a/cobbler/modules/authz_ownership.py b/cobbler/modules/authz_ownership.py
index 9b271f4..43cf523 100644
--- a/cobbler/modules/authz_ownership.py
+++ b/cobbler/modules/authz_ownership.py
@@ -69,7 +69,7 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
# classify the type of operation
save_or_remove = False
- for criteria in ["save","remove","modify"]:
+ for criteria in ["save_","remove_","modify_"]:
if resource.find(criteria) != -1:
save_or_remove = True
@@ -78,15 +78,18 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
found_user = False
for g in user_groups:
- if user in user_groups[g]:
- found_user = True
- # if user is in the admin group, always authorize
- # regardless of the ownership of the object.
- if g == "admin":
- if debug:
- print "[OWNERSHIP] user % is an admin, PASS" % user
- return 1
- break
+ for x in user_groups[g]:
+ if debug:
+ print "[OWNERSHIP] noted user %s in group %s" % (x,g)
+ if x == user:
+ found_user = True
+ # if user is in the admin group, always authorize
+ # regardless of the ownership of the object.
+ if g == "admins" or g == "admin":
+ if debug:
+ print "[OWNERSHIP] user %s is an admin, PASS" % user
+ return 1
+ break
if not found_user:
# if the user isn't anywhere in the file, reject regardless
@@ -107,6 +110,8 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
obj = None
if resource.find("remove") != -1:
+ if debug:
+ print "[OWNERSHIP] looking up object %s" % (arg1)
if resource == "remove_distro":
obj = api_handle.find_distro(arg1)
elif resource == "remove_profile":
@@ -115,7 +120,9 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
obj = api_handle.find_system(arg1)
elif resource == "remove_repo":
obj = api_handle.find_system(arg1)
- else:
+ elif resource.find("save") != -1 or resource.find("modify") != -1:
+ if debug:
+ print "[OWNERSHIP] object being considered is: %s for %s" % (arg1, resource)
obj = arg1
# if the object has no ownership data, allow access regardless
@@ -132,9 +139,9 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
print "[OWNERSHIP] user %s in match list, PASS" % user
return 1
for group in user_groups:
- if user in user_groups[group]:
+ if group == allowed and user in user_groups[group]:
if debug:
- print "[OWNERSHIP] user %s matched by group, PASS" % user
+ print "[OWNERSHIP] user %s matched by group (%s), PASS" % (user, group)
return 1
# can't find user or group in ownership list and ownership is defined
@@ -145,11 +152,13 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
if __name__ == "__main__":
+ # real tests are contained in tests/tests.py
import api as cobbler_api
api = cobbler_api.BootAPI()
print __parse_config()
print authorize(api, "admin1", "sync")
d = api.find_distro("F9B-i386")
+ d.set_owners(["allowed"])
+ api.add_distro(d)
print authorize(api, "admin1", "save_distro", d, debug=True)
-
- # real tests are contained in tests/tests.py
+ print authorize(api, "basement2", "save_distro", d, debug=True)
diff --git a/tests/tests.py b/tests/tests.py
index 546c83f..426ddf2 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -111,9 +111,9 @@ class Ownership(BootTest):
profile = self.api.find_profile(name="testprofile0")
system = self.api.find_system(name="drwily.rdu.redhat.com")
repo = self.api.find_repo(name="test_repo")
- self.assertTrue(distro.set_owners("superlab,basement1"))
- self.assertTrue(profile.set_owners("superlab,basement1"))
- self.assertTrue(system.set_owners("superlab,basement1"))
+ self.assertTrue(distro.set_owners(["superlab","basement1"]))
+ self.assertTrue(profile.set_owners(["superlab","basement1"]))
+ self.assertTrue(system.set_owners(["superlab","basement1"]))
self.assertTrue(repo.set_owners([]))
self.api.add_distro(distro)
self.api.add_profile(profile)
@@ -144,8 +144,8 @@ class Ownership(BootTest):
xo = self.api.find_distro("testdistro0")
xn = "testdistro0"
- ro = self.api.find_repo("testrepo0")
- rn = "testrepo0"
+ ro = self.api.find_repo("test_repo")
+ rn = "test_repo"
# ensure admin1 can edit (he's an admin) and do other tasks
# same applies to basement1 who is explicitly added as a user
--
cgit
From 08ca3dda388b39b02f58121803ca95e8c8d09ac3 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 27 Mar 2008 17:46:23 -0400
Subject: Now that authz_ownership works, remove debug code to make it easier
to read. Also enable code in test scripts to prevent clobbering a users
"users.conf" file when running unit tests.
---
cobbler/modules/authz_ownership.py | 38 +++++---------------------------------
tests/tests.py | 34 +++++++++++++++++-----------------
2 files changed, 22 insertions(+), 50 deletions(-)
diff --git a/cobbler/modules/authz_ownership.py b/cobbler/modules/authz_ownership.py
index 43cf523..3befc4a 100644
--- a/cobbler/modules/authz_ownership.py
+++ b/cobbler/modules/authz_ownership.py
@@ -35,7 +35,7 @@ def register():
"""
return "authz"
-def __parse_config(debug=False):
+def __parse_config():
etcfile='/etc/cobbler/users.conf'
if not os.path.exists(etcfile):
raise CX(_("/etc/cobbler/users.conf does not exist"))
@@ -43,29 +43,21 @@ def __parse_config(debug=False):
config.read(etcfile)
alldata = {}
sections = config.sections()
- if debug:
- print "[OWNERSHIP] sections=%s" % sections
for g in sections:
alldata[str(g)] = {}
opts = config.options(g)
- if debug:
- print "[OWNERSHIP] for group %s, users: %s" % (g,opts)
for o in opts:
alldata[g][o] = 1
return alldata
-def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
+def authorize(api_handle,user,resource,arg1=None,arg2=None):
"""
Validate a user against a resource.
All users in the file are permitted by this module.
"""
- user_groups = __parse_config(debug)
- if debug:
- print "[OWNERSHIP] ------------"
- print "can user %s do %s (arg1=%s)?" % (user,resource,arg1)
- print "consult db: %s" % user_groups
+ user_groups = __parse_config()
# classify the type of operation
save_or_remove = False
@@ -79,29 +71,21 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
found_user = False
for g in user_groups:
for x in user_groups[g]:
- if debug:
- print "[OWNERSHIP] noted user %s in group %s" % (x,g)
if x == user:
found_user = True
# if user is in the admin group, always authorize
# regardless of the ownership of the object.
if g == "admins" or g == "admin":
- if debug:
- print "[OWNERSHIP] user %s is an admin, PASS" % user
return 1
break
if not found_user:
# if the user isn't anywhere in the file, reject regardless
# they can still use read-only XMLRPC
- if debug:
- print "[OWNERSHIP] user %s not found in list, FAIL" % user
return 0
if not save_or_remove:
# sufficient to allow access for non save/remove ops to all
# users for now, may want to refine later.
- if debug:
- print "[OWNERSHIP] user %s is cleared for non-edit ops, PASS" % user
return 1
# now we have a save_or_remove op, so we must check ownership
@@ -110,8 +94,6 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
obj = None
if resource.find("remove") != -1:
- if debug:
- print "[OWNERSHIP] looking up object %s" % (arg1)
if resource == "remove_distro":
obj = api_handle.find_distro(arg1)
elif resource == "remove_profile":
@@ -121,33 +103,23 @@ def authorize(api_handle,user,resource,arg1=None,arg2=None,debug=False):
elif resource == "remove_repo":
obj = api_handle.find_system(arg1)
elif resource.find("save") != -1 or resource.find("modify") != -1:
- if debug:
- print "[OWNERSHIP] object being considered is: %s for %s" % (arg1, resource)
obj = arg1
# if the object has no ownership data, allow access regardless
if obj.owners is None or obj.owners == []:
- if debug:
- print "[OWNERSHIP] user %s is cleared, object is not owned, PASS" % user
return 1
# otherwise, ownership by user/group
for allowed in obj.owners:
if user == allowed:
# user match
- if debug:
- print "[OWNERSHIP] user %s in match list, PASS" % user
return 1
for group in user_groups:
if group == allowed and user in user_groups[group]:
- if debug:
- print "[OWNERSHIP] user %s matched by group (%s), PASS" % (user, group)
return 1
# can't find user or group in ownership list and ownership is defined
# so reject the operation
- if debug:
- print "[OWNERSHIP] user %s rejected by default policy, FAIL" % user
return 0
@@ -160,5 +132,5 @@ if __name__ == "__main__":
d = api.find_distro("F9B-i386")
d.set_owners(["allowed"])
api.add_distro(d)
- print authorize(api, "admin1", "save_distro", d, debug=True)
- print authorize(api, "basement2", "save_distro", d, debug=True)
+ print authorize(api, "admin1", "save_distro", d)
+ print authorize(api, "basement2", "save_distro", d)
diff --git a/tests/tests.py b/tests/tests.py
index 426ddf2..c3cbea7 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -126,8 +126,8 @@ class Ownership(BootTest):
authorize = authz_module.authorize
# if the users.conf file exists, back it up for the tests
- #if os.path.exists("/etc/cobbler/users.conf"):
- # shutil.copyfile("/etc/cobbler/users.conf","/tmp/cobbler_ubak")
+ if os.path.exists("/etc/cobbler/users.conf"):
+ shutil.copyfile("/etc/cobbler/users.conf","/tmp/cobbler_ubak")
fd = open("/etc/cobbler/users.conf","w+")
fd.write("\n")
@@ -151,41 +151,41 @@ class Ownership(BootTest):
# same applies to basement1 who is explicitly added as a user
# and superlab1 who is in a group in the ownership list
for user in ["admin1","superlab1","basement1"]:
- self.assertTrue(1==authorize(self.api, user, "save_distro", xo, debug=True),"%s can save_distro" % user)
- self.assertTrue(1==authorize(self.api, user, "modify_distro", xo, debug=True),"%s can modify_distro" % user)
- self.assertTrue(1==authorize(self.api, user, "copy_distro", xo, debug=True),"%s can copy_distro" % user)
- self.assertTrue(1==authorize(self.api, user, "remove_distro", xn, debug=True),"%s can remove_distro" % user)
+ self.assertTrue(1==authorize(self.api, user, "save_distro", xo),"%s can save_distro" % user)
+ self.assertTrue(1==authorize(self.api, user, "modify_distro", xo),"%s can modify_distro" % user)
+ self.assertTrue(1==authorize(self.api, user, "copy_distro", xo),"%s can copy_distro" % user)
+ self.assertTrue(1==authorize(self.api, user, "remove_distro", xn),"%s can remove_distro" % user)
# ensure all users in the file can sync
for user in [ "admin1", "superlab1", "basement1", "basement2" ]:
- self.assertTrue(1==authorize(self.api, user, "sync", debug=True))
+ self.assertTrue(1==authorize(self.api, user, "sync"))
# make sure basement2 can't edit (not in group)
# and same goes for "dne" (does not exist in users.conf)
for user in [ "basement2", "dne" ]:
- self.assertTrue(0==authorize(self.api, user, "save_distro", xo, debug=True), "user %s cannot save_distro" % user)
- self.assertTrue(0==authorize(self.api, user, "modify_distro", xo, debug=True), "user %s cannot modify_distro" % user)
- self.assertTrue(0==authorize(self.api, user, "remove_distro", xn, debug=True), "user %s cannot remove_distro" % user)
+ self.assertTrue(0==authorize(self.api, user, "save_distro", xo), "user %s cannot save_distro" % user)
+ self.assertTrue(0==authorize(self.api, user, "modify_distro", xo), "user %s cannot modify_distro" % user)
+ self.assertTrue(0==authorize(self.api, user, "remove_distro", xn), "user %s cannot remove_distro" % user)
# basement2 is in the file so he can still copy
- self.assertTrue(1==authorize(self.api, "basement2", "copy_distro", xo, debug=True), "basement2 can copy_distro")
+ self.assertTrue(1==authorize(self.api, "basement2", "copy_distro", xo), "basement2 can copy_distro")
# dne can not copy or sync either (not in the users.conf)
- self.assertTrue(0==authorize(self.api, "dne", "copy_distro", xo, debug=True), "dne cannot copy_distro")
- self.assertTrue(0==authorize(self.api, "dne", "sync", debug=True), "dne cannot sync")
+ self.assertTrue(0==authorize(self.api, "dne", "copy_distro", xo), "dne cannot copy_distro")
+ self.assertTrue(0==authorize(self.api, "dne", "sync"), "dne cannot sync")
# unlike the distro testdistro0, testrepo0 is unowned
# so any user in the file will be able to edit it.
for user in [ "admin1", "superlab1", "basement1", "basement2" ]:
- self.assertTrue(1==authorize(self.api, user, "save_repo", ro, debug=True), "user %s can save_repo" % user)
+ self.assertTrue(1==authorize(self.api, user, "save_repo", ro), "user %s can save_repo" % user)
# though dne is still not listed and will be denied
- self.assertTrue(0==authorize(self.api, "dne", "save_repo", ro, debug=True), "dne cannot save_repo")
+ self.assertTrue(0==authorize(self.api, "dne", "save_repo", ro), "dne cannot save_repo")
# if we survive, restore the users file as module testing is done
- #if os.path.exists("/tmp/cobbler_ubak"):
- # shutil.copyfile("/etc/cobbler/users.conf","/tmp/cobbler_ubak")
+ if os.path.exists("/tmp/cobbler_ubak"):
+ shutil.copyfile("/etc/cobbler/users.conf","/tmp/cobbler_ubak")
class MultiNIC(BootTest):
--
cgit
From af4f5696e9fa1a800a45289931ed147b7fb6f5ed Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 28 Mar 2008 17:23:12 -0400
Subject: Add owners list to WebUI pages, also customize function for saving
lists to avoid extra whitespace on comma delimited inputs.
---
cobbler/utils.py | 4 +++-
webui_templates/distro_edit.tmpl | 18 ++++++++++++++++++
webui_templates/profile_edit.tmpl | 18 ++++++++++++++++++
webui_templates/repo_edit.tmpl | 17 +++++++++++++++++
webui_templates/system_edit.tmpl | 18 ++++++++++++++++++
5 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 9c770d0..4d2b635 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -239,7 +239,9 @@ def input_string_or_list(options,delim=","):
elif type(options) == list:
return options
elif type(options) == str:
- tokens = options.split(",")
+ tokens = options.split(delim)
+ if delim == ",":
+ tokens = [t.lstrip().rstrip() for t in tokens]
return tokens
else:
raise CX(_("invalid input type"))
diff --git a/webui_templates/distro_edit.tmpl b/webui_templates/distro_edit.tmpl
index 4729816..8b7d2cb 100644
--- a/webui_templates/distro_edit.tmpl
+++ b/webui_templates/distro_edit.tmpl
@@ -172,6 +172,24 @@ function disablename(value)
+
Applies only if using authz_ownership module, comma-delimited
+
+
+
+
## ====================================== start of looping through interfaces
--
cgit
From 2e71866208f81f0df7205bce724168b480db83e7 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 28 Mar 2008 17:25:53 -0400
Subject: Add code to make WebUI process new fields
---
cobbler/webui/CobblerWeb.py | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index 9a0cf90..ebbfbf6 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -169,7 +169,7 @@ class CobblerWeb(object):
} )
def distro_save(self,name=None,oldname=None,new_or_edit=None,editmode='edit',kernel=None,
- initrd=None,kopts=None,ksmeta=None,arch=None,breed=None,
+ initrd=None,kopts=None,ksmeta=None,owners=None,arch=None,breed=None,
delete1=None,delete2=None,**args):
if not self.__xmlrpc_setup():
@@ -220,6 +220,8 @@ class CobblerWeb(object):
self.remote.modify_distro(distro, 'kopts', kopts, self.token)
if ksmeta:
self.remote.modify_distro(distro, 'ksmeta', ksmeta, self.token)
+ if owners:
+ self.remote.modify_distro(distro, 'owners', owners, self.token)
if arch:
self.remote.modify_distro(distro, 'arch', arch, self.token)
if breed:
@@ -288,7 +290,7 @@ class CobblerWeb(object):
def system_save(self,name=None,oldname=None,editmode="edit",profile=None,
new_or_edit=None,
- kopts=None, ksmeta=None, server_override=None, netboot='n',
+ kopts=None, ksmeta=None, owners=None, server_override=None, netboot='n',
delete1=None, delete2=None, **args):
if not self.__xmlrpc_setup():
@@ -332,6 +334,8 @@ class CobblerWeb(object):
self.remote.modify_system(system, 'kopts', kopts, self.token)
if ksmeta:
self.remote.modify_system(system, 'ksmeta', ksmeta, self.token)
+ if owners:
+ self.remote.modify_system(system, 'owners', owners, self.token)
if netboot:
self.remote.modify_system(system, 'netboot-enabled', netboot, self.token)
if server_override:
@@ -441,7 +445,7 @@ class CobblerWeb(object):
def profile_save(self,new_or_edit=None,editmode='edit',name=None,oldname=None,
distro=None,kickstart=None,kopts=None,
- ksmeta=None,virtfilesize=None,virtram=None,virttype=None,
+ ksmeta=None,owners=None,virtfilesize=None,virtram=None,virttype=None,
virtpath=None,repos=None,dhcptag=None,delete1=None,delete2=None,
parent=None,virtcpus=None,virtbridge=None,subprofile=None,server_override=None,**args):
@@ -495,6 +499,8 @@ class CobblerWeb(object):
self.remote.modify_profile(profile, 'kickstart', kickstart, self.token)
if kopts:
self.remote.modify_profile(profile, 'kopts', kopts, self.token)
+ if owners:
+ self.remote.modify_profile(profile, 'owners', kopts, self.token)
if ksmeta:
self.remote.modify_profile(profile, 'ksmeta', ksmeta, self.token)
if virtfilesize:
@@ -571,7 +577,7 @@ class CobblerWeb(object):
} )
def repo_save(self,name=None,oldname=None,new_or_edit=None,editmode="edit",
- mirror=None,keep_updated=None,priority=99,
+ mirror=None,owners=None,keep_updated=None,priority=99,
rpm_list=None,createrepo_flags=None,arch=None,yumopts=None,
delete1=None,delete2=None,**args):
if not self.__xmlrpc_setup():
@@ -624,6 +630,8 @@ class CobblerWeb(object):
self.remote.modify_repo(repo, 'arch', arch, self.token)
if yumopts:
self.remote.modify_repo(repo, 'yumopts', yumopts, self.token)
+ if owners:
+ self.remote.modify_repo(repo, 'owners', owners, self.token)
self.remote.save_repo(repo, self.token)
--
cgit
From 9a2c291b0e068d622f6e70e55df29bc7dcc60359 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 28 Mar 2008 17:39:50 -0400
Subject: Fix some typos
---
cobbler/remote.py | 4 +++-
cobbler/webui/CobblerWeb.py | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 76ffbcf..fa74e17 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -624,7 +624,9 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
def __authorize(self,token,resource,arg1=None,arg2=None):
user = self.get_user_from_token(token)
- self.log("calling authorize for resource %s" % resource, user=user)
+ args = [ resource, arg1, arg2 ]
+ self.log("calling authorize for resource %s" % args, user=user)
+
rc = self.api.authorize(user,resource,arg1,arg2)
if rc:
return True
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index ebbfbf6..f53ba4d 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -500,7 +500,7 @@ class CobblerWeb(object):
if kopts:
self.remote.modify_profile(profile, 'kopts', kopts, self.token)
if owners:
- self.remote.modify_profile(profile, 'owners', kopts, self.token)
+ self.remote.modify_profile(profile, 'owners', owners, self.token)
if ksmeta:
self.remote.modify_profile(profile, 'ksmeta', ksmeta, self.token)
if virtfilesize:
--
cgit
From c9ff51e05c0e5e8a86d6a5d3654bf505a3dfdb17 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 28 Mar 2008 18:00:11 -0400
Subject: Fix some more bugs with ownership editing/saving. Working well in
the WebUI now with respect to being able to change things, still need to work
on better showing denials and what folks can edit.
---
cobbler/item_repo.py | 2 ++
cobbler/item_system.py | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/cobbler/item_repo.py b/cobbler/item_repo.py
index d65d09b..e796561 100644
--- a/cobbler/item_repo.py
+++ b/cobbler/item_repo.py
@@ -39,6 +39,7 @@ class Repo(item.Item):
self.depth = 2 # arbitrary, as not really apart of the graph
self.arch = "" # use default arch
self.yumopts = {}
+ self.owners = []
def from_datastruct(self,seed_data):
self.parent = self.load_item(seed_data, 'parent')
@@ -51,6 +52,7 @@ class Repo(item.Item):
self.arch = self.load_item(seed_data, 'arch')
self.depth = self.load_item(seed_data, 'depth', 2)
self.yumopts = self.load_item(seed_data, 'yumopts', {})
+ self.owners = self.load_item(seed_data, 'owners', [])
# force this to be saved as a boolean
self.set_keep_updated(self.keep_updated)
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 51dd063..6b2315a 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -81,7 +81,7 @@ class System(item.Item):
self.parent = self.load_item(seed_data, 'parent')
self.name = self.load_item(seed_data, 'name')
- self.owners = self.load_item(seed_data, 'owners')
+ self.owners = self.load_item(seed_data, 'owners', [])
self.profile = self.load_item(seed_data, 'profile')
self.kernel_options = self.load_item(seed_data, 'kernel_options', {})
self.ks_meta = self.load_item(seed_data, 'ks_meta', {})
@@ -338,7 +338,7 @@ class System(item.Item):
def to_datastruct(self):
return {
'name' : self.name,
- 'owners' : self.set_owners,
+ 'owners' : self.owners,
'profile' : self.profile,
'kernel_options' : self.kernel_options,
'ks_meta' : self.ks_meta,
--
cgit
From 328f4f65d79ad8af4bb888330563689f1f09e21a Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 31 Mar 2008 15:28:55 -0400
Subject: Remove trailing commas in config file
---
config/settings | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/config/settings b/config/settings
index d9b1785..11c21f2 100644
--- a/config/settings
+++ b/config/settings
@@ -20,10 +20,10 @@ kernel_options:
ksdevice: eth0
lang: ' '
text: ~
-ldap_server: "ldap.example.com",
-ldap_base_dn: "DC=example,DC=com",
-ldap_port: 389,
-ldap_tls: 1,
+ldap_server: "ldap.example.com"
+ldap_base_dn: "DC=example,DC=com"
+ldap_port: 389
+ldap_tls: 1
manage_dhcp: 0
manage_dhcp_mode: isc
next_server: '127.0.0.1'
--
cgit
From ca136de01b6d6604ca0fdf2990395c9212abd6a8 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 31 Mar 2008 15:34:10 -0400
Subject: Fix default config file format.
---
config/users.conf | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/config/users.conf b/config/users.conf
index 94a3566..129659a 100644
--- a/config/users.conf
+++ b/config/users.conf
@@ -18,9 +18,11 @@
# cobbler command line example:
#
# cobbler system edit --name=server1 --owner=dbas,mac,pete,jack
-
+#
+# NOTE: yes, you do need the equal sign after the names.
+# don't remove that part. It's reserved for future use.
[admins]
-admin
-cobbler
+admin = ""
+cobbler = ""
--
cgit
From eee7bfa18052bb1e3d0c84421f2b425073043888 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 31 Mar 2008 16:15:55 -0400
Subject: Minor changes to the authn/z test program so they don't go through
Apache auth filters and can produce slightly more useful feedback, also
removed a stray print.
---
cobbler/demo_connect.py | 7 ++++++-
cobbler/modules/authn_ldap.py | 4 ++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/cobbler/demo_connect.py b/cobbler/demo_connect.py
index 6397a6b..94fa390 100644
--- a/cobbler/demo_connect.py
+++ b/cobbler/demo_connect.py
@@ -18,11 +18,16 @@ if __name__ == "__main__":
p = optparse.OptionParser()
p.add_option("-u","--user",dest="user",default="test")
p.add_option("-p","--pass",dest="password",default="test")
- sp = ServerProxy("http://127.0.0.1/cobbler_api_rw")
+
+ # NOTE: if you've changed your xmlrpc_rw port or
+ # disabled xmlrpc_rw this test probably won't work
+
+ sp = ServerProxy("http://127.0.0.1:25152")
(options, args) = p.parse_args()
print "- trying to login with user=%s" % options.user
token = sp.login(options.user,options.password)
print "- token: %s" % token
+ print "- authenticated ok, now seeing if user is authorized"
check = sp.check_access(token,"imaginary_method_name")
print "- access ok? %s" % check
diff --git a/cobbler/modules/authn_ldap.py b/cobbler/modules/authn_ldap.py
index 6d190bd..8e54a45 100644
--- a/cobbler/modules/authn_ldap.py
+++ b/cobbler/modules/authn_ldap.py
@@ -83,7 +83,7 @@ def authenticate(api_handle,username,password):
# ignore entry; we don't need it
pass
else:
- print "FAIL 2"
+ # print "FAIL 2"
return False
try:
@@ -92,7 +92,7 @@ def authenticate(api_handle,username,password):
dir.unbind()
return True
except:
- traceback.print_exc()
+ # traceback.print_exc()
return False
# catch-all
return False
--
cgit
From c3437479cc300683ac3ffd270114eed3dcaf4f39 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 31 Mar 2008 17:09:26 -0400
Subject: Distro now instrumented with a warning panel that indicates when you
probably won't be able to edit an object.
---
cobbler/remote.py | 44 ++++++++++++++++++++++++++++++++++++----
cobbler/webui/CobblerWeb.py | 7 ++++++-
webui_templates/distro_edit.tmpl | 9 ++++++++
3 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index fa74e17..5e3fb83 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -593,6 +593,42 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.log("invalid token",token=token)
raise CX(_("invalid token: %s" % token))
+ def __name_to_object(self,resource,name):
+ if resource.find("distro") != -1:
+ return self.api.find_distro(name)
+ if resource.find("profile") != -1:
+ return self.api.find_profile(name)
+ if resource.find("system") != -1:
+ return self.api.find_system(name)
+ if resource.find("repo") != -1:
+ return self.api.find_repo(name)
+ return None
+
+ def check_access_no_fail(self,token,resource,arg1=None,arg2=None):
+ """
+ This is called by the WUI to decide whether an element
+ is editable or not. It differs form check_access in that
+ it is supposed to /not/ log the access checks (TBA) and does
+ not raise exceptions.
+ """
+
+ need_remap = False
+ for x in [ "distro", "profile", "system", "repo" ]:
+ if arg1 is not None and resource.find(x) != -1:
+ need_remap = True
+ break
+
+ if need_remap:
+ # we're called with an object name, but need an object
+ arg1 = self.__name_to_object(resource,arg1)
+
+ try:
+ self.check_access(token,resource,arg1,arg2)
+ return True
+ except:
+ utils.log_exc(self.logger)
+ return False
+
def check_access(self,token,resource,arg1=None,arg2=None):
validated = self.__validate_token(token)
user = self.get_user_from_token(token)
@@ -881,8 +917,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing distro object handle.
"""
- self.check_access(token, "modify_distro", attribute, arg)
obj = self.__get_object(object_id)
+ self.check_access(token, "modify_distro", obj, attribute)
return self.__call_method(obj, attribute, arg)
def modify_profile(self,object_id,attribute,arg,token):
@@ -890,8 +926,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing profile object handle.
"""
- self.check_access(token, "modify_profile", attribute, arg)
obj = self.__get_object(object_id)
+ self.check_access(token, "modify_profile", obj, attribute)
return self.__call_method(obj, attribute, arg)
def modify_system(self,object_id,attribute,arg,token):
@@ -899,8 +935,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing system object handle.
"""
- self.check_access(token, "modify_system", attribute, arg)
obj = self.__get_object(object_id)
+ self.check_access(token, "modify_system", obj, attribute)
return self.__call_method(obj, attribute, arg)
def modify_repo(self,object_id,attribute,arg,token):
@@ -908,8 +944,8 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
Allows modification of certain attributes on newly created or
existing repo object handle.
"""
- self.check_access(token, "modify_repo", attribute, arg)
obj = self.__get_object(object_id)
+ self.check_access(token, "modify_repo", obj, attribute)
return self.__call_method(obj, attribute, arg)
def remove_distro(self,name,token,recursive=1):
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index f53ba4d..b2de916 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -162,9 +162,14 @@ class CobblerWeb(object):
input_distro = None
if name is not None:
input_distro = self.remote.get_distro(name, True)
-
+ can_edit = self.remote.check_access_no_fail(self.token,"modify_distro",name)
+ else:
+ can_edit = self.remote.check_access_no_fail(self.token,"new_distro",None)
+
+
return self.__render( 'distro_edit.tmpl', {
'edit' : True,
+ 'editable' : can_edit,
'distro': input_distro,
} )
diff --git a/webui_templates/distro_edit.tmpl b/webui_templates/distro_edit.tmpl
index 8b7d2cb..ccbb72f 100644
--- a/webui_templates/distro_edit.tmpl
+++ b/webui_templates/distro_edit.tmpl
@@ -15,6 +15,15 @@ function disablename(value)
#end if
+#if $editable != True
+
+$editable
+
+WARNING: It looks like you do not have permission to make changes.
+To recieve access, contact your Cobbler server administrator.
+
+#end if
+
-The Cobbler WebUI is designed for day-to-day usage of the Cobbler provisioning server. It performs
-most but not all of the functions Cobbler can perform. Nearly all of what you would
-need for routine maintaince of your deployment setups can be done through the web. If you have
+The Cobbler WebUI is designed for simplifying day-to-day usage of the Cobbler provisioning server. It performs
+most but not all of the functions the command line tool "cobbler" or the API can perform. If you have
not already done so, you may be interested to read more about Cobbler at
-cobbler.et.redhat.com and hosted.fedoraproject.org.
+cobbler.et.redhat.com and at fedorahosted.org.
Those pages contain further documentation, tips & tricks, and links to the mailing list and users/developers
IRC channel.
-It is expected that you have read the Cobbler manpage, which for the most part focuses on cobbler as run from the command line. You will need to use the command line some, so please do read the docs. For starters, you should have started your cobbler install with running "cobbler check" locally. If not,
+It is probably a good idea to read the Cobbler manpage, which for the most part focuses on cobbler as run from the command line. Admins will need to use the command line some, so please do read the docs if you are in charge of the Cobbler server -- or if you need more detail about what some of the options mean.
+
+
+
+The Cobbler server install should have started your cobbler install with running "cobbler check" locally to resolve potential configuration problems. If not,
please do so now before continuing. This will make sure your installation is configured and ready to go. The rest
of this document will mainly be detailing the differences between the CLI (as described in the manpage) and the Web interface.
@@ -52,12 +54,15 @@ content from a DVD or an rsync mirror -- running cobbler import locally is also
-Another command that you cannot run locally is "cobbler reposync", which is a fairly long-running operation
+Another command that you cannot run via the web interface is "cobbler reposync", which can be a fairly long-running operation
that you may want to put on a crontab. You also cannot edit the cobbler settings file (this is more
of a precaution against locking yourself out of the WebUI), but you can view it. For instance this means
that if you want Cobbler to help manage your DHCP config (great!) you can do that through the Web UI
-but you have to turn that on in the settings file. Furthermore, files like /etc/cobbler/dhcp.template
-have to be edited locally.
+but you have to turn that on in the settings file (be sure to restart cobblerd after making changes). Furthermore, other configuration and template files in /etc/cobbler (that are not kickstart templates) also have to be edited locally.
+
+
+
+Your Cobbler server administrator may have set cobbler up to allow access to only certain objects for certain user accounts. In the event of this, you will see messages in the interface that indicate when you do not have permissions to perform certain actions. Contact your Cobbler server administrator to resolve these items or to learn more if you have questions.
--
cgit
From d0bc28d37734a35c332e3e60ba56ccff5e037018 Mon Sep 17 00:00:00 2001
From: root
Date: Fri, 4 Apr 2008 16:34:48 -0400
Subject: Working on adding checks for duplicate names/ips/macs to cobbler
---
cobbler/api.py | 16 +++---
cobbler/collection.py | 69 +++++++++++++++++++++--
cobbler/commands.py | 30 +++++++++-
cobbler/modules/cli_system.py | 7 ++-
cobbler/settings.py | 2 +
config/settings | 2 +
templates/dnsmasq.template | 2 +-
tests/tests.py | 125 ++++++++++++++++++++++++++++++++++++++++++
8 files changed, 238 insertions(+), 15 deletions(-)
diff --git a/cobbler/api.py b/cobbler/api.py
index 13fc5f3..54c315b 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -221,21 +221,21 @@ class BootAPI:
self.log("new_repo",[is_subobject])
return self._config.new_repo(is_subobject=is_subobject)
- def add_distro(self, ref):
+ def add_distro(self, ref, check_for_duplicate_names=False):
self.log("add_distro",[ref.name])
- return self._config.distros().add(ref,save=True)
+ return self._config.distros().add(ref,save=True,check_for_duplicate_names=check_for_duplicate_names)
- def add_profile(self, ref):
+ def add_profile(self, ref, check_for_duplicate_names=False):
self.log("add_profile",[ref.name])
- return self._config.profiles().add(ref,save=True)
+ return self._config.profiles().add(ref,save=True,check_for_duplicate_names=check_for_duplicate_names)
- def add_system(self,ref):
+ def add_system(self, ref, check_for_duplicate_names=False, check_for_duplicate_netinfo=False):
self.log("add_system",[ref.name])
- return self._config.systems().add(ref,save=True)
+ return self._config.systems().add(ref,save=True,check_for_duplicate_names=check_for_duplicate_names,check_for_duplicate_netinfo=check_for_duplicate_netinfo)
- def add_repo(self,ref):
+ def add_repo(self, ref, check_for_duplicate_names=False):
self.log("add_repo",[ref.name])
- return self._config.repos().add(ref,save=True)
+ return self._config.repos().add(ref,save=True,check_for_duplicate_names=check_for_duplicate_names)
def find_distro(self, name=None, return_list=False, **kargs):
return self._config.distros().find(name=name, return_list=return_list, **kargs)
diff --git a/cobbler/collection.py b/cobbler/collection.py
index 339a4b2..14bba57 100644
--- a/cobbler/collection.py
+++ b/cobbler/collection.py
@@ -35,7 +35,8 @@ class Collection(serializable.Serializable):
"""
self.config = config
self.clear()
- self.log_func = self.config.api.log
+ self.api = self.config.api
+ self.log_func = self.api.log
self.lite_sync = None
def factory_produce(self,config,seed_data):
@@ -125,10 +126,10 @@ class Collection(serializable.Serializable):
k.set_parent(newname)
else:
k.set_distro(newname)
- self.config.api.profiles().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers)
+ self.api.profiles().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers)
elif k.COLLECTION_TYPE == "system":
k.set_profile(newname)
- self.config.api.systems().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers)
+ self.api.systems().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers)
elif k.COLLECTION_TYPE == "repo":
raise CX(_("internal error, not expected to have repo child objects"))
else:
@@ -139,7 +140,7 @@ class Collection(serializable.Serializable):
return True
- def add(self,ref,save=False,with_copy=False,with_triggers=True,with_sync=True,quick_pxe_update=False):
+ def add(self,ref,save=False,with_copy=False,with_triggers=True,with_sync=True,quick_pxe_update=False,check_for_duplicate_names=False,check_for_duplicate_netinfo=False):
"""
Add an object to the collection, if it's valid. Returns True
if the object was added to the collection. Returns False if the
@@ -167,6 +168,11 @@ class Collection(serializable.Serializable):
# if not saving the object, you can't run these features
with_triggers = False
with_sync = False
+
+ # Avoid adding objects to the collection
+ # if an object of the same/ip/mac already exists.
+ self.__duplication_checks(ref,check_for_duplicate_names,check_for_duplicate_netinfo)
+
if ref is None or not ref.is_valid():
raise CX(_("insufficient or invalid arguments supplied"))
@@ -220,6 +226,61 @@ class Collection(serializable.Serializable):
def _run_triggers(self,ref,globber):
return utils.run_triggers(ref,globber)
+ def __duplication_checks(self,ref,check_for_duplicate_names,check_for_duplicate_netinfo):
+ """
+ Prevents adding objects with the same name.
+ Prevents adding or editing to provide the same IP, or MAC.
+ This applies to new "add" commands,
+ Edits that are not copies/renames should only yelp if they match
+ an object that is not the same as the object being edited. (FIXME)
+ """
+
+ # always protect against duplicate names
+ if check_for_duplicate_names:
+ match = None
+ if isinstance(ref, item_system.System):
+ match = self.api.find_system(ref.name)
+ elif isinstance(ref, item_profile.Profile):
+ match = self.api.find_profile(ref.name)
+ elif isinstance(ref, item_distro.Distro):
+ match = self.api.find_distro(ref.name)
+ elif isinstance(ref, item_repo.Repo):
+ match = self.api.find_repo(ref.name)
+
+ if match:
+ raise CX(_("An object already exists with that name. Try 'edit'?"))
+
+ # the duplicate mac/ip checks can be disabled.
+ if not check_for_duplicate_netinfo:
+ return
+
+ # FIXME: if we run this command on edits it may yield false
+ # positives when ref is set to replace an object of an existing
+ # name, so we should probably /not/ run this on edits yet at this
+ # point. Logic to deal with renames vs. edit/copies is somewhat
+ # involved.
+ if isinstance(ref, item_system.System):
+ for (name, intf) in ref.interfaces.iteritems():
+ match_ip = []
+ match_mac = []
+ input_mac = intf["mac_address"]
+ input_ip = intf["ip_address"]
+ if not self.api.settings().allow_duplicate_macs and input_mac is not None and input_mac != "":
+ match_mac = self.api.find_system(mac_address=input_mac,return_list=True)
+ if not self.api.settings().allow_duplicate_ips and input_ip is not None and input_ip != "":
+ match_ip = self.api.find_system(ip_address=input_ip,return_list=True)
+ # it's ok to conflict with your own net info.
+ # FIXME: copies won't ever work this way, so they should NOT
+ # use the flags that engadge these checks. Renames should
+ # be exempt also
+
+ for x in match_mac:
+ if x.name != ref.name:
+ raise CX(_("Can't save system %s. The MAC address (%s) is already used by system %s (%s)") % (ref.name, intf["mac_address"], x.name, name))
+ for x in match_ip:
+ if x.name != ref.name:
+ raise CX(_("Can't save system %s. The IP address (%s) is already used by system %s (%s)") % (ref.name, intf["ip_address"], x.name, name))
+
def printable(self):
"""
Creates a printable representation of the collection suitable
diff --git a/cobbler/commands.py b/cobbler/commands.py
index d97a6e1..6bb0419 100644
--- a/cobbler/commands.py
+++ b/cobbler/commands.py
@@ -251,10 +251,38 @@ class CobblerFunction:
opt_sync = not options.nosync
opt_triggers = not options.notriggers
+ # ** WARNING: COMPLICATED **
+ # what operation we call depends on what type of object we are editing
+ # and what the operation is. The details behind this is that the
+ # add operation has special semantics around adding objects that might
+ # clobber other objects, and we don't want that to happen. Edit
+ # does not have to check for named clobbering but still needs
+ # to check for IP/MAC clobbering in some scenarios (FIXME).
+ # this is all enforced by collections.py though we need to make
+ # the apppropriate call to add to invoke the safety code in the right
+ # places -- and not in places where the safety code will generate
+ # errors under legit circumstances.
+
if not ("rename" in self.args):
- rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers)
+ if "add" in self.args:
+ if obj.COLLECTION_TYPE == "system":
+ # duplicate names and netinfo are both bad.
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=True, check_for_duplicate_netinfo=True)
+ else:
+ # duplicate names are bad
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=True, check_for_duplicate_netinfo=False)
+ else:
+ # editing or copying (but not renaming), so duplicate netinfo
+ # CAN be bad, duplicate names are already handled, though
+ # we need to clean up checks around duplicate netinfo here
+ # (FIXME) so they are made and work.
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers)
+
else:
+ # we are renaming here, so duplicate netinfo checks also
+ # need to be made.(FIXME)
rc = collect_fn().rename(obj, self.options.newname)
+
return rc
def reporting_sorter(self, a, b):
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 01ead35..01f2ba6 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -103,8 +103,13 @@ class SystemFunction(commands.CobblerFunction):
if self.options.owners:
obj.set_owners(self.options.owners)
- return self.object_manipulator_finish(obj, self.api.systems, self.options)
+ rc = self.object_manipulator_finish(obj, self.api.systems, self.options)
+ if ["copy"] in self.args:
+ # run through and find conflicts
+ print _("WARNING: after copying systems, be sure that the ip/mac information is unique").
+
+ return rc
########################################################
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 0ef2ab7..c201ddd 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -24,6 +24,8 @@ TESTMODE = False
DEFAULTS = {
"allow_cgi_mac_registration" : 0,
"allow_cgi_profile_change" : 0,
+ "allow_duplicate_macs" : 0,
+ "allow_duplicate_ips" : 0,
"bootloaders" : {
"standard" : "/usr/lib/syslinux/pxelinux.0",
"ia64" : "/var/lib/cobbler/elilo-3.6-ia64.efi"
diff --git a/config/settings b/config/settings
index 36cd9b4..8fc0fdf 100644
--- a/config/settings
+++ b/config/settings
@@ -1,6 +1,8 @@
---
allow_cgi_mac_registration: 0
allow_cgi_profile_change: 0
+allow_duplicate_macs: 0
+allow_duplicate_ips: 0
bootloaders:
ia64: /var/lib/cobbler/elilo-3.6-ia64.efi
standard: /usr/lib/syslinux/pxelinux.0
diff --git a/templates/dnsmasq.template b/templates/dnsmasq.template
index 0646b71..28297d2 100644
--- a/templates/dnsmasq.template
+++ b/templates/dnsmasq.template
@@ -6,7 +6,7 @@
#no-poll
#enable-dbus
read-ethers
-addn-hosts = /var/lib/cobbler/hosts_cobbler/
+addn-hosts = /var/lib/cobbler/cobbler_hosts
dhcp-range=192.168.1.5,192.168.1.200
dhcp-option=3,$next_server
diff --git a/tests/tests.py b/tests/tests.py
index 8a86bab..4060eef 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -8,6 +8,7 @@ import os
import subprocess
import tempfile
import shutil
+import traceback
from cobbler.cexceptions import *
@@ -84,6 +85,7 @@ class BootTest(unittest.TestCase):
system = self.api.new_system()
self.assertTrue(system.set_name("drwily.rdu.redhat.com"))
self.assertTrue(system.set_mac_address("BB:EE:EE:EE:EE:FF","intf0"))
+ self.assertTrue(system.set_ip_address("192.51.51.50","intf0"))
self.assertTrue(system.set_profile("testprofile0"))
self.assertTrue(self.api.add_system(system))
self.assertTrue(self.api.find_system(name="drwily.rdu.redhat.com"))
@@ -100,6 +102,129 @@ class BootTest(unittest.TestCase):
self.assertTrue(repo.set_mirror("/tmp/test_example_cobbler_repo"))
self.assertTrue(self.api.repos().add(repo))
+class DuplicateNamesAndIpPrevention(BootTest):
+
+ """
+ The command line (and WebUI) have checks to prevent new system
+ additions from conflicting with existing systems and overwriting
+ them inadvertantly. This class tests that code. NOTE: General API
+ users will /not/ encounter these checks.
+ """
+
+ def test_duplicate_prevention(self):
+
+ # find things we are going to test with
+ distro1 = self.api.find_distro(name="testdistro0")
+ profile1 = self.api.find_profile(name="testprofile0")
+ system1 = self.api.find_system(name="drwily.rdu.redhat.com")
+ repo1 = self.api.find_repo(name="test_repo")
+
+ # make sure we can't overwrite a previous distro with
+ # the equivalent of an "add" (not an edit) on the
+ # command line.
+ distro2 = self.api.new_distro()
+ self.assertTrue(distro2.set_name("testdistro0"))
+ self.assertTrue(distro2.set_kernel(self.fk_kernel))
+ self.assertTrue(distro2.set_initrd(self.fk_initrd))
+ self.assertTrue(distro2.set_owners("canary"))
+ # this should fail
+ try:
+ self.api.add_distro(distro2,check_for_duplicate_names=True)
+ self.assertTrue(1==2,"distro add should fail")
+ except CobblerException:
+ pass
+ except:
+ self.assertTrue(1==2,"exception type")
+ # we caught the exception but make doubly sure there was no write
+ distro_check = self.api.find_distro(name="testdistro0")
+ self.assertTrue("canary" not in distro_check.owners)
+
+ # repeat the check for profiles
+ profile2 = self.api.new_profile()
+ self.assertTrue(profile2.set_name("testprofile0"))
+ self.assertTrue(profile2.set_distro("testdistro0"))
+ # this should fail
+ try:
+ self.api.add_profile(profile2,check_for_duplicate_names=True)
+ self.assertTrue(1==2,"profile add should fail")
+ except CobblerException:
+ pass
+ except:
+ traceback.print_exc()
+ self.assertTrue(1==2,"exception type")
+
+ # repeat the check for systems (just names this time)
+ system2 = self.api.new_system()
+ self.assertTrue(system2.set_name("drwily.rdu.redhat.com"))
+ self.assertTrue(system2.set_profile("testprofile0"))
+ # this should fail
+ try:
+ self.api.add_system(system2,check_for_duplicate_names=True)
+ self.assertTrue(1==2,"system add should fail")
+ except CobblerException:
+ pass
+ except:
+ traceback.print_exc()
+ self.assertTrue(1==2,"exception type")
+
+ # repeat the check for repos
+ repo2 = self.api.new_repo()
+ self.assertTrue(repo2.set_name("test_repo"))
+ self.assertTrue(repo2.set_mirror("http://imaginary"))
+ # self.failUnlessRaises(CobblerException,self.api.add_repo,[repo,check_for_duplicate_names=True])
+ try:
+ self.api.add_repo(repo2,check_for_duplicate_names=True)
+ self.assertTrue(1==2,"repo add should fail")
+ except CobblerException:
+ pass
+ except:
+ self.assertTrue(1==2,"exception type")
+
+ # now one more check to verify we can't add a system
+ # of a different name but duplicate netinfo.
+ system3 = self.api.new_system()
+ self.assertTrue(system3.set_name("unused_name"))
+ self.assertTrue(system3.set_profile("testprofile0"))
+ # MAC is initially accepted
+ self.assertTrue(system3.set_mac_address("BB:EE:EE:EE:EE:FF","intf3"))
+ # can't add as this MAC already exists!
+
+ #self.failUnlessRaises(CobblerException,self.api.add_system,[system3,check_for_duplicate_names=True,check_for_duplicate_netinfo=True)
+ try:
+ self.api.add_system(system3,check_for_duplicate_names=True,check_for_duplicate_netinfo=True)
+ except CobblerException:
+ pass
+ except:
+ traceback.print_exc()
+ self.assertTrue(1==2,"wrong exception type")
+
+ # set the MAC to a different value and try again
+ self.assertTrue(system3.set_mac_address("FF:EE:EE:EE:EE:DD","intf3"))
+ # it should work
+ self.assertTrue(self.api.add_system(system3,check_for_duplicate_names=True,check_for_duplicate_netinfo=True))
+ # now set the IP so that collides
+ self.assertTrue(system3.set_ip_address("192.51.51.50","intf6"))
+ # this should also fail
+
+ # self.failUnlessRaises(CobblerException,self.api.add_system,[system3,check_for_duplicate_names=True,check_for_duplicate_netinfo=True)
+ try:
+ self.api.add_system(system3,check_for_duplicate_names=True,check_for_duplicate_netinfo=True)
+ self.assertTrue(1==2,"system add should fail")
+ except CobblerException:
+ pass
+ except:
+ self.assertTrue(1==2,"wrong exception type")
+
+ # fix the IP and Mac back
+ self.assertTrue(system3.set_ip_address("192.86.75.30","intf6"))
+ self.assertTrue(system3.set_mac_address("AE:BE:DE:CE:AE:EE","intf3"))
+ # now it works again
+ # note that we will not check for duplicate names as we want
+ # to test this as an 'edit' operation.
+ self.assertTrue(self.api.add_system(system3,check_for_duplicate_names=False,check_for_duplicate_netinfo=True))
+
+ # FIXME: note -- how netinfo is handled when doing renames/copies/edits
+ # is more involved and we probably should add tests for that also.
class Ownership(BootTest):
--
cgit
From 7fcd436b4581f849df3a4114f6df1a862d788404 Mon Sep 17 00:00:00 2001
From: root
Date: Fri, 4 Apr 2008 16:36:02 -0400
Subject: changelog edits
---
CHANGELOG | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 60e6369..04fc8b5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,8 @@ Cobbler CHANGELOG
- added authn_ldap and stub for authz_configfile
- authz_configfile allows filtering ldap/other users by config file
- WebUI now has checkbox on distro/profile for deleting child objects
+- cli has different semantics between "add" and "edit" now
+- cobbler wants to keep IPs/MACs unique now in configuration (can be disabled)
- ??? - 0.8.3
- fix WebUI documentation URL
--
cgit
From e387ae10607ec65fb2ca21292a3c889d5f1a2805 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 4 Apr 2008 16:38:08 -0400
Subject: add dnsmasq change to changelog
---
CHANGELOG | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG b/CHANGELOG
index 04fc8b5..64cfb2f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -18,6 +18,7 @@ Cobbler CHANGELOG
- fix bug in /etc/cobbler/modules.conf regarding pluggable authn/z
- fix default flags for yumdownloader
- fix for RHEL 4u6 DVD/tree import x86_64 arch detection
+- fix for dnsmasq template file host config path
* Fri Feb 22 2008 - 0.8.2
- fix to webui to allow repos to be edited there on profile page
--
cgit
From b7e606d6fe4c431c8fb95e96ac6b4c5e101f202d Mon Sep 17 00:00:00 2001
From: root
Date: Fri, 4 Apr 2008 16:40:25 -0400
Subject: Remove check from this area of the command line.
---
cobbler/modules/cli_system.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 01f2ba6..b173b4b 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -105,10 +105,6 @@ class SystemFunction(commands.CobblerFunction):
rc = self.object_manipulator_finish(obj, self.api.systems, self.options)
- if ["copy"] in self.args:
- # run through and find conflicts
- print _("WARNING: after copying systems, be sure that the ip/mac information is unique").
-
return rc
--
cgit
From 9337f9411092bcd3da4005fa29557f875fbf68e8 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 4 Apr 2008 17:12:32 -0400
Subject: Get duplicate name/ip/mac checks implemented for WebUI and XMLRPC now
that command line/local-API is done.
---
cobbler/remote.py | 31 +++++++++++++++++++++++--------
cobbler/webui/CobblerWeb.py | 10 +++++-----
webui_templates/distro_edit.tmpl | 2 ++
webui_templates/profile_edit.tmpl | 2 ++
webui_templates/repo_edit.tmpl | 2 ++
webui_templates/system_edit.tmpl | 2 ++
6 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index ed3cc53..d9f937b 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -810,41 +810,56 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
found = self.api.repos().find(name)
return self.__store_object(found)
- def save_distro(self,object_id,token):
+ def save_distro(self,object_id,token,editmode="bypass"):
"""
Saves a newly created or modified distro object to disk.
"""
self.log("save_distro",object_id=object_id,token=token)
obj = self.__get_object(object_id)
self.check_access(token,"save_distro",obj)
- return self.api.distros().add(obj,save=True)
+ if editmode == "new":
+ return self.api.distros().add(obj,save=True,check_for_duplicate_names=True)
+ else:
+ return self.api.distros().add(obj,save=True)
- def save_profile(self,object_id,token):
+ def save_profile(self,object_id,token,editmode="bypass"):
"""
Saves a newly created or modified profile object to disk.
"""
self.log("save_profile",token=token,object_id=object_id)
obj = self.__get_object(object_id)
self.check_access(token,"save_profile",obj)
- return self.api.profiles().add(obj,save=True)
+ if editmode == "new":
+ return self.api.profiles().add(obj,save=True,check_for_duplicate_names=True)
+ else:
+ return self.api.profiles().add(obj,save=True)
- def save_system(self,object_id,token):
+ def save_system(self,object_id,token,editmode="bypass"):
"""
Saves a newly created or modified system object to disk.
"""
self.log("save_system",token=token,object_id=object_id)
obj = self.__get_object(object_id)
self.check_access(token,"save_system",obj)
- return self.api.systems().add(obj,save=True)
+ if editmode == "new":
+ return self.api.systems().add(obj,save=True,check_for_duplicate_names=True,check_for_duplicate_netinfo=True)
+ elif editmode == "edit":
+ return self.api.systems().add(obj,save=True,check_for_duplicate_netinfo=True)
+ else:
+ return self.api.systems().add(obj,save=True)
+
- def save_repo(self,object_id,token=None):
+ def save_repo(self,object_id,token=None,editmode="bypass"):
"""
Saves a newly created or modified repo object to disk.
"""
self.log("save_repo",object_id=object_id,token=token)
obj = self.__get_object(object_id)
self.check_access(token,"save_repo",obj)
- return self.api.repos().add(obj,save=True)
+ if editmode == "new":
+ return self.api.repos().add(obj,save=True,check_for_duplicate_names=True)
+ else:
+ return self.api.repos().add(obj,save=True)
def copy_distro(self,object_id,newname,token=None):
"""
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index 727e4cb..628d776 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -243,7 +243,8 @@ class CobblerWeb(object):
self.remote.modify_distro(distro, 'arch', arch, self.token)
if breed:
self.remote.modify_distro(distro, 'breed', breed, self.token)
- self.remote.save_distro(distro, self.token)
+ # now time to save, do we want to run duplication checks?
+ self.remote.save_distro(distro, self.token, editmode)
except Exception, e:
log_exc(self.apache)
return self.error_page("Error while saving distro: %s" % str(e))
@@ -385,8 +386,7 @@ class CobblerWeb(object):
mods["gateway-%s" % interface] = gateway
self.remote.modify_system(system,'modify-interface', mods, self.token)
- # now commit the edits
- self.remote.save_system( system, self.token)
+ self.remote.save_system(system, self.token, editmode)
except Exception, e:
log_exc(self.apache)
@@ -572,7 +572,7 @@ class CobblerWeb(object):
if dhcptag:
self.remote.modify_profile(profile, 'dhcp-tag', dhcptag, self.token)
- self.remote.save_profile(profile,self.token)
+ self.remote.save_profile(profile,self.token, editmode)
except Exception, e:
log_exc(self.apache)
return self.error_page("Error while saving profile: %s" % str(e))
@@ -687,7 +687,7 @@ class CobblerWeb(object):
if owners:
self.remote.modify_repo(repo, 'owners', owners, self.token)
- self.remote.save_repo(repo, self.token)
+ self.remote.save_repo(repo, self.token, editmode)
except Exception, e:
log_exc(self.apache)
diff --git a/webui_templates/distro_edit.tmpl b/webui_templates/distro_edit.tmpl
index 5d19a43..f72ab11 100644
--- a/webui_templates/distro_edit.tmpl
+++ b/webui_templates/distro_edit.tmpl
@@ -66,6 +66,8 @@ function disablename(value)
How do you want to modify this object?
+ #else
+
#end if
diff --git a/webui_templates/profile_edit.tmpl b/webui_templates/profile_edit.tmpl
index 2f7a732..0c8f156 100644
--- a/webui_templates/profile_edit.tmpl
+++ b/webui_templates/profile_edit.tmpl
@@ -80,6 +80,8 @@ function disablename(value)
How do you want to modify this object?
+ #else
+
#end if
#if $subprofile
diff --git a/webui_templates/repo_edit.tmpl b/webui_templates/repo_edit.tmpl
index 469854a..30d516d 100644
--- a/webui_templates/repo_edit.tmpl
+++ b/webui_templates/repo_edit.tmpl
@@ -62,6 +62,8 @@ function disablename(value)
How do you want to modify this object?
+ #else
+
#end if
diff --git a/webui_templates/system_edit.tmpl b/webui_templates/system_edit.tmpl
index 5396f1d..684c6d1 100644
--- a/webui_templates/system_edit.tmpl
+++ b/webui_templates/system_edit.tmpl
@@ -138,6 +138,8 @@ function page_onload() {
How do you want to modify this object?
+ #else
+
#end if
--
cgit
From 2d14d31b9aa6b34eaacfad650b99f132c3a103ad Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 4 Apr 2008 17:24:37 -0400
Subject: remove FIXMEs as things have been tested and work WRT the duplication
prevention feature.
---
cobbler/collection.py | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/cobbler/collection.py b/cobbler/collection.py
index 14bba57..e63c3ca 100644
--- a/cobbler/collection.py
+++ b/cobbler/collection.py
@@ -230,9 +230,7 @@ class Collection(serializable.Serializable):
"""
Prevents adding objects with the same name.
Prevents adding or editing to provide the same IP, or MAC.
- This applies to new "add" commands,
- Edits that are not copies/renames should only yelp if they match
- an object that is not the same as the object being edited. (FIXME)
+ Enforcement is based on whether the API caller requests it.
"""
# always protect against duplicate names
@@ -254,11 +252,6 @@ class Collection(serializable.Serializable):
if not check_for_duplicate_netinfo:
return
- # FIXME: if we run this command on edits it may yield false
- # positives when ref is set to replace an object of an existing
- # name, so we should probably /not/ run this on edits yet at this
- # point. Logic to deal with renames vs. edit/copies is somewhat
- # involved.
if isinstance(ref, item_system.System):
for (name, intf) in ref.interfaces.iteritems():
match_ip = []
@@ -270,9 +263,6 @@ class Collection(serializable.Serializable):
if not self.api.settings().allow_duplicate_ips and input_ip is not None and input_ip != "":
match_ip = self.api.find_system(ip_address=input_ip,return_list=True)
# it's ok to conflict with your own net info.
- # FIXME: copies won't ever work this way, so they should NOT
- # use the flags that engadge these checks. Renames should
- # be exempt also
for x in match_mac:
if x.name != ref.name:
--
cgit
From f3a7e9f8a2b85fb936d98aa118bec5189b26140f Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 4 Apr 2008 17:45:32 -0400
Subject: Added a "--clobber" option to all add commands that allows the add to
function in an "add or edit" mode. Before in Cobbler, add and edit were
largely aliases so this was not needed -- now it is. Using --clobber the
object will be created if it does not exist, or it will overwrite the
existing one (as "edit" does) when it is there. If --clobber is left off,
add will refuse to overwrite an existing object. This is a minor break to
scripts that are calling cobbler directly but not those to API users --
scripts /should/ be checking return codes.
---
CHANGELOG | 3 ++-
cobbler/commands.py | 14 ++++++++++++--
cobbler/modules/cli_distro.py | 4 ++++
cobbler/modules/cli_profile.py | 5 +++++
cobbler/modules/cli_repo.py | 4 ++++
cobbler/modules/cli_system.py | 3 +++
6 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 64cfb2f..54bfac6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,8 +10,9 @@ Cobbler CHANGELOG
- added authn_ldap and stub for authz_configfile
- authz_configfile allows filtering ldap/other users by config file
- WebUI now has checkbox on distro/profile for deleting child objects
-- cli has different semantics between "add" and "edit" now
+- cli has different semantics between "add" and "edit" now for safety reasons
- cobbler wants to keep IPs/MACs unique now in configuration (can be disabled)
+- added --clobber option to allow add to overwrite existing objects (for scripts)
- ??? - 0.8.3
- fix WebUI documentation URL
diff --git a/cobbler/commands.py b/cobbler/commands.py
index 6bb0419..2dc627b 100644
--- a/cobbler/commands.py
+++ b/cobbler/commands.py
@@ -241,6 +241,10 @@ class CobblerFunction:
Boilerplate for objects that offer add/edit/delete/remove/copy functionality.
"""
+ clobber = False
+ if "add" in self.args:
+ clobber = options.clobber
+
if "copy" in self.args: # or "rename" in self.args:
if self.options.newname:
obj = obj.make_clone()
@@ -267,10 +271,16 @@ class CobblerFunction:
if "add" in self.args:
if obj.COLLECTION_TYPE == "system":
# duplicate names and netinfo are both bad.
- rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=True, check_for_duplicate_netinfo=True)
+ if not clobber:
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=True, check_for_duplicate_netinfo=True)
+ else:
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=False, check_for_duplicate_netinfo=True)
else:
# duplicate names are bad
- rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=True, check_for_duplicate_netinfo=False)
+ if not clobber:
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=True, check_for_duplicate_netinfo=False)
+ else:
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=False, check_for_duplicate_netinfo=False)
else:
# editing or copying (but not renaming), so duplicate netinfo
# CAN be bad, duplicate names are already handled, though
diff --git a/cobbler/modules/cli_distro.py b/cobbler/modules/cli_distro.py
index 9e0637f..8c7b70f 100644
--- a/cobbler/modules/cli_distro.py
+++ b/cobbler/modules/cli_distro.py
@@ -40,6 +40,9 @@ class DistroFunction(commands.CobblerFunction):
if not self.matches_args(args,["remove","report","list"]):
p.add_option("--arch", dest="arch", help="ex: x86, x86_64, ia64")
p.add_option("--breed", dest="breed", help="ex: redhat, debian, suse")
+ if self.matches_args(args,["add"]):
+ p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
+ if not self.matches_args(args,["remove","report","list"]):
p.add_option("--initrd", dest="initrd", help="absolute path to initrd.img (REQUIRED)")
p.add_option("--kernel", dest="kernel", help="absolute path to vmlinuz (REQUIRED)")
p.add_option("--kopts", dest="kopts", help="ex: 'noipv6'")
@@ -48,6 +51,7 @@ class DistroFunction(commands.CobblerFunction):
p.add_option("--name", dest="name", help="ex: 'RHEL-5-i386' (REQUIRED)")
+
if self.matches_args(args,["copy","rename"]):
p.add_option("--newname", dest="newname", help="for copy/rename commands")
if not self.matches_args(args,["remove","report","list"]):
diff --git a/cobbler/modules/cli_profile.py b/cobbler/modules/cli_profile.py
index 9912607..0bf4b8c 100644
--- a/cobbler/modules/cli_profile.py
+++ b/cobbler/modules/cli_profile.py
@@ -36,6 +36,11 @@ class ProfileFunction(commands.CobblerFunction):
return [ "add", "edit", "copy", "rename", "remove", "list", "report" ]
def add_options(self, p, args):
+
+ if self.matches_args(args,["add"]):
+ p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
+
+
if not self.matches_args(args,["remove","report","list"]):
p.add_option("--distro", dest="distro", help="ex: 'RHEL-5-i386' (REQUIRED)")
diff --git a/cobbler/modules/cli_repo.py b/cobbler/modules/cli_repo.py
index 88e45dd..e8ec04a 100644
--- a/cobbler/modules/cli_repo.py
+++ b/cobbler/modules/cli_repo.py
@@ -37,9 +37,13 @@ class RepoFunction(commands.CobblerFunction):
def add_options(self, p, args):
+
if not self.matches_args(args,["remove","report","list"]):
p.add_option("--arch", dest="arch", help="overrides repo arch if required")
+ if self.matches_args(args,["add"]):
+ p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
+ if not self.matches_args(args,["remove","report","list"]):
p.add_option("--createrepo-flags", dest="createrepo_flags", help="additional flags for createrepo")
p.add_option("--keep-updated", dest="keep_updated", help="update on each reposync, yes/no")
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index b173b4b..34c8886 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -37,6 +37,9 @@ class SystemFunction(commands.CobblerFunction):
def add_options(self, p, args):
+ if self.matches_args(args,["add"]):
+ p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
+
if not self.matches_args(args,["remove","report","list"]):
p.add_option("--dhcp-tag", dest="dhcp_tag", help="for use in advanced DHCP configurations")
p.add_option("--gateway", dest="gateway", help="for static IP / templating usage")
--
cgit
From cdca9443cab19f992e76a205533be0d13c091d47 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 8 Apr 2008 13:11:09 -0400
Subject: Merge.
---
CHANGELOG | 9 +--------
cobbler.spec | 6 +-----
2 files changed, 2 insertions(+), 13 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 3f8cf5a..2bd50fa 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,12 +1,7 @@
Cobbler CHANGELOG
(all entries mdehaan@redhat.com unless noted otherwise)
-<<<<<<< HEAD:CHANGELOG
- Mon Mar 10 2008 - 0.9.0
-=======
-* Tue Apr 08 2008 - 0.8.3
->>>>>>> master:CHANGELOG
-- Make createrepo get run for local cobbler reposync invocations as needed
- patch to allow yumopts to override gpgcheck
- applied patch to send hostname from ISC
- added patch to allow --kopts/--ksmeta items to be cleared with --kopts=delete
@@ -19,16 +14,14 @@ Cobbler CHANGELOG
- added --clobber option to allow add to overwrite existing objects (for scripts)
- ??? - 0.8.3
+- Make createrepo get run for local cobbler reposync invocations as needed
- fix WebUI documentation URL
- fix bug in /etc/cobbler/modules.conf regarding pluggable authn/z
- fix default flags for yumdownloader
- fix for RHEL 4u6 DVD/tree import x86_64 arch detection
-<<<<<<< HEAD:CHANGELOG
- fix for dnsmasq template file host config path
-=======
- fix dnsmasq template to point at the correct hosts file
- force all names to be alphanumeric
->>>>>>> master:CHANGELOG
* Fri Feb 22 2008 - 0.8.2
- fix to webui to allow repos to be edited there on profile page
diff --git a/cobbler.spec b/cobbler.spec
index b4e04bd..9e64040 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -191,15 +191,11 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
-<<<<<<< HEAD:cobbler.spec
-* Wed Mar 26 2008 Michael DeHaan - 0.9.0-1
+* Tue Apr 08 2008 Michael DeHaan - 0.9.0-1
- Upstream changes (see CHANGELOG)
- packaged /etc/cobbler/users.conf
-* Mon Mar 10 2008 Michael DeHaan - 0.8.3-1
-=======
* Tue Apr 08 2008 Michael DeHaan - 0.8.3-1
->>>>>>> master:cobbler.spec
- Upstream changes (see CHANGELOG)
* Fri Mar 07 2008 Michael DeHaan - 0.8.2-1
--
cgit
From 52c1048879ddf3a6ea87fe32ba99ba8f76a6e20e Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 8 Apr 2008 16:20:43 -0400
Subject: fix changelog
---
CHANGELOG | 1 +
scripts/cobbler_auth_help | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG b/CHANGELOG
index 2bd50fa..75e3425 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,7 @@ Cobbler CHANGELOG
- cli has different semantics between "add" and "edit" now for safety reasons
- cobbler wants to keep IPs/MACs unique now in configuration (can be disabled)
- added --clobber option to allow add to overwrite existing objects (for scripts)
+- updated/tested kerberos support for those needing to auth against it
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/scripts/cobbler_auth_help b/scripts/cobbler_auth_help
index 198e95b..c43cd5b 100644
--- a/scripts/cobbler_auth_help
+++ b/scripts/cobbler_auth_help
@@ -43,7 +43,7 @@ my $kerberos = Authen::Simple::Kerberos->new(
realm => $realm
);
-print "authenticating: $username against $method $realm ($password)\n" if $verbose;
+print "authenticating: $username against (realm=$realm) (pass=$password)\n" if $verbose;
if ( $kerberos->authenticate( $username, $password ) ) {
print "ok\n" if $verbose;
--
cgit
From 68469d9c744b17d4bd291718dd4d03ff02b64db7 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 8 Apr 2008 16:21:25 -0400
Subject: Allow underscores.
---
cobbler/item.py | 2 +-
cobbler/item_system.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cobbler/item.py b/cobbler/item.py
index 454b704..249a50c 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -116,7 +116,7 @@ class Item(serializable.Serializable):
if type(name) != type(""):
raise CX(_("name must be a string"))
for x in name:
- if not x.isalnum() and not x in [ "-", ".", ":", "+" ] :
+ if not x.isalnum() and not x in [ "_", "-", ".", ":", "+" ] :
raise CX(_("invalid characters in name"))
self.name = name
return True
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index dd7bd64..975a6d2 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -156,7 +156,7 @@ class System(item.Item):
if type(name) != type(""):
raise CX(_("name must be a string"))
for x in name:
- if not x.isalnum() and not x in [ "-", ".", ":", "+" ] :
+ if not x.isalnum() and not x in [ "_", "-", ".", ":", "+" ] :
raise CX(_("invalid characters in name"))
if utils.is_mac(name):
--
cgit
From c4a6d241faa677b9dbe9572addcd1148a72ffaba Mon Sep 17 00:00:00 2001
From: root
Date: Tue, 8 Apr 2008 16:24:06 -0400
Subject: merge
---
cobbler.spec | 4 ----
cobbler/webui/master.py | 4 ++--
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/cobbler.spec b/cobbler.spec
index 070bff3..ca6640f 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -191,15 +191,11 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
-<<<<<<< HEAD:cobbler.spec
* Tue Apr 08 2008 Michael DeHaan - 0.9.0-1
- Upstream changes (see CHANGELOG)
- packaged /etc/cobbler/users.conf
-* Tue Apr 08 2008 Michael DeHaan - 0.8.3-1
-=======
* Tue Apr 08 2008 Michael DeHaan - 0.8.3-2
->>>>>>> master:cobbler.spec
- Upstream changes (see CHANGELOG)
* Fri Mar 07 2008 Michael DeHaan - 0.8.2-1
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 0a6e9dd..8f7de66 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -33,8 +33,8 @@ VFN=valueForName
currentTime=time.time
__CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1207681739.292002
-__CHEETAH_genTimestamp__ = 'Tue Apr 8 15:08:59 2008'
+__CHEETAH_genTime__ = 1207686192.9310019
+__CHEETAH_genTimestamp__ = 'Tue Apr 8 16:23:12 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
__CHEETAH_srcLastModified__ = 'Fri Feb 15 14:47:43 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
--
cgit
From eeb2cc4214f3047536e9cd4a5b814581a84f286a Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 8 Apr 2008 17:59:21 -0400
Subject: Update menu.c32 so timeouts work in the PXE menus
---
loaders/menu.c32 | Bin 26496 -> 51788 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/loaders/menu.c32 b/loaders/menu.c32
index 7912a08..a3d8628 100644
Binary files a/loaders/menu.c32 and b/loaders/menu.c32 differ
--
cgit
From 421abb9ba9d45037cc4fce41408d0f5dfd3cf62e Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 8 Apr 2008 18:24:42 -0400
Subject: update templates to invoke menu.c32 automatically w/ timeout,
skipping the step of having to type "menu" at the PXE prompt, which is
occasionally a source of user confusion. We can now also do submenus if we
want to, now that menu.c32 is updated.
---
CHANGELOG | 2 ++
templates/pxedefault.template | 8 ++++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 75e3425..6c0cf96 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,6 +13,8 @@ Cobbler CHANGELOG
- cobbler wants to keep IPs/MACs unique now in configuration (can be disabled)
- added --clobber option to allow add to overwrite existing objects (for scripts)
- updated/tested kerberos support for those needing to auth against it
+- update menu.c32 to 3.62 to allow for timeouts during menu (and future submenu)
+- update PXE defaults to invoke menu.c32 automatically w/ timeout
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/templates/pxedefault.template b/templates/pxedefault.template
index d731892..d95d7cc 100644
--- a/templates/pxedefault.template
+++ b/templates/pxedefault.template
@@ -1,5 +1,5 @@
-DEFAULT local
-PROMPT 1
+DEFAULT menu
+PROMPT 0
MENU TITLE Cobbler | http://cobbler.et.redhat.com
TIMEOUT 200
TOTALTIMEOUT 6000
@@ -10,4 +10,8 @@ LABEL local
MENU DEFAULT
LOCALBOOT 0
+MENU seperator
+
$pxe_menu_items
+
+MENU end
--
cgit
From a5575530aee5642bfb0d99af5088d0519845b0f4 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 9 Apr 2008 11:46:29 -0400
Subject: Apply iranzo's memtest patch
---
cobbler/action_sync.py | 53 +++++++++++++++++++++++++++++++++++++++++--
templates/pxedefault.template | 2 --
2 files changed, 51 insertions(+), 4 deletions(-)
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 8a0eadf..5cb0977 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -109,6 +109,11 @@ class BootSync:
self.copyfile(path, destpath)
self.copyfile("/var/lib/cobbler/menu.c32", os.path.join(self.bootloc, "menu.c32"))
+ # Copy memtest to tftpboot if package is installed on system
+ for memtest in glob.glob('/boot/memtest*'):
+ base = os.path.basename(memtest)
+ self.copyfile(memtest,os.path.join(self.bootloc,"images",base))
+
def write_dhcp_file(self):
"""
DHCP files are written when manage_dhcp is set in
@@ -818,13 +823,57 @@ class BootSync:
contents = self.write_pxe_file(None,None,profile,distro,False,include_header=False)
if contents is not None:
pxe_menu_items = pxe_menu_items + contents + "\n"
-
- # save the template.
+
+ # if we have any memtest files in images, make entries for them
+ # after we list the profiles
+ memtests = glob.glob(self.bootloc + "/images/memtest*")
+ if len(memtests) > 0:
+ pxe_menu_items = pxe_menu_items + "\n\n"
+ for memtest in glob.glob(self.bootloc + '/memtest*'):
+ base = os.path.basename(memtest)
+ contents = self.write_memtest_pxe("/images/%s" % base)
+ pxe_menu_items = pxe_menu_items + contents + "\n"
+
+ # save the template.
metadata = { "pxe_menu_items" : pxe_menu_items }
outfile = os.path.join(self.bootloc, "pxelinux.cfg", "default")
self.apply_template(template_data, metadata, outfile)
template_src.close()
+ def write_memtest_pxe(self,filename):
+ """
+ Write a configuration file for memtest
+ """
+
+ # ---
+ # just some random variables
+ template = None
+ metadata = {}
+ buffer = ""
+
+ # ---
+ template = "/etc/cobbler/pxeprofile.template"
+
+ # ---
+ # store variables for templating
+ metadata["menu_label"] = "MENU LABEL %s" % os.path.basename(filename)
+ metadata["profile_name"] = os.path.basename(filename)
+ metadata["kernel_path"] = "/images/%s" % os.path.basename(filename)
+ metadata["initrd_path"] = ""
+ metadata["append_line"] = ""
+
+ # ---
+ # get the template
+ template_fh = open(template)
+ template_data = template_fh.read()
+ template_fh.close()
+
+ # ---
+ # return results
+ buffer = self.apply_template(template_data, metadata, None)
+ return buffer
+
+
def write_pxe_file(self,filename,system,profile,distro,is_ia64, include_header=True):
"""
diff --git a/templates/pxedefault.template b/templates/pxedefault.template
index d95d7cc..bb09893 100644
--- a/templates/pxedefault.template
+++ b/templates/pxedefault.template
@@ -10,8 +10,6 @@ LABEL local
MENU DEFAULT
LOCALBOOT 0
-MENU seperator
-
$pxe_menu_items
MENU end
--
cgit
From 4e33bffad605c41ebae28142eaf5203b4465f809 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 9 Apr 2008 16:42:57 -0400
Subject: Two things -- (A) remove rhpl dep as we aren't using it and we want
to use more standard xlat for other distros potentially, (B) fix the kerb
module some more.
---
cobbler.spec | 1 -
cobbler/action_check.py | 2 +-
cobbler/action_import.py | 2 +-
cobbler/action_litesync.py | 2 +-
cobbler/action_reposync.py | 2 +-
cobbler/action_status.py | 2 +-
cobbler/action_sync.py | 2 +-
cobbler/action_validate.py | 2 +-
cobbler/api.py | 2 +-
cobbler/cobbler.py | 3 +--
cobbler/cobblerd.py | 2 +-
cobbler/collection.py | 2 +-
cobbler/collection_distros.py | 2 +-
cobbler/collection_profiles.py | 2 +-
cobbler/collection_repos.py | 2 +-
cobbler/collection_systems.py | 2 +-
cobbler/commands.py | 2 +-
cobbler/config.py | 2 +-
cobbler/item.py | 2 +-
cobbler/item_distro.py | 2 +-
cobbler/item_profile.py | 2 +-
cobbler/item_repo.py | 2 +-
cobbler/item_system.py | 2 +-
cobbler/module_loader.py | 2 +-
cobbler/modules/authn_configfile.py | 2 +-
cobbler/modules/authn_kerberos.py | 4 ++--
cobbler/modules/authn_ldap.py | 2 +-
cobbler/modules/authz_allowall.py | 2 +-
cobbler/modules/authz_configfile.py | 2 +-
cobbler/modules/authz_ownership.py | 2 +-
cobbler/modules/cli_distro.py | 2 +-
cobbler/modules/cli_misc.py | 2 +-
cobbler/modules/cli_profile.py | 2 +-
cobbler/modules/cli_repo.py | 2 +-
cobbler/modules/cli_system.py | 2 +-
cobbler/modules/serializer_shelve.py | 2 +-
cobbler/modules/serializer_yaml.py | 2 +-
cobbler/remote.py | 2 +-
cobbler/serializable.py | 2 +-
cobbler/serializer.py | 2 +-
cobbler/settings.py | 2 +-
cobbler/utils.py | 6 +++++-
cobbler/webui/master.py | 38 +++++++++++++-----------------------
tests/tests.py | 18 ++++++++---------
44 files changed, 69 insertions(+), 77 deletions(-)
diff --git a/cobbler.spec b/cobbler.spec
index ca6640f..2b6c88d 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -14,7 +14,6 @@ Requires: python-devel
Requires: createrepo
Requires: mod_python
Requires: python-cheetah
-Requires: rhpl
Requires: rsync
Requires(post): /sbin/chkconfig
Requires(preun): /sbin/chkconfig
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 1fb4734..85084d7 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -18,7 +18,7 @@ import re
import sub_process
import action_sync
import utils
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class BootCheck:
diff --git a/cobbler/action_import.py b/cobbler/action_import.py
index db09818..d224e55 100644
--- a/cobbler/action_import.py
+++ b/cobbler/action_import.py
@@ -23,7 +23,7 @@ import glob
import api
import utils
import shutil
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
WGET_CMD = "wget --mirror --no-parent --no-host-directories --directory-prefix %s/%s %s"
RSYNC_CMD = "rsync -a %s '%s' %s/ks_mirror/%s --exclude-from=/etc/cobbler/rsync.exclude --progress"
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index 9200a3e..a73e7c3 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -30,7 +30,7 @@ from cexceptions import *
import traceback
import errno
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class BootLiteSync:
diff --git a/cobbler/action_reposync.py b/cobbler/action_reposync.py
index c86e0be..d6b97a0 100644
--- a/cobbler/action_reposync.py
+++ b/cobbler/action_reposync.py
@@ -25,7 +25,7 @@ from cexceptions import *
import traceback
import errno
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class RepoSync:
"""
diff --git a/cobbler/action_status.py b/cobbler/action_status.py
index cc6ebd4..7366060 100644
--- a/cobbler/action_status.py
+++ b/cobbler/action_status.py
@@ -19,7 +19,7 @@ import glob
import time
import api as cobbler_api
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class BootStatusReport:
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 5cb0977..5c8aab9 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -35,7 +35,7 @@ import item_system
from Cheetah.Template import Template
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class BootSync:
diff --git a/cobbler/action_validate.py b/cobbler/action_validate.py
index f898478..8ede60c 100644
--- a/cobbler/action_validate.py
+++ b/cobbler/action_validate.py
@@ -15,7 +15,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import os
import re
import sub_process
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Validate:
diff --git a/cobbler/api.py b/cobbler/api.py
index 54c315b..0eacb78 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -29,7 +29,7 @@ import module_loader
import logging
import os
import fcntl
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
ERROR = 100
INFO = 10
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index c02302e..c164244 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -23,7 +23,7 @@ import optparse
import commands
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
I18N_DOMAIN = "cobbler"
####################################################
@@ -31,7 +31,6 @@ I18N_DOMAIN = "cobbler"
class BootCLI:
def __init__(self):
- textdomain(I18N_DOMAIN)
self.api = api.BootAPI()
self.loader = commands.FunctionLoader()
climods = self.api.get_modules_in_category("cli")
diff --git a/cobbler/cobblerd.py b/cobbler/cobblerd.py
index 5640aec..8859e03 100644
--- a/cobbler/cobblerd.py
+++ b/cobbler/cobblerd.py
@@ -16,7 +16,7 @@ import time
import os
import SimpleXMLRPCServer
import glob
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import xmlrpclib
from server import xmlrpclib2
diff --git a/cobbler/collection.py b/cobbler/collection.py
index e63c3ca..1b509f2 100644
--- a/cobbler/collection.py
+++ b/cobbler/collection.py
@@ -25,7 +25,7 @@ import item_profile
import item_distro
import item_repo
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Collection(serializable.Serializable):
diff --git a/cobbler/collection_distros.py b/cobbler/collection_distros.py
index f78dd64..5857b9a 100644
--- a/cobbler/collection_distros.py
+++ b/cobbler/collection_distros.py
@@ -18,7 +18,7 @@ import collection
import item_distro as distro
from cexceptions import *
import action_litesync
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Distros(collection.Collection):
diff --git a/cobbler/collection_profiles.py b/cobbler/collection_profiles.py
index f00a8dc..139c94e 100644
--- a/cobbler/collection_profiles.py
+++ b/cobbler/collection_profiles.py
@@ -20,7 +20,7 @@ import utils
import collection
from cexceptions import *
import action_litesync
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
#--------------------------------------------
diff --git a/cobbler/collection_repos.py b/cobbler/collection_repos.py
index 44bef2a..91e0667 100644
--- a/cobbler/collection_repos.py
+++ b/cobbler/collection_repos.py
@@ -18,7 +18,7 @@ import item_repo as repo
import utils
import collection
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
TESTMODE = False
diff --git a/cobbler/collection_systems.py b/cobbler/collection_systems.py
index 140a981..8a967be 100644
--- a/cobbler/collection_systems.py
+++ b/cobbler/collection_systems.py
@@ -18,7 +18,7 @@ import utils
import collection
from cexceptions import *
import action_litesync
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
#--------------------------------------------
diff --git a/cobbler/commands.py b/cobbler/commands.py
index 2dc627b..7a6a25b 100644
--- a/cobbler/commands.py
+++ b/cobbler/commands.py
@@ -14,7 +14,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import optparse
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import sys
HELP_FORMAT = "%-20s%s"
diff --git a/cobbler/config.py b/cobbler/config.py
index 258b241..4a1b9a4 100644
--- a/cobbler/config.py
+++ b/cobbler/config.py
@@ -29,7 +29,7 @@ import modules.serializer_yaml as serializer_yaml
import settings
import serializer
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Config:
diff --git a/cobbler/item.py b/cobbler/item.py
index 249a50c..2549dce 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -16,7 +16,7 @@ import exceptions
import serializable
import utils
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Item(serializable.Serializable):
diff --git a/cobbler/item_distro.py b/cobbler/item_distro.py
index 98eaae7..1e392a5 100644
--- a/cobbler/item_distro.py
+++ b/cobbler/item_distro.py
@@ -20,7 +20,7 @@ import weakref
import os
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Distro(item.Item):
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index 2e3a539..a352ce1 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -16,7 +16,7 @@ import utils
import item
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Profile(item.Item):
diff --git a/cobbler/item_repo.py b/cobbler/item_repo.py
index 1ebea30..f9e9714 100644
--- a/cobbler/item_repo.py
+++ b/cobbler/item_repo.py
@@ -15,7 +15,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import utils
import item
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class Repo(item.Item):
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 975a6d2..73eda71 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -15,7 +15,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import utils
import item
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
class System(item.Item):
diff --git a/cobbler/module_loader.py b/cobbler/module_loader.py
index b695a04..d584ce3 100644
--- a/cobbler/module_loader.py
+++ b/cobbler/module_loader.py
@@ -19,7 +19,7 @@ import distutils.sysconfig
import os
import sys
import glob
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import ConfigParser
MODULE_CACHE = {}
diff --git a/cobbler/modules/authn_configfile.py b/cobbler/modules/authn_configfile.py
index ffe87a7..be453be 100644
--- a/cobbler/modules/authn_configfile.py
+++ b/cobbler/modules/authn_configfile.py
@@ -17,7 +17,7 @@ import distutils.sysconfig
import ConfigParser
import sys
import os
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import md5
import traceback
diff --git a/cobbler/modules/authn_kerberos.py b/cobbler/modules/authn_kerberos.py
index 7f85db6..46c01ad 100644
--- a/cobbler/modules/authn_kerberos.py
+++ b/cobbler/modules/authn_kerberos.py
@@ -30,7 +30,7 @@ import distutils.sysconfig
import ConfigParser
import sys
import os
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import md5
import traceback
# since sub_process isn't available on older OS's
@@ -58,7 +58,7 @@ def authenticate(api_handle,username,password):
Uses cobbler_auth_helper
"""
- realm = self.api.settings().kerberos_realm
+ realm = api_handle.settings().kerberos_realm
api_handle.logger.debug("authenticating %s against %s" % (username,realm))
rc = subprocess.call([
diff --git a/cobbler/modules/authn_ldap.py b/cobbler/modules/authn_ldap.py
index cec913b..eef4b2a 100644
--- a/cobbler/modules/authn_ldap.py
+++ b/cobbler/modules/authn_ldap.py
@@ -14,7 +14,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import distutils.sysconfig
import sys
import os
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import md5
import traceback
import ldap
diff --git a/cobbler/modules/authz_allowall.py b/cobbler/modules/authz_allowall.py
index 1b05630..10d4b17 100644
--- a/cobbler/modules/authz_allowall.py
+++ b/cobbler/modules/authz_allowall.py
@@ -16,7 +16,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import distutils.sysconfig
import ConfigParser
import sys
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
diff --git a/cobbler/modules/authz_configfile.py b/cobbler/modules/authz_configfile.py
index c183721..84343e2 100644
--- a/cobbler/modules/authz_configfile.py
+++ b/cobbler/modules/authz_configfile.py
@@ -16,7 +16,7 @@ import distutils.sysconfig
import ConfigParser
import sys
import os
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
diff --git a/cobbler/modules/authz_ownership.py b/cobbler/modules/authz_ownership.py
index 1fe25a9..fbd00f9 100644
--- a/cobbler/modules/authz_ownership.py
+++ b/cobbler/modules/authz_ownership.py
@@ -19,7 +19,7 @@ import distutils.sysconfig
import ConfigParser
import sys
import os
-from rhpl.translate import _, N_, textdomain, utf8
+from cobbler.utils import _
plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
diff --git a/cobbler/modules/cli_distro.py b/cobbler/modules/cli_distro.py
index 8c7b70f..4d86448 100644
--- a/cobbler/modules/cli_distro.py
+++ b/cobbler/modules/cli_distro.py
@@ -19,7 +19,7 @@ plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import commands
import cexceptions
diff --git a/cobbler/modules/cli_misc.py b/cobbler/modules/cli_misc.py
index ebbba47..0fd44a6 100644
--- a/cobbler/modules/cli_misc.py
+++ b/cobbler/modules/cli_misc.py
@@ -19,7 +19,7 @@ plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import commands
from cexceptions import *
HELP_FORMAT = commands.HELP_FORMAT
diff --git a/cobbler/modules/cli_profile.py b/cobbler/modules/cli_profile.py
index 0bf4b8c..b543b80 100644
--- a/cobbler/modules/cli_profile.py
+++ b/cobbler/modules/cli_profile.py
@@ -19,7 +19,7 @@ plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import commands
import cexceptions
diff --git a/cobbler/modules/cli_repo.py b/cobbler/modules/cli_repo.py
index e8ec04a..a567d2d 100644
--- a/cobbler/modules/cli_repo.py
+++ b/cobbler/modules/cli_repo.py
@@ -19,7 +19,7 @@ plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import commands
import cexceptions
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 34c8886..976c380 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -19,7 +19,7 @@ plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import commands
import cexceptions
diff --git a/cobbler/modules/serializer_shelve.py b/cobbler/modules/serializer_shelve.py
index 246a92a..09495dd 100644
--- a/cobbler/modules/serializer_shelve.py
+++ b/cobbler/modules/serializer_shelve.py
@@ -24,7 +24,7 @@ import os
import sys
import glob
import traceback
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import os
import shelve
import time
diff --git a/cobbler/modules/serializer_yaml.py b/cobbler/modules/serializer_yaml.py
index 6425bd1..724265d 100644
--- a/cobbler/modules/serializer_yaml.py
+++ b/cobbler/modules/serializer_yaml.py
@@ -21,7 +21,7 @@ plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import utils
import yaml # Howell-Clark version
import cexceptions
diff --git a/cobbler/remote.py b/cobbler/remote.py
index d9f937b..f7e2226 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -18,7 +18,7 @@ import socket
import time
import os
import SimpleXMLRPCServer
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import xmlrpclib
import random
import base64
diff --git a/cobbler/serializable.py b/cobbler/serializable.py
index ba8f015..ad9e64e 100644
--- a/cobbler/serializable.py
+++ b/cobbler/serializable.py
@@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import exceptions
class Serializable:
diff --git a/cobbler/serializer.py b/cobbler/serializer.py
index ae9f18c..25d0d60 100644
--- a/cobbler/serializer.py
+++ b/cobbler/serializer.py
@@ -15,7 +15,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import errno
import os
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
import fcntl
from cexceptions import *
diff --git a/cobbler/settings.py b/cobbler/settings.py
index c201ddd..bc16835 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -14,7 +14,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import serializable
import utils
-from rhpl.translate import _, N_, textdomain, utf8
+from utils import _
TESTMODE = False
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 4d2b635..8757762 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -22,7 +22,11 @@ import shutil
import string
import traceback
from cexceptions import *
-from rhpl.translate import _, N_, textdomain, utf8
+
+#placeholder for translation
+def _(foo):
+ return foo
+
MODULE_CACHE = {}
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 8f7de66..3e0c2fb 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -31,12 +31,12 @@ VFFSL=valueFromFrameOrSearchList
VFSL=valueFromSearchList
VFN=valueForName
currentTime=time.time
-__CHEETAH_version__ = '2.0.1'
-__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1207686192.9310019
-__CHEETAH_genTimestamp__ = 'Tue Apr 8 16:23:12 2008'
+__CHEETAH_version__ = '2.0rc7'
+__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 7)
+__CHEETAH_genTime__ = 1207768044.4095509
+__CHEETAH_genTimestamp__ = 'Wed Apr 9 21:07:24 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
-__CHEETAH_srcLastModified__ = 'Fri Feb 15 14:47:43 2008'
+__CHEETAH_srcLastModified__ = 'Wed Apr 9 21:03:21 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
@@ -158,20 +158,16 @@ class master(Template):
diff --git a/tests/tests.py b/tests/tests.py
index 4060eef..8536a70 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -813,15 +813,15 @@ class TestListings(BootTest):
self.assertTrue(len(self.api.profiles().printable()) > 0)
self.assertTrue(len(self.api.distros().printable()) > 0)
-class TestCLIBasic(BootTest):
-
- def test_cli(self):
- # just invoke the CLI to increase coverage and ensure
- # nothing major is broke at top level. Full CLI command testing
- # is not included (yet) since the API tests hit that fairly throughly
- # and it would easily double the length of the tests.
- app = "/usr/bin/python"
- self.assertTrue(subprocess.call([app,"cobbler/cobbler.py","list"]) == 0)
+#class TestCLIBasic(BootTest):
+#
+# def test_cli(self):
+# # just invoke the CLI to increase coverage and ensure
+# # nothing major is broke at top level. Full CLI command testing
+# # is not included (yet) since the API tests hit that fairly throughly
+# # and it would easily double the length of the tests.
+# app = "/usr/bin/python"
+# self.assertTrue(subprocess.call([app,"cobbler/cobbler.py","list"]) == 0)
if __name__ == "__main__":
if not os.path.exists("setup.py"):
--
cgit
From 82c540e75dfe750b2877f7177a87b4e91d5e5b1e Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 9 Apr 2008 16:44:24 -0400
Subject: Add Ronald to AUTHORS
---
AUTHORS | 1 +
1 file changed, 1 insertion(+)
diff --git a/AUTHORS b/AUTHORS
index 3e4dcef..5d2c797 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -28,6 +28,7 @@ Patches and other contributions from:
Christophe Sahut
Scott Seago
Al Tobey
+ Ronald van den Blink
Tim Verhoeven
[...send patches to get your name here...]
--
cgit
From 249ccbea4d2615a7623ac91149dda863eefec093 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 9 Apr 2008 17:00:44 -0400
Subject: update changelog
---
CHANGELOG | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG b/CHANGELOG
index 6c0cf96..dee7f3c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@ Cobbler CHANGELOG
- updated/tested kerberos support for those needing to auth against it
- update menu.c32 to 3.62 to allow for timeouts during menu (and future submenu)
- update PXE defaults to invoke menu.c32 automatically w/ timeout
+- removed dependency on rhpl
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
--
cgit
From 5da91f89c12b998a4e83db4d21ec6086aca37feb Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 11 Apr 2008 12:17:42 -0400
Subject: Import now takes an --arch, which is now a recommended field, to
ensure best practices in naming.
---
CHANGELOG | 1 +
cobbler/action_check.py | 22 ++++++++++--------
cobbler/action_import.py | 23 ++++++++++++++++++-
cobbler/api.py | 4 ++--
cobbler/modules/cli_misc.py | 8 ++++---
cobbler/utils.py | 56 +++++++++++++++++++++++++++++----------------
config/cobblerd | 19 +++++++++++----
docs/cobbler.pod | 12 ++++++----
website/new/download.html | 25 ++++++++------------
9 files changed, 110 insertions(+), 60 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index dee7f3c..80aa334 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -16,6 +16,7 @@ Cobbler CHANGELOG
- update menu.c32 to 3.62 to allow for timeouts during menu (and future submenu)
- update PXE defaults to invoke menu.c32 automatically w/ timeout
- removed dependency on rhpl
+- import can now take an --arch (and is recommended usage)
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 85084d7..e91396f 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -19,7 +19,6 @@ import sub_process
import action_sync
import utils
from utils import _
-
class BootCheck:
def __init__(self,config):
@@ -61,10 +60,18 @@ class BootCheck:
return status
def check_service(self, status, which):
- if os.path.exists("/etc/rc.d/init.d/%s" % which):
- rc = sub_process.call("/sbin/service %s status >/dev/null 2>/dev/null" % which, shell=True)
- if rc != 0:
- status.append(_("service %s is not running") % which)
+ if utils.check_dist() == "redhat":
+ if os.path.exists("/etc/rc.d/init.d/%s" % which):
+ rc = sub_process.call("/sbin/service %s status >/dev/null 2>/dev/null" % which, shell=True)
+ if rc != 0:
+ status.append(_("service %s is not running") % which)
+ elif utils.check_dist() == "debian":
+ if os.path.exists("/etc/init.d/%s" % which):
+ rc = sub_process.call("/etc/init.d/%s status /dev/null 2>/dev/null" % which, shell=True)
+ if rc != 0:
+ status.append(_("service %s is not running") % which)
+ else:
+ status.append(_("Unknown distribution type, cannot check for running service %s" % which))
def check_iptables(self, status):
if os.path.exists("/etc/rc.d/init.d/iptables"):
@@ -95,10 +102,7 @@ class BootCheck:
"""
Check if Apache is installed.
"""
- if not os.path.exists(self.settings.httpd_bin):
- status.append(_("Apache doesn't appear to be installed"))
- else:
- self.check_service(status,"httpd")
+ self.check_service(status,"httpd")
def check_dhcpd_bin(self,status):
diff --git a/cobbler/action_import.py b/cobbler/action_import.py
index d224e55..7f5409b 100644
--- a/cobbler/action_import.py
+++ b/cobbler/action_import.py
@@ -36,7 +36,7 @@ TRY_LIST = [
class Importer:
- def __init__(self,api,config,mirror,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None):
+ def __init__(self,api,config,mirror,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None):
"""
Performs an import of a install tree (or trees) from the given
mirror address. The prefix of the distro is to be specified
@@ -59,6 +59,7 @@ class Importer:
self.distros_added = []
self.kickstart_file = kickstart_file
self.rsync_flags = rsync_flags
+ self.arch = arch
# ----------------------------------------------------------------------
@@ -67,6 +68,26 @@ class Importer:
raise CX(_("import failed. no --mirror specified"))
if self.mirror_name is None:
raise CX(_("import failed. no --name specified"))
+ if self.arch is not None:
+ self.arch = self.arch.lower()
+ if self.arch not in [ "x86", "ia64", "x86_64" ]:
+ raise CX(_("arch must be x86, x86_64, or ia64"))
+
+ mpath = os.path.join(self.settings.webdir, "ks_mirror", self.mirror_name)
+ if os.path.exists(mpath) and self.arch is None:
+ if not found:
+ raise CX(_("Something already exists at this import location (%s). You must specify --arch to avoid potentially overwriting existing files.") % mpath)
+
+ if self.arch:
+ # append the arch path to the name if the arch is not already
+ # found in the name.
+ found = False
+ for x in [ "ia64", "i386", "x86_64", "x86" ]:
+ if self.mirror_name.lower().find(x) != -1:
+ found = True
+ break
+ if not found:
+ self.mirror_name = self.mirror_name + "-" + self.arch
if self.mirror_name is None:
raise CX(_("import failed. no --name specified"))
diff --git a/cobbler/api.py b/cobbler/api.py
index 0eacb78..ef6fa8e 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -336,7 +336,7 @@ class BootAPI:
statusifier = action_status.BootStatusReport(self._config, mode)
return statusifier.run()
- def import_tree(self,mirror_url,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None):
+ def import_tree(self,mirror_url,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None):
"""
Automatically import a directory tree full of distribution files.
mirror_url can be a string that represents a path, a user@host
@@ -346,7 +346,7 @@ class BootAPI:
"""
self.log("import_tree",[mirror_url, mirror_name, network_root, kickstart_file, rsync_flags])
importer = action_import.Importer(
- self, self._config, mirror_url, mirror_name, network_root, kickstart_file, rsync_flags
+ self, self._config, mirror_url, mirror_name, network_root, kickstart_file, rsync_flags, arch
)
return importer.run()
diff --git a/cobbler/modules/cli_misc.py b/cobbler/modules/cli_misc.py
index 0fd44a6..f8b0a7d 100644
--- a/cobbler/modules/cli_misc.py
+++ b/cobbler/modules/cli_misc.py
@@ -73,11 +73,12 @@ class ImportFunction(commands.CobblerFunction):
return "import"
def add_options(self, p, args):
+ p.add_option("--arch", dest="arch", help="explicitly specify the architecture being imported (RECOMENDED)")
p.add_option("--path", dest="mirror", help="local path or rsync location (REQUIRED)")
p.add_option("--mirror", dest="mirror_alt", help="alias for --path")
p.add_option("--name", dest="name", help="name, ex 'RHEL-5', (REQUIRED)")
- p.add_option("--available-as", dest="available_as", help="do not mirror, use this as install tree")
- p.add_option("--kickstart", dest="kickstart_file", help="use the kickstart file specified as the profile's kickstart file")
+ p.add_option("--available-as", dest="available_as", help="do not mirror, use this as install tree base")
+ p.add_option("--kickstart", dest="kickstart_file", help="use the kickstart file specified as the profile's kickstart file, do not auto-assign")
p.add_option("--rsync-flags", dest="rsync_flags", help="pass additional flags to rsync")
def run(self):
@@ -92,7 +93,8 @@ class ImportFunction(commands.CobblerFunction):
self.options.name,
network_root=self.options.available_as,
kickstart_file=self.options.kickstart_file,
- rsync_flags=self.options.rsync_flags
+ rsync_flags=self.options.rsync_flags,
+ arch=self.options.arch
)
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 8757762..d8cf6fc 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -487,28 +487,44 @@ def fix_mod_python_select_submission(repos):
repos = repos.replace('"',"")
repos = repos.lstrip().rstrip()
return repos
+def check_dist():
+ if os.path.exists("/etc/debian_version"):
+ return "debian"
+ else:
+ return "redhat"
def redhat_release():
- if not os.path.exists("/bin/rpm"):
- return ("unknown", 0)
- args = ["/bin/rpm", "-q", "--whatprovides", "redhat-release"]
- cmd = sub_process.Popen(args,shell=False,stdout=sub_process.PIPE)
- data = cmd.communicate()[0]
- data = data.rstrip().lower()
- make = "other"
- if data.find("redhat") != -1:
- make = "redhat"
- elif data.find("centos") != -1:
- make = "centos"
- elif data.find("fedora") != -1:
- make = "fedora"
- version = data.split("release-")[-1]
- rest = 0
- if version.find("-"):
- parts = version.split("-")
- version = parts[0]
- rest = parts[1]
- return (make, float(version), rest)
+ if check_dist() == "redhat":
+
+ if not os.path.exists("/bin/rpm"):
+ return ("unknown", 0)
+ args = ["/bin/rpm", "-q", "--whatprovides", "redhat-release"]
+ cmd = sub_process.Popen(args,shell=False,stdout=sub_process.PIPE)
+ data = cmd.communicate()[0]
+ data = data.rstrip().lower()
+ make = "other"
+ if data.find("redhat") != -1:
+ make = "redhat"
+ elif data.find("centos") != -1:
+ make = "centos"
+ elif data.find("fedora") != -1:
+ make = "fedora"
+ version = data.split("release-")[-1]
+ rest = 0
+ if version.find("-"):
+ parts = version.split("-")
+ version = parts[0]
+ rest = parts[1]
+ return (make, float(version), rest)
+ elif check_dist() == "debian":
+ fd = open("/etc/debian_version")
+ parts = fd.read().split(".")
+ version = parts[0]
+ rest = parts[1]
+ make = "debian"
+ return (make, float(version), rest)
+ else:
+ return ("unknown",0)
def tftpboot_location():
diff --git a/config/cobblerd b/config/cobblerd
index 6b52956..7d6d571 100755
--- a/config/cobblerd
+++ b/config/cobblerd
@@ -25,12 +25,23 @@
# Sanity checks.
[ -x /usr/bin/cobblerd ] || exit 0
+DEBIAN_VERSION=/etc/debian_version
# Source function library.
-. /etc/rc.d/init.d/functions
+if [ -e $DEBIAN_VERSION ]; then
+
+ . /etc/init.d/functions
+else
+ . /etc/rc.d/init.d/functions
+fi
SERVICE=cobblerd
PROCESS=cobblerd
CONFIG_ARGS=" "
+if [ -e $DEBIAN_VERSION ]; then
+ LOCKFILE=/var/lock/$SERVICE
+else
+ LOCKFILE=/var/lock/subsys/$SERVICE
+fi
RETVAL=0
@@ -39,7 +50,7 @@ start() {
daemon --check $SERVICE $PROCESS --daemon $CONFIG_ARGS
RETVAL=$?
echo
- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE
+ [ $RETVAL -eq 0 ] && touch $LOCKFILE
return $RETVAL
}
@@ -49,7 +60,7 @@ stop() {
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
- rm -f /var/lock/subsys/$SERVICE
+ rm -f $LOCKFILE
rm -f /var/run/$SERVICE.pid
fi
}
@@ -69,7 +80,7 @@ case "$1" in
RETVAL=$?
;;
condrestart)
- [ -f /var/lock/subsys/$SERVICE ] && restart || :
+ [ -f $LOCKFILE ] && restart || :
;;
reload)
echo "can't reload configuration, you have to restart it"
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index 719850d..d7a4550 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -410,20 +410,22 @@ run after systems are added to regenerate and reload the DHCP configuration.
=head2 IMPORT WORKFLOW
-This example shows how to create a provisioning infrastructure from a distribution mirror.
+This example shows how to create a provisioning infrastructure from a distribution mirror or DVD ISO.
Then a default PXE configuration is created, so that by default systems will PXE boot into
a fully automated install process for that distribution.
You can use a network rsync mirror, a mounted DVD location, or a tree you have available
via a network filesystem.
+Import knows how to autodetect the architecture of what is being imported, though to make sure things are named correctly, it's always a good idea to specify --arch. For instance, if you import a distribution named "fedora8" from an ISO, and it's an x86_64 ISO, specify --arch=x86_64 and the distro will be named "fedora8-x86_64" automatically, and the right architecture field will also be set on the distribution object. If you are batch importing an entire mirror (containing multiple distributions and arches), you don't have to do this, as cobbler will set the names for things based on the paths it finds.
+
B
-B
+B
# OR
-B
+B
# OR (using an eternal NAS box without mirroring)
@@ -576,11 +578,11 @@ After an import is run, cobbler will try to detect the distribution type and aut
Mirrored content is saved automatically in /var/www/cobbler/ks_mirror.
-Example: B
+Example: B
Example2: B
-Example3: B
+Example3: B
Example4: B
diff --git a/website/new/download.html b/website/new/download.html
index 821d684..977fb1b 100644
--- a/website/new/download.html
+++ b/website/new/download.html
@@ -48,31 +48,24 @@ The lastest stable releases of Cobbler and Koan are included in
rpmbuild --rebuild those RPMs and then install them
-
now rebuild --rebuild and install Cobbler from it's source RPM
+
Grab python-setuputils and python-cheetah from EPEL and install them. These are found in the main EPEL repo, not EPEL testing -- here's the link: i386 and x86_64.
+
now rpmbuild --rebuild cobbler*.src.rpm
+
install the RPM, which is now built in /usr/src/redhat/RPMS/noarch
+
satisfy any dependencies you have by using yum and the EPEL 5 repos
--
cgit
From 650fcae97e686108592cff603ad6e95c5dc43c7d Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 11 Apr 2008 15:50:09 -0400
Subject: Now possible to override snippets on a per-profile or per-system
basis, as discussed on the mailing list for usage for doing disk/package
config, etc
---
CHANGELOG | 1 +
cobbler/action_litesync.py | 20 ++--
cobbler/action_sync.py | 259 ++++++++-------------------------------------
cobbler/templar.py | 189 +++++++++++++++++++++++++++++++++
cobbler/utils.py | 75 +++++++++++--
5 files changed, 312 insertions(+), 232 deletions(-)
create mode 100644 cobbler/templar.py
diff --git a/CHANGELOG b/CHANGELOG
index 80aa334..b6d6d14 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -17,6 +17,7 @@ Cobbler CHANGELOG
- update PXE defaults to invoke menu.c32 automatically w/ timeout
- removed dependency on rhpl
- import can now take an --arch (and is recommended usage)
+- now possible to override snippets on a profile/system specific basis
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index a73e7c3..bc7ffb2 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -68,13 +68,13 @@ class BootLiteSync:
def remove_single_distro(self, name):
bootloc = utils.tftpboot_location()
# delete distro YAML file in distros/$name in webdir
- self.sync.rmfile(os.path.join(self.settings.webdir, "distros", name))
+ utils.rmfile(os.path.join(self.settings.webdir, "distros", name))
# delete contents of images/$name directory in webdir
- self.sync.rmtree(os.path.join(self.settings.webdir, "images", name))
+ utils.rmtree(os.path.join(self.settings.webdir, "images", name))
# delete contents of images/$name in tftpboot
- self.sync.rmtree(os.path.join(bootloc, "images", name))
+ utils.rmtree(os.path.join(bootloc, "images", name))
# delete potential symlink to tree in webdir/links
- self.sync.rmfile(os.path.join(self.settings.webdir, "links", name))
+ utils.rmfile(os.path.join(self.settings.webdir, "links", name))
def add_single_profile(self, name):
# get the profile object:
@@ -101,9 +101,9 @@ class BootLiteSync:
# rebuild profile_list YAML file in webdir
self.sync.write_listings()
# delete profiles/$name file in webdir
- self.sync.rmfile(os.path.join(self.settings.webdir, "profiles", name))
+ utils.rmfile(os.path.join(self.settings.webdir, "profiles", name))
# delete contents on kickstarts/$name directory in webdir
- self.sync.rmtree(os.path.join(self.settings.webdir, "kickstarts", name))
+ utils.rmtree(os.path.join(self.settings.webdir, "kickstarts", name))
def update_system_netboot_status(self,name):
system = self.systems.find(name=name)
@@ -133,13 +133,13 @@ class BootLiteSync:
# rebuild system_list file in webdir
self.sync.write_listings()
# delete system YAML file in systems/$name in webdir
- self.sync.rmfile(os.path.join(self.settings.webdir, "systems", name))
+ utils.rmfile(os.path.join(self.settings.webdir, "systems", name))
# delete contents of kickstarts_sys/$name in webdir
system_record = self.systems.find(name=name)
# delete any kickstart files related to this system
for (name,interface) in system_record.interfaces.iteritems():
filename = utils.get_config_filename(system_record,interface=name)
- self.sync.rmtree(os.path.join(self.settings.webdir, "kickstarts_sys", filename))
+ utils.rmtree(os.path.join(self.settings.webdir, "kickstarts_sys", filename))
# unneeded
#if not system_record.is_pxe_supported():
@@ -154,7 +154,7 @@ class BootLiteSync:
if distro is not None and distro in [ "ia64", "IA64"]:
itanic = True
if not itanic:
- self.sync.rmfile(os.path.join(bootloc, "pxelinux.cfg", filename))
+ utils.rmfile(os.path.join(bootloc, "pxelinux.cfg", filename))
else:
- self.sync.rmfile(os.path.join(bootloc, filename))
+ utils.rmfile(os.path.join(bootloc, filename))
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 5c8aab9..1e65e42 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -1,10 +1,9 @@
"""
-Builds out a TFTP/cobbler boot tree based on the object tree.
+Builds out filesystem trees/data based on the object tree.
This is the code behind 'cobbler sync'.
-Copyright 2006,2007, Red Hat, Inc
+Copyright 2006-2008, Red Hat, Inc
Michael DeHaan
-Tim Verhoeven
This software may be freely redistributed under the terms of the GNU
general public license.
@@ -22,11 +21,13 @@ import yaml # Howell-Clark version
import sub_process
import sys
import glob
+import traceback
+import errno
import utils
from cexceptions import *
-import traceback
-import errno
+import templar
+
import item_distro
import item_profile
@@ -55,8 +56,7 @@ class BootSync:
self.systems = config.systems()
self.settings = config.settings()
self.repos = config.repos()
- self.blend_cache = {}
- self.load_snippet_cache()
+ self.templar = templar.Templar(config)
self.bootloc = utils.tftpboot_location()
def run(self):
@@ -106,13 +106,13 @@ class BootSync:
path = self.settings.bootloaders[loader]
newname = os.path.basename(path)
destpath = os.path.join(self.bootloc, newname)
- self.copyfile(path, destpath)
- self.copyfile("/var/lib/cobbler/menu.c32", os.path.join(self.bootloc, "menu.c32"))
+ utils.copyfile(path, destpath)
+ utils.copyfile("/var/lib/cobbler/menu.c32", os.path.join(self.bootloc, "menu.c32"))
# Copy memtest to tftpboot if package is installed on system
for memtest in glob.glob('/boot/memtest*'):
base = os.path.basename(memtest)
- self.copyfile(memtest,os.path.join(self.bootloc,"images",base))
+ utils.copyfile(memtest,os.path.join(self.bootloc,"images",base))
def write_dhcp_file(self):
"""
@@ -221,7 +221,7 @@ class BootSync:
continue
metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
- self.apply_template(template_data, metadata, settings_file)
+ self.templar.render(template_data, metadata, settings_file, None)
def regen_ethers(self):
# dnsmasq knows how to read this database of MACs -> IPs, so we'll keep it up to date
@@ -276,16 +276,16 @@ class BootSync:
path = os.path.join(self.settings.webdir,x)
if os.path.isfile(path):
if not x.endswith(".py"):
- self.rmfile(path)
+ utils.rmfile(path)
if os.path.isdir(path):
if not x in ["web", "webui", "localmirror","repo_mirror","ks_mirror","kickstarts","kickstarts_sys","distros","images","systems","profiles","links","repo_profile","repo_system"] :
# delete directories that shouldn't exist
- self.rmtree(path)
+ utils.rmtree(path)
if x in ["kickstarts","kickstarts_sys","images","systems","distros","profiles","repo_profile","repo_system"]:
# clean out directory contents
- self.rmtree_contents(path)
- self.rmtree_contents(os.path.join(self.bootloc, "pxelinux.cfg"))
- self.rmtree_contents(os.path.join(self.bootloc, "images"))
+ utils.rmtree_contents(path)
+ utils.rmtree_contents(os.path.join(self.bootloc, "pxelinux.cfg"))
+ utils.rmtree_contents(os.path.join(self.bootloc, "images"))
def copy_distros(self):
"""
@@ -306,7 +306,7 @@ class BootSync:
for dirtree in [self.bootloc, self.settings.webdir]:
distros = os.path.join(dirtree, "images")
distro_dir = os.path.join(distros,d.name)
- self.mkdir(distro_dir)
+ utils.mkdir(distro_dir)
kernel = utils.find_kernel(d.kernel) # full path
initrd = utils.find_initrd(d.initrd) # full path
if kernel is None or not os.path.isfile(kernel):
@@ -316,13 +316,13 @@ class BootSync:
b_kernel = os.path.basename(kernel)
b_initrd = os.path.basename(initrd)
if kernel.startswith(dirtree):
- self.linkfile(kernel, os.path.join(distro_dir, b_kernel))
+ utils.linkfile(kernel, os.path.join(distro_dir, b_kernel))
else:
- self.copyfile(kernel, os.path.join(distro_dir, b_kernel))
+ utils.copyfile(kernel, os.path.join(distro_dir, b_kernel))
if initrd.startswith(dirtree):
- self.linkfile(initrd, os.path.join(distro_dir, b_initrd))
+ utils.linkfile(initrd, os.path.join(distro_dir, b_initrd))
else:
- self.copyfile(initrd, os.path.join(distro_dir, b_initrd))
+ utils.copyfile(initrd, os.path.join(distro_dir, b_initrd))
def validate_kickstarts(self):
"""
@@ -356,7 +356,7 @@ class BootSync:
def validate_kickstart_for_specific_profile(self,g):
distro = g.get_conceptual_parent()
- meta = utils.blender(self.api, False, g, self.blend_cache)
+ meta = utils.blender(self.api, False, g)
if distro is None:
raise CX(_("profile %(profile)s references missing distro %(distro)s") % { "profile" : g.name, "distro" : g.distro })
kickstart_path = utils.find_kickstart(meta["kickstart"])
@@ -367,10 +367,10 @@ class BootSync:
"kickstarts", # profile kickstarts go here
g.name
)
- self.mkdir(copy_path)
+ utils.mkdir(copy_path)
dest = os.path.join(copy_path, "ks.cfg")
try:
- meta = utils.blender(self.api, False, g, self.blend_cache)
+ meta = utils.blender(self.api, False, g)
ksmeta = meta["ks_meta"]
del meta["ks_meta"]
meta.update(ksmeta) # make available at top level
@@ -379,7 +379,7 @@ class BootSync:
meta["kickstart_done"] = self.generate_kickstart_signal(g, None)
meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
kfile = open(kickstart_path)
- self.apply_template(kfile, meta, dest)
+ self.templar.render(kfile, meta, dest, g)
kfile.close()
except:
traceback.print_exc() # leave this in, for now...
@@ -404,7 +404,7 @@ class BootSync:
if system:
blend_this = system
- blended = utils.blender(self.api, False, blend_this, self.blend_cache)
+ blended = utils.blender(self.api, False, blend_this)
kickstart = blended.get("kickstart",None)
buf = ""
@@ -436,7 +436,7 @@ class BootSync:
"""
buf = ""
- blended = utils.blender(self.api, False, obj, self.blend_cache)
+ blended = utils.blender(self.api, False, obj)
configs = self.get_repo_filenames(obj,is_profile)
repos = self.repos
@@ -479,7 +479,7 @@ class BootSync:
baseurls
"""
- blended = utils.blender(self.api, False, obj, self.blend_cache)
+ blended = utils.blender(self.api, False, obj)
urlseg = self.get_repo_segname(is_profile)
topdir = "%s/%s/%s/*.repo" % (self.settings.webdir, urlseg, blended["name"])
@@ -503,7 +503,7 @@ class BootSync:
if not is_profile:
distro = distro.get_conceptual_parent()
- blended = utils.blender(self.api, False, obj, self.blend_cache)
+ blended = utils.blender(self.api, False, obj)
configs = self.get_repo_filenames(obj, is_profile)
buf = ""
@@ -545,14 +545,14 @@ class BootSync:
if profile is None:
raise CX(_("system %(system)s references missing profile %(profile)s") % { "system" : s.name, "profile" : s.profile })
distro = profile.get_conceptual_parent()
- meta = utils.blender(self.api, False, s, self.blend_cache)
+ meta = utils.blender(self.api, False, s)
kickstart_path = utils.find_kickstart(meta["kickstart"])
if kickstart_path and os.path.exists(kickstart_path):
copy_path = os.path.join(self.settings.webdir,
"kickstarts_sys", # system kickstarts go here
s.name
)
- self.mkdir(copy_path)
+ utils.mkdir(copy_path)
dest = os.path.join(copy_path, "ks.cfg")
try:
ksmeta = meta["ks_meta"]
@@ -563,107 +563,12 @@ class BootSync:
meta["kickstart_done"] = self.generate_kickstart_signal(profile, s)
meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
kfile = open(kickstart_path)
- self.apply_template(kfile, meta, dest)
+ self.templar.render(kfile, meta, dest, s)
kfile.close()
except:
traceback.print_exc()
raise CX(_("Error templating file %(src)s to %(dest)s") % { "src" : meta["kickstart"], "dest" : dest })
- def load_snippet_cache(self):
-
- # first load all of the files in /var/lib/cobbler/snippets and load them, for use
- # in adding long bits to kickstart templates without having to have them hard coded
- # inside the sync code.
-
- snippet_cache = {}
- snippets = glob.glob("%s/*" % self.settings.snippetsdir)
- for snip in snippets:
- if os.path.isdir(snip):
- continue
- snip_file = open(snip)
- data = snip_file.read()
- snip_file.close()
- snippet_cache[os.path.basename(snip)] = data
- self.snippet_cache = snippet_cache
-
-
- def apply_template(self, data_input, metadata, out_path):
- """
- Take filesystem file kickstart_input, apply metadata using
- Cheetah and save as out_path.
- """
-
- if type(data_input) != str:
- data = data_input.read()
- else:
- data = data_input
-
- # backward support for Cobbler's legacy (and slightly more readable)
- # template syntax.
- data = data.replace("TEMPLATE::","$")
-
- # replace contents of the data stream with items from the snippet cache
- # do not use Cheetah yet, Cheetah can't really be run twice on the same
- # stream and be expected to do the right thing
- newdata = ""
- for line in data.split("\n"):
- for x in self.snippet_cache:
- if not line.startswith("#"):
- line = line.replace("SNIPPET::%s" % x, self.snippet_cache[x])
- newdata = "\n".join((newdata, line))
- data = newdata
-
- # HACK: the ksmeta field may contain nfs://server:/mount in which
- # case this is likely WRONG for kickstart, which needs the NFS
- # directive instead. Do this to make the templates work.
- newdata = ""
- if metadata.has_key("tree") and metadata["tree"].startswith("nfs://"):
- for line in data.split("\n"):
- if line.find("--url") != -1 and line.find("url ") != -1:
- rest = metadata["tree"][6:] # strip off "nfs://" part
- try:
- (server, dir) = rest.split(":",2)
- except:
- raise CX(_("Invalid syntax for NFS path given during import: %s" % metadata["tree"]))
- line = "nfs --server %s --dir %s" % (server,dir)
- # but put the URL part back in so koan can still see
- # what the original value was
- line = line + "\n" + "#url --url=%s" % metadata["tree"]
- newdata = newdata + line + "\n"
- data = newdata
-
- # tell Cheetah not to blow up if it can't find a symbol for something
- data = "#errorCatcher Echo\n" + data
-
- # now do full templating scan, where we will also templatify the snippet insertions
- t = Template(source=data, searchList=[metadata])
- try:
- data_out = str(t)
- except:
- print _("There appears to be an formatting error in the template file.")
- print _("For completeness, the traceback from Cheetah has been included below.")
- raise
-
- # now apply some magic post-filtering that is used by cobbler import and some
- # other places, but doesn't use Cheetah. Forcing folks to double escape
- # things would be very unwelcome.
-
- for x in metadata:
- if type(metadata[x]) == str:
- data_out = data_out.replace("@@%s@@" % x, metadata[x])
-
- # remove leading newlines which apparently breaks AutoYAST ?
- if data_out.startswith("\n"):
- data_out = data_out.strip()
-
- if out_path is not None:
- self.mkdir(os.path.dirname(out_path))
- fd = open(out_path, "w+")
- fd.write(data_out)
- fd.close()
-
- return data_out
-
def build_trees(self):
"""
Now that kernels and initrds are copied and kickstarts are all valid,
@@ -703,7 +608,7 @@ class BootSync:
and also potentially in listed in the source_repos structure of the distro object, however
these files have server URLs in them that must be templated out. This function does this.
"""
- blended = utils.blender(self.api, False, obj, self.blend_cache)
+ blended = utils.blender(self.api, False, obj)
if is_profile:
outseg = "repos_profile"
@@ -735,7 +640,7 @@ class BootSync:
dispname = infile.split("/")[-1].replace(".repo","")
confdir = os.path.join(self.settings.webdir, outseg)
outdir = os.path.join(confdir, blended["name"])
- self.mkdir(outdir)
+ utils.mkdir(outdir)
try:
infile_h = open(infile)
except:
@@ -744,7 +649,7 @@ class BootSync:
infile_data = infile_h.read()
infile_h.close()
outfile = os.path.join(outdir, "%s.repo" % (dispname))
- self.apply_template(infile_data, blended, outfile)
+ self.templar.render(infile_data, blended, outfile, None)
def write_all_system_files(self,system,just_edit_pxe=False):
@@ -788,7 +693,7 @@ class BootSync:
self.write_pxe_file(f2,system,profile,distro,True)
else:
# ensure the file doesn't exist
- self.rmfile(f2)
+ utils.rmfile(f2)
if not just_edit_pxe:
# allows netboot-disable to be highly performant
@@ -834,10 +739,10 @@ class BootSync:
contents = self.write_memtest_pxe("/images/%s" % base)
pxe_menu_items = pxe_menu_items + contents + "\n"
- # save the template.
+ # save the template.
metadata = { "pxe_menu_items" : pxe_menu_items }
outfile = os.path.join(self.bootloc, "pxelinux.cfg", "default")
- self.apply_template(template_data, metadata, outfile)
+ self.templar.render(template_data, metadata, outfile, None)
template_src.close()
def write_memtest_pxe(self,filename):
@@ -845,16 +750,13 @@ class BootSync:
Write a configuration file for memtest
"""
- # ---
# just some random variables
template = None
metadata = {}
buffer = ""
- # ---
template = "/etc/cobbler/pxeprofile.template"
- # ---
# store variables for templating
metadata["menu_label"] = "MENU LABEL %s" % os.path.basename(filename)
metadata["profile_name"] = os.path.basename(filename)
@@ -862,15 +764,13 @@ class BootSync:
metadata["initrd_path"] = ""
metadata["append_line"] = ""
- # ---
# get the template
template_fh = open(template)
template_data = template_fh.read()
template_fh.close()
- # ---
# return results
- buffer = self.apply_template(template_data, metadata, None)
+ buffer = self.templar.render(template_data, metadata, None)
return buffer
@@ -902,7 +802,7 @@ class BootSync:
initrd_path = os.path.join("/images",distro.name,os.path.basename(distro.initrd))
# Find the kickstart if we inherit from another profile
- kickstart_path = utils.blender(self.api, True, profile, self.blend_cache)["kickstart"]
+ kickstart_path = utils.blender(self.api, True, profile)["kickstart"]
# ---
# choose a template
@@ -915,12 +815,11 @@ class BootSync:
# now build the kernel command line
if system is not None:
- blended = utils.blender(self.api, True,system,self.blend_cache)
+ blended = utils.blender(self.api, True, system)
else:
- blended = utils.blender(self.api, True,profile,self.blend_cache)
+ blended = utils.blender(self.api, True,profile)
kopts = blended["kernel_options"]
- # ---
# generate the append line
append_line = "append %s" % utils.hash_to_string(kopts)
if not is_ia64:
@@ -928,7 +827,6 @@ class BootSync:
if len(append_line) >= 255 + len("append "):
print _("warning: kernel option length exceeds 255")
- # ---
# kickstart path rewriting (get URLs for local files)
if kickstart_path is not None and kickstart_path != "":
@@ -945,7 +843,6 @@ class BootSync:
append_line = "%s auto=true url=%s" % (append_line, kickstart_path)
append_line = append_line.replace("ksdevice","interface")
- # ---
# store variables for templating
metadata["menu_label"] = ""
if not is_ia64 and system is None:
@@ -955,15 +852,13 @@ class BootSync:
metadata["initrd_path"] = initrd_path
metadata["append_line"] = append_line
- # ---
# get the template
template_fh = open(template)
template_data = template_fh.read()
template_fh.close()
- # ---
# save file and/or return results, depending on how called.
- buffer = self.apply_template(template_data, metadata, None)
+ buffer = self.templar.render(template_data, metadata, None)
if filename is not None:
fd = open(filename, "w")
fd.write(buffer)
@@ -991,7 +886,7 @@ class BootSync:
"""
Create distro information for koan install
"""
- blended = utils.blender(self.api, True, distro, self.blend_cache)
+ blended = utils.blender(self.api, True, distro)
filename = os.path.join(self.settings.webdir,"distros",distro.name)
fd = open(filename, "w+")
fd.write(yaml.dump(blended))
@@ -1004,7 +899,7 @@ class BootSync:
NOTE: relevant to http only
"""
- blended = utils.blender(self.api, True, profile, self.blend_cache)
+ blended = utils.blender(self.api, True, profile)
filename = os.path.join(self.settings.webdir,"profiles",profile.name)
fd = open(filename, "w+")
if blended.has_key("kickstart") and blended["kickstart"].startswith("/"):
@@ -1020,73 +915,11 @@ class BootSync:
NOTE: relevant to http only
"""
- blended = utils.blender(self.api, True, system, self.blend_cache)
+ blended = utils.blender(self.api, True, system)
filename = os.path.join(self.settings.webdir,"systems",system.name)
fd = open(filename, "w+")
fd.write(yaml.dump(blended))
fd.close()
- def linkfile(self, src, dst):
- """
- Attempt to create a link dst that points to src. Because file
- systems suck we attempt several different methods or bail to
- self.copyfile()
- """
- try:
- return os.link(src, dst)
- except (IOError, OSError):
- pass
-
- try:
- return os.symlink(src, dst)
- except (IOError, OSError):
- pass
-
- return self.copyfile(src, dst)
-
- def copyfile(self,src,dst):
- try:
- return shutil.copyfile(src,dst)
- except:
- if not os.path.samefile(src,dst):
- # accomodate for the possibility that we already copied
- # the file as a symlink/hardlink
- raise CX(_("Error copying %(src)s to %(dst)s") % { "src" : src, "dst" : dst})
-
- def rmfile(self,path):
- try:
- os.unlink(path)
- return True
- except OSError, ioe:
- if not ioe.errno == errno.ENOENT: # doesn't exist
- traceback.print_exc()
- raise CX(_("Error deleting %s") % path)
- return True
-
- def rmtree_contents(self,path):
- what_to_delete = glob.glob("%s/*" % path)
- for x in what_to_delete:
- self.rmtree(x)
-
- def rmtree(self,path):
- try:
- if os.path.isfile(path):
- return self.rmfile(path)
- else:
- return shutil.rmtree(path,ignore_errors=True)
- except OSError, ioe:
- traceback.print_exc()
- if not ioe.errno == errno.ENOENT: # doesn't exist
- raise CX(_("Error deleting %s") % path)
- return True
-
- def mkdir(self,path,mode=0777):
- try:
- return os.makedirs(path,mode)
- except OSError, oe:
- if not oe.errno == 17: # already exists (no constant for 17?)
- traceback.print_exc()
- print oe.errno
- raise CX(_("Error creating") % path)
diff --git a/cobbler/templar.py b/cobbler/templar.py
new file mode 100644
index 0000000..fa401b8
--- /dev/null
+++ b/cobbler/templar.py
@@ -0,0 +1,189 @@
+"""
+Cobbler uses Cheetah templates for lots of stuff, but there's
+some additional magic around that to deal with snippets/etc.
+(And it's not spelled wrong!)
+
+Copyright 2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import glob
+import utils
+from cexceptions import *
+from Cheetah.Template import Template
+
+class Templar:
+
+ def __init__(self,config):
+ """
+ Constructor
+ """
+ self.config = config
+ self.api = config.api
+ self.settings = config.settings()
+ self.cache = {}
+
+ def render(self, data_input, search_table, out_path, subject=None):
+ """
+ Render data_input back into a file.
+ data_input is either a string or a filename
+ search_table is a hash of metadata keys and values
+ out_path if not-none writes the results to a file
+ (though results are always returned)
+ subject is a profile or system object, if available (for snippet eval)
+ """
+
+ if type(data_input) != str:
+ raw_data = data_input.read()
+ else:
+ raw_data = data_input
+
+ # backward support for Cobbler's legacy (and slightly more readable)
+ # template syntax.
+ raw_data = raw_data.replace("TEMPLATE::","$")
+
+ # replace snippets with the proper Cheetah include directives prior to processing.
+ # see Wiki for full details on how snippets operate.
+ snippet_results = ""
+ for line in raw_data.split("\n"):
+ line = self.replace_snippets(line,subject)
+ snippet_results = "\n".join((snippet_results, line))
+ raw_data = snippet_results
+
+ # HACK: the ksmeta field may contain nfs://server:/mount in which
+ # case this is likely WRONG for kickstart, which needs the NFS
+ # directive instead. Do this to make the templates work.
+ newdata = ""
+ if search_table.has_key("tree") and search_table["tree"].startswith("nfs://"):
+ for line in data.split("\n"):
+ if line.find("--url") != -1 and line.find("url ") != -1:
+ rest = search_table["tree"][6:] # strip off "nfs://" part
+ try:
+ (server, dir) = rest.split(":",2)
+ except:
+ raise CX(_("Invalid syntax for NFS path given during import: %s" % search_table["tree"]))
+ line = "nfs --server %s --dir %s" % (server,dir)
+ # but put the URL part back in so koan can still see
+ # what the original value was
+ line = line + "\n" + "#url --url=%s" % search_table["tree"]
+ newdata = newdata + line + "\n"
+ raw_data = newdata
+
+ # tell Cheetah not to blow up if it can't find a symbol for something
+ raw_data = "#errorCatcher Echo\n" + raw_data
+
+ # now do full templating scan, where we will also templatify the snippet insertions
+ t = Template(source=raw_data, searchList=[search_table])
+ try:
+ data_out = str(t)
+ except:
+ print _("There appears to be an formatting error in the template file.")
+ print _("For completeness, the traceback from Cheetah has been included below.")
+ raise
+
+ # now apply some magic post-filtering that is used by cobbler import and some
+ # other places, but doesn't use Cheetah. Forcing folks to double escape
+ # things would be very unwelcome.
+
+ for x in search_table:
+ if type(search_table[x]) == str:
+ data_out = data_out.replace("@@%s@@" % x, search_table[x])
+
+ # remove leading newlines which apparently breaks AutoYAST ?
+ if data_out.startswith("\n"):
+ data_out = data_out.strip()
+
+ if out_path is not None:
+ utils.mkdir(os.path.dirname(out_path))
+ fd = open(out_path, "w+")
+ fd.write(data_out)
+ fd.close()
+
+ return data_out
+
+ def replace_snippets(self,line,subject):
+ """
+ Replace all SNIPPET:: syntaxes on a line with the
+ results of evaluating the snippet, taking care not
+ to replace tabs with spaces or anything like that
+ """
+ tokens = line.split(None)
+ for t in tokens:
+ if t.startswith("SNIPPET::"):
+ snippet_name = t.replace("SNIPPET::","")
+ line = line.replace(t,self.eval_snippet(snippet_name,subject))
+ return line
+
+ def eval_snippet(self,name,subject):
+ """
+ Replace SNIPPET::foo with contents of files:
+ Use /var/lib/cobbler/snippets/per_system/$name/$sysname
+ /var/lib/cobbler/snippets/per_profile/$name/$proname
+ /var/lib/cobbler/snippets/$name
+ in order... (first one wins)
+ """
+
+ sd = self.settings.snippetsdir
+ default_path = "%s/%s" % (sd,name)
+
+ if subject is None:
+ if os.path.exists(default_path):
+ return self.slurp(default_path)
+ else:
+ return self.slurp(None)
+
+
+ if subject.COLLECTION_TYPE == "system":
+ profile = self.api.find_profile(name=subject.profile)
+ sys_path = "%s/per_system/%s/%s" % (sd,name,subject.name)
+ pro_path = "%s/per_profile/%s/%s" % (sd,name,profile.name)
+ if os.path.exists(sys_path):
+ return self.slurp(sys_path)
+ elif os.path.exists(pro_path):
+ return self.slurp(pro_path)
+ elif os.path.exists(default_path):
+ return self.slurp(default_path)
+ else:
+ return self.slurp(None)
+
+ if subject.COLLECTION_TYPE == "profile":
+ pro_path = "%s/per_profile/%s/%s" % (sd,name,subject.name)
+ if os.path.exists(pro_path):
+ return self.slurp(pro_path)
+ elif os.path.exists(default_path):
+ return self.slurp(default_path)
+ else:
+ return self.slurp(None)
+
+ return self.slurp(None)
+
+ def slurp(self,filename):
+ """
+ Get the contents of a filename but if none is specified
+ just include some generic error text for the rendered
+ template.
+ """
+
+ if filename is None:
+ return "# error: no snippet data found"
+
+ # potentially eliminate a ton of system calls if syncing
+ # thousands of systems that use the same template
+ if self.cache.has_key(filename):
+ return self.cache[filename]
+
+ fd = open(filename,"r")
+ data = fd.read()
+ self.cache[filename] = data
+ fd.close()
+
+ return data
diff --git a/cobbler/utils.py b/cobbler/utils.py
index d8cf6fc..2d601c7 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -21,6 +21,7 @@ import sub_process
import shutil
import string
import traceback
+import errno
from cexceptions import *
#placeholder for translation
@@ -296,19 +297,14 @@ def grab_tree(api_handle, obj):
results.append(settings)
return results
-def blender(api_handle,remove_hashes, root_obj, blend_cache=None):
+def blender(api_handle,remove_hashes, root_obj):
"""
Combine all of the data in an object tree from the perspective
of that point on the tree, and produce a merged hash containing
consolidated data.
"""
- cache_enabled = False # FIXME: disabled for now as there a few bugs in this impl.
-
blend_key = "%s/%s/%s" % (root_obj.TYPE_NAME, root_obj.name, remove_hashes)
- if cache_enabled and blend_cache is not None:
- if blend_cache.has_key(blend_key):
- return blend_cache[blend_key]
settings = api_handle.settings()
tree = grab_tree(api_handle, root_obj)
@@ -353,9 +349,6 @@ def blender(api_handle,remove_hashes, root_obj, blend_cache=None):
# sanitize output for koan and kernel option lines, etc
if remove_hashes:
results = flatten(results)
-
- if cache_enabled and blend_cache is not None:
- blend_cache[blend_key] = results
return results
def flatten(data):
@@ -548,6 +541,70 @@ def tftpboot_location():
return "/var/lib/tftpboot"
return "/tftpboot"
+def linkfile(src, dst):
+ """
+ Attempt to create a link dst that points to src. Because file
+ systems suck we attempt several different methods or bail to
+ copyfile()
+ """
+
+ try:
+ return os.link(src, dst)
+ except (IOError, OSError):
+ pass
+
+ try:
+ return os.symlink(src, dst)
+ except (IOError, OSError):
+ pass
+
+ return utils.copyfile(src, dst)
+
+def copyfile(src,dst):
+ try:
+ return shutil.copyfile(src,dst)
+ except:
+ if not os.path.samefile(src,dst):
+ # accomodate for the possibility that we already copied
+ # the file as a symlink/hardlink
+ raise CX(_("Error copying %(src)s to %(dst)s") % { "src" : src, "dst" : dst})
+
+def rmfile(path):
+ try:
+ os.unlink(path)
+ return True
+ except OSError, ioe:
+ if not ioe.errno == errno.ENOENT: # doesn't exist
+ traceback.print_exc()
+ raise CX(_("Error deleting %s") % path)
+ return True
+
+def rmtree_contents(path):
+ what_to_delete = glob.glob("%s/*" % path)
+ for x in what_to_delete:
+ rmtree(x)
+
+def rmtree(path):
+ try:
+ if os.path.isfile(path):
+ return rmfile(path)
+ else:
+ return shutil.rmtree(path,ignore_errors=True)
+ except OSError, ioe:
+ traceback.print_exc()
+ if not ioe.errno == errno.ENOENT: # doesn't exist
+ raise CX(_("Error deleting %s") % path)
+ return True
+
+def mkdir(path,mode=0777):
+ try:
+ return os.makedirs(path,mode)
+ except OSError, oe:
+ if not oe.errno == 17: # already exists (no constant for 17?)
+ traceback.print_exc()
+ print oe.errno
+ raise CX(_("Error creating") % path)
+
if __name__ == "__main__":
# print redhat_release()
print tftpboot_location()
--
cgit
From 6f6c1c700aac364d5cb2f29d039c950f26767f10 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 14 Apr 2008 11:07:24 -0400
Subject: F8/9 kickstart format support
---
CHANGELOG | 1 +
cobbler/action_import.py | 9 ++-------
cobbler/utils.py | 10 ++++++++--
setup.py | 1 +
4 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index b6d6d14..5e1e8ca 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -18,6 +18,7 @@ Cobbler CHANGELOG
- removed dependency on rhpl
- import can now take an --arch (and is recommended usage)
- now possible to override snippets on a profile/system specific basis
+- provide a different default sample kickstart for imports of F8 and later
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_import.py b/cobbler/action_import.py
index 7f5409b..377b122 100644
--- a/cobbler/action_import.py
+++ b/cobbler/action_import.py
@@ -192,13 +192,6 @@ class Importer:
print _("- skipping distro %s since it wasn't imported this time") % profile.distro
continue
- # THIS IS OBSOLETE:
- #
- #if not distro.kernel.startswith("%s/ks_mirror/" % self.settings.webdir):
- # # this isn't a mirrored profile, so we won't touch it
- # print _("- skipping %s since profile isn't mirrored") % profile.name
- # continue
-
if (self.kickstart_file == None):
kdir = os.path.dirname(distro.kernel)
base_dir = "/".join(kdir.split("/")[0:-2])
@@ -287,6 +280,8 @@ class Importer:
def set_kickstart(self, profile, flavor, major, minor):
if flavor == "fedora":
+ if major >= 8:
+ return profile.set_kickstart("/etc/cobbler/sample_end.ks")
if major >= 6:
return profile.set_kickstart("/etc/cobbler/sample.ks")
if flavor == "redhat" or flavor == "centos":
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 2d601c7..8cc75bb 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -480,13 +480,19 @@ def fix_mod_python_select_submission(repos):
repos = repos.replace('"',"")
repos = repos.lstrip().rstrip()
return repos
+
def check_dist():
+ """
+ Determines what distro we're running under.
+ """
if os.path.exists("/etc/debian_version"):
return "debian"
else:
+ # valid for Fedora and all Red Hat / Fedora derivatives
return "redhat"
-def redhat_release():
+def os_release():
+
if check_dist() == "redhat":
if not os.path.exists("/bin/rpm"):
@@ -536,7 +542,7 @@ def tftpboot_location():
return t
# otherwise, guess based on the distro
- (make,version,rest) = redhat_release()
+ (make,version,rest) = os_release()
if make == "fedora" and version >= 9:
return "/var/lib/tftpboot"
return "/tftpboot"
diff --git a/setup.py b/setup.py
index 51ffe80..31ead00 100644
--- a/setup.py
+++ b/setup.py
@@ -88,6 +88,7 @@ if __name__ == "__main__":
# sample kickstart files
(etcpath, ['kickstarts/legacy.ks']),
(etcpath, ['kickstarts/sample.ks']),
+ (etcpath, ['kickstarts/sample_end.ks']),
(etcpath, ['kickstarts/default.ks']),
# templates for DHCP and syslinux configs
--
cgit
From 51119d1acc532cfad68b9fe4a1daa945fe7cd3f0 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 14 Apr 2008 16:31:08 -0400
Subject: Better kerberos support. See the Wiki.
---
CHANGELOG | 1 +
MANIFEST.in | 1 -
Makefile | 2 +
cobbler.spec | 1 -
cobbler/cobblerd.py | 35 +++++++++++++----
cobbler/modules/authn_kerberos.py | 81 ---------------------------------------
cobbler/modules/authn_ldap.py | 7 +++-
cobbler/modules/authn_passthru.py | 49 +++++++++++++++++++++++
cobbler/utils.py | 2 +-
scripts/cobbler_auth_help | 55 --------------------------
scripts/index.py | 25 +++++++++++-
setup.py | 2 +-
12 files changed, 111 insertions(+), 150 deletions(-)
delete mode 100644 cobbler/modules/authn_kerberos.py
create mode 100644 cobbler/modules/authn_passthru.py
delete mode 100644 scripts/cobbler_auth_help
diff --git a/CHANGELOG b/CHANGELOG
index 5e1e8ca..0713969 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -19,6 +19,7 @@ Cobbler CHANGELOG
- import can now take an --arch (and is recommended usage)
- now possible to override snippets on a profile/system specific basis
- provide a different default sample kickstart for imports of F8 and later
+- support for kerberos authentication
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/MANIFEST.in b/MANIFEST.in
index 4c8ed20..c553c03 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -24,7 +24,6 @@ include scripts/findks.cgi
include scripts/nopxe.cgi
include scripts/gateway.py
include scripts/post_install_trigger.cgi
-include scripts/cobbler_auth_help
include snippets/*
recursive-include po *.pot
recursive-include po *.po
diff --git a/Makefile b/Makefile
index e742e39..bc71166 100644
--- a/Makefile
+++ b/Makefile
@@ -38,6 +38,7 @@ install: clean manpage
devinstall:
cp /var/lib/cobbler/settings /tmp/cobbler_settings
cp /etc/cobbler/modules.conf /tmp/cobbler_modules.conf
+ cp /etc/httpd/conf.d/cobbler.conf /tmp/cobbler_http.conf
cp /etc/cobbler/users.conf /tmp/cobbler_users.conf
-cp /etc/cobbler/users.digest /tmp/cobbler_users.digest
make install
@@ -45,6 +46,7 @@ devinstall:
cp /tmp/cobbler_modules.conf /etc/cobbler/modules.conf
cp /tmp/cobbler_users.conf /etc/cobbler/users.conf
-cp /tmp/cobbler_users.digest /etc/cobbler/users.digest
+ cp /tmp/cobbler_http.conf /etc/httpd/conf.d/cobbler.conf
find /var/lib/cobbler/triggers | xargs chmod +x
chown -R apache /var/www/cobbler
chown -R apache /var/www/cgi-bin/cobbler
diff --git a/cobbler.spec b/cobbler.spec
index 2b6c88d..9b775cd 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -120,7 +120,6 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%dir /tftpboot/images
%{_bindir}/cobbler
%{_bindir}/cobblerd
-%{_bindir}/cobbler_auth_help
%dir /etc/cobbler
%config(noreplace) /etc/cobbler/*.ks
%config(noreplace) /etc/cobbler/*.template
diff --git a/cobbler/cobblerd.py b/cobbler/cobblerd.py
index 8859e03..065e99e 100644
--- a/cobbler/cobblerd.py
+++ b/cobbler/cobblerd.py
@@ -18,6 +18,7 @@ import SimpleXMLRPCServer
import glob
from utils import _
import xmlrpclib
+import binascii
from server import xmlrpclib2
import api as cobbler_api
@@ -40,6 +41,8 @@ def core(logger=None):
pid = os.fork()
+ regen_ss_file()
+
if pid == 0:
# part one: XMLRPC -- which may be just read-only or both read-only and read-write
do_xmlrpc_tasks(bootapi, settings, xmlrpc_port, xmlrpc_port2, logger)
@@ -47,6 +50,21 @@ def core(logger=None):
# part two: syslog, or syslog+avahi if avahi is installed
do_other_tasks(bootapi, settings, syslog_port, logger)
+def regen_ss_file():
+ # this is only used for Kerberos auth at the moment.
+ # it identifies XMLRPC requests from Apache that have already
+ # been cleared by Kerberos.
+
+ fd = open("/dev/urandom")
+ data = fd.read(512)
+ fd.close()
+ fd = open("/var/lib/cobbler/web.ss","w+")
+ fd.write(binascii.hexlify(data))
+ fd.close()
+ os.system("chmod 700 /var/lib/cobbler/web.ss")
+ os.system("chown apache /var/lib/cobbler/web.ss")
+ return 1
+
def do_xmlrpc_tasks(bootapi, settings, xmlrpc_port, xmlrpc_port2, logger):
if str(settings.xmlrpc_rw_enabled) != "0":
pid2 = os.fork()
@@ -195,11 +213,14 @@ if __name__ == "__main__":
#main()
- bootapi = cobbler_api.BootAPI()
- settings = bootapi.settings()
- syslog_port = settings.syslog_port
- xmlrpc_port = settings.xmlrpc_port
- xmlrpc_port2 = settings.xmlrpc_rw_port
- logger = bootapi.logger_remote
- do_xmlrpc_unix(bootapi, settings, logger)
+ #bootapi = cobbler_api.BootAPI()
+ #settings = bootapi.settings()
+ #syslog_port = settings.syslog_port
+ #xmlrpc_port = settings.xmlrpc_port
+ #xmlrpc_port2 = settings.xmlrpc_rw_port
+ #logger = bootapi.logger_remote
+ #do_xmlrpc_unix(bootapi, settings, logger)
+
+ regen_ss_file()
+
diff --git a/cobbler/modules/authn_kerberos.py b/cobbler/modules/authn_kerberos.py
deleted file mode 100644
index 46c01ad..0000000
--- a/cobbler/modules/authn_kerberos.py
+++ /dev/null
@@ -1,81 +0,0 @@
-"""
-Authentication module that uses kerberos.
-
-Copyright 2007, Red Hat, Inc
-Michael DeHaan
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-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., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-# NOTE: this is not using 'straight up' kerberos in that we
-# relay passwords through cobblerd for authentication, that may
-# be done later. It does of course check against kerberos,
-# however.
-
-# ALSO NOTE: we're calling out to a Perl program to make
-# this work. You must install Authen::Simple::Kerberos
-# from CPAN and the Kerberos libraries for this to work.
-# See the Cobbler Wiki for more info.
-
-# ALSO ALSO NOTE: set kerberos_realm in /var/lib/cobbler/settings
-# to something appropriate or this will never work. CASING
-# MATTERS. example.com != EXAMPLE.COM.
-
-import distutils.sysconfig
-import ConfigParser
-import sys
-import os
-from utils import _
-import md5
-import traceback
-# since sub_process isn't available on older OS's
-try:
- import sub_process as subprocess
-except:
- import subprocess
-
-plib = distutils.sysconfig.get_python_lib()
-mod_path="%s/cobbler" % plib
-sys.path.insert(0, mod_path)
-
-import cexceptions
-import utils
-
-def register():
- """
- The mandatory cobbler module registration hook.
- """
- return "authn"
-
-def authenticate(api_handle,username,password):
- """
- Validate a username/password combo, returning True/False
- Uses cobbler_auth_helper
- """
-
- realm = api_handle.settings().kerberos_realm
- api_handle.logger.debug("authenticating %s against %s" % (username,realm))
-
- rc = subprocess.call([
- "/usr/bin/cobbler_auth_help",
- "--method=kerberos",
- "--username=%s" % username,
- "--password=%s" % password,
- "--realm=%s" % realm
- ])
- print rc
- if rc == 42:
- api_handle.logger.debug("authenticated ok")
- # authentication ok (FIXME: log)
- return True
- else:
- api_handle.logger.debug("authentication failed")
- # authentication failed
- return False
-
-
diff --git a/cobbler/modules/authn_ldap.py b/cobbler/modules/authn_ldap.py
index eef4b2a..ff31750 100644
--- a/cobbler/modules/authn_ldap.py
+++ b/cobbler/modules/authn_ldap.py
@@ -17,7 +17,10 @@ import os
from utils import _
import md5
import traceback
-import ldap
+
+# we'll import this just a bit later
+# to keep it from being a requirement
+# import ldap
plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
@@ -38,6 +41,8 @@ def authenticate(api_handle,username,password):
"""
Validate an ldap bind, returning True/False
"""
+
+ import ldap
server = api_handle.settings().ldap_server
basedn = api_handle.settings().ldap_base_dn
diff --git a/cobbler/modules/authn_passthru.py b/cobbler/modules/authn_passthru.py
new file mode 100644
index 0000000..ebbe79a
--- /dev/null
+++ b/cobbler/modules/authn_passthru.py
@@ -0,0 +1,49 @@
+"""
+Authentication module that defers to Apache and trusts
+what Apache trusts.
+
+Copyright 2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+import sys
+import os
+from utils import _
+import traceback
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+import cexceptions
+import utils
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "authn"
+
+def authenticate(api_handle,username,password):
+ """
+ Validate a username/password combo, returning True/False
+ Uses cobbler_auth_helper
+ """
+
+ fd = open("/var/lib/cobbler/web.ss")
+ data = fd.read()
+ if password == data:
+ rc = 1
+ else:
+ rc = 0
+ fd.close()
+ return data
+
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 8cc75bb..8a09025 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -564,7 +564,7 @@ def linkfile(src, dst):
except (IOError, OSError):
pass
- return utils.copyfile(src, dst)
+ return copyfile(src, dst)
def copyfile(src,dst):
try:
diff --git a/scripts/cobbler_auth_help b/scripts/cobbler_auth_help
deleted file mode 100644
index c43cd5b..0000000
--- a/scripts/cobbler_auth_help
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/perl
-
-# Kerberos helper for logins
-#
-# Copyright 2007, Red Hat, Inc
-# Michael DeHaan
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# Usage:
-# cobbler_auth_helper kerberos username pass
-# (may do other auth types later)
-# Returns:
-# 0 on ok, non-0 on failure
-# API info:
-# http://search.cpan.org/~chansen/Authen-Simple-Kerberos-0.1/
-
-use warnings;
-use strict;
-
-use Authen::Simple::Kerberos;
-use Getopt::Long;
-
-my $method;
-my $username;
-my $realm;
-my $password;
-my $verbose=1;
-
-my $result = GetOptions(
- "method=s" => \$method,
- "username=s" => \$username,
- "realm=s" => \$realm,
- "password=s" => \$password,
-);
-
-my $kerberos = Authen::Simple::Kerberos->new(
- realm => $realm
-);
-
-print "authenticating: $username against (realm=$realm) (pass=$password)\n" if $verbose;
-
-if ( $kerberos->authenticate( $username, $password ) ) {
- print "ok\n" if $verbose;
- exit(42);
-}
-
-print "denied\n" if $verbose;
-exit(1);
-
diff --git a/scripts/index.py b/scripts/index.py
index d32a3a6..281e36e 100755
--- a/scripts/index.py
+++ b/scripts/index.py
@@ -18,6 +18,7 @@ from mod_python import util
import xmlrpclib
import cgi
+import os
from cobbler.webui import CobblerWeb
XMLRPC_SERVER = "http://127.0.0.1:25152" # was http://127.0.0.1/cobbler_api_rw"
@@ -70,7 +71,28 @@ def handler(req):
my_user = __get_user(req)
my_uri = req.uri
sess = __get_session(req)
- token = sess['cobbler_token']
+
+ if not sess.has_key('cobbler_token'):
+ # using Kerberos instead of Python Auth handler?
+ # We need to get our own token for use with authn_passthru
+ # which should also be configured in /etc/cobbler/modules.conf
+ # if another auth mode is configured in modules.conf this will
+ # most certaintly fail.
+ try:
+ if not os.path.exists("/var/lib/cobbler/web.ss"):
+ apache.log_error("cannot load /var/lib/cobbler/web.ss")
+ return apache.HTTP_UNAUTHORIZED
+ fd = open("/var/lib/cobbler/web.ss")
+ data = fd.read()
+ my_pw = data
+ fd.close()
+ token = xmlrpc_server.login(my_user,my_pw)
+ except Exception, e:
+ apache.log_error(str(e))
+ return apache.HTTP_UNAUTHORIZED
+ sess['cobbler_token'] = token
+ else:
+ token = sess['cobbler_token']
# needed?
req.add_common_vars()
@@ -118,7 +140,6 @@ def authenhandler(req):
my_user = req.user
my_uri = req.uri
- apache.log_error("authenhandler called: %s" % my_user)
try:
token = xmlrpc_server.login(my_user,my_pw)
except Exception, e:
diff --git a/setup.py b/setup.py
index 31ead00..6d4a1cd 100644
--- a/setup.py
+++ b/setup.py
@@ -60,7 +60,7 @@ if __name__ == "__main__":
"cobbler/server",
"cobbler/webui",
],
- scripts = ["scripts/cobbler", "scripts/cobblerd", "scripts/cobbler_auth_help"],
+ scripts = ["scripts/cobbler", "scripts/cobblerd"],
data_files = [
(modpython, ['scripts/index.py']),
# cgi files
--
cgit
From 2ccbb4b130afac3d1707433b3988259ea109db7f Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 15 Apr 2008 17:34:50 -0400
Subject: Replaced the existing cobbler pre/post install triggers system with a
much more flexible model that (for each system) passes in the following.
First arg: the word "system" or "profile", Second arg: the name of the said
system or profile, Third: the MAC if available, Fourth: the IP. This is all
logged by a default "status" trigger to /var/log/cobbler/install.log, for
being read by the soon-to-be-revamped cobbler check. The check system logs
all of this in order, followed by the word "start" or "stop", followed by the
number of seconds since Epoch.
---
CHANGELOG | 1 +
Makefile | 1 +
cobbler.spec | 3 ++
cobbler/action_status.py | 5 +++
cobbler/action_sync.py | 56 +++++++++++++++---------
cobbler/remote.py | 32 +++++++-------
cobbler/settings.py | 2 +-
cobbler/utils.py | 10 +++--
config/cobblerd_rotate | 7 +++
config/settings | 2 +-
kickstarts/sample.ks | 1 +
scripts/install_trigger.cgi | 92 ++++++++++++++++++++++++++++++++++++++++
scripts/post_install_trigger.cgi | 72 -------------------------------
setup.py | 5 ++-
triggers/status_post.trigger | 16 +++++++
triggers/status_pre.trigger | 16 +++++++
16 files changed, 207 insertions(+), 114 deletions(-)
create mode 100644 scripts/install_trigger.cgi
delete mode 100644 scripts/post_install_trigger.cgi
create mode 100644 triggers/status_post.trigger
create mode 100644 triggers/status_pre.trigger
diff --git a/CHANGELOG b/CHANGELOG
index 0713969..d1fb79d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,6 +20,7 @@ Cobbler CHANGELOG
- now possible to override snippets on a profile/system specific basis
- provide a different default sample kickstart for imports of F8 and later
- support for kerberos authentication
+- revamped pre/post install triggers system (triggered via cgi from kickstart wget)
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/Makefile b/Makefile
index bc71166..b8e5d0a 100644
--- a/Makefile
+++ b/Makefile
@@ -55,6 +55,7 @@ devinstall:
webtest: devinstall
/sbin/service cobblerd restart
/sbin/service httpd restart
+ chmod +x /var/www/cgi-bin/cobbler/*.cgi
sdist: clean messages updatewui
python setup.py sdist
diff --git a/cobbler.spec b/cobbler.spec
index 9b775cd..5e63f48 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -163,11 +163,14 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%dir /var/lib/cobbler/triggers/delete/repo/post
%dir /var/lib/cobbler/triggers/sync/pre
%dir /var/lib/cobbler/triggers/sync/post
+%dir /var/lib/cobbler/triggers/install/pre
%dir /var/lib/cobbler/triggers/install/post
%dir /var/lib/cobbler/snippets/
%defattr(744,root,root)
%config(noreplace) /var/lib/cobbler/triggers/sync/post/restart-services.trigger
+%config(noreplace) /var/lib/cobbler/triggers/install/pre/status_pre.trigger
+%config(noreplace) /var/lib/cobbler/triggers/install/post/status_post.trigger
%defattr(664,root,root)
%config(noreplace) /var/lib/cobbler/settings
diff --git a/cobbler/action_status.py b/cobbler/action_status.py
index 7366060..703bf41 100644
--- a/cobbler/action_status.py
+++ b/cobbler/action_status.py
@@ -100,6 +100,11 @@ class BootStatusReport:
tracking will be incomplete. This should be noted in the docs.
"""
+
+ print "NOTE: this function is being replaced right now. Stay tuned!"
+ return 0
+
+
api = cobbler_api.BootAPI()
apache_results = self.scan_apache_logfiles()
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 1e65e42..5b7b546 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -376,7 +376,8 @@ class BootSync:
meta.update(ksmeta) # make available at top level
meta["yum_repo_stanza"] = self.generate_repo_stanza(g,True)
meta["yum_config_stanza"] = self.generate_config_stanza(g,True)
- meta["kickstart_done"] = self.generate_kickstart_signal(g, None)
+ meta["kickstart_done"] = self.generate_kickstart_signal(0, g, None)
+ meta["kickstart_start"] = self.generate_kickstart_signal(1, g, None)
meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
kfile = open(kickstart_path)
self.templar.render(kfile, meta, dest, g)
@@ -386,40 +387,56 @@ class BootSync:
msg = "err_kickstart2"
raise CX(_("Error while rendering kickstart file %(src)s to %(dest)s") % { "src" : kickstart_path, "dest" : dest })
- def generate_kickstart_signal(self, profile, system=None):
+ def generate_kickstart_signal(self, is_pre=0, profile=None, system=None):
"""
- Do things that we do at the end of kickstarts...
- * signal the status watcher we're done
- * disable PXE if needed
- * save the original kickstart file for debug
+ Do things that we do at the start/end of kickstarts...
+ * start: signal the status watcher we're starting
+ * end: signal the status watcher we're done
+ * end: disable PXE if needed
+ * end: save the original kickstart file for debug
"""
# FIXME: watcher is more of a request than a packaged file
# we should eventually package something and let it do something important"
- pattern1 = "wget \"http://%s/cgi-bin/cobbler/nopxe.cgi?system=%s\""
- pattern2 = "wget \"http://%s/cobbler/%s/%s/ks.cfg\" -O /root/cobbler.ks"
- pattern3 = "wget \"http://%s/cgi-bin/cobbler/post_install_trigger.cgi?system=%s\""
+
+ nopxe = "\nwget \"http://%s/cgi-bin/cobbler/nopxe.cgi?system=%s\""
+ saveks = "\nwget \"http://%s/cobbler/%s/%s/ks.cfg\" -O /root/cobbler.ks"
+ runpost = "\nwget \"http://%s/cgi-bin/cobbler/install_trigger.cgi?mode=post&%s=%s\""
+ runpre = "\nwget \"http://%s/cgi-bin/cobbler/install_trigger.cgi?mode=pre&%s=%s\""
+ what = "profile"
blend_this = profile
if system:
+ what = "system"
blend_this = system
blended = utils.blender(self.api, False, blend_this)
kickstart = blended.get("kickstart",None)
buf = ""
+ srv = blended["http_server"]
if system is not None:
- if str(self.settings.pxe_just_once).upper() in [ "1", "Y", "YES", "TRUE" ]:
- buf = buf + "\n" + pattern1 % (blended["http_server"], system.name)
- if kickstart and os.path.exists(kickstart):
- buf = buf + "\n" + pattern2 % (blended["http_server"], "kickstarts_sys", system.name)
- if self.settings.run_post_install_trigger:
- buf = buf + "\n" + pattern3 % (blended["http_server"], system.name)
+ if not is_pre:
+ if str(self.settings.pxe_just_once).upper() in [ "1", "Y", "YES", "TRUE" ]:
+ buf = buf + nopxe % (srv, system.name)
+ if kickstart and os.path.exists(kickstart):
+ buf = buf + saveks % (srv, "kickstarts_sys", system.name)
+ if self.settings.run_install_trigger:
+ buf = buf + runpost % (srv, what, system.name)
+ else:
+ if self.settings.run_install_trigger:
+ buf = buf + runpre % (srv, what, system.name)
else:
- if kickstart and os.path.exists(kickstart):
- buf = buf + "\n" + pattern2 % (blended["http_server"], "kickstarts", profile.name)
-
+ if not is_pre:
+ if kickstart and os.path.exists(kickstart):
+ buf = buf + saveks % (srv, "kickstarts", profile.name)
+ if self.settings.run_install_trigger:
+ buf = buf + runpost % (srv, what, profile.name)
+ else:
+ if self.settings.run_install_trigger:
+ buf = buf + runpre % (srv, what, profile.name)
+
return buf
def get_repo_segname(self, is_profile):
@@ -560,7 +577,8 @@ class BootSync:
meta.update(ksmeta) # make available at top level
meta["yum_repo_stanza"] = self.generate_repo_stanza(s, False)
meta["yum_config_stanza"] = self.generate_config_stanza(s, False)
- meta["kickstart_done"] = self.generate_kickstart_signal(profile, s)
+ meta["kickstart_done"] = self.generate_kickstart_signal(0, profile, s)
+ meta["kickstart_start"] = self.generate_kickstart_signal(1, profile, s)
meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
kfile = open(kickstart_path)
self.templar.render(kfile, meta, dest, s)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index f7e2226..b606bbc 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -230,26 +230,28 @@ class CobblerXMLRPCInterface:
systems.add(obj,save=True,with_triggers=False,with_sync=False,quick_pxe_update=True)
return True
- def run_post_install_triggers(self,name,token=None):
+ def run_install_triggers(self,mode,objtype,name,mac,ip,token=None):
+
"""
- This is a feature used to run the post install trigger.
- It passes the system named "name" to the trigger. Disabled by default as
- this requires public API access and is technically a read-write operation.
+ This is a feature used to run the pre/post install triggers.
+ See CobblerTriggers on Wiki for details
"""
- self.log("run_post_install_triggers",token=token)
- # used by postinstalltrigger.cgi
- self.api.clear()
- self.api.deserialize()
- if not self.api.settings().run_post_install_trigger:
- # feature disabled!
+ self.log("run_install_triggers",token=token)
+
+ if mode != "pre" and mode != "post":
return False
- systems = self.api.systems()
- obj = systems.find(name=name)
- if obj == None:
- # system not found!
+ if objtype != "system" and objtype !="profile":
return False
- utils.run_triggers(obj, "/var/lib/cobbler/triggers/install/post/*")
+
+ # the trigger script is called with name,mac, and ip as arguments 1,2, and 3
+ # we do not do API lookups here because they are rather expensive at install
+ # time if reinstalling all of a cluster all at once.
+ # we can do that at "cobbler check" time.
+
+ utils.run_triggers(None, "/var/lib/cobbler/triggers/install/%s/*" % mode, additional=[objtype,name,mac,ip])
+
+
return True
def _refresh(self):
diff --git a/cobbler/settings.py b/cobbler/settings.py
index bc16835..9066d7d 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -61,7 +61,7 @@ DEFAULTS = {
"manage_dhcp_mode" : "isc",
"next_server" : "127.0.0.1",
"pxe_just_once" : 0,
- "run_post_install_trigger" : 0,
+ "run_install_trigger" : 1,
"server" : "127.0.0.1",
"snippetsdir" : "/var/lib/cobbler/snippets",
"syslog_port" : 25150,
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 8a09025..0f09345 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -430,7 +430,7 @@ def hash_to_string(hash):
buffer = buffer + str(key) + "=" + str(value) + " "
return buffer
-def run_triggers(ref,globber):
+def run_triggers(ref,globber,additional=[]):
"""
Runs all the trigger scripts in a given directory.
ref can be a cobbler object, if not None, the name will be passed
@@ -447,10 +447,12 @@ def run_triggers(ref,globber):
# skip .rpmnew files that may have been installed
# in the triggers directory
continue
+ arglist = [ file ]
if ref:
- rc = sub_process.call([file,ref.name], shell=False)
- else:
- rc = sub_process.call([file], shell=False)
+ arglist.append(ref.name)
+ for x in additional:
+ arglist.append(x)
+ rc = sub_process.call(arglist, shell=False)
except:
print _("Warning: failed to execute trigger: %s" % file)
continue
diff --git a/config/cobblerd_rotate b/config/cobblerd_rotate
index 0e4bcbf..c7a8b19 100644
--- a/config/cobblerd_rotate
+++ b/config/cobblerd_rotate
@@ -21,3 +21,10 @@
fi
endscript
}
+
+/var/log/cobbler/install.log {
+ missingok
+ notifempty
+ rotate 4
+ weekly
+}
diff --git a/config/settings b/config/settings
index 8fc0fdf..33eb4b1 100644
--- a/config/settings
+++ b/config/settings
@@ -35,7 +35,7 @@ manage_dhcp: 0
manage_dhcp_mode: isc
next_server: '127.0.0.1'
pxe_just_once: 0
-run_post_install_trigger: 0
+run_install_trigger: 1
server: '127.0.0.1'
snippetsdir: /var/lib/cobbler/snippets
syslog_port: 25150
diff --git a/kickstarts/sample.ks b/kickstarts/sample.ks
index 5208ed7..1a7b731 100644
--- a/kickstarts/sample.ks
+++ b/kickstarts/sample.ks
@@ -39,6 +39,7 @@ zerombr
# Magically figure out how to partition this thing
SNIPPET::partition_select
+$kickstart_start
%packages
diff --git a/scripts/install_trigger.cgi b/scripts/install_trigger.cgi
new file mode 100644
index 0000000..493591f
--- /dev/null
+++ b/scripts/install_trigger.cgi
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# This script runs post install triggers in /var/lib/cobbler/triggers/install/post
+# if the triggers are enabled in the settings file.
+#
+# (C) Tim Verhoeven , 2007
+# tweaked: Michael DeHaan , 2007-2008
+
+import cgi
+import cgitb
+import time
+import os
+import sys
+import socket
+import xmlrpclib
+from cobbler import sub_process as sub_process
+
+COBBLER_BASE = "/var/www/cobbler"
+XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
+
+#----------------------------------------------------------------------
+
+class ServerProxy(xmlrpclib.ServerProxy):
+
+ def __init__(self, url=None):
+ xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
+
+#----------------------------------------------------------------------
+
+def parse_query():
+ """
+ Read arguments from query string.
+ """
+
+ form = cgi.parse()
+
+ mac = "?"
+ if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
+ devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
+ mac = devicepair.split()[1].strip()
+
+ ip = "?"
+ if os.environ.has_key("REMOTE_ADDR"):
+ ip = os.environ["REMOTE_ADDR"]
+
+ name = "?"
+ objtype = "?"
+ if form.has_key("system"):
+ name = form["system"][0]
+ objtype = "system"
+ elif form.has_key("profile"):
+ name = form["profile"][0]
+ objtype = "profile"
+
+ mode = "?"
+ if form.has_key("mode"):
+ mode = form["mode"][0]
+
+ return (mode,objtype,name,mac,ip)
+
+def invoke(mode,objtype,name,mac,ip):
+ """
+ Determine if this feature is enabled.
+ """
+
+ xmlrpc_server = ServerProxy(XMLRPC_SERVER)
+ print xmlrpc_server.run_install_triggers(mode,objtype,name,mac,ip)
+
+ return True
+
+#----------------------------------------------------------------------
+
+def header():
+ print "Content-type: text/plain"
+ print
+
+#----------------------------------------------------------------------
+
+if __name__ == "__main__":
+ cgitb.enable(format='text')
+ header()
+ (mode,objtype,name,mac,ip) = parse_query()
+ invoke(mode,objtype,name,mac,ip)
+
+
diff --git a/scripts/post_install_trigger.cgi b/scripts/post_install_trigger.cgi
deleted file mode 100644
index 4a79c8b..0000000
--- a/scripts/post_install_trigger.cgi
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env python
-
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# This script runs post install triggers in /var/lib/cobbler/triggers/install/post
-# if the triggers are enabled in the settings file.
-#
-# (C) Tim Verhoeven , 2007
-# tweaked: Michael DeHaan
-
-import cgi
-import cgitb
-import time
-import os
-import sys
-import socket
-import xmlrpclib
-from cobbler import sub_process as sub_process
-
-COBBLER_BASE = "/var/www/cobbler"
-XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
-
-#----------------------------------------------------------------------
-
-class ServerProxy(xmlrpclib.ServerProxy):
-
- def __init__(self, url=None):
- xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
-
-#----------------------------------------------------------------------
-
-def parse_query():
- """
- Read arguments from query string.
- """
-
- form = cgi.parse()
-
- if form.has_key("system"):
- return form["system"][0]
- return 0
-
-def invoke(name):
- """
- Determine if this feature is enabled.
- """
-
- xmlrpc_server = ServerProxy(XMLRPC_SERVER)
- print xmlrpc_server.run_post_install_triggers(name)
-
- return True
-
-#----------------------------------------------------------------------
-
-def header():
- print "Content-type: text/plain"
- print
-
-#----------------------------------------------------------------------
-
-if __name__ == "__main__":
- cgitb.enable(format='text')
- header()
- name = parse_query()
- invoke(name)
-
-
diff --git a/setup.py b/setup.py
index 6d4a1cd..c8a6c99 100644
--- a/setup.py
+++ b/setup.py
@@ -65,7 +65,7 @@ if __name__ == "__main__":
(modpython, ['scripts/index.py']),
# cgi files
(cgipath, ['scripts/findks.cgi', 'scripts/nopxe.cgi']),
- (cgipath, ['scripts/post_install_trigger.cgi']),
+ (cgipath, ['scripts/install_trigger.cgi']),
# miscellaneous config files
(rotpath, ['config/cobblerd_rotate']),
@@ -192,7 +192,8 @@ if __name__ == "__main__":
("%sdelete/repo/pre" % trigpath, []),
("%sdelete/repo/post" % trigpath, []),
("%sdelete/repo/post" % trigpath, []),
- ("%sinstall/post" % trigpath, []),
+ ("%sinstall/pre" % trigpath, [ "triggers/status_pre.trigger"]),
+ ("%sinstall/post" % trigpath, [ "triggers/status_post.trigger"]),
("%ssync/pre" % trigpath, []),
("%ssync/post" % trigpath, [ "triggers/restart-services.trigger" ])
],
diff --git a/triggers/status_post.trigger b/triggers/status_post.trigger
new file mode 100644
index 0000000..32934c8
--- /dev/null
+++ b/triggers/status_post.trigger
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+
+import os
+import sys
+import time
+
+objtype = sys.argv[1] # "system" or "profile"
+name = sys.argv[2] # name of system or profile
+mac = sys.argv[3] # mac or "?"
+ip = sys.argv[4] # ip or "?"
+
+fd = open("/var/log/cobbler/install.log","a+")
+fd.write("%s\t%s\t%s\t%s\tstop\t%s\n" % (objtype,name,mac,ip,time.time()))
+fd.close()
+
+sys.exit(0)
diff --git a/triggers/status_pre.trigger b/triggers/status_pre.trigger
new file mode 100644
index 0000000..385beaa
--- /dev/null
+++ b/triggers/status_pre.trigger
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+
+import os
+import sys
+import time
+
+objtype = sys.argv[1] # "system" or "profile"
+name = sys.argv[2] # name of system or profile
+mac = sys.argv[3] # mac or "?"
+ip = sys.argv[4] # ip or "?"
+
+fd = open("/var/log/cobbler/install.log","a+")
+fd.write("%s\t%s\t%s\t%s\tstart\t%s\n" % (objtype,name,mac,ip,time.time()))
+fd.close()
+
+sys.exit(0)
--
cgit
From 2eabc9130522acc1e1de034ec062338572076a02 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 15 Apr 2008 18:01:27 -0400
Subject: Add missing file
---
kickstarts/sample_end.ks | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 kickstarts/sample_end.ks
diff --git a/kickstarts/sample_end.ks b/kickstarts/sample_end.ks
new file mode 100644
index 0000000..b856a3d
--- /dev/null
+++ b/kickstarts/sample_end.ks
@@ -0,0 +1,55 @@
+# kickstart template for Fedora 8 and later.
+# (includes %end blocks)
+# do not use with earlier distros
+
+#platform=x86, AMD64, or Intel EM64T
+# System authorization information
+auth --useshadow --enablemd5
+# System bootloader configuration
+bootloader --location=mbr
+# Partition clearing information
+clearpart --all --initlabel
+# Use text mode install
+text
+# Firewall configuration
+firewall --enabled
+# Run the Setup Agent on first boot
+firstboot --disable
+# System keyboard
+keyboard us
+# System language
+lang en_US
+# Use network installation
+url --url=$tree
+# If any cobbler repo definitions were referenced in the kickstart profile, include them here.
+$yum_repo_stanza
+# Network information
+network --bootproto=dhcp --device=eth0 --onboot=on
+# Reboot after installation
+reboot
+
+#Root password
+rootpw --iscrypted \$1\$mF86/UHC\$WvcIcX2t6crBz2onWxyac.
+# SELinux configuration
+selinux --disabled
+# Do not configure the X Window System
+skipx
+# System timezone
+timezone America/New_York
+# Install OS instead of upgrade
+install
+# Clear the Master Boot Record
+zerombr
+
+# Magically figure out how to partition this thing
+SNIPPET::partition_select
+$kickstart_start
+
+
+%packages
+%end
+
+%post
+$yum_config_stanza
+$kickstart_done
+%end
--
cgit
From 98e7ccdd019dd6b2fe6eb7325a681cb132a36741 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 15 Apr 2008 18:21:08 -0400
Subject: logrotate should not send emails to root when restarting services.
---
CHANGELOG | 1 +
config/cobblerd_rotate | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index d1fb79d..d48e3d7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -21,6 +21,7 @@ Cobbler CHANGELOG
- provide a different default sample kickstart for imports of F8 and later
- support for kerberos authentication
- revamped pre/post install triggers system (triggered via cgi from kickstart wget)
+- logrotate should not send emails to root when restarting services
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/config/cobblerd_rotate b/config/cobblerd_rotate
index c7a8b19..e739c47 100644
--- a/config/cobblerd_rotate
+++ b/config/cobblerd_rotate
@@ -5,7 +5,7 @@
weekly
postrotate
if [ -f /var/lock/subsys/cobblerd ]; then
- /etc/init.d/cobblerd condrestart
+ /etc/init.d/cobblerd condrestart > /dev/null
fi
endscript
}
@@ -17,7 +17,7 @@
weekly
postrotate
if [ -f /var/lock/subsys/cobblerd ]; then
- /etc/init.d/cobblerd condrestart
+ /etc/init.d/cobblerd condrestart > /dev/null
fi
endscript
}
--
cgit
From c70084fdd316b4ee8e4cd80a4ab8d66a7655043c Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 15 Apr 2008 18:26:19 -0400
Subject: Fix manifest.in to add missing file, remove one file no longer used.
---
MANIFEST.in | 3 +--
cobbler/webui/master.py | 38 ++++++++++++++++++++++++--------------
2 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index c553c03..12f9f9e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -22,8 +22,7 @@ include scripts/index.py
include scripts/cobblerd
include scripts/findks.cgi
include scripts/nopxe.cgi
-include scripts/gateway.py
-include scripts/post_install_trigger.cgi
+include scripts/install_trigger.cgi
include snippets/*
recursive-include po *.pot
recursive-include po *.po
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 3e0c2fb..1e6d30d 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -31,12 +31,12 @@ VFFSL=valueFromFrameOrSearchList
VFSL=valueFromSearchList
VFN=valueForName
currentTime=time.time
-__CHEETAH_version__ = '2.0rc7'
-__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 7)
-__CHEETAH_genTime__ = 1207768044.4095509
-__CHEETAH_genTimestamp__ = 'Wed Apr 9 21:07:24 2008'
+__CHEETAH_version__ = '2.0.1'
+__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
+__CHEETAH_genTime__ = 1208298360.4598751
+__CHEETAH_genTimestamp__ = 'Tue Apr 15 18:26:00 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
-__CHEETAH_srcLastModified__ = 'Wed Apr 9 21:03:21 2008'
+__CHEETAH_srcLastModified__ = 'Fri Feb 15 14:47:43 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
@@ -158,16 +158,20 @@ class master(Template):
--
cgit
From 53a87f698e38627c95e1e5e0f99a3b2f9f55ff13 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 16 Apr 2008 12:17:32 -0400
Subject: To make things easier to understand, enable RW-xmlrpc by default,
just change the authentication modes to deny_all in the config file (by
default)
---
CHANGELOG | 2 ++
cobbler/action_import.py | 3 +--
cobbler/modules/authn_denyall.py | 43 ++++++++++++++++++++++++++++++++++++++++
config/modules.conf | 2 +-
config/settings | 2 +-
5 files changed, 48 insertions(+), 4 deletions(-)
create mode 100644 cobbler/modules/authn_denyall.py
diff --git a/CHANGELOG b/CHANGELOG
index d48e3d7..6fb090f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -22,6 +22,8 @@ Cobbler CHANGELOG
- support for kerberos authentication
- revamped pre/post install triggers system (triggered via cgi from kickstart wget)
- logrotate should not send emails to root when restarting services
+- default core (but not repo add) repos to priority 1 (lowest) if using priorities plugin
+- change default authentication to deny_all, xmlrpc_rw_enabled now on by default
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_import.py b/cobbler/action_import.py
index 377b122..2e70c80 100644
--- a/cobbler/action_import.py
+++ b/cobbler/action_import.py
@@ -458,8 +458,7 @@ class Importer:
config_file.write("baseurl=http://@@http_server@@/cobbler/ks_mirror/%s\n" % (urlseg))
config_file.write("enabled=1\n")
config_file.write("gpgcheck=0\n")
- # NOTE: yum priority defaults to 99 if that plugin is enabled
- # so don't need to add priority=99 here
+ config_file.write("priority=1\n")
config_file.close()
# don't run creatrepo twice -- this can happen easily for Xen and PXE, when
diff --git a/cobbler/modules/authn_denyall.py b/cobbler/modules/authn_denyall.py
new file mode 100644
index 0000000..91e27d4
--- /dev/null
+++ b/cobbler/modules/authn_denyall.py
@@ -0,0 +1,43 @@
+"""
+Authentication module that denies everything.
+Used to disable the WebUI by default.
+
+Copyright 2007-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+import sys
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "authn"
+
+def authenticate(api_handle,username,password):
+ """
+ Validate a username/password combo, returning True/False
+
+ Thanks to http://trac.edgewall.org/ticket/845 for supplying
+ the algorithm info.
+ """
+
+ # debugging only (not safe to enable)
+ # api_handle.logger.debug("backend authenticate (%s,%s)" % (username,password))
+
+ return False
+
+
diff --git a/config/modules.conf b/config/modules.conf
index 2daf0e4..88aa134 100644
--- a/config/modules.conf
+++ b/config/modules.conf
@@ -6,7 +6,7 @@ system = serializer_yaml
repo = serializer_yaml
[authentication]
-module = authn_configfile
+module = authn_denyall
[authorization]
module = authz_allowall
diff --git a/config/settings b/config/settings
index 33eb4b1..fc6739a 100644
--- a/config/settings
+++ b/config/settings
@@ -43,7 +43,7 @@ tftpd_bin: /usr/sbin/in.tftpd
tftpd_conf: /etc/xinetd.d/tftp
webdir: /var/www/cobbler
xmlrpc_port: 25151
-xmlrpc_rw_enabled: 0
+xmlrpc_rw_enabled: 1
xmlrpc_rw_port: 25152
yum_post_install_mirror: 0
yumdownloader_flags: "--resolve"
--
cgit
From 6c371de03a0bbd9901223b707575e0804b9786a5 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 16 Apr 2008 13:46:20 -0400
Subject: Change settings.
---
cobbler/settings.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 9066d7d..1695cbb 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -69,7 +69,7 @@ DEFAULTS = {
"tftpd_conf" : "/etc/xinetd.d/tftp",
"webdir" : "/var/www/cobbler",
"xmlrpc_port" : 25151,
- "xmlrpc_rw_enabled" : 0,
+ "xmlrpc_rw_enabled" : 1,
"xmlrpc_rw_port" : 25152,
"yum_post_install_mirror" : 1,
"yumdownloader_flags" : "--resolve"
--
cgit
From 30f0d9f1f5e3ebe897c0786f52e2f404cd88b737 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 16 Apr 2008 14:13:16 -0400
Subject: Fix if clause
---
cobbler/action_import.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cobbler/action_import.py b/cobbler/action_import.py
index 2e70c80..3e726a6 100644
--- a/cobbler/action_import.py
+++ b/cobbler/action_import.py
@@ -74,9 +74,9 @@ class Importer:
raise CX(_("arch must be x86, x86_64, or ia64"))
mpath = os.path.join(self.settings.webdir, "ks_mirror", self.mirror_name)
+
if os.path.exists(mpath) and self.arch is None:
- if not found:
- raise CX(_("Something already exists at this import location (%s). You must specify --arch to avoid potentially overwriting existing files.") % mpath)
+ raise CX(_("Something already exists at this import location (%s). You must specify --arch to avoid potentially overwriting existing files.") % mpath)
if self.arch:
# append the arch path to the name if the arch is not already
--
cgit
From 143f4e068dc1a7e2f5b7196bcfc9a7317bf11fcc Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 16 Apr 2008 18:37:48 -0400
Subject: This is the new status engine in progress. I still need to do some
things to parse out times and indicate how long installs have been active (so
there is an easier way to grep for last installs). Technically this will
also provide ways of looking at an install history which is probably
something we could add if it was interesting. Lots of options.
---
CHANGELOG | 2 +
cobbler/action_status.py | 295 ++++++++++++++++----------------------------
cobbler/api.py | 4 +-
cobbler/item_repo.py | 7 ++
cobbler/modules/cli_misc.py | 2 +-
cobbler/utils.py | 3 -
6 files changed, 119 insertions(+), 194 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 6fb090f..f721aa3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,6 +24,8 @@ Cobbler CHANGELOG
- logrotate should not send emails to root when restarting services
- default core (but not repo add) repos to priority 1 (lowest) if using priorities plugin
- change default authentication to deny_all, xmlrpc_rw_enabled now on by default
+- additional fix for mod_python select box submissions
+- set repo arch if found in the URL and no --arch is specified
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_status.py b/cobbler/action_status.py
index 703bf41..cd76a39 100644
--- a/cobbler/action_status.py
+++ b/cobbler/action_status.py
@@ -2,7 +2,7 @@
Reports on kickstart activity by examining the logs in
/var/log/cobbler.
-Copyright 2007, Red Hat, Inc
+Copyright 2007-2008, Red Hat, Inc
Michael DeHaan
This software may be freely redistributed under the terms of the GNU
@@ -19,7 +19,7 @@ import glob
import time
import api as cobbler_api
-from utils import _
+#from utils import _
class BootStatusReport:
@@ -30,207 +30,126 @@ class BootStatusReport:
"""
self.config = config
self.settings = config.settings()
+ self.ip_data = {}
self.mode = mode
# -------------------------------------------------------
- def scan_apache_logfiles(self):
- results = {}
- files = [ "/var/log/httpd/access_log" ]
- for x in range(1,4):
- consider = "/var/log/httpd/access_log.%s" % x
- if os.path.exists(consider):
- files.append(consider)
- for fname in files:
- fh = open(fname)
- data = fh.readline()
- while (data is not None and data != ""):
- data = fh.readline()
- tokens = data.split(None)
- if len(tokens) < 6:
- continue
- ip = tokens[0]
- stime = tokens[3].replace("[","")
- req = tokens[6]
- if req.find("/cblr") == -1:
- continue
- ttime = time.strptime(stime,"%d/%b/%Y:%H:%M:%S")
- itime = time.mktime(ttime)
- if not results.has_key(ip):
- results[ip] = {}
- results[ip][itime] = req
-
- return results
-
- # -------------------------------------------------------
-
- def scan_syslog_logfiles(self):
-
- # find all of the logged IP addrs
- filelist = glob.glob("/var/log/cobbler/syslog/*")
- filelist.sort()
- results = {}
-
- for fullname in filelist:
- #fname = os.path.basename(fullname)
- logfile = open(fullname, "r")
- # for each line in the file...
- data = logfile.readline()
- while(data is not None and data != ""):
- data = logfile.readline()
-
- try:
- (epoch, strdate, ip, request) = data.split("\t", 3)
- epoch = float(epoch)
- except:
- continue
-
- if not results.has_key(ip):
- results[ip] = {}
- results[ip][epoch] = request
-
- return results
-
- # -------------------------------------------------------
+ def scan_logfiles(self):
- def run(self):
- """
- Calculate and print a kickstart-status report.
- For kickstart trees not in /var/lib/cobbler (or a symlink off of there)
- tracking will be incomplete. This should be noted in the docs.
- """
+ #profile foosball ? 127.0.0.1 start 1208294043.58
+ #system neo ? 127.0.0.1 start 1208295122.86
- print "NOTE: this function is being replaced right now. Stay tuned!"
- return 0
+ files = glob.glob("/var/log/cobbler/install.log*")
+ for fname in files:
+ fd = open(fname)
+ data = fd.read()
+ for line in data.split("\n"):
+ tokens = line.split()
+ if len(tokens) == 0:
+ continue
+ (profile_or_system, name, mac, ip, start_or_stop, ts) = tokens
+ self.catalog(profile_or_system,name,mac,ip,start_or_stop,ts)
+ fd.close()
+
+ # ------------------------------------------------------
+
+ def catalog(self,profile_or_system,name,mac,ip,start_or_stop,ts):
+ ip_data = self.ip_data
+
+ if not ip_data.has_key(ip):
+ ip_data[ip] = {}
+ elem = ip_data[ip]
+
+ ts = float(ts)
+
+ if not elem.has_key("most_recent_start"):
+ elem["most_recent_start"] = -1
+ if not elem.has_key("most_recent_stop"):
+ elem["most_recent_stop"] = -1
+ if not elem.has_key("most_recent_target"):
+ elem["most_recent_target"] = "?"
+ if not elem.has_key("seen_start"):
+ elem["seen_start"] = 0
+ if not elem.has_key("seen_stop"):
+ elem["seen_stop"] = 0
+ if not elem.has_key("mac"):
+ elem["mac"] = "?"
+
+ mrstart = elem["most_recent_start"]
+ mrstop = elem["most_recent_stop"]
+ mrtarg = elem["most_recent_target"]
+ snstart = elem["seen_start"]
+ snstop = elem["seen_stop"]
+ snmac = elem["mac"]
+
+
+ if start_or_stop == "start":
+ if mrstart < ts:
+ mrstart = ts
+ mrtarg = "%s:%s" % (profile_or_system, name)
+ snmac = mac
+ elem["seen_start"] = elem["seen_start"] + 1
+
+ if start_or_stop == "stop":
+ if mrstop < ts:
+ mrstop = ts
+ mrtarg = "%s:%s" % (profile_or_system, name)
+ snmac = mac
+ elem["seen_stop"] = elem["seen_stop"] + 1
+
+ elem["most_recent_start"] = mrstart
+ elem["most_recent_stop"] = mrstop
+ elem["most_recent_target"] = mrtarg
+ elem["mac"] = mac
+ # -------------------------------------------------------
- api = cobbler_api.BootAPI()
+ def process_results(self):
+ # FIXME: this should update the times here
+ print "DEBUG: %s" % self.ip_data
+ return self.ip_data
- apache_results = self.scan_apache_logfiles()
- syslog_results = self.scan_syslog_logfiles()
- ips = apache_results.keys()
+ def get_printable_results(self):
+ # ip | last mac | last target | start | stop | count
+ format = "%-15s %-17s %-20s %-17s %-17s %5s"
+ ip_data = self.ip_data
+ ips = ip_data.keys()
ips.sort()
- ips2 = syslog_results.keys()
- ips2.sort()
-
- ips.extend(ips2)
- ip_printed = {}
-
- last_recorded_time = 0
- time_collisions = 0
-
- #header = ("Name", "State", "Started", "Last Request", "Seconds", "Log Entries")
- print "%-20s | %-15s | %-25s | %-25s | %-10s | %-6s" % (
- _("Name"),
- _("State"),
- _("Last Request"),
- _("Started"),
- _("Seconds"),
- _("Log Entries")
+ line = (
+ "ip",
+ "mac",
+ "target",
+ "start",
+ "stop",
+ "count",
)
-
-
+ print "DEBUG:", line
+ buf = format % line
for ip in ips:
- if ip_printed.has_key(ip):
- continue
- ip_printed[ip] = 1
- entries = {} # hash of access times and messages
- if apache_results.has_key(ip):
- times = apache_results[ip].keys()
- for logtime in times:
- request = apache_results[ip][logtime]
- if request.find("?system_done") != -1:
- entries[logtime] = "DONE"
- elif request.find("?profile_done") != -1:
- entries[logtime] = "DONE"
- else:
- entries[logtime] = "1" # don't really care what the filename was
-
- if syslog_results.has_key(ip):
- times = syslog_results[ip].keys()
- for logtime in times:
- request = syslog_results[ip][logtime]
- if request.find("methodcomplete") != -1:
- entries[logtime] = "DONE"
- elif request.find("Method =") != -1:
- entries[logtime] = "START"
- else:
- entries[logtime] = "1"
-
- obj = api.systems().find(ip_address=ip)
-
- if obj is not None:
- self.generate_report(entries,obj.name)
- else:
- self.generate_report(entries,ip)
-
- return True
+ elem = ip_data[ip]
+ line = (
+ ip,
+ elem["mac"],
+ elem["most_recent_target"],
+ elem["most_recent_start"], # clean up
+ elem["most_recent_stop"], # clean up
+ elem["seen_stop"]
+ )
+ print "DEBUG: ", line
+ buf = buf + "\n" + format % line
+ return buf
- #-----------------------------------------
+ # -------------------------------------------------------
- def generate_report(self,entries,name):
+ def run(self):
"""
- Given the information about transferred files and kickstart finish times, attempt
- to produce a report that most describes the state of the system.
+ Calculate and print a kickstart-status report.
"""
- # sort the access times
- rtimes = entries.keys()
- rtimes.sort()
-
- # variables for calculating kickstart state
- last_request_time = 0
- last_start_time = 0
- last_done_time = 0
- fcount = 0
-
- if len(rtimes) == 0:
- print _("%s: ?") % name
- return
-
- # for each request time the machine has made
- for rtime in rtimes:
-
- rtime = rtime
- fname = entries[rtime]
-
- if fname == "START":
- install_state = "installing"
- last_start_time = rtime
- last_request_time = rtime
- fcount = 0
- elif fname == "DONE":
- # kickstart finished
- last_done_time = rtime
- install_state = "done"
- else:
- install_state = "?"
- last_request_time = rtime
- fcount = fcount + 1
-
- # calculate elapsed time for kickstart
- elapsed_time = 0
- if install_state == "done":
- elapsed_time = int(last_done_time - last_start_time)
- else:
- elapsed_time = int(last_request_time - last_start_time)
-
- # FIXME: IP to MAC mapping where cobbler knows about it would be nice.
- display_start = time.asctime(time.localtime(last_start_time))
- display_last = time.asctime(time.localtime(last_request_time))
-
- if display_start.find(" 1969") != -1:
- display_start = "?"
- elapsed_time = "?"
-
- # print the status line for this IP address
- print "%-20s | %-15s | %-25s | %-25s | %-10s | %-6s" % (
- name,
- install_state,
- display_start,
- display_last,
- elapsed_time,
- fcount
- )
-
+
+ self.scan_logfiles()
+ self.process_results()
+ print self.get_printable_results()
+ return True
diff --git a/cobbler/api.py b/cobbler/api.py
index ef6fa8e..6f7d1b1 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -332,8 +332,8 @@ class BootAPI:
return reposync.run(name)
def status(self,mode):
- self.log("status",[mode])
- statusifier = action_status.BootStatusReport(self._config, mode)
+ self.log("status")
+ statusifier = action_status.BootStatusReport(self._config,mode)
return statusifier.run()
def import_tree(self,mirror_url,mirror_name,network_root=None,kickstart_file=None,rsync_flags=None,arch=None):
diff --git a/cobbler/item_repo.py b/cobbler/item_repo.py
index f9e9714..b87528d 100644
--- a/cobbler/item_repo.py
+++ b/cobbler/item_repo.py
@@ -66,6 +66,13 @@ class Repo(item.Item):
reposync/repotrack integration over HTTP might come later.
"""
self.mirror = mirror
+ if self.arch is None or self.arch == "":
+ if mirror.find("x86_64") != -1:
+ self.set_arch("x86_64")
+ elif mirror.find("x86") != -1 or mirror.find("i386") != -1:
+ self.set_arch("x86")
+ elif mirror.find("ia64") != -1:
+ self.set_arch("ia64")
return True
def set_keep_updated(self,keep_updated):
diff --git a/cobbler/modules/cli_misc.py b/cobbler/modules/cli_misc.py
index f8b0a7d..af2f6b2 100644
--- a/cobbler/modules/cli_misc.py
+++ b/cobbler/modules/cli_misc.py
@@ -200,7 +200,7 @@ class StatusFunction(commands.CobblerFunction):
return "status"
def run(self):
- return self.api.status("text") # no other output modes supported yet
+ return self.api.status("text") # no other output modes supported yet
########################################################
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 0f09345..7bd37ad 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -467,9 +467,6 @@ def fix_mod_python_select_submission(repos):
which doesn't seem to happen on all versions of python/mp.
"""
- if str(repos).find("Field(") == -1:
- return repos # no hack needed
-
# should be nice regex, but this is readable :)
repos = str(repos)
repos = repos.replace("'repos'","")
--
cgit
From 71d051435420f49f915aab8895d3ca4396c8ccc8 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 17 Apr 2008 16:42:50 -0400
Subject: (A) The Python-yaml open source code that we had been using
apparently didn't have copyright headers (not sure why, we absolutely
positively want them there) so I'm adding them now. Similarly, I have
included a copy of the license of the library in the docs directory.
(B) This checkin also includes some work on the status command.
---
cobbler/action_status.py | 85 ++++++++++++++++++++++++--------------------
cobbler/yaml/__init__.py | 6 ++++
cobbler/yaml/dump.py | 7 ++++
cobbler/yaml/implicit.py | 6 ++++
cobbler/yaml/inline.py | 6 ++++
cobbler/yaml/klass.py | 6 ++++
cobbler/yaml/load.py | 6 ++++
cobbler/yaml/ordered_dict.py | 7 ++++
cobbler/yaml/redump.py | 6 ++++
cobbler/yaml/stream.py | 6 ++++
cobbler/yaml/timestamp.py | 7 ++++
cobbler/yaml/ypath.py | 7 ++++
docs/pyyaml-license.htm | 78 ++++++++++++++++++++++++++++++++++++++++
scripts/install_trigger.cgi | 5 +--
14 files changed, 198 insertions(+), 40 deletions(-)
create mode 100644 docs/pyyaml-license.htm
diff --git a/cobbler/action_status.py b/cobbler/action_status.py
index cd76a39..df5062e 100644
--- a/cobbler/action_status.py
+++ b/cobbler/action_status.py
@@ -21,9 +21,18 @@ import api as cobbler_api
#from utils import _
+# ARRAY INDEXES
+MOST_RECENT_START = 0
+MOST_RECENT_STOP = 1
+MOST_RECENT_TARGET = 2
+SEEN_START = 3
+SEEN_STOP = 4
+MAC = 5
+STATE = 6
class BootStatusReport:
+
def __init__(self,config,mode):
"""
Constructor
@@ -59,30 +68,17 @@ class BootStatusReport:
ip_data = self.ip_data
if not ip_data.has_key(ip):
- ip_data[ip] = {}
+ ip_data[ip] = [ -1, -1, "?", 0, 0, "?", "?" ]
elem = ip_data[ip]
ts = float(ts)
-
- if not elem.has_key("most_recent_start"):
- elem["most_recent_start"] = -1
- if not elem.has_key("most_recent_stop"):
- elem["most_recent_stop"] = -1
- if not elem.has_key("most_recent_target"):
- elem["most_recent_target"] = "?"
- if not elem.has_key("seen_start"):
- elem["seen_start"] = 0
- if not elem.has_key("seen_stop"):
- elem["seen_stop"] = 0
- if not elem.has_key("mac"):
- elem["mac"] = "?"
-
- mrstart = elem["most_recent_start"]
- mrstop = elem["most_recent_stop"]
- mrtarg = elem["most_recent_target"]
- snstart = elem["seen_start"]
- snstop = elem["seen_stop"]
- snmac = elem["mac"]
+
+ mrstart = elem[MOST_RECENT_START]
+ mrstop = elem[MOST_RECENT_STOP]
+ mrtarg = elem[MOST_RECENT_TARGET]
+ snstart = elem[SEEN_START]
+ snstop = elem[SEEN_STOP]
+ snmac = elem[MAC]
if start_or_stop == "start":
@@ -90,30 +86,47 @@ class BootStatusReport:
mrstart = ts
mrtarg = "%s:%s" % (profile_or_system, name)
snmac = mac
- elem["seen_start"] = elem["seen_start"] + 1
+ elem[SEEN_START] = elem[SEEN_START] + 1
if start_or_stop == "stop":
if mrstop < ts:
mrstop = ts
mrtarg = "%s:%s" % (profile_or_system, name)
snmac = mac
- elem["seen_stop"] = elem["seen_stop"] + 1
+ elem[SEEN_STOP] = elem[SEEN_STOP] + 1
- elem["most_recent_start"] = mrstart
- elem["most_recent_stop"] = mrstop
- elem["most_recent_target"] = mrtarg
- elem["mac"] = mac
+ elem[MOST_RECENT_START] = mrstart
+ elem[MOST_RECENT_STOP] = mrstop
+ elem[MOST_RECENT_TARGET] = mrtarg
+ elem[MAC] = mac
# -------------------------------------------------------
def process_results(self):
# FIXME: this should update the times here
- print "DEBUG: %s" % self.ip_data
+
+ tnow = int(time.time())
+ for ip in self.ip_data.keys():
+ elem = self.ip_data[ip]
+
+ start = int(elem[MOST_RECENT_START])
+ stop = int(elem[MOST_RECENT_STOP])
+ if (stop > start):
+ elem[STATE] = "finished"
+ else:
+ delta = tnow - start
+ min = delta / 60
+ sec = delta % 60
+ if min > 100:
+ elem[STATE] = "unknown/stalled"
+ else:
+ elem[STATE] = "installing (%sm %ss)" % (min,sec)
+
return self.ip_data
def get_printable_results(self):
# ip | last mac | last target | start | stop | count
- format = "%-15s %-17s %-20s %-17s %-17s %5s"
+ format = "%-15s|%-17s|%-20s|%-17s|%-17s"
ip_data = self.ip_data
ips = ip_data.keys()
ips.sort()
@@ -122,22 +135,18 @@ class BootStatusReport:
"mac",
"target",
"start",
- "stop",
- "count",
+ "state",
)
- print "DEBUG:", line
buf = format % line
for ip in ips:
elem = ip_data[ip]
line = (
ip,
- elem["mac"],
- elem["most_recent_target"],
- elem["most_recent_start"], # clean up
- elem["most_recent_stop"], # clean up
- elem["seen_stop"]
+ elem[MAC],
+ elem[MOST_RECENT_TARGET],
+ time.ctime(elem[MOST_RECENT_START]),
+ elem[STATE]
)
- print "DEBUG: ", line
buf = buf + "\n" + format % line
return buf
diff --git a/cobbler/yaml/__init__.py b/cobbler/yaml/__init__.py
index 419d1f3..bd21b40 100644
--- a/cobbler/yaml/__init__.py
+++ b/cobbler/yaml/__init__.py
@@ -1,3 +1,9 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
__version__ = "0.32"
from load import loadFile, load, Parser, l
from dump import dump, dumpToFile, Dumper, d
diff --git a/cobbler/yaml/dump.py b/cobbler/yaml/dump.py
index b8e9d79..eb34955 100644
--- a/cobbler/yaml/dump.py
+++ b/cobbler/yaml/dump.py
@@ -1,3 +1,10 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
+
import types
import string
from types import StringType, UnicodeType, IntType, FloatType
diff --git a/cobbler/yaml/implicit.py b/cobbler/yaml/implicit.py
index 6172564..49d65e0 100644
--- a/cobbler/yaml/implicit.py
+++ b/cobbler/yaml/implicit.py
@@ -1,3 +1,9 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
import re
import string
from timestamp import timestamp, matchTime
diff --git a/cobbler/yaml/inline.py b/cobbler/yaml/inline.py
index 8e647de..d4f6439 100644
--- a/cobbler/yaml/inline.py
+++ b/cobbler/yaml/inline.py
@@ -1,3 +1,9 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
import re
import string
diff --git a/cobbler/yaml/klass.py b/cobbler/yaml/klass.py
index edcf5a8..c182fcf 100644
--- a/cobbler/yaml/klass.py
+++ b/cobbler/yaml/klass.py
@@ -1,3 +1,9 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
import new
import re
diff --git a/cobbler/yaml/load.py b/cobbler/yaml/load.py
index 259178d..54931d6 100644
--- a/cobbler/yaml/load.py
+++ b/cobbler/yaml/load.py
@@ -1,3 +1,9 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
import re, string
from implicit import convertImplicit
from inline import InlineTokenizer
diff --git a/cobbler/yaml/ordered_dict.py b/cobbler/yaml/ordered_dict.py
index b3788b7..5bc2e3e 100644
--- a/cobbler/yaml/ordered_dict.py
+++ b/cobbler/yaml/ordered_dict.py
@@ -1,3 +1,10 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
+
# This is extremely crude implementation of an OrderedDict.
# If you know of a better implementation, please send it to
# the author Steve Howell. You can find my email via
diff --git a/cobbler/yaml/redump.py b/cobbler/yaml/redump.py
index 56ea958..eefd68e 100644
--- a/cobbler/yaml/redump.py
+++ b/cobbler/yaml/redump.py
@@ -1,3 +1,9 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
from ordered_dict import OrderedDict
from load import Parser
from dump import Dumper
diff --git a/cobbler/yaml/stream.py b/cobbler/yaml/stream.py
index cc78c4b..dcd65c3 100644
--- a/cobbler/yaml/stream.py
+++ b/cobbler/yaml/stream.py
@@ -1,3 +1,9 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
import re
import string
diff --git a/cobbler/yaml/timestamp.py b/cobbler/yaml/timestamp.py
index abcb2e6..5c522f6 100644
--- a/cobbler/yaml/timestamp.py
+++ b/cobbler/yaml/timestamp.py
@@ -1,3 +1,10 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
+
import time, re, string
from types import ListType, TupleType
diff --git a/cobbler/yaml/ypath.py b/cobbler/yaml/ypath.py
index 51d9d2f..b183a23 100644
--- a/cobbler/yaml/ypath.py
+++ b/cobbler/yaml/ypath.py
@@ -1,3 +1,10 @@
+"""
+pyyaml legacy
+Copyright (c) 2001 Steve Howell and Friends; All Rights Reserved
+(see open source license information in docs/ directory)
+"""
+
+
from types import ListType, StringType, IntType, DictType, InstanceType
import re
from urllib import quote
diff --git a/docs/pyyaml-license.htm b/docs/pyyaml-license.htm
new file mode 100644
index 0000000..6993ea9
--- /dev/null
+++ b/docs/pyyaml-license.htm
@@ -0,0 +1,78 @@
+NOTE: the directory ".../yaml" contains the a derivative
+of the PyYaml library. It follows the license below
+and has been modified to disable the YAML "anchor"
+behavior.
+
+========================================================
+
+A. HISTORY OF THE SOFTWARE
+==========================
+
+The Python library for YAML was started by Steve Howell in
+February 2002. Steve is the primary author of the project,
+but others have contributed. See the README for more on
+the project. The term "PyYaml" refers to the entire
+distribution of this library, including examples, documentation,
+and test files, as well as the core implementation.
+
+This library is intended for general use, and the license
+below protects the "open source" nature of the library. The
+license does, however, allow for use of the library in
+commercial applications as well, subject to the terms
+and conditions listed. The license below is a minor
+rewrite of the Python 2.2 license, with no substantive
+differences.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PyYaml
+===============================================================
+
+LICENSE AGREEMENT FOR PyYaml
+----------------------------
+
+1. This LICENSE AGREEMENT is between Stephen S. Howell ("Author"),
+and the Individual or Organization ("Licensee") accessing and
+otherwise using PyYaml software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, Author
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use PyYaml
+alone or in any derivative version, provided, however, that Author's
+License Agreement and Author's notice of copyright, i.e., "Copyright (c)
+2001 Steve Howell and Friends; All Rights Reserved" are never removed
+from PyYaml, and are included in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates PyYaml or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to PyYaml.
+
+4. Author is making PyYaml available to Licensee on an "AS IS"
+basis. Author MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, Author MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PyYaml WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. Author SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+2.2 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.2,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between Author and
+Licensee. This License Agreement does not grant permission to use Author
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using PyYaml, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
diff --git a/scripts/install_trigger.cgi b/scripts/install_trigger.cgi
index 493591f..c8d065b 100644
--- a/scripts/install_trigger.cgi
+++ b/scripts/install_trigger.cgi
@@ -42,8 +42,9 @@ def parse_query():
form = cgi.parse()
mac = "?"
- if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
- devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
+
+ if os.environ.has_key("X-RHN-Provisioning-MAC-0"):
+ devicepair = os.environ["X-RHN-Provisioning-MAC-0"]
mac = devicepair.split()[1].strip()
ip = "?"
--
cgit
From 7b33e5feeddd51f08d3b5377c0bacf8ca23a0915 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 17 Apr 2008 17:20:52 -0400
Subject: Fix install trigger back since the modifications also were not
pulling in the MAC in F9.
---
scripts/install_trigger.cgi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/install_trigger.cgi b/scripts/install_trigger.cgi
index c8d065b..abe5cf6 100644
--- a/scripts/install_trigger.cgi
+++ b/scripts/install_trigger.cgi
@@ -43,8 +43,8 @@ def parse_query():
mac = "?"
- if os.environ.has_key("X-RHN-Provisioning-MAC-0"):
- devicepair = os.environ["X-RHN-Provisioning-MAC-0"]
+ if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
+ devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
mac = devicepair.split()[1].strip()
ip = "?"
--
cgit
From ad17059740c03a4e503867d4c39bc3647502287c Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 18 Apr 2008 11:44:57 -0400
Subject: kssendmac does not make this information available at the time of
this wget
---
cobbler/remote.py | 4 ++--
scripts/install_trigger.cgi | 16 +++++-----------
triggers/status_post.trigger | 5 ++---
triggers/status_pre.trigger | 5 ++---
4 files changed, 11 insertions(+), 19 deletions(-)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index b606bbc..0cbaf22 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -230,7 +230,7 @@ class CobblerXMLRPCInterface:
systems.add(obj,save=True,with_triggers=False,with_sync=False,quick_pxe_update=True)
return True
- def run_install_triggers(self,mode,objtype,name,mac,ip,token=None):
+ def run_install_triggers(self,mode,objtype,name,ip,token=None):
"""
This is a feature used to run the pre/post install triggers.
@@ -249,7 +249,7 @@ class CobblerXMLRPCInterface:
# time if reinstalling all of a cluster all at once.
# we can do that at "cobbler check" time.
- utils.run_triggers(None, "/var/lib/cobbler/triggers/install/%s/*" % mode, additional=[objtype,name,mac,ip])
+ utils.run_triggers(None, "/var/lib/cobbler/triggers/install/%s/*" % mode, additional=[objtype,name,ip])
return True
diff --git a/scripts/install_trigger.cgi b/scripts/install_trigger.cgi
index abe5cf6..b83ff57 100644
--- a/scripts/install_trigger.cgi
+++ b/scripts/install_trigger.cgi
@@ -41,12 +41,6 @@ def parse_query():
form = cgi.parse()
- mac = "?"
-
- if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
- devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
- mac = devicepair.split()[1].strip()
-
ip = "?"
if os.environ.has_key("REMOTE_ADDR"):
ip = os.environ["REMOTE_ADDR"]
@@ -64,15 +58,15 @@ def parse_query():
if form.has_key("mode"):
mode = form["mode"][0]
- return (mode,objtype,name,mac,ip)
+ return (mode,objtype,name,ip)
-def invoke(mode,objtype,name,mac,ip):
+def invoke(mode,objtype,name,ip):
"""
Determine if this feature is enabled.
"""
xmlrpc_server = ServerProxy(XMLRPC_SERVER)
- print xmlrpc_server.run_install_triggers(mode,objtype,name,mac,ip)
+ print xmlrpc_server.run_install_triggers(mode,objtype,name,ip)
return True
@@ -87,7 +81,7 @@ def header():
if __name__ == "__main__":
cgitb.enable(format='text')
header()
- (mode,objtype,name,mac,ip) = parse_query()
- invoke(mode,objtype,name,mac,ip)
+ (mode,objtype,name,ip) = parse_query()
+ invoke(mode,objtype,name,ip)
diff --git a/triggers/status_post.trigger b/triggers/status_post.trigger
index 32934c8..753cceb 100644
--- a/triggers/status_post.trigger
+++ b/triggers/status_post.trigger
@@ -6,11 +6,10 @@ import time
objtype = sys.argv[1] # "system" or "profile"
name = sys.argv[2] # name of system or profile
-mac = sys.argv[3] # mac or "?"
-ip = sys.argv[4] # ip or "?"
+ip = sys.argv[3] # ip or "?"
fd = open("/var/log/cobbler/install.log","a+")
-fd.write("%s\t%s\t%s\t%s\tstop\t%s\n" % (objtype,name,mac,ip,time.time()))
+fd.write("%s\t%s\t%s\t%s\tstop\t%s\n" % (objtype,name,ip,time.time()))
fd.close()
sys.exit(0)
diff --git a/triggers/status_pre.trigger b/triggers/status_pre.trigger
index 385beaa..8d6f6b6 100644
--- a/triggers/status_pre.trigger
+++ b/triggers/status_pre.trigger
@@ -6,11 +6,10 @@ import time
objtype = sys.argv[1] # "system" or "profile"
name = sys.argv[2] # name of system or profile
-mac = sys.argv[3] # mac or "?"
-ip = sys.argv[4] # ip or "?"
+ip = sys.argv[3] # ip or "?"
fd = open("/var/log/cobbler/install.log","a+")
-fd.write("%s\t%s\t%s\t%s\tstart\t%s\n" % (objtype,name,mac,ip,time.time()))
+fd.write("%s\t%s\t%s\t%s\tstart\t%s\n" % (objtype,name,ip,time.time()))
fd.close()
sys.exit(0)
--
cgit
From b15ca0fe01a01ee6792c857e766642d9d50ab760 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 18 Apr 2008 12:03:40 -0400
Subject: Finish removing mac from new install tracking
---
cobbler/action_status.py | 20 ++++++-------------
cobbler/modules/authn_testing.py | 42 ++++++++++++++++++++++++++++++++++++++++
triggers/status_post.trigger | 2 +-
triggers/status_pre.trigger | 2 +-
4 files changed, 50 insertions(+), 16 deletions(-)
create mode 100644 cobbler/modules/authn_testing.py
diff --git a/cobbler/action_status.py b/cobbler/action_status.py
index df5062e..79f9083 100644
--- a/cobbler/action_status.py
+++ b/cobbler/action_status.py
@@ -27,8 +27,7 @@ MOST_RECENT_STOP = 1
MOST_RECENT_TARGET = 2
SEEN_START = 3
SEEN_STOP = 4
-MAC = 5
-STATE = 6
+STATE = 5
class BootStatusReport:
@@ -58,17 +57,17 @@ class BootStatusReport:
tokens = line.split()
if len(tokens) == 0:
continue
- (profile_or_system, name, mac, ip, start_or_stop, ts) = tokens
- self.catalog(profile_or_system,name,mac,ip,start_or_stop,ts)
+ (profile_or_system, name, ip, start_or_stop, ts) = tokens
+ self.catalog(profile_or_system,name,ip,start_or_stop,ts)
fd.close()
# ------------------------------------------------------
- def catalog(self,profile_or_system,name,mac,ip,start_or_stop,ts):
+ def catalog(self,profile_or_system,name,ip,start_or_stop,ts):
ip_data = self.ip_data
if not ip_data.has_key(ip):
- ip_data[ip] = [ -1, -1, "?", 0, 0, "?", "?" ]
+ ip_data[ip] = [ -1, -1, "?", 0, 0, "?" ]
elem = ip_data[ip]
ts = float(ts)
@@ -78,27 +77,23 @@ class BootStatusReport:
mrtarg = elem[MOST_RECENT_TARGET]
snstart = elem[SEEN_START]
snstop = elem[SEEN_STOP]
- snmac = elem[MAC]
if start_or_stop == "start":
if mrstart < ts:
mrstart = ts
mrtarg = "%s:%s" % (profile_or_system, name)
- snmac = mac
elem[SEEN_START] = elem[SEEN_START] + 1
if start_or_stop == "stop":
if mrstop < ts:
mrstop = ts
mrtarg = "%s:%s" % (profile_or_system, name)
- snmac = mac
elem[SEEN_STOP] = elem[SEEN_STOP] + 1
elem[MOST_RECENT_START] = mrstart
elem[MOST_RECENT_STOP] = mrstop
elem[MOST_RECENT_TARGET] = mrtarg
- elem[MAC] = mac
# -------------------------------------------------------
@@ -125,14 +120,12 @@ class BootStatusReport:
return self.ip_data
def get_printable_results(self):
- # ip | last mac | last target | start | stop | count
- format = "%-15s|%-17s|%-20s|%-17s|%-17s"
+ format = "%-15s|%-20s|%-17s|%-17s"
ip_data = self.ip_data
ips = ip_data.keys()
ips.sort()
line = (
"ip",
- "mac",
"target",
"start",
"state",
@@ -142,7 +135,6 @@ class BootStatusReport:
elem = ip_data[ip]
line = (
ip,
- elem[MAC],
elem[MOST_RECENT_TARGET],
time.ctime(elem[MOST_RECENT_START]),
elem[STATE]
diff --git a/cobbler/modules/authn_testing.py b/cobbler/modules/authn_testing.py
new file mode 100644
index 0000000..cd74cdf
--- /dev/null
+++ b/cobbler/modules/authn_testing.py
@@ -0,0 +1,42 @@
+"""
+Authentication module that denies everything.
+Unsafe demo. Allows anyone in with testing/testing.
+
+Copyright 2007-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import distutils.sysconfig
+import sys
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "authn"
+
+def authenticate(api_handle,username,password):
+ """
+ Validate a username/password combo, returning True/False
+
+ Thanks to http://trac.edgewall.org/ticket/845 for supplying
+ the algorithm info.
+ """
+
+ if username == "testing" and password == "testing":
+ return True
+ return False
+
+
diff --git a/triggers/status_post.trigger b/triggers/status_post.trigger
index 753cceb..f69afe2 100644
--- a/triggers/status_post.trigger
+++ b/triggers/status_post.trigger
@@ -9,7 +9,7 @@ name = sys.argv[2] # name of system or profile
ip = sys.argv[3] # ip or "?"
fd = open("/var/log/cobbler/install.log","a+")
-fd.write("%s\t%s\t%s\t%s\tstop\t%s\n" % (objtype,name,ip,time.time()))
+fd.write("%s\t%s\t%s\tstop\t%s\n" % (objtype,name,ip,time.time()))
fd.close()
sys.exit(0)
diff --git a/triggers/status_pre.trigger b/triggers/status_pre.trigger
index 8d6f6b6..95df1fb 100644
--- a/triggers/status_pre.trigger
+++ b/triggers/status_pre.trigger
@@ -9,7 +9,7 @@ name = sys.argv[2] # name of system or profile
ip = sys.argv[3] # ip or "?"
fd = open("/var/log/cobbler/install.log","a+")
-fd.write("%s\t%s\t%s\t%s\tstart\t%s\n" % (objtype,name,ip,time.time()))
+fd.write("%s\t%s\t%s\tstart\t%s\n" % (objtype,name,ip,time.time()))
fd.close()
sys.exit(0)
--
cgit
From efbcc041464733e90af670a5d1dfe13e70aaa05c Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 18 Apr 2008 17:31:26 -0400
Subject: Kickstarts are now dynamically generated by mod_python, CGI's now
fall under mod_python, kickstart templating code now moved out of sync
function.
---
CHANGELOG | 4 +
MANIFEST.in | 7 +-
Makefile | 1 +
cobbler.spec | 5 +-
cobbler/action_litesync.py | 13 +-
cobbler/action_sync.py | 365 +-------------------------------------------
cobbler/api.py | 11 +-
cobbler/kickgen.py | 272 +++++++++++++++++++++++++++++++++
cobbler/remote.py | 8 +
cobbler/services.py | 94 ++++++++++++
cobbler/settings.py | 5 +-
cobbler/webui/master.py | 4 +-
config/cobbler_svc.conf | 12 ++
config/settings | 5 +-
legacy/change_profile.cgi | 86 +++++++++++
legacy/findks.cgi | 153 +++++++++++++++++++
legacy/install_trigger.cgi | 87 +++++++++++
legacy/nopxe.cgi | 80 ++++++++++
legacy/register_mac.cgi | 105 +++++++++++++
legacy/watcher.py | 63 ++++++++
scripts/change_profile.cgi | 86 -----------
scripts/findks.cgi | 153 -------------------
scripts/install_trigger.cgi | 87 -----------
scripts/nopxe.cgi | 80 ----------
scripts/register_mac.cgi | 105 -------------
scripts/services.py | 67 ++++++++
scripts/watcher.py | 63 --------
setup.py | 9 +-
28 files changed, 1067 insertions(+), 963 deletions(-)
create mode 100644 cobbler/kickgen.py
create mode 100644 cobbler/services.py
create mode 100644 config/cobbler_svc.conf
create mode 100755 legacy/change_profile.cgi
create mode 100755 legacy/findks.cgi
create mode 100644 legacy/install_trigger.cgi
create mode 100755 legacy/nopxe.cgi
create mode 100755 legacy/register_mac.cgi
create mode 100755 legacy/watcher.py
delete mode 100755 scripts/change_profile.cgi
delete mode 100755 scripts/findks.cgi
delete mode 100644 scripts/install_trigger.cgi
delete mode 100755 scripts/nopxe.cgi
delete mode 100755 scripts/register_mac.cgi
create mode 100755 scripts/services.py
delete mode 100755 scripts/watcher.py
diff --git a/CHANGELOG b/CHANGELOG
index f721aa3..a97dd5e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -26,6 +26,10 @@ Cobbler CHANGELOG
- change default authentication to deny_all, xmlrpc_rw_enabled now on by default
- additional fix for mod_python select box submissions
- set repo arch if found in the URL and no --arch is specified
+- CGI scripts have been moved under mod_python for speed/consolidation
+- kickstart templates are now evaluated dynamically
+- optional MAC registration is now built-in to requesting kickstarts
+- legacy static file generation from /var/www/cobbler removed
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/MANIFEST.in b/MANIFEST.in
index 12f9f9e..644c0c2 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -17,12 +17,7 @@ include docs/cobbler.1.gz
include docs/cobbler.html
include docs/wui.html
include COPYING AUTHORS README CHANGELOG
-include scripts/watcher.py
-include scripts/index.py
-include scripts/cobblerd
-include scripts/findks.cgi
-include scripts/nopxe.cgi
-include scripts/install_trigger.cgi
+include scripts/*.py
include snippets/*
recursive-include po *.pot
recursive-include po *.po
diff --git a/Makefile b/Makefile
index b8e5d0a..6287f5d 100644
--- a/Makefile
+++ b/Makefile
@@ -51,6 +51,7 @@ devinstall:
chown -R apache /var/www/cobbler
chown -R apache /var/www/cgi-bin/cobbler
chmod -R +x /var/www/cobbler/web
+ chmod -R +x /var/www/cobbler/svc
webtest: devinstall
/sbin/service cobblerd restart
diff --git a/cobbler.spec b/cobbler.spec
index 5e63f48..7b4e525 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -83,8 +83,8 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%defattr(755,apache,apache)
%dir /var/www/cobbler/web/
/var/www/cobbler/web/*.py*
-%dir /var/www/cgi-bin/cobbler/
-/var/www/cgi-bin/cobbler/*.cgi
+%dir /var/www/cobbler/svc/
+/var/www/cobbler/svc/*.py*
%defattr(755,apache,apache)
%dir /usr/share/cobbler/webui_templates
@@ -195,6 +195,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
* Tue Apr 08 2008 Michael DeHaan - 0.9.0-1
- Upstream changes (see CHANGELOG)
- packaged /etc/cobbler/users.conf
+- remaining CGI replaced with mod_python
* Tue Apr 08 2008 Michael DeHaan - 0.8.3-2
- Upstream changes (see CHANGELOG)
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index bc7ffb2..3a2de8e 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -82,11 +82,7 @@ class BootLiteSync:
if profile is None:
raise CX(_("error in profile lookup"))
# rebuild profile_list YAML file in webdir
- self.sync.write_listings()
- # add profiles/$name YAML file in webdir
self.sync.write_profile_file(profile)
- # generate kickstart for kickstarts/$name/ks.cfg in webdir
- self.sync.validate_kickstart_for_specific_profile(profile)
# rebuild the yum configuration files for any attached repos
self.sync.retemplate_yum_repos(profile,True)
# cascade sync
@@ -98,8 +94,6 @@ class BootLiteSync:
self.add_single_system(k.name)
def remove_single_profile(self, name):
- # rebuild profile_list YAML file in webdir
- self.sync.write_listings()
# delete profiles/$name file in webdir
utils.rmfile(os.path.join(self.settings.webdir, "profiles", name))
# delete contents on kickstarts/$name directory in webdir
@@ -109,7 +103,7 @@ class BootLiteSync:
system = self.systems.find(name=name)
if system is None:
raise CX(_("error in system lookup for %s") % name)
- self.sync.write_all_system_files(system,True)
+ self.sync.write_all_system_files(system)
def add_single_system(self, name):
# get the system object:
@@ -119,19 +113,14 @@ class BootLiteSync:
# rebuild system_list file in webdir
self.sync.regen_ethers() # /etc/ethers, for dnsmasq & rarpd
self.sync.regen_hosts() # /var/lib/cobbler/cobbler_hosts, pretty much for dnsmasq
- self.sync.write_listings()
# write the PXE and YAML files for the system
self.sync.write_all_system_files(system)
# per system kickstarts
- self.sync.validate_kickstart_for_specific_system(system)
- # rebuild the yum configuration files for any attached repos
self.sync.retemplate_yum_repos(system,False)
def remove_single_system(self, name):
bootloc = utils.tftpboot_location()
system_record = self.systems.find(name=name)
- # rebuild system_list file in webdir
- self.sync.write_listings()
# delete system YAML file in systems/$name in webdir
utils.rmfile(os.path.join(self.settings.webdir, "systems", name))
# delete contents of kickstarts_sys/$name in webdir
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 5b7b546..aa53d12 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -27,7 +27,7 @@ import errno
import utils
from cexceptions import *
import templar
-
+import kickgen
import item_distro
import item_profile
@@ -57,6 +57,7 @@ class BootSync:
self.settings = config.settings()
self.repos = config.repos()
self.templar = templar.Templar(config)
+ self.kickgen = kickgen.KickGen(config)
self.bootloc = utils.tftpboot_location()
def run(self):
@@ -82,9 +83,9 @@ class BootSync:
self.clean_trees()
self.copy_bootloaders()
self.copy_distros()
+ for x in self.systems:
+ self.write_all_system_files(x)
self.retemplate_all_yum_repos()
- self.validate_kickstarts()
- self.build_trees()
if self.settings.manage_dhcp:
# these functions DRT for ISC or dnsmasq
self.write_dhcp_file()
@@ -278,7 +279,7 @@ class BootSync:
if not x.endswith(".py"):
utils.rmfile(path)
if os.path.isdir(path):
- if not x in ["web", "webui", "localmirror","repo_mirror","ks_mirror","kickstarts","kickstarts_sys","distros","images","systems","profiles","links","repo_profile","repo_system"] :
+ if not x in ["web", "webui", "localmirror","repo_mirror","ks_mirror","images","links","repo_profile","repo_system","svc"] :
# delete directories that shouldn't exist
utils.rmtree(path)
if x in ["kickstarts","kickstarts_sys","images","systems","distros","profiles","repo_profile","repo_system"]:
@@ -324,294 +325,6 @@ class BootSync:
else:
utils.copyfile(initrd, os.path.join(distro_dir, b_initrd))
- def validate_kickstarts(self):
- """
- Similar to what we do for distros, ensure all the kickstarts
- in conf file are valid. kickstarts are referenced by URL
- (http or ftp), can stay as is. kickstarts referenced by absolute
- path (i.e. are files path) will be mirrored over http.
- """
-
- self.validate_kickstarts_per_profile()
- self.validate_kickstarts_per_system()
- return True
-
- def validate_kickstarts_per_profile(self):
- """
- Koan provisioning (Virt + auto-ks) needs kickstarts
- per profile. Validate them as needed. Local kickstarts
- get template substitution. Since http:// kickstarts might
- get generated via magic URLs, those are *not* substituted.
- NFS kickstarts are also not substituted when referenced
- by NFS URL's as we don't copy those files over to the cobbler
- directories. They are supposed to be live such that an
- admin can update those without needing to run 'sync' again.
-
- NOTE: kickstart only uses the web directory (if it uses them at all)
- """
-
- for g in self.profiles:
- print _("sync profile: %s") % g.name
- self.validate_kickstart_for_specific_profile(g)
-
- def validate_kickstart_for_specific_profile(self,g):
- distro = g.get_conceptual_parent()
- meta = utils.blender(self.api, False, g)
- if distro is None:
- raise CX(_("profile %(profile)s references missing distro %(distro)s") % { "profile" : g.name, "distro" : g.distro })
- kickstart_path = utils.find_kickstart(meta["kickstart"])
- if kickstart_path is not None and os.path.exists(kickstart_path):
- # the input is an *actual* file, hence we have to copy it
- copy_path = os.path.join(
- self.settings.webdir,
- "kickstarts", # profile kickstarts go here
- g.name
- )
- utils.mkdir(copy_path)
- dest = os.path.join(copy_path, "ks.cfg")
- try:
- meta = utils.blender(self.api, False, g)
- ksmeta = meta["ks_meta"]
- del meta["ks_meta"]
- meta.update(ksmeta) # make available at top level
- meta["yum_repo_stanza"] = self.generate_repo_stanza(g,True)
- meta["yum_config_stanza"] = self.generate_config_stanza(g,True)
- meta["kickstart_done"] = self.generate_kickstart_signal(0, g, None)
- meta["kickstart_start"] = self.generate_kickstart_signal(1, g, None)
- meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
- kfile = open(kickstart_path)
- self.templar.render(kfile, meta, dest, g)
- kfile.close()
- except:
- traceback.print_exc() # leave this in, for now...
- msg = "err_kickstart2"
- raise CX(_("Error while rendering kickstart file %(src)s to %(dest)s") % { "src" : kickstart_path, "dest" : dest })
-
- def generate_kickstart_signal(self, is_pre=0, profile=None, system=None):
- """
- Do things that we do at the start/end of kickstarts...
- * start: signal the status watcher we're starting
- * end: signal the status watcher we're done
- * end: disable PXE if needed
- * end: save the original kickstart file for debug
- """
-
- # FIXME: watcher is more of a request than a packaged file
- # we should eventually package something and let it do something important"
-
- nopxe = "\nwget \"http://%s/cgi-bin/cobbler/nopxe.cgi?system=%s\""
- saveks = "\nwget \"http://%s/cobbler/%s/%s/ks.cfg\" -O /root/cobbler.ks"
- runpost = "\nwget \"http://%s/cgi-bin/cobbler/install_trigger.cgi?mode=post&%s=%s\""
- runpre = "\nwget \"http://%s/cgi-bin/cobbler/install_trigger.cgi?mode=pre&%s=%s\""
-
- what = "profile"
- blend_this = profile
- if system:
- what = "system"
- blend_this = system
-
- blended = utils.blender(self.api, False, blend_this)
- kickstart = blended.get("kickstart",None)
-
- buf = ""
- srv = blended["http_server"]
- if system is not None:
- if not is_pre:
- if str(self.settings.pxe_just_once).upper() in [ "1", "Y", "YES", "TRUE" ]:
- buf = buf + nopxe % (srv, system.name)
- if kickstart and os.path.exists(kickstart):
- buf = buf + saveks % (srv, "kickstarts_sys", system.name)
- if self.settings.run_install_trigger:
- buf = buf + runpost % (srv, what, system.name)
- else:
- if self.settings.run_install_trigger:
- buf = buf + runpre % (srv, what, system.name)
-
- else:
- if not is_pre:
- if kickstart and os.path.exists(kickstart):
- buf = buf + saveks % (srv, "kickstarts", profile.name)
- if self.settings.run_install_trigger:
- buf = buf + runpost % (srv, what, profile.name)
- else:
- if self.settings.run_install_trigger:
- buf = buf + runpre % (srv, what, profile.name)
-
- return buf
-
- def get_repo_segname(self, is_profile):
- if is_profile:
- return "repos_profile"
- else:
- return "repos_system"
-
- def generate_repo_stanza(self, obj, is_profile=True):
-
- """
- Automatically attaches yum repos to profiles/systems in kickstart files
- that contain the magic $yum_repo_stanza variable.
- """
-
- buf = ""
- blended = utils.blender(self.api, False, obj)
- configs = self.get_repo_filenames(obj,is_profile)
- repos = self.repos
-
- for c in configs:
- name = c.split("/")[-1].replace(".repo","")
- (is_core, baseurl) = self.analyze_repo_config(c)
- for repo in repos:
- if repo.name == name:
- if not repo.yumopts.has_key('enabled') or repo.yumopts['enabled'] == '1':
- buf = buf + "repo --name=%s --baseurl=%s\n" % (name, baseurl)
- return buf
-
- def analyze_repo_config(self, filename):
- fd = open(filename)
- data = fd.read()
- lines = data.split("\n")
- ret = False
- baseurl = None
- for line in lines:
- if line.find("ks_mirror") != -1:
- ret = True
- if line.find("baseurl") != -1:
- first, baseurl = line.split("=")
- fd.close()
- return (ret, baseurl)
-
- def get_repo_baseurl(self, server, repo_name, is_repo_mirror=True):
- """
- Construct the URL to a repo definition.
- """
- if is_repo_mirror:
- return "http://%s/cobbler/repo_mirror/%s" % (server, repo_name)
- else:
- return "http://%s/cobbler/ks_mirror/config/%s" % (server, repo_name)
-
- def get_repo_filenames(self, obj, is_profile=True):
- """
- For a given object, return the paths to repo configuration templates
- that will be used to generate per-object repo configuration files and
- baseurls
- """
-
- blended = utils.blender(self.api, False, obj)
- urlseg = self.get_repo_segname(is_profile)
-
- topdir = "%s/%s/%s/*.repo" % (self.settings.webdir, urlseg, blended["name"])
- files = glob.glob(topdir)
- return files
-
-
- def generate_config_stanza(self, obj, is_profile=True):
-
- """
- Add in automatic to configure /etc/yum.repos.d on the remote system
- if the kickstart file contains the magic $yum_config_stanza.
- """
-
- if not self.settings.yum_post_install_mirror:
- return ""
-
- urlseg = self.get_repo_segname(is_profile)
-
- distro = obj.get_conceptual_parent()
- if not is_profile:
- distro = distro.get_conceptual_parent()
-
- blended = utils.blender(self.api, False, obj)
- configs = self.get_repo_filenames(obj, is_profile)
- buf = ""
-
- # for each kickstart template we have rendered ...
- for c in configs:
-
- name = c.split("/")[-1].replace(".repo","")
- # add the line to create the yum config file on the target box
- conf = self.get_repo_config_file(blended["http_server"],urlseg,blended["name"],name)
- buf = buf + "wget \"%s\" --output-document=/etc/yum.repos.d/%s.repo\n" % (conf, name)
-
- return buf
-
- def get_repo_config_file(self,server,urlseg,obj_name,repo_name):
- """
- Construct the URL to a repo config file that is usable in kickstart
- for use with yum. This is different than the templates cobbler reposync
- creates, as this file will allow the server to migrate and have different
- variables for different subnets/profiles/etc.
- """
- return "http://%s/cblr/%s/%s/%s.repo" % (server,urlseg,obj_name,repo_name)
-
- def validate_kickstarts_per_system(self):
- """
- PXE provisioning needs kickstarts evaluated per system.
- Profiles would normally be sufficient, but not in cases
- such as static IP, where we want to be able to do templating
- on a system basis.
-
- NOTE: kickstart only uses the web directory (if it uses them at all)
- """
-
- for s in self.systems:
- print _("sync system: %s") % s.name
- self.validate_kickstart_for_specific_system(s)
-
- def validate_kickstart_for_specific_system(self,s):
- profile = s.get_conceptual_parent()
- if profile is None:
- raise CX(_("system %(system)s references missing profile %(profile)s") % { "system" : s.name, "profile" : s.profile })
- distro = profile.get_conceptual_parent()
- meta = utils.blender(self.api, False, s)
- kickstart_path = utils.find_kickstart(meta["kickstart"])
- if kickstart_path and os.path.exists(kickstart_path):
- copy_path = os.path.join(self.settings.webdir,
- "kickstarts_sys", # system kickstarts go here
- s.name
- )
- utils.mkdir(copy_path)
- dest = os.path.join(copy_path, "ks.cfg")
- try:
- ksmeta = meta["ks_meta"]
- del meta["ks_meta"]
- meta.update(ksmeta) # make available at top level
- meta["yum_repo_stanza"] = self.generate_repo_stanza(s, False)
- meta["yum_config_stanza"] = self.generate_config_stanza(s, False)
- meta["kickstart_done"] = self.generate_kickstart_signal(0, profile, s)
- meta["kickstart_start"] = self.generate_kickstart_signal(1, profile, s)
- meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
- kfile = open(kickstart_path)
- self.templar.render(kfile, meta, dest, s)
- kfile.close()
- except:
- traceback.print_exc()
- raise CX(_("Error templating file %(src)s to %(dest)s") % { "src" : meta["kickstart"], "dest" : dest })
-
- def build_trees(self):
- """
- Now that kernels and initrds are copied and kickstarts are all valid,
- build the pxelinux.cfg tree, which contains a directory for each
- configured IP or MAC address. Also build a tree for Virt info.
-
- NOTE: some info needs to go in TFTP and HTTP directories, but not all.
- Usually it's just one or the other.
-
- """
-
- self.write_listings()
-
- # create pxelinux.cfg under tftpboot
- # and file for each MAC or IP (hex encoded 01-XX-XX-XX-XX-XX-XX)
-
- for d in self.distros:
- self.write_distro_file(d)
-
- for p in self.profiles:
- self.write_profile_file(p)
-
- for system in self.systems:
- self.write_all_system_files(system)
-
def retemplate_all_yum_repos(self):
for p in self.profiles:
self.retemplate_yum_repos(p,True)
@@ -619,8 +332,6 @@ class BootSync:
self.retemplate_yum_repos(system,False)
def retemplate_yum_repos(self,obj,is_profile):
- # FIXME: blender could use caching for performance
- # FIXME: make stanza generation code load stuff from the right place
"""
Yum repository management files are in self.settings.webdir/repo_mirror/$name/config.repo
and also potentially in listed in the source_repos structure of the distro object, however
@@ -670,7 +381,7 @@ class BootSync:
self.templar.render(infile_data, blended, outfile, None)
- def write_all_system_files(self,system,just_edit_pxe=False):
+ def write_all_system_files(self,system):
profile = system.get_conceptual_parent()
if profile is None:
@@ -713,11 +424,6 @@ class BootSync:
# ensure the file doesn't exist
utils.rmfile(f2)
- if not just_edit_pxe:
- # allows netboot-disable to be highly performant
- # by not invoking the Cheetah engine
- self.write_system_file(f3,system)
-
counter = counter + 1
@@ -849,9 +555,9 @@ class BootSync:
if kickstart_path is not None and kickstart_path != "":
if system is not None and kickstart_path.startswith("/"):
- kickstart_path = "http://%s/cblr/kickstarts_sys/%s/ks.cfg" % (blended["http_server"], system.name)
+ kickstart_path = "http://%s/cblr/svc/?op=ks&system=%s" % (blended["http_server"], system.name)
elif kickstart_path.startswith("/") or kickstart_path.find("/cobbler/kickstarts/") != -1:
- kickstart_path = "http://%s/cblr/kickstarts/%s/ks.cfg" % (blended["http_server"], profile.name)
+ kickstart_path = "http://%s/cblr/svc/?op=ks&profile=%s" % (blended["http_server"], profile.name)
if distro.breed is None or distro.breed == "redhat":
append_line = "%s ks=%s" % (append_line, kickstart_path)
@@ -884,60 +590,5 @@ class BootSync:
return buffer
- def write_listings(self):
- """
- Creates a very simple index of available systems and profiles
- that cobbler knows about. Just the names, no details.
- """
- names1 = [x.name for x in self.profiles]
- names2 = [x.name for x in self.systems]
- data1 = yaml.dump(names1)
- data2 = yaml.dump(names2)
- fd1 = open(os.path.join(self.settings.webdir, "profile_list"), "w+")
- fd2 = open(os.path.join(self.settings.webdir, "system_list"), "w+")
- fd1.write(data1)
- fd2.write(data2)
- fd1.close()
- fd2.close()
-
- def write_distro_file(self,distro):
- """
- Create distro information for koan install
- """
- blended = utils.blender(self.api, True, distro)
- filename = os.path.join(self.settings.webdir,"distros",distro.name)
- fd = open(filename, "w+")
- fd.write(yaml.dump(blended))
- fd.close()
-
- def write_profile_file(self,profile):
- """
- Create profile information for virt install
-
- NOTE: relevant to http only
- """
-
- blended = utils.blender(self.api, True, profile)
- filename = os.path.join(self.settings.webdir,"profiles",profile.name)
- fd = open(filename, "w+")
- if blended.has_key("kickstart") and blended["kickstart"].startswith("/"):
- # write the file location as needed by koan
- blended["kickstart"] = "http://%s/cblr/kickstarts/%s/ks.cfg" % (blended["http_server"], profile.name)
- fd.write(yaml.dump(blended))
- fd.close()
-
- def write_system_file(self,filename,system):
- """
- Create system information for virt install
-
- NOTE: relevant to http only
- """
-
- blended = utils.blender(self.api, True, system)
- filename = os.path.join(self.settings.webdir,"systems",system.name)
- fd = open(filename, "w+")
- fd.write(yaml.dump(blended))
- fd.close()
-
diff --git a/cobbler/api.py b/cobbler/api.py
index 6f7d1b1..ebe987e 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -25,6 +25,7 @@ import action_validate
from cexceptions import *
import sub_process
import module_loader
+import kickgen
import logging
import os
@@ -79,6 +80,7 @@ class BootAPI:
"module",
"authz_allowall"
)
+ self.kickgen = kickgen.KickGen(self._config)
self.logger.debug("API handle initialized")
def __setup_logger(self,name):
@@ -284,7 +286,14 @@ class BootAPI:
# run cobbler reposync to apply changes
return True
-
+
+ def generate_kickstart(self,profile,system):
+ self.log("generate_kickstart")
+ if system:
+ return self.kickgen.generate_kickstart_for_system(system)
+ else:
+ return self.kickgen.generate_kickstart_for_profile(profile)
+
def check(self):
"""
See if all preqs for network booting are valid. This returns
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
new file mode 100644
index 0000000..dce33f3
--- /dev/null
+++ b/cobbler/kickgen.py
@@ -0,0 +1,272 @@
+"""
+Builds out filesystem trees/data based on the object tree.
+This is the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+
+class KickGen:
+ """
+ Handles conversion of internal state to the tftpboot tree layout
+ """
+
+ def __init__(self,config):
+ """
+ Constructor
+ """
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+
+ def generate_kickstart_for_profile(self,g):
+
+ g = self.api.find_profile(name=g)
+ if g is None:
+ return "# profile not found"
+
+ distro = g.get_conceptual_parent()
+ meta = utils.blender(self.api, False, g)
+ if distro is None:
+ raise CX(_("profile %(profile)s references missing distro %(distro)s") % { "profile" : g.name, "distro" : g.distro })
+ kickstart_path = utils.find_kickstart(meta["kickstart"])
+ if kickstart_path is not None and os.path.exists(kickstart_path):
+ # the input is an *actual* file, hence we have to copy it
+ try:
+ meta = utils.blender(self.api, False, g)
+ ksmeta = meta["ks_meta"]
+ del meta["ks_meta"]
+ meta.update(ksmeta) # make available at top level
+ meta["yum_repo_stanza"] = self.generate_repo_stanza(g,True)
+ meta["yum_config_stanza"] = self.generate_config_stanza(g,True)
+ meta["kickstart_done"] = self.generate_kickstart_signal(0, g, None)
+ meta["kickstart_start"] = self.generate_kickstart_signal(1, g, None)
+ meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
+ kfile = open(kickstart_path)
+ data = self.templar.render(kfile, meta, None, g)
+ kfile.close()
+ return data
+ except:
+ traceback.print_exc() # leave this in, for now...
+ msg = "err_kickstart2"
+ raise CX(_("Error while rendering kickstart file"))
+
+ def generate_kickstart_signal(self, is_pre=0, profile=None, system=None):
+ """
+ Do things that we do at the start/end of kickstarts...
+ * start: signal the status watcher we're starting
+ * end: signal the status watcher we're done
+ * end: disable PXE if needed
+ * end: save the original kickstart file for debug
+ """
+
+ nopxe = "\nwget \"http://%s/cblr/svc/?op=nopxe&system=%s\" -O /dev/null"
+ saveks = "\nwget \"http://%s/cblr/svc/?op=ks&%s=%s\" -O /root/cobbler.ks"
+ runpost = "\nwget \"http://%s/cblr/srv/?op=trig&?mode=post&%s=%s\" -O /dev/null"
+ runpre = "\nwget \"http://%s/cblr/srv/?op=trig&?mode=pre&%s=%s\" -O /dev/null"
+
+ what = "profile"
+ blend_this = profile
+ if system:
+ what = "system"
+ blend_this = system
+
+ blended = utils.blender(self.api, False, blend_this)
+ kickstart = blended.get("kickstart",None)
+
+ buf = ""
+ srv = blended["http_server"]
+ if system is not None:
+ if not is_pre:
+ if str(self.settings.pxe_just_once).upper() in [ "1", "Y", "YES", "TRUE" ]:
+ buf = buf + nopxe % (srv, system.name)
+ if kickstart and os.path.exists(kickstart):
+ buf = buf + saveks % (srv, "system", system.name)
+ if self.settings.run_install_triggers:
+ buf = buf + runpost % (srv, what, system.name)
+ else:
+ if self.settings.run_install_triggers:
+ buf = buf + runpre % (srv, what, system.name)
+
+ else:
+ if not is_pre:
+ if kickstart and os.path.exists(kickstart):
+ buf = buf + saveks % (srv, "profile", profile.name)
+ if self.settings.run_install_triggers:
+ buf = buf + runpost % (srv, what, profile.name)
+ else:
+ if self.settings.run_install_triggers:
+ buf = buf + runpre % (srv, what, profile.name)
+
+ return buf
+
+ def generate_repo_stanza(self, obj, is_profile=True):
+
+ """
+ Automatically attaches yum repos to profiles/systems in kickstart files
+ that contain the magic $yum_repo_stanza variable.
+ """
+
+ buf = ""
+ blended = utils.blender(self.api, False, obj)
+ configs = self.get_repo_filenames(obj,is_profile)
+ repos = self.repos
+
+ for c in configs:
+ name = c.split("/")[-1].replace(".repo","")
+ (is_core, baseurl) = self.analyze_repo_config(c)
+ for repo in repos:
+ if repo.name == name:
+ if not repo.yumopts.has_key('enabled') or repo.yumopts['enabled'] == '1':
+ buf = buf + "repo --name=%s --baseurl=%s\n" % (name, baseurl)
+ return buf
+
+ def analyze_repo_config(self, filename):
+ fd = open(filename)
+ data = fd.read()
+ lines = data.split("\n")
+ ret = False
+ baseurl = None
+ for line in lines:
+ if line.find("ks_mirror") != -1:
+ ret = True
+ if line.find("baseurl") != -1:
+ first, baseurl = line.split("=")
+ fd.close()
+ return (ret, baseurl)
+
+ def get_repo_baseurl(self, server, repo_name, is_repo_mirror=True):
+ """
+ Construct the URL to a repo definition.
+ """
+ if is_repo_mirror:
+ return "http://%s/cobbler/repo_mirror/%s" % (server, repo_name)
+ else:
+ return "http://%s/cobbler/ks_mirror/config/%s" % (server, repo_name)
+
+ def get_repo_filenames(self, obj, is_profile=True):
+ """
+ For a given object, return the paths to repo configuration templates
+ that will be used to generate per-object repo configuration files and
+ baseurls
+ """
+
+ blended = utils.blender(self.api, False, obj)
+ urlseg = self.get_repo_segname(is_profile)
+
+ topdir = "%s/%s/%s/*.repo" % (self.settings.webdir, urlseg, blended["name"])
+ files = glob.glob(topdir)
+ return files
+
+
+ def get_repo_segname(self, is_profile):
+ if is_profile:
+ return "repos_profile"
+ else:
+ return "repos_system"
+
+
+ def generate_config_stanza(self, obj, is_profile=True):
+
+ """
+ Add in automatic to configure /etc/yum.repos.d on the remote system
+ if the kickstart file contains the magic $yum_config_stanza.
+ """
+
+ if not self.settings.yum_post_install_mirror:
+ return ""
+
+ urlseg = self.get_repo_segname(is_profile)
+
+ distro = obj.get_conceptual_parent()
+ if not is_profile:
+ distro = distro.get_conceptual_parent()
+
+ blended = utils.blender(self.api, False, obj)
+ configs = self.get_repo_filenames(obj, is_profile)
+ buf = ""
+
+ # for each kickstart template we have rendered ...
+ for c in configs:
+
+ name = c.split("/")[-1].replace(".repo","")
+ # add the line to create the yum config file on the target box
+ conf = self.get_repo_config_file(blended["http_server"],urlseg,blended["name"],name)
+ buf = buf + "wget \"%s\" --output-document=/etc/yum.repos.d/%s.repo\n" % (conf, name)
+
+ return buf
+
+ def get_repo_config_file(self,server,urlseg,obj_name,repo_name):
+ """
+ Construct the URL to a repo config file that is usable in kickstart
+ for use with yum. This is different than the templates cobbler reposync
+ creates, as this file will allow the server to migrate and have different
+ variables for different subnets/profiles/etc.
+ """
+ return "http://%s/cblr/%s/%s/%s.repo" % (server,urlseg,obj_name,repo_name)
+
+ def generate_kickstart_for_system(self,s):
+
+
+ s = self.api.find_system(name=s)
+ if s is None:
+ return "# system not found"
+
+ profile = s.get_conceptual_parent()
+ if profile is None:
+ raise CX(_("system %(system)s references missing profile %(profile)s") % { "system" : s.name, "profile" : s.profile })
+ distro = profile.get_conceptual_parent()
+ meta = utils.blender(self.api, False, s)
+ kickstart_path = utils.find_kickstart(meta["kickstart"])
+ if kickstart_path and os.path.exists(kickstart_path):
+ try:
+ ksmeta = meta["ks_meta"]
+ del meta["ks_meta"]
+ meta.update(ksmeta) # make available at top level
+ meta["yum_repo_stanza"] = self.generate_repo_stanza(s, False)
+ meta["yum_config_stanza"] = self.generate_config_stanza(s, False)
+ meta["kickstart_done"] = self.generate_kickstart_signal(0, profile, s)
+ meta["kickstart_start"] = self.generate_kickstart_signal(1, profile, s)
+ meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
+ kfile = open(kickstart_path)
+ data = self.templar.render(kfile, meta, None, s)
+ kfile.close()
+ return data
+ except:
+ traceback.print_exc()
+ raise CX(_("Error templating file"))
+
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 0cbaf22..a87355b 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -158,6 +158,14 @@ class CobblerXMLRPCInterface:
return self._fix_none(data)
+ def generate_kickstart(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None,reg=None):
+ self.log("generate_kickstart")
+
+ if reg is not None and profile and not system:
+ regrc = self.register_mac(REMOTE_MAC,profile)
+
+ return self.api.generate_kickstart(profile,system)
+
def get_settings(self,token=None):
"""
Return the contents of /var/lib/cobbler/settings, which is a hash.
diff --git a/cobbler/services.py b/cobbler/services.py
new file mode 100644
index 0000000..9ced0c6
--- /dev/null
+++ b/cobbler/services.py
@@ -0,0 +1,94 @@
+# Mod Python service functions for Cobbler's public interface
+# (aka cool stuff that works with wget)
+#
+# Copyright 2007 Albert P. Tobey
+# additions: Michael DeHaan
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import exceptions
+import xmlrpclib
+import os
+import traceback
+import string
+import sys
+import time
+
+def log_exc(apache):
+ """
+ Log active traceback to logfile.
+ """
+ (t, v, tb) = sys.exc_info()
+ apache.log_error("Exception occured: %s" % t )
+ apache.log_error("Exception value: %s" % v)
+ apache.log_error("Exception Info:\n%s" % string.join(traceback.format_list(traceback.extract_tb(tb))))
+
+class CobblerSvc(object):
+ """
+ Interesting mod python functions are all keyed off the parameter
+ mode, which defaults to index. All options are passed
+ as parameters into the function.
+ """
+ def __init__(self, server=None, apache=None):
+ self.server = server
+ self.apache = apache
+ self.remote = None
+
+ def __xmlrpc_setup(self):
+ """
+ Sets up the connection to the Cobbler XMLRPC server.
+ This is the version that does not require logins.
+ """
+ self.remote = xmlrpclib.Server(self.server, allow_none=True)
+
+ def modes(self):
+ """
+ Returns a list of methods in this object that can be run as web
+ modes.
+ """
+ retval = list()
+ for m in dir(self):
+ func = getattr( self, m )
+ if hasattr(func, 'exposed') and getattr(func,'exposed'):
+ retval.append(m)
+ return retval
+
+ def index(self,**args):
+ return "no mode specified"
+
+ def ks(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None,reg=None,**rest):
+ """
+ Generate kickstart files...
+ """
+ self.__xmlrpc_setup()
+ return self.remote.generate_kickstart(profile,system,REMOTE_ADDR,REMOTE_MAC)
+
+ def trig(self,mode="?",profile=None,system=None,REMOTE_ADDR=None,**rest):
+ """
+ Hook to call install triggers.
+ """
+ self.__xmlrpc_setup()
+ ip = REMOTE_ADDR
+ if profile:
+ rc = self.remote.run_install_triggers(mode,"profile",profile,ip)
+ else:
+ rc = self.remote.run_install_triggers(mode,"system",system,ip)
+ return str(rc)
+
+ def nopxe(self,system=None,**rest):
+ self.__xmlrpc_setup()
+ return str(self.remote.disable_netboot(system))
+
+ # =======================================================
+ # list of functions that are callable via mod_python:
+ modes.exposed = False
+ index.exposed = True
+ ks.exposed = True
+ trig.exposed = True
+
+
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 1695cbb..40ed571 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -22,8 +22,6 @@ TESTMODE = False
# we need.
DEFAULTS = {
- "allow_cgi_mac_registration" : 0,
- "allow_cgi_profile_change" : 0,
"allow_duplicate_macs" : 0,
"allow_duplicate_ips" : 0,
"bootloaders" : {
@@ -61,7 +59,8 @@ DEFAULTS = {
"manage_dhcp_mode" : "isc",
"next_server" : "127.0.0.1",
"pxe_just_once" : 0,
- "run_install_trigger" : 1,
+ "register_new_installs" : 0,
+ "run_install_triggers" : 1,
"server" : "127.0.0.1",
"snippetsdir" : "/var/lib/cobbler/snippets",
"syslog_port" : 25150,
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 1e6d30d..0eec178 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -33,8 +33,8 @@ VFN=valueForName
currentTime=time.time
__CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1208298360.4598751
-__CHEETAH_genTimestamp__ = 'Tue Apr 15 18:26:00 2008'
+__CHEETAH_genTime__ = 1208545841.2024181
+__CHEETAH_genTimestamp__ = 'Fri Apr 18 15:10:41 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
__CHEETAH_srcLastModified__ = 'Fri Feb 15 14:47:43 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
diff --git a/config/cobbler_svc.conf b/config/cobbler_svc.conf
new file mode 100644
index 0000000..f0c86de
--- /dev/null
+++ b/config/cobbler_svc.conf
@@ -0,0 +1,12 @@
+# This configuration file allows cobbler data
+# to be accessed over HTTP.
+
+# mod_python WebUI/services
+
+
+ SetHandler mod_python
+ PythonHandler services
+ PythonDebug on
+
+
+
diff --git a/config/settings b/config/settings
index fc6739a..10e06e2 100644
--- a/config/settings
+++ b/config/settings
@@ -1,6 +1,4 @@
---
-allow_cgi_mac_registration: 0
-allow_cgi_profile_change: 0
allow_duplicate_macs: 0
allow_duplicate_ips: 0
bootloaders:
@@ -35,7 +33,8 @@ manage_dhcp: 0
manage_dhcp_mode: isc
next_server: '127.0.0.1'
pxe_just_once: 0
-run_install_trigger: 1
+register_new_installs: 0
+run_install_triggers: 1
server: '127.0.0.1'
snippetsdir: /var/lib/cobbler/snippets
syslog_port: 25150
diff --git a/legacy/change_profile.cgi b/legacy/change_profile.cgi
new file mode 100755
index 0000000..f7330f1
--- /dev/null
+++ b/legacy/change_profile.cgi
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+# Michael DeHaan
+# (C) 2008 Red Hat Inc
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# what is this? This is a
+# script to change cobbler profiles for the requestor
+# from one profile to another, as specified by ?profile=foo
+# ex: wget http://cobbler.example.org/cgi-bin/change_profile.cgi?profile=foo
+# suitable to be called from kickstart,etc
+
+import cgi
+import cgitb
+import time
+import os
+import sys
+import socket
+import xmlrpclib
+
+COBBLER_BASE = "/var/www/cobbler"
+XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
+DEFAULT_PROFILE = "default"
+
+#----------------------------------------------------------------------
+
+class ServerProxy(xmlrpclib.ServerProxy):
+
+ def __init__(self, url=None):
+ xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
+
+#----------------------------------------------------------------------
+
+def parse_query():
+
+ form = cgi.parse()
+
+ mac = "-1"
+ if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
+ # FIXME: will not key off other NICs
+ devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
+ return devicepair.split()[1].strip()
+
+ if form.has_key("profile"):
+ profile = form["profile"][0]
+ else:
+ profile = DEFAULT_PROFILE
+ system = autodetect()
+ print "# incoming profile = %s" % profile
+ print "# incoming system = %s" % system
+ return (system["name"],profile)
+
+#----------------------------------------------------------------------
+
+def autodetect():
+ # get mac address, requires kssendmac on the kernel options line.
+ else:
+ return "-1"
+
+
+#----------------------------------------------------------------------
+
+def header():
+ print "Content-type: text/plain"
+ print
+
+#----------------------------------------------------------------------
+
+if __name__ == "__main__":
+ cgitb.enable(format='text')
+ header()
+ server = ServerProxy(XMLRPC_SERVER)
+ (mac, profile) = parse_query()
+ try:
+ ip = os.environ["REMOTE_ADDR"]
+ except:
+ ip = "???"
+ print "# attempting to change system(mac=%s) to profile(%s)" % (mac,profile)
+ server.change_profile(mac,profile)
+
diff --git a/legacy/findks.cgi b/legacy/findks.cgi
new file mode 100755
index 0000000..39adbcf
--- /dev/null
+++ b/legacy/findks.cgi
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# based on:
+# Cobbler ks-serving script
+# July 5 2007
+# Adam Wolf
+# http://feelslikeburning.com/projects/live-cd-restoring-with-cobbler/
+
+import cgi
+import cgitb
+import time
+import os
+import sys
+import socket
+import xmlrpclib
+
+COBBLER_BASE = "/var/www/cobbler"
+XMLRPC_SERVER = "http://127.0.0.1/cobbler_api_rw"
+
+#----------------------------------------------------------------------
+
+class ServerProxy(xmlrpclib.ServerProxy):
+
+ def __init__(self, url=None):
+ xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
+
+#----------------------------------------------------------------------
+
+def parse_query():
+
+ form = cgi.parse()
+
+ if form.has_key("system"):
+ name = form["system"][0]
+ type = "system"
+ elif form.has_key("profile"):
+ name = form["profile"][0]
+ type = "profile"
+ else:
+ type = "system"
+ name = autodetect()
+ return (name,type)
+
+#----------------------------------------------------------------------
+
+def autodetect():
+
+ # connect to cobblerd and get the list of systems
+
+ try:
+ xmlrpc_server = ServerProxy(XMLRPC_SERVER)
+ systems = xmlrpc_server.get_systems()
+ except:
+ print "# could not contact cobblerd at %s" % XMLRPC_SERVER
+ sys.exit(1)
+
+ # if kssendmac was in the kernel options line, see
+ # if a system can be found matching the MAC address. This
+ # is more specific than an IP match.
+
+ if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
+ # FIXME: will not key off other NICs
+ devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
+ mac = devicepair.split()[1].strip()
+ # mac is the macaddress of the first nic reported by anaconda
+
+ candidates = []
+ for x in systems:
+
+ for y in x["interfaces"]:
+ if x["interfaces"][y]["ip_address"] == ip:
+ candidates.append(x)
+
+ if len(candidates) == 0:
+ print "# no system entries with MAC %s found" % mac
+ print "# trying IP lookup"
+ elif len(candidates) > 1:
+ print "# multiple system entries with MAC %s found" % mac
+ sys.exit(1)
+ elif len(candidates) == 1:
+ print "# kickstart matched by MAC: %s" % mac
+ return candidates[0]
+
+ # attempt to match by the IP.
+
+ ip = os.environ["REMOTE_ADDR"]
+ candidates = [system['name'] for system in systems if system['ip_address'] == ip]
+
+ if len(candidates) == 0:
+ print "# no system entries with ip %s found" % ip
+ sys.exit(1)
+ elif len(candidates) > 1:
+ print "# multiple system entries with ip %s found" % ip
+ sys.exit(1)
+ elif len(candidates) == 1:
+ return candidates[0]
+
+#----------------------------------------------------------------------
+
+def serve_file(name):
+
+ # never hurts to be safe...
+ name = name.replace("/","")
+ name = name.replace("..","")
+ name = name.replace(";","")
+
+ if type == "system":
+ ks_path = "%s/kickstarts_sys/%s/ks.cfg" % (COBBLER_BASE, name)
+ elif type == "profile":
+ ks_path = "%s/kickstarts/%s/ks.cfg" % (COBBLER_BASE, name)
+
+ if not os.path.exists(ks_path):
+ print "# no such cobbler object"
+ sys.exit(1)
+
+ try:
+ ksfile = open(ks_path)
+ except:
+ print "# Cannot open file %s" % ks_path
+ sys.exit(1)
+
+ for line in ksfile:
+ print line.strip()
+ ksfile.close()
+
+#----------------------------------------------------------------------
+
+def header():
+ print "Content-type: text/plain"
+ print
+ print "# kickstart managed by Cobbler -- http://cobbler.et.redhat.com"
+ print "# served on %s" % time.ctime()
+
+#----------------------------------------------------------------------
+
+if __name__ == "__main__":
+ cgitb.enable(format='text')
+ header()
+ (name, type) = parse_query()
+ print "# %s %s" % (type,name)
+ print "# requestor ip = %s" % os.environ["REMOTE_ADDR"]
+ print "# ============================="
+ print " "
+ serve_file(name)
+
+
diff --git a/legacy/install_trigger.cgi b/legacy/install_trigger.cgi
new file mode 100644
index 0000000..b83ff57
--- /dev/null
+++ b/legacy/install_trigger.cgi
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# This script runs post install triggers in /var/lib/cobbler/triggers/install/post
+# if the triggers are enabled in the settings file.
+#
+# (C) Tim Verhoeven , 2007
+# tweaked: Michael DeHaan , 2007-2008
+
+import cgi
+import cgitb
+import time
+import os
+import sys
+import socket
+import xmlrpclib
+from cobbler import sub_process as sub_process
+
+COBBLER_BASE = "/var/www/cobbler"
+XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
+
+#----------------------------------------------------------------------
+
+class ServerProxy(xmlrpclib.ServerProxy):
+
+ def __init__(self, url=None):
+ xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
+
+#----------------------------------------------------------------------
+
+def parse_query():
+ """
+ Read arguments from query string.
+ """
+
+ form = cgi.parse()
+
+ ip = "?"
+ if os.environ.has_key("REMOTE_ADDR"):
+ ip = os.environ["REMOTE_ADDR"]
+
+ name = "?"
+ objtype = "?"
+ if form.has_key("system"):
+ name = form["system"][0]
+ objtype = "system"
+ elif form.has_key("profile"):
+ name = form["profile"][0]
+ objtype = "profile"
+
+ mode = "?"
+ if form.has_key("mode"):
+ mode = form["mode"][0]
+
+ return (mode,objtype,name,ip)
+
+def invoke(mode,objtype,name,ip):
+ """
+ Determine if this feature is enabled.
+ """
+
+ xmlrpc_server = ServerProxy(XMLRPC_SERVER)
+ print xmlrpc_server.run_install_triggers(mode,objtype,name,ip)
+
+ return True
+
+#----------------------------------------------------------------------
+
+def header():
+ print "Content-type: text/plain"
+ print
+
+#----------------------------------------------------------------------
+
+if __name__ == "__main__":
+ cgitb.enable(format='text')
+ header()
+ (mode,objtype,name,ip) = parse_query()
+ invoke(mode,objtype,name,ip)
+
+
diff --git a/legacy/nopxe.cgi b/legacy/nopxe.cgi
new file mode 100755
index 0000000..a2eae88
--- /dev/null
+++ b/legacy/nopxe.cgi
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# This script disables the netboot flag for a given
+# system if (and only if) pxe_just_once is enabled in settings.
+# It must not be able to do anything else for security
+# reasons.
+#
+#
+# (C) Red Hat, 2007
+# Michael DeHaan
+#
+
+import cgi
+import cgitb
+import time
+import os
+import sys
+import socket
+import xmlrpclib
+from cobbler import sub_process as sub_process
+
+COBBLER_BASE = "/var/www/cobbler"
+XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
+
+#----------------------------------------------------------------------
+
+class ServerProxy(xmlrpclib.ServerProxy):
+
+ def __init__(self, url=None):
+ xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
+
+#----------------------------------------------------------------------
+
+def parse_query():
+ """
+ Read arguments from query string.
+ """
+
+ form = cgi.parse()
+
+ if form.has_key("system"):
+ return form["system"][0]
+ return 0
+
+def disable(name):
+ """
+ Determine if this feature is enabled.
+ """
+
+ #try:
+ xmlrpc_server = ServerProxy(XMLRPC_SERVER)
+ print xmlrpc_server.disable_netboot(name)
+ #except:
+ # print "# could not contact cobblerd at %s" % XMLRPC_SERVER
+ # sys.exit(1)
+
+ return True
+
+#----------------------------------------------------------------------
+
+def header():
+ print "Content-type: text/plain"
+ print
+
+#----------------------------------------------------------------------
+
+if __name__ == "__main__":
+ cgitb.enable(format='text')
+ header()
+ name = parse_query()
+ disable(name)
+
+
diff --git a/legacy/register_mac.cgi b/legacy/register_mac.cgi
new file mode 100755
index 0000000..3f251c4
--- /dev/null
+++ b/legacy/register_mac.cgi
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+
+# Michael DeHaan
+# (C) 2008 Red Hat Inc
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# what is this? This is a
+# script to auto add systems who make a wget into cobbler.
+# right now it requires "kssendmac" in kernel options and takes only 1 arg
+# ex: wget http://cobbler.example.org/cgi-bin/register_mac?profile=foo
+# suitable to be called from kickstart,etc
+
+import cgi
+#import cgitb
+import time
+import os
+import sys
+import socket
+import xmlrpclib
+
+# FIXME: edit these two variables to match your webui configuration
+USERNAME = "cobbler"
+PASSWORD = "cobbler"
+
+COBBLER_BASE = "/var/www/cobbler"
+XMLRPC_SERVER = "http://127.0.0.1/cobbler_api_rw"
+DEFAULT_PROFILE = "default"
+
+#----------------------------------------------------------------------
+
+class ServerProxy(xmlrpclib.ServerProxy):
+
+ def __init__(self, url=None):
+ xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
+
+#----------------------------------------------------------------------
+
+def parse_query():
+
+ form = cgi.parse()
+
+ if form.has_key("profile"):
+ profile = form["profile"][0]
+ else:
+ profile = DEFAULT_PROFILE
+ mac = autodetect()
+ print "# incoming profile = %s" % profile
+ return (mac,profile)
+
+#----------------------------------------------------------------------
+
+def autodetect():
+
+ # connect to cobblerd and get the list of systems
+
+ try:
+ xmlrpc_server = ServerProxy(XMLRPC_SERVER)
+ systems = xmlrpc_server.get_systems()
+ except:
+ print "# could not contact cobblerd at %s" % XMLRPC_SERVER
+ sys.exit(1)
+
+ # if kssendmac was in the kernel options line, see
+ # if a system can be found matching the MAC address. This
+ # is more specific than an IP match.
+
+ if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
+ # FIXME: will not key off other NICs
+ devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
+ mac = devicepair.split()[1].strip()
+ print "# discovered MAC: %s" % mac.lower()
+ return mac.lower()
+ else:
+ print "# missing kssendmac in the kernel args? Can't continue."
+ return "BB:EE:EE:EE:EE:FF"
+
+#----------------------------------------------------------------------
+
+
+def make_change(server,mac,profile,token):
+ server.register_mac(mac,profile)
+
+#----------------------------------------------------------------------
+
+def header():
+ print "Content-type: text/plain"
+ print
+
+#----------------------------------------------------------------------
+
+if __name__ == "__main__":
+ #cgitb.enable(format='text')
+ header()
+ server = ServerProxy(XMLRPC_SERVER)
+ token = server.login(USERNAME,PASSWORD)
+ (mac, profile) = parse_query()
+ print "# running for %s %s" % (mac,profile)
+ make_change(server,mac,profile,token)
+
diff --git a/legacy/watcher.py b/legacy/watcher.py
new file mode 100755
index 0000000..dfa8dc3
--- /dev/null
+++ b/legacy/watcher.py
@@ -0,0 +1,63 @@
+# cobbler mod_python handler for observing kickstart activity
+#
+# Copyright 2007, Red Hat, Inc
+# Michael DeHaan
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import time
+from mod_python import apache
+
+def outputfilter(filter):
+
+
+ # extract important info
+ request = filter.req
+ connection = request.connection
+ (address,port) = connection.remote_addr
+
+ # open the logfile (directory be set writeable by installer)
+ logfile = open("/var/log/cobbler/kicklog/%s" % address,"a+")
+
+ log_it = True
+ if request.the_request.find("cobbler_track") == -1 and request.the_request.find("cblr/") == -1:
+ log_it = False
+
+ if log_it:
+ # write the timestamp
+ t = time.localtime()
+ seconds = str(time.mktime(t))
+ logfile.write(seconds)
+ logfile.write("\t")
+ timestr = str(time.asctime(t))
+ logfile.write(timestr)
+ logfile.write("\t")
+
+ # write the IP address of the client
+ logfile.write(address)
+ logfile.write("\t")
+
+ # write the filename being requested
+ logfile.write(request.the_request)
+ # logfile.write(request.filename)
+ logfile.write("\n")
+
+ # if requesting this file, don't return it
+ if request.the_request.find("watcher.py") != -1:
+ filter.close()
+ return
+
+ # pass-through filter
+ s = filter.read()
+ while s:
+ filter.write(s)
+ s = filter.read()
+ if s is None:
+ filter.close()
+ logfile.close()
+
diff --git a/scripts/change_profile.cgi b/scripts/change_profile.cgi
deleted file mode 100755
index f7330f1..0000000
--- a/scripts/change_profile.cgi
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python
-
-# Michael DeHaan
-# (C) 2008 Red Hat Inc
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# what is this? This is a
-# script to change cobbler profiles for the requestor
-# from one profile to another, as specified by ?profile=foo
-# ex: wget http://cobbler.example.org/cgi-bin/change_profile.cgi?profile=foo
-# suitable to be called from kickstart,etc
-
-import cgi
-import cgitb
-import time
-import os
-import sys
-import socket
-import xmlrpclib
-
-COBBLER_BASE = "/var/www/cobbler"
-XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
-DEFAULT_PROFILE = "default"
-
-#----------------------------------------------------------------------
-
-class ServerProxy(xmlrpclib.ServerProxy):
-
- def __init__(self, url=None):
- xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
-
-#----------------------------------------------------------------------
-
-def parse_query():
-
- form = cgi.parse()
-
- mac = "-1"
- if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
- # FIXME: will not key off other NICs
- devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
- return devicepair.split()[1].strip()
-
- if form.has_key("profile"):
- profile = form["profile"][0]
- else:
- profile = DEFAULT_PROFILE
- system = autodetect()
- print "# incoming profile = %s" % profile
- print "# incoming system = %s" % system
- return (system["name"],profile)
-
-#----------------------------------------------------------------------
-
-def autodetect():
- # get mac address, requires kssendmac on the kernel options line.
- else:
- return "-1"
-
-
-#----------------------------------------------------------------------
-
-def header():
- print "Content-type: text/plain"
- print
-
-#----------------------------------------------------------------------
-
-if __name__ == "__main__":
- cgitb.enable(format='text')
- header()
- server = ServerProxy(XMLRPC_SERVER)
- (mac, profile) = parse_query()
- try:
- ip = os.environ["REMOTE_ADDR"]
- except:
- ip = "???"
- print "# attempting to change system(mac=%s) to profile(%s)" % (mac,profile)
- server.change_profile(mac,profile)
-
diff --git a/scripts/findks.cgi b/scripts/findks.cgi
deleted file mode 100755
index 39adbcf..0000000
--- a/scripts/findks.cgi
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/usr/bin/env python
-
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# based on:
-# Cobbler ks-serving script
-# July 5 2007
-# Adam Wolf
-# http://feelslikeburning.com/projects/live-cd-restoring-with-cobbler/
-
-import cgi
-import cgitb
-import time
-import os
-import sys
-import socket
-import xmlrpclib
-
-COBBLER_BASE = "/var/www/cobbler"
-XMLRPC_SERVER = "http://127.0.0.1/cobbler_api_rw"
-
-#----------------------------------------------------------------------
-
-class ServerProxy(xmlrpclib.ServerProxy):
-
- def __init__(self, url=None):
- xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
-
-#----------------------------------------------------------------------
-
-def parse_query():
-
- form = cgi.parse()
-
- if form.has_key("system"):
- name = form["system"][0]
- type = "system"
- elif form.has_key("profile"):
- name = form["profile"][0]
- type = "profile"
- else:
- type = "system"
- name = autodetect()
- return (name,type)
-
-#----------------------------------------------------------------------
-
-def autodetect():
-
- # connect to cobblerd and get the list of systems
-
- try:
- xmlrpc_server = ServerProxy(XMLRPC_SERVER)
- systems = xmlrpc_server.get_systems()
- except:
- print "# could not contact cobblerd at %s" % XMLRPC_SERVER
- sys.exit(1)
-
- # if kssendmac was in the kernel options line, see
- # if a system can be found matching the MAC address. This
- # is more specific than an IP match.
-
- if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
- # FIXME: will not key off other NICs
- devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
- mac = devicepair.split()[1].strip()
- # mac is the macaddress of the first nic reported by anaconda
-
- candidates = []
- for x in systems:
-
- for y in x["interfaces"]:
- if x["interfaces"][y]["ip_address"] == ip:
- candidates.append(x)
-
- if len(candidates) == 0:
- print "# no system entries with MAC %s found" % mac
- print "# trying IP lookup"
- elif len(candidates) > 1:
- print "# multiple system entries with MAC %s found" % mac
- sys.exit(1)
- elif len(candidates) == 1:
- print "# kickstart matched by MAC: %s" % mac
- return candidates[0]
-
- # attempt to match by the IP.
-
- ip = os.environ["REMOTE_ADDR"]
- candidates = [system['name'] for system in systems if system['ip_address'] == ip]
-
- if len(candidates) == 0:
- print "# no system entries with ip %s found" % ip
- sys.exit(1)
- elif len(candidates) > 1:
- print "# multiple system entries with ip %s found" % ip
- sys.exit(1)
- elif len(candidates) == 1:
- return candidates[0]
-
-#----------------------------------------------------------------------
-
-def serve_file(name):
-
- # never hurts to be safe...
- name = name.replace("/","")
- name = name.replace("..","")
- name = name.replace(";","")
-
- if type == "system":
- ks_path = "%s/kickstarts_sys/%s/ks.cfg" % (COBBLER_BASE, name)
- elif type == "profile":
- ks_path = "%s/kickstarts/%s/ks.cfg" % (COBBLER_BASE, name)
-
- if not os.path.exists(ks_path):
- print "# no such cobbler object"
- sys.exit(1)
-
- try:
- ksfile = open(ks_path)
- except:
- print "# Cannot open file %s" % ks_path
- sys.exit(1)
-
- for line in ksfile:
- print line.strip()
- ksfile.close()
-
-#----------------------------------------------------------------------
-
-def header():
- print "Content-type: text/plain"
- print
- print "# kickstart managed by Cobbler -- http://cobbler.et.redhat.com"
- print "# served on %s" % time.ctime()
-
-#----------------------------------------------------------------------
-
-if __name__ == "__main__":
- cgitb.enable(format='text')
- header()
- (name, type) = parse_query()
- print "# %s %s" % (type,name)
- print "# requestor ip = %s" % os.environ["REMOTE_ADDR"]
- print "# ============================="
- print " "
- serve_file(name)
-
-
diff --git a/scripts/install_trigger.cgi b/scripts/install_trigger.cgi
deleted file mode 100644
index b83ff57..0000000
--- a/scripts/install_trigger.cgi
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/env python
-
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# This script runs post install triggers in /var/lib/cobbler/triggers/install/post
-# if the triggers are enabled in the settings file.
-#
-# (C) Tim Verhoeven , 2007
-# tweaked: Michael DeHaan , 2007-2008
-
-import cgi
-import cgitb
-import time
-import os
-import sys
-import socket
-import xmlrpclib
-from cobbler import sub_process as sub_process
-
-COBBLER_BASE = "/var/www/cobbler"
-XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
-
-#----------------------------------------------------------------------
-
-class ServerProxy(xmlrpclib.ServerProxy):
-
- def __init__(self, url=None):
- xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
-
-#----------------------------------------------------------------------
-
-def parse_query():
- """
- Read arguments from query string.
- """
-
- form = cgi.parse()
-
- ip = "?"
- if os.environ.has_key("REMOTE_ADDR"):
- ip = os.environ["REMOTE_ADDR"]
-
- name = "?"
- objtype = "?"
- if form.has_key("system"):
- name = form["system"][0]
- objtype = "system"
- elif form.has_key("profile"):
- name = form["profile"][0]
- objtype = "profile"
-
- mode = "?"
- if form.has_key("mode"):
- mode = form["mode"][0]
-
- return (mode,objtype,name,ip)
-
-def invoke(mode,objtype,name,ip):
- """
- Determine if this feature is enabled.
- """
-
- xmlrpc_server = ServerProxy(XMLRPC_SERVER)
- print xmlrpc_server.run_install_triggers(mode,objtype,name,ip)
-
- return True
-
-#----------------------------------------------------------------------
-
-def header():
- print "Content-type: text/plain"
- print
-
-#----------------------------------------------------------------------
-
-if __name__ == "__main__":
- cgitb.enable(format='text')
- header()
- (mode,objtype,name,ip) = parse_query()
- invoke(mode,objtype,name,ip)
-
-
diff --git a/scripts/nopxe.cgi b/scripts/nopxe.cgi
deleted file mode 100755
index a2eae88..0000000
--- a/scripts/nopxe.cgi
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python
-
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# This script disables the netboot flag for a given
-# system if (and only if) pxe_just_once is enabled in settings.
-# It must not be able to do anything else for security
-# reasons.
-#
-#
-# (C) Red Hat, 2007
-# Michael DeHaan
-#
-
-import cgi
-import cgitb
-import time
-import os
-import sys
-import socket
-import xmlrpclib
-from cobbler import sub_process as sub_process
-
-COBBLER_BASE = "/var/www/cobbler"
-XMLRPC_SERVER = "http://127.0.0.1/cobbler_api"
-
-#----------------------------------------------------------------------
-
-class ServerProxy(xmlrpclib.ServerProxy):
-
- def __init__(self, url=None):
- xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
-
-#----------------------------------------------------------------------
-
-def parse_query():
- """
- Read arguments from query string.
- """
-
- form = cgi.parse()
-
- if form.has_key("system"):
- return form["system"][0]
- return 0
-
-def disable(name):
- """
- Determine if this feature is enabled.
- """
-
- #try:
- xmlrpc_server = ServerProxy(XMLRPC_SERVER)
- print xmlrpc_server.disable_netboot(name)
- #except:
- # print "# could not contact cobblerd at %s" % XMLRPC_SERVER
- # sys.exit(1)
-
- return True
-
-#----------------------------------------------------------------------
-
-def header():
- print "Content-type: text/plain"
- print
-
-#----------------------------------------------------------------------
-
-if __name__ == "__main__":
- cgitb.enable(format='text')
- header()
- name = parse_query()
- disable(name)
-
-
diff --git a/scripts/register_mac.cgi b/scripts/register_mac.cgi
deleted file mode 100755
index 5507525..0000000
--- a/scripts/register_mac.cgi
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-
-# Michael DeHaan
-# (C) 2008 Red Hat Inc
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# what is this? This is a
-# script to auto add systems who make a wget into cobbler.
-# right now it requires "kssendmac" in kernel options and takes only 1 arg
-# ex: wget http://cobbler.example.org/cgi-bin/regsister_mac?profile=foo
-# suitable to be called from kickstart,etc
-
-import cgi
-#import cgitb
-import time
-import os
-import sys
-import socket
-import xmlrpclib
-
-# FIXME: edit these two variables to match your webui configuration
-USERNAME = "cobbler"
-PASSWORD = "cobbler"
-
-COBBLER_BASE = "/var/www/cobbler"
-XMLRPC_SERVER = "http://127.0.0.1/cobbler_api_rw"
-DEFAULT_PROFILE = "default"
-
-#----------------------------------------------------------------------
-
-class ServerProxy(xmlrpclib.ServerProxy):
-
- def __init__(self, url=None):
- xmlrpclib.ServerProxy.__init__(self, url, allow_none=True)
-
-#----------------------------------------------------------------------
-
-def parse_query():
-
- form = cgi.parse()
-
- if form.has_key("profile"):
- profile = form["profile"][0]
- else:
- profile = DEFAULT_PROFILE
- mac = autodetect()
- print "# incoming profile = %s" % profile
- return (mac,profile)
-
-#----------------------------------------------------------------------
-
-def autodetect():
-
- # connect to cobblerd and get the list of systems
-
- try:
- xmlrpc_server = ServerProxy(XMLRPC_SERVER)
- systems = xmlrpc_server.get_systems()
- except:
- print "# could not contact cobblerd at %s" % XMLRPC_SERVER
- sys.exit(1)
-
- # if kssendmac was in the kernel options line, see
- # if a system can be found matching the MAC address. This
- # is more specific than an IP match.
-
- if os.environ.has_key("HTTP_X_RHN_PROVISIONING_MAC_0"):
- # FIXME: will not key off other NICs
- devicepair = os.environ["HTTP_X_RHN_PROVISIONING_MAC_0"]
- mac = devicepair.split()[1].strip()
- print "# discovered MAC: %s" % mac.lower()
- return mac.lower()
- else:
- print "# missing kssendmac in the kernel args? Can't continue."
- return "BB:EE:EE:EE:EE:FF"
-
-#----------------------------------------------------------------------
-
-
-def make_change(server,mac,profile,token):
- server.register_mac(mac,profile)
-
-#----------------------------------------------------------------------
-
-def header():
- print "Content-type: text/plain"
- print
-
-#----------------------------------------------------------------------
-
-if __name__ == "__main__":
- #cgitb.enable(format='text')
- header()
- server = ServerProxy(XMLRPC_SERVER)
- token = server.login(USERNAME,PASSWORD)
- (mac, profile) = parse_query()
- print "# running for %s %s" % (mac,profile)
- make_change(server,mac,profile,token)
-
diff --git a/scripts/services.py b/scripts/services.py
new file mode 100755
index 0000000..07243ae
--- /dev/null
+++ b/scripts/services.py
@@ -0,0 +1,67 @@
+"""
+mod_python gateway to cgi-like cobbler web functions
+
+Copyright 2007-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+from mod_python import apache
+from mod_python import Session
+from mod_python import util
+
+import xmlrpclib
+import cgi
+import os
+from cobbler.services import CobblerSvc
+
+#=======================================
+
+def handler(req):
+
+ """
+ Right now, index serves everything.
+
+ Hitting this URL means we've already cleared authn/authz
+ but we still need to use the token for all remote requests.
+ """
+
+ my_uri = req.uri
+
+ # apache.log_error("cannot load /var/lib/cobbler/web.ss")
+ req.add_common_vars()
+
+ # process form and qs data, if any
+ fs = util.FieldStorage(req)
+ form = {}
+ for x in fs.keys():
+ form[x] = str(fs.get(x,'default'))
+
+ form["REMOTE_ADDR"] = req.subprocess_env.get("REMOTE_ADDR",None)
+ form["REMOTE_MAC"] = req.subprocess_env.get("HTTP_X_RHN_PROVISIONING_MAC_0",None)
+
+ # instantiate a CobblerWeb object
+ cw = CobblerSvc(
+ apache = apache,
+ server = "http://127.0.0.1/cobbler_api"
+ )
+
+ # check for a valid path/mode
+ # handle invalid paths gracefully
+ mode = form.get('op','index')
+
+ func = getattr( cw, mode )
+ content = func( **form )
+
+ # apache.log_error("%s:%s ... %s" % (my_user, my_uri, str(form)))
+ req.content_type = "text/plain"
+ req.write(content)
+
+ return apache.OK
+
diff --git a/scripts/watcher.py b/scripts/watcher.py
deleted file mode 100755
index dfa8dc3..0000000
--- a/scripts/watcher.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# cobbler mod_python handler for observing kickstart activity
-#
-# Copyright 2007, Red Hat, Inc
-# Michael DeHaan
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import time
-from mod_python import apache
-
-def outputfilter(filter):
-
-
- # extract important info
- request = filter.req
- connection = request.connection
- (address,port) = connection.remote_addr
-
- # open the logfile (directory be set writeable by installer)
- logfile = open("/var/log/cobbler/kicklog/%s" % address,"a+")
-
- log_it = True
- if request.the_request.find("cobbler_track") == -1 and request.the_request.find("cblr/") == -1:
- log_it = False
-
- if log_it:
- # write the timestamp
- t = time.localtime()
- seconds = str(time.mktime(t))
- logfile.write(seconds)
- logfile.write("\t")
- timestr = str(time.asctime(t))
- logfile.write(timestr)
- logfile.write("\t")
-
- # write the IP address of the client
- logfile.write(address)
- logfile.write("\t")
-
- # write the filename being requested
- logfile.write(request.the_request)
- # logfile.write(request.filename)
- logfile.write("\n")
-
- # if requesting this file, don't return it
- if request.the_request.find("watcher.py") != -1:
- filter.close()
- return
-
- # pass-through filter
- s = filter.read()
- while s:
- filter.write(s)
- s = filter.read()
- if s is None:
- filter.close()
- logfile.close()
-
diff --git a/setup.py b/setup.py
index c8a6c99..eb969d1 100644
--- a/setup.py
+++ b/setup.py
@@ -44,8 +44,9 @@ if __name__ == "__main__":
tftp_cfg = "/tftpboot/pxelinux.cfg"
tftp_images = "/tftpboot/images"
rotpath = "/etc/logrotate.d"
- cgipath = "/var/www/cgi-bin/cobbler"
+ # cgipath = "/var/www/cgi-bin/cobbler"
modpython = "/var/www/cobbler/web"
+ modpythonsvc = "/var/www/cobbler/svc"
setup(
name="cobbler",
version = VERSION,
@@ -63,13 +64,15 @@ if __name__ == "__main__":
scripts = ["scripts/cobbler", "scripts/cobblerd"],
data_files = [
(modpython, ['scripts/index.py']),
+ (modpythonsvc, ['scripts/services.py']),
# cgi files
- (cgipath, ['scripts/findks.cgi', 'scripts/nopxe.cgi']),
- (cgipath, ['scripts/install_trigger.cgi']),
+ # (cgipath, ['scripts/nopxe.cgi']),
+ # (cgipath, ['scripts/install_trigger.cgi']),
# miscellaneous config files
(rotpath, ['config/cobblerd_rotate']),
(wwwconf, ['config/cobbler.conf']),
+ (wwwconf, ['config/cobbler_svc.conf']),
(cobpath, ['config/cobbler_hosts']),
(etcpath, ['config/modules.conf']),
(etcpath, ['config/users.digest']),
--
cgit
From bb84177f0e5b3de18afc12378ec18d089170a10e Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 18 Apr 2008 17:45:24 -0400
Subject: Fix some things found by the tests and also update the tests to not
look for static files
---
cobbler/action_litesync.py | 10 +---------
tests/tests.py | 4 ++--
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index 3a2de8e..89e24b4 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -56,8 +56,6 @@ class BootLiteSync:
distro = self.distros.find(name=name)
if distro is None:
raise CX(_("error in distro lookup: %s") % name)
- # generate YAML file in distros/$name in webdir
- self.sync.write_distro_file(distro)
# copy image files to images/$name in webdir & tftpboot:
self.sync.copy_single_distro_files(distro)
# cascade sync
@@ -67,8 +65,6 @@ class BootLiteSync:
def remove_single_distro(self, name):
bootloc = utils.tftpboot_location()
- # delete distro YAML file in distros/$name in webdir
- utils.rmfile(os.path.join(self.settings.webdir, "distros", name))
# delete contents of images/$name directory in webdir
utils.rmtree(os.path.join(self.settings.webdir, "images", name))
# delete contents of images/$name in tftpboot
@@ -81,8 +77,6 @@ class BootLiteSync:
profile = self.profiles.find(name=name)
if profile is None:
raise CX(_("error in profile lookup"))
- # rebuild profile_list YAML file in webdir
- self.sync.write_profile_file(profile)
# rebuild the yum configuration files for any attached repos
self.sync.retemplate_yum_repos(profile,True)
# cascade sync
@@ -113,7 +107,7 @@ class BootLiteSync:
# rebuild system_list file in webdir
self.sync.regen_ethers() # /etc/ethers, for dnsmasq & rarpd
self.sync.regen_hosts() # /var/lib/cobbler/cobbler_hosts, pretty much for dnsmasq
- # write the PXE and YAML files for the system
+ # write the PXE files for the system
self.sync.write_all_system_files(system)
# per system kickstarts
self.sync.retemplate_yum_repos(system,False)
@@ -121,8 +115,6 @@ class BootLiteSync:
def remove_single_system(self, name):
bootloc = utils.tftpboot_location()
system_record = self.systems.find(name=name)
- # delete system YAML file in systems/$name in webdir
- utils.rmfile(os.path.join(self.settings.webdir, "systems", name))
# delete contents of kickstarts_sys/$name in webdir
system_record = self.systems.find(name=name)
# delete any kickstart files related to this system
diff --git a/tests/tests.py b/tests/tests.py
index 8536a70..bb64dd1 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -743,7 +743,7 @@ class SyncContents(BootTest):
fh = open("/tftpboot/pxelinux.cfg/%s" % converted)
data = fh.read()
- self.assertTrue(data.find("kickstarts_sys") != -1)
+ self.assertTrue(data.find("op=ks") != -1)
fh.close()
# ensure that after sync is applied, the blender cache still allows
@@ -753,7 +753,7 @@ class SyncContents(BootTest):
self.api.sync()
fh = open("/tftpboot/pxelinux.cfg/%s" % converted)
data = fh.read()
- self.assertTrue(data.find("kickstarts_sys") != -1)
+ self.assertTrue(data.find("op=ks") != -1)
fh.close()
--
cgit
From aae7d2bb2133fcd171207e0c2a70ed009136d447 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 18 Apr 2008 17:48:49 -0400
Subject: Update specfile to no longer package legacy directories
---
cobbler.spec | 5 -----
1 file changed, 5 deletions(-)
diff --git a/cobbler.spec b/cobbler.spec
index 7b4e525..5ebe403 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -96,17 +96,12 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%dir /var/log/cobbler/kicklog
%dir /var/www/cobbler/
%dir /var/www/cobbler/localmirror
-%dir /var/www/cobbler/kickstarts
-%dir /var/www/cobbler/kickstarts_sys
%dir /var/www/cobbler/repo_mirror
%dir /var/www/cobbler/repos_profile
%dir /var/www/cobbler/repos_system
%dir /var/www/cobbler/ks_mirror
%dir /var/www/cobbler/ks_mirror/config
%dir /var/www/cobbler/images
-%dir /var/www/cobbler/distros
-%dir /var/www/cobbler/profiles
-%dir /var/www/cobbler/systems
%dir /var/www/cobbler/links
%defattr(755,apache,apache)
%dir /var/www/cobbler/webui
--
cgit
From b3d798bd603d4c1fe6bb6740b9f95630ba4ee483 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 18 Apr 2008 18:25:14 -0400
Subject: Abstract out sync code into it's constituent parts, plus some
packaging changes that I left out earlier.
---
MANIFEST.in | 1 +
cobbler.spec | 1 +
cobbler/action_litesync.py | 14 +-
cobbler/action_sync.py | 495 ++-------------------------------------------
cobbler/dhcpgen.py | 196 ++++++++++++++++++
cobbler/pxegen.py | 322 +++++++++++++++++++++++++++++
cobbler/webui/master.py | 4 +-
cobbler/yumgen.py | 108 ++++++++++
8 files changed, 655 insertions(+), 486 deletions(-)
create mode 100644 cobbler/dhcpgen.py
create mode 100644 cobbler/pxegen.py
create mode 100644 cobbler/yumgen.py
diff --git a/MANIFEST.in b/MANIFEST.in
index 644c0c2..3216946 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -2,6 +2,7 @@ include loaders/COPYING_ELILO
include loaders/elilo-3.6-ia64.efi
include loaders/menu.c32
include config/cobbler.conf
+include config/cobbler_svc.conf
include config/rsync.exclude
include config/cobblerd
include config/cobblerd_rotate
diff --git a/cobbler.spec b/cobbler.spec
index 5ebe403..2d0cc15 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -134,6 +134,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%{_mandir}/man1/cobbler.1.gz
/etc/init.d/cobblerd
%config(noreplace) /etc/httpd/conf.d/cobbler.conf
+%config(noreplace) /etc/httpd/conf.d/cobbler_svc.conf
%dir /var/log/cobbler/syslog
%defattr(755,root,root)
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index 89e24b4..c2029d4 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -57,7 +57,7 @@ class BootLiteSync:
if distro is None:
raise CX(_("error in distro lookup: %s") % name)
# copy image files to images/$name in webdir & tftpboot:
- self.sync.copy_single_distro_files(distro)
+ self.sync.pxegen.copy_single_distro_files(distro)
# cascade sync
kids = distro.get_children()
for k in kids:
@@ -78,7 +78,7 @@ class BootLiteSync:
if profile is None:
raise CX(_("error in profile lookup"))
# rebuild the yum configuration files for any attached repos
- self.sync.retemplate_yum_repos(profile,True)
+ self.sync.yumgen.retemplate_yum_repos(profile,True)
# cascade sync
kids = profile.get_children()
for k in kids:
@@ -97,7 +97,7 @@ class BootLiteSync:
system = self.systems.find(name=name)
if system is None:
raise CX(_("error in system lookup for %s") % name)
- self.sync.write_all_system_files(system)
+ self.sync.pxegen.write_all_system_files(system)
def add_single_system(self, name):
# get the system object:
@@ -105,12 +105,12 @@ class BootLiteSync:
if system is None:
raise CX(_("error in system lookup for %s") % name)
# rebuild system_list file in webdir
- self.sync.regen_ethers() # /etc/ethers, for dnsmasq & rarpd
- self.sync.regen_hosts() # /var/lib/cobbler/cobbler_hosts, pretty much for dnsmasq
+ self.sync.dhcpgen.regen_ethers() # /etc/ethers, for dnsmasq & rarpd
+ self.sync.dhcpgen.regen_hosts() # /var/lib/cobbler/cobbler_hosts, pretty much for dnsmasq
# write the PXE files for the system
- self.sync.write_all_system_files(system)
+ self.sync.pxegen.write_all_system_files(system)
# per system kickstarts
- self.sync.retemplate_yum_repos(system,False)
+ self.sync.yumgen.retemplate_yum_repos(system,False)
def remove_single_system(self, name):
bootloc = utils.tftpboot_location()
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index aa53d12..4156ea7 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -27,7 +27,9 @@ import errno
import utils
from cexceptions import *
import templar
-import kickgen
+import pxegen
+import dhcpgen
+import yumgen
import item_distro
import item_profile
@@ -57,7 +59,9 @@ class BootSync:
self.settings = config.settings()
self.repos = config.repos()
self.templar = templar.Templar(config)
- self.kickgen = kickgen.KickGen(config)
+ self.pxegen = pxegen.PXEGen(config)
+ self.dhcpgen = dhcpgen.DHCPGen(config)
+ self.yumgen = yumgen.YumGen(config)
self.bootloc = utils.tftpboot_location()
def run(self):
@@ -71,195 +75,35 @@ class BootSync:
# run pre-triggers...
utils.run_triggers(None, "/var/lib/cobbler/triggers/sync/pre/*")
- # in case the pre-trigger modified any objects...
+ # (paranoid) in case the pre-trigger modified any objects...
self.api.deserialize()
self.distros = self.config.distros()
self.profiles = self.config.profiles()
self.systems = self.config.systems()
self.settings = self.config.settings()
self.repos = self.config.repos()
+ self.pxegen = pxegen.PXEGen(self.config)
+ self.dhcpgen = dhcpgen.DHCPGen(self.config)
+ self.yumgen = yumgen.YumGen(self.config)
# execute the core of the sync operation
self.clean_trees()
- self.copy_bootloaders()
- self.copy_distros()
+ self.pxegen.copy_bootloaders()
+ self.pxegen.copy_distros()
for x in self.systems:
- self.write_all_system_files(x)
- self.retemplate_all_yum_repos()
+ self.pxegen.write_all_system_files(x)
+ self.yumgen.retemplate_all_yum_repos()
if self.settings.manage_dhcp:
# these functions DRT for ISC or dnsmasq
- self.write_dhcp_file()
- self.regen_ethers()
- self.regen_hosts()
- self.make_pxe_menu()
+ self.dhcpgen.write_dhcp_file()
+ self.dhcpgen.regen_ethers()
+ self.dhcpgen.regen_hosts()
+ self.pxegen.make_pxe_menu()
# run post-triggers
utils.run_triggers(None, "/var/lib/cobbler/triggers/sync/post/*")
return True
- def copy_bootloaders(self):
- """
- Copy bootloaders to the configured tftpboot directory
- NOTE: we support different arch's if defined in
- /var/lib/cobbler/settings.
- """
- for loader in self.settings.bootloaders.keys():
- path = self.settings.bootloaders[loader]
- newname = os.path.basename(path)
- destpath = os.path.join(self.bootloc, newname)
- utils.copyfile(path, destpath)
- utils.copyfile("/var/lib/cobbler/menu.c32", os.path.join(self.bootloc, "menu.c32"))
-
- # Copy memtest to tftpboot if package is installed on system
- for memtest in glob.glob('/boot/memtest*'):
- base = os.path.basename(memtest)
- utils.copyfile(memtest,os.path.join(self.bootloc,"images",base))
-
- def write_dhcp_file(self):
- """
- DHCP files are written when manage_dhcp is set in
- /var/lib/cobbler/settings.
- """
-
- settings_file = self.settings.dhcpd_conf
- template_file = "/etc/cobbler/dhcp.template"
- mode = self.settings.manage_dhcp_mode.lower()
- if mode == "dnsmasq":
- settings_file = self.settings.dnsmasq_conf
- template_file = "/etc/cobbler/dnsmasq.template"
-
- try:
- f2 = open(template_file,"r")
- except:
- raise CX(_("error writing template to file: %s") % template_file)
- template_data = ""
- template_data = f2.read()
- f2.close()
-
- # build each per-system definition
- # as configured, this only works for ISC, patches accepted
- # from those that care about Itanium. elilo seems to be unmaintained
- # so additional maintaince in other areas may be required to keep
- # this working.
-
- elilo = os.path.basename(self.settings.bootloaders["ia64"])
-
- system_definitions = {}
- counter = 0
-
- # we used to just loop through each system, but now we must loop
- # through each network interface of each system.
-
- for system in self.systems:
- profile = system.get_conceptual_parent()
- distro = profile.get_conceptual_parent()
- for (name, interface) in system.interfaces.iteritems():
-
- mac = interface["mac_address"]
- ip = interface["ip_address"]
- host = interface["hostname"]
-
- if mac is None or mac == "":
- # can't write a DHCP entry for this system
- continue
-
- counter = counter + 1
- systxt = ""
-
- if mode == "isc":
-
- # the label the entry after the hostname if possible
- if host is not None and host != "":
- systxt = "\nhost %s {\n" % host
- if self.settings.isc_set_host_name:
- systxt = systxt + " option host-name = %s;\n" % host
- else:
- systxt = "\nhost generic%d {\n" % counter
-
- if distro.arch == "ia64":
- # can't use pxelinux.0 anymore
- systxt = systxt + " filename \"/%s\";\n" % elilo
- systxt = systxt + " hardware ethernet %s;\n" % mac
- if ip is not None and ip != "":
- systxt = systxt + " fixed-address %s;\n" % ip
- systxt = systxt + "}\n"
-
- else:
- # dnsmasq. don't have to write IP and other info here, but we do tag
- # each MAC based on the arch of it's distro, if it needs something other
- # than pxelinux.0 -- for these arches, and these arches only, a dnsmasq
- # reload (full "cobbler sync") would be required after adding the system
- # to cobbler, just to tag this relationship.
-
- if ip is not None and ip != "":
- if distro.arch.lower() == "ia64":
- systxt = "dhcp-host=net:ia64," + ip + "\n"
- # support for other arches needs modifications here
- else:
- systxt = ""
-
- dhcp_tag = interface["dhcp_tag"]
- if dhcp_tag == "":
- dhcp_tag = "default"
-
- if not system_definitions.has_key(dhcp_tag):
- system_definitions[dhcp_tag] = ""
- system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt
-
- # we are now done with the looping through each interface of each system
-
- metadata = {
- "insert_cobbler_system_definitions" : system_definitions.get("default",""),
- "date" : time.asctime(time.gmtime()),
- "cobbler_server" : self.settings.server,
- "next_server" : self.settings.next_server,
- "elilo" : elilo
- }
-
- # now add in other DHCP expansions that are not tagged with "default"
- for x in system_definitions.keys():
- if x == "default":
- continue
- metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
-
- self.templar.render(template_data, metadata, settings_file, None)
-
- def regen_ethers(self):
- # dnsmasq knows how to read this database of MACs -> IPs, so we'll keep it up to date
- # every time we add a system.
- # read 'man ethers' for format info
- fh = open("/etc/ethers","w+")
- for sys in self.systems:
- for (name, interface) in sys.interfaces.iteritems():
- mac = interface["mac_address"]
- ip = interface["ip_address"]
- if mac is None or mac == "":
- # can't write this w/o a MAC address
- continue
- if ip is not None and ip != "":
- fh.write(mac.upper() + "\t" + ip + "\n")
- fh.close()
-
- def regen_hosts(self):
- # dnsmasq knows how to read this database for host info
- # (other things may also make use of this later)
- fh = open("/var/lib/cobbler/cobbler_hosts","w+")
- for sys in self.systems:
- for (name, interface) in sys.interfaces.iteritems():
- mac = interface["mac_address"]
- host = interface["hostname"]
- ip = interface["ip_address"]
- if mac is None or mac == "":
- continue
- if host is not None and host != "" and ip is not None and ip != "":
- fh.write(ip + "\t" + host + "\n")
- fh.close()
-
-
- #def templatify(self, data, metadata, outfile):
- # for x in metadata.keys():
- # template_data = template_data.replace("$%s" % x, metadata[x])
-
def clean_trees(self):
"""
Delete any previously built pxelinux.cfg tree and virt tree info and then create
@@ -288,307 +132,4 @@ class BootSync:
utils.rmtree_contents(os.path.join(self.bootloc, "pxelinux.cfg"))
utils.rmtree_contents(os.path.join(self.bootloc, "images"))
- def copy_distros(self):
- """
- A distro is a kernel and an initrd. Copy all of them and error
- out if any files are missing. The conf file was correct if built
- via the CLI or API, though it's possible files have been moved
- since or perhaps they reference NFS directories that are no longer
- mounted.
-
- NOTE: this has to be done for both tftp and http methods
- """
- # copy is a 4-letter word but tftpboot runs chroot, thus it's required.
- for d in self.distros:
- print _("sync distro: %s") % d.name
- self.copy_single_distro_files(d)
-
- def copy_single_distro_files(self, d):
- for dirtree in [self.bootloc, self.settings.webdir]:
- distros = os.path.join(dirtree, "images")
- distro_dir = os.path.join(distros,d.name)
- utils.mkdir(distro_dir)
- kernel = utils.find_kernel(d.kernel) # full path
- initrd = utils.find_initrd(d.initrd) # full path
- if kernel is None or not os.path.isfile(kernel):
- raise CX(_("kernel not found: %(file)s, distro: %(distro)s") % { "file" : d.kernel, "distro" : d.name })
- if initrd is None or not os.path.isfile(initrd):
- raise CX(_("initrd not found: %(file)s, distro: %(distro)s") % { "file" : d.initrd, "distro" : d.name })
- b_kernel = os.path.basename(kernel)
- b_initrd = os.path.basename(initrd)
- if kernel.startswith(dirtree):
- utils.linkfile(kernel, os.path.join(distro_dir, b_kernel))
- else:
- utils.copyfile(kernel, os.path.join(distro_dir, b_kernel))
- if initrd.startswith(dirtree):
- utils.linkfile(initrd, os.path.join(distro_dir, b_initrd))
- else:
- utils.copyfile(initrd, os.path.join(distro_dir, b_initrd))
-
- def retemplate_all_yum_repos(self):
- for p in self.profiles:
- self.retemplate_yum_repos(p,True)
- for system in self.systems:
- self.retemplate_yum_repos(system,False)
-
- def retemplate_yum_repos(self,obj,is_profile):
- """
- Yum repository management files are in self.settings.webdir/repo_mirror/$name/config.repo
- and also potentially in listed in the source_repos structure of the distro object, however
- these files have server URLs in them that must be templated out. This function does this.
- """
- blended = utils.blender(self.api, False, obj)
-
- if is_profile:
- outseg = "repos_profile"
- else:
- outseg = "repos_system"
-
- input_files = []
-
- # chance old versions from upgrade do not have a source_repos
- # workaround for user bug
- if not blended.has_key("source_repos"):
- blended["source_repos"] = []
-
- # tack on all the install source repos IF there is more than one.
- # this is basically to support things like RHEL5 split trees
- # if there is only one, then there is no need to do this.
-
- for r in blended["source_repos"]:
- filename = self.settings.webdir + "/" + "/".join(r[0].split("/")[4:])
- input_files.append(filename)
-
- for repo in blended["repos"]:
- input_files.append(os.path.join(self.settings.webdir, "repo_mirror", repo, "config.repo"))
-
- for infile in input_files:
- if infile.find("ks_mirror") == -1:
- dispname = infile.split("/")[-2]
- else:
- dispname = infile.split("/")[-1].replace(".repo","")
- confdir = os.path.join(self.settings.webdir, outseg)
- outdir = os.path.join(confdir, blended["name"])
- utils.mkdir(outdir)
- try:
- infile_h = open(infile)
- except:
- print _("WARNING: cobbler reposync needs to be run on repo (%s), then re-run cobbler sync") % dispname
- continue
- infile_data = infile_h.read()
- infile_h.close()
- outfile = os.path.join(outdir, "%s.repo" % (dispname))
- self.templar.render(infile_data, blended, outfile, None)
-
-
- def write_all_system_files(self,system):
-
- profile = system.get_conceptual_parent()
- if profile is None:
- raise CX(_("system %(system)s references a missing profile %(profile)s") % { "system" : system.name, "profile" : system.profile})
- distro = profile.get_conceptual_parent()
- if distro is None:
- raise CX(_("profile %(profile)s references a missing distro %(distro)s") % { "profile" : system.profile, "distro" : profile.distro})
-
- # this used to just generate a single PXE config file, but now must
- # generate one record for each described NIC ...
-
- counter = 0
- for (name,interface) in system.interfaces.iteritems():
-
- ip = interface["ip_address"]
-
- f1 = utils.get_config_filename(system,interface=name)
-
- # for tftp only ...
- if distro.arch in [ "x86", "x86_64", "standard"]:
- # pxelinux wants a file named $name under pxelinux.cfg
- f2 = os.path.join(self.bootloc, "pxelinux.cfg", f1)
- if distro.arch == "ia64":
- # elilo expects files to be named "$name.conf" in the root
- # and can not do files based on the MAC address
- if ip is not None and ip != "":
- print _("Warning: Itanium system object (%s) needs an IP address to PXE") % system.name
-
- filename = "%s.conf" % utils.get_config_filename(system,interface=name)
- f2 = os.path.join(self.bootloc, filename)
-
- f3 = os.path.join(self.settings.webdir, "systems", f1)
-
- if system.netboot_enabled and system.is_pxe_supported():
- if distro.arch in [ "x86", "x86_64", "standard"]:
- self.write_pxe_file(f2,system,profile,distro,False)
- if distro.arch == "ia64":
- self.write_pxe_file(f2,system,profile,distro,True)
- else:
- # ensure the file doesn't exist
- utils.rmfile(f2)
-
- counter = counter + 1
-
-
- def make_pxe_menu(self):
- # only do this if there is NOT a system named default.
- default = self.systems.find(name="default")
- if default is not None:
- return
-
- fname = os.path.join(self.bootloc, "pxelinux.cfg", "default")
-
- # read the default template file
- template_src = open("/etc/cobbler/pxedefault.template")
- template_data = template_src.read()
-
- # sort the profiles
- profile_list = [profile for profile in self.profiles]
- def sort_name(a,b):
- return cmp(a.name,b.name)
- profile_list.sort(sort_name)
-
- # build out the menu entries
- pxe_menu_items = ""
- for profile in profile_list:
- distro = profile.get_conceptual_parent()
- contents = self.write_pxe_file(None,None,profile,distro,False,include_header=False)
- if contents is not None:
- pxe_menu_items = pxe_menu_items + contents + "\n"
-
- # if we have any memtest files in images, make entries for them
- # after we list the profiles
- memtests = glob.glob(self.bootloc + "/images/memtest*")
- if len(memtests) > 0:
- pxe_menu_items = pxe_menu_items + "\n\n"
- for memtest in glob.glob(self.bootloc + '/memtest*'):
- base = os.path.basename(memtest)
- contents = self.write_memtest_pxe("/images/%s" % base)
- pxe_menu_items = pxe_menu_items + contents + "\n"
-
- # save the template.
- metadata = { "pxe_menu_items" : pxe_menu_items }
- outfile = os.path.join(self.bootloc, "pxelinux.cfg", "default")
- self.templar.render(template_data, metadata, outfile, None)
- template_src.close()
-
- def write_memtest_pxe(self,filename):
- """
- Write a configuration file for memtest
- """
-
- # just some random variables
- template = None
- metadata = {}
- buffer = ""
-
- template = "/etc/cobbler/pxeprofile.template"
-
- # store variables for templating
- metadata["menu_label"] = "MENU LABEL %s" % os.path.basename(filename)
- metadata["profile_name"] = os.path.basename(filename)
- metadata["kernel_path"] = "/images/%s" % os.path.basename(filename)
- metadata["initrd_path"] = ""
- metadata["append_line"] = ""
-
- # get the template
- template_fh = open(template)
- template_data = template_fh.read()
- template_fh.close()
-
- # return results
- buffer = self.templar.render(template_data, metadata, None)
- return buffer
-
-
-
- def write_pxe_file(self,filename,system,profile,distro,is_ia64, include_header=True):
- """
- Write a configuration file for the boot loader(s).
- More system-specific configuration may come in later, if so
- that would appear inside the system object in api.py
-
- NOTE: relevant to tftp only
- """
-
- # ---
- # system might have netboot_enabled set to False (see item_system.py), if so,
- # don't do anything else and flag the error condition.
- if system is not None and not system.netboot_enabled:
- return None
-
- # ---
- # just some random variables
- template = None
- metadata = {}
- buffer = ""
-
- # ---
- # find kernel and initrd
- kernel_path = os.path.join("/images",distro.name,os.path.basename(distro.kernel))
- initrd_path = os.path.join("/images",distro.name,os.path.basename(distro.initrd))
-
- # Find the kickstart if we inherit from another profile
- kickstart_path = utils.blender(self.api, True, profile)["kickstart"]
-
- # ---
- # choose a template
- if system is None:
- template = "/etc/cobbler/pxeprofile.template"
- elif not is_ia64:
- template = "/etc/cobbler/pxesystem.template"
- else:
- template = "/etc/cobbler/pxesystem_ia64.template"
-
- # now build the kernel command line
- if system is not None:
- blended = utils.blender(self.api, True, system)
- else:
- blended = utils.blender(self.api, True,profile)
- kopts = blended["kernel_options"]
-
- # generate the append line
- append_line = "append %s" % utils.hash_to_string(kopts)
- if not is_ia64:
- append_line = "%s initrd=%s" % (append_line, initrd_path)
- if len(append_line) >= 255 + len("append "):
- print _("warning: kernel option length exceeds 255")
-
- # kickstart path rewriting (get URLs for local files)
- if kickstart_path is not None and kickstart_path != "":
-
- if system is not None and kickstart_path.startswith("/"):
- kickstart_path = "http://%s/cblr/svc/?op=ks&system=%s" % (blended["http_server"], system.name)
- elif kickstart_path.startswith("/") or kickstart_path.find("/cobbler/kickstarts/") != -1:
- kickstart_path = "http://%s/cblr/svc/?op=ks&profile=%s" % (blended["http_server"], profile.name)
-
- if distro.breed is None or distro.breed == "redhat":
- append_line = "%s ks=%s" % (append_line, kickstart_path)
- elif distro.breed == "suse":
- append_line = "%s autoyast=%s" % (append_line, kickstart_path)
- elif distro.breed == "debian":
- append_line = "%s auto=true url=%s" % (append_line, kickstart_path)
- append_line = append_line.replace("ksdevice","interface")
-
- # store variables for templating
- metadata["menu_label"] = ""
- if not is_ia64 and system is None:
- metadata["menu_label"] = "MENU LABEL %s" % profile.name
- metadata["profile_name"] = profile.name
- metadata["kernel_path"] = kernel_path
- metadata["initrd_path"] = initrd_path
- metadata["append_line"] = append_line
-
- # get the template
- template_fh = open(template)
- template_data = template_fh.read()
- template_fh.close()
-
- # save file and/or return results, depending on how called.
- buffer = self.templar.render(template_data, metadata, None)
- if filename is not None:
- fd = open(filename, "w")
- fd.write(buffer)
- fd.close()
- return buffer
-
-
-
diff --git a/cobbler/dhcpgen.py b/cobbler/dhcpgen.py
new file mode 100644
index 0000000..0ec3dda
--- /dev/null
+++ b/cobbler/dhcpgen.py
@@ -0,0 +1,196 @@
+"""
+Builds out DHCP info
+This is the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+class DHCPGen:
+ """
+ Handles conversion of internal state to the tftpboot tree layout
+ """
+
+ def __init__(self,config,verbose=False):
+ """
+ Constructor
+ """
+ self.verbose = verbose
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+
+ def write_dhcp_file(self):
+ """
+ DHCP files are written when manage_dhcp is set in
+ /var/lib/cobbler/settings.
+ """
+
+ settings_file = self.settings.dhcpd_conf
+ template_file = "/etc/cobbler/dhcp.template"
+ mode = self.settings.manage_dhcp_mode.lower()
+ if mode == "dnsmasq":
+ settings_file = self.settings.dnsmasq_conf
+ template_file = "/etc/cobbler/dnsmasq.template"
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error writing template to file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ # build each per-system definition
+ # as configured, this only works for ISC, patches accepted
+ # from those that care about Itanium. elilo seems to be unmaintained
+ # so additional maintaince in other areas may be required to keep
+ # this working.
+
+ elilo = os.path.basename(self.settings.bootloaders["ia64"])
+
+ system_definitions = {}
+ counter = 0
+
+ # we used to just loop through each system, but now we must loop
+ # through each network interface of each system.
+
+ for system in self.systems:
+ profile = system.get_conceptual_parent()
+ distro = profile.get_conceptual_parent()
+ for (name, interface) in system.interfaces.iteritems():
+
+ mac = interface["mac_address"]
+ ip = interface["ip_address"]
+ host = interface["hostname"]
+
+ if mac is None or mac == "":
+ # can't write a DHCP entry for this system
+ continue
+
+ counter = counter + 1
+ systxt = ""
+
+ if mode == "isc":
+
+ # the label the entry after the hostname if possible
+ if host is not None and host != "":
+ systxt = "\nhost %s {\n" % host
+ if self.settings.isc_set_host_name:
+ systxt = systxt + " option host-name = %s;\n" % host
+ else:
+ systxt = "\nhost generic%d {\n" % counter
+
+ if distro.arch == "ia64":
+ # can't use pxelinux.0 anymore
+ systxt = systxt + " filename \"/%s\";\n" % elilo
+ systxt = systxt + " hardware ethernet %s;\n" % mac
+ if ip is not None and ip != "":
+ systxt = systxt + " fixed-address %s;\n" % ip
+ systxt = systxt + "}\n"
+
+ else:
+ # dnsmasq. don't have to write IP and other info here, but we do tag
+ # each MAC based on the arch of it's distro, if it needs something other
+ # than pxelinux.0 -- for these arches, and these arches only, a dnsmasq
+ # reload (full "cobbler sync") would be required after adding the system
+ # to cobbler, just to tag this relationship.
+
+ if ip is not None and ip != "":
+ if distro.arch.lower() == "ia64":
+ systxt = "dhcp-host=net:ia64," + ip + "\n"
+ # support for other arches needs modifications here
+ else:
+ systxt = ""
+
+ dhcp_tag = interface["dhcp_tag"]
+ if dhcp_tag == "":
+ dhcp_tag = "default"
+
+ if not system_definitions.has_key(dhcp_tag):
+ system_definitions[dhcp_tag] = ""
+ system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt
+
+ # we are now done with the looping through each interface of each system
+
+ metadata = {
+ "insert_cobbler_system_definitions" : system_definitions.get("default",""),
+ "date" : time.asctime(time.gmtime()),
+ "cobbler_server" : self.settings.server,
+ "next_server" : self.settings.next_server,
+ "elilo" : elilo
+ }
+
+ # now add in other DHCP expansions that are not tagged with "default"
+ for x in system_definitions.keys():
+ if x == "default":
+ continue
+ metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
+
+ self.templar.render(template_data, metadata, settings_file, None)
+
+ def regen_ethers(self):
+ # dnsmasq knows how to read this database of MACs -> IPs, so we'll keep it up to date
+ # every time we add a system.
+ # read 'man ethers' for format info
+ fh = open("/etc/ethers","w+")
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ mac = interface["mac_address"]
+ ip = interface["ip_address"]
+ if mac is None or mac == "":
+ # can't write this w/o a MAC address
+ continue
+ if ip is not None and ip != "":
+ fh.write(mac.upper() + "\t" + ip + "\n")
+ fh.close()
+
+ def regen_hosts(self):
+ # dnsmasq knows how to read this database for host info
+ # (other things may also make use of this later)
+ fh = open("/var/lib/cobbler/cobbler_hosts","w+")
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ mac = interface["mac_address"]
+ host = interface["hostname"]
+ ip = interface["ip_address"]
+ if mac is None or mac == "":
+ continue
+ if host is not None and host != "" and ip is not None and ip != "":
+ fh.write(ip + "\t" + host + "\n")
+ fh.close()
+
+
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
new file mode 100644
index 0000000..527b6a2
--- /dev/null
+++ b/cobbler/pxegen.py
@@ -0,0 +1,322 @@
+"""
+Builds out filesystem trees/data based on the object tree.
+This is the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+
+class PXEGen:
+ """
+ Handles building out PXE stuff
+ """
+
+ def __init__(self,config):
+ """
+ Constructor
+ """
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+ self.bootloc = utils.tftpboot_location()
+
+ def copy_bootloaders(self):
+ """
+ Copy bootloaders to the configured tftpboot directory
+ NOTE: we support different arch's if defined in
+ /var/lib/cobbler/settings.
+ """
+ for loader in self.settings.bootloaders.keys():
+ path = self.settings.bootloaders[loader]
+ newname = os.path.basename(path)
+ destpath = os.path.join(self.bootloc, newname)
+ utils.copyfile(path, destpath)
+ utils.copyfile("/var/lib/cobbler/menu.c32", os.path.join(self.bootloc, "menu.c32"))
+
+ # Copy memtest to tftpboot if package is installed on system
+ for memtest in glob.glob('/boot/memtest*'):
+ base = os.path.basename(memtest)
+ utils.copyfile(memtest,os.path.join(self.bootloc,"images",base))
+
+ def copy_distros(self):
+ """
+ A distro is a kernel and an initrd. Copy all of them and error
+ out if any files are missing. The conf file was correct if built
+ via the CLI or API, though it's possible files have been moved
+ since or perhaps they reference NFS directories that are no longer
+ mounted.
+
+ NOTE: this has to be done for both tftp and http methods
+ """
+ # copy is a 4-letter word but tftpboot runs chroot, thus it's required.
+ for d in self.distros:
+ print _("sync distro: %s") % d.name
+ self.copy_single_distro_files(d)
+
+ def copy_single_distro_files(self, d):
+ for dirtree in [self.bootloc, self.settings.webdir]:
+ distros = os.path.join(dirtree, "images")
+ distro_dir = os.path.join(distros,d.name)
+ utils.mkdir(distro_dir)
+ kernel = utils.find_kernel(d.kernel) # full path
+ initrd = utils.find_initrd(d.initrd) # full path
+ if kernel is None or not os.path.isfile(kernel):
+ raise CX(_("kernel not found: %(file)s, distro: %(distro)s") % { "file" : d.kernel, "distro" : d.name })
+ if initrd is None or not os.path.isfile(initrd):
+ raise CX(_("initrd not found: %(file)s, distro: %(distro)s") % { "file" : d.initrd, "distro" : d.name })
+ b_kernel = os.path.basename(kernel)
+ b_initrd = os.path.basename(initrd)
+ if kernel.startswith(dirtree):
+ utils.linkfile(kernel, os.path.join(distro_dir, b_kernel))
+ else:
+ utils.copyfile(kernel, os.path.join(distro_dir, b_kernel))
+ if initrd.startswith(dirtree):
+ utils.linkfile(initrd, os.path.join(distro_dir, b_initrd))
+ else:
+ utils.copyfile(initrd, os.path.join(distro_dir, b_initrd))
+
+ def write_all_system_files(self,system):
+
+ profile = system.get_conceptual_parent()
+ if profile is None:
+ raise CX(_("system %(system)s references a missing profile %(profile)s") % { "system" : system.name, "profile" : system.profile})
+ distro = profile.get_conceptual_parent()
+ if distro is None:
+ raise CX(_("profile %(profile)s references a missing distro %(distro)s") % { "profile" : system.profile, "distro" : profile.distro})
+
+ # this used to just generate a single PXE config file, but now must
+ # generate one record for each described NIC ...
+
+ counter = 0
+ for (name,interface) in system.interfaces.iteritems():
+
+ ip = interface["ip_address"]
+
+ f1 = utils.get_config_filename(system,interface=name)
+
+ # for tftp only ...
+ if distro.arch in [ "x86", "x86_64", "standard"]:
+ # pxelinux wants a file named $name under pxelinux.cfg
+ f2 = os.path.join(self.bootloc, "pxelinux.cfg", f1)
+ if distro.arch == "ia64":
+ # elilo expects files to be named "$name.conf" in the root
+ # and can not do files based on the MAC address
+ if ip is not None and ip != "":
+ print _("Warning: Itanium system object (%s) needs an IP address to PXE") % system.name
+
+ filename = "%s.conf" % utils.get_config_filename(system,interface=name)
+ f2 = os.path.join(self.bootloc, filename)
+
+ f3 = os.path.join(self.settings.webdir, "systems", f1)
+
+ if system.netboot_enabled and system.is_pxe_supported():
+ if distro.arch in [ "x86", "x86_64", "standard"]:
+ self.write_pxe_file(f2,system,profile,distro,False)
+ if distro.arch == "ia64":
+ self.write_pxe_file(f2,system,profile,distro,True)
+ else:
+ # ensure the file doesn't exist
+ utils.rmfile(f2)
+
+ counter = counter + 1
+
+
+ def make_pxe_menu(self):
+ # only do this if there is NOT a system named default.
+ default = self.systems.find(name="default")
+ if default is not None:
+ return
+
+ fname = os.path.join(self.bootloc, "pxelinux.cfg", "default")
+
+ # read the default template file
+ template_src = open("/etc/cobbler/pxedefault.template")
+ template_data = template_src.read()
+
+ # sort the profiles
+ profile_list = [profile for profile in self.profiles]
+ def sort_name(a,b):
+ return cmp(a.name,b.name)
+ profile_list.sort(sort_name)
+
+ # build out the menu entries
+ pxe_menu_items = ""
+ for profile in profile_list:
+ distro = profile.get_conceptual_parent()
+ contents = self.write_pxe_file(None,None,profile,distro,False,include_header=False)
+ if contents is not None:
+ pxe_menu_items = pxe_menu_items + contents + "\n"
+
+ # if we have any memtest files in images, make entries for them
+ # after we list the profiles
+ memtests = glob.glob(self.bootloc + "/images/memtest*")
+ if len(memtests) > 0:
+ pxe_menu_items = pxe_menu_items + "\n\n"
+ for memtest in glob.glob(self.bootloc + '/memtest*'):
+ base = os.path.basename(memtest)
+ contents = self.write_memtest_pxe("/images/%s" % base)
+ pxe_menu_items = pxe_menu_items + contents + "\n"
+
+ # save the template.
+ metadata = { "pxe_menu_items" : pxe_menu_items }
+ outfile = os.path.join(self.bootloc, "pxelinux.cfg", "default")
+ self.templar.render(template_data, metadata, outfile, None)
+ template_src.close()
+
+ def write_memtest_pxe(self,filename):
+ """
+ Write a configuration file for memtest
+ """
+
+ # just some random variables
+ template = None
+ metadata = {}
+ buffer = ""
+
+ template = "/etc/cobbler/pxeprofile.template"
+
+ # store variables for templating
+ metadata["menu_label"] = "MENU LABEL %s" % os.path.basename(filename)
+ metadata["profile_name"] = os.path.basename(filename)
+ metadata["kernel_path"] = "/images/%s" % os.path.basename(filename)
+ metadata["initrd_path"] = ""
+ metadata["append_line"] = ""
+
+ # get the template
+ template_fh = open(template)
+ template_data = template_fh.read()
+ template_fh.close()
+
+ # return results
+ buffer = self.templar.render(template_data, metadata, None)
+ return buffer
+
+
+
+ def write_pxe_file(self,filename,system,profile,distro,is_ia64, include_header=True):
+ """
+ Write a configuration file for the boot loader(s).
+ More system-specific configuration may come in later, if so
+ that would appear inside the system object in api.py
+
+ NOTE: relevant to tftp only
+ """
+
+ # ---
+ # system might have netboot_enabled set to False (see item_system.py), if so,
+ # don't do anything else and flag the error condition.
+ if system is not None and not system.netboot_enabled:
+ return None
+
+ # ---
+ # just some random variables
+ template = None
+ metadata = {}
+ buffer = ""
+
+ # ---
+ # find kernel and initrd
+ kernel_path = os.path.join("/images",distro.name,os.path.basename(distro.kernel))
+ initrd_path = os.path.join("/images",distro.name,os.path.basename(distro.initrd))
+
+ # Find the kickstart if we inherit from another profile
+ kickstart_path = utils.blender(self.api, True, profile)["kickstart"]
+
+ # ---
+ # choose a template
+ if system is None:
+ template = "/etc/cobbler/pxeprofile.template"
+ elif not is_ia64:
+ template = "/etc/cobbler/pxesystem.template"
+ else:
+ template = "/etc/cobbler/pxesystem_ia64.template"
+
+ # now build the kernel command line
+ if system is not None:
+ blended = utils.blender(self.api, True, system)
+ else:
+ blended = utils.blender(self.api, True,profile)
+ kopts = blended["kernel_options"]
+
+ # generate the append line
+ append_line = "append %s" % utils.hash_to_string(kopts)
+ if not is_ia64:
+ append_line = "%s initrd=%s" % (append_line, initrd_path)
+ if len(append_line) >= 255 + len("append "):
+ print _("warning: kernel option length exceeds 255")
+
+ # kickstart path rewriting (get URLs for local files)
+ if kickstart_path is not None and kickstart_path != "":
+
+ if system is not None and kickstart_path.startswith("/"):
+ kickstart_path = "http://%s/cblr/svc/?op=ks&system=%s" % (blended["http_server"], system.name)
+ elif kickstart_path.startswith("/") or kickstart_path.find("/cobbler/kickstarts/") != -1:
+ kickstart_path = "http://%s/cblr/svc/?op=ks&profile=%s" % (blended["http_server"], profile.name)
+
+ if distro.breed is None or distro.breed == "redhat":
+ append_line = "%s ks=%s" % (append_line, kickstart_path)
+ elif distro.breed == "suse":
+ append_line = "%s autoyast=%s" % (append_line, kickstart_path)
+ elif distro.breed == "debian":
+ append_line = "%s auto=true url=%s" % (append_line, kickstart_path)
+ append_line = append_line.replace("ksdevice","interface")
+
+ # store variables for templating
+ metadata["menu_label"] = ""
+ if not is_ia64 and system is None:
+ metadata["menu_label"] = "MENU LABEL %s" % profile.name
+ metadata["profile_name"] = profile.name
+ metadata["kernel_path"] = kernel_path
+ metadata["initrd_path"] = initrd_path
+ metadata["append_line"] = append_line
+
+ # get the template
+ template_fh = open(template)
+ template_data = template_fh.read()
+ template_fh.close()
+
+ # save file and/or return results, depending on how called.
+ buffer = self.templar.render(template_data, metadata, None)
+ if filename is not None:
+ fd = open(filename, "w")
+ fd.write(buffer)
+ fd.close()
+ return buffer
+
+
+
+
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 0eec178..14f06b5 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -33,8 +33,8 @@ VFN=valueForName
currentTime=time.time
__CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1208545841.2024181
-__CHEETAH_genTimestamp__ = 'Fri Apr 18 15:10:41 2008'
+__CHEETAH_genTime__ = 1208557454.7957201
+__CHEETAH_genTimestamp__ = 'Fri Apr 18 18:24:14 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
__CHEETAH_srcLastModified__ = 'Fri Feb 15 14:47:43 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
diff --git a/cobbler/yumgen.py b/cobbler/yumgen.py
new file mode 100644
index 0000000..e39a72e
--- /dev/null
+++ b/cobbler/yumgen.py
@@ -0,0 +1,108 @@
+"""
+Builds out filesystem trees/data based on the object tree.
+This is the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+
+class YumGen:
+
+ def __init__(self,config):
+ """
+ Constructor
+ """
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+
+ def retemplate_all_yum_repos(self):
+ for p in self.profiles:
+ self.retemplate_yum_repos(p,True)
+ for system in self.systems:
+ self.retemplate_yum_repos(system,False)
+
+ def retemplate_yum_repos(self,obj,is_profile):
+ """
+ Yum repository management files are in self.settings.webdir/repo_mirror/$name/config.repo
+ and also potentially in listed in the source_repos structure of the distro object, however
+ these files have server URLs in them that must be templated out. This function does this.
+ """
+ blended = utils.blender(self.api, False, obj)
+
+ if is_profile:
+ outseg = "repos_profile"
+ else:
+ outseg = "repos_system"
+
+ input_files = []
+
+ # chance old versions from upgrade do not have a source_repos
+ # workaround for user bug
+ if not blended.has_key("source_repos"):
+ blended["source_repos"] = []
+
+ # tack on all the install source repos IF there is more than one.
+ # this is basically to support things like RHEL5 split trees
+ # if there is only one, then there is no need to do this.
+
+ for r in blended["source_repos"]:
+ filename = self.settings.webdir + "/" + "/".join(r[0].split("/")[4:])
+ input_files.append(filename)
+
+ for repo in blended["repos"]:
+ input_files.append(os.path.join(self.settings.webdir, "repo_mirror", repo, "config.repo"))
+
+ for infile in input_files:
+ if infile.find("ks_mirror") == -1:
+ dispname = infile.split("/")[-2]
+ else:
+ dispname = infile.split("/")[-1].replace(".repo","")
+ confdir = os.path.join(self.settings.webdir, outseg)
+ outdir = os.path.join(confdir, blended["name"])
+ utils.mkdir(outdir)
+ try:
+ infile_h = open(infile)
+ except:
+ print _("WARNING: cobbler reposync needs to be run on repo (%s), then re-run cobbler sync") % dispname
+ continue
+ infile_data = infile_h.read()
+ infile_h.close()
+ outfile = os.path.join(outdir, "%s.repo" % (dispname))
+ self.templar.render(infile_data, blended, outfile, None)
+
+
--
cgit
From 91f390fbd37b6e185342bda84dfa5179d46bf7d8 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 21 Apr 2008 10:49:35 -0400
Subject: Add isc_set_hostname to packaged settings file
---
config/settings | 1 +
1 file changed, 1 insertion(+)
diff --git a/config/settings b/config/settings
index 10e06e2..0a3aaa4 100644
--- a/config/settings
+++ b/config/settings
@@ -16,6 +16,7 @@ dnsmasq_bin: /usr/sbin/dnsmasq
dnsmasq_conf: /etc/dnsmasq.conf
httpd_bin: /usr/sbin/httpd
http_port: 80
+isc_set_host_name: 0
kerberos_realm: 'example.org'
kernel_options:
ksdevice: eth0
--
cgit
From 6284e8477856ec3b84e06d5e01c05ea226e33a2f Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 21 Apr 2008 11:03:42 -0400
Subject: Fix memtest location
---
cobbler/pxegen.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
index 527b6a2..e39fdc8 100644
--- a/cobbler/pxegen.py
+++ b/cobbler/pxegen.py
@@ -186,7 +186,7 @@ class PXEGen:
memtests = glob.glob(self.bootloc + "/images/memtest*")
if len(memtests) > 0:
pxe_menu_items = pxe_menu_items + "\n\n"
- for memtest in glob.glob(self.bootloc + '/memtest*'):
+ for memtest in glob.glob(self.bootloc + '/images/memtest*'):
base = os.path.basename(memtest)
contents = self.write_memtest_pxe("/images/%s" % base)
pxe_menu_items = pxe_menu_items + contents + "\n"
--
cgit
From 54f590b14b728a7554a879870ef7c65b00d9ffb0 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 21 Apr 2008 14:42:38 -0400
Subject: Correct URLs in kickstart post
---
cobbler/kickgen.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index dce33f3..b0d0a62 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -96,8 +96,8 @@ class KickGen:
nopxe = "\nwget \"http://%s/cblr/svc/?op=nopxe&system=%s\" -O /dev/null"
saveks = "\nwget \"http://%s/cblr/svc/?op=ks&%s=%s\" -O /root/cobbler.ks"
- runpost = "\nwget \"http://%s/cblr/srv/?op=trig&?mode=post&%s=%s\" -O /dev/null"
- runpre = "\nwget \"http://%s/cblr/srv/?op=trig&?mode=pre&%s=%s\" -O /dev/null"
+ runpost = "\nwget \"http://%s/cblr/svc/?op=trig&?mode=post&%s=%s\" -O /dev/null"
+ runpre = "\nwget \"http://%s/cblr/svc/?op=trig&?mode=pre&%s=%s\" -O /dev/null"
what = "profile"
blend_this = profile
--
cgit
From 6e65a221533c36ffb8b3bb5bc5338944dd0523fd Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 21 Apr 2008 16:51:38 -0400
Subject: Send registration parameters at the right spot.
---
cobbler/kickgen.py | 4 ++--
cobbler/pxegen.py | 2 ++
cobbler/remote.py | 2 +-
config/settings | 1 -
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index b0d0a62..1b1cfdd 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -96,8 +96,8 @@ class KickGen:
nopxe = "\nwget \"http://%s/cblr/svc/?op=nopxe&system=%s\" -O /dev/null"
saveks = "\nwget \"http://%s/cblr/svc/?op=ks&%s=%s\" -O /root/cobbler.ks"
- runpost = "\nwget \"http://%s/cblr/svc/?op=trig&?mode=post&%s=%s\" -O /dev/null"
- runpre = "\nwget \"http://%s/cblr/svc/?op=trig&?mode=pre&%s=%s\" -O /dev/null"
+ runpost = "\nwget \"http://%s/cblr/svc/?op=trig&mode=post&%s=%s\" -O /dev/null"
+ runpre = "\nwget \"http://%s/cblr/svc/?op=trig&mode=pre&%s=%s\" -O /dev/null"
what = "profile"
blend_this = profile
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
index e39fdc8..a8a9af6 100644
--- a/cobbler/pxegen.py
+++ b/cobbler/pxegen.py
@@ -286,6 +286,8 @@ class PXEGen:
kickstart_path = "http://%s/cblr/svc/?op=ks&system=%s" % (blended["http_server"], system.name)
elif kickstart_path.startswith("/") or kickstart_path.find("/cobbler/kickstarts/") != -1:
kickstart_path = "http://%s/cblr/svc/?op=ks&profile=%s" % (blended["http_server"], profile.name)
+ if self.settings.register_new_installs:
+ kickstart_path = kickstart_path + "®=1"
if distro.breed is None or distro.breed == "redhat":
append_line = "%s ks=%s" % (append_line, kickstart_path)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index a87355b..17be852 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -201,7 +201,7 @@ class CobblerXMLRPCInterface:
READ: https://fedorahosted.org/cobbler/wiki/AutoRegistration
"""
- if not self.api.settings().allow_cgi_mac_registration:
+ if not self.api.settings().register_new_installs:
return 1
system = self.api.find_system(mac_address=mac)
diff --git a/config/settings b/config/settings
index 0a3aaa4..10e06e2 100644
--- a/config/settings
+++ b/config/settings
@@ -16,7 +16,6 @@ dnsmasq_bin: /usr/sbin/dnsmasq
dnsmasq_conf: /etc/dnsmasq.conf
httpd_bin: /usr/sbin/httpd
http_port: 80
-isc_set_host_name: 0
kerberos_realm: 'example.org'
kernel_options:
ksdevice: eth0
--
cgit
From d02bc788cf637b3e5f8805c03d800170f7e22c32 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 21 Apr 2008 17:27:35 -0400
Subject: Modify services.py to send over registration bit.
---
cobbler/services.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/services.py b/cobbler/services.py
index 9ced0c6..fde62bb 100644
--- a/cobbler/services.py
+++ b/cobbler/services.py
@@ -66,7 +66,7 @@ class CobblerSvc(object):
Generate kickstart files...
"""
self.__xmlrpc_setup()
- return self.remote.generate_kickstart(profile,system,REMOTE_ADDR,REMOTE_MAC)
+ return self.remote.generate_kickstart(profile,system,REMOTE_ADDR,REMOTE_MAC,reg)
def trig(self,mode="?",profile=None,system=None,REMOTE_ADDR=None,**rest):
"""
--
cgit
From 912231cabd05f4b6ffebfde8bce77037281b0f20 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 21 Apr 2008 18:21:39 -0400
Subject: Move registration code to backend only, as users trying out the
kickstarts will not be sending mac info and there is not a problem of them
accidentally getting registered.
---
cobbler/pxegen.py | 2 --
cobbler/remote.py | 79 +++--------------------------------------------------
cobbler/services.py | 4 +--
3 files changed, 6 insertions(+), 79 deletions(-)
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
index a8a9af6..e39fdc8 100644
--- a/cobbler/pxegen.py
+++ b/cobbler/pxegen.py
@@ -286,8 +286,6 @@ class PXEGen:
kickstart_path = "http://%s/cblr/svc/?op=ks&system=%s" % (blended["http_server"], system.name)
elif kickstart_path.startswith("/") or kickstart_path.find("/cobbler/kickstarts/") != -1:
kickstart_path = "http://%s/cblr/svc/?op=ks&profile=%s" % (blended["http_server"], profile.name)
- if self.settings.register_new_installs:
- kickstart_path = kickstart_path + "®=1"
if distro.breed is None or distro.breed == "redhat":
append_line = "%s ks=%s" % (append_line, kickstart_path)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 17be852..3ad2277 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -18,7 +18,7 @@ import socket
import time
import os
import SimpleXMLRPCServer
-from utils import _
+from rhpl.translate import _, N_, textdomain, utf8
import xmlrpclib
import random
import base64
@@ -158,10 +158,10 @@ class CobblerXMLRPCInterface:
return self._fix_none(data)
- def generate_kickstart(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None,reg=None):
+ def generate_kickstart(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None):
self.log("generate_kickstart")
- if reg is not None and profile and not system:
+ if profile and not system:
regrc = self.register_mac(REMOTE_MAC,profile)
return self.api.generate_kickstart(profile,system)
@@ -986,74 +986,6 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
def remove_profile(self,name,token,recursive=1):
"""
Deletes a profile from a collection. Note that this just requires the name
- of the profile, not a handle.
- """
- self.log("remove_profile",name=name,token=token)
- self.check_access(token, "remove_profile", name)
- rc = self.api._config.profiles().remove(name,recursive=True)
- return rc
-
- def remove_system(self,name,token):
- """
- Deletes a system from a collection. Note that this just requires the name
- of the system, not a handle.
- """
- self.log("remove_system",name=name,token=token)
- self.check_access(token, "remove_system", name)
- rc = self.api._config.systems().remove(name)
- return rc
-
- def remove_repo(self,name,token):
- """
- Deletes a repo from a collection. Note that this just requires the name
- of the repo, not a handle.
- """
- self.log("remove_repo",name=name,token=token)
- self.check_access(token, "remove_repo", name)
- rc = self.api._config.repos().remove(name)
- return rc
-
- def sync(self,token):
- """
- Applies changes in Cobbler to the filesystem.
- Editing a leaf-node object (like a system) does not require
- this, but if updating a upper-level object or a kickstart file,
- running sync at the end of operations is a good idea. A typical
- cobbler sync may take anywhere between a few seconds and several
- minutes, so user interfaces should be programmed accordingly.
- Future versions of cobbler may understand how to do a cascade sync
- on object edits making explicit calls to sync redundant.
- """
- self.log("sync",token=token)
- self.check_access(token, "sync")
- return self.api.sync()
-
- def reposync(self,repos=[],token=None):
- """
- Updates one or more mirrored yum repositories.
- reposync is very slow and probably should not be used
- through the XMLRPC API, setting up reposync on nightly cron is better.
- """
- self.log("reposync",token=token,name=repos)
- self.check_access(token, "reposync", repos)
- return self.api.reposync(repos)
-
- def import_tree(self,mirror_url,mirror_name,network_root=None,token=None):
- """
- I'm exposing this in the XMLRPC API for consistancy but as this
- can be a very long running operation usage is /not/ recommended.
- It would be better to use the CLI. See documentation in api.py.
- This command may be removed from the API in a future release.
- """
- self.log("import_tree",name=mirror_name,token=token)
- self.check_access(token, "import_tree")
- return self.api.import_tree(mirror_url,mirror_name,network_root)
-
- def get_kickstart_templates(self,token):
- """
- Returns all of the kickstarts that are in use by the system.
- """
- self.log("get_kickstart_templates",token=token)
self.check_access(token, "get_kickstart_templates")
files = {}
for x in self.api.profiles():
@@ -1075,10 +1007,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
"""
self.log("read_or_write_kickstart_template",name=kickstart_file,token=token)
- if is_read:
- self.check_access(token,"read_kickstart",kickstart_file)
- else:
- self.check_access(token,"modify_kickstart",kickstart_file)
+ self.check_access(token,"read_or_write_kickstart_templates",kickstart_file,is_read)
if kickstart_file.find("..") != -1 or not kickstart_file.startswith("/"):
raise CX(_("tainted file location"))
diff --git a/cobbler/services.py b/cobbler/services.py
index fde62bb..70153a0 100644
--- a/cobbler/services.py
+++ b/cobbler/services.py
@@ -61,12 +61,12 @@ class CobblerSvc(object):
def index(self,**args):
return "no mode specified"
- def ks(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None,reg=None,**rest):
+ def ks(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None,**rest):
"""
Generate kickstart files...
"""
self.__xmlrpc_setup()
- return self.remote.generate_kickstart(profile,system,REMOTE_ADDR,REMOTE_MAC,reg)
+ return self.remote.generate_kickstart(profile,system,REMOTE_ADDR,REMOTE_MAC)
def trig(self,mode="?",profile=None,system=None,REMOTE_ADDR=None,**rest):
"""
--
cgit
From 169be68abf25fa66d0a922377d2110d30fc7bc67 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 22 Apr 2008 13:14:40 -0400
Subject: Fix docstring
---
cobbler/remote.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 3ad2277..28041b4 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -986,6 +986,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
def remove_profile(self,name,token,recursive=1):
"""
Deletes a profile from a collection. Note that this just requires the name
+ """
self.check_access(token, "get_kickstart_templates")
files = {}
for x in self.api.profiles():
@@ -998,7 +999,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
def read_or_write_kickstart_template(self,kickstart_file,is_read,new_data,token):
- """
+ """
Allows the WebUI to be used as a kickstart file editor. For security
reasons we will only allow kickstart files to be edited if they reside in
/var/lib/cobbler/kickstarts/ or /etc/cobbler. This limits the damage
--
cgit
From c382a735c28c3453d181e304078e2f14a9df98c6 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 22 Apr 2008 17:27:48 -0400
Subject: Some fixes in reg code
---
cobbler/item.py | 5 +++--
cobbler/remote.py | 9 ++++++---
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/cobbler/item.py b/cobbler/item.py
index 2549dce..bdd7c8b 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -198,8 +198,9 @@ class Item(serializable.Serializable):
if key in [ "mac_address", "ip_address", "subnet", "gateway", "virt_bridge", "dhcp_tag", "hostname" ]:
key_found_already = True
for (name, interface) in data["interfaces"].iteritems():
- if interface[key].lower() == value.lower():
- return True
+ if value is not None:
+ if interface[key].lower() == value.lower():
+ return True
if not data.has_key(key):
if not key_found_already:
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 28041b4..d9ec275 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -201,14 +201,17 @@ class CobblerXMLRPCInterface:
READ: https://fedorahosted.org/cobbler/wiki/AutoRegistration
"""
- if not self.api.settings().register_new_installs:
+ if mac is None:
return 1
+ if not self.api.settings().register_new_installs:
+ return 2
+
system = self.api.find_system(mac_address=mac)
if system is not None:
- return 2
+ return 3
- obj = server.new_system(token)
+ obj = self.api.new_system()
obj.set_profile(profile)
obj.set_name(mac.replace(":","_"))
obj.set_mac_address(mac, "intf0")
--
cgit
From 11d6201018d14319f8227f67ccaed575e8ef35d8 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 22 Apr 2008 17:47:39 -0400
Subject: Auto registration now tested and confirmed to work (if you have it
enabled in settings)
---
cobbler/item_system.py | 2 +-
cobbler/remote.py | 18 ++++++++++++++----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 73eda71..1bcc111 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -157,7 +157,7 @@ class System(item.Item):
raise CX(_("name must be a string"))
for x in name:
if not x.isalnum() and not x in [ "_", "-", ".", ":", "+" ] :
- raise CX(_("invalid characters in name"))
+ raise CX(_("invalid characters in name: %s") % x)
if utils.is_mac(name):
if intf["mac_address"] == "":
diff --git a/cobbler/remote.py b/cobbler/remote.py
index d9ec275..c25e700 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -192,7 +192,7 @@ class CobblerXMLRPCInterface:
self.api.add_system(system)
- def register_mac(self,mac,token=None):
+ def register_mac(self,mac,profile,token=None):
"""
If allow_cgi_register_mac is enabled in settings, this allows
kickstarts to add new system records for per-profile-provisioned
@@ -202,20 +202,30 @@ class CobblerXMLRPCInterface:
"""
if mac is None:
+ # don't go further if not being called by anaconda
return 1
if not self.api.settings().register_new_installs:
+ # must be enabled in settings
return 2
system = self.api.find_system(mac_address=mac)
- if system is not None:
+ if system is not None:
+ # do not allow overwrites
return 3
+ # the MAC probably looks like "eth0 AA:BB:CC:DD:EE:FF" now, fix it
+ if mac.find(" ") != -1:
+ mac = mac.split()[-1]
+
+ self.log("register mac for profile %s" % profile,token=token,name=mac)
obj = self.api.new_system()
obj.set_profile(profile)
- obj.set_name(mac.replace(":","_"))
+ name = mac.replace(":","_")
+ obj.set_name(name)
obj.set_mac_address(mac, "intf0")
- systems.add(obj,save=True)
+ obj.set_netboot_enabled(False)
+ self.api.add_system(obj)
return 0
def disable_netboot(self,name,token=None):
--
cgit
From dc8db8a8924503232860939eb2e8d151ebea5f9f Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 12:23:44 -0400
Subject: Add "dumpvars" command.
---
CHANGELOG | 1 +
cobbler/api.py | 3 +++
cobbler/commands.py | 17 +++++++++++++--
cobbler/item.py | 8 +++++++
cobbler/modules/cli_distro.py | 37 +++++++++++++++++----------------
cobbler/modules/cli_profile.py | 47 +++++++++++++++++++++---------------------
cobbler/modules/cli_repo.py | 16 +++++++-------
cobbler/modules/cli_system.py | 14 +++++++------
8 files changed, 86 insertions(+), 57 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index a97dd5e..4396f2d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -30,6 +30,7 @@ Cobbler CHANGELOG
- kickstart templates are now evaluated dynamically
- optional MAC registration is now built-in to requesting kickstarts
- legacy static file generation from /var/www/cobbler removed
+- implement "cobbler ___ dumpvars --name=X" feature to show template vars
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/api.py b/cobbler/api.py
index ebe987e..1814c41 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -251,6 +251,9 @@ class BootAPI:
def find_repo(self, name=None, return_list=False, **kargs):
return self._config.repos().find(name=name, return_list=return_list, **kargs)
+ def dump_vars(self, obj, format=False):
+ return obj.dump_vars(format)
+
def auto_add_repos(self):
"""
Import any repos this server knows about and mirror them.
diff --git a/cobbler/commands.py b/cobbler/commands.py
index 7a6a25b..657934c 100644
--- a/cobbler/commands.py
+++ b/cobbler/commands.py
@@ -195,6 +195,14 @@ class CobblerFunction:
Boilerplate for objects that offer add/edit/delete/remove/copy functionality.
"""
+ if "dumpvars" in self.args:
+ if not self.options.name:
+ raise CX(_("name is required"))
+ obj = collect_fn().find(self.options.name)
+ if obj is None:
+ raise CX(_("object not found"))
+ return obj
+
if "remove" in self.args:
recursive = False
# only applies to distros/profiles and is not supported elsewhere
@@ -219,11 +227,12 @@ class CobblerFunction:
self.reporting_list_names2(collect_fn(),self.options.name)
return None
+ if not self.options.name:
+ raise CX(_("name is required"))
+
if "add" in self.args:
obj = new_fn(is_subobject=subobject)
else:
- if not self.options.name:
- raise CX(_("name is required"))
if "delete" in self.args:
collect_fn().remove(self.options.name, with_delete=True)
return None
@@ -241,6 +250,10 @@ class CobblerFunction:
Boilerplate for objects that offer add/edit/delete/remove/copy functionality.
"""
+ if "dumpvars" in self.args:
+ print obj.dump_vars(True)
+ return True
+
clobber = False
if "add" in self.args:
clobber = options.clobber
diff --git a/cobbler/item.py b/cobbler/item.py
index bdd7c8b..992a18d 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -17,6 +17,7 @@ import serializable
import utils
from cexceptions import *
from utils import _
+import pprint
class Item(serializable.Serializable):
@@ -212,3 +213,10 @@ class Item(serializable.Serializable):
else:
return False
+ def dump_vars(self,data,format=True):
+ raw = utils.blender(self.config.api, False, self)
+ if format:
+ return pprint.pformat(raw)
+ else:
+ return raw
+
diff --git a/cobbler/modules/cli_distro.py b/cobbler/modules/cli_distro.py
index 4d86448..b7a8fa7 100644
--- a/cobbler/modules/cli_distro.py
+++ b/cobbler/modules/cli_distro.py
@@ -33,16 +33,16 @@ class DistroFunction(commands.CobblerFunction):
return "distro"
def subcommands(self):
- return [ "add", "edit", "copy", "rename", "remove", "list", "report" ]
+ return [ "add", "edit", "copy", "rename", "remove", "list", "report", "dumpvars" ]
def add_options(self, p, args):
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--arch", dest="arch", help="ex: x86, x86_64, ia64")
p.add_option("--breed", dest="breed", help="ex: redhat, debian, suse")
if self.matches_args(args,["add"]):
p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--initrd", dest="initrd", help="absolute path to initrd.img (REQUIRED)")
p.add_option("--kernel", dest="kernel", help="absolute path to vmlinuz (REQUIRED)")
p.add_option("--kopts", dest="kopts", help="ex: 'noipv6'")
@@ -54,11 +54,11 @@ class DistroFunction(commands.CobblerFunction):
if self.matches_args(args,["copy","rename"]):
p.add_option("--newname", dest="newname", help="for copy/rename commands")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
- if not self.matches_args(args,["report","list"]):
+ if not self.matches_args(args,["dumpvars","report","list"]):
p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
if self.matches_args(args,["remove"]):
@@ -70,18 +70,19 @@ class DistroFunction(commands.CobblerFunction):
if obj is None:
return True
- if self.options.kernel:
- obj.set_kernel(self.options.kernel)
- if self.options.initrd:
- obj.set_initrd(self.options.initrd)
- if self.options.kopts:
- obj.set_kernel_options(self.options.kopts)
- if self.options.ksmeta:
- obj.set_ksmeta(self.options.ksmeta)
- if self.options.breed:
- obj.set_breed(self.options.breed)
- if self.options.owners:
- obj.set_owners(self.options.owners)
+ if not "dumpvars" in self.args:
+ if self.options.kernel:
+ obj.set_kernel(self.options.kernel)
+ if self.options.initrd:
+ obj.set_initrd(self.options.initrd)
+ if self.options.kopts:
+ obj.set_kernel_options(self.options.kopts)
+ if self.options.ksmeta:
+ obj.set_ksmeta(self.options.ksmeta)
+ if self.options.breed:
+ obj.set_breed(self.options.breed)
+ if self.options.owners:
+ obj.set_owners(self.options.owners)
return self.object_manipulator_finish(obj, self.api.distros, self.options)
diff --git a/cobbler/modules/cli_profile.py b/cobbler/modules/cli_profile.py
index b543b80..45b7b2e 100644
--- a/cobbler/modules/cli_profile.py
+++ b/cobbler/modules/cli_profile.py
@@ -33,7 +33,7 @@ class ProfileFunction(commands.CobblerFunction):
return "profile"
def subcommands(self):
- return [ "add", "edit", "copy", "rename", "remove", "list", "report" ]
+ return [ "add", "edit", "copy", "rename", "remove", "list", "report", "dumpvars" ]
def add_options(self, p, args):
@@ -41,7 +41,7 @@ class ProfileFunction(commands.CobblerFunction):
p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--distro", dest="distro", help="ex: 'RHEL-5-i386' (REQUIRED)")
p.add_option("--dhcp-tag", dest="dhcp_tag", help="for use in advanced DHCP configuration")
@@ -55,16 +55,16 @@ class ProfileFunction(commands.CobblerFunction):
if "copy" in args or "rename" in args:
p.add_option("--newname", dest="newname")
- if not self.matches_args(args,["remove","report", "list"]):
+ if not self.matches_args(args,["dumpvars","remove","report", "list"]):
p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
- if not self.matches_args(args,["report", "list"]):
+ if not self.matches_args(args,["dumpvars","report", "list"]):
p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
if self.matches_args(args,["remove"]):
p.add_option("--recursive", action="store_true", dest="recursive", help="also delete child objects")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--repos", dest="repos", help="names of cobbler repos")
p.add_option("--server-override", dest="server_override", help="overrides value in settings file")
p.add_option("--virt-bridge", dest="virt_bridge", help="ex: 'virbr0'")
@@ -76,8 +76,7 @@ class ProfileFunction(commands.CobblerFunction):
def run(self):
-
- if self.matches_args(self.args,["report","list","remove"]) or not self.options.inherit:
+ if self.matches_args(self.args,["report","list","remove","dumpvars"]) or not self.options.inherit:
obj = self.object_manipulator_start(self.api.new_profile,self.api.profiles,subobject=False)
else:
obj = self.object_manipulator_start(self.api.new_profile,self.api.profiles,subobject=True)
@@ -85,23 +84,23 @@ class ProfileFunction(commands.CobblerFunction):
if obj is None:
return True
- if self.options.inherit: obj.set_parent(self.options.inherit)
- if self.options.distro: obj.set_distro(self.options.distro)
- if self.options.kickstart: obj.set_kickstart(self.options.kickstart)
- if self.options.kopts: obj.set_kernel_options(self.options.kopts)
- if self.options.ksmeta: obj.set_ksmeta(self.options.ksmeta)
- if self.options.virt_file_size: obj.set_virt_file_size(self.options.virt_file_size)
- if self.options.virt_ram: obj.set_virt_ram(self.options.virt_ram)
- if self.options.virt_bridge: obj.set_virt_bridge(self.options.virt_bridge)
- if self.options.virt_type: obj.set_virt_type(self.options.virt_type)
- if self.options.virt_cpus: obj.set_virt_cpus(self.options.virt_cpus)
- if self.options.repos: obj.set_repos(self.options.repos)
- if self.options.virt_path: obj.set_virt_path(self.options.virt_path)
- if self.options.dhcp_tag: obj.set_dhcp_tag(self.options.dhcp_tag)
- if self.options.server_override: obj.set_server(self.options.server)
-
- if self.options.owners:
- obj.set_owners(self.options.owners)
+ if not self.matches_args(self.args,["dumpvars"]):
+ if self.options.inherit: obj.set_parent(self.options.inherit)
+ if self.options.distro: obj.set_distro(self.options.distro)
+ if self.options.kickstart: obj.set_kickstart(self.options.kickstart)
+ if self.options.kopts: obj.set_kernel_options(self.options.kopts)
+ if self.options.ksmeta: obj.set_ksmeta(self.options.ksmeta)
+ if self.options.virt_file_size: obj.set_virt_file_size(self.options.virt_file_size)
+ if self.options.virt_ram: obj.set_virt_ram(self.options.virt_ram)
+ if self.options.virt_bridge: obj.set_virt_bridge(self.options.virt_bridge)
+ if self.options.virt_type: obj.set_virt_type(self.options.virt_type)
+ if self.options.virt_cpus: obj.set_virt_cpus(self.options.virt_cpus)
+ if self.options.repos: obj.set_repos(self.options.repos)
+ if self.options.virt_path: obj.set_virt_path(self.options.virt_path)
+ if self.options.dhcp_tag: obj.set_dhcp_tag(self.options.dhcp_tag)
+ if self.options.server_override: obj.set_server(self.options.server)
+
+ if self.options.owners: obj.set_owners(self.options.owners)
return self.object_manipulator_finish(obj, self.api.profiles, self.options)
diff --git a/cobbler/modules/cli_repo.py b/cobbler/modules/cli_repo.py
index a567d2d..f31ab26 100644
--- a/cobbler/modules/cli_repo.py
+++ b/cobbler/modules/cli_repo.py
@@ -33,23 +33,23 @@ class RepoFunction(commands.CobblerFunction):
return "repo"
def subcommands(self):
- return [ "add", "edit", "copy", "rename", "remove", "list", "report" ]
+ return [ "add", "edit", "copy", "rename", "remove", "list", "report", "dumpvars" ]
def add_options(self, p, args):
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--arch", dest="arch", help="overrides repo arch if required")
if self.matches_args(args,["add"]):
p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--createrepo-flags", dest="createrepo_flags", help="additional flags for createrepo")
p.add_option("--keep-updated", dest="keep_updated", help="update on each reposync, yes/no")
p.add_option("--name", dest="name", help="ex: 'Fedora-8-updates-i386' (REQUIRED)")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--mirror", dest="mirror", help="source to mirror (REQUIRED)")
p.add_option("--priority", dest="priority", help="set priority")
p.add_option("--rpm-list", dest="rpm_list", help="just mirror these rpms")
@@ -59,11 +59,11 @@ class RepoFunction(commands.CobblerFunction):
p.add_option("--newname", dest="newname", help="used for copy/edit")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
- if not self.matches_args(args,["report","list"]):
+ if not self.matches_args(args,["dumpvars","report","list"]):
p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
@@ -72,6 +72,8 @@ class RepoFunction(commands.CobblerFunction):
obj = self.object_manipulator_start(self.api.new_repo,self.api.repos)
if obj is None:
return True
+ if self.matches_args(self.args,["dumpvars"]):
+ return self.object_manipulator_finish(obj, self.api.profiles, self.options)
if self.options.arch: obj.set_arch(self.options.arch)
if self.options.createrepo_flags: obj.set_createrepo_flags(self.options.createrepo_flags)
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 976c380..0c9a5b8 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -33,14 +33,14 @@ class SystemFunction(commands.CobblerFunction):
return "system"
def subcommands(self):
- return [ "add", "edit", "copy", "rename", "remove", "report", "list" ]
+ return [ "add", "edit", "copy", "rename", "remove", "report", "list", "dumpvars" ]
def add_options(self, p, args):
if self.matches_args(args,["add"]):
p.add_option("--clobber", dest="clobber", help="allow add to overwrite existing objects", action="store_true")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--dhcp-tag", dest="dhcp_tag", help="for use in advanced DHCP configurations")
p.add_option("--gateway", dest="gateway", help="for static IP / templating usage")
p.add_option("--hostname", dest="hostname", help="ex: server.example.org")
@@ -53,19 +53,19 @@ class SystemFunction(commands.CobblerFunction):
p.add_option("--name", dest="name", help="a name for the system (REQUIRED)")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--netboot-enabled", dest="netboot_enabled", help="PXE on (1) or off (0)")
if self.matches_args(args,["copy","rename"]):
p.add_option("--newname", dest="newname", help="for use with copy/edit")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
- if not self.matches_args(args,["report","list"]):
+ if not self.matches_args(args,["dumpvars","report","list"]):
p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
- if not self.matches_args(args,["remove","report","list"]):
+ if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--owners", dest="owners", help="specify owners for authz_ownership module")
p.add_option("--profile", dest="profile", help="name of cobbler profile (REQUIRED)")
p.add_option("--server-override", dest="server_override", help="overrides server value in settings file")
@@ -80,6 +80,8 @@ class SystemFunction(commands.CobblerFunction):
obj = self.object_manipulator_start(self.api.new_system,self.api.systems)
if obj is None:
return True
+ if self.matches_args(self.args,["dumpvars"]):
+ return self.object_manipulator_finish(obj, self.api.profiles, self.options)
if self.options.profile: obj.set_profile(self.options.profile)
if self.options.kopts: obj.set_kernel_options(self.options.kopts)
--
cgit
From 7ca984b22725d19890c60423e5156aaa179809ad Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 12:36:10 -0400
Subject: Fix exception processing bug for older broken Python
---
cobbler/cobbler.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index c164244..5cd0c2e 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -56,7 +56,7 @@ def main():
except SystemExit:
pass # probably exited from optparse, nothing extra to print
except Exception, exc2:
- if str(type(exc2)).find("CX") == -1:
+ if str(type(exc2)).find("CX") != -1:
traceback.print_exc()
else:
print str(exc2)[1:-1] # remove framing air quotes
--
cgit
From a3583f38b6bf136a683b14394ee24988a8f206ca Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 13:16:55 -0400
Subject: validateks now works against all URLs, not just local files
---
CHANGELOG | 1 +
cobbler/action_validate.py | 46 +++++++++++++++++++++++++++++-----------------
cobbler/cobbler.py | 2 +-
3 files changed, 31 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 4396f2d..2e92fea 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -31,6 +31,7 @@ Cobbler CHANGELOG
- optional MAC registration is now built-in to requesting kickstarts
- legacy static file generation from /var/www/cobbler removed
- implement "cobbler ___ dumpvars --name=X" feature to show template vars
+- validateks now works against all URLs as opposed to rendered local files
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_validate.py b/cobbler/action_validate.py
index 8ede60c..44f3a9a 100644
--- a/cobbler/action_validate.py
+++ b/cobbler/action_validate.py
@@ -16,6 +16,7 @@ import os
import re
import sub_process
from utils import _
+import utils
class Validate:
@@ -39,16 +40,10 @@ class Validate:
failed = False
for x in self.config.profiles():
- distro = x.get_conceptual_parent()
- if distro.breed != "redhat":
- continue
- if not self.checkfile(x.name, "%s/kickstarts/%s/ks.cfg" % (self.settings.webdir, x.name)):
+ if not self.checkfile(x, True):
failed = True
for x in self.config.systems():
- distro = x.get_conceptual_parent().get_conceptual_parent()
- if distro.breed != "redhat":
- continue
- if not self.checkfile(x.name, "%s/kickstarts_sys/%s/ks.cfg" % (self.settings.webdir, x.name)):
+ if not self.checkfile(x, False):
failed = True
if failed:
@@ -58,15 +53,32 @@ class Validate:
return failed
- def checkfile(self,name,file):
- # print _("scanning rendered kickstart template: %s" % file)
- if not os.path.exists(file):
- print _("kickstart file does not exist for: %s") % name
- return False
- rc = os.system("/usr/bin/ksvalidator %s" % file)
- if not rc == 0:
- print _("ksvalidator detected a possible problem for: %s") % name
- print _(" rendered kickstart template at: %s" % file)
+ def checkfile(self,obj,is_profile):
+ blended = utils.blender(self.config.api, False, obj)
+ ks = blended["kickstart"]
+ breed = blended["breed"]
+ if breed != "redhat":
+ print "%s has a breed of %s, skipping" % (obj.name, breed)
+ return True
+ if ks is None or ks == "":
+ print "%s has no kickstart, skipping" % obj.name
+ return True
+
+ server = blended["server"]
+ if not ks.startswith("/"):
+ url = self.kickstart
+ elif is_profile:
+ url = "http://%s/cblr/svc/?op=ks;profile=%s" % (server,obj.name)
+ else:
+ url = "http://%s/cblr/svc/?op=ks;system=%s" % (server,obj.name)
+
+ print "----------------------------"
+ print "checking url: %s" % url
+
+
+ rc = os.system("/usr/bin/ksvalidator \"%s\"" % url)
+ if rc != 0:
return False
+
return True
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 5cd0c2e..c164244 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -56,7 +56,7 @@ def main():
except SystemExit:
pass # probably exited from optparse, nothing extra to print
except Exception, exc2:
- if str(type(exc2)).find("CX") != -1:
+ if str(type(exc2)).find("CX") == -1:
traceback.print_exc()
else:
print str(exc2)[1:-1] # remove framing air quotes
--
cgit
From 5a53dfb37bbd95aa5c3ae5d67c493c2b1879c8f7 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 13:43:16 -0400
Subject: Fix instance checking
---
cobbler/cobbler.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index c164244..5db40ce 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -56,7 +56,7 @@ def main():
except SystemExit:
pass # probably exited from optparse, nothing extra to print
except Exception, exc2:
- if str(type(exc2)).find("CX") == -1:
+ if isinstance(exc2, CX) or isinstance(exc2, CobblerException)
traceback.print_exc()
else:
print str(exc2)[1:-1] # remove framing air quotes
--
cgit
From b93705dc092d8e675bcb0690b29c20dbd2d58b68 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 13:47:58 -0400
Subject: Typo
---
cobbler/cobbler.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 5db40ce..e8a2ef5 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -56,7 +56,7 @@ def main():
except SystemExit:
pass # probably exited from optparse, nothing extra to print
except Exception, exc2:
- if isinstance(exc2, CX) or isinstance(exc2, CobblerException)
+ if isinstance(exc2, CX) or isinstance(exc2, CobblerException):
traceback.print_exc()
else:
print str(exc2)[1:-1] # remove framing air quotes
--
cgit
From aba4879418ece5fb1c1126d45dfefcca73b4abc7 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 14:14:54 -0400
Subject: Services operations are now happy with unicode data.
---
cobbler/services.py | 5 +++--
scripts/services.py | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/cobbler/services.py b/cobbler/services.py
index 70153a0..adaf6fc 100644
--- a/cobbler/services.py
+++ b/cobbler/services.py
@@ -66,8 +66,9 @@ class CobblerSvc(object):
Generate kickstart files...
"""
self.__xmlrpc_setup()
- return self.remote.generate_kickstart(profile,system,REMOTE_ADDR,REMOTE_MAC)
-
+ data = self.remote.generate_kickstart(profile,system,REMOTE_ADDR,REMOTE_MAC)
+ return u"%s" % data
+
def trig(self,mode="?",profile=None,system=None,REMOTE_ADDR=None,**rest):
"""
Hook to call install triggers.
diff --git a/scripts/services.py b/scripts/services.py
index 07243ae..2486a4a 100755
--- a/scripts/services.py
+++ b/scripts/services.py
@@ -60,8 +60,9 @@ def handler(req):
content = func( **form )
# apache.log_error("%s:%s ... %s" % (my_user, my_uri, str(form)))
- req.content_type = "text/plain"
- req.write(content)
+ req.content_type = "text/plain;charset=utf-8"
+ content = unicode(content)
+ req.write(content.encode('utf-8'))
return apache.OK
--
cgit
From 16359a0f6cef98adf4da1dcd4a402fbdb6751e5d Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 14:19:00 -0400
Subject: Apply unicode changes to webui also
---
scripts/index.py | 4 ++--
scripts/services.py | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/index.py b/scripts/index.py
index 281e36e..8d10129 100755
--- a/scripts/index.py
+++ b/scripts/index.py
@@ -122,8 +122,8 @@ def handler(req):
content = func( "Invalid Mode: \"%s\"" % mode )
# apache.log_error("%s:%s ... %s" % (my_user, my_uri, str(form)))
- req.content_type = "text/html"
- req.write(content)
+ req.content_type = "text/html;charset=utf-8"
+ req.write(unicode(content).encode('utf-8'))
return apache.OK
diff --git a/scripts/services.py b/scripts/services.py
index 2486a4a..b41d6a0 100755
--- a/scripts/services.py
+++ b/scripts/services.py
@@ -61,8 +61,8 @@ def handler(req):
# apache.log_error("%s:%s ... %s" % (my_user, my_uri, str(form)))
req.content_type = "text/plain;charset=utf-8"
- content = unicode(content)
- req.write(content.encode('utf-8'))
+ content = unicode(content).encode('utf-8')
+ req.write(content)
return apache.OK
--
cgit
From 5cde562c195f159c460cd2ef181a402eadad3bf2 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 14:19:56 -0400
Subject: changelog
---
CHANGELOG | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG b/CHANGELOG
index 2e92fea..ce085f1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -42,6 +42,7 @@ Cobbler CHANGELOG
- fix for dnsmasq template file host config path
- fix dnsmasq template to point at the correct hosts file
- force all names to be alphanumeric
+- all mod python pieces now happy with Unicode output
* Fri Feb 22 2008 - 0.8.2
- fix to webui to allow repos to be edited there on profile page
--
cgit
From 899a61bdf1a1369c656a9e34513b17f558e864bc Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 14:49:47 -0400
Subject: Support "fake" query string URLs to support xend's esoteric parser
that doesn't like query strings on the kernel options line.
---
scripts/services.py | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/scripts/services.py b/scripts/services.py
index b41d6a0..8fcb8f8 100755
--- a/scripts/services.py
+++ b/scripts/services.py
@@ -33,6 +33,8 @@ def handler(req):
"""
my_uri = req.uri
+
+
# apache.log_error("cannot load /var/lib/cobbler/web.ss")
req.add_common_vars()
@@ -42,6 +44,26 @@ def handler(req):
form = {}
for x in fs.keys():
form[x] = str(fs.get(x,'default'))
+
+ if my_uri.find("?") == -1:
+ # support fake query strings
+ # something log /cobbler/web/op/ks/server/foo
+ # which is needed because of xend parser errors
+ # not tolerating ";" and also libvirt on 5.1 not
+ # tolerating "&" (nor "&").
+
+ tokens = my_uri.split("/")
+ tokens = tokens[3:]
+ label = True
+ field = ""
+ for t in tokens:
+ if label:
+ field = t
+ apache.log_error("field %s" % field)
+ else:
+ form[field] = t
+ apache.log_error("adding %s to %s" % (field,t))
+ label = not label
form["REMOTE_ADDR"] = req.subprocess_env.get("REMOTE_ADDR",None)
form["REMOTE_MAC"] = req.subprocess_env.get("HTTP_X_RHN_PROVISIONING_MAC_0",None)
--
cgit
From 7e7533b8011e43f9d380275d91d2b69b2ed36162 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 15:12:33 -0400
Subject: Modify URLs
---
cobbler/kickgen.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index 1b1cfdd..a5e540e 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -94,10 +94,10 @@ class KickGen:
* end: save the original kickstart file for debug
"""
- nopxe = "\nwget \"http://%s/cblr/svc/?op=nopxe&system=%s\" -O /dev/null"
- saveks = "\nwget \"http://%s/cblr/svc/?op=ks&%s=%s\" -O /root/cobbler.ks"
- runpost = "\nwget \"http://%s/cblr/svc/?op=trig&mode=post&%s=%s\" -O /dev/null"
- runpre = "\nwget \"http://%s/cblr/svc/?op=trig&mode=pre&%s=%s\" -O /dev/null"
+ nopxe = "\nwget \"http://%s/cblr/svc/op/nopxe/system/%s\" -O /dev/null"
+ saveks = "\nwget \"http://%s/cblr/svc/op/ks/%s/%s\" -O /root/cobbler.ks"
+ runpost = "\nwget \"http://%s/cblr/svc/op/trig/mode/post/%s/%s\" -O /dev/null"
+ runpre = "\nwget \"http://%s/cblr/svc/op/trig/mode/pre/%s/%s\" -O /dev/null"
what = "profile"
blend_this = profile
--
cgit
From 7fe5d10a7387fb8f7d972567db54b3e0927081c5 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 23 Apr 2008 15:13:49 -0400
Subject: apply URL changes to PXE also
---
cobbler/pxegen.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
index e39fdc8..8cb8c93 100644
--- a/cobbler/pxegen.py
+++ b/cobbler/pxegen.py
@@ -283,9 +283,9 @@ class PXEGen:
if kickstart_path is not None and kickstart_path != "":
if system is not None and kickstart_path.startswith("/"):
- kickstart_path = "http://%s/cblr/svc/?op=ks&system=%s" % (blended["http_server"], system.name)
+ kickstart_path = "http://%s/cblr/svc/op/ks/system/%s" % (blended["http_server"], system.name)
elif kickstart_path.startswith("/") or kickstart_path.find("/cobbler/kickstarts/") != -1:
- kickstart_path = "http://%s/cblr/svc/?op=ks&profile=%s" % (blended["http_server"], profile.name)
+ kickstart_path = "http://%s/cblr/svc/op/ks/profile/%s" % (blended["http_server"], profile.name)
if distro.breed is None or distro.breed == "redhat":
append_line = "%s ks=%s" % (append_line, kickstart_path)
--
cgit
From 9f314143b39edfa0943c68158d1ae954af4f4f86 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 24 Apr 2008 13:46:04 -0400
Subject: It's now possible to create new kickstart templates in
/var/lib/cobbler/kickstarts/ from the WebUI, as well as delete ones that are
no longer being used while on the edit page for that template.
---
CHANGELOG | 1 +
cobbler/remote.py | 43 ++++++++++++++++++++++++++++++++---
cobbler/webui/CobblerWeb.py | 29 +++++++++++++++++++++---
cobbler/webui/master.py | 16 +++++++++-----
setup.py | 1 +
webui_templates/ksfile_edit.tmpl | 39 ++++++++++++++++++++++++--------
webui_templates/ksfile_list.tmpl | 3 ++-
webui_templates/ksfile_new.tmpl | 48 ++++++++++++++++++++++++++++++++++++++++
webui_templates/master.tmpl | 1 +
9 files changed, 159 insertions(+), 22 deletions(-)
create mode 100644 webui_templates/ksfile_new.tmpl
diff --git a/CHANGELOG b/CHANGELOG
index ce085f1..ed91270 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -32,6 +32,7 @@ Cobbler CHANGELOG
- legacy static file generation from /var/www/cobbler removed
- implement "cobbler ___ dumpvars --name=X" feature to show template vars
- validateks now works against all URLs as opposed to rendered local files
+- now possible to create new kickstarts in webui, and delete unused ones
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/remote.py b/cobbler/remote.py
index c25e700..a7e056b 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -24,6 +24,7 @@ import random
import base64
import string
import traceback
+import glob
import api as cobbler_api
import utils
@@ -158,6 +159,35 @@ class CobblerXMLRPCInterface:
return self._fix_none(data)
+ def get_kickstart_templates(self,token):
+ """
+ Returns all of the kickstarts that are in use by the system.
+ """
+ self.log("get_kickstart_templates",token=token)
+ self.check_access(token, "get_kickstart_templates")
+ files = {}
+ for x in self.api.profiles():
+ if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
+ files[x.kickstart] = 1
+ for x in self.api.systems():
+ if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
+ files[x.kickstart] = 1
+ for x in glob.glob("/var/lib/cobbler/kickstarts/*"):
+ files[x] = 1
+
+ return files.keys()
+
+ def is_kickstart_in_use(self,ks,token):
+ self.log("is_kickstart_in_use",token=token)
+ self.check_access(token, "is_kickstart_in_use")
+ for x in self.api.profiles():
+ if x.kickstart is not None and x.kickstart == ks:
+ return True
+ for x in self.api.systems():
+ if x.kickstart is not None and x.kickstart == ks:
+ return True
+ return False
+
def generate_kickstart(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None):
self.log("generate_kickstart")
@@ -1042,9 +1072,16 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
fileh.close()
return data
else:
- fileh = open(kickstart_file,"w+")
- fileh.write(new_data)
- fileh.close()
+ if new_data == -1:
+ # delete requested
+ if not self.is_kickstart_in_use(kickstart_file,token):
+ os.remove(kickstart_file)
+ else:
+ raise CX(_("attempt to delete in-use file"))
+ else:
+ fileh = open(kickstart_file,"w+")
+ fileh.write(new_data)
+ fileh.close()
return True
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index 628d776..2eeb1a3 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -712,6 +712,20 @@ class CobblerWeb(object):
'ksfiles': self.remote.get_kickstart_templates(self.token)
} )
+ def ksfile_new(self, name=None,**spam):
+
+
+ if not self.__xmlrpc_setup():
+ return self.xmlrpc_auth_failure()
+
+ can_edit = self.remote.check_access_no_fail(self.token,"add_kickstart",name)
+ return self.__render( 'ksfile_new.tmpl', {
+ 'editable' : can_edit,
+ 'ksdata': ''
+ } )
+
+
+
def ksfile_edit(self, name=None,**spam):
@@ -721,18 +735,26 @@ class CobblerWeb(object):
can_edit = self.remote.check_access_no_fail(self.token,"modify_kickstart",name)
return self.__render( 'ksfile_edit.tmpl', {
'name': name,
+ 'deleteable' : not self.remote.is_kickstart_in_use(name,self.token),
'editable' : can_edit,
'ksdata': self.remote.read_or_write_kickstart_template(name,True,"",self.token)
} )
- def ksfile_save(self, name=None, ksdata=None, **args):
+ def ksfile_save(self, name=None, ksdata=None, delete1=None, delete2=None, isnew=None, **args):
if not self.__xmlrpc_setup():
return self.xmlrpc_auth_failure()
+
+
try:
- self.remote.read_or_write_kickstart_template(name,False,ksdata,self.token)
+ if delete1 and delete2:
+ self.remote.read_or_write_kickstart_template(name,False,-1,self.token)
+ if isnew is not None:
+ name = "/var/lib/cobbler/kickstarts/" + name
+ if not delete1 and not delete2:
+ self.remote.read_or_write_kickstart_template(name,False,ksdata,self.token)
except Exception, e:
return self.error_page("An error occurred while trying to save kickstart file %s:
%s" % (name,str(e)))
- return self.ksfile_edit(name=name)
+ return self.ksfile_list()
# ------------------------------------------------------------------------ #
# Miscellaneous
@@ -813,6 +835,7 @@ class CobblerWeb(object):
settings_view.exposed = True
ksfile_edit.exposed = True
+ ksfile_new.exposed = True
ksfile_save.exposed = True
ksfile_list.exposed = True
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 14f06b5..22391eb 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -33,10 +33,10 @@ VFN=valueForName
currentTime=time.time
__CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1208557454.7957201
-__CHEETAH_genTimestamp__ = 'Fri Apr 18 18:24:14 2008'
+__CHEETAH_genTime__ = 1209057202.737108
+__CHEETAH_genTimestamp__ = 'Thu Apr 24 13:13:22 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
-__CHEETAH_srcLastModified__ = 'Fri Feb 15 14:47:43 2008'
+__CHEETAH_srcLastModified__ = 'Thu Apr 24 12:59:37 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
@@ -69,7 +69,7 @@ class master(Template):
- ## CHEETAH: generated from #block body at line 53, col 1.
+ ## CHEETAH: generated from #block body at line 54, col 1.
trans = KWS.get("trans")
if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
trans = self.transaction # is None unless self.awake() was called
@@ -196,11 +196,15 @@ class master(Template):
diff --git a/website/new/img/et_logo.png b/website/new/img/et_logo.png
new file mode 100644
index 0000000..e094b59
Binary files /dev/null and b/website/new/img/et_logo.png differ
diff --git a/website/new/img/footer_corner.png b/website/new/img/footer_corner.png
new file mode 100644
index 0000000..090bfce
Binary files /dev/null and b/website/new/img/footer_corner.png differ
diff --git a/website/new/img/footer_pattern.png b/website/new/img/footer_pattern.png
new file mode 100644
index 0000000..647c52a
Binary files /dev/null and b/website/new/img/footer_pattern.png differ
diff --git a/website/push.sh b/website/push.sh
index 594c50b..9623250 100644
--- a/website/push.sh
+++ b/website/push.sh
@@ -1,2 +1,3 @@
#!/bin/sh
-scp -r new/* et.redhat.com:/var/www/sites/cobbler.et.redhat.com
+#scp -r new/* et.redhat.com:/var/www/sites/cobbler.et.redhat.com
+cp -r new/* /var/www/html/stage
--
cgit
From 97a4085adb0d83efd1008614b2b7da5546016ea6 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 1 May 2008 17:50:15 -0400
Subject: Working on adding a "cobbler buildiso" command to generate non-live
CD's. Menu does not work yet, but getting there.
Also made registration check for duplicate macs, but needs testing.
---
cobbler/action_buildiso.py | 168 ++++++++++++++++++++++++++++++++++++++++++++
cobbler/api.py | 7 ++
cobbler/cobbler.py | 19 +++--
cobbler/modules/cli_misc.py | 28 ++++++--
cobbler/remote.py | 4 ++
5 files changed, 210 insertions(+), 16 deletions(-)
create mode 100644 cobbler/action_buildiso.py
diff --git a/cobbler/action_buildiso.py b/cobbler/action_buildiso.py
new file mode 100644
index 0000000..0a2edac
--- /dev/null
+++ b/cobbler/action_buildiso.py
@@ -0,0 +1,168 @@
+"""
+Builds non-live bootable CD's that have PXE-equivalent behavior
+for all cobbler profiles currently in memory.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import sub_process
+import sys
+import traceback
+import shutil
+import sub_process
+
+import utils
+from cexceptions import *
+from utils import _
+
+# FIXME: lots of overlap with pxegen.py, should consolidate
+# FIXME: disable timeouts and remove local boot for this?
+HEADER = """
+
+DEFAULT menu
+PROMPT 0
+MENU TITLE Cobbler | http://cobbler.et.redhat.com
+TIMEOUT 200
+TOTALTIMEOUT 6000
+ONTIMEOUT local
+
+LABEL local
+ MENU LABEL (local)
+ MENU DEFAULT
+ LOCALBOOT 0
+
+"""
+
+class BuildIso:
+ """
+ Handles conversion of internal state to the tftpboot tree layout
+ """
+
+ def __init__(self,config,verbose=False):
+ """
+ Constructor
+ """
+ self.verbose = verbose
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+
+ def run(self,iso=None,tempdir=None,profiles=None):
+
+ # verify we can find isolinux.bin
+
+ if iso is None:
+ iso = "kickstart.iso"
+
+ isolinuxbin = "/usr/lib/syslinux/isolinux.bin"
+ if not os.path.exists(isolinuxbin):
+ raise CX(_("Required file not found: %s") % isolinuxbin)
+
+ # if iso is none, create it in . as "cobbler.iso"
+ if tempdir is None:
+ tempdir = os.path.join(os.getcwd(), "buildiso")
+ print _("- using/creating tempdir: %s") % tempdir
+ if not os.path.exists(tempdir):
+ os.makedirs(tempdir)
+
+ # if base of tempdir does not exist, fail
+ # create all profiles unless filtered by "profiles"
+ imagesdir = os.path.join(tempdir, "images")
+ isolinuxdir = os.path.join(tempdir, "isolinux")
+
+ print _("- building tree for isolinux")
+ if not os.path.exists(imagesdir):
+ os.makedirs(imagesdir)
+ if not os.path.exists(isolinuxdir):
+ os.makedirs(isolinuxdir)
+
+ print _("- copying miscellaneous files")
+ utils.copyfile(isolinuxbin, os.path.join(isolinuxdir, "isolinux.bin"))
+ menu = "/var/lib/cobbler/menu.c32"
+ files = [ isolinuxbin, menu ]
+ for f in files:
+ if not os.path.exists(f):
+ raise CX(_("Required file not found: %s") % f)
+ utils.copyfile(f, os.path.join(isolinuxdir, os.path.basename(f)))
+
+ print _("- copying kernels and initrds")
+ # copy all images in included profiles to images dir
+ for x in self.api.profiles():
+ use_this = True
+ if profiles is not None:
+ which_profiles = profiles.split(",")
+ if not use_this in which_profiles:
+ use_this = False
+ dist = x.get_conceptual_parent()
+ distdir = os.path.join(isolinuxdir, x.name)
+ if not os.path.exists(distdir):
+ os.makedirs(distdir)
+ # tempdir/isolinux/$distro/vmlinuz, initrd.img
+ # FIXME: this will likely crash on non-Linux breeds
+ shutil.copyfile(dist.kernel, os.path.join(distdir, "vmlinuz"))
+ shutil.copyfile(dist.initrd, os.path.join(distdir, "initrd.img"))
+
+ # generate isolinux.cfg
+ print _("- generating a isolinux.cfg")
+ isolinuxcfg = os.path.join(isolinuxdir, "isolinux.cfg")
+ cfg = open(isolinuxcfg, "w+")
+ cfg.write(HEADER) # fixme, use template
+
+ for x in self.api.profiles():
+ # FIXME
+ use_this = True
+ if profiles is not None:
+ which_profiles = profiles.split(",")
+ if not use_this in which_profiles:
+ use_this = False
+ if use_this:
+ dist = x.get_conceptual_parent()
+ data = utils.blender(self.api, True, x)
+
+ cfg.write("\n")
+ cfg.write("LABEL %s\n" % x.name)
+ cfg.write(" MENU LABEL %s\n" % x.name)
+ cfg.write(" kernel /%s/vmlinuz\n" % dist.name)
+
+ if data["kickstart"].startswith("/"):
+ data["kickstart"] = "http://%s/cblr/svc/op/ks/profile/%s" % (
+ data["server"],
+ x.name
+ )
+
+ append_line = " append %s/initrd.img" % dist.name
+ append_line = append_line + " ks=%s " % data["kickstart"]
+ append_line = append_line + " %s\n" % data["kernel_options"]
+ cfg.write(append_line)
+
+ print _("- done writing config")
+ cfg.write("\n")
+ cfg.write("MENU END\n")
+ cfg.close()
+
+ cmd = "mkisofs -o %s -r -b isolinux/isolinux.bin" % iso
+ cmd = cmd + " -no-emul-boot -boot-load-size 4 "
+ cmd = cmd + " -boot-info-table -V Cobbler\ Install -R -J -T %s" % tempdir
+
+ print _("- running: %s") % cmd
+ rc = sub_process.call(cmd, shell=True)
+ if rc:
+ raise CX(_("mkisofs failed"))
+
+ print _("ISO build complete")
+ print _("You may wish to delete: %s") % tempdir
+ print _("The output file is: %s") % iso
+
+
diff --git a/cobbler/api.py b/cobbler/api.py
index 1814c41..7bcd4fa 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -22,6 +22,7 @@ import action_import
import action_reposync
import action_status
import action_validate
+import action_buildiso
from cexceptions import *
import sub_process
import module_loader
@@ -417,3 +418,9 @@ class BootAPI:
self.log("authorize",[user,resource,arg1,arg2,rc],debug=True)
return rc
+ def build_iso(self,iso=None,profiles=None,tempdir=None):
+ builder = action_buildiso.BuildIso(self._config)
+ return builder.run(
+ iso=iso, profiles=profiles, tempdir=tempdir
+ )
+
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index e8a2ef5..627e398 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -21,6 +21,7 @@ import os.path
import traceback
import optparse
import commands
+import cexceptions
from cexceptions import *
from utils import _
@@ -49,20 +50,16 @@ def main():
"""
exitcode = 0
try:
- # FIXME: redo locking code?
return BootCLI().run(sys.argv)
- except CX, exc:
- print str(exc)[1:-1] # remove framing air quotes
- except SystemExit:
- pass # probably exited from optparse, nothing extra to print
- except Exception, exc2:
- if isinstance(exc2, CX) or isinstance(exc2, CobblerException):
- traceback.print_exc()
+ except Exception, exc:
+ if isinstance(exc, cexceptions.CobblerException) or \
+ isinstance(exc, cexceptions.CX) or \
+ str(type(exc)).find("CX") != -1 or \
+ str(type(exc)).find("CobblerException") != -1:
+ print str(exc)[1:-1] # remove framing air quotes
else:
- print str(exc2)[1:-1] # remove framing air quotes
+ traceback.print_exc()
return 1
- return 1
-
if __name__ == "__main__":
sys.exit(main())
diff --git a/cobbler/modules/cli_misc.py b/cobbler/modules/cli_misc.py
index af2f6b2..6ca14a2 100644
--- a/cobbler/modules/cli_misc.py
+++ b/cobbler/modules/cli_misc.py
@@ -184,11 +184,6 @@ class ReportFunction(commands.CobblerFunction):
self.reporting_print_sorted(self.api.repos())
return True
-## FIXME: add legacy command translator to keep things simple
-## cobbler system report foo --> cobbler report --what=systems --name=foo
-## cobbler system report --> cobbler report --what=systems
-## ditto for "cobbler list"
-
########################################################
class StatusFunction(commands.CobblerFunction):
@@ -244,6 +239,28 @@ class ValidateKsFunction(commands.CobblerFunction):
def run(self):
return self.api.validateks()
+########################################################
+
+class BuildIsoFunction(commands.CobblerFunction):
+
+ def add_options(self,p,args):
+ p.add_option("--iso", dest="isoname", help="(OPTIONAL) output ISO to this path")
+ p.add_option("--profiles", dest="profiles", help="(OPTIONAL) use these profiles only")
+ p.add_option("--tempdir", dest="tempdir", help="(OPTIONAL) working directory")
+
+ def help_me(self):
+ return HELP_FORMAT % ("cobbler buildiso","")
+
+ def command_name(self):
+ return "buildiso"
+
+ def run(self):
+ return self.api.build_iso(
+ iso=self.options.isoname,
+ profiles=self.options.profiles,
+ tempdir=self.options.tempdir
+ )
+
########################################################
# MODULE HOOKS
@@ -255,6 +272,7 @@ def register():
def cli_functions(api):
return [
+ BuildIsoFunction(api),
CheckFunction(api), ImportFunction(api), ReserializeFunction(api),
ListFunction(api), ReportFunction(api), StatusFunction(api),
SyncFunction(api), RepoSyncFunction(api), ValidateKsFunction(api)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index a7e056b..18c3947 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -248,6 +248,10 @@ class CobblerXMLRPCInterface:
if mac.find(" ") != -1:
mac = mac.split()[-1]
+ dup = self.api.find_system(mac_address=mac)
+ if dup is not None:
+ return 4
+
self.log("register mac for profile %s" % profile,token=token,name=mac)
obj = self.api.new_system()
obj.set_profile(profile)
--
cgit
From 5cc622d9683da05055e8ee93dc31fb8beabd3213 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 1 May 2008 18:09:07 -0400
Subject: Fix some paths and parameters. More to do.
---
cobbler/action_buildiso.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cobbler/action_buildiso.py b/cobbler/action_buildiso.py
index 0a2edac..d11bee4 100644
--- a/cobbler/action_buildiso.py
+++ b/cobbler/action_buildiso.py
@@ -134,7 +134,7 @@ class BuildIso:
cfg.write("\n")
cfg.write("LABEL %s\n" % x.name)
cfg.write(" MENU LABEL %s\n" % x.name)
- cfg.write(" kernel /%s/vmlinuz\n" % dist.name)
+ cfg.write(" kernel %s/vmlinuz\n" % dist.name)
if data["kickstart"].startswith("/"):
data["kickstart"] = "http://%s/cblr/svc/op/ks/profile/%s" % (
@@ -142,7 +142,7 @@ class BuildIso:
x.name
)
- append_line = " append %s/initrd.img" % dist.name
+ append_line = " append initrd=%s/initrd.img" % dist.name
append_line = append_line + " ks=%s " % data["kickstart"]
append_line = append_line + " %s\n" % data["kernel_options"]
cfg.write(append_line)
--
cgit
From 2f6b73def7068ee401d37b7eeee44a9fc064c9a1 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 10:29:50 -0400
Subject: Build iso completion
---
cobbler/action_buildiso.py | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/cobbler/action_buildiso.py b/cobbler/action_buildiso.py
index d11bee4..639bd6b 100644
--- a/cobbler/action_buildiso.py
+++ b/cobbler/action_buildiso.py
@@ -40,7 +40,7 @@ ONTIMEOUT local
LABEL local
MENU LABEL (local)
MENU DEFAULT
- LOCALBOOT 0
+ LOCALBOOT -1
"""
@@ -58,6 +58,16 @@ class BuildIso:
self.api = config.api
self.distros = config.distros()
self.profiles = config.profiles()
+ self.distmap = {}
+ self.distctr = 0
+
+ def make_shorter(self,distname):
+ if self.distmap.has_key(distname):
+ return self.distmap[distname]
+ else:
+ self.distctr = self.distctr + 1
+ self.distmap[distname] = str(self.distctr)
+ return str(self.distctr)
def run(self,iso=None,tempdir=None,profiles=None):
@@ -106,13 +116,13 @@ class BuildIso:
if not use_this in which_profiles:
use_this = False
dist = x.get_conceptual_parent()
- distdir = os.path.join(isolinuxdir, x.name)
- if not os.path.exists(distdir):
- os.makedirs(distdir)
+ if dist.name.find("-xen") != -1:
+ continue
+ distname = self.make_shorter(dist.name)
# tempdir/isolinux/$distro/vmlinuz, initrd.img
# FIXME: this will likely crash on non-Linux breeds
- shutil.copyfile(dist.kernel, os.path.join(distdir, "vmlinuz"))
- shutil.copyfile(dist.initrd, os.path.join(distdir, "initrd.img"))
+ shutil.copyfile(dist.kernel, os.path.join(isolinuxdir, "%s.krn" % distname))
+ shutil.copyfile(dist.initrd, os.path.join(isolinuxdir, "%s.img" % distname))
# generate isolinux.cfg
print _("- generating a isolinux.cfg")
@@ -129,12 +139,15 @@ class BuildIso:
use_this = False
if use_this:
dist = x.get_conceptual_parent()
+ if dist.name.find("-xen") != -1:
+ continue
data = utils.blender(self.api, True, x)
+ distname = self.make_shorter(dist.name)
cfg.write("\n")
cfg.write("LABEL %s\n" % x.name)
cfg.write(" MENU LABEL %s\n" % x.name)
- cfg.write(" kernel %s/vmlinuz\n" % dist.name)
+ cfg.write(" kernel %s.krn\n" % distname)
if data["kickstart"].startswith("/"):
data["kickstart"] = "http://%s/cblr/svc/op/ks/profile/%s" % (
@@ -142,7 +155,7 @@ class BuildIso:
x.name
)
- append_line = " append initrd=%s/initrd.img" % dist.name
+ append_line = " append initrd=%s.img" % distname
append_line = append_line + " ks=%s " % data["kickstart"]
append_line = append_line + " %s\n" % data["kernel_options"]
cfg.write(append_line)
@@ -152,7 +165,7 @@ class BuildIso:
cfg.write("MENU END\n")
cfg.close()
- cmd = "mkisofs -o %s -r -b isolinux/isolinux.bin" % iso
+ cmd = "mkisofs -o %s -r -b isolinux/isolinux.bin -c isolinux/boot.cat" % iso
cmd = cmd + " -no-emul-boot -boot-load-size 4 "
cmd = cmd + " -boot-info-table -V Cobbler\ Install -R -J -T %s" % tempdir
--
cgit
From 7eb0fa0be305d1d682b29aaff6dde267402a9e6a Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 11:51:33 -0400
Subject: Apply Pablo's patch to add OMAPI support to dhcp config generation.
---
cobbler/dhcpgen.py | 82 +++++++++++++++++++++++++++++++++++++--
cobbler/settings.py | 2 +
config/settings | 2 +
templates/dhcp.template | 1 +
triggers/restart-services.trigger | 10 ++++-
5 files changed, 93 insertions(+), 4 deletions(-)
diff --git a/cobbler/dhcpgen.py b/cobbler/dhcpgen.py
index 2d6facf..cc6d410 100644
--- a/cobbler/dhcpgen.py
+++ b/cobbler/dhcpgen.py
@@ -22,6 +22,9 @@ import sys
import glob
import traceback
import errno
+import popen2
+from shlex import shlex
+
import utils
from cexceptions import *
@@ -53,6 +56,50 @@ class DHCPGen:
self.repos = config.repos()
self.templar = templar.Templar(config)
+ def writeDHCPLease(self,port,host,ip,mac):
+ """writeDHCPLease(port,host,ip,mac)
+ Use DHCP's API to create a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """
+ #Code from http://svn.osgdc.org/browse/kusu/kusu/trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025
+ fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("set ip-address = %s\n" % ip)
+ tochild.flush()
+ tochild.write("set hardware-address = %s\n" % mac)
+ tochild.flush()
+ tochild.write("set hardware-type = 1\n")
+ tochild.flush()
+ tochild.write("create\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+
+ def removeDHCPLease(self,port,host):
+ """removeDHCPLease(port,host)
+ Use DHCP's API to delete a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """
+ fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("open\n") # opens register with host information
+ tochild.flush()
+ tochild.write("remove\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+
+
def write_dhcp_file(self):
"""
DHCP files are written when manage_dhcp is set in
@@ -84,10 +131,28 @@ class DHCPGen:
system_definitions = {}
counter = 0
+
+
+ # Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in
+ # case to avoid conflicts with the hosts we're defining and to clean
+ # possible removed hosts (only if using OMAPI)
+ #
+ # Pablo Iranzo Gómez (Pablo.Iranzo@redhat.com)
+ if self.settings.omapi and self.settings.omapi_port:
+ file = open('/var/lib/dhcpd/dhcpd.leases')
+ item = shlex(file)
+ while 1:
+ elem = item.get_token()
+ if not elem:
+ break
+ if elem == 'host':
+ hostremove = item.get_token()
+ self.removeDHCPLease(self.settings.omapi_port,hostremove)
+
# we used to just loop through each system, but now we must loop
# through each network interface of each system.
-
+
for system in self.systems:
profile = system.get_conceptual_parent()
distro = profile.get_conceptual_parent()
@@ -121,6 +186,19 @@ class DHCPGen:
if ip is not None and ip != "":
systxt = systxt + " fixed-address %s;\n" % ip
systxt = systxt + "}\n"
+
+ # If we have all values defined and we're using omapi,
+ # we will just create entries dinamically into DHCPD
+ # without requiring a restart (but file will be written
+ # as usual for having it working after restart)
+
+ if ip is not None and ip != "":
+ if mac is not None and mac != "":
+ if host is not None and host != "":
+ if self.settings.omapi and self.settings.omapi_port:
+ self.removeDHCPLease(self.settings.omapi_port,host)
+ self.writeDHCPLease(self.settings.omapi_port,host,ip,mac)
+
else:
# dnsmasq. don't have to write IP and other info here, but we do tag
@@ -192,5 +270,3 @@ class DHCPGen:
if host is not None and host != "" and ip is not None and ip != "":
fh.write(ip + "\t" + host + "\n")
fh.close()
-
-
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 40ed571..491de75 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -58,6 +58,8 @@ DEFAULTS = {
"manage_dhcp" : 0,
"manage_dhcp_mode" : "isc",
"next_server" : "127.0.0.1",
+ "omapi" : 1,
+ "omapi_port" : 647,
"pxe_just_once" : 0,
"register_new_installs" : 0,
"run_install_triggers" : 1,
diff --git a/config/settings b/config/settings
index 10e06e2..724f419 100644
--- a/config/settings
+++ b/config/settings
@@ -32,6 +32,8 @@ ldap_search_prefix: 'uid='
manage_dhcp: 0
manage_dhcp_mode: isc
next_server: '127.0.0.1'
+omapi: 1
+omapi_port: 647
pxe_just_once: 0
register_new_installs: 0
run_install_triggers: 1
diff --git a/templates/dhcp.template b/templates/dhcp.template
index 705cc77..19afcad 100644
--- a/templates/dhcp.template
+++ b/templates/dhcp.template
@@ -9,6 +9,7 @@ ddns-update-style interim;
allow booting;
allow bootp;
+omapi-port 647;
ignore client-updates;
set vendorclass = option vendor-class-identifier;
diff --git a/triggers/restart-services.trigger b/triggers/restart-services.trigger
index b65b825..6a0e320 100644
--- a/triggers/restart-services.trigger
+++ b/triggers/restart-services.trigger
@@ -8,11 +8,19 @@ bootapi = capi.BootAPI()
settings = bootapi.settings()
manage_dhcp = str(settings.manage_dhcp).lower()
manage_dhcp_mode = str(settings.manage_dhcp_mode).lower()
+omapi = settings.omapi
+omapi_port = settings.omapi_port
+
+
+
+# We're just going to restart DHCPD if using ISC and if not using OMAPI at all
rc = 0
if manage_dhcp != "0":
if manage_dhcp_mode == "isc":
- rc = os.system("/sbin/service dhcpd restart")
+ if not omapi:
+ if not omapi_port:
+ rc = os.system("/sbin/service dhcpd restart")
elif manage_dhcp_mode == "dnsmasq":
rc = os.system("/sbin/service dnsmasq restart")
else:
--
cgit
From 82f4bb814835a8aadcfe5cbba8bfbc4359c34b39 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 11:58:36 -0400
Subject: Apply John Eckersberg's patch for BIND management.
---
AUTHORS | 1 +
cobbler/action_sync.py | 4 ++++
cobbler/settings.py | 4 ++++
cobbler/webui/master.py | 1 -
config/settings | 1 +
docs/cobbler.pod | 14 ++++++++++++--
setup.py | 4 +++-
triggers/restart-services.trigger | 9 ++++++++-
website/new/docs/cobbler.html | 14 ++++++++++++++
9 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index 5d2c797..cb26afc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,6 +11,7 @@ Patches and other contributions from:
James Bowes
C. Daniel Chase
Máirín Duffy
+ John Eckersberg
Tru Huynh
Matt Hyclak
Pablo Iranzo Gómez
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 4156ea7..98faa0c 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -29,6 +29,7 @@ from cexceptions import *
import templar
import pxegen
import dhcpgen
+import dnsgen
import yumgen
import item_distro
@@ -84,6 +85,7 @@ class BootSync:
self.repos = self.config.repos()
self.pxegen = pxegen.PXEGen(self.config)
self.dhcpgen = dhcpgen.DHCPGen(self.config)
+ self.dnsgen = dnsgen.DNSGen(self.config)
self.yumgen = yumgen.YumGen(self.config)
# execute the core of the sync operation
@@ -98,6 +100,8 @@ class BootSync:
self.dhcpgen.write_dhcp_file()
self.dhcpgen.regen_ethers()
self.dhcpgen.regen_hosts()
+ if self.settings.manage_dns:
+ self.dnsgen.write_bind_files()
self.pxegen.make_pxe_menu()
# run post-triggers
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 491de75..a661768 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -57,6 +57,10 @@ DEFAULTS = {
},
"manage_dhcp" : 0,
"manage_dhcp_mode" : "isc",
+ "manage_dns" : 0,
+ "manage_forward_zones" : [],
+ "manage_reverse_zones" : [],
+ "named_conf" : "/etc/named.conf",
"next_server" : "127.0.0.1",
"omapi" : 1,
"omapi_port" : 647,
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 22391eb..7e54a2d 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -35,7 +35,6 @@ __CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
__CHEETAH_genTime__ = 1209057202.737108
__CHEETAH_genTimestamp__ = 'Thu Apr 24 13:13:22 2008'
-__CHEETAH_src__ = 'webui_templates/master.tmpl'
__CHEETAH_srcLastModified__ = 'Thu Apr 24 12:59:37 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
diff --git a/config/settings b/config/settings
index 724f419..6f2aff6 100644
--- a/config/settings
+++ b/config/settings
@@ -31,6 +31,7 @@ ldap_search_passwd: ''
ldap_search_prefix: 'uid='
manage_dhcp: 0
manage_dhcp_mode: isc
+manage_dns: 0
next_server: '127.0.0.1'
omapi: 1
omapi_port: 647
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index d7a4550..21ec78e 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -403,8 +403,8 @@ Cobbler sync is used to repair or rebuild the contents /tftpboot or /var/www/cob
Sync should be run whenever files in /var/lib/cobbler are manually edited (which is not recommended except for the settings file) or when making changes to kickstart files. In practice, this should not happen often, though running sync too many times does not cause any adverse effects.
-If using cobbler to manage a DHCP server (see the advanced section of this manpage), sync does need to be
-run after systems are added to regenerate and reload the DHCP configuration.
+If using cobbler to manage a DHCP and/or DNS server (see the advanced section of this manpage), sync does need to be
+run after systems are added to regenerate and reload the DHCP/DNS configuration.
=head1 EXAMPLES
@@ -565,6 +565,16 @@ Itanium systems names also need to be assigned to a distro that was created with
The dhcpd.conf file will be updated each time "cobbler sync" is run, and not until then, so it is important to remember to use "cobbler sync" when using this feature.
+=head2 BIND CONFIGURATION MANAGEMENT
+
+Cobbler can optionally manage DNS configuration using BIND.
+
+This feature is off by default and must be turned on by setting 'manage_dns' to 1 in /var/lib/cobbler/settings. You may restrict the scope of zones managed with the options 'manage_forward_zones' and 'manage_reverse_zones'.
+
+Cobbler will use /etc/cobbler/bind.template and /etc/cobbler/zone.template as a starting point for the named.conf and individual zone files, respectively. These files must be user edited for the user's particular networking environment. Read the file and understand how BIND works before proceeding.
+
+The named.conf file as well as all zone files will be updated each time ``cobbler sync'' is run, and not until then, so it is important to remember to use ``cobbler sync'' when using this feature.
+
=head2 SERVICE DISCOVERY (AVAHI)
If the avahi-tools package is installed, cobblerd will broadcast it's presence on the network, allowing it to be discovered by koan with the koan --server=DISCOVER parameter.
diff --git a/setup.py b/setup.py
index 91eabed..442da5b 100644
--- a/setup.py
+++ b/setup.py
@@ -94,13 +94,15 @@ if __name__ == "__main__":
(etcpath, ['kickstarts/sample_end.ks']),
(etcpath, ['kickstarts/default.ks']),
- # templates for DHCP and syslinux configs
+ # templates for DHCP, DNS, and syslinux configs
(etcpath, ['templates/dhcp.template']),
(etcpath, ['templates/dnsmasq.template']),
+ (etcpath, ['templates/named.template']),
(etcpath, ['templates/pxedefault.template']),
(etcpath, ['templates/pxesystem.template']),
(etcpath, ['templates/pxesystem_ia64.template']),
(etcpath, ['templates/pxeprofile.template']),
+ (etcpath, ['templates/zone.template']),
# kickstart dir
(vl_kick, []),
diff --git a/triggers/restart-services.trigger b/triggers/restart-services.trigger
index 6a0e320..24fc033 100644
--- a/triggers/restart-services.trigger
+++ b/triggers/restart-services.trigger
@@ -8,13 +8,13 @@ bootapi = capi.BootAPI()
settings = bootapi.settings()
manage_dhcp = str(settings.manage_dhcp).lower()
manage_dhcp_mode = str(settings.manage_dhcp_mode).lower()
+manage_dns = str(settings.manage_dns).lower()
omapi = settings.omapi
omapi_port = settings.omapi_port
# We're just going to restart DHCPD if using ISC and if not using OMAPI at all
-
rc = 0
if manage_dhcp != "0":
if manage_dhcp_mode == "isc":
@@ -27,4 +27,11 @@ if manage_dhcp != "0":
print "- error: unknown DHCP engine: %s" % manage_dhcp_mode
rc = 411
+if rc != 0:
+ sys.exit(rc)
+
+if manage_dns != "0":
+ rc = os.system("/sbin/service named restart")
+
sys.exit(rc)
+
diff --git a/website/new/docs/cobbler.html b/website/new/docs/cobbler.html
index 36ad3e0..06a8b14 100644
--- a/website/new/docs/cobbler.html
+++ b/website/new/docs/cobbler.html
@@ -661,6 +661,20 @@ the setting to 'isc'.
The dhcpd.conf file will be updated each time ``cobbler sync'' is run, and not until then, so it is important to remember to use ``cobbler sync'' when using this feature.
Cobbler can optionally manage DNS configuration using BIND.
+
This feature is off by default and must be turned on by setting 'manage_dns' to 1 in
+/var/lib/cobbler/settings. You may restrict the scope of zones
+managed with the options 'manage_forward_zones' and
+'manage_reverse_zones'.
+
Cobbler will use /etc/cobbler/bind.template and
+ /etc/cobbler/zone.template as a starting point for the named.conf
+ and individual zone files, respectively. These files must be user
+ edited for the user's particular networking environment. Read the
+ file and understand how BIND works before proceeding.
+
The named.conf file as well as all zone files will be updated each time ``cobbler sync'' is run, and not until then, so it is important to remember to use ``cobbler sync'' when using this feature.
If the avahi-tools package is installed, cobblerd will broadcast it's presence on the network, allowing it to be discovered by koan with the koan --server=DISCOVER parameter.
--
cgit
From 13eff0d1bb7e36569a00bcd291d73781ab2351e4 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 12:41:20 -0400
Subject: Adjusting the dhcp patch some, prior to moving it all into modules/
---
cobbler/action_sync.py | 2 +-
cobbler/api.py | 15 +++++-
cobbler/dhcpgen.py | 106 +++++++++++++++++++++-----------------
cobbler/settings.py | 2 +-
config/settings | 2 +-
templates/dhcp.template | 4 +-
tests/tests.py | 4 +-
triggers/restart-services.trigger | 4 +-
8 files changed, 82 insertions(+), 57 deletions(-)
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 98faa0c..53ef3a7 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -47,7 +47,7 @@ class BootSync:
Handles conversion of internal state to the tftpboot tree layout
"""
- def __init__(self,config,verbose=False):
+ def __init__(self,config,verbose=False,dhcp=None,dns=None):
"""
Constructor
"""
diff --git a/cobbler/api.py b/cobbler/api.py
index 7bcd4fa..29a854d 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -81,6 +81,16 @@ class BootAPI:
"module",
"authz_allowall"
)
+ self.dhcp = self.get_module_from_file(
+ "dhcp_management",
+ "module",
+ "dhcp_isc"
+ )
+ self.dns = self.get_module_from_file(
+ "dns_management",
+ "module",
+ "dns_bind"
+ )
self.kickgen = kickgen.KickGen(self._config)
self.logger.debug("API handle initialized")
@@ -332,9 +342,12 @@ class BootAPI:
saved with serialize() will NOT be synchronized with this command.
"""
self.log("sync")
- sync = action_sync.BootSync(self._config)
+ sync = self.get_sync()
return sync.run()
+ def get_sync(self):
+ return action_sync.BootSync(self._config,dhcp=self.dhcp,dns=self.dns)
+
def reposync(self, name=None):
"""
Take the contents of /var/lib/cobbler/repos and update them --
diff --git a/cobbler/dhcpgen.py b/cobbler/dhcpgen.py
index cc6d410..5dd981c 100644
--- a/cobbler/dhcpgen.py
+++ b/cobbler/dhcpgen.py
@@ -60,44 +60,54 @@ class DHCPGen:
"""writeDHCPLease(port,host,ip,mac)
Use DHCP's API to create a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """
#Code from http://svn.osgdc.org/browse/kusu/kusu/trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025
- fromchild, tochild = popen2.popen2("/usr/bin/omshell")
- tochild.write("port %s\n" % port)
- tochild.flush()
- tochild.write("connect\n")
- tochild.flush()
- tochild.write("new host\n")
- tochild.flush()
- tochild.write('set name = \"%s\"\n' % host)
- tochild.flush()
- tochild.write("set ip-address = %s\n" % ip)
- tochild.flush()
- tochild.write("set hardware-address = %s\n" % mac)
- tochild.flush()
- tochild.write("set hardware-type = 1\n")
- tochild.flush()
- tochild.write("create\n")
- tochild.flush()
- tochild.close()
- fromchild.close()
-
+ # FIXME: should use subprocess
+ try:
+ fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("set ip-address = %s\n" % ip)
+ tochild.flush()
+ tochild.write("set hardware-address = %s\n" % mac)
+ tochild.flush()
+ tochild.write("set hardware-type = 1\n")
+ tochild.flush()
+ tochild.write("create\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+ except IOError:
+ # FIXME: just catch 32 (broken pipe) and show a warning
+ pass
+
def removeDHCPLease(self,port,host):
"""removeDHCPLease(port,host)
Use DHCP's API to delete a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """
fromchild, tochild = popen2.popen2("/usr/bin/omshell")
- tochild.write("port %s\n" % port)
- tochild.flush()
- tochild.write("connect\n")
- tochild.flush()
- tochild.write("new host\n")
- tochild.flush()
- tochild.write('set name = \"%s\"\n' % host)
- tochild.flush()
- tochild.write("open\n") # opens register with host information
- tochild.flush()
- tochild.write("remove\n")
- tochild.flush()
- tochild.close()
- fromchild.close()
+ try:
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("open\n") # opens register with host information
+ tochild.flush()
+ tochild.write("remove\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+ except IOError:
+ # FIXME: convert this to subprocess.
+ # FIXME: catch specific errors only (32/broken pipe)
+ pass
def write_dhcp_file(self):
@@ -136,19 +146,17 @@ class DHCPGen:
# Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in
# case to avoid conflicts with the hosts we're defining and to clean
# possible removed hosts (only if using OMAPI)
- #
- # Pablo Iranzo Gómez (Pablo.Iranzo@redhat.com)
- if self.settings.omapi and self.settings.omapi_port:
- file = open('/var/lib/dhcpd/dhcpd.leases')
- item = shlex(file)
- while 1:
- elem = item.get_token()
- if not elem:
- break
- if elem == 'host':
- hostremove = item.get_token()
- self.removeDHCPLease(self.settings.omapi_port,hostremove)
-
+ if self.settings.omapi_enabled and self.settings.omapi_port:
+ if os.path.exists("/var/lib/dhcpd/dhcpd.leases"):
+ file = open('/var/lib/dhcpd/dhcpd.leases')
+ item = shlex(file)
+ while 1:
+ elem = item.get_token()
+ if not elem:
+ break
+ if elem == 'host':
+ hostremove = item.get_token()
+ self.removeDHCPLease(self.settings.omapi_port,hostremove)
# we used to just loop through each system, but now we must loop
# through each network interface of each system.
@@ -195,7 +203,7 @@ class DHCPGen:
if ip is not None and ip != "":
if mac is not None and mac != "":
if host is not None and host != "":
- if self.settings.omapi and self.settings.omapi_port:
+ if self.settings.omapi_enabled and self.settings.omapi_port:
self.removeDHCPLease(self.settings.omapi_port,host)
self.writeDHCPLease(self.settings.omapi_port,host,ip,mac)
@@ -225,6 +233,8 @@ class DHCPGen:
# we are now done with the looping through each interface of each system
metadata = {
+ "omapi_enabled" : self.settings.omapi_enabled,
+ "omapi_port" : self.settings.omapi_port,
"insert_cobbler_system_definitions" : system_definitions.get("default",""),
"date" : time.asctime(time.gmtime()),
"cobbler_server" : self.settings.server,
diff --git a/cobbler/settings.py b/cobbler/settings.py
index a661768..70b2ac8 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -62,7 +62,7 @@ DEFAULTS = {
"manage_reverse_zones" : [],
"named_conf" : "/etc/named.conf",
"next_server" : "127.0.0.1",
- "omapi" : 1,
+ "omapi_enabled" : 0,
"omapi_port" : 647,
"pxe_just_once" : 0,
"register_new_installs" : 0,
diff --git a/config/settings b/config/settings
index 6f2aff6..8b39707 100644
--- a/config/settings
+++ b/config/settings
@@ -33,7 +33,7 @@ manage_dhcp: 0
manage_dhcp_mode: isc
manage_dns: 0
next_server: '127.0.0.1'
-omapi: 1
+omapi_enabled: 1
omapi_port: 647
pxe_just_once: 0
register_new_installs: 0
diff --git a/templates/dhcp.template b/templates/dhcp.template
index 19afcad..344b108 100644
--- a/templates/dhcp.template
+++ b/templates/dhcp.template
@@ -9,7 +9,9 @@ ddns-update-style interim;
allow booting;
allow bootp;
-omapi-port 647;
+#if $omapi_enabled
+omapi-port $omapi_port;
+#end if
ignore client-updates;
set vendorclass = option vendor-class-identifier;
diff --git a/tests/tests.py b/tests/tests.py
index bb64dd1..02d53be 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -743,7 +743,7 @@ class SyncContents(BootTest):
fh = open("/tftpboot/pxelinux.cfg/%s" % converted)
data = fh.read()
- self.assertTrue(data.find("op=ks") != -1)
+ self.assertTrue(data.find("/op/ks/") != -1)
fh.close()
# ensure that after sync is applied, the blender cache still allows
@@ -753,7 +753,7 @@ class SyncContents(BootTest):
self.api.sync()
fh = open("/tftpboot/pxelinux.cfg/%s" % converted)
data = fh.read()
- self.assertTrue(data.find("op=ks") != -1)
+ self.assertTrue(data.find("/op/ks/") != -1)
fh.close()
diff --git a/triggers/restart-services.trigger b/triggers/restart-services.trigger
index 24fc033..bc7c36e 100644
--- a/triggers/restart-services.trigger
+++ b/triggers/restart-services.trigger
@@ -9,7 +9,7 @@ settings = bootapi.settings()
manage_dhcp = str(settings.manage_dhcp).lower()
manage_dhcp_mode = str(settings.manage_dhcp_mode).lower()
manage_dns = str(settings.manage_dns).lower()
-omapi = settings.omapi
+omapi_enabled = settings.omapi_enabled
omapi_port = settings.omapi_port
@@ -18,7 +18,7 @@ omapi_port = settings.omapi_port
rc = 0
if manage_dhcp != "0":
if manage_dhcp_mode == "isc":
- if not omapi:
+ if not omapi_enabled:
if not omapi_port:
rc = os.system("/sbin/service dhcpd restart")
elif manage_dhcp_mode == "dnsmasq":
--
cgit
From 34652b616c1adda6379c47886caed3b219fc29d1 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 12:47:18 -0400
Subject: Do not add profiles that have -xen distros to PXE menu entries as
there is no chance of them booting there.
---
cobbler/pxegen.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
index 8cb8c93..639c30b 100644
--- a/cobbler/pxegen.py
+++ b/cobbler/pxegen.py
@@ -177,6 +177,9 @@ class PXEGen:
pxe_menu_items = ""
for profile in profile_list:
distro = profile.get_conceptual_parent()
+ # xen distros can be ruled out as they won't boot
+ if distro.name.find("-xen") != -1:
+ continue
contents = self.write_pxe_file(None,None,profile,distro,False,include_header=False)
if contents is not None:
pxe_menu_items = pxe_menu_items + contents + "\n"
--
cgit
From e4fce2b7321c880f8c1f1adbdf137fc4d66563de Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 13:02:10 -0400
Subject: Changelog and doc cleanup (note: manpages reference future behavior
WRT dns/dhcp behavior, to be implemented soon).
---
CHANGELOG | 4 ++++
docs/cobbler.pod | 40 +++++++++++++++++++---------------------
2 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index ed91270..278b8fa 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -33,6 +33,10 @@ Cobbler CHANGELOG
- implement "cobbler ___ dumpvars --name=X" feature to show template vars
- validateks now works against all URLs as opposed to rendered local files
- now possible to create new kickstarts in webui, and delete unused ones
+- support for OMAPI for avoid dhcp restarts
+- support for managing BIND
+- xen kernel (PV) distros do not get added to PXE menus as they won't boot there
+- cobbler buildiso command to build non live ISOs
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index 21ec78e..311a94c 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -537,43 +537,37 @@ Anywhere a kickstart template mentions SNIPPET::snippet_name, the file named /va
To check for potential errors in kickstarts, prior to installation, use "cobbler validateks". This function will check all profile and system kickstarts for detectable errors. Since pykickstart is not future-Anaconda-version aware, there may be some false positives. It should be noted that "cobbler validateks" runs on the rendered kickstart output, not kickstart templates themselves.
-=head2 DHCP CONFIGURATION MANAGEMENT
+=head2 DHCP MANAGEMENT
-Cobbler can optionally help you manage DHCP and (depending on how used) DNS as it relates
-to systems you wish to provision/control. This allows cobbler to essentially maintain a database
-of all of your installed systems, and be a central point of control for aspects related to setting
-up those systems.
+Cobbler can optionally help you manage DHCP server. This feature is off by default.
-This feature is off by default and must be turned on by setting 'manage_dhcp' to 1 in
-/var/lib/cobbler/settings. Choices include ISC dhcpd (default), or DNSmasq, which can be chosen
-by setting manage_dhcp_mode to 'dnsmasq'. If you choose dnsmasq and want to revert to ISC, change
-the setting to 'isc'.
+Choose either "management = isc_and_bind" in /etc/cobbler/dhcp.template or "management = "dnsmasq" in /etc/cobbler/modules.conf. Then set "manage_dhcp" to 1 in /var/lib/cobbler/settings.
+
+This allows DHCP to be managed via "cobbler system add" commands, when you specify the mac address and IP address for systems you add into cobbler.
Depending on your choice, cobbler will use /etc/cobbler/dhcpd.template or /etc/cobbler/dnsmasq.template as a starting point. This file must be user edited for the user's particular networking environment. Read the file and understand how the particular app (ISC dhcpd or dnsmasq) work before proceeding.
If you already have DHCP configuration data that you would like to preserve (say DHCP was manually configured earlier), insert the relevant portions of it into the template file, as running "cobbler sync" will overwrite your previous configuration.
-In summary, if this manage_dhcp bit is enabled, the following features are enabled:
+NOTE: Itanium systems names also need to be assigned to a distro that was created with the "--arch=ia64" parameter. If you have Itanium systems, you must (for now) choose 'dhcp_isc' for /etc/cobbler/modules.conf and manage_dhcp in the /var/lib/cobbler/settings file, and are required to use --ip when creating the system object in order for those systems to PXE. This is due to an elilo limitation.
-(A) pinning dhcp hostnames to MAC addresses automatically.
-(B) relatively seamless mixing of Itanium and x86/x86_64 machines in a PXE environment (ISC only)
-(C) assigning hostnames to MAC addresses using DNS (dnsmasq only).
+By default, the DHCP configuration file will be updated each time "cobbler sync" is run, and not until then, so it is important to remember to use "cobbler sync" when using this feature.
-These options are all enabled by using the --hostname and --ip options when using the "cobbler system add" command.
+If omapi_enabled is set to 1 in /var/lib/cobbler/settings, the need to sync when adding new system records can be eliminated.
-Itanium systems names also need to be assigned to a distro that was created with the "--arch=ia64" parameter. If you have Itanium systems, you must (for now) choose 'isc' for 'manage_dhcp_mode' in the /var/lib/cobbler/settings file, and are required to use --ip when creating the system object in order for those systems to PXE.
+=head2 DNS CONFIGURATION MANAGEMENT
-The dhcpd.conf file will be updated each time "cobbler sync" is run, and not until then, so it is important to remember to use "cobbler sync" when using this feature.
+Cobbler can optionally manage DNS configuration using BIND and dnsmasq.
-=head2 BIND CONFIGURATION MANAGEMENT
+Choose either "management = isc_and_bind" or "management = dnsmasq" in /etc/cobbler/modules.conf and then enable manage_dns in /var/lib/cobbler/settings.
-Cobbler can optionally manage DNS configuration using BIND.
+This feature is off by default. If using BIND, you may restrict the scope of zones managed with the options 'manage_forward_zones' and 'manage_reverse_zones'. (See the Wiki for more information on this).
-This feature is off by default and must be turned on by setting 'manage_dns' to 1 in /var/lib/cobbler/settings. You may restrict the scope of zones managed with the options 'manage_forward_zones' and 'manage_reverse_zones'.
+If using BIND, Cobbler will use /etc/cobbler/bind.template and /etc/cobbler/zone.template as a starting point for the named.conf and individual zone files, respectively. These files must be user edited for the user's particular networking environment. Read the file and understand how BIND works before proceeding.
-Cobbler will use /etc/cobbler/bind.template and /etc/cobbler/zone.template as a starting point for the named.conf and individual zone files, respectively. These files must be user edited for the user's particular networking environment. Read the file and understand how BIND works before proceeding.
+If using dnsmasq, the template is /etc/cobbler/dnsmasq.template. Read this file and understand how dnsmasq works before proceeding.
-The named.conf file as well as all zone files will be updated each time ``cobbler sync'' is run, and not until then, so it is important to remember to use ``cobbler sync'' when using this feature.
+All managed files (whether zone files and named.conf for BIND, or dnsmasq.conf for dnsmasq) will be updated each time ``cobbler sync'' is run, and not until then, so it is important to remember to use ``cobbler sync'' when using this feature.
=head2 SERVICE DISCOVERY (AVAHI)
@@ -684,6 +678,10 @@ Most of the day-to-day actions in cobbler's command line can be performed in Cob
https://hosted.fedoraproject.org/projects/cobbler/wiki/CobblerWebUi
+=head2 BOOT CD
+
+Cobbler can build all of it's profiles into a bootable CD image using the "cobbler buildiso" command. This allows for PXE-menu like bringup of bare metal in evnvironments where PXE is not possible. Another more advanced method is described in the koan manpage, though this method is easier and sufficient for most applications.
+
=head1 EXIT_STATUS
cobbler's command line returns a zero for success and non-zero for failure.
--
cgit
From a6fd395b51a624e4aa7d09b4960382784cefa8e8 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 16:05:32 -0400
Subject: Working on moving DNS/DHCP management to cobbler/modules (uses
modules.conf) In progress.
---
cobbler/action_check.py | 8 +-
cobbler/action_litesync.py | 24 +-
cobbler/action_sync.py | 18 +-
cobbler/api.py | 17 +-
cobbler/dhcpgen.py | 282 ----------------------
cobbler/manage_ctrl.py | 76 ++++++
cobbler/modules/manage_dnsmasq.py | 191 +++++++++++++++
cobbler/modules/manage_isc_and_bind.py | 425 +++++++++++++++++++++++++++++++++
config/modules.conf | 5 +
config/settings | 1 -
10 files changed, 736 insertions(+), 311 deletions(-)
delete mode 100644 cobbler/dhcpgen.py
create mode 100644 cobbler/manage_ctrl.py
create mode 100644 cobbler/modules/manage_dnsmasq.py
create mode 100644 cobbler/modules/manage_isc_and_bind.py
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index e91396f..588a65a 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -37,8 +37,8 @@ class BootCheck:
status = []
self.check_name(status)
if self.settings.manage_dhcp:
- mode = self.settings.manage_dhcp_mode.lower()
- if mode == "isc":
+ mode = self.config.api.get_sync().manager.what()
+ if mode == "isc_and_bind":
self.check_dhcpd_bin(status)
self.check_dhcpd_conf(status)
self.check_service(status,"dhcpd")
@@ -46,7 +46,9 @@ class BootCheck:
self.check_dnsmasq_bin(status)
self.check_service(status,"dnsmasq")
else:
- status.append(_("manage_dhcp_mode in /var/lib/cobbler/settings should be 'isc' or 'dnsmasq'"))
+ status.append(_("configured management mode in modules.conf is unknown"))
+ # FIXME: add in checks for bind config
+
self.check_service(status, "cobblerd")
self.check_bootloaders(status)
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index c2029d4..ba0a256 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -49,7 +49,7 @@ class BootLiteSync:
self.systems = config.systems()
self.settings = config.settings()
self.repos = config.repos()
- self.sync = action_sync.BootSync(self.config)
+ self.sync = config.api.get_sync()
def add_single_distro(self, name):
# get the distro record
@@ -105,12 +105,22 @@ class BootLiteSync:
if system is None:
raise CX(_("error in system lookup for %s") % name)
# rebuild system_list file in webdir
- self.sync.dhcpgen.regen_ethers() # /etc/ethers, for dnsmasq & rarpd
- self.sync.dhcpgen.regen_hosts() # /var/lib/cobbler/cobbler_hosts, pretty much for dnsmasq
+ self.sync.manager.regen_ethers()
+ self.sync.manager.regen_hosts()
# write the PXE files for the system
self.sync.pxegen.write_all_system_files(system)
# per system kickstarts
self.sync.yumgen.retemplate_yum_repos(system,False)
+ if self.settings.manage_dhcp:
+ if self.settings.omapi_enabled:
+ for (name,interface) in system.interfaces.iteritems():
+ self.sync.manager.write_dhcp_lease(
+ self.settings.omapi_port,
+ interface["hostname"],
+ interface["mac-address"],
+ interface["ip-address"]
+ )
+
def remove_single_system(self, name):
bootloc = utils.tftpboot_location()
@@ -122,6 +132,14 @@ class BootLiteSync:
filename = utils.get_config_filename(system_record,interface=name)
utils.rmtree(os.path.join(self.settings.webdir, "kickstarts_sys", filename))
+ if self.settings.manage_dhcp:
+ if self.settings.omapi_enabled:
+ for (name,interface) in system_record.interfaces.iteritems():
+ self.sync.manager.remove_dhcp_lease(
+ self.settings.omapi_port,
+ interface["hostname"]
+ )
+
# unneeded
#if not system_record.is_pxe_supported():
# # no need to go any further with PXE cleanup
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 53ef3a7..fbc9402 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -28,8 +28,7 @@ import utils
from cexceptions import *
import templar
import pxegen
-import dhcpgen
-import dnsgen
+import manage_ctrl
import yumgen
import item_distro
@@ -47,7 +46,7 @@ class BootSync:
Handles conversion of internal state to the tftpboot tree layout
"""
- def __init__(self,config,verbose=False,dhcp=None,dns=None):
+ def __init__(self,config,verbose=False,manage=None):
"""
Constructor
"""
@@ -61,7 +60,7 @@ class BootSync:
self.repos = config.repos()
self.templar = templar.Templar(config)
self.pxegen = pxegen.PXEGen(config)
- self.dhcpgen = dhcpgen.DHCPGen(config)
+ self.manager = manage
self.yumgen = yumgen.YumGen(config)
self.bootloc = utils.tftpboot_location()
@@ -84,8 +83,6 @@ class BootSync:
self.settings = self.config.settings()
self.repos = self.config.repos()
self.pxegen = pxegen.PXEGen(self.config)
- self.dhcpgen = dhcpgen.DHCPGen(self.config)
- self.dnsgen = dnsgen.DNSGen(self.config)
self.yumgen = yumgen.YumGen(self.config)
# execute the core of the sync operation
@@ -96,12 +93,11 @@ class BootSync:
self.pxegen.write_all_system_files(x)
self.yumgen.retemplate_all_yum_repos()
if self.settings.manage_dhcp:
- # these functions DRT for ISC or dnsmasq
- self.dhcpgen.write_dhcp_file()
- self.dhcpgen.regen_ethers()
- self.dhcpgen.regen_hosts()
+ self.manager.write_dhcp_file()
+ self.manager.regen_ethers()
+ self.manager.regen_hosts()
if self.settings.manage_dns:
- self.dnsgen.write_bind_files()
+ self.manager.write_dns_files()
self.pxegen.make_pxe_menu()
# run post-triggers
diff --git a/cobbler/api.py b/cobbler/api.py
index 29a854d..1f5a246 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -81,16 +81,6 @@ class BootAPI:
"module",
"authz_allowall"
)
- self.dhcp = self.get_module_from_file(
- "dhcp_management",
- "module",
- "dhcp_isc"
- )
- self.dns = self.get_module_from_file(
- "dns_management",
- "module",
- "dns_bind"
- )
self.kickgen = kickgen.KickGen(self._config)
self.logger.debug("API handle initialized")
@@ -346,7 +336,12 @@ class BootAPI:
return sync.run()
def get_sync(self):
- return action_sync.BootSync(self._config,dhcp=self.dhcp,dns=self.dns)
+ self.manage = self.get_module_from_file(
+ "management",
+ "module",
+ "manage_isc_and_bind"
+ ).get_manager(self._config)
+ return action_sync.BootSync(self._config,manage=self.manage)
def reposync(self, name=None):
"""
diff --git a/cobbler/dhcpgen.py b/cobbler/dhcpgen.py
deleted file mode 100644
index 5dd981c..0000000
--- a/cobbler/dhcpgen.py
+++ /dev/null
@@ -1,282 +0,0 @@
-"""
-Builds out DHCP info
-This is the code behind 'cobbler sync'.
-
-Copyright 2006-2008, Red Hat, Inc
-Michael DeHaan
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-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., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-import os
-import os.path
-import shutil
-import time
-import sub_process
-import sys
-import glob
-import traceback
-import errno
-import popen2
-from shlex import shlex
-
-
-import utils
-from cexceptions import *
-import templar
-
-import item_distro
-import item_profile
-import item_repo
-import item_system
-
-from utils import _
-
-class DHCPGen:
- """
- Handles conversion of internal state to the tftpboot tree layout
- """
-
- def __init__(self,config,verbose=False):
- """
- Constructor
- """
- self.verbose = verbose
- self.config = config
- self.api = config.api
- self.distros = config.distros()
- self.profiles = config.profiles()
- self.systems = config.systems()
- self.settings = config.settings()
- self.repos = config.repos()
- self.templar = templar.Templar(config)
-
- def writeDHCPLease(self,port,host,ip,mac):
- """writeDHCPLease(port,host,ip,mac)
- Use DHCP's API to create a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """
- #Code from http://svn.osgdc.org/browse/kusu/kusu/trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025
- # FIXME: should use subprocess
- try:
- fromchild, tochild = popen2.popen2("/usr/bin/omshell")
- tochild.write("port %s\n" % port)
- tochild.flush()
- tochild.write("connect\n")
- tochild.flush()
- tochild.write("new host\n")
- tochild.flush()
- tochild.write('set name = \"%s\"\n' % host)
- tochild.flush()
- tochild.write("set ip-address = %s\n" % ip)
- tochild.flush()
- tochild.write("set hardware-address = %s\n" % mac)
- tochild.flush()
- tochild.write("set hardware-type = 1\n")
- tochild.flush()
- tochild.write("create\n")
- tochild.flush()
- tochild.close()
- fromchild.close()
- except IOError:
- # FIXME: just catch 32 (broken pipe) and show a warning
- pass
-
- def removeDHCPLease(self,port,host):
- """removeDHCPLease(port,host)
- Use DHCP's API to delete a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """
- fromchild, tochild = popen2.popen2("/usr/bin/omshell")
- try:
- tochild.write("port %s\n" % port)
- tochild.flush()
- tochild.write("connect\n")
- tochild.flush()
- tochild.write("new host\n")
- tochild.flush()
- tochild.write('set name = \"%s\"\n' % host)
- tochild.flush()
- tochild.write("open\n") # opens register with host information
- tochild.flush()
- tochild.write("remove\n")
- tochild.flush()
- tochild.close()
- fromchild.close()
- except IOError:
- # FIXME: convert this to subprocess.
- # FIXME: catch specific errors only (32/broken pipe)
- pass
-
-
- def write_dhcp_file(self):
- """
- DHCP files are written when manage_dhcp is set in
- /var/lib/cobbler/settings.
- """
-
- settings_file = self.settings.dhcpd_conf
- template_file = "/etc/cobbler/dhcp.template"
- mode = self.settings.manage_dhcp_mode.lower()
- if mode == "dnsmasq":
- settings_file = self.settings.dnsmasq_conf
- template_file = "/etc/cobbler/dnsmasq.template"
-
- try:
- f2 = open(template_file,"r")
- except:
- raise CX(_("error writing template to file: %s") % template_file)
- template_data = ""
- template_data = f2.read()
- f2.close()
-
- # build each per-system definition
- # as configured, this only works for ISC, patches accepted
- # from those that care about Itanium. elilo seems to be unmaintained
- # so additional maintaince in other areas may be required to keep
- # this working.
-
- elilo = os.path.basename(self.settings.bootloaders["ia64"])
-
- system_definitions = {}
- counter = 0
-
-
- # Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in
- # case to avoid conflicts with the hosts we're defining and to clean
- # possible removed hosts (only if using OMAPI)
- if self.settings.omapi_enabled and self.settings.omapi_port:
- if os.path.exists("/var/lib/dhcpd/dhcpd.leases"):
- file = open('/var/lib/dhcpd/dhcpd.leases')
- item = shlex(file)
- while 1:
- elem = item.get_token()
- if not elem:
- break
- if elem == 'host':
- hostremove = item.get_token()
- self.removeDHCPLease(self.settings.omapi_port,hostremove)
-
- # we used to just loop through each system, but now we must loop
- # through each network interface of each system.
-
- for system in self.systems:
- profile = system.get_conceptual_parent()
- distro = profile.get_conceptual_parent()
- for (name, interface) in system.interfaces.iteritems():
-
- mac = interface["mac_address"]
- ip = interface["ip_address"]
- host = interface["hostname"]
-
- if mac is None or mac == "":
- # can't write a DHCP entry for this system
- continue
-
- counter = counter + 1
- systxt = ""
-
- if mode == "isc":
-
- # the label the entry after the hostname if possible
- if host is not None and host != "":
- systxt = "\nhost %s {\n" % host
- if self.settings.isc_set_host_name:
- systxt = systxt + " option host-name = \"%s\";\n" % host
- else:
- systxt = "\nhost generic%d {\n" % counter
-
- if distro.arch == "ia64":
- # can't use pxelinux.0 anymore
- systxt = systxt + " filename \"/%s\";\n" % elilo
- systxt = systxt + " hardware ethernet %s;\n" % mac
- if ip is not None and ip != "":
- systxt = systxt + " fixed-address %s;\n" % ip
- systxt = systxt + "}\n"
-
- # If we have all values defined and we're using omapi,
- # we will just create entries dinamically into DHCPD
- # without requiring a restart (but file will be written
- # as usual for having it working after restart)
-
- if ip is not None and ip != "":
- if mac is not None and mac != "":
- if host is not None and host != "":
- if self.settings.omapi_enabled and self.settings.omapi_port:
- self.removeDHCPLease(self.settings.omapi_port,host)
- self.writeDHCPLease(self.settings.omapi_port,host,ip,mac)
-
-
- else:
- # dnsmasq. don't have to write IP and other info here, but we do tag
- # each MAC based on the arch of it's distro, if it needs something other
- # than pxelinux.0 -- for these arches, and these arches only, a dnsmasq
- # reload (full "cobbler sync") would be required after adding the system
- # to cobbler, just to tag this relationship.
-
- if ip is not None and ip != "":
- if distro.arch.lower() == "ia64":
- systxt = "dhcp-host=net:ia64," + ip + "\n"
- # support for other arches needs modifications here
- else:
- systxt = ""
-
- dhcp_tag = interface["dhcp_tag"]
- if dhcp_tag == "":
- dhcp_tag = "default"
-
- if not system_definitions.has_key(dhcp_tag):
- system_definitions[dhcp_tag] = ""
- system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt
-
- # we are now done with the looping through each interface of each system
-
- metadata = {
- "omapi_enabled" : self.settings.omapi_enabled,
- "omapi_port" : self.settings.omapi_port,
- "insert_cobbler_system_definitions" : system_definitions.get("default",""),
- "date" : time.asctime(time.gmtime()),
- "cobbler_server" : self.settings.server,
- "next_server" : self.settings.next_server,
- "elilo" : elilo
- }
-
- # now add in other DHCP expansions that are not tagged with "default"
- for x in system_definitions.keys():
- if x == "default":
- continue
- metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
-
- self.templar.render(template_data, metadata, settings_file, None)
-
- def regen_ethers(self):
- # dnsmasq knows how to read this database of MACs -> IPs, so we'll keep it up to date
- # every time we add a system.
- # read 'man ethers' for format info
- fh = open("/etc/ethers","w+")
- for sys in self.systems:
- for (name, interface) in sys.interfaces.iteritems():
- mac = interface["mac_address"]
- ip = interface["ip_address"]
- if mac is None or mac == "":
- # can't write this w/o a MAC address
- continue
- if ip is not None and ip != "":
- fh.write(mac.upper() + "\t" + ip + "\n")
- fh.close()
-
- def regen_hosts(self):
- # dnsmasq knows how to read this database for host info
- # (other things may also make use of this later)
- fh = open("/var/lib/cobbler/cobbler_hosts","w+")
- for sys in self.systems:
- for (name, interface) in sys.interfaces.iteritems():
- mac = interface["mac_address"]
- host = interface["hostname"]
- ip = interface["ip_address"]
- if mac is None or mac == "":
- continue
- if host is not None and host != "" and ip is not None and ip != "":
- fh.write(ip + "\t" + host + "\n")
- fh.close()
diff --git a/cobbler/manage_ctrl.py b/cobbler/manage_ctrl.py
new file mode 100644
index 0000000..a01910a
--- /dev/null
+++ b/cobbler/manage_ctrl.py
@@ -0,0 +1,76 @@
+"""
+Builds out DHCP info
+This is the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+import popen2
+from shlex import shlex
+
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+class ManageCtrl:
+ """
+ Handles conversion of internal state to the tftpboot tree layout
+ """
+
+ def __init__(self,config,verbose=False,dns=None,dhcp=None):
+ """
+ Constructor
+ """
+ self.verbose = verbose
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+ self.dns = dns
+
+ def write_dhcp_lease(self,port,host,ip,mac):
+ return dhcp.write_dhcp_lease(port,host,ip,mac)
+
+ def remove_dhcp_lease(self,port,host):
+ return dhcp.remove_dhcp_lease(port,host)
+
+ def write_dhcp_file(self):
+ return dhcp.write_dhcp_file()
+
+ def regen_ethers(self):
+ return dhcp.regen_ethers()
+
+ def regen_hosts(self):
+ return dns.regen_hosts()
+
+ def write_dns_files(self):
+ return dns.write_bind_files()
diff --git a/cobbler/modules/manage_dnsmasq.py b/cobbler/modules/manage_dnsmasq.py
new file mode 100644
index 0000000..d37a2d4
--- /dev/null
+++ b/cobbler/modules/manage_dnsmasq.py
@@ -0,0 +1,191 @@
+
+"""
+This is some of the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+John Eckersberg
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+import popen2
+from shlex import shlex
+import utils
+from cexceptions import *
+import templar
+import item_distro
+import item_profile
+import item_repo
+import item_system
+from utils import _
+
+def register():
+ return "manage"
+
+class DnsmasqManager:
+ """
+ Handles conversion of internal state to the tftpboot tree layout
+ """
+
+ def __init__(self,config,verbose=False,dhcp=None):
+ """
+ Constructor
+ """
+ self.verbose = verbose
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+ self.dns = dns
+
+ def what(self):
+ return "dnsmasq"
+
+ def write_dhcp_lease(self,port,host,ip,mac):
+ pass
+
+ def remove_dhcp_lease(self,port,host):
+ pass
+
+
+ def write_dhcp_file(self):
+ """
+ DHCP files are written when manage_dhcp is set in
+ /var/lib/cobbler/settings.
+ """
+
+ settings_file = self.settings.dnsmasq_conf
+ template_file = "/etc/cobbler/dnsmasq.template"
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error writing template to file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ # build each per-system definition
+ # as configured, this only works for ISC, patches accepted
+ # from those that care about Itanium. elilo seems to be unmaintained
+ # so additional maintaince in other areas may be required to keep
+ # this working.
+
+ elilo = os.path.basename(self.settings.bootloaders["ia64"])
+
+ system_definitions = {}
+ counter = 0
+
+ # we used to just loop through each system, but now we must loop
+ # through each network interface of each system.
+
+ for system in self.systems:
+ profile = system.get_conceptual_parent()
+ distro = profile.get_conceptual_parent()
+ for (name, interface) in system.interfaces.iteritems():
+
+ mac = interface["mac_address"]
+ ip = interface["ip_address"]
+ host = interface["hostname"]
+
+ if mac is None or mac == "":
+ # can't write a DHCP entry for this system
+ continue
+
+ counter = counter + 1
+ systxt = ""
+
+ # dnsmasq. don't have to write IP and other info here, but we do tag
+ # each MAC based on the arch of it's distro, if it needs something other
+ # than pxelinux.0 -- for these arches, and these arches only, a dnsmasq
+ # reload (full "cobbler sync") would be required after adding the system
+ # to cobbler, just to tag this relationship.
+
+ if ip is not None and ip != "":
+ if distro.arch.lower() == "ia64":
+ systxt = "dhcp-host=net:ia64," + ip + "\n"
+ # support for other arches needs modifications here
+ else:
+ systxt = ""
+
+ dhcp_tag = interface["dhcp_tag"]
+ if dhcp_tag == "":
+ dhcp_tag = "default"
+
+ if not system_definitions.has_key(dhcp_tag):
+ system_definitions[dhcp_tag] = ""
+ system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt
+
+ # we are now done with the looping through each interface of each system
+
+ metadata = {
+ "omapi_enabled" : self.settings.omapi_enabled,
+ "omapi_port" : self.settings.omapi_port,
+ "insert_cobbler_system_definitions" : system_definitions.get("default",""),
+ "date" : time.asctime(time.gmtime()),
+ "cobbler_server" : self.settings.server,
+ "next_server" : self.settings.next_server,
+ "elilo" : elilo
+ }
+
+ # now add in other DHCP expansions that are not tagged with "default"
+ for x in system_definitions.keys():
+ if x == "default":
+ continue
+ metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
+
+ self.templar.render(template_data, metadata, settings_file, None)
+
+ def regen_ethers(self):
+ # dnsmasq knows how to read this database of MACs -> IPs, so we'll keep it up to date
+ # every time we add a system.
+ # read 'man ethers' for format info
+ fh = open("/etc/ethers","w+")
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ mac = interface["mac_address"]
+ ip = interface["ip_address"]
+ if mac is None or mac == "":
+ # can't write this w/o a MAC address
+ continue
+ if ip is not None and ip != "":
+ fh.write(mac.upper() + "\t" + ip + "\n")
+ fh.close()
+
+ def regen_hosts(self):
+ # dnsmasq knows how to read this database for host info
+ # (other things may also make use of this later)
+ fh = open("/var/lib/cobbler/cobbler_hosts","w+")
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ mac = interface["mac_address"]
+ host = interface["hostname"]
+ ip = interface["ip_address"]
+ if mac is None or mac == "":
+ continue
+ if host is not None and host != "" and ip is not None and ip != "":
+ fh.write(ip + "\t" + host + "\n")
+ fh.close()
+
+def get_manager(config):
+ return DnsmasqManager(config)
+
diff --git a/cobbler/modules/manage_isc_and_bind.py b/cobbler/modules/manage_isc_and_bind.py
new file mode 100644
index 0000000..bc3a338
--- /dev/null
+++ b/cobbler/modules/manage_isc_and_bind.py
@@ -0,0 +1,425 @@
+"""
+This is some of the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+John Eckersberg
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+import popen2
+from shlex import shlex
+
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "manage"
+
+
+class IscAndBindManager:
+
+ def what(self):
+ return "isc_and_bind"
+
+ def __init__(self,config,verbose=False):
+ """
+ Constructor
+ """
+ self.verbose = verbose
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+
+ def write_dhcp_lease(self,port,host,ip,mac):
+ """
+ Use DHCP's API to create a DHCP entry in the
+ /var/lib/dhcpd/dhcpd.leases file
+ #Code from http://svn.osgdc.org/browse/kusu/kusu
+ # /trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025
+ # FIXME: should use subprocess
+ """
+ try:
+ fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("set ip-address = %s\n" % ip)
+ tochild.flush()
+ tochild.write("set hardware-address = %s\n" % mac)
+ tochild.flush()
+ tochild.write("set hardware-type = 1\n")
+ tochild.flush()
+ tochild.write("create\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+ except IOError:
+ # FIXME: just catch 32 (broken pipe) and show a warning
+ pass
+
+ def remove_dhcp_lease(self,port,host):
+ """
+ removeDHCPLease(port,host)
+ Use DHCP's API to delete a DHCP entry in
+ the /var/lib/dhcpd/dhcpd.leases file
+ """
+ fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ try:
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("open\n") # opens register with host information
+ tochild.flush()
+ tochild.write("remove\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+ except IOError:
+ # FIXME: convert this to subprocess.
+ # FIXME: catch specific errors only (32/broken pipe)
+ pass
+
+ def write_dhcp_file(self):
+ """
+ DHCP files are written when manage_dhcp is set in
+ /var/lib/cobbler/settings.
+ """
+
+ settings_file = self.settings.dhcpd_conf
+ template_file = "/etc/cobbler/dhcp.template"
+ mode = self.settings.manage_dhcp_mode.lower()
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error writing template to file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ # build each per-system definition
+ # as configured, this only works for ISC, patches accepted
+ # from those that care about Itanium. elilo seems to be unmaintained
+ # so additional maintaince in other areas may be required to keep
+ # this working.
+
+ elilo = os.path.basename(self.settings.bootloaders["ia64"])
+
+ system_definitions = {}
+ counter = 0
+
+
+ # Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in
+ # case to avoid conflicts with the hosts we're defining and to clean
+ # possible removed hosts (only if using OMAPI)
+ if self.settings.omapi_enabled and self.settings.omapi_port:
+ if os.path.exists("/var/lib/dhcpd/dhcpd.leases"):
+ file = open('/var/lib/dhcpd/dhcpd.leases')
+ item = shlex(file)
+ while 1:
+ elem = item.get_token()
+ if not elem:
+ break
+ if elem == 'host':
+ hostremove = item.get_token()
+ self.removeDHCPLease(self.settings.omapi_port,hostremove)
+
+ # we used to just loop through each system, but now we must loop
+ # through each network interface of each system.
+
+ for system in self.systems:
+ profile = system.get_conceptual_parent()
+ distro = profile.get_conceptual_parent()
+ for (name, interface) in system.interfaces.iteritems():
+
+ mac = interface["mac_address"]
+ ip = interface["ip_address"]
+ host = interface["hostname"]
+
+ if mac is None or mac == "":
+ # can't write a DHCP entry for this system
+ continue
+
+ counter = counter + 1
+ systxt = ""
+
+
+ # the label the entry after the hostname if possible
+ if host is not None and host != "":
+ systxt = "\nhost %s {\n" % host
+ if self.settings.isc_set_host_name:
+ systxt = systxt + " option host-name = \"%s\";\n" % host
+ else:
+ systxt = "\nhost generic%d {\n" % counter
+
+ if distro.arch == "ia64":
+ # can't use pxelinux.0 anymore
+ systxt = systxt + " filename \"/%s\";\n" % elilo
+ systxt = systxt + " hardware ethernet %s;\n" % mac
+ if ip is not None and ip != "":
+ systxt = systxt + " fixed-address %s;\n" % ip
+ systxt = systxt + "}\n"
+
+ # If we have all values defined and we're using omapi,
+ # we will just create entries dinamically into DHCPD
+ # without requiring a restart (but file will be written
+ # as usual for having it working after restart)
+
+ if ip is not None and ip != "":
+ if mac is not None and mac != "":
+ if host is not None and host != "":
+ if self.settings.omapi_enabled and self.settings.omapi_port:
+ self.removeDHCPLease(self.settings.omapi_port,host)
+ self.writeDHCPLease(self.settings.omapi_port,host,ip,mac)
+
+ dhcp_tag = interface["dhcp_tag"]
+ if dhcp_tag == "":
+ dhcp_tag = "default"
+
+ if not system_definitions.has_key(dhcp_tag):
+ system_definitions[dhcp_tag] = ""
+ system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt
+
+ # we are now done with the looping through each interface of each system
+
+ metadata = {
+ "omapi_enabled" : self.settings.omapi_enabled,
+ "omapi_port" : self.settings.omapi_port,
+ "insert_cobbler_system_definitions" : system_definitions.get("default",""),
+ "date" : time.asctime(time.gmtime()),
+ "cobbler_server" : self.settings.server,
+ "next_server" : self.settings.next_server,
+ "elilo" : elilo
+ }
+
+ # now add in other DHCP expansions that are not tagged with "default"
+ for x in system_definitions.keys():
+ if x == "default":
+ continue
+ metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
+
+ self.templar.render(template_data, metadata, settings_file, None)
+
+ def regen_ethers(self):
+ pass # ISC/BIND do not use this
+
+
+ def regen_hosts(self):
+ pass # ISC/BIND do not use this
+
+
+ def __forward_zones(self):
+ """
+ Returns ALL forward zones for all systems
+ """
+ zones = {}
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ host = interface["hostname"]
+ ip = interface["ip_address"]
+ if not host or not ip:
+ # gotsta have some hostname and ip or else!
+ continue
+ tokens = host.split('.')
+ zone = '.'.join(tokens[1:])
+ if zones.has_key(zone):
+ zones[zone].append((host.split('.')[0], ip))
+ else:
+ zones[zone] = [(host.split('.')[0], ip)]
+ return zones
+
+ def __reverse_zones(self):
+ """
+ Returns ALL reverse zones for all systems
+ """
+ zones = {}
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ host = interface["hostname"]
+ ip = interface["ip_address"]
+ if not host or not ip:
+ # gotsta have some hostname and ip or else!
+ continue
+ tokens = ip.split('.')
+ zone = '.'.join(tokens[0:3])
+ if zones.has_key(zone):
+ zones[zone].append((tokens[3], host + '.'))
+ else:
+ zones[zone] = [(tokens[3], host + '.')]
+ return zones
+
+ def __config_forward_zones(self):
+ """
+ Returns only the forward zones which have systems and are defined
+ in the option manage_forward_zones
+
+ Alternatively if manage_forward_zones is empty, return all systems
+ """
+ all = self.__forward_zones()
+ want = self.settings.manage_forward_zones
+ if want == []: return all
+ ret = {}
+ for zone in all.keys():
+ if zone in want:
+ ret[zone] = all[zone]
+ return ret
+
+ def __config_reverse_zones(self):
+ """
+ Returns only the reverse zones which have systems and are defined
+ in the option manage_reverse_zones
+
+ Alternatively if manage_reverse_zones is empty, return all systems
+ """
+ all = self.__reverse_zones()
+ want = self.settings.manage_reverse_zones
+ if want == []: return all
+ ret = {}
+ for zone in all.keys():
+ if zone in want:
+ ret[zone] = all[zone]
+ return ret
+
+ def __write_named_conf(self):
+ """
+ Write out the named.conf main config file from the template.
+ """
+ settings_file = self.settings.named_conf
+ template_file = "/etc/cobbler/named.template"
+ forward_zones = self.settings.manage_forward_zones
+ reverse_zones = self.settings.manage_reverse_zones
+
+ metadata = {'zone_include': ''}
+ for zone in self.__config_forward_zones().keys():
+ txt = """
+zone "%(zone)s." {
+ type master;
+ file "%(zone)s";
+};
+""" % {'zone': zone}
+ metadata['zone_include'] = metadata['zone_include'] + txt
+
+ for zone in self.__config_reverse_zones().keys():
+ tokens = zone.split('.')
+ tokens.reverse()
+ arpa = '.'.join(tokens) + '.in-addr.arpa'
+ txt = """
+zone "%(arpa)s." {
+ type master;
+ file "%(zone)s";
+};
+""" % {'arpa': arpa, 'zone': zone}
+ metadata['zone_include'] = metadata['zone_include'] + txt
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error reading template from file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ self.templar.render(template_data, metadata, settings_file, None)
+
+ def __write_zone_files(self):
+ """
+ Write out the forward and reverse zone files for all the zones
+ defined in manage_forward_zones and manage_reverse_zones
+ """
+ template_file = "/etc/cobbler/zone.template"
+ cobbler_server = self.settings.server
+ serial = int(time.time())
+ forward = self.__config_forward_zones()
+ reverse = self.__config_reverse_zones()
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error reading template from file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ for (zone, hosts) in forward.iteritems():
+ metadata = {
+ 'cobbler_server': cobbler_server,
+ 'serial': serial,
+ 'host_record': ''
+ }
+
+ for host in hosts:
+ txt = '%s\tIN\tA\t%s\n' % host
+ metadata['host_record'] = metadata['host_record'] + txt
+
+ self.templar.render(template_data, metadata, '/var/named/' + zone, None)
+
+ for (zone, hosts) in reverse.iteritems():
+ metadata = {
+ 'cobbler_server': cobbler_server,
+ 'serial': serial,
+ 'host_record': ''
+ }
+
+ for host in hosts:
+ txt = '%s\tIN\tPTR\t%s\n' % host
+ metadata['host_record'] = metadata['host_record'] + txt
+
+ self.templar.render(template_data, metadata, '/var/named/' + zone, None)
+
+
+ def write_dns_files(self):
+ """
+ BIND files are written when manage_dns is set in
+ /var/lib/cobbler/settings.
+ """
+
+ self.__write_named_conf()
+ self.__write_zone_files()
+
+def get_manager(config):
+ return IscAndBindManager(config)
+
diff --git a/config/modules.conf b/config/modules.conf
index 88aa134..c16385e 100644
--- a/config/modules.conf
+++ b/config/modules.conf
@@ -10,3 +10,8 @@ module = authn_denyall
[authorization]
module = authz_allowall
+
+[manage]
+module = manage_isc_and_bind
+
+
diff --git a/config/settings b/config/settings
index 8b39707..5c4d7fa 100644
--- a/config/settings
+++ b/config/settings
@@ -30,7 +30,6 @@ ldap_search_bind_dn: ''
ldap_search_passwd: ''
ldap_search_prefix: 'uid='
manage_dhcp: 0
-manage_dhcp_mode: isc
manage_dns: 0
next_server: '127.0.0.1'
omapi_enabled: 1
--
cgit
From 6ffd4eca30766153aa920888411f6437948757b2 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 16:38:22 -0400
Subject: Add some missing files and do some more work on dns/dhcp refactoring
---
cobbler/action_check.py | 8 +++++++-
cobbler/action_litesync.py | 4 ++--
cobbler/modules/manage_dnsmasq.py | 5 ++++-
cobbler/modules/manage_isc_and_bind.py | 4 ++--
templates/named.template | 18 ++++++++++++++++++
templates/zone.template | 13 +++++++++++++
6 files changed, 46 insertions(+), 6 deletions(-)
create mode 100644 templates/named.template
create mode 100644 templates/zone.template
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 588a65a..2004c9f 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -48,7 +48,13 @@ class BootCheck:
else:
status.append(_("configured management mode in modules.conf is unknown"))
# FIXME: add in checks for bind config
-
+ if self.settings.manage_dns:
+ mode = self.config.api.get_sync().manager.what()
+ if mode == "isc_and_bind":
+ #self.check_bind_bin(status)
+ #self.check_service(status,"dhcpd")
+ pass
+
self.check_service(status, "cobblerd")
self.check_bootloaders(status)
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index ba0a256..9df99cc 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -117,8 +117,8 @@ class BootLiteSync:
self.sync.manager.write_dhcp_lease(
self.settings.omapi_port,
interface["hostname"],
- interface["mac-address"],
- interface["ip-address"]
+ interface["mac_address"],
+ interface["ip_address"]
)
diff --git a/cobbler/modules/manage_dnsmasq.py b/cobbler/modules/manage_dnsmasq.py
index d37a2d4..465995f 100644
--- a/cobbler/modules/manage_dnsmasq.py
+++ b/cobbler/modules/manage_dnsmasq.py
@@ -55,7 +55,6 @@ class DnsmasqManager:
self.settings = config.settings()
self.repos = config.repos()
self.templar = templar.Templar(config)
- self.dns = dns
def what(self):
return "dnsmasq"
@@ -186,6 +185,10 @@ class DnsmasqManager:
fh.write(ip + "\t" + host + "\n")
fh.close()
+ def write_dns_files(self):
+ # already taken care of by the regen_hosts()
+ pass
+
def get_manager(config):
return DnsmasqManager(config)
diff --git a/cobbler/modules/manage_isc_and_bind.py b/cobbler/modules/manage_isc_and_bind.py
index bc3a338..3927c69 100644
--- a/cobbler/modules/manage_isc_and_bind.py
+++ b/cobbler/modules/manage_isc_and_bind.py
@@ -213,8 +213,8 @@ class IscAndBindManager:
if mac is not None and mac != "":
if host is not None and host != "":
if self.settings.omapi_enabled and self.settings.omapi_port:
- self.removeDHCPLease(self.settings.omapi_port,host)
- self.writeDHCPLease(self.settings.omapi_port,host,ip,mac)
+ self.remove_dhcp_lease(self.settings.omapi_port,host)
+ self.write_dhcp_lease(self.settings.omapi_port,host,ip,mac)
dhcp_tag = interface["dhcp_tag"]
if dhcp_tag == "":
diff --git a/templates/named.template b/templates/named.template
new file mode 100644
index 0000000..f77eadc
--- /dev/null
+++ b/templates/named.template
@@ -0,0 +1,18 @@
+options {
+ listen-on port 53 { 127.0.0.1; };
+ directory "/var/named";
+ dump-file "/var/named/data/cache_dump.db";
+ statistics-file "/var/named/data/named_stats.txt";
+ memstatistics-file "/var/named/data/named_mem_stats.txt";
+ allow-query { localhost; };
+ recursion yes;
+};
+
+logging {
+ channel default_debug {
+ file "data/named.run";
+ severity dynamic;
+ };
+};
+
+$zone_include
diff --git a/templates/zone.template b/templates/zone.template
new file mode 100644
index 0000000..5426f78
--- /dev/null
+++ b/templates/zone.template
@@ -0,0 +1,13 @@
+\$TTL 300
+@ IN SOA $cobbler_server. nobody.example.com. (
+ $serial ; Serial
+ 600 ; Refresh
+ 1800 ; Retry
+ 604800 ; Expire
+ 300 ; TTL
+ )
+
+ IN NS $cobbler_server.
+
+
+$host_record
--
cgit
From 35fd760f0fc069906da78aebf4a1ecb3e2414291 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 16:50:33 -0400
Subject: Added some check code for BIND.
---
cobbler/action_check.py | 16 ++++++++++++----
cobbler/settings.py | 2 ++
config/settings | 2 ++
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 2004c9f..e81e66c 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -51,8 +51,8 @@ class BootCheck:
if self.settings.manage_dns:
mode = self.config.api.get_sync().manager.what()
if mode == "isc_and_bind":
- #self.check_bind_bin(status)
- #self.check_service(status,"dhcpd")
+ self.check_bind_bin(status)
+ self.check_service(status,"named")
pass
self.check_service(status, "cobblerd")
@@ -118,14 +118,22 @@ class BootCheck:
Check if dhcpd is installed
"""
if not os.path.exists(self.settings.dhcpd_bin):
- status.append(_("dhcpd isn't installed, but is enabled in /var/lib/cobbler/settings"))
+ status.append(_("dhcpd isn't installed, but management is enabled in /var/lib/cobbler/settings"))
def check_dnsmasq_bin(self,status):
"""
Check if dnsmasq is installed
"""
if not os.path.exists(self.settings.dnsmasq_bin):
- status.append(_("dnsmasq isn't installed, but is enabled in /var/lib/cobbler/settings"))
+ status.append(_("dnsmasq isn't installed, but management is enabled in /var/lib/cobbler/settings"))
+
+ def check_bind_bin(self,status):
+ """
+ Check if bind is installed.
+ """
+ if not os.path.exists(self.settings.bind_bin):
+ status.append(_("bind isn't installed, but management is enabled in /var/lib/cobbler/settings"))
+
def check_bootloaders(self,status):
"""
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 70b2ac8..bf12545 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -24,6 +24,7 @@ TESTMODE = False
DEFAULTS = {
"allow_duplicate_macs" : 0,
"allow_duplicate_ips" : 0,
+ "bind_bin" : "/usr/sbin/named",
"bootloaders" : {
"standard" : "/usr/lib/syslinux/pxelinux.0",
"ia64" : "/var/lib/cobbler/elilo-3.6-ia64.efi"
@@ -64,6 +65,7 @@ DEFAULTS = {
"next_server" : "127.0.0.1",
"omapi_enabled" : 0,
"omapi_port" : 647,
+ "omshell_bin" : "/usr/bin/omshell",
"pxe_just_once" : 0,
"register_new_installs" : 0,
"run_install_triggers" : 1,
diff --git a/config/settings b/config/settings
index 5c4d7fa..2f6b08d 100644
--- a/config/settings
+++ b/config/settings
@@ -1,6 +1,7 @@
---
allow_duplicate_macs: 0
allow_duplicate_ips: 0
+bind_bin: /usr/sbin/named
bootloaders:
ia64: /var/lib/cobbler/elilo-3.6-ia64.efi
standard: /usr/lib/syslinux/pxelinux.0
@@ -34,6 +35,7 @@ manage_dns: 0
next_server: '127.0.0.1'
omapi_enabled: 1
omapi_port: 647
+omshell_bin: /usr/bin/omshell
pxe_just_once: 0
register_new_installs: 0
run_install_triggers: 1
--
cgit
From ca041e7ed57a4818ed490b9fd9429db20d9d8860 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 2 May 2008 17:31:46 -0400
Subject: Various DNS/DHCP work.
---
cobbler/action_check.py | 16 +-
cobbler/action_litesync.py | 10 +-
cobbler/action_sync.py | 14 +-
cobbler/api.py | 13 +-
cobbler/modules/manage_bind.py | 242 +++++++++++++++++++
cobbler/modules/manage_isc.py | 253 ++++++++++++++++++++
cobbler/modules/manage_isc_and_bind.py | 425 ---------------------------------
config/modules.conf | 7 +-
8 files changed, 529 insertions(+), 451 deletions(-)
create mode 100644 cobbler/modules/manage_bind.py
create mode 100644 cobbler/modules/manage_isc.py
delete mode 100644 cobbler/modules/manage_isc_and_bind.py
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index e81e66c..9fe0543 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -37,23 +37,23 @@ class BootCheck:
status = []
self.check_name(status)
if self.settings.manage_dhcp:
- mode = self.config.api.get_sync().manager.what()
- if mode == "isc_and_bind":
+ mode = self.config.api.get_sync().dhcp.what()
+ if mode == "isc":
self.check_dhcpd_bin(status)
self.check_dhcpd_conf(status)
self.check_service(status,"dhcpd")
elif mode == "dnsmasq":
self.check_dnsmasq_bin(status)
self.check_service(status,"dnsmasq")
- else:
- status.append(_("configured management mode in modules.conf is unknown"))
- # FIXME: add in checks for bind config
+
if self.settings.manage_dns:
- mode = self.config.api.get_sync().manager.what()
- if mode == "isc_and_bind":
+ mode = self.config.api.get_sync().dns.what()
+ if mode == "bind":
self.check_bind_bin(status)
self.check_service(status,"named")
- pass
+ elif mode == "dnsmasq" and not self.settings.manage_dhcp:
+ self.check_dnsmasq_bin(status)
+ self.check_service(status,"dnsmasq")
self.check_service(status, "cobblerd")
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index 9df99cc..ba3e3ee 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -105,8 +105,10 @@ class BootLiteSync:
if system is None:
raise CX(_("error in system lookup for %s") % name)
# rebuild system_list file in webdir
- self.sync.manager.regen_ethers()
- self.sync.manager.regen_hosts()
+ if self.settings.manage_dhcp:
+ self.sync.dns.regen_ethers()
+ if self.settings.manage_dns:
+ self.sync.dhcp.regen_hosts()
# write the PXE files for the system
self.sync.pxegen.write_all_system_files(system)
# per system kickstarts
@@ -114,7 +116,7 @@ class BootLiteSync:
if self.settings.manage_dhcp:
if self.settings.omapi_enabled:
for (name,interface) in system.interfaces.iteritems():
- self.sync.manager.write_dhcp_lease(
+ self.sync.dhcp.write_dhcp_lease(
self.settings.omapi_port,
interface["hostname"],
interface["mac_address"],
@@ -135,7 +137,7 @@ class BootLiteSync:
if self.settings.manage_dhcp:
if self.settings.omapi_enabled:
for (name,interface) in system_record.interfaces.iteritems():
- self.sync.manager.remove_dhcp_lease(
+ self.sync.dhcp.remove_dhcp_lease(
self.settings.omapi_port,
interface["hostname"]
)
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index fbc9402..55cdad5 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -28,7 +28,6 @@ import utils
from cexceptions import *
import templar
import pxegen
-import manage_ctrl
import yumgen
import item_distro
@@ -46,7 +45,7 @@ class BootSync:
Handles conversion of internal state to the tftpboot tree layout
"""
- def __init__(self,config,verbose=False,manage=None):
+ def __init__(self,config,verbose=False,dhcp=None,dns=None):
"""
Constructor
"""
@@ -60,7 +59,8 @@ class BootSync:
self.repos = config.repos()
self.templar = templar.Templar(config)
self.pxegen = pxegen.PXEGen(config)
- self.manager = manage
+ self.dns = dns
+ self.dhcp = dhcp
self.yumgen = yumgen.YumGen(config)
self.bootloc = utils.tftpboot_location()
@@ -93,11 +93,11 @@ class BootSync:
self.pxegen.write_all_system_files(x)
self.yumgen.retemplate_all_yum_repos()
if self.settings.manage_dhcp:
- self.manager.write_dhcp_file()
- self.manager.regen_ethers()
- self.manager.regen_hosts()
+ self.dhcp.write_dhcp_file()
+ self.dhcp.regen_ethers()
if self.settings.manage_dns:
- self.manager.write_dns_files()
+ self.dns.regen_hosts()
+ self.dns.write_dns_files()
self.pxegen.make_pxe_menu()
# run post-triggers
diff --git a/cobbler/api.py b/cobbler/api.py
index 1f5a246..20c7364 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -336,12 +336,17 @@ class BootAPI:
return sync.run()
def get_sync(self):
- self.manage = self.get_module_from_file(
- "management",
+ self.dhcp = self.get_module_from_file(
+ "dhcp",
"module",
- "manage_isc_and_bind"
+ "manage_isc"
).get_manager(self._config)
- return action_sync.BootSync(self._config,manage=self.manage)
+ self.dns = self.get_module_from_file(
+ "dns",
+ "module",
+ "manage_bind"
+ ).get_manager(self._config)
+ return action_sync.BootSync(self._config,dhcp=self.dhcp,dns=self.dns)
def reposync(self, name=None):
"""
diff --git a/cobbler/modules/manage_bind.py b/cobbler/modules/manage_bind.py
new file mode 100644
index 0000000..900a832
--- /dev/null
+++ b/cobbler/modules/manage_bind.py
@@ -0,0 +1,242 @@
+"""
+This is some of the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+John Eckersberg
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+import popen2
+from shlex import shlex
+
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "manage"
+
+
+class BindManager:
+
+ def what(self):
+ return "isc_and_bind"
+
+ def __init__(self,config,verbose=False):
+ """
+ Constructor
+ """
+ self.verbose = verbose
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+
+ def regen_hosts(self):
+ pass # not used
+
+ def __forward_zones(self):
+ """
+ Returns ALL forward zones for all systems
+ """
+ zones = {}
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ host = interface["hostname"]
+ ip = interface["ip_address"]
+ if not host or not ip:
+ # gotsta have some hostname and ip or else!
+ continue
+ if host.find(".") == -1:
+ continue
+ tokens = host.split('.')
+ zone = '.'.join(tokens[1:])
+ if zones.has_key(zone):
+ zones[zone].append((host.split('.')[0], ip))
+ else:
+ zones[zone] = [(host.split('.')[0], ip)]
+ return zones
+
+ def __reverse_zones(self):
+ """
+ Returns ALL reverse zones for all systems
+ """
+ zones = {}
+ for sys in self.systems:
+ for (name, interface) in sys.interfaces.iteritems():
+ host = interface["hostname"]
+ ip = interface["ip_address"]
+ if not host or not ip:
+ # gotsta have some hostname and ip or else!
+ continue
+ tokens = ip.split('.')
+ zone = '.'.join(tokens[0:3])
+ if zones.has_key(zone):
+ zones[zone].append((tokens[3], host + '.'))
+ else:
+ zones[zone] = [(tokens[3], host + '.')]
+ return zones
+
+ def __config_forward_zones(self):
+ """
+ Returns only the forward zones which have systems and are defined
+ in the option manage_forward_zones
+
+ Alternatively if manage_forward_zones is empty, return all systems
+ """
+ all = self.__forward_zones()
+ want = self.settings.manage_forward_zones
+ if want == []: return all
+ ret = {}
+ for zone in all.keys():
+ if zone in want:
+ ret[zone] = all[zone]
+ return ret
+
+ def __config_reverse_zones(self):
+ """
+ Returns only the reverse zones which have systems and are defined
+ in the option manage_reverse_zones
+
+ Alternatively if manage_reverse_zones is empty, return all systems
+ """
+ all = self.__reverse_zones()
+ want = self.settings.manage_reverse_zones
+ if want == []: return all
+ ret = {}
+ for zone in all.keys():
+ if zone in want:
+ ret[zone] = all[zone]
+ return ret
+
+ def __write_named_conf(self):
+ """
+ Write out the named.conf main config file from the template.
+ """
+ settings_file = self.settings.named_conf
+ template_file = "/etc/cobbler/named.template"
+ forward_zones = self.settings.manage_forward_zones
+ reverse_zones = self.settings.manage_reverse_zones
+
+ metadata = {'zone_include': ''}
+ for zone in self.__config_forward_zones().keys():
+ txt = """
+zone "%(zone)s." {
+ type master;
+ file "%(zone)s";
+};
+""" % {'zone': zone}
+ metadata['zone_include'] = metadata['zone_include'] + txt
+
+ for zone in self.__config_reverse_zones().keys():
+ tokens = zone.split('.')
+ tokens.reverse()
+ arpa = '.'.join(tokens) + '.in-addr.arpa'
+ txt = """
+zone "%(arpa)s." {
+ type master;
+ file "%(zone)s";
+};
+""" % {'arpa': arpa, 'zone': zone}
+ metadata['zone_include'] = metadata['zone_include'] + txt
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error reading template from file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ self.templar.render(template_data, metadata, settings_file, None)
+
+ def __write_zone_files(self):
+ """
+ Write out the forward and reverse zone files for all the zones
+ defined in manage_forward_zones and manage_reverse_zones
+ """
+ template_file = "/etc/cobbler/zone.template"
+ cobbler_server = self.settings.server
+ serial = int(time.time())
+ forward = self.__config_forward_zones()
+ reverse = self.__config_reverse_zones()
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error reading template from file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ for (zone, hosts) in forward.iteritems():
+ metadata = {
+ 'cobbler_server': cobbler_server,
+ 'serial': serial,
+ 'host_record': ''
+ }
+
+ for host in hosts:
+ txt = '%s\tIN\tA\t%s\n' % host
+ metadata['host_record'] = metadata['host_record'] + txt
+
+ self.templar.render(template_data, metadata, '/var/named/' + zone, None)
+
+ for (zone, hosts) in reverse.iteritems():
+ metadata = {
+ 'cobbler_server': cobbler_server,
+ 'serial': serial,
+ 'host_record': ''
+ }
+
+ for host in hosts:
+ txt = '%s\tIN\tPTR\t%s\n' % host
+ metadata['host_record'] = metadata['host_record'] + txt
+
+ self.templar.render(template_data, metadata, '/var/named/' + zone, None)
+
+
+ def write_dns_files(self):
+ """
+ BIND files are written when manage_dns is set in
+ /var/lib/cobbler/settings.
+ """
+
+ self.__write_named_conf()
+ self.__write_zone_files()
+
+def get_manager(config):
+ return BindManager(config)
+
diff --git a/cobbler/modules/manage_isc.py b/cobbler/modules/manage_isc.py
new file mode 100644
index 0000000..bc88412
--- /dev/null
+++ b/cobbler/modules/manage_isc.py
@@ -0,0 +1,253 @@
+"""
+This is some of the code behind 'cobbler sync'.
+
+Copyright 2006-2008, Red Hat, Inc
+Michael DeHaan
+John Eckersberg
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import shutil
+import time
+import sub_process
+import sys
+import glob
+import traceback
+import errno
+import popen2
+from shlex import shlex
+
+
+import utils
+from cexceptions import *
+import templar
+
+import item_distro
+import item_profile
+import item_repo
+import item_system
+
+from utils import _
+
+
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "manage"
+
+
+class IscManager:
+
+ def what(self):
+ return "isc_and_bind"
+
+ def __init__(self,config,verbose=False):
+ """
+ Constructor
+ """
+ self.verbose = verbose
+ self.config = config
+ self.api = config.api
+ self.distros = config.distros()
+ self.profiles = config.profiles()
+ self.systems = config.systems()
+ self.settings = config.settings()
+ self.repos = config.repos()
+ self.templar = templar.Templar(config)
+
+ def write_dhcp_lease(self,port,host,ip,mac):
+ """
+ Use DHCP's API to create a DHCP entry in the
+ /var/lib/dhcpd/dhcpd.leases file
+ #Code from http://svn.osgdc.org/browse/kusu/kusu
+ # /trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025
+ # FIXME: should use subprocess
+ """
+ try:
+ fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("set ip-address = %s\n" % ip)
+ tochild.flush()
+ tochild.write("set hardware-address = %s\n" % mac)
+ tochild.flush()
+ tochild.write("set hardware-type = 1\n")
+ tochild.flush()
+ tochild.write("create\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+ except IOError:
+ # FIXME: just catch 32 (broken pipe) and show a warning
+ pass
+
+ def remove_dhcp_lease(self,port,host):
+ """
+ removeDHCPLease(port,host)
+ Use DHCP's API to delete a DHCP entry in
+ the /var/lib/dhcpd/dhcpd.leases file
+ """
+ fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ try:
+ tochild.write("port %s\n" % port)
+ tochild.flush()
+ tochild.write("connect\n")
+ tochild.flush()
+ tochild.write("new host\n")
+ tochild.flush()
+ tochild.write('set name = \"%s\"\n' % host)
+ tochild.flush()
+ tochild.write("open\n") # opens register with host information
+ tochild.flush()
+ tochild.write("remove\n")
+ tochild.flush()
+ tochild.close()
+ fromchild.close()
+ except IOError:
+ # FIXME: convert this to subprocess.
+ # FIXME: catch specific errors only (32/broken pipe)
+ pass
+
+ def write_dhcp_file(self):
+ """
+ DHCP files are written when manage_dhcp is set in
+ /var/lib/cobbler/settings.
+ """
+
+ settings_file = self.settings.dhcpd_conf
+ template_file = "/etc/cobbler/dhcp.template"
+ mode = self.settings.manage_dhcp_mode.lower()
+
+ try:
+ f2 = open(template_file,"r")
+ except:
+ raise CX(_("error writing template to file: %s") % template_file)
+ template_data = ""
+ template_data = f2.read()
+ f2.close()
+
+ # build each per-system definition
+ # as configured, this only works for ISC, patches accepted
+ # from those that care about Itanium. elilo seems to be unmaintained
+ # so additional maintaince in other areas may be required to keep
+ # this working.
+
+ elilo = os.path.basename(self.settings.bootloaders["ia64"])
+
+ system_definitions = {}
+ counter = 0
+
+
+ # Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in
+ # case to avoid conflicts with the hosts we're defining and to clean
+ # possible removed hosts (only if using OMAPI)
+ if self.settings.omapi_enabled and self.settings.omapi_port:
+ if os.path.exists("/var/lib/dhcpd/dhcpd.leases"):
+ file = open('/var/lib/dhcpd/dhcpd.leases')
+ item = shlex(file)
+ while 1:
+ elem = item.get_token()
+ if not elem:
+ break
+ if elem == 'host':
+ hostremove = item.get_token()
+ self.removeDHCPLease(self.settings.omapi_port,hostremove)
+
+ # we used to just loop through each system, but now we must loop
+ # through each network interface of each system.
+
+ for system in self.systems:
+ profile = system.get_conceptual_parent()
+ distro = profile.get_conceptual_parent()
+ for (name, interface) in system.interfaces.iteritems():
+
+ mac = interface["mac_address"]
+ ip = interface["ip_address"]
+ host = interface["hostname"]
+
+ if mac is None or mac == "":
+ # can't write a DHCP entry for this system
+ continue
+
+ counter = counter + 1
+ systxt = ""
+
+
+ # the label the entry after the hostname if possible
+ if host is not None and host != "":
+ systxt = "\nhost %s {\n" % host
+ if self.settings.isc_set_host_name:
+ systxt = systxt + " option host-name = \"%s\";\n" % host
+ else:
+ systxt = "\nhost generic%d {\n" % counter
+
+ if distro.arch == "ia64":
+ # can't use pxelinux.0 anymore
+ systxt = systxt + " filename \"/%s\";\n" % elilo
+ systxt = systxt + " hardware ethernet %s;\n" % mac
+ if ip is not None and ip != "":
+ systxt = systxt + " fixed-address %s;\n" % ip
+ systxt = systxt + "}\n"
+
+ # If we have all values defined and we're using omapi,
+ # we will just create entries dinamically into DHCPD
+ # without requiring a restart (but file will be written
+ # as usual for having it working after restart)
+
+ if ip is not None and ip != "":
+ if mac is not None and mac != "":
+ if host is not None and host != "":
+ if self.settings.omapi_enabled and self.settings.omapi_port:
+ self.remove_dhcp_lease(self.settings.omapi_port,host)
+ self.write_dhcp_lease(self.settings.omapi_port,host,ip,mac)
+
+ dhcp_tag = interface["dhcp_tag"]
+ if dhcp_tag == "":
+ dhcp_tag = "default"
+
+ if not system_definitions.has_key(dhcp_tag):
+ system_definitions[dhcp_tag] = ""
+ system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt
+
+ # we are now done with the looping through each interface of each system
+
+ metadata = {
+ "omapi_enabled" : self.settings.omapi_enabled,
+ "omapi_port" : self.settings.omapi_port,
+ "insert_cobbler_system_definitions" : system_definitions.get("default",""),
+ "date" : time.asctime(time.gmtime()),
+ "cobbler_server" : self.settings.server,
+ "next_server" : self.settings.next_server,
+ "elilo" : elilo
+ }
+
+ # now add in other DHCP expansions that are not tagged with "default"
+ for x in system_definitions.keys():
+ if x == "default":
+ continue
+ metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
+
+ self.templar.render(template_data, metadata, settings_file, None)
+
+ def regen_ethers(self):
+ pass # ISC/BIND do not use this
+
+
+def get_manager(config):
+ return IscManager(config)
+
diff --git a/cobbler/modules/manage_isc_and_bind.py b/cobbler/modules/manage_isc_and_bind.py
deleted file mode 100644
index 3927c69..0000000
--- a/cobbler/modules/manage_isc_and_bind.py
+++ /dev/null
@@ -1,425 +0,0 @@
-"""
-This is some of the code behind 'cobbler sync'.
-
-Copyright 2006-2008, Red Hat, Inc
-Michael DeHaan
-John Eckersberg
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-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., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-import os
-import os.path
-import shutil
-import time
-import sub_process
-import sys
-import glob
-import traceback
-import errno
-import popen2
-from shlex import shlex
-
-
-import utils
-from cexceptions import *
-import templar
-
-import item_distro
-import item_profile
-import item_repo
-import item_system
-
-from utils import _
-
-
-def register():
- """
- The mandatory cobbler module registration hook.
- """
- return "manage"
-
-
-class IscAndBindManager:
-
- def what(self):
- return "isc_and_bind"
-
- def __init__(self,config,verbose=False):
- """
- Constructor
- """
- self.verbose = verbose
- self.config = config
- self.api = config.api
- self.distros = config.distros()
- self.profiles = config.profiles()
- self.systems = config.systems()
- self.settings = config.settings()
- self.repos = config.repos()
- self.templar = templar.Templar(config)
-
- def write_dhcp_lease(self,port,host,ip,mac):
- """
- Use DHCP's API to create a DHCP entry in the
- /var/lib/dhcpd/dhcpd.leases file
- #Code from http://svn.osgdc.org/browse/kusu/kusu
- # /trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025
- # FIXME: should use subprocess
- """
- try:
- fromchild, tochild = popen2.popen2("/usr/bin/omshell")
- tochild.write("port %s\n" % port)
- tochild.flush()
- tochild.write("connect\n")
- tochild.flush()
- tochild.write("new host\n")
- tochild.flush()
- tochild.write('set name = \"%s\"\n' % host)
- tochild.flush()
- tochild.write("set ip-address = %s\n" % ip)
- tochild.flush()
- tochild.write("set hardware-address = %s\n" % mac)
- tochild.flush()
- tochild.write("set hardware-type = 1\n")
- tochild.flush()
- tochild.write("create\n")
- tochild.flush()
- tochild.close()
- fromchild.close()
- except IOError:
- # FIXME: just catch 32 (broken pipe) and show a warning
- pass
-
- def remove_dhcp_lease(self,port,host):
- """
- removeDHCPLease(port,host)
- Use DHCP's API to delete a DHCP entry in
- the /var/lib/dhcpd/dhcpd.leases file
- """
- fromchild, tochild = popen2.popen2("/usr/bin/omshell")
- try:
- tochild.write("port %s\n" % port)
- tochild.flush()
- tochild.write("connect\n")
- tochild.flush()
- tochild.write("new host\n")
- tochild.flush()
- tochild.write('set name = \"%s\"\n' % host)
- tochild.flush()
- tochild.write("open\n") # opens register with host information
- tochild.flush()
- tochild.write("remove\n")
- tochild.flush()
- tochild.close()
- fromchild.close()
- except IOError:
- # FIXME: convert this to subprocess.
- # FIXME: catch specific errors only (32/broken pipe)
- pass
-
- def write_dhcp_file(self):
- """
- DHCP files are written when manage_dhcp is set in
- /var/lib/cobbler/settings.
- """
-
- settings_file = self.settings.dhcpd_conf
- template_file = "/etc/cobbler/dhcp.template"
- mode = self.settings.manage_dhcp_mode.lower()
-
- try:
- f2 = open(template_file,"r")
- except:
- raise CX(_("error writing template to file: %s") % template_file)
- template_data = ""
- template_data = f2.read()
- f2.close()
-
- # build each per-system definition
- # as configured, this only works for ISC, patches accepted
- # from those that care about Itanium. elilo seems to be unmaintained
- # so additional maintaince in other areas may be required to keep
- # this working.
-
- elilo = os.path.basename(self.settings.bootloaders["ia64"])
-
- system_definitions = {}
- counter = 0
-
-
- # Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in
- # case to avoid conflicts with the hosts we're defining and to clean
- # possible removed hosts (only if using OMAPI)
- if self.settings.omapi_enabled and self.settings.omapi_port:
- if os.path.exists("/var/lib/dhcpd/dhcpd.leases"):
- file = open('/var/lib/dhcpd/dhcpd.leases')
- item = shlex(file)
- while 1:
- elem = item.get_token()
- if not elem:
- break
- if elem == 'host':
- hostremove = item.get_token()
- self.removeDHCPLease(self.settings.omapi_port,hostremove)
-
- # we used to just loop through each system, but now we must loop
- # through each network interface of each system.
-
- for system in self.systems:
- profile = system.get_conceptual_parent()
- distro = profile.get_conceptual_parent()
- for (name, interface) in system.interfaces.iteritems():
-
- mac = interface["mac_address"]
- ip = interface["ip_address"]
- host = interface["hostname"]
-
- if mac is None or mac == "":
- # can't write a DHCP entry for this system
- continue
-
- counter = counter + 1
- systxt = ""
-
-
- # the label the entry after the hostname if possible
- if host is not None and host != "":
- systxt = "\nhost %s {\n" % host
- if self.settings.isc_set_host_name:
- systxt = systxt + " option host-name = \"%s\";\n" % host
- else:
- systxt = "\nhost generic%d {\n" % counter
-
- if distro.arch == "ia64":
- # can't use pxelinux.0 anymore
- systxt = systxt + " filename \"/%s\";\n" % elilo
- systxt = systxt + " hardware ethernet %s;\n" % mac
- if ip is not None and ip != "":
- systxt = systxt + " fixed-address %s;\n" % ip
- systxt = systxt + "}\n"
-
- # If we have all values defined and we're using omapi,
- # we will just create entries dinamically into DHCPD
- # without requiring a restart (but file will be written
- # as usual for having it working after restart)
-
- if ip is not None and ip != "":
- if mac is not None and mac != "":
- if host is not None and host != "":
- if self.settings.omapi_enabled and self.settings.omapi_port:
- self.remove_dhcp_lease(self.settings.omapi_port,host)
- self.write_dhcp_lease(self.settings.omapi_port,host,ip,mac)
-
- dhcp_tag = interface["dhcp_tag"]
- if dhcp_tag == "":
- dhcp_tag = "default"
-
- if not system_definitions.has_key(dhcp_tag):
- system_definitions[dhcp_tag] = ""
- system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt
-
- # we are now done with the looping through each interface of each system
-
- metadata = {
- "omapi_enabled" : self.settings.omapi_enabled,
- "omapi_port" : self.settings.omapi_port,
- "insert_cobbler_system_definitions" : system_definitions.get("default",""),
- "date" : time.asctime(time.gmtime()),
- "cobbler_server" : self.settings.server,
- "next_server" : self.settings.next_server,
- "elilo" : elilo
- }
-
- # now add in other DHCP expansions that are not tagged with "default"
- for x in system_definitions.keys():
- if x == "default":
- continue
- metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x]
-
- self.templar.render(template_data, metadata, settings_file, None)
-
- def regen_ethers(self):
- pass # ISC/BIND do not use this
-
-
- def regen_hosts(self):
- pass # ISC/BIND do not use this
-
-
- def __forward_zones(self):
- """
- Returns ALL forward zones for all systems
- """
- zones = {}
- for sys in self.systems:
- for (name, interface) in sys.interfaces.iteritems():
- host = interface["hostname"]
- ip = interface["ip_address"]
- if not host or not ip:
- # gotsta have some hostname and ip or else!
- continue
- tokens = host.split('.')
- zone = '.'.join(tokens[1:])
- if zones.has_key(zone):
- zones[zone].append((host.split('.')[0], ip))
- else:
- zones[zone] = [(host.split('.')[0], ip)]
- return zones
-
- def __reverse_zones(self):
- """
- Returns ALL reverse zones for all systems
- """
- zones = {}
- for sys in self.systems:
- for (name, interface) in sys.interfaces.iteritems():
- host = interface["hostname"]
- ip = interface["ip_address"]
- if not host or not ip:
- # gotsta have some hostname and ip or else!
- continue
- tokens = ip.split('.')
- zone = '.'.join(tokens[0:3])
- if zones.has_key(zone):
- zones[zone].append((tokens[3], host + '.'))
- else:
- zones[zone] = [(tokens[3], host + '.')]
- return zones
-
- def __config_forward_zones(self):
- """
- Returns only the forward zones which have systems and are defined
- in the option manage_forward_zones
-
- Alternatively if manage_forward_zones is empty, return all systems
- """
- all = self.__forward_zones()
- want = self.settings.manage_forward_zones
- if want == []: return all
- ret = {}
- for zone in all.keys():
- if zone in want:
- ret[zone] = all[zone]
- return ret
-
- def __config_reverse_zones(self):
- """
- Returns only the reverse zones which have systems and are defined
- in the option manage_reverse_zones
-
- Alternatively if manage_reverse_zones is empty, return all systems
- """
- all = self.__reverse_zones()
- want = self.settings.manage_reverse_zones
- if want == []: return all
- ret = {}
- for zone in all.keys():
- if zone in want:
- ret[zone] = all[zone]
- return ret
-
- def __write_named_conf(self):
- """
- Write out the named.conf main config file from the template.
- """
- settings_file = self.settings.named_conf
- template_file = "/etc/cobbler/named.template"
- forward_zones = self.settings.manage_forward_zones
- reverse_zones = self.settings.manage_reverse_zones
-
- metadata = {'zone_include': ''}
- for zone in self.__config_forward_zones().keys():
- txt = """
-zone "%(zone)s." {
- type master;
- file "%(zone)s";
-};
-""" % {'zone': zone}
- metadata['zone_include'] = metadata['zone_include'] + txt
-
- for zone in self.__config_reverse_zones().keys():
- tokens = zone.split('.')
- tokens.reverse()
- arpa = '.'.join(tokens) + '.in-addr.arpa'
- txt = """
-zone "%(arpa)s." {
- type master;
- file "%(zone)s";
-};
-""" % {'arpa': arpa, 'zone': zone}
- metadata['zone_include'] = metadata['zone_include'] + txt
-
- try:
- f2 = open(template_file,"r")
- except:
- raise CX(_("error reading template from file: %s") % template_file)
- template_data = ""
- template_data = f2.read()
- f2.close()
-
- self.templar.render(template_data, metadata, settings_file, None)
-
- def __write_zone_files(self):
- """
- Write out the forward and reverse zone files for all the zones
- defined in manage_forward_zones and manage_reverse_zones
- """
- template_file = "/etc/cobbler/zone.template"
- cobbler_server = self.settings.server
- serial = int(time.time())
- forward = self.__config_forward_zones()
- reverse = self.__config_reverse_zones()
-
- try:
- f2 = open(template_file,"r")
- except:
- raise CX(_("error reading template from file: %s") % template_file)
- template_data = ""
- template_data = f2.read()
- f2.close()
-
- for (zone, hosts) in forward.iteritems():
- metadata = {
- 'cobbler_server': cobbler_server,
- 'serial': serial,
- 'host_record': ''
- }
-
- for host in hosts:
- txt = '%s\tIN\tA\t%s\n' % host
- metadata['host_record'] = metadata['host_record'] + txt
-
- self.templar.render(template_data, metadata, '/var/named/' + zone, None)
-
- for (zone, hosts) in reverse.iteritems():
- metadata = {
- 'cobbler_server': cobbler_server,
- 'serial': serial,
- 'host_record': ''
- }
-
- for host in hosts:
- txt = '%s\tIN\tPTR\t%s\n' % host
- metadata['host_record'] = metadata['host_record'] + txt
-
- self.templar.render(template_data, metadata, '/var/named/' + zone, None)
-
-
- def write_dns_files(self):
- """
- BIND files are written when manage_dns is set in
- /var/lib/cobbler/settings.
- """
-
- self.__write_named_conf()
- self.__write_zone_files()
-
-def get_manager(config):
- return IscAndBindManager(config)
-
diff --git a/config/modules.conf b/config/modules.conf
index c16385e..8e6b8be 100644
--- a/config/modules.conf
+++ b/config/modules.conf
@@ -11,7 +11,8 @@ module = authn_denyall
[authorization]
module = authz_allowall
-[manage]
-module = manage_isc_and_bind
-
+[dns]
+module = manage_isc
+[dhcp]
+module = manage_bind
--
cgit
From 110e28b4296e7118c3a6886afdcb6542c85ef54c Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 12:11:14 -0400
Subject: Website cleanup, add link to other et projects, remove some code we
no longer need, consolidate docs on FPO for stuff that frequently changes.
---
website/new/about.html | 11 +-
website/new/cobbler-dhcp.php | 44 --------
website/new/cobbler-import.php | 44 --------
website/new/cobbler-manpage.php | 44 --------
website/new/cobbler-repos.php | 44 --------
website/new/communicate.html | 27 -----
website/new/communicate.php | 48 ---------
website/new/css/style.css | 2 +-
website/new/download.html | 2 +-
website/new/faq.html | 66 ------------
website/new/faq.php | 48 ---------
website/new/feed.php | 31 ------
website/new/footer.html | 9 +-
website/new/koan-manpage.php | 44 --------
website/new/nav.php | 41 +-------
website/new/news-feed.php | 0
website/new/news.html | 1 -
website/new/rss-aggregator.php | 73 -------------
website/new/rss-parser.php | 221 ----------------------------------------
19 files changed, 13 insertions(+), 787 deletions(-)
delete mode 100755 website/new/cobbler-dhcp.php
delete mode 100755 website/new/cobbler-import.php
delete mode 100755 website/new/cobbler-manpage.php
delete mode 100755 website/new/cobbler-repos.php
delete mode 100644 website/new/communicate.html
delete mode 100755 website/new/communicate.php
delete mode 100644 website/new/faq.html
delete mode 100755 website/new/faq.php
delete mode 100755 website/new/feed.php
delete mode 100755 website/new/koan-manpage.php
delete mode 100644 website/new/news-feed.php
delete mode 100644 website/new/news.html
delete mode 100755 website/new/rss-aggregator.php
delete mode 100755 website/new/rss-parser.php
diff --git a/website/new/about.html b/website/new/about.html
index 2d8370a..b9dfc1a 100644
--- a/website/new/about.html
+++ b/website/new/about.html
@@ -1,12 +1,15 @@
About Cobbler
-
Cobbler is a Linux boot server that allows for rapid setup of network installation environments. With a simple series of commands, network installs can be configured for PXE, reinstallations, and virtualized installs using Xen or KVM. Cobbler uses a helper program called 'Koan' (which interacts with Cobbler) for reinstallation and virtualization support.
+
Cobbler is a Linux provisioning server that allows for rapid setup of network installation environments. With a simple series of commands, network installs can be configured for PXE, reinstallations, and virtualized installs using Xen or KVM. Cobbler uses a helper program called 'Koan' (which interacts with Cobbler) for reinstallation and virtualization support.
-
Setting up Cobbler is simple. Installation trees can be imported directly from media you already have (or copied from a mirror location), and turned into network install sources within minutes. RHEL, Fedora, and Centos are all supported for both the boot server and installation targets.
+
Setting up a new Cobbler server is trivial as Cobbler eliminates much of the complexity of configuring the underlying install components. Simply install cobbler via yum, import media you may already have from mirrors or DVD ISOs, and start adding new records into cobbler using the command line or web interface. Extensive documentation is provided on the Cobbler Wiki.
-
Cobbler can, if desired, also assist in managing of DHCP infrastructure for provisioned systems (using ISC dhcp or dnsmasq), mirroring install trees, templating kickstart files, automatically creating PXE menus, and locally mirroring repositories used by systems on your network. Lots of additional information on advanced features can be found on the Cobbler Wiki.
+
When creating deployment infrastructure, many components must be dealt with. Cobbler glues together all of these diverse components and makes them easy to manage. As low-level bringup often involves adding records to DHCP and DNS, cobbler "system add" commands can (optionally) be configured to help manage DHCP and DNS using templates. For static IP networks, cobbler still provides solid deployment solutions, including the ability to build DVD network install CDs and reinstall existing Linux systems via the koan command line.
-
In short, Cobbler helps build and maintain network installation infrastructure really easily. It's highly customizable to your particular methods of operation through a wide variety of options, a pluggable extension mechanism, and (for developers) its own Python API. Cobbler lets administrators forget how software gets installed and delivered and lets them concentrate instead on what they want to install where.
+
Cobbler also contains a very powerful kickstart templating system that can help you manage all of the differences in the answer files that drive your automated deployments. Additionally, Cobbler can help mirror packages via yum and rsync, and associate those local mirrors with profiles in cobbler, so they are available to all installed systems.
+
+
In short, Cobbler helps build and maintain network installation infrastructure really easily. It's highly customizable to your particular methods of operation through a wide variety of options, a powerful command line, a Web interface, a pluggable extension mechanism, and (for developers) its own Python API. Cobbler lets administrators forget how software gets installed and delivered and lets them concentrate instead on what they want to install where.
Whether you run a large datacenter, a campus lab, or just have a handfull of machines on a home network, cobbler can help you perform installations and updates faster.
Send comments, questions, patches, and suggestions to the et-mgmt-tools mailing list. You can send mail even if you aren't a list member. This is a community project, so if you feel like contributing, download the source, check it out, and join the list.
If no one seems to be responding to your requests in IRC, feel free to ask your questions on the mailing list. (It's quite common for IRC users to 'idle' their nicks in a channel so they can catch up on any conversation they missed later on.)
-
Note: irc.freenode.net has an IRC 'nick' (nickname, the name you go by in chat) registration system. Some irc.freenode.net channels require that you identify with the server every time you log in. This identification is also required for private messages on the network (no, they're not ignoring you; you probably just haven't identified with the registration system!) For more information, please consult the Freenode Frequently-Asked Questions page on user registration.
-
-
User Submitted Content
-
-As mentioned in the documentation section, Cobbler has a Wiki for user submitted content.
-
-
Bugs/Features
-
-Bugs and Features for all distributions can be filed on the Cobbler and Koan Trac pages. Cobbler and koan also have bugzilla components if you are using Fedora and prefer to post items there. Regardless, the mailing list and the IRC channel are very active -- so if you need help, you do not need to file a bug report unless you want to do so.
-
-
-
-
diff --git a/website/new/communicate.php b/website/new/communicate.php
deleted file mode 100755
index 59af7ae..0000000
--- a/website/new/communicate.php
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-Cobbler
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Communicate
-
-
-
-
-
-
-
-
-
diff --git a/website/new/css/style.css b/website/new/css/style.css
index b02cb02..d3bfe13 100644
--- a/website/new/css/style.css
+++ b/website/new/css/style.css
@@ -183,7 +183,7 @@ tt {
border: 0px;
width: 100%;
background: #757575;
- height: 180px;
+ height: 290px;
}
/* This is hidden from IE <= 6 because it can't do transparency */
diff --git a/website/new/download.html b/website/new/download.html
index 977fb1b..ddf3978 100644
--- a/website/new/download.html
+++ b/website/new/download.html
@@ -1,4 +1,4 @@
-
Cobbler is in use in a lot of diverse configurations. Large companies, hosting datacenters, college labs, consultants, ISVs, developers, and home Linux users all use cobbler and koan in different ways. It is intended to cover the large configurations just as easily as the smaller ones -- and be non-complex for all classes of users.
-
- Back to top
-
-Cobbler runs on RHEL 4 and later, Fedora 5 and later, and Centos 4 and later. Koan, cobbler's helper program, also works with RHEL 3.
-
- Back to top
-
Cobbler's helper program koan can be used on the target system to reinstall it's operating system with another operating system. This solution is ideal for those users who can not take advantage of PXE due to hardware, network, or policy constraints. For more information, see the koan manpage documentation.
-
- Back to top
-
Cobbler's helper program, koan, when invoked on the remote host system, pulls down information from the remote cobbler server to begin a fully automated installation of a virtual guest. This works out of the box for any distribution that contains a Xen kernel. For more information, see the koan manpage documentation.
-
- Back to top
-
-When the administrator on the Cobbler server runs Cobbler commands, cobbler updates a configuration tree, which is stored in /var/lib/cobbler. Data from this configuration database is used to update various entities on the target operating system. Cobbler will restart services, as well as create trees of files in /tftpboot and /var/www/cobbler -- for use with PXE and koan, respectively.
-
-Koan interacts with cobbler by retrieving data over XMLRPC. Cobbler serves up XMLRPC using "cobblerd", which also has the dual purpose of logging syslog data from kickstart -- which is used in Cobbler's kickstart tracking feature. For a better understanding of how this works, see the Cobbler manpage documentation.
-Back to top
-
-Send in bug reports, patches, ideas, or comments. We're interested in hearing about your real-world provisioning challenges and how we can solve them for system administrators everywhere.
-
- Back to top
-
\n";
- }
- else {
- echo "Sorry: It's not possible to reach RSS file $url\n ";
- // you will probably hide this message in a live version
- }
-}
-
-// ===============================================================================
-
-// include lastRSS
-include "./rss-parser.php";
-
-// List of RSS URLs
-$rss_left = array(
- 'http://freshmeat.net/backend/fm.rdf',
- 'http://slashdot.org/slashdot.rdf'
-);
-$rss_right = array(
- 'http://www.freshfolder.com/rss.php',
- 'http://phpbuilder.com/rss_feed.php'
-);
-
-// Create lastRSS object
-$rss = new lastRSS;
-
-// Set cache dir and cache time limit (5 seconds)
-// (don't forget to chmod cahce dir to 777 to allow writing)
-$rss->cache_dir = './temp';
-$rss->cache_time = 1200;
-
-
-// Show all rss files
-echo "
";
-?>
-
diff --git a/website/new/rss-parser.php b/website/new/rss-parser.php
deleted file mode 100755
index cfe1637..0000000
--- a/website/new/rss-parser.php
+++ /dev/null
@@ -1,221 +0,0 @@
-cache_dir != '') {
- $cache_file = $this->cache_dir . '/rsscache_' . md5($rss_url);
- $timedif = @(time() - filemtime($cache_file));
- if ($timedif < $this->cache_time) {
- // cached file is fresh enough, return cached array
- $result = unserialize(join('', file($cache_file)));
- // set 'cached' to 1 only if cached file is correct
- if ($result) $result['cached'] = 1;
- } else {
- // cached file is too old, create new
- $result = $this->Parse($rss_url);
- $serialized = serialize($result);
- if ($f = @fopen($cache_file, 'w')) {
- fwrite ($f, $serialized, strlen($serialized));
- fclose($f);
- }
- if ($result) $result['cached'] = 0;
- }
- }
- // If CACHE DISABLED >> load and parse the file directly
- else {
- $result = $this->Parse($rss_url);
- if ($result) $result['cached'] = 0;
- }
- // return result
- return $result;
- }
-
- // -------------------------------------------------------------------
- // Modification of preg_match(); return trimed field with index 1
- // from 'classic' preg_match() array output
- // -------------------------------------------------------------------
- function my_preg_match ($pattern, $subject) {
- // start regullar expression
- preg_match($pattern, $subject, $out);
-
- // if there is some result... process it and return it
- if(isset($out[1])) {
- // Process CDATA (if present)
- if ($this->CDATA == 'content') { // Get CDATA content (without CDATA tag)
- $out[1] = strtr($out[1], array(''', ']]>'=>''));
- } elseif ($this->CDATA == 'strip') { // Strip CDATA
- $out[1] = strtr($out[1], array(''', ']]>'=>''));
- }
-
- // If code page is set convert character encoding to required
- if ($this->cp != '')
- //$out[1] = $this->MyConvertEncoding($this->rsscp, $this->cp, $out[1]);
- $out[1] = iconv($this->rsscp, $this->cp.'//TRANSLIT', $out[1]);
- // Return result
- return trim($out[1]);
- } else {
- // if there is NO result, return empty string
- return '';
- }
- }
-
- // -------------------------------------------------------------------
- // Replace HTML entities &something; by real characters
- // -------------------------------------------------------------------
- function unhtmlentities ($string) {
- // Get HTML entities table
- $trans_tbl = get_html_translation_table (HTML_ENTITIES, ENT_QUOTES);
- // Flip keys<==>values
- $trans_tbl = array_flip ($trans_tbl);
- // Add support for ' entity (missing in HTML_ENTITIES)
- $trans_tbl += array(''' => "'");
- // Replace entities by values
- return strtr ($string, $trans_tbl);
- }
-
- // -------------------------------------------------------------------
- // Parse() is private method used by Get() to load and parse RSS file.
- // Don't use Parse() in your scripts - use Get($rss_file) instead.
- // -------------------------------------------------------------------
- function Parse ($rss_url) {
- // Open and load RSS file
- if ($f = @fopen($rss_url, 'r')) {
- $rss_content = '';
- while (!feof($f)) {
- $rss_content .= fgets($f, 4096);
- }
- fclose($f);
-
- // Parse document encoding
- $result['encoding'] = $this->my_preg_match("'encoding=[\'\"](.*?)[\'\"]'si", $rss_content);
- // if document codepage is specified, use it
- if ($result['encoding'] != '')
- { $this->rsscp = $result['encoding']; } // This is used in my_preg_match()
- // otherwise use the default codepage
- else
- { $this->rsscp = $this->default_cp; } // This is used in my_preg_match()
-
- // Parse CHANNEL info
- preg_match("'(.*?)'si", $rss_content, $out_channel);
- foreach($this->channeltags as $channeltag)
- {
- $temp = $this->my_preg_match("'<$channeltag.*?>(.*?)$channeltag>'si", $out_channel[1]);
- if ($temp != '') $result[$channeltag] = $temp; // Set only if not empty
- }
- // If date_format is specified and lastBuildDate is valid
- if ($this->date_format != '' && ($timestamp = strtotime($result['lastBuildDate'])) !==-1) {
- // convert lastBuildDate to specified date format
- $result['lastBuildDate'] = date($this->date_format, $timestamp);
- }
-
- // Parse TEXTINPUT info
- preg_match("']*[^/])>(.*?)'si", $rss_content, $out_textinfo);
- // This a little strange regexp means:
- // Look for tag with or without any attributes, but skip truncated version (it's not beggining tag)
- if (isset($out_textinfo[2])) {
- foreach($this->textinputtags as $textinputtag) {
- $temp = $this->my_preg_match("'<$textinputtag.*?>(.*?)$textinputtag>'si", $out_textinfo[2]);
- if ($temp != '') $result['textinput_'.$textinputtag] = $temp; // Set only if not empty
- }
- }
- // Parse IMAGE info
- preg_match("'(.*?)'si", $rss_content, $out_imageinfo);
- if (isset($out_imageinfo[1])) {
- foreach($this->imagetags as $imagetag) {
- $temp = $this->my_preg_match("'<$imagetag.*?>(.*?)$imagetag>'si", $out_imageinfo[1]);
- if ($temp != '') $result['image_'.$imagetag] = $temp; // Set only if not empty
- }
- }
- // Parse ITEMS
- preg_match_all("'(.*?)'si", $rss_content, $items);
- $rss_items = $items[2];
- $i = 0;
- $result['items'] = array(); // create array even if there are no items
- foreach($rss_items as $rss_item) {
- // If number of items is lower then limit: Parse one item
- if ($i < $this->items_limit || $this->items_limit == 0) {
- foreach($this->itemtags as $itemtag) {
- $temp = $this->my_preg_match("'<$itemtag.*?>(.*?)$itemtag>'si", $rss_item);
- if ($temp != '') $result['items'][$i][$itemtag] = $temp; // Set only if not empty
- }
- // Strip HTML tags and other bullshit from DESCRIPTION
- if ($this->stripHTML && $result['items'][$i]['description'])
- $result['items'][$i]['description'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['description'])));
- // Strip HTML tags and other bullshit from TITLE
- if ($this->stripHTML && $result['items'][$i]['title'])
- $result['items'][$i]['title'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['title'])));
- // If date_format is specified and pubDate is valid
- if ($this->date_format != '' && ($timestamp = strtotime($result['items'][$i]['pubDate'])) !==-1) {
- // convert pubDate to specified date format
- $result['items'][$i]['pubDate'] = date($this->date_format, $timestamp);
- }
- // Item counter
- $i++;
- }
- }
-
- $result['items_count'] = $i;
- return $result;
- }
- else // Error in opening return False
- {
- return False;
- }
- }
-}
-
-?>
-
--
cgit
From 17e2579f3bd7c14dab0e14ed2a808fe9546f556d Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 12:12:09 -0400
Subject: Fix typo in config file.
---
config/modules.conf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/config/modules.conf b/config/modules.conf
index 8e6b8be..8863e02 100644
--- a/config/modules.conf
+++ b/config/modules.conf
@@ -12,7 +12,7 @@ module = authn_denyall
module = authz_allowall
[dns]
-module = manage_isc
+module = manage_bind
[dhcp]
-module = manage_bind
+module = manage_isc
--
cgit
From 3b447a659ddd9c8ee97ece470c876dd36aa32914 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 14:36:36 -0400
Subject: Apply jeckersb's patch to allow per-zone templates
---
cobbler/modules/manage_bind.py | 29 ++++++++++++++++++++++-------
cobbler/webui/master.py | 7 ++++---
docs/cobbler.pod | 2 +-
setup.py | 4 ++++
4 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/cobbler/modules/manage_bind.py b/cobbler/modules/manage_bind.py
index 900a832..e14122a 100644
--- a/cobbler/modules/manage_bind.py
+++ b/cobbler/modules/manage_bind.py
@@ -184,21 +184,20 @@ zone "%(arpa)s." {
def __write_zone_files(self):
"""
- Write out the forward and reverse zone files for all the zones
- defined in manage_forward_zones and manage_reverse_zones
+ Write out the forward and reverse zone files for all configured zones
"""
- template_file = "/etc/cobbler/zone.template"
+ default_template_file = "/etc/cobbler/zone.template"
cobbler_server = self.settings.server
serial = int(time.time())
forward = self.__config_forward_zones()
reverse = self.__config_reverse_zones()
try:
- f2 = open(template_file,"r")
+ f2 = open(default_template_file,"r")
except:
- raise CX(_("error reading template from file: %s") % template_file)
- template_data = ""
- template_data = f2.read()
+ raise CX(_("error reading template from file: %s") % default_template_file)
+ default_template_data = ""
+ default_template_data = f2.read()
f2.close()
for (zone, hosts) in forward.iteritems():
@@ -208,6 +207,14 @@ zone "%(arpa)s." {
'host_record': ''
}
+ # grab zone-specific template if it exists
+ try:
+ fd = open('/etc/cobbler/zone_templates/%s' % zone)
+ template_data = fd.read()
+ fd.close()
+ except:
+ template_data = default_template_data
+
for host in hosts:
txt = '%s\tIN\tA\t%s\n' % host
metadata['host_record'] = metadata['host_record'] + txt
@@ -221,6 +228,14 @@ zone "%(arpa)s." {
'host_record': ''
}
+ # grab zone-specific template if it exists
+ try:
+ fd = open('/etc/cobbler/zone_templates/%s' % zone)
+ template_data = fd.read()
+ fd.close()
+ except:
+ template_data = default_template_data
+
for host in hosts:
txt = '%s\tIN\tPTR\t%s\n' % host
metadata['host_record'] = metadata['host_record'] + txt
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index 7e54a2d..cdde14d 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -33,9 +33,10 @@ VFN=valueForName
currentTime=time.time
__CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1209057202.737108
-__CHEETAH_genTimestamp__ = 'Thu Apr 24 13:13:22 2008'
-__CHEETAH_srcLastModified__ = 'Thu Apr 24 12:59:37 2008'
+__CHEETAH_genTime__ = 1209998447.8930521
+__CHEETAH_genTimestamp__ = 'Mon May 5 10:40:47 2008'
+__CHEETAH_src__ = 'webui_templates/master.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu May 1 13:51:29 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index 311a94c..018c3f4 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -563,7 +563,7 @@ Choose either "management = isc_and_bind" or "management = dnsmasq" in /etc/cobb
This feature is off by default. If using BIND, you may restrict the scope of zones managed with the options 'manage_forward_zones' and 'manage_reverse_zones'. (See the Wiki for more information on this).
-If using BIND, Cobbler will use /etc/cobbler/bind.template and /etc/cobbler/zone.template as a starting point for the named.conf and individual zone files, respectively. These files must be user edited for the user's particular networking environment. Read the file and understand how BIND works before proceeding.
+If using BIND, Cobbler will use /etc/cobbler/bind.template and /etc/cobbler/zone.template as a starting point for the named.conf and individual zone files, respectively. You may drop zone-specific template files in /etc/cobbler/zone_templates/name-of-zone which will override the default. These files must be user edited for the user's particular networking environment. Read the file and understand how BIND works before proceeding.
If using dnsmasq, the template is /etc/cobbler/dnsmasq.template. Read this file and understand how dnsmasq works before proceeding.
diff --git a/setup.py b/setup.py
index 442da5b..07d9880 100644
--- a/setup.py
+++ b/setup.py
@@ -41,6 +41,7 @@ if __name__ == "__main__":
vw_systems = "/var/www/cobbler/systems"
vw_profiles = "/var/www/cobbler/profiles"
vw_links = "/var/www/cobbler/links"
+ zone_templates = "/etc/cobbler/zone_templates"
tftp_cfg = "/tftpboot/pxelinux.cfg"
tftp_images = "/tftpboot/images"
rotpath = "/etc/logrotate.d"
@@ -134,6 +135,9 @@ if __name__ == "__main__":
(vw_profiles, []),
(vw_links, []),
+ # zone-specific templates directory
+ (zone_templates, []),
+
# tftp directories that we own
(tftp_cfg, []),
(tftp_images, []),
--
cgit
From 5a3883b847007ba11e8058441c5bcc401b36fd1f Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 14:38:09 -0400
Subject: Remove typo in function
---
cobbler/modules/manage_isc.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/cobbler/modules/manage_isc.py b/cobbler/modules/manage_isc.py
index bc88412..5bbe2fa 100644
--- a/cobbler/modules/manage_isc.py
+++ b/cobbler/modules/manage_isc.py
@@ -98,7 +98,6 @@ class IscManager:
def remove_dhcp_lease(self,port,host):
"""
- removeDHCPLease(port,host)
Use DHCP's API to delete a DHCP entry in
the /var/lib/dhcpd/dhcpd.leases file
"""
@@ -166,7 +165,7 @@ class IscManager:
break
if elem == 'host':
hostremove = item.get_token()
- self.removeDHCPLease(self.settings.omapi_port,hostremove)
+ self.remove_dhcp_lease(self.settings.omapi_port,hostremove)
# we used to just loop through each system, but now we must loop
# through each network interface of each system.
--
cgit
From 3c4bb08f300527952067287fa205120eb0de3933 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 14:39:04 -0400
Subject: Change default PXE behavior for local to "-1" which means next step
in boot process as opposed to picking a specific drive.
---
templates/pxedefault.template | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/pxedefault.template b/templates/pxedefault.template
index bb09893..206c028 100644
--- a/templates/pxedefault.template
+++ b/templates/pxedefault.template
@@ -8,7 +8,7 @@ ONTIMEOUT local
LABEL local
MENU LABEL (local)
MENU DEFAULT
- LOCALBOOT 0
+ LOCALBOOT -1
$pxe_menu_items
--
cgit
From 97cb9acc37c4b230f5ac914044d0425cf73a11d0 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 14:40:44 -0400
Subject: Get omshell path from config file
---
cobbler/modules/manage_isc.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cobbler/modules/manage_isc.py b/cobbler/modules/manage_isc.py
index 5bbe2fa..895eadc 100644
--- a/cobbler/modules/manage_isc.py
+++ b/cobbler/modules/manage_isc.py
@@ -73,7 +73,7 @@ class IscManager:
# FIXME: should use subprocess
"""
try:
- fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ fromchild, tochild = popen2.popen2(self.settings.omshell_bin)
tochild.write("port %s\n" % port)
tochild.flush()
tochild.write("connect\n")
@@ -101,7 +101,7 @@ class IscManager:
Use DHCP's API to delete a DHCP entry in
the /var/lib/dhcpd/dhcpd.leases file
"""
- fromchild, tochild = popen2.popen2("/usr/bin/omshell")
+ fromchild, tochild = popen2.popen2(self.settings.omshell_bin)
try:
tochild.write("port %s\n" % port)
tochild.flush()
--
cgit
From 19e53e8ad1a6889d020c6029d2d34273dacdc750 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 14:46:37 -0400
Subject: Always restart dhcp seperate from dns.
---
triggers/restart-services.trigger | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/triggers/restart-services.trigger b/triggers/restart-services.trigger
index bc7c36e..d586f46 100644
--- a/triggers/restart-services.trigger
+++ b/triggers/restart-services.trigger
@@ -4,6 +4,8 @@ import cobbler.api as capi
import os
import sys
+#!/usr/bin/python
+
bootapi = capi.BootAPI()
settings = bootapi.settings()
manage_dhcp = str(settings.manage_dhcp).lower()
@@ -12,14 +14,10 @@ manage_dns = str(settings.manage_dns).lower()
omapi_enabled = settings.omapi_enabled
omapi_port = settings.omapi_port
-
-
-# We're just going to restart DHCPD if using ISC and if not using OMAPI at all
rc = 0
if manage_dhcp != "0":
if manage_dhcp_mode == "isc":
if not omapi_enabled:
- if not omapi_port:
rc = os.system("/sbin/service dhcpd restart")
elif manage_dhcp_mode == "dnsmasq":
rc = os.system("/sbin/service dnsmasq restart")
@@ -27,9 +25,6 @@ if manage_dhcp != "0":
print "- error: unknown DHCP engine: %s" % manage_dhcp_mode
rc = 411
-if rc != 0:
- sys.exit(rc)
-
if manage_dns != "0":
rc = os.system("/sbin/service named restart")
--
cgit
From e38519a052ae0c5aa472856621de15e45e008845 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 5 May 2008 17:02:48 -0400
Subject: omshell wants lowercase macs
---
cobbler/modules/manage_isc.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/modules/manage_isc.py b/cobbler/modules/manage_isc.py
index 895eadc..c398270 100644
--- a/cobbler/modules/manage_isc.py
+++ b/cobbler/modules/manage_isc.py
@@ -84,7 +84,7 @@ class IscManager:
tochild.flush()
tochild.write("set ip-address = %s\n" % ip)
tochild.flush()
- tochild.write("set hardware-address = %s\n" % mac)
+ tochild.write("set hardware-address = %s\n" % mac.lower())
tochild.flush()
tochild.write("set hardware-type = 1\n")
tochild.flush()
--
cgit
From 6aeaebf293c899a05ff64fb35bf992a0e100d057 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 6 May 2008 11:39:39 -0400
Subject: Revert to previous local boot PXE policy
---
templates/pxedefault.template | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/pxedefault.template b/templates/pxedefault.template
index 206c028..bb09893 100644
--- a/templates/pxedefault.template
+++ b/templates/pxedefault.template
@@ -8,7 +8,7 @@ ONTIMEOUT local
LABEL local
MENU LABEL (local)
MENU DEFAULT
- LOCALBOOT -1
+ LOCALBOOT 0
$pxe_menu_items
--
cgit
From 66d034de6a272f24c4afe023c211c4857e64dc72 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 6 May 2008 11:54:35 -0400
Subject: Swap dhcp and dns module references
---
cobbler/action_litesync.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index ba3e3ee..ad669be 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -106,9 +106,9 @@ class BootLiteSync:
raise CX(_("error in system lookup for %s") % name)
# rebuild system_list file in webdir
if self.settings.manage_dhcp:
- self.sync.dns.regen_ethers()
+ self.sync.dhcp.regen_ethers()
if self.settings.manage_dns:
- self.sync.dhcp.regen_hosts()
+ self.sync.dns.regen_hosts()
# write the PXE files for the system
self.sync.pxegen.write_all_system_files(system)
# per system kickstarts
--
cgit
From 31645710cbb926f6859f38e5feb11e3263925478 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 6 May 2008 12:30:03 -0400
Subject: Redo exception handling code for older python to eliminate tracebacks
that should not be printed.
---
cobbler/cexceptions.py | 3 +++
cobbler/cobbler.py | 12 +++++-------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/cobbler/cexceptions.py b/cobbler/cexceptions.py
index a78f7f2..dba2857 100644
--- a/cobbler/cexceptions.py
+++ b/cobbler/cexceptions.py
@@ -20,6 +20,9 @@ class CobblerException(exceptions.Exception):
def __init__(self, value, *args):
self.value = value % args
+ # this is a hack to work around some odd exception handling
+ # in older pythons
+ self.from_cobbler = 1
def __str__(self):
return repr(self.value)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 627e398..160dbc5 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -52,13 +52,11 @@ def main():
try:
return BootCLI().run(sys.argv)
except Exception, exc:
- if isinstance(exc, cexceptions.CobblerException) or \
- isinstance(exc, cexceptions.CX) or \
- str(type(exc)).find("CX") != -1 or \
- str(type(exc)).find("CobblerException") != -1:
- print str(exc)[1:-1] # remove framing air quotes
- else:
- traceback.print_exc()
+ try:
+ getattr(exc, "from_cobbler")
+ print str(exc)[1:-1]
+ except:
+ traceback.print_exc()
return 1
if __name__ == "__main__":
--
cgit
From ae4a1c0b3551aadba6ea09bd6211e5c617d034a4 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 6 May 2008 15:50:54 -0400
Subject: More exception handling.
---
cobbler/cobbler.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 160dbc5..0e15175 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -20,6 +20,7 @@ import os
import os.path
import traceback
import optparse
+import string
import commands
import cexceptions
from cexceptions import *
@@ -52,11 +53,12 @@ def main():
try:
return BootCLI().run(sys.argv)
except Exception, exc:
+ (t, v, tb) = sys.exc_info()
try:
getattr(exc, "from_cobbler")
print str(exc)[1:-1]
except:
- traceback.print_exc()
+ print string.join(traceback.format_list(traceback.extract_tb(tb)))
return 1
if __name__ == "__main__":
--
cgit
From 4f5d4161611ba4189c3e36a67bd00cae21afa562 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 6 May 2008 16:09:01 -0400
Subject: Ignore system exit
---
cobbler/cobbler.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 0e15175..5081009 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -52,6 +52,8 @@ def main():
exitcode = 0
try:
return BootCLI().run(sys.argv)
+ except SystemExit, ex:
+ return 1
except Exception, exc:
(t, v, tb) = sys.exc_info()
try:
--
cgit
From e9cba0c5d8ca7356621a737a09b6a22d8b00e9fc Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 7 May 2008 15:17:18 -0400
Subject: Improve tracebacks.
---
cobbler/cobbler.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 5081009..970a06a 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -60,6 +60,8 @@ def main():
getattr(exc, "from_cobbler")
print str(exc)[1:-1]
except:
+ print t
+ print v
print string.join(traceback.format_list(traceback.extract_tb(tb)))
return 1
--
cgit
From 072204fb8d3e351c2c6e67beb52de175cad0c979 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 8 May 2008 10:09:08 -0400
Subject: Apply John Eckersberg's patch to allow random mac usage from the
command line.
---
cobbler/modules/cli_system.py | 8 ++++++--
cobbler/remote.py | 20 ++++----------------
cobbler/utils.py | 21 +++++++++++++++++++++
cobbler/webui/master.py | 4 ++--
4 files changed, 33 insertions(+), 20 deletions(-)
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 0c9a5b8..419b561 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -19,7 +19,7 @@ plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)
-from utils import _
+from utils import _, get_random_mac
import commands
import cexceptions
@@ -98,7 +98,11 @@ class SystemFunction(commands.CobblerFunction):
my_interface = "intf0"
if self.options.hostname: obj.set_hostname(self.options.hostname, my_interface)
- if self.options.mac: obj.set_mac_address(self.options.mac, my_interface)
+ if self.options.mac:
+ if self.options.mac.lower() == 'random':
+ obj.set_mac_address(get_random_mac(self.api), my_interface)
+ else:
+ obj.set_mac_address(self.options.mac, my_interface)
if self.options.ip: obj.set_ip_address(self.options.ip, my_interface)
if self.options.subnet: obj.set_subnet(self.options.subnet, my_interface)
if self.options.gateway: obj.set_gateway(self.options.gateway, my_interface)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 18c3947..749298e 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -475,25 +475,13 @@ class CobblerXMLRPCInterface:
def get_random_mac(self,token=None):
"""
- Generate a random MAC address.
- from xend/server/netif.py
- Generate a random MAC address.
- Uses OUI 00-16-3E, allocated to
- Xensource, Inc. Last 3 fields are random.
- return: MAC address string
+ Wrapper for utils.get_random_mac
+
+ Used in the webui
"""
self.log("get_random_mac",token=None)
self._refresh()
- mac = [ 0x00, 0x16, 0x3e,
- random.randint(0x00, 0x7f),
- random.randint(0x00, 0xff),
- random.randint(0x00, 0xff) ]
- mac = ':'.join(map(lambda x: "%02x" % x, mac))
- systems = self.api.systems()
- while ( systems.find(mac_address=mac) ):
- mac = self.get_random_mac()
-
- return mac
+ return utils.get_random_mac(self.api)
def _fix_none(self,data):
"""
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 7bd37ad..14019e8 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -17,6 +17,7 @@ import os
import re
import socket
import glob
+import random
import sub_process
import shutil
import string
@@ -111,6 +112,26 @@ def is_mac(strdata):
return True
return False
+def get_random_mac(api_handle):
+ """
+ Generate a random MAC address.
+ from xend/server/netif.py
+ Generate a random MAC address.
+ Uses OUI 00-16-3E, allocated to
+ Xensource, Inc. Last 3 fields are random.
+ return: MAC address string
+ """
+ mac = [ 0x00, 0x16, 0x3e,
+ random.randint(0x00, 0x7f),
+ random.randint(0x00, 0xff),
+ random.randint(0x00, 0xff) ]
+ mac = ':'.join(map(lambda x: "%02x" % x, mac))
+ systems = api_handle.systems()
+ while ( systems.find(mac_address=mac) ):
+ mac = get_random_mac(api_handle)
+
+ return mac
+
def resolve_ip(strdata):
"""
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
index cdde14d..50f9fd1 100644
--- a/cobbler/webui/master.py
+++ b/cobbler/webui/master.py
@@ -33,8 +33,8 @@ VFN=valueForName
currentTime=time.time
__CHEETAH_version__ = '2.0.1'
__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1209998447.8930521
-__CHEETAH_genTimestamp__ = 'Mon May 5 10:40:47 2008'
+__CHEETAH_genTime__ = 1210208830.681746
+__CHEETAH_genTimestamp__ = 'Wed May 7 21:07:10 2008'
__CHEETAH_src__ = 'webui_templates/master.tmpl'
__CHEETAH_srcLastModified__ = 'Thu May 1 13:51:29 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
--
cgit
From 7ee964ea8bc64284409c7ac053eb0c12b449aed6 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 8 May 2008 13:41:07 -0400
Subject: Apply scott henson's replicate patch.
---
AUTHORS | 1 +
CHANGELOG | 1 +
Makefile | 2 +-
cobbler/api.py | 5 +
cobbler/modules/cli_misc.py | 21 +++-
cobbler/settings.py | 1 +
cobbler/webui/master.py | 266 --------------------------------------------
7 files changed, 29 insertions(+), 268 deletions(-)
delete mode 100644 cobbler/webui/master.py
diff --git a/AUTHORS b/AUTHORS
index cb26afc..9230de5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,6 +12,7 @@ Patches and other contributions from:
C. Daniel Chase
Máirín Duffy
John Eckersberg
+ Scott Henson
Tru Huynh
Matt Hyclak
Pablo Iranzo Gómez
diff --git a/CHANGELOG b/CHANGELOG
index 278b8fa..eec038e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -37,6 +37,7 @@ Cobbler CHANGELOG
- support for managing BIND
- xen kernel (PV) distros do not get added to PXE menus as they won't boot there
- cobbler buildiso command to build non live ISOs
+- cobbler replicate command
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/Makefile b/Makefile
index 6287f5d..af01e9f 100644
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,7 @@ messages: cobbler/*.py
sed -i'~' -e 's/SOME DESCRIPTIVE TITLE/cobbler/g' -e 's/YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/2007 Red Hat, Inc. /g' -e 's/FIRST AUTHOR , YEAR/Michael DeHaan , 2007/g' -e 's/PACKAGE VERSION/cobbler $(VERSION)-$(RELEASE)/g' -e 's/PACKAGE/cobbler/g' $(MESSAGESPOT)
-rpms: clean manpage sdist
+rpms: clean updatewui manpage sdist
mkdir -p rpm-build
cp dist/*.gz rpm-build/
rpmbuild --define "_topdir %(pwd)/rpm-build" \
diff --git a/cobbler/api.py b/cobbler/api.py
index 20c7364..1b73acd 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -23,6 +23,7 @@ import action_reposync
import action_status
import action_validate
import action_buildiso
+import action_replicate
from cexceptions import *
import sub_process
import module_loader
@@ -437,3 +438,7 @@ class BootAPI:
iso=iso, profiles=profiles, tempdir=tempdir
)
+ def replicate(self, cobbler_master = None):
+ replicator = action_replicate.Replicate(self._config)
+ return replicator.run(cobbler_master = cobbler_master)
+
diff --git a/cobbler/modules/cli_misc.py b/cobbler/modules/cli_misc.py
index 6ca14a2..c72b11d 100644
--- a/cobbler/modules/cli_misc.py
+++ b/cobbler/modules/cli_misc.py
@@ -261,6 +261,24 @@ class BuildIsoFunction(commands.CobblerFunction):
tempdir=self.options.tempdir
)
+########################################################
+
+class ReplicateFunction(commands.CobblerFunction):
+
+ def help_me(self):
+ return HELP_FORMAT % ("cobbler replicate","[ARGS|--help]")
+
+ def command_name(self):
+ return "replicate"
+
+ def add_options(self, p, args):
+ p.add_option("--master", dest="master", help="Cobbler server to replicate from.")
+
+ def run(self):
+ return self.api.replicate(cobbler_master = self.options.master)
+
+
+
########################################################
# MODULE HOOKS
@@ -275,7 +293,8 @@ def cli_functions(api):
BuildIsoFunction(api),
CheckFunction(api), ImportFunction(api), ReserializeFunction(api),
ListFunction(api), ReportFunction(api), StatusFunction(api),
- SyncFunction(api), RepoSyncFunction(api), ValidateKsFunction(api)
+ SyncFunction(api), RepoSyncFunction(api), ValidateKsFunction(api),
+ ReplicateFunction(api)
]
return []
diff --git a/cobbler/settings.py b/cobbler/settings.py
index bf12545..d147d4b 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -29,6 +29,7 @@ DEFAULTS = {
"standard" : "/usr/lib/syslinux/pxelinux.0",
"ia64" : "/var/lib/cobbler/elilo-3.6-ia64.efi"
},
+ "cobbler_master" : '',
"default_kickstart" : "/etc/cobbler/default.ks",
"default_virt_bridge" : "xenbr0",
"default_virt_type" : "auto",
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
deleted file mode 100644
index 50f9fd1..0000000
--- a/cobbler/webui/master.py
+++ /dev/null
@@ -1,266 +0,0 @@
-#!/usr/bin/env python
-
-
-
-
-##################################################
-## DEPENDENCIES
-import sys
-import os
-import os.path
-from os.path import getmtime, exists
-import time
-import types
-import __builtin__
-from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
-from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
-from Cheetah.Template import Template
-from Cheetah.DummyTransaction import DummyTransaction
-from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
-from Cheetah.CacheRegion import CacheRegion
-import Cheetah.Filters as Filters
-import Cheetah.ErrorCatchers as ErrorCatchers
-
-##################################################
-## MODULE CONSTANTS
-try:
- True, False
-except NameError:
- True, False = (1==1), (1==0)
-VFFSL=valueFromFrameOrSearchList
-VFSL=valueFromSearchList
-VFN=valueForName
-currentTime=time.time
-__CHEETAH_version__ = '2.0.1'
-__CHEETAH_versionTuple__ = (2, 0, 1, 'final', 0)
-__CHEETAH_genTime__ = 1210208830.681746
-__CHEETAH_genTimestamp__ = 'Wed May 7 21:07:10 2008'
-__CHEETAH_src__ = 'webui_templates/master.tmpl'
-__CHEETAH_srcLastModified__ = 'Thu May 1 13:51:29 2008'
-__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
-
-if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
- raise AssertionError(
- 'This template was compiled with Cheetah version'
- ' %s. Templates compiled before version %s must be recompiled.'%(
- __CHEETAH_version__, RequiredCheetahVersion))
-
-##################################################
-## CLASSES
-
-class master(Template):
-
- ##################################################
- ## CHEETAH GENERATED METHODS
-
-
- def __init__(self, *args, **KWs):
-
- Template.__init__(self, *args, **KWs)
- if not self._CHEETAH__instanceInitialized:
- cheetahKWArgs = {}
- allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
- for k,v in KWs.items():
- if k in allowedKWs: cheetahKWArgs[k] = v
- self._initCheetahInstance(**cheetahKWArgs)
-
-
- def body(self, **KWS):
-
-
-
- ## CHEETAH: generated from #block body at line 54, col 1.
- trans = KWS.get("trans")
- if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
- trans = self.transaction # is None unless self.awake() was called
- if not trans:
- trans = DummyTransaction()
- _dummyTrans = True
- else: _dummyTrans = False
- write = trans.response().write
- SL = self._CHEETAH__searchList
- _filter = self._CHEETAH__currentFilter
-
- ########################################
- ## START - generated method body
-
- write('''
-
Template Failure
-
-''')
-
- ########################################
- ## END - generated method body
-
- return _dummyTrans and trans.response().getvalue() or ""
-
-
- def respond(self, trans=None):
-
-
-
- ## CHEETAH: main method generated for this template
- if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
- trans = self.transaction # is None unless self.awake() was called
- if not trans:
- trans = DummyTransaction()
- _dummyTrans = True
- else: _dummyTrans = False
- write = trans.response().write
- SL = self._CHEETAH__searchList
- _filter = self._CHEETAH__currentFilter
-
- ########################################
- ## START - generated method body
-
- write('''
-
-
- ''')
- _v = VFFSL(SL,"title",True) # '$title' on line 5, col 12
- if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 5, col 12.
- write('''
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-''')
-
- ########################################
- ## END - generated method body
-
- return _dummyTrans and trans.response().getvalue() or ""
-
- ##################################################
- ## CHEETAH GENERATED ATTRIBUTES
-
-
- _CHEETAH__instanceInitialized = False
-
- _CHEETAH_version = __CHEETAH_version__
-
- _CHEETAH_versionTuple = __CHEETAH_versionTuple__
-
- _CHEETAH_genTime = __CHEETAH_genTime__
-
- _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
-
- _CHEETAH_src = __CHEETAH_src__
-
- _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
-
- title = "Cobbler Web Interface"
-
- _mainCheetahMethod_for_master= 'respond'
-
-## END CLASS DEFINITION
-
-if not hasattr(master, '_initCheetahAttributes'):
- templateAPIClass = getattr(master, '_CHEETAH_templateClass', Template)
- templateAPIClass._addCheetahPlumbingCodeToClass(master)
-
-
-# CHEETAH was developed by Tavis Rudd and Mike Orr
-# with code, advice and input from many other volunteers.
-# For more information visit http://www.CheetahTemplate.org/
-
-##################################################
-## if run from command line:
-if __name__ == '__main__':
- from Cheetah.TemplateCmdLineIface import CmdLineIface
- CmdLineIface(templateObj=master()).run()
-
-
--
cgit
From 6ae4029a0c0021cb9151cb5a22a68c4b72ecf8cc Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 8 May 2008 16:57:33 -0400
Subject: Added --mirror-locally option to repo add/edit and WebUI for
specifying that a cobbler repo object is to be used directly, rather than
mirrored into /var/www/cobbler by reposync/rsync. This can be usable when
network connectivity outside is certain, and there are no performance or
bandwidth needs on a local mirror. This supports http:// and ftp:// only,
rsync:// is not natively understood by yum.
---
CHANGELOG | 1 +
cobbler/action_reposync.py | 37 +++++++++++++++++++++++++++----------
cobbler/item_repo.py | 18 ++++++++++++++++--
cobbler/kickgen.py | 7 ++++++-
cobbler/modules/cli_repo.py | 2 ++
cobbler/remote.py | 5 +++++
cobbler/services.py | 1 +
cobbler/webui/CobblerWeb.py | 7 ++++++-
docs/cobbler.pod | 6 +++++-
webui_templates/repo_edit.tmpl | 30 +++++++++++++++++++++---------
10 files changed, 90 insertions(+), 24 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index eec038e..2a70394 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -38,6 +38,7 @@ Cobbler CHANGELOG
- xen kernel (PV) distros do not get added to PXE menus as they won't boot there
- cobbler buildiso command to build non live ISOs
- cobbler replicate command
+- added cobbler repo option --mirror-locally to reference external repos without mirroring
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_reposync.py b/cobbler/action_reposync.py
index d6b97a0..33bfe30 100644
--- a/cobbler/action_reposync.py
+++ b/cobbler/action_reposync.py
@@ -57,8 +57,10 @@ class RepoSync:
self.verbose = verbose
for repo in self.repos:
if name is not None and repo.name != name:
+ # invoked to sync only a specific repo, this is not the one
continue
elif name is None and not repo.keep_updated:
+ # invoked to run against all repos, but this one is off
print _("- %s is set to not be updated") % repo.name
continue
@@ -71,6 +73,8 @@ class RepoSync:
if repo.is_rsync_mirror():
self.do_rsync(repo)
else:
+ # which may actually NOT reposync if the repo is set to not mirror locally
+ # but that's a technicality
self.do_reposync(repo)
self.update_permissions(repo_path)
@@ -105,7 +109,7 @@ class RepoSync:
store_path = os.path.join(self.settings.webdir, "repo_mirror")
dest_path = os.path.join(store_path, repo.name)
temp_path = os.path.join(store_path, ".origin")
- if not os.path.isdir(temp_path):
+ if not os.path.isdir(temp_path) and repo.mirror_locally:
# FIXME: there's a chance this might break the RHN D/L case
os.makedirs(temp_path)
@@ -118,18 +122,21 @@ class RepoSync:
# this is the simple non-RHN case.
# create the config file that yum will use for the copying
- temp_file = self.create_local_file(repo, temp_path, output=False)
+ if repo.mirror_locally:
+ temp_file = self.create_local_file(repo, temp_path, output=False)
- if not has_rpm_list:
+ if not has_rpm_list and repo.mirror_locally:
# if we have not requested only certain RPMs, use reposync
cmd = "/usr/bin/reposync --config=%s --repoid=%s --download_path=%s" % (temp_file, repo.name, store_path)
if repo.arch != "":
+ if repo.arch == "x86":
+ repo.arch = "i386" # FIX potential arch errors
cmd = "%s -a %s" % (cmd, repo.arch)
print _("- %s") % cmd
cmds.append(cmd)
- else:
+ elif repo.mirror_locally:
# create the output directory if it doesn't exist
if not os.path.exists(dest_path):
@@ -149,6 +156,8 @@ class RepoSync:
# this is the somewhat more-complex RHN case.
# NOTE: this requires that you have entitlements for the server and you give the mirror as rhn://$channelname
+ if not repo.mirror_locally:
+ raise CX(_("rhn:// repos do not work with --mirror-locally=1"))
if has_rpm_list:
print _("- warning: --rpm-list is not supported for RHN content")
@@ -161,7 +170,6 @@ class RepoSync:
if repo.arch != "":
cmd = "%s -a %s" % (cmd, repo.arch)
- print _("- %s") % cmd
cmds.append(cmd)
# now regardless of whether we're doing yumdownloader or reposync
@@ -169,9 +177,10 @@ class RepoSync:
# commands here. Any failure at any point stops the operation.
for cmd in cmds:
- rc = sub_process.call(cmd, shell=True)
- if rc !=0:
- raise CX(_("cobbler reposync failed"))
+ if repo.mirror_locally:
+ rc = sub_process.call(cmd, shell=True)
+ if rc !=0:
+ raise CX(_("cobbler reposync failed"))
# some more special case handling for RHN.
# create the config file now, because the directory didn't exist earlier
@@ -181,7 +190,8 @@ class RepoSync:
# now run createrepo to rebuild the index
- os.path.walk(dest_path, self.createrepo_walker, repo)
+ if repo.mirror_locally:
+ os.path.walk(dest_path, self.createrepo_walker, repo)
# create the config file the hosts will use to access the repository.
@@ -196,6 +206,9 @@ class RepoSync:
Handle copying of rsync:// and rsync-over-ssh repos.
"""
+ if not repo.mirror_locally:
+ raise CX(_("rsync:// urls must be mirrored locally, yum cannot access them directly"))
+
if repo.rpm_list != "":
print _("- warning: --rpm-list is not supported for rsync'd repositories")
dest_path = os.path.join(self.settings.webdir, "repo_mirror", repo.name)
@@ -238,7 +251,11 @@ class RepoSync:
optenabled = False
optgpgcheck = False
if output:
- line = "baseurl=http://${server}/cobbler/repo_mirror/%s\n" % (repo.name)
+ if repo.mirror_locally:
+ line = "baseurl=http://${server}/cobbler/repo_mirror/%s\n" % (repo.name)
+ else:
+ line = "baseurl=%s" % (repo.mirror)
+
config_file.write(line)
# user may have options specific to certain yum plugins
# add them to the file
diff --git a/cobbler/item_repo.py b/cobbler/item_repo.py
index b87528d..ba32a07 100644
--- a/cobbler/item_repo.py
+++ b/cobbler/item_repo.py
@@ -31,6 +31,7 @@ class Repo(item.Item):
def clear(self,is_subobject=False):
self.parent = None
self.name = None
+ # FIXME: subobject code does not really make sense for repos
self.mirror = (None, '<>')[is_subobject]
self.keep_updated = ('y', '<>')[is_subobject]
self.priority = (99, '<>')[is_subobject]
@@ -40,6 +41,7 @@ class Repo(item.Item):
self.arch = "" # use default arch
self.yumopts = {}
self.owners = self.settings.default_ownership
+ self.mirror_locally = 1
def from_datastruct(self,seed_data):
self.parent = self.load_item(seed_data, 'parent')
@@ -53,6 +55,7 @@ class Repo(item.Item):
self.depth = self.load_item(seed_data, 'depth', 2)
self.yumopts = self.load_item(seed_data, 'yumopts', {})
self.owners = self.load_item(seed_data, 'owners', self.settings.default_ownership)
+ self.mirror_locally = self.load_item(seed_data, 'mirror_locally', '1')
# coerce types from input file
self.set_keep_updated(self.keep_updated)
@@ -70,7 +73,7 @@ class Repo(item.Item):
if mirror.find("x86_64") != -1:
self.set_arch("x86_64")
elif mirror.find("x86") != -1 or mirror.find("i386") != -1:
- self.set_arch("x86")
+ self.set_arch("i386")
elif mirror.find("ia64") != -1:
self.set_arch("ia64")
return True
@@ -165,6 +168,7 @@ class Repo(item.Item):
'name' : self.name,
'owners' : self.owners,
'mirror' : self.mirror,
+ 'mirror_locally' : self.mirror_locally,
'keep_updated' : self.keep_updated,
'priority' : self.priority,
'rpm_list' : self.rpm_list,
@@ -175,10 +179,19 @@ class Repo(item.Item):
'yumopts' : self.yumopts
}
+ def set_mirror_locally(self,value):
+ value = str(value).lower()
+ if value in [ "yes", "y", "1", "on", "true" ]:
+ self.mirror_locally = 1
+ else:
+ self.mirror_locally = 0
+ return True
+
def printable(self):
buf = _("repo : %s\n") % self.name
buf = buf + _("owners : %s\n") % self.owners
buf = buf + _("mirror : %s\n") % self.mirror
+ buf = buf + _("mirror locally : %s\n") % self.mirror_locally
buf = buf + _("keep updated : %s\n") % self.keep_updated
buf = buf + _("priority : %s\n") % self.priority
buf = buf + _("rpm list : %s\n") % self.rpm_list
@@ -215,6 +228,7 @@ class Repo(item.Item):
'rpm-list' : self.set_rpm_list,
'createrepo-flags' : self.set_createrepo_flags,
'yumopts' : self.set_yumopts,
- 'owners' : self.set_owners
+ 'owners' : self.set_owners,
+ 'mirror-locally' : self.set_mirror_locally
}
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index a5e540e..a9bc095 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -146,13 +146,18 @@ class KickGen:
configs = self.get_repo_filenames(obj,is_profile)
repos = self.repos
+ # FIXME: this really should be dynamically generated as with the kickstarts
for c in configs:
name = c.split("/")[-1].replace(".repo","")
(is_core, baseurl) = self.analyze_repo_config(c)
for repo in repos:
if repo.name == name:
if not repo.yumopts.has_key('enabled') or repo.yumopts['enabled'] == '1':
- buf = buf + "repo --name=%s --baseurl=%s\n" % (name, baseurl)
+ if repo.mirror_locally:
+ buf = buf + "repo --name=%s --baseurl=%s\n" % (name, baseurl)
+ else:
+ buf = buf + "repo --name=%s --baseurl=%s\n" % (name, repo.mirror)
+
return buf
def analyze_repo_config(self, filename):
diff --git a/cobbler/modules/cli_repo.py b/cobbler/modules/cli_repo.py
index f31ab26..af6a9d1 100644
--- a/cobbler/modules/cli_repo.py
+++ b/cobbler/modules/cli_repo.py
@@ -51,6 +51,7 @@ class RepoFunction(commands.CobblerFunction):
if not self.matches_args(args,["dumpvars","remove","report","list"]):
p.add_option("--mirror", dest="mirror", help="source to mirror (REQUIRED)")
+ p.add_option("--mirror-locally", dest="mirror_locally", help="mirror or use external directly? (default 1)")
p.add_option("--priority", dest="priority", help="set priority")
p.add_option("--rpm-list", dest="rpm_list", help="just mirror these rpms")
p.add_option("--yumopts", dest="yumopts", help="ex: pluginvar=abcd")
@@ -81,6 +82,7 @@ class RepoFunction(commands.CobblerFunction):
if self.options.keep_updated: obj.set_keep_updated(self.options.keep_updated)
if self.options.priority: obj.set_priority(self.options.priority)
if self.options.mirror: obj.set_mirror(self.options.mirror)
+ if self.options.mirror_locally: obj.set_mirror_locally(self.options.mirror_locally)
if self.options.yumopts: obj.set_yumopts(self.options.yumopts)
if self.options.owners:
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 749298e..87695d2 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -65,6 +65,11 @@ class CobblerXMLRPCInterface:
def ping(self):
return True
+ def update(self,token=None):
+ # ensure the config is up to date as of /now/
+ self.api.deserialize()
+ return True
+
def get_user_from_token(self,token):
if not TOKEN_CACHE.has_key(token):
raise CX(_("invalid token: %s") % token)
diff --git a/cobbler/services.py b/cobbler/services.py
index adaf6fc..1cb3864 100644
--- a/cobbler/services.py
+++ b/cobbler/services.py
@@ -45,6 +45,7 @@ class CobblerSvc(object):
This is the version that does not require logins.
"""
self.remote = xmlrpclib.Server(self.server, allow_none=True)
+ self.remote.update()
def modes(self):
"""
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index 2eeb1a3..0951633 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -61,6 +61,8 @@ class CobblerWeb(object):
try:
self.remote.token_check(self.token)
self.username = self.remote.get_user_from_token(self.token)
+ # ensure config is up2date
+ self.remote.update(self.token)
return True
except Exception, e:
if str(e).find("invalid token") != -1:
@@ -79,6 +81,8 @@ class CobblerWeb(object):
log_exc(self.apache)
return False
self.password = None # don't need it anymore, get rid of it
+ # ensure configuration is up2date
+ self.remote.update(self.token)
return True
# login failed
@@ -631,7 +635,7 @@ class CobblerWeb(object):
} )
def repo_save(self,name=None,oldname=None,new_or_edit=None,editmode="edit",
- mirror=None,owners=None,keep_updated=None,priority=99,
+ mirror=None,owners=None,keep_updated=None,mirror_locally=0,priority=99,
rpm_list=None,createrepo_flags=None,arch=None,yumopts=None,
delete1=None,delete2=None,**args):
if not self.__xmlrpc_setup():
@@ -675,6 +679,7 @@ class CobblerWeb(object):
self.remote.modify_repo(repo, 'mirror', mirror, self.token)
self.remote.modify_repo(repo, 'keep-updated', keep_updated, self.token)
self.remote.modify_repo(repo, 'priority', priority, self.token)
+ self.remote.modify_repo(repo, 'mirror-locally', mirror_locally, self.token)
if rpm_list:
self.remote.modify_repo(repo, 'rpm-list', rpm_list, self.token)
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index 018c3f4..9f5154e 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -280,7 +280,7 @@ on your network will result in faster, more up-to-date installations and faster
are only provisioning a home setup, this will probably be overkill, though it can be very useful
for larger setups (labs, datacenters, etc).
-B
+B
=over
@@ -335,6 +335,10 @@ Specifies optional flags to feed into the createrepo tool, which is called when
Specifies that the named repository should not be updated during a normal "cobbler reposync". The repo may still be updated by name. See "cobbler reposync" below.
+=item mirror-locally
+
+When true, specifies that this yum repo is to be referenced directly via kickstarts and not mirrored locally on the cobbler server. Only http:// and ftp:// mirror urls are supported when using --mirror-locally=1.
+
=item priority
Specifies the priority of the repository (the lower the number, the higher the priority), which applies to installed machines using the repositories that also have the yum priorities plugin installed. The default priority for the plugin is 99, as is that of all cobbler mirrored repositories.
diff --git a/webui_templates/repo_edit.tmpl b/webui_templates/repo_edit.tmpl
index 30d516d..c259a13 100644
--- a/webui_templates/repo_edit.tmpl
+++ b/webui_templates/repo_edit.tmpl
@@ -90,10 +90,24 @@ function disablename(value)
checked="true"
#end if
/>
-
Disable to prevent the mirror from being updated.
+
Uncheck to prevent the mirror from being updated again.
+
+
+
+
+
+
+
+
Uncheck to reference the repository directly instead of mirroring.
+
+
@@ -130,7 +144,7 @@ function disablename(value)
-
+
-
+
-
+
-Note: Newly added repos contain no package content until
-"cobbler reposync" is run from the command line, which means
-that profiles relying on these repositories will not install.
-Placing "cobbler reposync" on a crontab to ensure frequent
-updates is recommended procedure.
+Note: Newly added repo definitions will not be usable until
+"cobbler reposync" is run from the command line on this system.
+Placing "cobbler reposync" on a crontab is recommended procedure.
--
cgit
From a2800a1cb6dfc7c3b4a0feeacd265c147c977110 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 8 May 2008 18:20:28 -0400
Subject: Adding --virt overrides for many more additional fields that were
found in the profiles objects but not in the system objects. This needs
testing in both the webui and command line.
---
CHANGELOG | 1 +
cobbler/item_profile.py | 143 ++++----------------------------------
cobbler/item_system.py | 90 +++++++++++++++---------
cobbler/modules/cli_system.py | 18 +++--
cobbler/utils.py | 146 +++++++++++++++++++++++++++++++++++++++
cobbler/webui/CobblerWeb.py | 16 ++++-
webui_templates/system_edit.tmpl | 106 ++++++++++++++++++++++++++--
7 files changed, 347 insertions(+), 173 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 2a70394..6f46185 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -39,6 +39,7 @@ Cobbler CHANGELOG
- cobbler buildiso command to build non live ISOs
- cobbler replicate command
- added cobbler repo option --mirror-locally to reference external repos without mirroring
+- all virt parameters on profiles can now be overriden on cobbler profile objects
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index a352ce1..b472b48 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -138,46 +138,7 @@ class Profile(item.Item):
self.server = server
return True
- def set_repos(self,repos):
-
- # WARNING: hack
- repos = utils.fix_mod_python_select_submission(repos)
-
-
- # allow the magic inherit string to persist
- if repos == "<>":
- # FIXME: this is not inheritable in the WebUI presently ?
- self.repos = "<>"
- return
-
- # store as an array regardless of input type
- if repos is None:
- repolist = []
- elif type(repos) != list:
- # allow backwards compatibility support of string input
- repolist = repos.split(None)
- else:
- repolist = repos
-
-
- # make sure there are no empty strings
- try:
- repolist.remove('')
- except:
- pass
-
- self.repos = []
-
- # if any repos don't exist, fail the operation
- ok = True
- for r in repolist:
- if self.config.repos().find(name=r) is not None:
- self.repos.append(r)
- else:
- print _("warning: repository not found: %s" % r)
-
- return True
-
+
def set_kickstart(self,kickstart):
"""
Sets the kickstart. This must be a NFS, HTTP, or FTP URL.
@@ -192,108 +153,27 @@ class Profile(item.Item):
raise CX(_("kickstart not found"))
def set_virt_cpus(self,num):
- """
- For Virt only. Set the number of virtual CPUs to give to the
- virtual machine. This is fed to virtinst RAW, so cobbler
- will not yelp if you try to feed it 9999 CPUs. No formatting
- like 9,999 please :)
- """
- if num == "<>":
- self.virt_cpus = "<>"
- return True
-
- try:
- num = int(str(num))
- except:
- raise CX(_("invalid number of virtual CPUs"))
-
- self.virt_cpus = num
- return True
+ return utils.set_virt_cpus(self,num)
def set_virt_file_size(self,num):
- """
- For Virt only.
- Specifies the size of the virt image in gigabytes.
- Older versions of koan (x<0.6.3) interpret 0 as "don't care"
- Newer versions (x>=0.6.4) interpret 0 as "no disks"
- """
- # num is a non-negative integer (0 means default)
- # can also be a comma seperated list -- for usage with multiple disks
-
- if num == "<>":
- self.virt_file_size = "<>"
- return True
-
- if type(num) == str and num.find(",") != -1:
- tokens = num.split(",")
- for t in tokens:
- # hack to run validation on each
- self.set_virt_file_size(t)
- # if no exceptions raised, good enough
- self.virt_file_size = num
- return True
-
- try:
- inum = int(num)
- if inum != float(num):
- return CX(_("invalid virt file size"))
- if inum >= 0:
- self.virt_file_size = inum
- return True
- raise CX(_("invalid virt file size"))
- except:
- raise CX(_("invalid virt file size"))
-
+ return utils.set_virt_file_size(self,num)
+
def set_virt_ram(self,num):
- """
- For Virt only.
- Specifies the size of the Virt RAM in MB.
- 0 tells Koan to just choose a reasonable default.
- """
-
- if num == "<>":
- self.virt_ram = "<>"
- return True
-
- # num is a non-negative integer (0 means default)
- try:
- inum = int(num)
- if inum != float(num):
- return CX(_("invalid virt ram size"))
- if inum >= 0:
- self.virt_ram = inum
- return True
- return CX(_("invalid virt ram size"))
- except:
- return CX(_("invalid virt ram size"))
+ return utils.set_virt_ram(self,num)
def set_virt_type(self,vtype):
- """
- Virtualization preference, can be overridden by koan.
- """
-
- if vtype == "<>":
- self.virt_type == "<>"
- return True
-
- if vtype.lower() not in [ "qemu", "xenpv", "xenfv", "vmware", "auto" ]:
- raise CX(_("invalid virt type"))
- self.virt_type = vtype
- return True
+ return utils.set_virt_Type(self,vtype)
def set_virt_bridge(self,vbridge):
- """
- The default bridge for all virtual interfaces under this profile.
- """
self.virt_bridge = vbridge
return True
def set_virt_path(self,path):
- """
- Virtual storage location suggestion, can be overriden by koan.
- """
- self.virt_path = path
- return True
+ return utils.set_virt_path(self,path)
+
+ def set_repos(self,repos):
+ return utils.set_repos(self,repos)
+
def get_parent(self):
"""
@@ -375,6 +255,7 @@ class Profile(item.Item):
buf = buf + _("owners : %s\n") % self.owners
return buf
+
def remote_methods(self):
return {
'name' : self.set_name,
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 1bcc111..a97cdf6 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -38,9 +38,15 @@ class System(item.Item):
self.netboot_enabled = True
self.depth = 2
self.kickstart = "<>" # use value in profile
+ self.server = "<>" # "" (or settings)
self.virt_path = "<>" # ""
self.virt_type = "<>" # ""
- self.server = "<>" # "" (or settings)
+ self.virt_cpus = "<>" # ""
+ self.virt_file_size = "<>" # ""
+ self.virt_ram = "<>" # ""
+ self.virt_type = "<>" # ""
+ self.virt_path = "<>" # ""
+ self.virt_bridge = "<>" # ""
def delete_interface(self,name):
"""
@@ -87,11 +93,19 @@ class System(item.Item):
self.ks_meta = self.load_item(seed_data, 'ks_meta', {})
self.depth = self.load_item(seed_data, 'depth', 2)
self.kickstart = self.load_item(seed_data, 'kickstart', '<>')
- self.virt_path = self.load_item(seed_data, 'virt_path', '<>')
- self.virt_type = self.load_item(seed_data, 'virt_type', '<>')
self.netboot_enabled = self.load_item(seed_data, 'netboot_enabled', True)
self.server = self.load_item(seed_data, 'server', '<>')
+ # virt specific
+ self.virt_path = self.load_item(seed_data, 'virt_path', '<>')
+ self.virt_type = self.load_item(seed_data, 'virt_type', '<>')
+ self.virt_ram = self.load_item(seed_data,'virt_ram','<>')
+ self.virt_file_size = self.load_item(seed_data,'virt_file_size','<>')
+ self.virt_path = self.load_item(seed_data,'virt_path','<>')
+ self.virt_type = self.load_item(seed_data,'virt_type','<>')
+ self.virt_bridge = self.load_item(seed_data,'virt_bridge','<>')
+ self.virt_cpus = self.load_item(seed_data,'virt_cpus','<>')
+
# backwards compat, these settings are now part of the interfaces data structure
# and will contain data only in upgrade scenarios.
@@ -276,21 +290,20 @@ class System(item.Item):
return True
raise CX(_("invalid profile name"))
- def set_virt_path(self,path):
- """
- Virtual storage location suggestion, can be overriden by koan.
- """
- self.virt_path = path
- return True
+ def set_virt_cpus(self,num):
+ return utils.set_virt_cpus(self,num)
+
+ def set_virt_file_size(self,num):
+ return utils.set_virt_file_size(self,num)
+
+ def set_virt_ram(self,num):
+ return utils.set_virt_ram(self,num)
def set_virt_type(self,vtype):
- """
- Virtualization preference, can be overridden by koan.
- """
- if vtype.lower() not in [ "qemu", "xenpv", "xenfv", "vmware", "auto" ]:
- raise CX(_("invalid virt type"))
- self.virt_type = vtype
- return True
+ return utils.set_virt_Type(self,vtype)
+
+ def set_virt_path(self,path):
+ return utils.set_virt_path(self,path)
def set_netboot_enabled(self,netboot_enabled):
"""
@@ -347,19 +360,24 @@ class System(item.Item):
def to_datastruct(self):
return {
- 'name' : self.name,
- 'owners' : self.owners,
- 'profile' : self.profile,
- 'kernel_options' : self.kernel_options,
- 'ks_meta' : self.ks_meta,
- 'netboot_enabled' : self.netboot_enabled,
- 'parent' : self.parent,
- 'depth' : self.depth,
- 'kickstart' : self.kickstart,
- 'virt_type' : self.virt_type,
- 'virt_path' : self.virt_path,
- 'interfaces' : self.interfaces,
- 'server' : self.server
+ 'name' : self.name,
+ 'kernel_options' : self.kernel_options,
+ 'depth' : self.depth,
+ 'interfaces' : self.interfaces,
+ 'ks_meta' : self.ks_meta,
+ 'kickstart' : self.kickstart,
+ 'netboot_enabled' : self.netboot_enabled,
+ 'owners' : self.owners,
+ 'parent' : self.parent,
+ 'profile' : self.profile,
+ 'server' : self.server,
+ 'virt_cpus' : self.virt_cpus,
+ 'virt_bridge' : self.virt_bridge,
+ 'virt_file_size' : self.virt_file_size,
+ 'virt_path' : self.virt_path,
+ 'virt_ram' : self.virt_ram,
+ 'virt_type' : self.virt_type
+
}
def printable(self):
@@ -370,8 +388,14 @@ class System(item.Item):
buf = buf + _("netboot enabled? : %s\n") % self.netboot_enabled
buf = buf + _("kickstart : %s\n") % self.kickstart
- buf = buf + _("virt type : %s\n") % self.virt_type
- buf = buf + _("virt path : %s\n") % self.virt_path
+
+ buf = buf + _("virt file size : %s\n") % self.virt_file_size
+ buf = buf + _("virt ram : %s\n") % self.virt_ram
+ buf = buf + _("virt type : %s\n") % self.virt_type
+ buf = buf + _("virt path : %s\n") % self.virt_path
+ buf = buf + _("virt bridge : %s\n") % self.virt_bridge
+ buf = buf + _("virt cpus : %s\n") % self.virt_cpus
+
buf = buf + _("server : %s\n") % self.server
buf = buf + _("owners : %s\n") % self.owners
@@ -419,6 +443,10 @@ class System(item.Item):
'virt-type' : self.set_virt_type,
'modify-interface' : self.modify_interface,
'delete-interface' : self.delete_interface,
+ 'virt-path' : self.set_virt_path,
+ 'virt-type' : self.set_virt_type,
+ 'virt-bridge' : self.set_virt_bridge,
+ 'virt-cpus' : self.set_virt_cpus,
'server' : self.set_server,
'owners' : self.set_owners
}
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 419b561..6e301d1 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -70,9 +70,13 @@ class SystemFunction(commands.CobblerFunction):
p.add_option("--profile", dest="profile", help="name of cobbler profile (REQUIRED)")
p.add_option("--server-override", dest="server_override", help="overrides server value in settings file")
p.add_option("--subnet", dest="subnet", help="for static IP / templating usage")
- p.add_option("--virt-bridge", dest="virt_bridge", help="ex: virbr0")
- p.add_option("--virt-path", dest="virt_path", help="path, partition, or volume")
- p.add_option("--virt-type", dest="virt_type", help="ex: xenpv, qemu, xenfv")
+
+ p.add_option("--virt-bridge", dest="virt_bridge", help="ex: 'virbr0'")
+ p.add_option("--virt-cpus", dest="virt_cpus", help="integer (default: 1)")
+ p.add_option("--virt-file-size", dest="virt_file_size", help="size in GB")
+ p.add_option("--virt-path", dest="virt_path", help="path, partition, or volume")
+ p.add_option("--virt-ram", dest="virt_ram", help="size in MB")
+ p.add_option("--virt-type", dest="virt_type", help="ex: 'xenpv', 'qemu'")
def run(self):
@@ -89,8 +93,14 @@ class SystemFunction(commands.CobblerFunction):
if self.options.kickstart: obj.set_kickstart(self.options.kickstart)
if self.options.netboot_enabled: obj.set_netboot_enabled(self.options.netboot_enabled)
if self.options.server_override: obj.set_server(self.options.server_override)
- if self.options.virt_path: obj.set_virt_path(self.options.virt_path)
+
+ if self.options.virt_file_size: obj.set_virt_file_size(self.options.virt_file_size)
+ if self.options.virt_ram: obj.set_virt_ram(self.options.virt_ram)
+ if self.options.virt_bridge: obj.set_virt_bridge(self.options.virt_bridge)
if self.options.virt_type: obj.set_virt_type(self.options.virt_type)
+ if self.options.virt_cpus: obj.set_virt_cpus(self.options.virt_cpus)
+ if self.options.virt_path: obj.set_virt_path(self.options.virt_path)
+
if self.options.interface:
my_interface = "intf%s" % self.options.interface
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 14019e8..1b4b30a 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -631,6 +631,152 @@ def mkdir(path,mode=0777):
print oe.errno
raise CX(_("Error creating") % path)
+def set_repos(self,repos):
+ # WARNING: hack
+ repos = fix_mod_python_select_submission(repos)
+
+ # allow the magic inherit string to persist
+ if repos == "<>":
+ # FIXME: this is not inheritable in the WebUI presently ?
+ self.repos = "<>"
+ return
+
+ # store as an array regardless of input type
+ if repos is None:
+ repolist = []
+ elif type(repos) != list:
+ # allow backwards compatibility support of string input
+ repolist = repos.split(None)
+ else:
+ repolist = repos
+
+
+ # make sure there are no empty strings
+ try:
+ repolist.remove('')
+ except:
+ pass
+
+ self.repos = []
+
+ # if any repos don't exist, fail the operation
+ ok = True
+ for r in repolist:
+ if self.config.repos().find(name=r) is not None:
+ self.repos.append(r)
+ else:
+ print _("warning: repository not found: %s" % r)
+
+ return True
+
+def set_virt_file_size(self,num):
+ """
+ For Virt only.
+ Specifies the size of the virt image in gigabytes.
+ Older versions of koan (x<0.6.3) interpret 0 as "don't care"
+ Newer versions (x>=0.6.4) interpret 0 as "no disks"
+ """
+ # num is a non-negative integer (0 means default)
+ # can also be a comma seperated list -- for usage with multiple disks
+
+ if num == "<>":
+ self.virt_file_size = "<>"
+ return True
+
+ if type(num) == str and num.find(",") != -1:
+ tokens = num.split(",")
+ for t in tokens:
+ # hack to run validation on each
+ self.set_virt_file_size(t)
+ # if no exceptions raised, good enough
+ self.virt_file_size = num
+ return True
+
+ try:
+ inum = int(num)
+ if inum != float(num):
+ return CX(_("invalid virt file size"))
+ if inum >= 0:
+ self.virt_file_size = inum
+ return True
+ raise CX(_("invalid virt file size"))
+ except:
+ raise CX(_("invalid virt file size"))
+ return True
+
+def set_virt_ram(self,num):
+ """
+ For Virt only.
+ Specifies the size of the Virt RAM in MB.
+ 0 tells Koan to just choose a reasonable default.
+ """
+
+ if num == "<>":
+ self.virt_ram = "<>"
+ return True
+
+ # num is a non-negative integer (0 means default)
+ try:
+ inum = int(num)
+ if inum != float(num):
+ return CX(_("invalid virt ram size"))
+ if inum >= 0:
+ self.virt_ram = inum
+ return True
+ return CX(_("invalid virt ram size"))
+ except:
+ return CX(_("invalid virt ram size"))
+ return True
+
+def set_virt_type(self,vtype):
+ """
+ Virtualization preference, can be overridden by koan.
+ """
+
+ if vtype == "<>":
+ self.virt_type == "<>"
+ return True
+
+ if vtype.lower() not in [ "qemu", "xenpv", "xenfv", "vmware", "auto" ]:
+ raise CX(_("invalid virt type"))
+ self.virt_type = vtype
+ return True
+
+def set_virt_bridge(self,vbridge):
+ """
+ The default bridge for all virtual interfaces under this profile.
+ """
+ self.virt_bridge = vbridge
+ return True
+
+def set_virt_path(self,path):
+ """
+ Virtual storage location suggestion, can be overriden by koan.
+ """
+ self.virt_path = path
+ return True
+
+def set_virt_cpus(self,num):
+ """
+ For Virt only. Set the number of virtual CPUs to give to the
+ virtual machine. This is fed to virtinst RAW, so cobbler
+ will not yelp if you try to feed it 9999 CPUs. No formatting
+ like 9,999 please :)
+ """
+ if num == "<>":
+ self.virt_cpus = "<>"
+ return True
+
+ try:
+ num = int(str(num))
+ except:
+ raise CX(_("invalid number of virtual CPUs"))
+
+ self.virt_cpus = num
+ return True
+
+
+
if __name__ == "__main__":
# print redhat_release()
print tftpboot_location()
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index 0951633..1b52b80 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -313,7 +313,8 @@ class CobblerWeb(object):
def system_save(self,name=None,oldname=None,editmode="edit",profile=None,
new_or_edit=None,
kopts=None, ksmeta=None, owners=None, server_override=None, netboot='n',
- delete1=None, delete2=None, **args):
+ virtpath=None,virtram=None,virttype=None,virtcpus=None,virtfilesize=None,delete1=None, delete2=None, **args):
+
if not self.__xmlrpc_setup():
return self.xmlrpc_auth_failure()
@@ -363,6 +364,19 @@ class CobblerWeb(object):
if server_override:
self.remote.modify_system(system, 'server', server_override, self.token)
+ if virtfilesize:
+ self.remote.modify_system(system, 'virt-file-size', virtfilesize, self.token)
+ if virtcpus:
+ self.remote.modify_system(system, 'virt-cpus', virtcpus, self.token)
+ if virtram:
+ self.remote.modify_system(system, 'virt-ram', virtram, self.token)
+ if virttype:
+ self.remote.modify_system(system, 'virt-type', virtype, self.token)
+
+ if virtpath:
+ self.remote.modify_system(system, 'virt-path', virtpath, self.token)
+
+
for x in range(0,7):
interface = "intf%s" % x
macaddress = args.get("macaddress-%s" % interface, "")
diff --git a/webui_templates/system_edit.tmpl b/webui_templates/system_edit.tmpl
index 684c6d1..b996520 100644
--- a/webui_templates/system_edit.tmpl
+++ b/webui_templates/system_edit.tmpl
@@ -236,6 +236,106 @@ function page_onload() {
+
+
+
+
+
+
+
For virtual installs only, require this disk size in GB.
+
+
+
+
+
+
+
+
+
+
For virtual installs only, allocate this amount of RAM, in MB.
+
+
+
+
+
+
+
+
+
+ #if $system and $system.virt_type == "<>"
+ Inherit
+ #else
+ #if $system
+ Inherit
+ #else
+ Inherit
+ #end if
+ #end if
+
+
+ #if $system and $system.virt_type == "auto"
+ Any
+ #else
+ #if $system
+ Any
+ #else
+ Any
+ #end if
+ #end if
+
+ #if $system and $system.virt_type == "xenpv"
+ Xen (pv)
+ #else
+ Xen (pv)
+ #end if
+
+ #if $system and $system.virt_type == "qemu"
+ qemu/KVM
+ #else
+ qemu/KVM
+ #end if
+
What virtualization technology should koan use?
+
+
+
+
+
+
+
+
+
+
Sets koan's storage preferences, read manpage or leave blank.
+
+
+
+
+
+
+
+
+
+
How many virtual CPUs? This is an integer.
+
+
+
+
+
## ====================================== start of looping through interfaces
@@ -349,8 +449,6 @@ function page_onload() {
- ## FIXME: add virt_bridge editing (like above)
-
@@ -363,8 +461,6 @@ function page_onload() {
- ## FIXME: add subnet editing (like above)
-
@@ -377,8 +473,6 @@ function page_onload() {
- ## FIXME: add gateway editing (like above)
-
--
cgit
From 1467682551da147ff0064881c8429e3036a2f1a9 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 9 May 2008 11:02:11 -0400
Subject: Add missing file.
---
cobbler/action_replicate.py | 158 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
create mode 100644 cobbler/action_replicate.py
diff --git a/cobbler/action_replicate.py b/cobbler/action_replicate.py
new file mode 100644
index 0000000..139f18f
--- /dev/null
+++ b/cobbler/action_replicate.py
@@ -0,0 +1,158 @@
+"""
+Replicate from a cobbler master.
+
+Copyright 2007-2008, Red Hat, Inc
+Michael DeHaan
+Scott Henson
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import os.path
+import xmlrpclib
+import api as cobbler_api
+
+class Replicate:
+ def __init__(self,config):
+ """
+ Constructor
+ """
+ self.config = config
+ self.settings = config.settings()
+ self.api = config.api
+ self.remote = None
+ self.uri = None
+
+ # -------------------------------------------------------
+
+ def link_distro(self, distro):
+ """
+ Create the distro links
+ """
+ # find the tree location
+ dirname = os.path.dirname(distro.kernel)
+ tokens = dirname.split("/")
+ tokens = tokens[:-2]
+ base = "/".join(tokens)
+ dest_link = os.path.join(self.settings.webdir, "links", distro.name)
+
+ # create the links directory only if we are mirroring because with
+ # SELinux Apache can't symlink to NFS (without some doing)
+
+ if not os.path.exists(dest_link):
+ try:
+ os.symlink(base, dest_link)
+ except:
+ # this shouldn't happen but I've seen it ... debug ...
+ print _("- symlink creation failed: %(base)s, %(dest)s") % { "base" : base, "dest" : dest_link }
+
+ # -------------------------------------------------------
+
+ def add_distro(self, distro):
+ """
+ Add a distro that has been found
+ """
+ #Register the distro
+ if os.path.exists(distro['kernel']):
+ new_distro = self.api.new_distro()
+ new_distro.from_datastruct(distro)
+ #create the symlinks
+ self.link_distro(new_distro)
+ #Add the distro permanently
+ self.api.distros().add(new_distro, save=True)
+ print 'Added distro %s. Creating Links.' % distro['name']
+ else:
+ print 'Distro %s not here yet.' % distro['name']
+
+ # -------------------------------------------------------
+
+ def add_profile(self, profile):
+ """
+ Add a profile that has been found
+ """
+ #Register the new profile
+ new_profile = self.api.new_profile()
+ new_profile.from_datastruct(profile)
+ self.api.profiles().add(new_profile, save=True)
+ print 'Added profile %s.' % profile['name']
+
+
+ # -------------------------------------------------------
+
+ def check_profile(self, profile):
+ """
+ Check that a profile belongs to a distro
+ """
+ profiles = self.api.profiles().to_datastruct()
+ if profile not in profiles:
+ for distro in self.api.distros().to_datastruct():
+ if distro['name'] == profile['name']:
+ return True
+ return False
+
+
+ # -------------------------------------------------------
+
+ def sync_distros(self):
+ """
+ Sync distros from master
+ """
+ local_distros = self.api.distros()
+ remote_distros = self.remote.get_distros()
+
+ needsync = False
+ for distro in remote_distros:
+ if distro not in local_distros.to_datastruct():
+ print 'Found distro %s.' % distro['name']
+ self.add_distro(distro)
+ needsync = True
+
+ self.call_sync(needsync)
+
+
+ # -------------------------------------------------------
+
+ def sync_profiles(self):
+ """
+ Sync profiles from master
+ """
+ local_profiles = self.api.profiles()
+ remote_profiles = self.remote.get_profiles()
+
+ needsync = False
+ for profile in remote_profiles:
+ if self.check_profile(profile):
+ print 'Found profile %s.' % profilew['name']
+ self.add_profile(profile)
+ needsync = True
+ self.call_sync(needsync)
+
+
+ # -------------------------------------------------------
+
+ def call_sync(self, needsync):
+ if needsync:
+ self.api.sync()
+
+ # -------------------------------------------------------
+
+ def run(self, cobbler_master=None):
+ """
+ Get remote profiles and distros and sync them locally
+ """
+ if cobbler_master is not None:
+ self.uri = 'http://%s/cobbler_api' % cobbler_master
+ elif len(self.settings.cobbler_master) > 0:
+ self.uri = 'http://%s/cobbler_api' % self.settings.cobbler_master
+
+ if self.uri is not None:
+ self.remote = xmlrpclib.Server(self.uri)
+ self.sync_distros()
+ self.sync_profiles()
+
--
cgit
From cb19415d6574f91410cab56d50bbff9871edb4ce Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 9 May 2008 11:10:34 -0400
Subject: Apply patch to rework bind zone handling.
---
cobbler/modules/manage_bind.py | 120 +++++++++++++++++++++++++----------------
docs/cobbler.pod | 2 +-
2 files changed, 74 insertions(+), 48 deletions(-)
diff --git a/cobbler/modules/manage_bind.py b/cobbler/modules/manage_bind.py
index e14122a..339fbf0 100644
--- a/cobbler/modules/manage_bind.py
+++ b/cobbler/modules/manage_bind.py
@@ -23,6 +23,7 @@ import glob
import traceback
import errno
import popen2
+import re
from shlex import shlex
@@ -69,9 +70,13 @@ class BindManager:
def __forward_zones(self):
"""
- Returns ALL forward zones for all systems
+ Returns a map of zones and the records that belong
+ in them
"""
zones = {}
+ for zone in self.settings.manage_forward_zones:
+ zones[zone] = []
+
for sys in self.systems:
for (name, interface) in sys.interfaces.iteritems():
host = interface["hostname"]
@@ -81,19 +86,45 @@ class BindManager:
continue
if host.find(".") == -1:
continue
- tokens = host.split('.')
- zone = '.'.join(tokens[1:])
- if zones.has_key(zone):
- zones[zone].append((host.split('.')[0], ip))
- else:
- zones[zone] = [(host.split('.')[0], ip)]
+
+ # match the longest zone!
+ # e.g. if you have a host a.b.c.d.e
+ # if manage_forward_zones has:
+ # - c.d.e
+ # - b.c.d.e
+ # then a.b.c.d.e should go in b.c.d.e
+ best_match = ''
+ for zone in zones.keys():
+ if re.search('\.%s$' % zone, host) and len(zone) > len(best_match):
+ best_match = zone
+
+ if best_match == '': # no match
+ continue
+
+ # strip the zone off the hostname and append the
+ # remainder + ip to the zone list
+ host = host.replace(best_match, '')
+ if host[-1] == '.': # strip trailing '.' if it's there
+ host = host[:-1]
+ zones[best_match].append((host, ip))
+
+ # axe zones that are defined in manage_forward_zones
+ # but don't actually match any hosts
+ for (k,v) in zones.items():
+ if v == []:
+ zones.pop(k)
+
return zones
def __reverse_zones(self):
"""
- Returns ALL reverse zones for all systems
+ Returns a map of zones and the records that belong
+ in them
"""
zones = {}
+ for zone in self.settings.manage_reverse_zones:
+ zones[zone] = []
+
for sys in self.systems:
for (name, interface) in sys.interfaces.iteritems():
host = interface["hostname"]
@@ -101,45 +132,40 @@ class BindManager:
if not host or not ip:
# gotsta have some hostname and ip or else!
continue
+
+ # match the longest zone!
+ # e.g. if you have an ip 1.2.3.4
+ # if manage_reverse_zones has:
+ # - 1.2
+ # - 1.2.3
+ # then 1.2.3.4 should go in 1.2.3
+ best_match = ''
+ for zone in zones.keys():
+ if re.search('^%s\.' % zone, ip) and len(zone) > len(best_match):
+ best_match = zone
+
+ if best_match == '': # no match
+ continue
+
+ # strip the zone off the front of the ip
+ # reverse the rest of the octets
+ # append the remainder + hostname
+ ip = ip.replace(best_match, '', 1)
+ if ip[0] == '.': # strip leading '.' if it's there
+ ip = ip[1:]
tokens = ip.split('.')
- zone = '.'.join(tokens[0:3])
- if zones.has_key(zone):
- zones[zone].append((tokens[3], host + '.'))
- else:
- zones[zone] = [(tokens[3], host + '.')]
- return zones
+ tokens.reverse()
+ ip = '.'.join(tokens)
+ zones[best_match].append((ip, host + '.'))
- def __config_forward_zones(self):
- """
- Returns only the forward zones which have systems and are defined
- in the option manage_forward_zones
+ # axe zones that are defined in manage_forward_zones
+ # but don't actually match any hosts
+ for (k,v) in zones.items():
+ if v == []:
+ zones.pop(k)
- Alternatively if manage_forward_zones is empty, return all systems
- """
- all = self.__forward_zones()
- want = self.settings.manage_forward_zones
- if want == []: return all
- ret = {}
- for zone in all.keys():
- if zone in want:
- ret[zone] = all[zone]
- return ret
-
- def __config_reverse_zones(self):
- """
- Returns only the reverse zones which have systems and are defined
- in the option manage_reverse_zones
+ return zones
- Alternatively if manage_reverse_zones is empty, return all systems
- """
- all = self.__reverse_zones()
- want = self.settings.manage_reverse_zones
- if want == []: return all
- ret = {}
- for zone in all.keys():
- if zone in want:
- ret[zone] = all[zone]
- return ret
def __write_named_conf(self):
"""
@@ -151,7 +177,7 @@ class BindManager:
reverse_zones = self.settings.manage_reverse_zones
metadata = {'zone_include': ''}
- for zone in self.__config_forward_zones().keys():
+ for zone in self.__forward_zones().keys():
txt = """
zone "%(zone)s." {
type master;
@@ -160,7 +186,7 @@ zone "%(zone)s." {
""" % {'zone': zone}
metadata['zone_include'] = metadata['zone_include'] + txt
- for zone in self.__config_reverse_zones().keys():
+ for zone in self.__reverse_zones().keys():
tokens = zone.split('.')
tokens.reverse()
arpa = '.'.join(tokens) + '.in-addr.arpa'
@@ -189,8 +215,8 @@ zone "%(arpa)s." {
default_template_file = "/etc/cobbler/zone.template"
cobbler_server = self.settings.server
serial = int(time.time())
- forward = self.__config_forward_zones()
- reverse = self.__config_reverse_zones()
+ forward = self.__forward_zones()
+ reverse = self.__reverse_zones()
try:
f2 = open(default_template_file,"r")
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index 9f5154e..72836f0 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -565,7 +565,7 @@ Cobbler can optionally manage DNS configuration using BIND and dnsmasq.
Choose either "management = isc_and_bind" or "management = dnsmasq" in /etc/cobbler/modules.conf and then enable manage_dns in /var/lib/cobbler/settings.
-This feature is off by default. If using BIND, you may restrict the scope of zones managed with the options 'manage_forward_zones' and 'manage_reverse_zones'. (See the Wiki for more information on this).
+This feature is off by default. If using BIND, you must define the zones to be managed with the options 'manage_forward_zones' and 'manage_reverse_zones'. (See the Wiki for more information on this).
If using BIND, Cobbler will use /etc/cobbler/bind.template and /etc/cobbler/zone.template as a starting point for the named.conf and individual zone files, respectively. You may drop zone-specific template files in /etc/cobbler/zone_templates/name-of-zone which will override the default. These files must be user edited for the user's particular networking environment. Read the file and understand how BIND works before proceeding.
--
cgit
From 9c5b5e8502c3350f358129e0c1983efa5efdd9cc Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 9 May 2008 11:54:24 -0400
Subject: Fixes for virt overrides on system objects.
---
cobbler/item_distro.py | 6 +++---
cobbler/item_profile.py | 16 ++++++++--------
cobbler/item_repo.py | 8 ++++----
cobbler/item_system.py | 19 +++++++++----------
cobbler/modules/cli_system.py | 1 -
5 files changed, 24 insertions(+), 26 deletions(-)
diff --git a/cobbler/item_distro.py b/cobbler/item_distro.py
index 1e392a5..1a4c296 100644
--- a/cobbler/item_distro.py
+++ b/cobbler/item_distro.py
@@ -180,12 +180,12 @@ class Distro(item.Item):
kstr = utils.find_kernel(self.kernel)
istr = utils.find_initrd(self.initrd)
buf = _("distro : %s\n") % self.name
- buf = buf + _("kernel : %s\n") % kstr
+ buf = buf + _("breed : %s\n") % self.breed
+ buf = buf + _("architecture : %s\n") % self.arch
buf = buf + _("initrd : %s\n") % istr
+ buf = buf + _("kernel : %s\n") % kstr
buf = buf + _("kernel options : %s\n") % self.kernel_options
- buf = buf + _("architecture : %s\n") % self.arch
buf = buf + _("ks metadata : %s\n") % self.ks_meta
- buf = buf + _("breed : %s\n") % self.breed
buf = buf + _("owners : %s\n") % self.owners
return buf
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index b472b48..019f01a 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -240,19 +240,19 @@ class Profile(item.Item):
buf = buf + _("parent : %s\n") % self.parent
else:
buf = buf + _("distro : %s\n") % self.distro
- buf = buf + _("kickstart : %s\n") % self.kickstart
+ buf = buf + _("dhcp tag : %s\n") % self.dhcp_tag
buf = buf + _("kernel options : %s\n") % self.kernel_options
+ buf = buf + _("kickstart : %s\n") % self.kickstart
buf = buf + _("ks metadata : %s\n") % self.ks_meta
+ buf = buf + _("owners : %s\n") % self.owners
+ buf = buf + _("repos : %s\n") % self.repos
+ buf = buf + _("server : %s\n") % self.server
+ buf = buf + _("virt bridge : %s\n") % self.virt_bridge
+ buf = buf + _("virt cpus : %s\n") % self.virt_cpus
buf = buf + _("virt file size : %s\n") % self.virt_file_size
+ buf = buf + _("virt path : %s\n") % self.virt_path
buf = buf + _("virt ram : %s\n") % self.virt_ram
buf = buf + _("virt type : %s\n") % self.virt_type
- buf = buf + _("virt path : %s\n") % self.virt_path
- buf = buf + _("virt bridge : %s\n") % self.virt_bridge
- buf = buf + _("virt cpus : %s\n") % self.virt_cpus
- buf = buf + _("repos : %s\n") % self.repos
- buf = buf + _("dhcp tag : %s\n") % self.dhcp_tag
- buf = buf + _("server : %s\n") % self.server
- buf = buf + _("owners : %s\n") % self.owners
return buf
diff --git a/cobbler/item_repo.py b/cobbler/item_repo.py
index ba32a07..3b9b839 100644
--- a/cobbler/item_repo.py
+++ b/cobbler/item_repo.py
@@ -189,14 +189,14 @@ class Repo(item.Item):
def printable(self):
buf = _("repo : %s\n") % self.name
- buf = buf + _("owners : %s\n") % self.owners
+ buf = buf + _("arch : %s\n") % self.arch
+ buf = buf + _("createrepo_flags : %s\n") % self.createrepo_flags
+ buf = buf + _("keep updated : %s\n") % self.keep_updated
buf = buf + _("mirror : %s\n") % self.mirror
buf = buf + _("mirror locally : %s\n") % self.mirror_locally
- buf = buf + _("keep updated : %s\n") % self.keep_updated
+ buf = buf + _("owners : %s\n") % self.owners
buf = buf + _("priority : %s\n") % self.priority
buf = buf + _("rpm list : %s\n") % self.rpm_list
- buf = buf + _("createrepo_flags : %s\n") % self.createrepo_flags
- buf = buf + _("arch : %s\n") % self.arch
buf = buf + _("yum options : %s\n") % self.yumopts
return buf
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index a97cdf6..6effc22 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -300,7 +300,7 @@ class System(item.Item):
return utils.set_virt_ram(self,num)
def set_virt_type(self,vtype):
- return utils.set_virt_Type(self,vtype)
+ return utils.set_virt_type(self,vtype)
def set_virt_path(self,path):
return utils.set_virt_path(self,path)
@@ -384,20 +384,19 @@ class System(item.Item):
buf = _("system : %s\n") % self.name
buf = buf + _("profile : %s\n") % self.profile
buf = buf + _("kernel options : %s\n") % self.kernel_options
+ buf = buf + _("kickstart : %s\n") % self.kickstart
buf = buf + _("ks metadata : %s\n") % self.ks_meta
buf = buf + _("netboot enabled? : %s\n") % self.netboot_enabled
- buf = buf + _("kickstart : %s\n") % self.kickstart
+ buf = buf + _("owners : %s\n") % self.owners
+ buf = buf + _("server : %s\n") % self.server
- buf = buf + _("virt file size : %s\n") % self.virt_file_size
- buf = buf + _("virt ram : %s\n") % self.virt_ram
- buf = buf + _("virt type : %s\n") % self.virt_type
- buf = buf + _("virt path : %s\n") % self.virt_path
- buf = buf + _("virt bridge : %s\n") % self.virt_bridge
- buf = buf + _("virt cpus : %s\n") % self.virt_cpus
+ buf = buf + _("virt cpus : %s\n") % self.virt_cpus
+ buf = buf + _("virt file size : %s\n") % self.virt_file_size
+ buf = buf + _("virt path : %s\n") % self.virt_path
+ buf = buf + _("virt ram : %s\n") % self.virt_ram
+ buf = buf + _("virt type : %s\n") % self.virt_type
- buf = buf + _("server : %s\n") % self.server
- buf = buf + _("owners : %s\n") % self.owners
counter = 0
for (name,x) in self.interfaces.iteritems():
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 6e301d1..d8f8edf 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -96,7 +96,6 @@ class SystemFunction(commands.CobblerFunction):
if self.options.virt_file_size: obj.set_virt_file_size(self.options.virt_file_size)
if self.options.virt_ram: obj.set_virt_ram(self.options.virt_ram)
- if self.options.virt_bridge: obj.set_virt_bridge(self.options.virt_bridge)
if self.options.virt_type: obj.set_virt_type(self.options.virt_type)
if self.options.virt_cpus: obj.set_virt_cpus(self.options.virt_cpus)
if self.options.virt_path: obj.set_virt_path(self.options.virt_path)
--
cgit
From f4a1f5f2f62b5b75a0a327056ea9f34e72e7a50f Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 9 May 2008 12:32:55 -0400
Subject: Fixes for webapp new fields
---
cobbler/item_system.py | 3 ++-
cobbler/webui/CobblerWeb.py | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 6effc22..e7d6ed6 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -443,9 +443,10 @@ class System(item.Item):
'modify-interface' : self.modify_interface,
'delete-interface' : self.delete_interface,
'virt-path' : self.set_virt_path,
+ 'virt-ram' : self.set_virt_ram,
'virt-type' : self.set_virt_type,
- 'virt-bridge' : self.set_virt_bridge,
'virt-cpus' : self.set_virt_cpus,
+ 'virt-file-size' : self.set_virt_file_size,
'server' : self.set_server,
'owners' : self.set_owners
}
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
index 1b52b80..d272281 100644
--- a/cobbler/webui/CobblerWeb.py
+++ b/cobbler/webui/CobblerWeb.py
@@ -371,7 +371,7 @@ class CobblerWeb(object):
if virtram:
self.remote.modify_system(system, 'virt-ram', virtram, self.token)
if virttype:
- self.remote.modify_system(system, 'virt-type', virtype, self.token)
+ self.remote.modify_system(system, 'virt-type', virttype, self.token)
if virtpath:
self.remote.modify_system(system, 'virt-path', virtpath, self.token)
--
cgit
From 34fc9d39389ed2a949b0efbeea246f30a10c0265 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 9 May 2008 13:11:07 -0400
Subject: Added some additional links for kickstart viewing/editing to the
profile/system web pages
---
CHANGELOG | 1 +
cobbler/action_reposync.py | 2 +-
cobbler/item_profile.py | 2 +-
cobbler/kickgen.py | 5 ++++-
webui_templates/profile_list.tmpl | 19 ++++++++++++++++++-
webui_templates/system_list.tmpl | 24 +++++++++++++++++++++---
6 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 6f46185..79b35d5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -40,6 +40,7 @@ Cobbler CHANGELOG
- cobbler replicate command
- added cobbler repo option --mirror-locally to reference external repos without mirroring
- all virt parameters on profiles can now be overriden on cobbler profile objects
+- added some additional links for kickstart viewing/editing to the web page
- ??? - 0.8.3
- Make createrepo get run for local cobbler reposync invocations as needed
diff --git a/cobbler/action_reposync.py b/cobbler/action_reposync.py
index 33bfe30..d6b30bc 100644
--- a/cobbler/action_reposync.py
+++ b/cobbler/action_reposync.py
@@ -254,7 +254,7 @@ class RepoSync:
if repo.mirror_locally:
line = "baseurl=http://${server}/cobbler/repo_mirror/%s\n" % (repo.name)
else:
- line = "baseurl=%s" % (repo.mirror)
+ line = "baseurl=%s\n" % (repo.mirror)
config_file.write(line)
# user may have options specific to certain yum plugins
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index 019f01a..c5c9bdb 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -162,7 +162,7 @@ class Profile(item.Item):
return utils.set_virt_ram(self,num)
def set_virt_type(self,vtype):
- return utils.set_virt_Type(self,vtype)
+ return utils.set_virt_type(self,vtype)
def set_virt_bridge(self,vbridge):
self.virt_bridge = vbridge
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index a9bc095..ba8bfd2 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -170,7 +170,10 @@ class KickGen:
if line.find("ks_mirror") != -1:
ret = True
if line.find("baseurl") != -1:
- first, baseurl = line.split("=")
+ try:
+ first, baseurl = line.split("=",1)
+ except:
+ raise CX(_("error scanning repo: %s" % filename))
fd.close()
return (ret, baseurl)
diff --git a/webui_templates/profile_list.tmpl b/webui_templates/profile_list.tmpl
index f213775..fefe753 100644
--- a/webui_templates/profile_list.tmpl
+++ b/webui_templates/profile_list.tmpl
@@ -38,7 +38,24 @@
$profile.parent
#end if
-
$profile.kickstart
+
+ #if $profile.kickstart and $profile.kickstart !=""
+ #set $kick = $profile.kickstart
+ #if $kick.startswith("http://") or $kick.startswith("ftp://") or $kick.startswith("nfs://")
+ #if not $kick.startswith("nfs://")
+ $kick
+ #else
+ $kick
+ #end if
+ #else
+ #set $name = $profile.name
+ (view rendered)
+ #if $kick != "" and $kick != "<>":
+ (edit template)
+ #end if
+ #end if
+ #end if
+
- ## FIXME: how to handle for multiple interface listing?
MAC
- ##
IP
- ##
Hostname
+
Kickstart
@@ -39,7 +37,27 @@
##
${system.mac_address}
##
${system.ip_address}
##
${system.hostname}
+
+
+ #set $kick = $system.kickstart
+ #if $kick.startswith("http://") or $kick.startswith("ftp://") or $kick.startswith("nfs://")
+ #if not $kick.startswith("nfs://")
+ $kick
+ #else
+ $kick
+ #end if
+ #else
+ #set $name = $system.name
+ #set $pname = $system.profile
+ (view rendered)
+ #if $kick != "<>" and $kick != ""
+ (edit template)
+ #end if
+ #end if
+
+
+
#end for
--
cgit
From 402ff49f5dd70671575e25d5224792f59a0c8408 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 9 May 2008 15:12:55 -0400
Subject: Release bump for test release
---
CHANGELOG | 2 +-
cobbler.spec | 4 ++--
setup.py | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 79b35d5..f08b74a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,7 +1,7 @@
Cobbler CHANGELOG
(all entries mdehaan@redhat.com unless noted otherwise)
-- Mon Mar 10 2008 - 0.9.0
+- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
- applied patch to send hostname from ISC
- added patch to allow --kopts/--ksmeta items to be cleared with --kopts=delete
diff --git a/cobbler.spec b/cobbler.spec
index 2d0cc15..5b23ec2 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -2,7 +2,7 @@
Summary: Boot server configurator
Name: cobbler
AutoReq: no
-Version: 0.9.0
+Version: 0.9.1
Release: 1%{?dist}
Source0: %{name}-%{version}.tar.gz
License: GPLv2+
@@ -188,7 +188,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
-* Tue Apr 08 2008 Michael DeHaan - 0.9.0-1
+* Fri May 09 2008 Michael DeHaan - 0.9.1-1
- Upstream changes (see CHANGELOG)
- packaged /etc/cobbler/users.conf
- remaining CGI replaced with mod_python
diff --git a/setup.py b/setup.py
index 07d9880..57c28ad 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ import sys
from distutils.core import setup, Extension
import string
-VERSION = "0.9.0"
+VERSION = "0.9.1"
SHORT_DESC = "Network Boot and Update Server"
LONG_DESC = """
Cobbler is a network boot and update server. Cobbler supports PXE, provisioning virtualized images, and reinstalling existing Linux machines. The last two modes require a helper tool called 'koan' that integrates with cobbler. Cobbler's advanced features include importing distributions from DVDs and rsync mirrors, kickstart templating, integrated yum mirroring, and built-in DHCP Management. Cobbler has a Python API for integration with other GPL systems management applications.
--
cgit
From bdcdc5b244ea5deb35ff92787e1fb4068968d9dd Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 12 May 2008 14:15:40 -0400
Subject: Apply patch to remove anti-createrepo conditions, bump version.
---
CHANGELOG | 3 +++
cobbler.spec | 5 ++++-
cobbler/action_reposync.py | 2 +-
setup.py | 2 +-
4 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index f08b74a..049ead8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
Cobbler CHANGELOG
(all entries mdehaan@redhat.com unless noted otherwise)
+- Mon May 12 2008 - 0.9.2
+- run createrepo with less preconditions during cobbler reposync
+
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
- applied patch to send hostname from ISC
diff --git a/cobbler.spec b/cobbler.spec
index 5b23ec2..51ea3aa 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -2,7 +2,7 @@
Summary: Boot server configurator
Name: cobbler
AutoReq: no
-Version: 0.9.1
+Version: 0.9.2
Release: 1%{?dist}
Source0: %{name}-%{version}.tar.gz
License: GPLv2+
@@ -188,6 +188,9 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
+* Mon May 12 2008 Michael DeHaan - 0.9.2-1
+- Upstream changes (see CHANGELOG)
+
* Fri May 09 2008 Michael DeHaan - 0.9.1-1
- Upstream changes (see CHANGELOG)
- packaged /etc/cobbler/users.conf
diff --git a/cobbler/action_reposync.py b/cobbler/action_reposync.py
index d6b30bc..495aa3a 100644
--- a/cobbler/action_reposync.py
+++ b/cobbler/action_reposync.py
@@ -285,7 +285,7 @@ class RepoSync:
"""
Used to run createrepo on a copied mirror.
"""
- if os.path.exists(os.path.join(dirname,"RPMS")) or repo.is_rsync_mirror():
+ if os.path.exists(dirname) or repo.is_rsync_mirror():
utils.remove_yum_olddata(dirname)
try:
cmd = "createrepo %s %s" % (repo.createrepo_flags, dirname)
diff --git a/setup.py b/setup.py
index 57c28ad..7b11c78 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ import sys
from distutils.core import setup, Extension
import string
-VERSION = "0.9.1"
+VERSION = "0.9.2"
SHORT_DESC = "Network Boot and Update Server"
LONG_DESC = """
Cobbler is a network boot and update server. Cobbler supports PXE, provisioning virtualized images, and reinstalling existing Linux machines. The last two modes require a helper tool called 'koan' that integrates with cobbler. Cobbler's advanced features include importing distributions from DVDs and rsync mirrors, kickstart templating, integrated yum mirroring, and built-in DHCP Management. Cobbler has a Python API for integration with other GPL systems management applications.
--
cgit
From aaf52ab85b518d8c6b4ed0211b69d6be531ae5a9 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 12 May 2008 14:27:06 -0400
Subject: Patch for replicate error handling + docs
---
CHANGELOG | 1 +
cobbler/action_replicate.py | 4 +++-
docs/cobbler.pod | 8 ++++++++
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG b/CHANGELOG
index 049ead8..95156a5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@ Cobbler CHANGELOG
- Mon May 12 2008 - 0.9.2
- run createrepo with less preconditions during cobbler reposync
+- doc upgrades and error handling for "cobbler replicate"
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/action_replicate.py b/cobbler/action_replicate.py
index 139f18f..ae3adc8 100644
--- a/cobbler/action_replicate.py
+++ b/cobbler/action_replicate.py
@@ -17,6 +17,7 @@ import os
import os.path
import xmlrpclib
import api as cobbler_api
+from utils import _
class Replicate:
def __init__(self,config):
@@ -150,7 +151,8 @@ class Replicate:
self.uri = 'http://%s/cobbler_api' % cobbler_master
elif len(self.settings.cobbler_master) > 0:
self.uri = 'http://%s/cobbler_api' % self.settings.cobbler_master
-
+ else:
+ print _('No cobbler master found to replicate from, try --master.')
if self.uri is not None:
self.remote = xmlrpclib.Server(self.uri)
self.sync_distros()
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index 72836f0..ce5cb0d 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -399,6 +399,14 @@ Objects can also be renamed, as long as other objects don't reference them.
B
+=head2 REPLICATING
+
+Cobbler can replicate distro and profile data from a master cobbler server.
+
+B
+
+This will bring over all distro data for which it can find data in /var/www/cobbler/ks_mirror can be found. It will also bring over any default profiles for those distros. A default cobbler master can be set in the settings file. Tree data must still be rsync'd (or otherwise mirrored) manually.
+
=head2 REBUILDING CONFIGURATIONS
B
--
cgit
From b3e6aa54f75dba69ea58797c04751b104b406136 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 12 May 2008 16:12:29 -0400
Subject: Make duplicate mac checking work in more places, nicer error when
encountering rootsquash.
---
CHANGELOG | 1 +
cobbler/commands.py | 11 ++++++-----
cobbler/utils.py | 11 +++++++----
3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 95156a5..729ec7f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@ Cobbler CHANGELOG
- Mon May 12 2008 - 0.9.2
- run createrepo with less preconditions during cobbler reposync
- doc upgrades and error handling for "cobbler replicate"
+- improved error message that occurs when copying from nfs w/ rootsquash
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/commands.py b/cobbler/commands.py
index 657934c..705249d 100644
--- a/cobbler/commands.py
+++ b/cobbler/commands.py
@@ -295,11 +295,12 @@ class CobblerFunction:
else:
rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_names=False, check_for_duplicate_netinfo=False)
else:
- # editing or copying (but not renaming), so duplicate netinfo
- # CAN be bad, duplicate names are already handled, though
- # we need to clean up checks around duplicate netinfo here
- # (FIXME) so they are made and work.
- rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers)
+ check_dup = False
+ if not "copy" in self.args:
+ check_dup = True
+ # FIXME: this ensures duplicate prevention on copy, but not
+ # rename?
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers, check_for_duplicate_netinfo=check_dup)
else:
# we are renaming here, so duplicate netinfo checks also
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 1b4b30a..a9b374f 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -590,10 +590,13 @@ def copyfile(src,dst):
try:
return shutil.copyfile(src,dst)
except:
- if not os.path.samefile(src,dst):
- # accomodate for the possibility that we already copied
- # the file as a symlink/hardlink
- raise CX(_("Error copying %(src)s to %(dst)s") % { "src" : src, "dst" : dst})
+ try:
+ if not os.path.samefile(src,dst):
+ # accomodate for the possibility that we already copied
+ # the file as a symlink/hardlink
+ raise CX(_("Error copying %(src)s to %(dst)s") % { "src" : src, "dst" : dst})
+ except:
+ raise CX(_("Problems reading %(src)s") % { "src" : src})
def rmfile(path):
try:
--
cgit
From 044efca218e1a05206fa659bb6a15597cb074bd9 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 12 May 2008 16:13:10 -0400
Subject: keep changelog up to date
---
CHANGELOG | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG b/CHANGELOG
index 729ec7f..f1d3164 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ Cobbler CHANGELOG
- run createrepo with less preconditions during cobbler reposync
- doc upgrades and error handling for "cobbler replicate"
- improved error message that occurs when copying from nfs w/ rootsquash
+- mac duplication checking improvements for CLI
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
--
cgit
From 6cc83a05f80d7f3c703aa8743ccacab2aa2ac86d Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Mon, 12 May 2008 17:20:22 -0400
Subject: Added code to cobbler check to look for httpd_can_network_connect
boolean if SELinux is enabled.
---
CHANGELOG | 1 +
cobbler/action_check.py | 14 ++++++++++++++
2 files changed, 15 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index f1d3164..e28d6eb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,7 @@ Cobbler CHANGELOG
- doc upgrades and error handling for "cobbler replicate"
- improved error message that occurs when copying from nfs w/ rootsquash
- mac duplication checking improvements for CLI
+- add warning to cobbler check if selinux is on and Apache boolean not set
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 9fe0543..29b39be 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -36,6 +36,7 @@ class BootCheck:
"""
status = []
self.check_name(status)
+ self.check_selinux(status)
if self.settings.manage_dhcp:
mode = self.config.api.get_sync().dhcp.what()
if mode == "isc":
@@ -106,6 +107,19 @@ class BootCheck:
if self.settings.next_server == "127.0.0.1":
status.append(_("For PXE to be functional, the 'next_server' field in /var/lib/cobbler/settings must be set to something other than 127.0.0.1, and should match the IP of the boot server on the PXE network."))
+ def check_selinux(self,status):
+ prc = sub_process.Popen("/usr/sbin/getenforce",shell=True,stdout=sub_process.PIPE)
+ data = prc.communicate()[0]
+ if data.lower().find("disabled") == -1:
+ # permissive or enforcing or something else
+ prc2 = sub_process.Popen("/usr/sbin/getsebool -a",shell=True,stdout=sub_process.PIPE)
+ data2 = prc2.communicate()[0]
+ for line in data2.split("\n"):
+ if line.find("httpd_can_network_connect ") != -1:
+ if line.find("off") != -1:
+ status.append(_("Must enable selinux boolean to enable Apache and web services components, run: setsebool -P httpd_can_network_connect true"))
+
+
def check_httpd(self,status):
"""
Check if Apache is installed.
--
cgit
From 5daab278a734ed9679ef1e7aaa51a62e82292b85 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 13 May 2008 11:59:22 -0400
Subject: Added code to cobbler check to see if any templates are still using
the default password, and if so, to warn about them.
---
CHANGELOG | 1 +
cobbler/action_check.py | 14 ++++++++++++++
cobbler/api.py | 3 +++
cobbler/remote.py | 12 +-----------
cobbler/utils.py | 15 +++++++++++++++
5 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index e28d6eb..500ff77 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,7 @@ Cobbler CHANGELOG
- improved error message that occurs when copying from nfs w/ rootsquash
- mac duplication checking improvements for CLI
- add warning to cobbler check if selinux is on and Apache boolean not set
+- added warning to cobbler check if templates use the default password
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 29b39be..5691d60 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -65,6 +65,7 @@ class BootCheck:
self.check_httpd(status)
self.check_iptables(status)
self.check_yum(status)
+ self.check_for_default_password(status)
return status
@@ -120,6 +121,19 @@ class BootCheck:
status.append(_("Must enable selinux boolean to enable Apache and web services components, run: setsebool -P httpd_can_network_connect true"))
+ def check_for_default_password(self,status):
+ templates = utils.get_kickstart_templates(self.config.api)
+ files = []
+ for t in templates:
+ fd = open(t)
+ data = fd.read()
+ fd.close()
+ if data.find("\$1\$mF86/UHC\$WvcIcX2t6crBz2onWxyac."):
+ files.append(t)
+ if len(files) > 0:
+ status.append(_("One or more kickstart templates references default password 'cobbler' and should be changed for security reasons: %s") % ", ".join(files))
+
+
def check_httpd(self,status):
"""
Check if Apache is installed.
diff --git a/cobbler/api.py b/cobbler/api.py
index 1b73acd..a2aa881 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -442,3 +442,6 @@ class BootAPI:
replicator = action_replicate.Replicate(self._config)
return replicator.run(cobbler_master = cobbler_master)
+ def get_kickstart_templates(self):
+ return utils.get_kickstar_templates(self)
+
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 87695d2..8cf9ba3 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -170,17 +170,7 @@ class CobblerXMLRPCInterface:
"""
self.log("get_kickstart_templates",token=token)
self.check_access(token, "get_kickstart_templates")
- files = {}
- for x in self.api.profiles():
- if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
- files[x.kickstart] = 1
- for x in self.api.systems():
- if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
- files[x.kickstart] = 1
- for x in glob.glob("/var/lib/cobbler/kickstarts/*"):
- files[x] = 1
-
- return files.keys()
+ return utils.get_kickstart_templates(self.api)
def is_kickstart_in_use(self,ks,token):
self.log("is_kickstart_in_use",token=token)
diff --git a/cobbler/utils.py b/cobbler/utils.py
index a9b374f..112d94b 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -778,6 +778,21 @@ def set_virt_cpus(self,num):
self.virt_cpus = num
return True
+def get_kickstart_templates(api):
+ files = {}
+ for x in api.profiles():
+ if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
+ files[x.kickstart] = 1
+ for x in api.systems():
+ if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
+ files[x.kickstart] = 1
+ for x in glob.glob("/var/lib/cobbler/kickstarts/*"):
+ files[x] = 1
+ for x in glob.glob("/etc/cobbler/*.ks"):
+ files[x] = 1
+
+ return files.keys()
+
if __name__ == "__main__":
--
cgit
From 58d126f8e2430d2d47e6e204f7866b9ee60426bf Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 13 May 2008 12:00:14 -0400
Subject: Fix find test.
---
cobbler/action_check.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 5691d60..044b56b 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -128,7 +128,7 @@ class BootCheck:
fd = open(t)
data = fd.read()
fd.close()
- if data.find("\$1\$mF86/UHC\$WvcIcX2t6crBz2onWxyac."):
+ if data.find("\$1\$mF86/UHC\$WvcIcX2t6crBz2onWxyac.") != -1:
files.append(t)
if len(files) > 0:
status.append(_("One or more kickstart templates references default password 'cobbler' and should be changed for security reasons: %s") % ", ".join(files))
--
cgit
From 045957209b62b2ab40a1bcdee0549ea54074bc48 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 13 May 2008 12:21:29 -0400
Subject: Allows cobbler system kickstart to be reset by setting them to "",
"delete", or None (the last via the API). This allows the system to use the
profile's kickstart setting as expected.
---
CHANGELOG | 1 +
cobbler/item_system.py | 3 +++
2 files changed, 4 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 500ff77..48fe825 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,7 @@ Cobbler CHANGELOG
- mac duplication checking improvements for CLI
- add warning to cobbler check if selinux is on and Apache boolean not set
- added warning to cobbler check if templates use the default password
+- setting per-system kickstart template to "" or "delete" restores inheritance
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index e7d6ed6..94ec392 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -352,6 +352,9 @@ class System(item.Item):
abstraction layer -- assigning systems to defined and repeatable
roles.
"""
+ if kickstart is None or kickstart == "" or kickstart == "delete":
+ self.kickstart = "<>"
+ return True
if utils.find_kickstart(kickstart):
self.kickstart = kickstart
return True
--
cgit
From 480798fdccd1d0bb5c4b160333f0933dc463053e Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 13 May 2008 15:45:13 -0400
Subject: Consolidate various repo related warnings under cobbler check and
clean up prints elsewhere.
---
CHANGELOG | 2 ++
cobbler/action_check.py | 29 +++++++++++++++++++++++++++++
cobbler/action_reposync.py | 2 +-
cobbler/item_profile.py | 11 +++++++----
cobbler/serializer.py | 4 ----
cobbler/utils.py | 18 +++++++++++-------
cobbler/yumgen.py | 4 +++-
7 files changed, 53 insertions(+), 17 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 48fe825..1992994 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,8 @@ Cobbler CHANGELOG
- add warning to cobbler check if selinux is on and Apache boolean not set
- added warning to cobbler check if templates use the default password
- setting per-system kickstart template to "" or "delete" restores inheritance
+- if repos in profiles no longer exist, remove noisy warning, move to "check"
+- move warning about reposync to check also (check is more useful at runtime now)
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index 044b56b..f5f86f0 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -66,6 +66,8 @@ class BootCheck:
self.check_iptables(status)
self.check_yum(status)
self.check_for_default_password(status)
+ self.check_for_unreferenced_repos(status)
+ self.check_for_unsynced_repos(status)
return status
@@ -134,6 +136,33 @@ class BootCheck:
status.append(_("One or more kickstart templates references default password 'cobbler' and should be changed for security reasons: %s") % ", ".join(files))
+ def check_for_unreferenced_repos(self,status):
+ repos = []
+ referenced = []
+ not_found = []
+ for r in self.config.api.repos():
+ repos.append(r.name)
+ for p in self.config.api.profiles():
+ my_repos = p.repos
+ referenced.extend(my_repos)
+ for r in referenced:
+ if r not in repos:
+ not_found.append(r)
+ if len(not_found) > 0:
+ status.append(_("One or more repos referenced by profile objects is no longer defined in cobbler: %s") % ", ".join(not_found))
+
+ def check_for_unsynced_repos(self,status):
+ need_sync = []
+ for r in self.config.repos():
+ if r.mirror_locally == 1:
+ lookfor = os.path.join(self.settings.webdir, "repo_mirror", r.name)
+ print "DEBUG: looking for: %s" % lookfor
+ if not os.path.exists(lookfor):
+ need_sync.append(r.name)
+ if len(need_sync) > 0:
+ status.append(_("One or more repos need to be processed by cobbler reposync for the first time before kickstarting against them: %s") % ", ".join(need_sync))
+
+
def check_httpd(self,status):
"""
Check if Apache is installed.
diff --git a/cobbler/action_reposync.py b/cobbler/action_reposync.py
index 495aa3a..57c2d08 100644
--- a/cobbler/action_reposync.py
+++ b/cobbler/action_reposync.py
@@ -314,7 +314,7 @@ class RepoSync:
if os.path.exists(getenforce):
data = sub_process.Popen(getenforce, shell=True, stdout=sub_process.PIPE).communicate()[0]
if data.lower().find("disabled") == -1:
- cmd3 = "chcon --reference /var/www %s" % repo_path
+ cmd3 = "chcon --reference /var/www %s >/dev/null 2>/dev/null" % repo_path
sub_process.call(cmd3, shell=True)
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index c5c9bdb..0e16f46 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -70,7 +70,10 @@ class Profile(item.Item):
# backwards compatibility
if type(self.repos) != list:
- self.set_repos(self.repos)
+ # ensure we are formatted correctly though if some repo
+ # defs don't exist on this side, don't fail as we need
+ # to convert everything -- cobbler check can report it
+ self.set_repos(self.repos,bypass_check=True)
self.set_parent(self.parent)
# virt specific
@@ -87,7 +90,7 @@ class Profile(item.Item):
if self.ks_meta != "<>" and type(self.ks_meta) != dict:
self.set_ksmeta(self.ks_meta)
if self.repos != "<>" and type(self.ks_meta) != list:
- self.set_repos(self.repos)
+ self.set_repos(self.repos,bypass_check=True)
self.set_owners(self.owners)
@@ -171,8 +174,8 @@ class Profile(item.Item):
def set_virt_path(self,path):
return utils.set_virt_path(self,path)
- def set_repos(self,repos):
- return utils.set_repos(self,repos)
+ def set_repos(self,repos,bypass_check=False):
+ return utils.set_repos(self,repos,bypass_check)
def get_parent(self):
diff --git a/cobbler/serializer.py b/cobbler/serializer.py
index 25d0d60..ac98412 100644
--- a/cobbler/serializer.py
+++ b/cobbler/serializer.py
@@ -59,10 +59,8 @@ def serialize_item(collection, item):
storage_module = __get_storage_module(collection.collection_type())
save_fn = getattr(storage_module, "serialize_item", None)
if save_fn is None:
- # print "DEBUG: WARNING: full serializer"
rc = storage_module.serialize(collection)
else:
- # print "DEBUG: partial serializer"
rc = save_fn(collection,item)
__release_lock()
return rc
@@ -75,10 +73,8 @@ def serialize_delete(collection, item):
storage_module = __get_storage_module(collection.collection_type())
delete_fn = getattr(storage_module, "serialize_delete", None)
if delete_fn is None:
- # print "DEBUG: full delete"
rc = storage_module.serialize(collection)
else:
- # print "DEBUG: partial delete"
rc = delete_fn(collection,item)
__release_lock()
return rc
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 112d94b..c62ec6c 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -634,7 +634,7 @@ def mkdir(path,mode=0777):
print oe.errno
raise CX(_("Error creating") % path)
-def set_repos(self,repos):
+def set_repos(self,repos,bypass_check=False):
# WARNING: hack
repos = fix_mod_python_select_submission(repos)
@@ -653,7 +653,6 @@ def set_repos(self,repos):
else:
repolist = repos
-
# make sure there are no empty strings
try:
repolist.remove('')
@@ -662,13 +661,18 @@ def set_repos(self,repos):
self.repos = []
- # if any repos don't exist, fail the operation
+ # if any repos don't exist, fail the set operation
+ # unless called from the deserializer stage in which
+ # case we have a soft error that check can report
ok = True
for r in repolist:
- if self.config.repos().find(name=r) is not None:
- self.repos.append(r)
- else:
- print _("warning: repository not found: %s" % r)
+ if bypass_check:
+ self.repos.append(r)
+ else:
+ if self.config.repos().find(name=r) is not None:
+ self.repos.append(r)
+ else:
+ raise CX(_("repo %s is not defined") % r)
return True
diff --git a/cobbler/yumgen.py b/cobbler/yumgen.py
index e39a72e..8c10be3 100644
--- a/cobbler/yumgen.py
+++ b/cobbler/yumgen.py
@@ -98,7 +98,9 @@ class YumGen:
try:
infile_h = open(infile)
except:
- print _("WARNING: cobbler reposync needs to be run on repo (%s), then re-run cobbler sync") % dispname
+ # file does not exist and the user needs to run reposync
+ # before we will use this, cobbler check will mention
+ # this problem
continue
infile_data = infile_h.read()
infile_h.close()
--
cgit
From 0f60b1a19ef32c63c591905b9640ebb60684f442 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 13 May 2008 16:04:34 -0400
Subject: If for some reason the user has defined a system where the first
interface record is blank and the second is not, still build the PXE tree
based on the second record.
---
CHANGELOG | 1 +
cobbler/item_system.py | 11 ++++++-----
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 1992994..079a790 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,7 @@ Cobbler CHANGELOG
- setting per-system kickstart template to "" or "delete" restores inheritance
- if repos in profiles no longer exist, remove noisy warning, move to "check"
- move warning about reposync to check also (check is more useful at runtime now)
+- build pxe trees for systems even if interface0 is undefined
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 94ec392..2318ced 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -229,11 +229,12 @@ class System(item.Item):
"""
if self.name == "default":
return True
- mac = self.get_mac_address(interface)
- ip = self.get_ip_address(interface)
- if mac is None and ip is None:
- return False
- return True
+ for (name,x) in self.interfaces.iteritems():
+ mac = x.get("mac_address",None)
+ ip = x.get("ip_address",None)
+ if mac is not None or ip is not None:
+ return True
+ return False
def set_dhcp_tag(self,dhcp_tag,interface="intf0"):
intf = self.__get_interface(interface)
--
cgit
From b7217f4730ed54abaec95855a682c5c9f3b73870 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 13 May 2008 17:18:16 -0400
Subject: Change the way error checking works around NFS read errors (root
squash)
---
CHANGELOG | 1 +
cobbler/remote.py | 10 ++++++++++
cobbler/utils.py | 13 ++++++-------
3 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 079a790..32ff3e0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,7 @@ Cobbler CHANGELOG
- if repos in profiles no longer exist, remove noisy warning, move to "check"
- move warning about reposync to check also (check is more useful at runtime now)
- build pxe trees for systems even if interface0 is undefined
+- add sync() back into XMLRPC API, missing in 0.9.1
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 8cf9ba3..69754a3 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -747,6 +747,16 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
return self.object_cache[object_id][0]
raise CX(_("No such object for ID: %s") % object_id)
+ def sync(self,token):
+ """
+ Run sync code, which should complete before XMLRPC timeout. We can't
+ do reposync this way. Would be nice to send output over AJAX/other
+ later.
+ """
+ self.log("sync",token=token)
+ self.check_access(token,"sync")
+ return self.api.sync()
+
def new_distro(self,token):
"""
Creates a new (unconfigured) distro object. It works something like
diff --git a/cobbler/utils.py b/cobbler/utils.py
index c62ec6c..6e756c9 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -590,13 +590,12 @@ def copyfile(src,dst):
try:
return shutil.copyfile(src,dst)
except:
- try:
- if not os.path.samefile(src,dst):
- # accomodate for the possibility that we already copied
- # the file as a symlink/hardlink
- raise CX(_("Error copying %(src)s to %(dst)s") % { "src" : src, "dst" : dst})
- except:
- raise CX(_("Problems reading %(src)s") % { "src" : src})
+ if not os.access(src,os.R_OK):
+ raise CX(_("Cannot read: %s") % src)
+ if not os.path.samefile(src,dst):
+ # accomodate for the possibility that we already copied
+ # the file as a symlink/hardlink
+ raise CX(_("Error copying %(src)s to %(dst)s") % { "src" : src, "dst" : dst})
def rmfile(path):
try:
--
cgit
From da5afb37f3d5f8ce4e4ad0508206eb68c8db25c9 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 14 May 2008 15:52:03 -0400
Subject: Since it's common to want to reference the name of the profile in a
template, and that changes whether the rendering is a per-profile or
per-system kickstart, I've added three new variables to make things easier:
"distro_name", "profile_name", and "system_name" which show up in the
templates automatically in addition to the existing "distro", "profile", and
"name" you get for a system, or "distro" and "name" for profile. This is
more consistant and easier to use in the templating language.
---
CHANGELOG | 1 +
cobbler/pxegen.py | 1 -
cobbler/utils.py | 13 +++++++++++++
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG b/CHANGELOG
index 32ff3e0..c34ffff 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,6 +13,7 @@ Cobbler CHANGELOG
- move warning about reposync to check also (check is more useful at runtime now)
- build pxe trees for systems even if interface0 is undefined
- add sync() back into XMLRPC API, missing in 0.9.1
+- added 'distro_name', 'profile_name', and 'system_name' to generated template vars
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
index 639c30b..d847569 100644
--- a/cobbler/pxegen.py
+++ b/cobbler/pxegen.py
@@ -84,7 +84,6 @@ class PXEGen:
"""
# copy is a 4-letter word but tftpboot runs chroot, thus it's required.
for d in self.distros:
- print _("sync distro: %s") % d.name
self.copy_single_distro_files(d)
def copy_single_distro_files(self, d):
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 6e756c9..a63f7af 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -370,6 +370,19 @@ def blender(api_handle,remove_hashes, root_obj):
# sanitize output for koan and kernel option lines, etc
if remove_hashes:
results = flatten(results)
+
+ # add in some variables for easier templating
+ # as these variables change based on object type
+ if results.has_key("interfaces"):
+ results["system_name"] = results["name"]
+ results["profile_name"] = results["profile"]
+ results["distro_name"] = results["distro"]
+ elif results.has_key("distro"):
+ results["profile_name"] = results["name"]
+ results["distro_name"] = results["distro"]
+ elif results.has_key("kernel"):
+ results["distro_name"] = results["name"]
+
return results
def flatten(data):
--
cgit
From 9d5b494aaac2d2b0be4b598d6049eb869ef4b49c Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 14 May 2008 15:58:44 -0400
Subject: Make template finder code (used by check and webapp) ignore
kickstarts that are not on the filesystem and are therefore real kickstarts
or URLs that generate them, not actual templates.
---
cobbler/utils.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/cobbler/utils.py b/cobbler/utils.py
index a63f7af..007b96c 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -798,10 +798,12 @@ def get_kickstart_templates(api):
files = {}
for x in api.profiles():
if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
- files[x.kickstart] = 1
+ if os.path.exists(x.kickstart):
+ files[x.kickstart] = 1
for x in api.systems():
if x.kickstart is not None and x.kickstart != "" and x.kickstart != "<>":
- files[x.kickstart] = 1
+ if os.path.exists(x.kickstart):
+ files[x.kickstart] = 1
for x in glob.glob("/var/lib/cobbler/kickstarts/*"):
files[x] = 1
for x in glob.glob("/etc/cobbler/*.ks"):
--
cgit
From 7b6922a1da2654874d14ba97340e95ab88eff202 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Wed, 14 May 2008 16:15:21 -0400
Subject: Added the ability to undefine a symbol that is defined in a parent
object.
This means that if a kernel option is set for a profile, and you want it unset
in a child system, you can say --kopts='!foo' to undefine the foo. Similarly you
can add symbols and undefine others at the same time... --kopts='bar !foo baz=3' and
so on.
This is relatively fringe usage but was previously not possible.
---
CHANGELOG | 1 +
cobbler/utils.py | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index c34ffff..c291335 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,6 +14,7 @@ Cobbler CHANGELOG
- build pxe trees for systems even if interface0 is undefined
- add sync() back into XMLRPC API, missing in 0.9.1
- added 'distro_name', 'profile_name', and 'system_name' to generated template vars
+- it's now possible to undefine a --ksmeta or kopts symbol defined in a parent with "!foo"
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 007b96c..455a7e3 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -446,6 +446,24 @@ def __consolidate(node,results):
else:
results[field] = data_item
+ # now if we have any "!foo" results in the list, delete corresponding
+ # key entry "foo", and also the entry "!foo", allowing for removal
+ # of kernel options set in a distro later in a profile, etc.
+
+ hash_removals(results,"kernel_options")
+ hash_removals(results,"ks_meta")
+
+def hash_removals(results,subkey):
+ if not results.has_key(subkey):
+ return
+ scan = results[subkey].keys()
+ for k in scan:
+ if k.startswith("!") and k != "!":
+ remove_me = k[1:]
+ if results[subkey].has_key(remove_me):
+ del results[subkey][remove_me]
+ del results[subkey][k]
+
def hash_to_string(hash):
"""
Convert a hash to a printable string.
--
cgit
From 57828b2e7ad347e7ffe76c58f210e6b5b0dedeca Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 15 May 2008 14:36:30 -0400
Subject: Checked in architecture diagram source, run "make graphviz" to build
it.
---
Makefile | 4 ++
docs/cobbler.dot | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 122 insertions(+)
create mode 100644 docs/cobbler.dot
diff --git a/Makefile b/Makefile
index af01e9f..3407721 100644
--- a/Makefile
+++ b/Makefile
@@ -100,3 +100,7 @@ eraseconfig:
-rm /var/lib/cobbler/profiles*
-rm /var/lib/cobbler/systems*
-rm /var/lib/cobbler/repos*
+
+graphviz:
+ dot -Tpdf docs/cobbler.dot -o cobbler.pdf
+
diff --git a/docs/cobbler.dot b/docs/cobbler.dot
new file mode 100644
index 0000000..e4eb2fb
--- /dev/null
+++ b/docs/cobbler.dot
@@ -0,0 +1,118 @@
+graph arch {
+
+
+webui -- apache
+
+cobblerd
+mgmt [label="mgmt/sync"]
+// yum stuff
+
+node [color="brown"]
+
+api
+misc -- replication
+misc -- buildiso
+i_dvd [label="DVD"]
+i_other [label="rsync/ssh/filesystem"]
+misc -- import
+import -- i_dvd
+import -- i_other
+misc -- check
+
+api -- mgmt
+api -- misc
+
+api -- yum_mirroring
+api -- triggers
+y_rsync [label="rsync/ssh/local"]
+y_http_ftp [label="http/ftp"]
+yum_mirroring -- y_rsync
+yum_mirroring -- y_http_ftp
+
+node [color="black"]
+
+cli -- api
+cli
+cobblerd -- api
+
+node [color="red"]
+
+// triggers stuff
+triggers_add [label="add/remove"]
+triggers_sync [label="sync"]
+triggers_install [label="install"]
+triggers -- triggers_add
+triggers -- triggers_sync
+triggers -- triggers_install
+
+// mgmt stuff
+
+node [color="grey"]
+
+dns
+dhcp
+mgmt -- tftpboot
+mgmt -- dns
+mgmt -- dhcp
+dns -- bind
+dns -- dnsmasq
+dhcp -- isc
+dhcp -- dnsmasq
+yumconfigs
+mgmt -- yumconfigs
+tftpboot -- templating
+isc -- templating
+dnsmasq -- templating
+bind -- templating
+yumconfigs -- templating
+templating -- snippets
+
+node [color="blue"]
+
+api -- configs
+configs -- settings
+configs -- objects
+objects -- distros
+objects -- systems
+objects -- profiles
+objects -- repos
+configs -- modules_conf
+configs -- cobbler_conf
+configs -- services_conf
+apache -- cobbler_conf
+apache -- services_conf
+
+
+node [color="green"]
+
+cobblerd -- security
+cobblerd -- webui [label="xmlrpc"]
+cobblerd -- avahi
+cobblerd -- mod_python [label="xmlrpc"]
+mod_python -- services [label="http"]
+services -- kickgen
+kickgen -- templating
+services -- registration
+services -- triggers
+
+services -- apache
+
+security -- authn
+security -- authz
+
+node [color="orange"]
+
+cobblerd -- koan [label="xmlrpc"]
+koan -- avahi
+koan -- replaceself
+replaceself -- livecd
+koan -- virt
+koan -- apache [label="http"]
+xen [label="xen fv/pv"]
+virt -- xen
+qemu_kvm [label="qemu/KVM"]
+virt -- qemu_kvm
+virt -- vmware
+
+
+}
--
cgit
From eb9fd952a3ea964d4e1aa1b0f7e6a0a208d12b40 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 15 May 2008 15:01:37 -0400
Subject: Add extra logging if an error is encountered while rendering a
kickstart
---
CHANGELOG | 1 +
cobbler/api.py | 12 +-----------
cobbler/kickgen.py | 3 +--
cobbler/utils.py | 13 +++++++++++++
4 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index c291335..72bba8a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@ Cobbler CHANGELOG
- add sync() back into XMLRPC API, missing in 0.9.1
- added 'distro_name', 'profile_name', and 'system_name' to generated template vars
- it's now possible to undefine a --ksmeta or kopts symbol defined in a parent with "!foo"
+- log errors while rendering kickstarts
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/cobbler/api.py b/cobbler/api.py
index a2aa881..cafc216 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -86,17 +86,7 @@ class BootAPI:
self.logger.debug("API handle initialized")
def __setup_logger(self,name):
- logger = logging.getLogger(name)
- logger.setLevel(logging.INFO)
- try:
- ch = logging.FileHandler("/var/log/cobbler/cobbler.log")
- except:
- raise CX(_("No write permissions on log file. Are you root?"))
- ch.setLevel(logging.INFO)
- formatter = logging.Formatter("%(asctime)s - %(name)s - %(message)s")
- ch.setFormatter(formatter)
- logger.addHandler(ch)
- return logger
+ return utils.setup_logger(name)
def log(self,msg,args=None,debug=False):
if debug:
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index ba8bfd2..9f0235d 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -81,8 +81,7 @@ class KickGen:
kfile.close()
return data
except:
- traceback.print_exc() # leave this in, for now...
- msg = "err_kickstart2"
+ utils.log_exc(self.api.logger)
raise CX(_("Error while rendering kickstart file"))
def generate_kickstart_signal(self, is_pre=0, profile=None, system=None):
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 455a7e3..de00150 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -23,6 +23,7 @@ import shutil
import string
import traceback
import errno
+import logging
from cexceptions import *
#placeholder for translation
@@ -37,6 +38,18 @@ MODULE_CACHE = {}
_re_kernel = re.compile(r'vmlinuz(.*)')
_re_initrd = re.compile(r'initrd(.*).img')
+def setup_logger(name):
+ logger = logging.getLogger(name)
+ logger.setLevel(logging.INFO)
+ try:
+ ch = logging.FileHandler("/var/log/cobbler/cobbler.log")
+ except:
+ raise CX(_("No write permissions on log file. Are you root?"))
+ ch.setLevel(logging.INFO)
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(message)s")
+ ch.setFormatter(formatter)
+ logger.addHandler(ch)
+ return logger
def log_exc(logger):
"""
--
cgit
From 825db5f84fc039330fdb09b7975a6b4e6bbc8b2e Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Thu, 15 May 2008 15:08:20 -0400
Subject: Cleaner error messages on kickstart rendering problems.
---
cobbler/kickgen.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index 9f0235d..f302d00 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -82,7 +82,7 @@ class KickGen:
return data
except:
utils.log_exc(self.api.logger)
- raise CX(_("Error while rendering kickstart file"))
+ return _("# Error while rendering kickstart file, see /var/log/cobbler/cobbler.log for details")
def generate_kickstart_signal(self, is_pre=0, profile=None, system=None):
"""
--
cgit
From 17f0ac054ef5bf160909095aaf119931edd5c39c Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 16 May 2008 13:51:49 -0400
Subject: Found out our config file supports comments (hooray) and added a
bunch explaining what all of the settings do. Should have done this long ago
but glad to have it!
---
CHANGELOG | 1 +
config/settings | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 72bba8a..8e01199 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -16,6 +16,7 @@ Cobbler CHANGELOG
- added 'distro_name', 'profile_name', and 'system_name' to generated template vars
- it's now possible to undefine a --ksmeta or kopts symbol defined in a parent with "!foo"
- log errors while rendering kickstarts
+- comments added to the config file, neat!
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/config/settings b/config/settings
index 2f6b08d..b1f7bd7 100644
--- a/config/settings
+++ b/config/settings
@@ -1,27 +1,72 @@
---
+# cobbler settings file
+# run "cobbler sync" after making changes
+# (it's a good idea to make backups too)
+#
+# if 1, cobbler will allow insertions of system records that duplicate
+# the mac address information of other system records. In general,
+# this is undesirable.
allow_duplicate_macs: 0
+
+# if 1, cobbler will allow insertions of system records that duplicate
+# the ip address information of other system records. In general,
+# this is undesirable.
allow_duplicate_ips: 0
+
+# the path to BIND's executable for this distribution.
bind_bin: /usr/sbin/named
+
+# where to find various bootloaders on the filesystem
bootloaders:
ia64: /var/lib/cobbler/elilo-3.6-ia64.efi
standard: /usr/lib/syslinux/pxelinux.0
+
+# if no kickstart is specified, use this template (FIXME)
default_kickstart: /etc/cobbler/default.ks
+
+# for libvirt based installs in koan, if no virt bridge
+# is specified, which bridge do we try?
default_virt_bridge: xenbr0
-default_virt_type: auto
+
+# if koan is invoked without --virt-type and no virt-type
+# is set on the profile/system, what virtualization type
+# should be assumed? Values: xenpv, xenfv, qemu, vmware
+default_virt_type: xenpv
+
+# use this as the default disk size for virt guests (GB)
default_virt_file_size: 5
+
+# use this as the default memory size for virt guests (MB)
default_virt_ram: 512
+
+# if using the authz_ownership module (see the Wiki), objects
+# created without specifying an owner are assigned to this
+# owner and/or group. Can be a comma seperated list.
default_ownership: "admin"
+
+# location for some important binaries and config files
+# that can vary based on the distribution.
dhcpd_bin: /usr/sbin/dhcpd
dhcpd_conf: /etc/dhcpd.conf
dnsmasq_bin: /usr/sbin/dnsmasq
dnsmasq_conf: /etc/dnsmasq.conf
httpd_bin: /usr/sbin/httpd
+
+# change this port if Apache is not running plaintext on port
+# 80. Most people can leave this alone.
http_port: 80
-kerberos_realm: 'example.org'
+
+# kernel options that should be present in every cobbler installation.
+# kernel options can also be applied at the distro/profile/system
+# level.
kernel_options:
ksdevice: eth0
lang: ' '
text: ~
+
+# configuration options if using the authn_ldap module. See the
+# the Wiki for details. This can be ignored if you are not using
+# LDAP for WebUI/XMLRPC authentication.
ldap_server: "ldap.example.com"
ldap_base_dn: "DC=example,DC=com"
ldap_port: 389
@@ -30,23 +75,112 @@ ldap_anonymous_bind: 1
ldap_search_bind_dn: ''
ldap_search_passwd: ''
ldap_search_prefix: 'uid='
+
+# set to 1 to enable Cobbler's DHCP management features.
+# the choice of DHCP management engine is in /etc/cobbler/modules.conf
manage_dhcp: 0
+
+# set to 1 to enable Cobbler's DNS management features.
+# the choice of DNS mangement engine is in /etc/cobbler/modules.conf
manage_dns: 0
+
+# if using cobbler with manage_dhcp, put the IP address
+# of the cobbler server here so that PXE booting guests can find it
next_server: '127.0.0.1'
+
+# if using cobbler with manage_dhcp and ISC, omapi allows realtime DHCP
+# updates without restarting ISC dhcpd.
omapi_enabled: 1
omapi_port: 647
omshell_bin: /usr/bin/omshell
+
+# if this setting is set to 1, cobbler systems that pxe boot
+# will request at the end of their installation to toggle the
+# --netboot-enabled record in the cobbler system record. This eliminates
+# the potential for a PXE boot loop if the system is set to PXE
+# first in it's BIOS order. Enable this if PXE is first in your BIOS
+# boot order, otherwise leave this disabled. See the manpage
+# for --netboot-enabled.
pxe_just_once: 0
+
+# if set to 1, new systems doing profile based installations will
+# contact cobbler to have system records created for them containing
+# the mac address information that they have requested for install.
+# this effectively allows for registration of new hardware via PXE
+# without having to manually enter in all of the mac addresses for
+# every machine on your network
register_new_installs: 0
+
+# install triggers are scripts in /var/lib/cobbler/triggers/install
+# that are triggered in kickstart pre and post sections. Any
+# executable script in those directories is run. They can be used
+# to send email or perform other actions. They are currently
+# run as root so if you do not need this functionality you can
+# disable it, though this will also disable "cobbler status" which
+# uses a logging trigger to audit install progress.
run_install_triggers: 1
+
+# this is the address of the cobbler server -- as it is used
+# by systems during the install process, it must be the address
+# or hostname of the system as those systems can see the server.
+# if you have a server that appears differently to different subnets
+# (dual homed, etc), you need to read the --server-override section
+# of the manpage for how that works.
server: '127.0.0.1'
+
+# this is a directory of files that cobbler uses to make
+# templating easier. See the Wiki for more information. Changing
+# this directory should not be required.
snippetsdir: /var/lib/cobbler/snippets
+
+# by default, installs are set to send syslog traffic on this port
+# and cobblerd will listen on this port. syslog data (for installs
+# that support it... RHEL 5 and later, etc) is logged in /var/log/cobbler
+# and can be used to help debug problematic installations. Syslog
+# is UDP and may not be available depending on network/firewall configuration.
syslog_port: 25150
+
+# locations of the TFTP binary and config file
tftpd_bin: /usr/sbin/in.tftpd
tftpd_conf: /etc/xinetd.d/tftp
+
+# cobbler's web directory. Don't change this setting -- see the
+# Wiki on "relocating your cobbler install" if your /var partition
+# is not large enough.
webdir: /var/www/cobbler
+
+# cobbler's public XMLRPC listens on this port. Change this only
+# if absolutely needed, as you'll have to start supplying a new
+# port option to koan if it is not the default.
xmlrpc_port: 25151
+
+# cobbler's read write XMLRPC is the version of XMLRPC
+# used by the WebUI and some features like system registration.
+# XMLRPC connections here require login information to access.
+# this feature can be disabled to gain increased security but
+# will disable the WebUI, registration, and potentially other
+# cobbler features. Most users should leave XMLRPC RW
+# enabled. The port can be relocated if needed.
xmlrpc_rw_enabled: 1
xmlrpc_rw_port: 25152
+
+# "cobbler repo add" commands set cobbler up with repository
+# information that can be used during kickstart and is automatically
+# set up in the cobbler kickstart templates. By default, these
+# are only available at install time. To make these repositories
+# usable on installed systems (since cobbler makes a very convient)
+# mirror, set this to 1. Most users can safely set this to 1. Users
+# who have a dual homed cobbler server, or are installing laptops that
+# will not always have access to the cobbler server may wish to leave
+# this as 0. In that case, the cobbler mirrored yum repos are still
+# accessable at http://cobbler.example.org/cblr/repo_mirror and yum
+# configuration can still be done manually. This is just a shortcut.
yum_post_install_mirror: 0
+
+# "cobbler repo" support normally uses rsync or reposync. If --rpm-list
+# is used, it's possible to download only a certain package list, plus
+# dependencies, but --resolve and other flags are not supported in
+# all versions of yumdownloader. This is a list of what flags
+# to pass to it. Only change this if you are experiencing problems
+# with "cobbler reposync" and are using --rpm-list.
yumdownloader_flags: "--resolve"
--
cgit
From 90666a4a0a3c918a31f7cdfd9fa9fd2a6ad48705 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 16 May 2008 14:42:37 -0400
Subject: The settings file is now /etc/cobbler/settings, and cobbler's command
line will warn the user the old file is no longer in use and ask them to
delete it before proceeding.
---
CHANGELOG | 1 +
Makefile | 16 ++++++++--------
cobbler.spec | 5 +++--
cobbler/action_check.py | 10 +++++-----
cobbler/api.py | 2 +-
cobbler/cobbler.py | 11 +++++++++++
cobbler/item_system.py | 2 +-
cobbler/pxegen.py | 2 +-
cobbler/remote.py | 2 +-
cobbler/settings.py | 8 --------
setup.py | 2 +-
11 files changed, 33 insertions(+), 28 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 8e01199..d43d434 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -17,6 +17,7 @@ Cobbler CHANGELOG
- it's now possible to undefine a --ksmeta or kopts symbol defined in a parent with "!foo"
- log errors while rendering kickstarts
- comments added to the config file, neat!
+- settings file is now /etc/cobbler/settings
- Fri May 09 2008 - 0.9.1
- patch to allow yumopts to override gpgcheck
diff --git a/Makefile b/Makefile
index 3407721..d7fd78c 100644
--- a/Makefile
+++ b/Makefile
@@ -36,17 +36,17 @@ install: clean manpage
python setup.py install -f
devinstall:
- cp /var/lib/cobbler/settings /tmp/cobbler_settings
- cp /etc/cobbler/modules.conf /tmp/cobbler_modules.conf
- cp /etc/httpd/conf.d/cobbler.conf /tmp/cobbler_http.conf
- cp /etc/cobbler/users.conf /tmp/cobbler_users.conf
+ -cp /etc/cobbler/settings /tmp/cobbler_settings
+ -cp /etc/cobbler/modules.conf /tmp/cobbler_modules.conf
+ -cp /etc/httpd/conf.d/cobbler.conf /tmp/cobbler_http.conf
+ -cp /etc/cobbler/users.conf /tmp/cobbler_users.conf
-cp /etc/cobbler/users.digest /tmp/cobbler_users.digest
make install
- cp /tmp/cobbler_settings /var/lib/cobbler/settings
- cp /tmp/cobbler_modules.conf /etc/cobbler/modules.conf
- cp /tmp/cobbler_users.conf /etc/cobbler/users.conf
+ -cp /tmp/cobbler_settings /etc/cobbler/settings
+ -cp /tmp/cobbler_modules.conf /etc/cobbler/modules.conf
+ -cp /tmp/cobbler_users.conf /etc/cobbler/users.conf
-cp /tmp/cobbler_users.digest /etc/cobbler/users.digest
- cp /tmp/cobbler_http.conf /etc/httpd/conf.d/cobbler.conf
+ -cp /tmp/cobbler_http.conf /etc/httpd/conf.d/cobbler.conf
find /var/lib/cobbler/triggers | xargs chmod +x
chown -R apache /var/www/cobbler
chown -R apache /var/www/cgi-bin/cobbler
diff --git a/cobbler.spec b/cobbler.spec
index 51ea3aa..c4284f3 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -169,7 +169,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%config(noreplace) /var/lib/cobbler/triggers/install/post/status_post.trigger
%defattr(664,root,root)
-%config(noreplace) /var/lib/cobbler/settings
+%config(noreplace) /etc/cobbler/settings
%config(noreplace) /var/lib/cobbler/snippets/partition_select
/var/lib/cobbler/elilo-3.6-ia64.efi
/var/lib/cobbler/menu.c32
@@ -188,8 +188,9 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
-* Mon May 12 2008 Michael DeHaan - 0.9.2-1
+* Fri May 16 2008 Michael DeHaan - 0.9.2-1
- Upstream changes (see CHANGELOG)
+- moved /var/lib/cobbler/settings to /etc/cobbler/settings
* Fri May 09 2008 Michael DeHaan - 0.9.1-1
- Upstream changes (see CHANGELOG)
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index f5f86f0..d38603b 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -106,9 +106,9 @@ class BootCheck:
parameters.
"""
if self.settings.server == "127.0.0.1":
- status.append(_("The 'server' field in /var/lib/cobbler/settings must be set to something other than localhost, or kickstarting features will not work. This should be a resolvable hostname or IP for the boot server as reachable by all machines that will use it."))
+ status.append(_("The 'server' field in /etc/cobbler/settings must be set to something other than localhost, or kickstarting features will not work. This should be a resolvable hostname or IP for the boot server as reachable by all machines that will use it."))
if self.settings.next_server == "127.0.0.1":
- status.append(_("For PXE to be functional, the 'next_server' field in /var/lib/cobbler/settings must be set to something other than 127.0.0.1, and should match the IP of the boot server on the PXE network."))
+ status.append(_("For PXE to be functional, the 'next_server' field in /etc/cobbler/settings must be set to something other than 127.0.0.1, and should match the IP of the boot server on the PXE network."))
def check_selinux(self,status):
prc = sub_process.Popen("/usr/sbin/getenforce",shell=True,stdout=sub_process.PIPE)
@@ -175,21 +175,21 @@ class BootCheck:
Check if dhcpd is installed
"""
if not os.path.exists(self.settings.dhcpd_bin):
- status.append(_("dhcpd isn't installed, but management is enabled in /var/lib/cobbler/settings"))
+ status.append(_("dhcpd isn't installed, but management is enabled in /etc/cobbler/settings"))
def check_dnsmasq_bin(self,status):
"""
Check if dnsmasq is installed
"""
if not os.path.exists(self.settings.dnsmasq_bin):
- status.append(_("dnsmasq isn't installed, but management is enabled in /var/lib/cobbler/settings"))
+ status.append(_("dnsmasq isn't installed, but management is enabled in /etc/cobbler/settings"))
def check_bind_bin(self,status):
"""
Check if bind is installed.
"""
if not os.path.exists(self.settings.bind_bin):
- status.append(_("bind isn't installed, but management is enabled in /var/lib/cobbler/settings"))
+ status.append(_("bind isn't installed, but management is enabled in /etc/cobbler/settings"))
def check_bootloaders(self,status):
diff --git a/cobbler/api.py b/cobbler/api.py
index cafc216..9f4a636 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -41,7 +41,7 @@ DEBUG = 5
# notes on locking:
# BootAPI is a singleton object
# the XMLRPC variants allow 1 simultaneous request
-# therefore we flock on /var/lib/cobbler/settings for now
+# therefore we flock on /etc/cobbler/settings for now
# on a request by request basis.
class BootAPI:
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 970a06a..2aed672 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -45,12 +45,23 @@ class BootCLI:
####################################################
+def run_upgrade_checks():
+ """
+ Cobbler tries to make manual upgrade steps unneeded, though
+ this function serves to inform users of manual steps when they /are/
+ needed.
+ """
+ # for users running pre-1.0 upgrading to 1.0
+ if os.path.exists("/var/lib/cobbler/settings"):
+ raise CX(_("/var/lib/cobbler/settings is no longer in use, remove this file to acknowledge you have migrated your configuration to /etc/cobbler/settings. Do not simply copy the file over or you will lose new configuration entries. Run 'cobbler check' and then 'cobbler sync' after making changes."))
+
def main():
"""
CLI entry point
"""
exitcode = 0
try:
+ run_upgrade_checks()
return BootCLI().run(sys.argv)
except SystemExit, ex:
return 1
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 2318ced..09f169d 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -249,7 +249,7 @@ class System(item.Item):
def set_ip_address(self,address,interface="intf0"):
"""
Assign a IP or hostname in DHCP when this MAC boots.
- Only works if manage_dhcp is set in /var/lib/cobbler/settings
+ Only works if manage_dhcp is set in /etc/cobbler/settings
"""
intf = self.__get_interface(interface)
if address == "" or utils.is_ip(address):
diff --git a/cobbler/pxegen.py b/cobbler/pxegen.py
index d847569..a438583 100644
--- a/cobbler/pxegen.py
+++ b/cobbler/pxegen.py
@@ -58,7 +58,7 @@ class PXEGen:
"""
Copy bootloaders to the configured tftpboot directory
NOTE: we support different arch's if defined in
- /var/lib/cobbler/settings.
+ /etc/cobbler/settings.
"""
for loader in self.settings.bootloaders.keys():
path = self.settings.bootloaders[loader]
diff --git a/cobbler/remote.py b/cobbler/remote.py
index 69754a3..1a414f3 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -193,7 +193,7 @@ class CobblerXMLRPCInterface:
def get_settings(self,token=None):
"""
- Return the contents of /var/lib/cobbler/settings, which is a hash.
+ Return the contents of /etc/cobbler/settings, which is a hash.
"""
self.log("get_settings",token=token)
return self.__get_all("settings")
diff --git a/cobbler/settings.py b/cobbler/settings.py
index d147d4b..4670ab0 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -140,11 +140,3 @@ class Settings(serializable.Serializable):
else:
raise AttributeError, name
-if __name__ == "__main__":
- # used to save a settings file to /var/lib/cobbler/settings, for purposes of
- # including a new updated settings file in the RPM without remembering how
- # to format lots of YAML.
- import yaml
- print yaml.dump(DEFAULTS)
-
-
diff --git a/setup.py b/setup.py
index 7b11c78..c659f9a 100644
--- a/setup.py
+++ b/setup.py
@@ -80,7 +80,7 @@ if __name__ == "__main__":
(etcpath, ['config/rsync.exclude']),
(etcpath, ['config/users.conf']),
(initpath, ['config/cobblerd']),
- (cobpath, ['config/settings']),
+ (etcpath, ['config/settings']),
# backups for upgrades
(backpath, []),
--
cgit
From 6f5ad0b0fe3d43f5cf5efaa465f8eff4c92eb642 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Fri, 16 May 2008 16:26:52 -0400
Subject: Fix to make serializer look in the right place, also removed a debug
print.
---
cobbler.spec | 4 ++--
cobbler/action_check.py | 1 -
cobbler/modules/serializer_yaml.py | 5 ++++-
website/codepush.sh | 3 ---
4 files changed, 6 insertions(+), 7 deletions(-)
delete mode 100644 website/codepush.sh
diff --git a/cobbler.spec b/cobbler.spec
index c4284f3..523485c 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -3,7 +3,7 @@ Summary: Boot server configurator
Name: cobbler
AutoReq: no
Version: 0.9.2
-Release: 1%{?dist}
+Release: 2%{?dist}
Source0: %{name}-%{version}.tar.gz
License: GPLv2+
Group: Applications/System
@@ -188,7 +188,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%changelog
-* Fri May 16 2008 Michael DeHaan - 0.9.2-1
+* Fri May 16 2008 Michael DeHaan - 0.9.2-2
- Upstream changes (see CHANGELOG)
- moved /var/lib/cobbler/settings to /etc/cobbler/settings
diff --git a/cobbler/action_check.py b/cobbler/action_check.py
index d38603b..74af0c6 100644
--- a/cobbler/action_check.py
+++ b/cobbler/action_check.py
@@ -156,7 +156,6 @@ class BootCheck:
for r in self.config.repos():
if r.mirror_locally == 1:
lookfor = os.path.join(self.settings.webdir, "repo_mirror", r.name)
- print "DEBUG: looking for: %s" % lookfor
if not os.path.exists(lookfor):
need_sync.append(r.name)
if len(need_sync) > 0:
diff --git a/cobbler/modules/serializer_yaml.py b/cobbler/modules/serializer_yaml.py
index 724265d..c4bd359 100644
--- a/cobbler/modules/serializer_yaml.py
+++ b/cobbler/modules/serializer_yaml.py
@@ -66,7 +66,10 @@ def get_filename(collection_type):
ending = collection_type
if not ending.endswith("s"):
ending = ending + "s"
- return "/var/lib/cobbler/%s" % ending
+ if ending != "settings":
+ return "/var/lib/cobbler/%s" % ending
+ else:
+ return "/etc/cobbler/settings"
def deserialize_raw(collection_type):
filename = get_filename(collection_type)
diff --git a/website/codepush.sh b/website/codepush.sh
deleted file mode 100644
index e997938..0000000
--- a/website/codepush.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-scp ../rpm-build/*.src.rpm et.redhat.com:/var/www/sites/cobbler.et.redhat.com/download
-scp ../rpm-build/*.tar.gz et.redhat.com:/var/www/sites/cobbler.et.redhat.com/download
--
cgit
From 3ee3e2052886af701e6f14b74d3463dbf9f9b069 Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 27 May 2008 12:00:24 -0400
Subject: doc item
---
docs/cobbler.pod | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index ce5cb0d..da3e58e 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -48,7 +48,7 @@ in network booting via PXE and just want to use koan to install virtual systems
=head2 ADDING A DISTRIBUTION
-This first step towards configurating what you want to provision is to add a distribution to the cobbler's configuration.
+This first step towards configurating what you want to provision is to add a distribution to cobbler's configuration.
If there is an rsync mirror, DVD, NFS, or filesystem tree available that you would rather import instead, skip down to the documentation about the "import" command. It's really a lot easier, and it only requires waiting for the mirror content to be copied and/or scanned. Imported mirrors also save time during install since they don't have to hit external install sources.
--
cgit
From 08d7f84030b1a709603568134c357fdd4813730a Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 27 May 2008 12:00:52 -0400
Subject: doc item
---
docs/cobbler.pod | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index da3e58e..93b184c 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -218,7 +218,7 @@ MAC addresses have the format AA:BB:CC:DD:EE:FF.
If cobbler is configured to generate a DHCP configuratition (see advanced section), use this
setting to define a specific IP for this system in DHCP. Leaving off this parameter will result in no DHCP management for this particular system.
-Example: ---ip=192.168.1.50
+Example: --ip=192.168.1.50
Note for Itanium users: this setting is always required for IA64 regardless of whether DHCP management is enabled.
--
cgit
From 2963016f5c143a6f3c3bc711a2b6d1ed07d65abe Mon Sep 17 00:00:00 2001
From: Michael DeHaan
Date: Tue, 27 May 2008 12:09:44 -0400
Subject: doc item
---
docs/cobbler.pod | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/cobbler.pod b/docs/cobbler.pod
index 93b184c..eb7000f 100644
--- a/docs/cobbler.pod
+++ b/docs/cobbler.pod
@@ -612,7 +612,7 @@ Note that all of the import commands will mirror install tree content into /var/
For import methods using rsync, additional flags can be passed to rsync with the option --rsync-flags.
-Should you want to force the usage of a specific cobbler kickstart template for all profiles created by an import, you can feed the option --kicksart to import, to bypass the built-in kickstart autodetection.
+Should you want to force the usage of a specific cobbler kickstart template for all profiles created by an import, you can feed the option --kickstart to import, to bypass the built-in kickstart auto-detection.
=head2 DEFAULT PXE BOOT BEHAVIOR
--
cgit