$ sudo python cobbler_distro_import.py -h
usage: cobbler_distro_import.py [-h] -p PATH -a ARCH [-n NICKNAME]
Import new distro into Cobbler
optional arguments:
-h, --help show this help message and exit
-p PATH, --path PATH [ HTTP(s) | NFS ] path of an ISO
-a ARCH, --arch ARCH Distro architecture, supported are: i386, x86_64, arm
-n NICKNAME, --nickname NICKNAME
Nickname for distribution
$ mount -o loop /tmp/<iso file> /mnt $ cobbler import --path=/mnt --name=<distro_name> \ --arch=<architecture> \ --kickstart=/var/lib/cobbler/kickstarts/<ks_file> $ cobbler distro list # verify work $ cobbler distro report $ umount /mnt $ rm /sascratch/iso/<iso file> # cleanup $ cobbler sync # if you import on master Cobbler
$ sudo cobbler_distro_import.py -p http://mysite.yu/OracleLinux/OL6/U10/i386/OracleLinux-R6-U10-Server-i386-dvd.iso -a i386 Check if Cobbler app is installed Check if OracleLinux-R6-U10-Server-i386-dvd is present. Wget downloading OracleLinux-R6-U10-Server-i386-dvd.iso 100% [........................................................] 3315597312 / 3315597312 OracleLinux-R6-U10-Server-i386-dvd.iso is downloaded Creating temp mount point /mnt/OracleLinux-R6-U10-Server-i386-dvd mount: /dev/loop0 is write-protected, mounting read-only /tmp/OracleLinux-R6-U10-Server-i386-dvd.iso is loop mounted to /mnt/OracleLinux-R6-U10-Server-i386-dvd task started: 2019-01-28_132905_import task started (id=Media import, time=Mon Jan 28 13:29:05 2019) ...shortened ... *** TASK COMPLETE *** OracleLinux-R6-U10-Server-i386-dvd was imported into Cobbler, still it's good to check import logs in /var/log/cobbler/tasks/ Unmount /mnt/OracleLinux-R6-U10-Server-i386-dvd Remove directory /mnt/OracleLinux-R6-U10-Server-i386-dvd Remove /tmp/OracleLinux-R6-U10-Server-i386-dvd.iso task started: 2019-01-28_132956_sync task started (id=Sync, time=Mon Jan 28 13:29:56 2019) ... *** TASK COMPLETE *** Run cobbler sync command
while true; do du -sh /var/www/cobbler/ks_mirror/; sleep 10; done
#!/bin/env python
import os
from time import gmtime, strftime
import datetime
import getpass
import distutils.spawn # check if cobbler is installed
import subprocess
import wget
import sys
import re # regex
import argparse
import logging, logging.handlers
import smtplib # sending email, plain text
from email.mime.text import MIMEText
# --- define colors
class color:
PURPLE = '\033[95m'
CYAN = '\033[96m'
DARKCYAN = '\033[36m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
END = '\033[0m'
# -- Does root run this?
def i_am_root():
"""
Exit if root doesn't run the script
"""
i_am=getpass.getuser()
return True if i_am == "root" else False
if not i_am_root():
sys.exit(color.RED + "Only root can run this script." + color.END )
# -- argument work
parser = argparse.ArgumentParser(description='Import new distro into Cobbler')
parser.add_argument("-p", "--path", help="[ HTTP(s) | NFS ] path of an ISO", required=True)
parser.add_argument("-a", "--arch", help="Distro architecture, supported are: i386, x86_64, arm", required=True)
parser.add_argument("-n", "--nickname", help="Nickname for distribution")
args = parser.parse_args()
iso_source_path=args.path
distro_arch=args.arch
nickname=args.nickname
# -- define LOGGING
PROGRAM = os.path.basename(sys.argv[0]) # name of this script
LOG_PATH = ("/var/log/" + PROGRAM) # put together "/var/log/script_name"
if not os.path.exists(LOG_PATH): # create LOG_PATH if doesn't exists
os.makedirs(LOG_PATH)
os.chown(LOG_PATH,-1,580) # root(-1 means no change):crm DSEE group
#os.chown(LOG_PATH,-1,485400023) # root(-1 means no change):userg_sa IPA group
os.chmod(LOG_PATH,0775) # drwxrwxr-x
LOG_FILE = (LOG_PATH + "/" + datetime.datetime.now().strftime("%m-%d-%Y_%Hh%Mm%Ss"))
formatter = logging.Formatter('%(asctime)s:%(levelname)s: %(message)s')
handler = logging.handlers.TimedRotatingFileHandler(LOG_FILE, when='MIDNIGHT', backupCount=50, utc=False)
handler.setFormatter(formatter)
# Set up a specific logger with our desired output level
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.debug("")
logger.debug(color.GREEN + "START AT : " + strftime("%a, %d %b %Y %H:%M:%S", gmtime()) + color.END)
KS_FILE = "/var/lib/cobbler/kickstarts/default.ks" # default ks, for attended installation
VALID_ARCH = re.compile('[iI]386$|[xX]86_64$|[aA][rR][mM]$')
NEW_DISTRO_NAME = subprocess.check_output(['basename %s .iso' % iso_source_path], shell=True).rstrip() # rstrip() remove \n
ISO_NAME = subprocess.check_output(['basename %s' % iso_source_path], shell=True).rstrip()
def find_download_location(location = "/.sascratch/iso/"):
"""
Function has one argument, if it's not provided, then it's /sascratch/iso/,
which is default download place for IPA client, and for DSEE clients it's /tmp/.
But, during testing, /sascratch/iso/ (nfs share) wasn't reliable, import times out,
hence using /tmp/ all the time maybe better. So I just add . in front of sascratch.
"""
global DOWNLOAD_PLACE
if os.path.isdir(location):
DOWNLOAD_PLACE = location
else:
DOWNLOAD_PLACE = "/tmp/"
def is_cobbler_installed():
"""
Check if Cobbler is present
"""
logger.debug("Check if Cobbler app is installed")
print ("Check if Cobbler app is installed")
if not distutils.spawn.find_executable("cobbler"):
logger.debug(color.RED + "Cobbler is not installed on this system." + color.END)
sys.exit(color.RED + "Cobbler is not installed on this system." + color.END)
def is_distro_present():
"""
Check if distro already exists
"""
logger.debug("Check if " + NEW_DISTRO_NAME + " is present.")
print ("Check if " + NEW_DISTRO_NAME + " is present.")
#NEW_DISTRO_STATUS = subprocess.call(['basename %s .iso' % iso_source_path], shell=True) # returns $?
#print ("exit status :" + str(NEW_DISTRO_STATUS))
#NEW_DISTRO_NAME = subprocess.check_output(['basename %s .iso' % iso_source_path], shell=True) # return output
#print ("command's output :" + NEW_DISTRO_NAME)
LIST_DISTRO = subprocess.check_output(['cobbler distro list'], shell=True) # this is string
if LIST_DISTRO.find(NEW_DISTRO_NAME) != -1: #.find returs index if found, and -1 otherwize
logger.debug("Distro " + NEW_DISTRO_NAME + " is already present.") # rstrip() remove \n
sys.exit("Distro " + NEW_DISTRO_NAME + " is already present.")
def get_http_iso():
"""
Get ISO image from HTTP server using wget
"""
if not os.path.exists(DOWNLOAD_PLACE):
logger.debug("Directory " + DOWNLOAD_PLACE + " doesn't exist, check why?")
sys.exit("Directory " + DOWNLOAD_PLACE + " doesn't exist, check why?")
try:
logger.debug("Wget downloading %s " % ISO_NAME)
print ("Wget downloading %s " % ISO_NAME)
os.chdir(DOWNLOAD_PLACE)
file=wget.download(iso_source_path)
logger.debug("%s is downloaded" % ISO_NAME)
print ("\n %s is downloaded" % ISO_NAME)
except:
logger.debug("Can't wget %s " % ISO_NAME)
sys.exit("Can't wget %s " % ISO_NAME)
def get_nfs_iso():
"""
Get ISO image from NFS server using rsync
"""
if not os.path.exists(DOWNLOAD_PLACE):
logger.debug("Directory " + DOWNLOAD_PLACE + " doesn't exist, check why?")
sys.exit("Directory " + DOWNLOAD_PLACE + " doesn't exist, check why?")
try:
logger.debug("Rsync-ing %s " % ISO_NAME)
print ("Rsync-ing %s " % ISO_NAME)
os.chdir(DOWNLOAD_PLACE)
subprocess.call(['rsync --progress -avH %s %s%s'
% (iso_source_path, DOWNLOAD_PLACE, ISO_NAME)], shell=True)
logger.debug("%s is rsync-ed" % ISO_NAME)
print ("\n %s is rsync-ed" % ISO_NAME)
except:
logger.debug("Can't rsync %s from NFS server" % ISO_NAME)
sys.exit("Can't rsync %s from NFS server" % ISO_NAME)
def find_iso_path_type_and_get_iso():
"""
Find if an ISO path is http or nfs location,
then get an ISO
"""
if os.path.isfile(iso_source_path):
# get iso via nfs
get_nfs_iso()
else:
# get iso via http
get_http_iso()
def create_mount_location():
"""
Create mount location
"""
try:
if not os.path.exists("/mnt/%s" % NEW_DISTRO_NAME):
logger.debug("Creating temp mount point /mnt/%s " % NEW_DISTRO_NAME)
print ("Creating temp mount point /mnt/%s " % NEW_DISTRO_NAME)
os.makedirs("/mnt/%s" % NEW_DISTRO_NAME)
except:
logger.debug("Can't create temp mount point /mnt/%s" % NEW_DISTRO_NAME)
sys.exit("Can't create temp mount point /mnt/%s" % NEW_DISTRO_NAME)
def mount_iso():
"""
Mount ISO
"""
try:
subprocess.call(['mount -o loop %s%s /mnt/%s'
% (DOWNLOAD_PLACE, ISO_NAME, NEW_DISTRO_NAME)], shell=True)
logger.debug("%s%s is loop mounted to /mnt/%s" % (DOWNLOAD_PLACE, ISO_NAME, NEW_DISTRO_NAME))
print ("%s%s is loop mounted to /mnt/%s" % (DOWNLOAD_PLACE, ISO_NAME, NEW_DISTRO_NAME))
except:
logger.debug("Can't mount %s%s" % (DOWNLOAD_PLACE, ISO_NAME))
sys.exit("Can't mount %s%s" % (DOWNLOAD_PLACE, ISO_NAME))
def import_distro(nickname = NEW_DISTRO_NAME):
"""
Import distro into Cobbler,
nickname has default values (if user doesn't provide info for them)
"""
try:
subprocess.call(['cobbler import --path=/mnt/%s --name=%s --arch=%s --kickstart=%s'
% (NEW_DISTRO_NAME, nickname, distro_arch, KS_FILE)], shell=True)
logger.debug("%s was imported into Cobbler, still it's good to check import logs in /var/log/cobbler/tasks/" % NEW_DISTRO_NAME)
print ("%s was imported into Cobbler, still it's good to check import logs in /var/log/cobbler/tasks/" % NEW_DISTRO_NAME)
except:
logger.debug("Can't import %s into Cobbler" % NEW_DISTRO_NAME)
sys.exit("Can't import %s into Cobbler" % NEW_DISTRO_NAME)
def cleanup():
"""
Cleanup: unmount /mnt/NEW_DISTRO_NAME, remove directory and downloaded ISO
"""
try:
subprocess.call(['umount /mnt/%s' % NEW_DISTRO_NAME], shell=True)
logger.debug("Unmount /mnt/%s" % NEW_DISTRO_NAME)
print ("Unmount /mnt/%s" % NEW_DISTRO_NAME)
except:
logger.debug("Can't umount /mnt/%s" % NEW_DISTRO_NAME)
sys.exit("Can't umount /mnt/%s" % NEW_DISTRO_NAME)
try:
subprocess.call(['rmdir /mnt/%s' % NEW_DISTRO_NAME], shell=True)
logger.debug("Remove directory /mnt/%s" % NEW_DISTRO_NAME)
print ("Remove directory /mnt/%s" % NEW_DISTRO_NAME)
except:
logger.debug("Can't remove directory /mnt/%s" % NEW_DISTRO_NAME)
sys.exit("Can't remove directory /mnt/%s" % NEW_DISTRO_NAME)
try:
subprocess.call(['rm -f %s%s' % (DOWNLOAD_PLACE, ISO_NAME)], shell=True)
logger.debug("Remove %s%s" % (DOWNLOAD_PLACE, ISO_NAME))
print ("Remove %s%s" % (DOWNLOAD_PLACE, ISO_NAME))
except:
logger.debug("Can't remove %s%s" % (DOWNLOAD_PLACE, ISO_NAME))
sys.exit("Can't remove %s%s" % (DOWNLOAD_PLACE, ISO_NAME))
def cobbler_sync():
"""
The command 'cobbler sync' has to be run so /etc/rsyncd.conf is updated.
This is important on Master Cobbler since a distro will be replicated.
"""
try:
subprocess.call(['cobbler sync'], shell=True)
logger.debug("Run cobbler sync command")
print ("Run cobbler sync command")
except:
logger.debug("Can't run cobbler sync command")
sys.exit("Can't run cobbler sync command")
# ----- MAIN --------------
if __name__ == '__main__':
# print 'This program is being run by itself'
if not VALID_ARCH.match(distro_arch):
sys.exit("%s is not valid architecture" % distro_arch )
else:
find_download_location()
is_cobbler_installed()
is_distro_present()
find_iso_path_type_and_get_iso()
create_mount_location()
mount_iso()
if nickname:
import_distro(nickname)
else:
import_distro()
cleanup()
cobbler_sync()
#else:
# print 'I am being imported from another module'
#logger.debug("\n")
sys.exit(0)
#!/bin/env bash
# Import cobbler disto
# arguments:
# $1 = http path to iso
# $2 = arch
# ks file is hardcoded
# supports IPA clients, must be able to access /sascratch/iso
# ---------------------------
PROGNAME=`basename $0| sed 's/^9//'`
LOGDATE=`date +%Y-%m-%d_%H_%M`
LOG_PATH="/var/log/`basename ${PROGNAME}`"
[ -d /var/log/`basename ${PROGNAME}` ] || mkdir /var/log/`basename ${PROGNAME}`
LOGFILE=${LOG_PATH}/${LOGDATE}.log
readonly loggerinfo="logger -t "${PROGNAME}" Info:"
readonly loggerwarning="logger -t "${PROGNAME}" Warning:"
readonly loggerproblem="logger -t "${PROGNAME}" Problem:"
who_cares="
zarko.dudic@yu.yu \
"
err() {
echo ; echo "Problem: $*" ; echo
${loggerproblem} "$*"
echo "$*" | mail -s "Problem from `hostname`:${PROGNAME}" ${who_cares}
exit 1
}
usage() {
echo "
Usage: ${PROGNAME} <http://iso-path> <arch>
(Cobbler supported) arch: i386, x86_64, arm
"
exit 1
}
# must be two arguments
if [ $# -ne 2 ]; then
usage ; exit 1
fi
readonly distro_name=`basename $1 .iso`
readonly arch=$2
ks_file="/var/lib/cobbler/kickstarts/default.ks"
cleaning() {
[ -d /mnt/${distro_name} ] && rmdir /mnt/${distro_name}
[ -f /sascratch/iso/${distro_name}.iso ] && rm -f /sascratch/iso/${distro_name}.iso
}
# cleaning in case of script termination and regular exit
trap cleaning HUP INT QUIT ABRT EXIT
# ---------- MAIN
(
ls /sascratch/iso/ > /dev/null
if [ $? -ne 0 ]; then
err "Can't access /sascratch/iso/, is this legit Cobbler server, plus IPA client?"
fi
if [ ${arch} != x86_64 -a ${arch} != arm -a ${arch} != i386 ]; then
err "${arch} is not supported architecture, it has to be i386 OR x86_64 OR arm"
fi
# is this cobbler server
which cobbler > /dev/null
if [ $? -ne 0 ]; then
err "Cobbler is not installed"
fi
# check if distro exist
cobbler distro list | grep ${distro_name} > /dev/null
if [ $? -eq 0 ]; then
err "
Distro ${distro_name} import has failed.
Looks like it is already present (or similar one), please check this.
"
fi
# get the ISO
wget -O /sascratch/iso/${distro_name}.iso $1 || \
(
( [ -f /sascratch/iso/${distro_name}.iso ] && \
rm -f /sascratch/iso/${distro_name}.iso
) && \
err "Can't wget $1"
)
# create mount location
[ -d /mnt/${distro_name} ] || ( mkdir /mnt/${distro_name} || err "Can't mkdir /mnt/${distro_name}" )
# mount ISO
mount -o loop /sascratch/iso/${distro_name}.iso /mnt/${distro_name} || \
err "Can't mount /mnt/${distro_name}"
# finally cobbler import
cobbler import \
--path=/mnt/${distro_name} --name=${distro_name} --arch=$2 \
--kickstart=${ks_file} || \
( cleaning ; err "Cobbler import has failed" )
[ -d /mnt/${distro_name} ] && ( umount /mnt/${distro_name} || err "Can't umount /mnt/${distro_name}" )
[ -d /mnt/${distro_name} ] && ( rmdir /mnt/${distro_name} || err "Can't rmdir /mnt/${distro_name}" )
[ -f /sascratch/iso/${distro_name}.iso ] && \
( rm /sascratch/iso/${distro_name}.iso || err "Can't remove /sascratch/iso/${distro_name}.iso" )
echo "${distro_name} import has been successful!" | \
mail -s "`hostname`:${PROGNAME}" ${who_cares} || \
err "Can't send email about successful import"
) > ${LOGFILE} 2>&1
exit 0
set pager=1 if [ -s $prefix/grubenv ]; then load_env fi if [ "${next_entry}" ] ; then set default="${next_entry}" set next_entry= save_env next_entry set boot_once=true else set default="${saved_entry}" fi if [ x"${feature_menuentry_id}" = xy ]; then menuentry_id_option="--id" else menuentry_id_option="" fi export menuentry_id_option if [ "${prev_saved_entry}" ]; then set saved_entry="${prev_saved_entry}" save_env saved_entry set prev_saved_entry= save_env prev_saved_entry set boot_once=true fi function savedefault { if [ -z "${boot_once}" ]; then saved_entry="${chosen}" save_env saved_entry fi } function load_video { if [ x$feature_all_video_module = xy ]; then insmod all_video else insmod efi_gop insmod efi_uga insmod ieee1275_fb insmod vbe insmod vga insmod video_bochs insmod video_cirrus fi } terminal_output console set timeout=200 if [ x$feature_timeout_style = xy ] ; then set timeout_style=menu set timeout=600 # Fallback normal timeout code in case the timeout_style feature is # unavailable. else set timeout=600 fi load_video set gfxpayload=keep insmod gzio insmod part_gpt insmod ext2 menuentry 'OL7.6 aarch64. Text install.' --class red --class gnu-linux --class gnu --class os { linux (http)http://ca-cobbler-master/tftpboot/images/OL-R7-U6_aarch64-arm-arm/vmlinuz \ ks=http://ca-cobbler-master/cblr/svc/op/ks/profile/OL-R7-U6_aarch64-arm-arm \ inst.repo=http://ca-cobbler-master/cobbler/ks_mirror/OL-R7-U6_aarch64-arm \ inst.ks=http://ca-cobbler-master/cblr/svc/op/ks/profile/OL-R7-U6_aarch64-arm-arm \ nomodeset inst.text initrd (http)http://ca-cobbler-master/tftpboot/images/OL-R7-U6_aarch64-arm-arm/initrd.img } menuentry 'Boot OL7.6 aarch64 in RESCUE' --class red --class gnu-linux --class gnu --class os { linux (tftp)/images/OL-R7-U6_aarch64-arm-arm/vmlinuz nomodeset rescue initrd (tftp)/images/OL-R7-U6_aarch64-arm-arm/initrd.img } menuentry 'OL8.1 aarch64. Text install.' --class red --class gnu-linux --class gnu --class os { linux (http)http://ca-cobbler-master/tftpboot/images/OL-R8-U1-aarch64-arm-arm/vmlinuz \ ks=http://ca-cobbler-master/cblr/svc/op/ks/profile/OL-R8-U1-aarch64-arm-arm \ inst.repo=http://ca-cobbler-master/cobbler/ks_mirror/OL-R8-U1-aarch64-arm \ inst.ks=http://ca-cobbler-master/cblr/svc/op/ks/profile/OL-R8-U1-aarch64-arm-arm \ nomodeset inst.text initrd (http)http://ca-cobbler-master/tftpboot/images/OL-R8-U1-aarch64-arm-arm/initrd.img } menuentry 'OL8.1 aarch64 in RESCUE' --class red --class gnu-linux --class gnu --class os { linux (tftp)/images/OL-R8-U1-aarch64-arm-arm/vmlinuz nomodeset rescue initrd (tftp)/images/OL-R8-U1-aarch64-arm-arm/initrd.img }
# x7-2 host dev111.domain.com { hardware ethernet 00:10:e0:da:c6:31; option routers 10.x.x.1; fixed-address 10.x.x.62; next-server 10.x.x.61; filename "grub2/grubx64-ol8_u0.efi"; }
# dev111.domain.com set default=0 set timeout=15 menuentry 'OL-R8-U1-x86_64 UEFI grub2 dev111' { echo "Loading vmlinuz" linuxefi images/OL-R8-U1-x86_64/vmlinuz ksdevice=bootif ks=http://cobbler.domain.com/cblr/svc/op/ks/profile/OL-R8-U1-x86_64 text console=ttyS0,9600 echo "Loading initrd.img" initrdefi images/OL-R8-U1-x86_64/initrd.img echo "Booting kernel" }