summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG8
-rw-r--r--NEWS9
-rw-r--r--TODO1
-rw-r--r--cobbler.pod12
-rw-r--r--cobbler.spec34
-rw-r--r--cobbler/action_enchant.py67
-rw-r--r--cobbler/action_sync.py9
-rw-r--r--cobbler/api.py138
-rwxr-xr-xcobbler/cobbler.py42
-rw-r--r--cobbler/cobbler_msg.py4
-rw-r--r--cobbler/item_system.py8
-rw-r--r--setup.py2
12 files changed, 249 insertions, 85 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 22bcf2f..f3af6b9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,12 @@
Cobbler CHANGELOG
+* Thr Sep 28 2006 - 0.2.1-1
+- New ability to "enchant" remote systems (see NEWS)
+- Misc. bugfixes
+
* Fri Sep 22 2006 - 0.2.0-1
-- New dhcp.d conf management features
-- IA64 support
+- New dhcp.d conf management features (see NEWS)
+- IA64 support (see NEWS)
- dhcpd.conf MAC & hostname association features
* Thr Sep 21 2006 - 0.1.1-8
diff --git a/NEWS b/NEWS
index 5cc9c2b..330beab 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+0.2.1
+
+** New "enchant" feature **
+
+Usage of "enchant" can install a profile on a remote system, even
+if that system does not have the koan helper tool installed.
+You'll need an IP or system name, a profile name, and the password
+to the system. See the manpage.
+
0.2.0
** New dhcp.conf templating and IA64 PXE features **
diff --git a/TODO b/TODO
index 4da0ec1..e94b7e1 100644
--- a/TODO
+++ b/TODO
@@ -4,5 +4,6 @@ cobbler TODO list
- Wake on lan integration for PXE
- Integration with stonnith or other up/down devices?
- koan push script for auto-ks simulation w/o koan
+ - Locking
diff --git a/cobbler.pod b/cobbler.pod
index 6080b6d..df09c68 100644
--- a/cobbler.pod
+++ b/cobbler.pod
@@ -236,6 +236,18 @@ Itanium systems also need to be specified by the MAC address, and in addition ne
The dhcpd.conf file will be updated each time "cobbler sync" is run.
+=head2 ENCHANT
+
+While the normal provisioning procedure is either to PXE bare-metal, or use koan to do something else (kickstart an existing system or deploy Xen), cobbler contains yet another option, called "enchant".
+
+Enchant takes a profile that has already been defined (run "cobbler sync" first!) and applies it to a remote system that may not have koan installed. This is all done from the cobbler server using SSH. If the remote system does not have the cobbler server's (root's) public key in /root/.authorized_keys it will prompt for passwords.
+
+Running "enchant" will replace the operating system of the target machine, so use it with caution.
+
+Usage: B<cobbler enchant --system=<ip|hostname> --profile=<string>>
+
+
+
=head2 TWEAKING
Enterprising users can edit the files in /var/lib/cobbler directly versus using the command line. The repair
diff --git a/cobbler.spec b/cobbler.spec
index e5af5ee..ce5e392 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -2,7 +2,7 @@
Summary: Boot server configurator
Name: cobbler
-Version: 0.2.0
+Version: 0.2.1
Release: 1%{?dist}
Source0: %{name}-%{version}.tar.gz
License: GPL
@@ -11,8 +11,10 @@ Requires: python >= 2.3
Requires: httpd
Requires: tftp-server
Requires: python-cheetah
+Requires: pexpect
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
BuildArch: noarch
+ExcludeArch: ppc
Url: http://et.redhat.com/page/Cobbler_%26_Koan_Provisioning_Tools
%description
@@ -52,21 +54,33 @@ rm -rf $RPM_BUILD_ROOT
%doc AUTHORS CHANGELOG NEWS README COPYING
%changelog
-* Fri Sep 22 2006 - 0.2.0-1
+* Thu Sep 28 2006 Michael DeHaan <mdehaan@redhat.com> - 0.2.1-1
+- Upstream pull of bugfixes and new remote system "enchant" feature
+
+* Fri Sep 22 2006 Michael DeHaan <mdehaan@redhat.com> - 0.2.0-1
- Lots of new PXE and dhcpd.conf upstream, elilo.efi now included.
-* Thu Sep 21 2006 - 0.1.1-8
+
+* Thu Sep 21 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.1-8
- Added doc files to %doc, removed INSTALLED_FILES code
-* Wed Sep 20 2006 - 0.1.1-7
+
+* Wed Sep 20 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.1-7
- Upstream updates
-* Fri Sep 15 2006 - 0.1.1-6
+
+* Fri Sep 15 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.1-6
- Make koan own it's directory, add GPL "COPYING" file.
-* Wed Aug 16 2006 - 0.1.1-5
+
+* Wed Aug 16 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.1-5
- Spec file tweaks only for FC-Extras
-* Thu Jul 20 2006 - 0.1.1-4
+
+* Thu Jul 20 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.1-4
- Fixed python import paths in yaml code, which errantly assumed yaml was installed as a module.
-* Wed Jul 12 2006 - 0.1.1-3
+
+* Wed Jul 12 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.1-3
- Added templating support using Cheetah
-* Thu Jul 9 2006 - 0.1.0-2
+
+* Thu Jul 9 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.0-2
- Fedora-Extras rpm spec tweaks
-* Tue Jun 28 2006 - 0.1.0-1
+
+* Tue Jun 28 2006 Michael DeHaan <mdehaan@redhat.com> - 0.1.0-1
- rpm genesis
+
diff --git a/cobbler/action_enchant.py b/cobbler/action_enchant.py
new file mode 100644
index 0000000..a71e04a
--- /dev/null
+++ b/cobbler/action_enchant.py
@@ -0,0 +1,67 @@
+"""
+Enables the "cobbler enchant" command to apply profiles
+to remote systems, whether or not they are running koan.
+
+Copyright 2006, Red Hat, Inc
+Michael DeHaan <mdehaan@redhat.com>
+
+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 cexceptions
+import os
+import os.path
+import subprocess
+import pexpect
+import pxssh
+import traceback
+
+class Enchant:
+
+ def __init__(self,config,sysname,profile,system,password):
+ """
+ Constructor. All arguments required.
+ """
+ self.config = config
+ self.settings = self.config.settings()
+ self.username = "root"
+ self.sysname = sysname
+ self.profile = profile
+ self.system = system
+ self.password = password
+
+ def call(self,cmd):
+ """
+ Invoke something over SSH.
+ """
+ print "ssh -> %s" % cmd
+ self.ssh.sendline(cmd)
+ self.ssh.prompt()
+
+ def run(self):
+ """
+ Replace the OS of a remote system.
+ """
+ try:
+ ssh = self.ssh = pxssh.pxssh()
+ if not ssh.login(self.sysname, self.username, self.password):
+ raise cexceptions.CobblerException("enchant_failed","SSH login denied")
+ else:
+ self.call("wget http://%s/cobbler/koan.rpm -o /koan.rpm" % self.settings.server)
+ self.call("rpm -Uvh koan.rpm --force")
+ if self.profile is not None:
+ self.call("koan --replace-self --profile=%s --server=%s" % (self.profile, self.settings.server))
+ return True
+ if self.system is not None:
+ self.call("koan --replace-self --system=%s --server=%s" % (self.system, self.settings.server))
+ return True
+ except:
+ traceback.print_exc()
+ return False
+ return False # shouldn't be here
+
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 02fb186..d7cd1a1 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -14,6 +14,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""
import os
+import os.path
import shutil
import time
import yaml
@@ -63,6 +64,7 @@ class BootSync:
self.validate_kickstarts()
self.configure_httpd()
self.build_trees()
+ self.copy_koan()
if self.settings.manage_dhcp:
self.write_dhcp_file()
try:
@@ -73,6 +75,13 @@ class BootSync:
print >>sys.stderr, "Warning: dhcpd restart failed: ", e
return True
+ def copy_koan(self):
+ koan_path = self.settings.koan_path
+ if koan_path is None:
+ return
+ if not os.path.isfile(koan_path):
+ raise cexceptions.CobblerException("exc_koan_path")
+ self.copyfile(koan_path, os.path.join(self.settings.webdir, "koan.rpm"))
def copy_bootloaders(self):
"""
diff --git a/cobbler/api.py b/cobbler/api.py
index 3ce5038..ffb25ba 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -18,106 +18,114 @@ import config
import utils
import action_sync
import action_check
+import action_enchant
import cexceptions
class BootAPI:
-
def __init__(self):
- """
- Constructor
- """
- self._config = config.Config()
- self.deserialize()
+ """
+ Constructor
+ """
+ self._config = config.Config()
+ self.deserialize()
def clear(self):
- """
- Forget about current list of profiles, distros, and systems
- """
- return self._config.clear()
+ """
+ Forget about current list of profiles, distros, and systems
+ """
+ return self._config.clear()
def systems(self):
- """
- Return the current list of systems
- """
- return self._config.systems()
+ """
+ Return the current list of systems
+ """
+ return self._config.systems()
def profiles(self):
- """
- Return the current list of profiles
- """
- return self._config.profiles()
+ """
+ Return the current list of profiles
+ """
+ return self._config.profiles()
def distros(self):
- """
- Return the current list of distributions
- """
- return self._config.distros()
+ """
+ Return the current list of distributions
+ """
+ return self._config.distros()
def settings(self):
- """
- Return the application configuration
- """
- return self._config.settings()
+ """
+ Return the application configuration
+ """
+ return self._config.settings()
def new_system(self):
- """
- Return a blank, unconfigured system, unattached to a collection
- """
- return self._config.new_system()
+ """
+ Return a blank, unconfigured system, unattached to a collection
+ """
+ return self._config.new_system()
def new_distro(self):
- """
- Create a blank, unconfigured distro, unattached to a collection.
- """
- return self._config.new_distro()
+ """
+ Create a blank, unconfigured distro, unattached to a collection.
+ """
+ return self._config.new_distro()
def new_profile(self):
- """
- Create a blank, unconfigured profile, unattached to a collection
- """
- return self._config.new_profile()
+ """
+ Create a blank, unconfigured profile, unattached to a collection
+ """
+ return self._config.new_profile()
def check(self):
- """
- See if all preqs for network booting are valid. This returns
- a list of strings containing instructions on things to correct.
- An empty list means there is nothing to correct, but that still
- doesn't mean there are configuration errors. This is mainly useful
- for human admins, who may, for instance, forget to properly set up
- their TFTP servers for PXE, etc.
- """
- check = action_check.BootCheck(self._config)
- return check.run()
+ """
+ See if all preqs for network booting are valid. This returns
+ a list of strings containing instructions on things to correct.
+ An empty list means there is nothing to correct, but that still
+ doesn't mean there are configuration errors. This is mainly useful
+ for human admins, who may, for instance, forget to properly set up
+ their TFTP servers for PXE, etc.
+ """
+ check = action_check.BootCheck(self._config)
+ return check.run()
def sync(self,dryrun=True):
- """
- Take the values currently written to the configuration files in
- /etc, and /var, and build out the information tree found in
- /tftpboot. Any operations done in the API that have not been
- saved with serialize() will NOT be synchronized with this command.
- """
- sync = action_sync.BootSync(self._config)
- return sync.run(dryrun=dryrun)
-
+ """
+ Take the values currently written to the configuration files in
+ /etc, and /var, and build out the information tree found in
+ /tftpboot. Any operations done in the API that have not been
+ saved with serialize() will NOT be synchronized with this command.
+ """
+ sync = action_sync.BootSync(self._config)
+ return sync.run(dryrun=dryrun)
+
+ def enchant(self,sysname,profile,system,password):
+ """
+ Apply a system profile to a running remote system, replacing
+ the current OS. Either profile or system should be None, other
+ arguments required.
+ """
+ enchant = action_enchant.Enchant(self._config,sysname,profile,password)
+ return enchant.run()
def serialize(self):
- """
- Save the config file(s) to disk.
- """
- return self._config.serialize()
+ """
+ Save the config file(s) to disk.
+ """
+ return self._config.serialize()
def deserialize(self):
- """
- Load the current configuration from config file(s)
- """
- return self._config.deserialize()
+ """
+ Load the current configuration from config file(s)
+ """
+ return self._config.deserialize()
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 86378f0..cf599bf 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -58,6 +58,7 @@ class BootCLI:
'systems' : self.system,
'system' : self.system,
'sync' : self.sync,
+ 'enchant' : self.enchant_system,
'--help' : self.usage,
'/?' : self.usage
}
@@ -88,7 +89,6 @@ class BootCLI:
commands = {
'--name' : lambda(a): self.api.systems().remove(a),
'--system' : lambda(a): self.api.systems().remove(a),
- '--system' : lambda(a): self.api.systems().remove(a)
}
on_ok = lambda: True
return self.apply_args(args,commands,on_ok)
@@ -134,6 +134,44 @@ class BootCLI:
on_ok = lambda: self.api.systems().add(sys)
return self.apply_args(args,commands,on_ok)
+ def enchant_system(self,args):
+ """
+ Replace an existing running password.
+ """
+ sysname = None
+ profile = None
+ system = None
+ password = None
+ first = None
+ last = None
+ for args in self.args:
+ try:
+ (first, last) = (None, None)
+ (first, last) = args.split("=")
+ except:
+ if first == None:
+ continue
+ raise cexceptions.CobblerException("enchant_args")
+ if first == "--name":
+ sysname = last
+ continue
+ if first == "--profile":
+ profile = last
+ continue
+ if first == "--password":
+ password = last
+ continue
+ if first == "--system":
+ system = last
+ continue
+ else:
+ raise cexceptions.CobblerException("weird_arg",args)
+ if sysname is None or (profile is None and system is None) or password is None or ((not profile is None) and (not system is None)):
+ raise cexceptions.CobblerException("enchant_args")
+ if system is not None:
+ return self.api.enchant(sysname,None,system,password)
+ else:
+ return self.api.enchant(sysname,profile,None,password)
def profile_edit(self,args):
"""
@@ -174,7 +212,6 @@ class BootCLI:
on_ok = lambda: self.api.distros().add(distro)
return self.apply_args(args,commands,on_ok)
-
def apply_args(self,args,input_routines,on_ok):
"""
Custom CLI handling, instead of getopt/optparse.
@@ -223,7 +260,6 @@ class BootCLI:
status = self.api.sync(dryrun=False)
return status
-
def check(self,args):
"""
Check system for network boot decency/prereqs: 'cobbler check'
diff --git a/cobbler/cobbler_msg.py b/cobbler/cobbler_msg.py
index 45da8b5..c642bf0 100644
--- a/cobbler/cobbler_msg.py
+++ b/cobbler/cobbler_msg.py
@@ -20,10 +20,14 @@ _msg_table = {
"distribution" : "Distribution",
"bad_server" : "The 'server' field in /var/lib/cobbler/settings must be set to something other than localhost, or kickstarting features will not work",
"parse_error" : "cobbler could not read %s, replacing...",
+ "no_ssh" : "cobbler can't read ~/.ssh/id_dsa.pub",
+ "exc_koan_path" : "koan_path in /var/lib/cobbler/settings is invalid",
"no_create" : "cobbler could not create: %s",
"no_delete" : "cobbler could not delete: %s",
"no_args" : "this command requires arguments.",
"missing_options" : "cannot perform this action, more arguments are required",
+ "enchant_args" : "usage: cobbler enchant --name=<string> --profile=<string> --password=<string>\nOR:\ncobbler enchant --name=<string> --system=<string> --password=<string>",
+ "enchant_failed" : "enchant failed (%s)",
"unknown_cmd" : "cobbler doesn't understand '%s'",
"bad_arg" : "cobbler was expecting an equal sign in argument '%s'",
"reject_arg" : "the value of parameter '%s' isn't valid",
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 2ada359..2279c91 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -109,9 +109,9 @@ class System(item.Item):
def printable(self,id):
buf = "system %-4s : %s\n" % (id, self.name)
buf = buf + "profile : %s\n" % self.profile
- buf = buf + "kernel options : %s" % self.kernel_options
- buf = buf + "ks metadata : %s" % self.ks_meta
- buf = buf + "pxe arch : %s" % self.pxe_arch
- buf = buf + "pxe hostname : %s" % self.pxe_hostname
+ buf = buf + "kernel options : %s\n" % self.kernel_options
+ buf = buf + "ks metadata : %s\n" % self.ks_meta
+ buf = buf + "pxe arch : %s\n" % self.pxe_arch
+ buf = buf + "pxe hostname : %s\n" % self.pxe_hostname
return buf
diff --git a/setup.py b/setup.py
index 9469385..4209e43 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ import sys
from distutils.core import setup, Extension
import string
-VERSION = "0.2.0"
+VERSION = "0.2.1"
SHORT_DESC = "Boot server configurator"
LONG_DESC = """
Cobbler is a command line tool for simplified configuration of boot/provisioning servers. It is also accessible as a Python library. Cobbler supports PXE, Xen, and re-provisioning an existing Linux system via auto-kickstart. The last two modes require 'koan' to be run on the remote system.