[prev in list] [next in list] [prev in thread] [next in thread] 

List:       spacewalk-devel
Subject:    [Spacewalk-devel] [PATCH 3/5] spacecmd enhancement: Add kickstart_export command
From:       Steven Hardy <shardy () redhat ! com>
Date:       2012-02-03 7:55:20
Message-ID: 20120203075510.GA18674 () shardy ! csb
[Download RAW message or body]

Adds option to export kickstart profile(s) to JSON format file
---
 spacecmd/src/lib/kickstart.py |  200 +++++++++++++++++++++++++++++++++++++----
 1 files changed, 184 insertions(+), 16 deletions(-)

diff --git a/spacecmd/src/lib/kickstart.py b/spacecmd/src/lib/kickstart.py
index d8aa4eb..90344d3 100644
--- a/spacecmd/src/lib/kickstart.py
+++ b/spacecmd/src/lib/kickstart.py
@@ -25,6 +25,7 @@ from operator import itemgetter
 from optparse import Option
 from urllib2 import urlopen, HTTPError
 from spacecmd.utils import *
+import re
 
 KICKSTART_OPTIONS = ['autostep', 'interactive', 'install', 'upgrade',
                      'text', 'network', 'cdrom', 'harddrive', 'nfs',
@@ -425,6 +426,26 @@ def do_kickstart_details(self, args):
 
 ####################
 
+def kickstart_getcontents(self, profile):
+
+    kickstart = None
+    if self.check_api_version('10.11'):
+        kickstart = self.client.kickstart.profile.downloadRenderedKickstart(\
+                                                       self.session, profile)
+    else:
+        # old versions of th API don't return a rendered Kickstart,
+        # so grab it in a hacky way
+        url = 'http://%s/ks/cfg/label/%s' % (self.server, profile)
+
+        try:
+            logging.debug('Retrieving %s' % url)
+            response = urlopen(url)
+            kickstart = response.read()
+        except HTTPError:
+            logging.error('Could not retrieve the Kickstart file')
+
+    return kickstart
+
 def help_kickstart_getcontents(self):
     print 'kickstart_getcontents: Show the contents of a Kickstart profile'
     print '                   as they would be presented to a client'
@@ -442,23 +463,10 @@ def do_kickstart_getcontents(self, args):
 
     profile = args[0]
 
-    if self.check_api_version('10.11'):
-        kickstart = self.client.kickstart.profile.downloadRenderedKickstart(\
-                                                       self.session, profile)
-    else:
-        # old versions of th API don't return a rendered Kickstart,
-        # so grab it in a hacky way
-        url = 'http://%s/ks/cfg/label/%s' % (self.server, profile)
-
-        try:
-            logging.debug('Retrieving %s' % url)
-            response = urlopen(url)
-            kickstart = response.read()
-        except HTTPError:
-            logging.error('Could not retrieve the Kickstart file')
-            return
+    kickstart = self.kickstart_getcontents(profile)
 
-    print kickstart
+    if kickstart:
+        print kickstart
 
 ####################
 
@@ -1789,4 +1797,164 @@ def do_kickstart_clone(self, args):
                                         options.name,
                                         options.clonename)
 
+####################
+
+def help_kickstart_export(self):
+    print 'kickstart_export: export kickstart profile(s) to json format file'
+    print '''usage: kickstart_export <KSPROFILE>... [options]
+options:
+    -f outfile.json : specify an output filename, defaults to <KSPROFILE>.json
+                      if exporting a single kickstart, profiles.json for multiple
+                      kickstarts, or ks_all.json if no KSPROFILE specified
+                      e.g (export ALL)
+
+Note : KSPROFILE list is optional, default is to export ALL'''
+
+def complete_kickstart_export(self, text, line, beg, end):
+    return tab_completer(self.do_kickstart_list('', True), text)
+
+def export_kickstart_getdetails(self, profile, kickstarts):
+
+    # Get the initial ks details struct from the kickstarts list-of-struct, 
+    # which is returned from kickstart.listKickstarts()
+    logging.debug("Getting kickstart profile details for %s" % profile)
+    details = None
+    for k in kickstarts:
+        if k.get('label') == profile:
+            details = k
+            break
+    logging.debug("Got basic details for %s : %s" % (profile, details))
+
+    # Now use the various other API functions to build up a more complete
+    # details struct for export.  Note there are a some ommisions from the API
+    # e.g the "template" option which enables cobbler templating on scripts
+    details['child_channels'] = \
+        self.client.kickstart.profile.getChildChannels(self.session, profile)
+    details['advanced_opts'] = \
+        self.client.kickstart.profile.getAdvancedOptions(self.session, profile)
+    details['software_list'] = \
+        self.client.kickstart.profile.software.getSoftwareList(self.session,\
+            profile)
+    details['custom_opts'] = \
+        self.client.kickstart.profile.getCustomOptions(self.session, profile)
+    details['script_list'] = \
+        self.client.kickstart.profile.listScripts(self.session, profile)
+    details['ip_ranges'] = \
+        self.client.kickstart.profile.listIpRanges(self.session, profile)
+    logging.debug("About to get variable_list for %s" % profile)
+    details['variable_list'] = \
+        self.client.kickstart.profile.getVariables(self.session, profile)
+    logging.debug("done variable_list for %s = %s" % (profile,\
+        details['variable_list']))
+    # just export the key names, then look for one with the same name on import
+    details['activation_keys'] = [ k['key'] for k in \
+        self.client.kickstart.profile.keys.getActivationKeys(self.session,\
+            profile) ]
+    details['partitioning_scheme'] = \
+        self.client.kickstart.profile.system.getPartitioningScheme(\
+            self.session, profile)
+    details['reg_type'] = \
+        self.client.kickstart.profile.system.getRegistrationType(self.session,\
+            profile)
+    details['config_mgmt'] = \
+        self.client.kickstart.profile.system.checkConfigManagement(\
+            self.session, profile)
+    details['remote_cmds'] = \
+        self.client.kickstart.profile.system.checkRemoteCommands(\
+            self.session, profile)
+    # Just export the file preservation list names, then look for one with the
+    # same name on import
+    details['file_preservations'] = [ f['name'] for f in \
+        self.client.kickstart.profile.system.listFilePreservations(\
+            self.session, profile) ]
+    # just export the key description/names , then look for one with the same 
+    # name on import
+    details['gpg_ssl_keys'] = [ k['description'] for k in \
+        self.client.kickstart.profile.system.listKeys(self.session, profile) ]
+
+    # There's a setLogging() but no getLogging(), so we look in the rendered
+    # kickstart to figure out if pre/post logging is enabled
+    kscontents = self.kickstart_getcontents(profile)
+    if re.search("pre --logfile", kscontents):
+        logging.debug("Detected pre script logging")
+        details['pre_logging'] = True
+    else:
+        details['pre_logging'] = False
+    if re.search("post --logfile", kscontents):
+        logging.debug("Detected post script logging")
+        details['post_logging'] = True
+    else:
+        details['post_logging'] = False
+
+    # There's also no way to get the "Kernel Options" and "Post Kernel Options"
+    # The Post options can be derived from the grubby --default-kernel` --args
+    # line in the kickstart, ugly but at least we can then show some of what's
+    # missing in the warnings that get printed on import
+    if re.search("`/sbin/grubby --default-kernel` --args=", kscontents):
+        post_kopts = \
+            kscontents.split("`/sbin/grubby --default-kernel` --args=")[1].\
+                split("\"")[1]
+        logging.debug("Post kernel options %s detected" % post_kopts)
+        details['post_kopts'] = post_kopts
+
+    return details
+
+def do_kickstart_export(self, args):
+    options = [ Option('-f', '--file', action='store') ]
+    (args, options) = parse_arguments(args, options)
+
+    filename=""
+    if options.file != None:
+        logging.debug("Passed filename do_kickstart_export %s" % \
+            options.file)
+        filename=options.file
+
+    # Get the list of profiles to export and sort out the filename if required
+    profiles=[]
+    if not len(args):
+        if len(filename) == 0:
+            filename="ks_all.json"
+        logging.info("Exporting ALL kickstart profiles to %s" % filename)
+        profiles = self.do_kickstart_list('', True)
+    else:
+        # allow globbing of kickstart kickstart names
+        profiles = filter_results(self.do_kickstart_list('', True), args)
+        logging.debug("kickstart_export called with args %s, profiles=%s" % \
+            (args, profiles))
+        if (len(profiles) == 0):
+            logging.error("Error, no valid kickstart profile passed, " + \
+                "check name is  correct with spacecmd kickstart_list")
+            return
+        if len(filename) == 0:
+            # No filename arg, so we try to do something sensible:
+            # If we are exporting exactly one ks, we default to ksname.json
+            # otherwise, generic ks_profiles.json name
+            if len(profiles) == 1:
+                filename="%s.json" % profiles[0]
+            else:
+                filename="ks_profiles.json"
+
+    # First grab the list of basic details about all kickstarts because you
+    # can't get details-per-label, call here to avoid potential duplicate calls
+    # in export_kickstart_getdetails for multi-profile exports
+    kickstarts = self.client.kickstart.listKickstarts(self.session)
+
+    # Dump as a list of dict
+    ksdetails_list=[]
+    for p in profiles:
+        logging.info("Exporting ks %s to %s" % (p, filename))
+        ksdetails_list.append(self.export_kickstart_getdetails(p, kickstarts))
+
+    logging.debug("About to dump %d ks profiles to %s" % \
+        (len(ksdetails_list), filename))
+    # Check if filepath exists, if an existing file we prompt for confirmation
+    if os.path.isfile(filename):
+        if not self.user_confirm("File %s exists, " % filename + \
+                    "confirm overwrite file? (y/n)"):
+            return
+    if json_dump_to_file(ksdetails_list, filename) != True:
+        logging.error("Error saving exported kickstart profiles to file" % \
+            filename)
+        return
+
 # vim:ts=4:expandtab:
-- 
1.7.1

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic