涛子 - 简单就是美

成单纯魁增,永继振国兴,克复宗清政,广开家必升

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

https://rhinstaller.github.io/anaconda/intro.html
https://github.com/rhinstaller/pykickstart/blob/master/docs/kickstart-docs.rst

台湾鸟哥写的文档 http://linux.vbird.org/linux_enterprise/0120installation.php

centos 6 install http log

192.168.48.137 - - [25/Jan/2016:17:03:21 +0800] "GET /kickstart/78:2b:cb:69:10:f3 HTTP/1.1" 200 1986 "-" "anaconda/13.21.239" "-"
192.168.48.137 - - [25/Jan/2016:17:03:27 +0800] "GET /centos-6/images/updates.img HTTP/1.1" 404 3650 "-" "anaconda/13.21.239" "-"
192.168.48.137 - - [25/Jan/2016:17:03:27 +0800] "GET /centos-6/images/product.img HTTP/1.1" 404 3650 "-" "anaconda/13.21.239" "-"
192.168.48.137 - - [25/Jan/2016:17:03:41 +0800] "GET /centos-6/images/install.img HTTP/1.1" 200 157290496 "-" "anaconda/13.21.239" "-"
192.168.48.137 - - [25/Jan/2016:17:04:26 +0800] "GET /centos-6/.treeinfo HTTP/1.1" 200 338 "-" "urlgrabber/3.9.1" "-"
192.168.48.137 - - [25/Jan/2016:17:04:27 +0800] "GET /centos-6/.treeinfo HTTP/1.1" 200 338 "-" "urlgrabber/3.9.1" "-"
192.168.48.137 - - [25/Jan/2016:17:04:27 +0800] "GET /centos-6/.treeinfo HTTP/1.1" 200 338 "-" "urlgrabber/3.9.1" "-"
192.168.48.137 - - [25/Jan/2016:17:04:27 +0800] "GET /centos-6/repodata/repomd.xml HTTP/1.1" 200 4061 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:27 +0800] "GET /centos-6/repodata/c11b211333eadda7b2e2d0f7fa8ffbf70a1d32d5182babbb43b90427578e2891-primary.sqlite.bz2 HTTP/1.1" 200 4784716 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:28 +0800] "GET /centos-6/repodata/4df092633ebecaeebdd78359a11a3c13f619f22605322e15e5e307beebd8e641-c6-x86_64-comps.xml HTTP/1.1" 200 1233934 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:29 +0800] "GET /centos-6/repodata/repomd.xml HTTP/1.1" 200 4061 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:29 +0800] "GET /centos-6/repodata/c11b211333eadda7b2e2d0f7fa8ffbf70a1d32d5182babbb43b90427578e2891-primary.sqlite.bz2 HTTP/1.1" 200 4784716 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:30 +0800] "GET /centos-6/repodata/4df092633ebecaeebdd78359a11a3c13f619f22605322e15e5e307beebd8e641-c6-x86_64-comps.xml HTTP/1.1" 200 1233934 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:31 +0800] "GET /centos-6/repodata/486d3ee62873814293a1be370640ae9c71863a35c7299eb76739e03369ad0c3f-c6-x86_64-comps.xml.gz HTTP/1.1" 200 224312 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:32 +0800] "GET /centos-6/repodata/486d3ee62873814293a1be370640ae9c71863a35c7299eb76739e03369ad0c3f-c6-x86_64-comps.xml.gz HTTP/1.1" 200 224312 "-" "CentOS (anaconda)/6.7" "-"
192.168.48.137 - - [25/Jan/2016:17:04:37 +0800] "GET /centos-6/repodata/40eeab440905d20a31dd7db33fa8724fba260bcb1047fb6488027b85c22876d2-filelists.sqlite.bz2 HTTP/1.1" 200 6484373 "-" "CentOS (anaconda)/6.7" "-"

centos 7 install http log

192.168.48.136 - - [06/May/2016:15:19:06 +0800] "GET /kickstart/78:2b:cb:69:10:f3 HTTP/1.1" 200 1150 "-" "curl/7.29.0" "-"
192.168.48.136 - - [06/May/2016:15:19:07 +0800] "GET /centos-7/.treeinfo HTTP/1.1" 200 1109 "-" "curl/7.29.0" "-"
192.168.48.136 - - [06/May/2016:15:19:32 +0800] "GET /centos-7/LiveOS/squashfs.img HTTP/1.1" 200 293052416 "-" "curl/7.29.0" "-"
192.168.48.136 - - [06/May/2016:15:19:32 +0800] "GET /centos-7/images/updates.img HTTP/1.1" 404 3650 "-" "curl/7.29.0" "-"
192.168.48.136 - - [06/May/2016:15:19:32 +0800] "GET /centos-7/images/product.img HTTP/1.1" 404 3650 "-" "curl/7.29.0" "-"
192.168.48.122 - - [06/May/2016:15:19:58 +0800] "GET /centos-7/.treeinfo HTTP/1.1" 200 1109 "-" "urlgrabber/3.10" "-"
192.168.48.122 - - [06/May/2016:15:19:58 +0800] "GET /centos-7/repodata/repomd.xml HTTP/1.1" 200 3734 "-" "CentOS (anaconda)/7 yum/3.4.3" "-"
192.168.48.122 - - [06/May/2016:15:19:58 +0800] "GET /centos-7/.treeinfo HTTP/1.1" 200 1109 "-" "urlgrabber/3.10" "-"
192.168.48.122 - - [06/May/2016:15:19:58 +0800] "GET /centos-7/repodata/5e7aa50a6f6811cee0b55013e2b742ef0aec84cdfdd5ae84875117c283e6aad0-primary.xml.gz HTTP/1.1" 200 312815 "-" "CentOS (anaconda)/7 yum/3.4.3" "-"
192.168.48.122 - - [06/May/2016:15:19:58 +0800] "GET /centos-7/repodata/4a04a16ba51071ab8942bc507087ed59cac82e9b22134b322f1452a45b87a1a2-c7-minimal-x86_64-comps.xml.gz HTTP/1.1" 200 3663 "-" "CentOS (anaconda)/7 yum/3.4.3" "-"
192.168.48.122 - - [06/May/2016:15:19:58 +0800] "GET /centos-7/repodata/90e86d06e1784b6846551fbfb92a21711a570eb3ce99ca4916a8a7344c916d58-primary.sqlite.bz2 HTTP/1.1" 200 631308 "-" "CentOS (anaconda)/7 yum/3.4.3" "-"

linux的安装流程 isolinux/vmlinuz -> isolinux/initrd.img -> /init -> /sbin/loader -> imagaes/install.img -> /usr/bin/anaconda
从上面的http下载日志可以看到在下载pxe所指示的kickstart文件以后,系统下载install.img进入安装过程。

centos7

label linux
  menu label ^Install CentOS 7
  kernel vmlinuz
  append initrd=initrd.img inst.stage2=hd:LABEL=CentOS\x207\x20x86_64 quiet

# inst.stage2=hd:LABEL=CentOS\x207\x20x86_64

centos6

label linux
  menu label ^Install or upgrade an existing system
  menu default
  kernel vmlinuz
  append initrd=initrd.img

解压initrd.img

file initrd.img
initrd.img: XZ compressed data

mv initrd.img initrd.img.xz
xz --format=lzma initrd.img.xz --decompress

mkdir initrd && cd initrd
cpio -ivdum < ../initrd.img

解压install.img

file install.img 
install.img: Squashfs filesystem, little endian, version 4.0, 157290118 bytes, 14956 inodes, blocksize: 131072 bytes, created: Wed Aug  5 05:41:04 2015

使用centos minimal做过安装源参考以下
http://tapira.hatenablog.com/entry/2015/05/26/115637

关于安装过程的监控交互,可以参考cobbler
http://cobbler.github.io/manuals/2.6.0/Appendix/E_-_Anaconda_Monitoring.html

kickstart

%pre
$SNIPPET('pre_anamon')

%post
$SNIPPET('post_anamon')

pre_anamon

#if $str($getVar('anamon_enabled','')) == "1"
curl -o /tmp/anamon "http://$server:$http_port/cobbler/aux/anamon"
python /tmp/anamon --name "$name" --server "$server" --port "$http_port"
#end if

post_anamon

#if $str($getVar('anamon_enabled','')) == "1"

## install anamon script
curl -o /usr/local/sbin/anamon "http://$server:$http_port/cobbler/aux/anamon"
## install anamon system service
curl -o /etc/rc.d/init.d/anamon "http://$server:$http_port/cobbler/aux/anamon.init"

## adjust permissions
chmod 755 /etc/rc.d/init.d/anamon /usr/local/sbin/anamon
test -d /selinux && restorecon /etc/rc.d/init.d/anamon /usr/local/sbin/anamon

## enable the script
chkconfig --add anamon

## configure anamon service
cat << __EOT__ > /etc/sysconfig/anamon
COBBLER_SERVER="$server"
COBBLER_PORT="$http_port"
COBBLER_NAME="$name"
LOGFILES="/var/log/boot.log /var/log/messages /var/log/dmesg /root/ks-post.log"
__EOT__

#end if

anamon

#!/usr/bin/python

"""
This is a script used to automatically log details from an Anaconda
install back to a cobbler server.
Copyright 2008, Red Hat, Inc and Others
various@redhat.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301  USA
"""

import os
import sys
import string
import time
import re
import base64
import shlex

# on older installers (EL 2) we might not have xmlrpclib
# and can't do logging, however this is more widely
# supported than remote syslog and also provides more
# detail.
try:
    import xmlrpclib
except ImportError, e:
    print "xmlrpclib not available, exiting"
    sys.exit(0)

# shlex.split support arrived in python-2.3, the following will provide some
# accomodation for older distros (e.g. RHEL3)
if not hasattr(shlex, "split"):
    shlex.split = lambda s: s.split(" ")

class WatchedFile:
    def __init__(self, fn, alias):
        self.fn = fn
        self.alias = alias
        self.reset()

    def reset(self):
        self.where = 0
        self.last_size = 0
        self.lfrag=''
        self.re_list={}
        self.seen_line={}

    def exists(self):
        return os.access(self.fn, os.F_OK)

    def lookfor(self,pattern):
        self.re_list[pattern] = re.compile(pattern,re.MULTILINE)
        self.seen_line[pattern] = 0

    def seen(self,pattern):
        if self.seen_line.has_key(pattern):
            return self.seen_line[pattern]
        else:
            return 0

    def changed(self):
        if not self.exists():
            return 0
        size = os.stat(self.fn)[6]
        if size > self.last_size:
            self.last_size = size
            return 1
        else:
            return 0

    def uploadWrapper(self, blocksize = 262144):
        """upload a file in chunks using the uploadFile call"""
        retries = 3
        fo = file(self.fn, "r")
        totalsize = os.path.getsize(self.fn)
        ofs = 0
        while True:
            lap = time.time()
            contents = fo.read(blocksize)
            size = len(contents)
            data = base64.encodestring(contents)
            if size == 0:
                offset = -1
                sz = ofs
            else:
                offset = ofs
                sz = size
            del contents
            tries = 0
            while tries <= retries:
                debug("upload_log_data('%s', '%s', %s, %s, ...)\n" % (name, self.alias, sz, offset))
                if session.upload_log_data(name, self.alias, sz, offset, data):
                    break
                else:
                    tries = tries + 1
            if size == 0:
                break
            ofs += size
        fo.close()

    def update(self):
        if not self.exists():
            return
        if not self.changed():
            return
        try:
            self.uploadWrapper()
        except:
            raise

class MountWatcher:

    def __init__(self,mp):
        self.mountpoint = mp
        self.zero()

    def zero(self):
        self.line=''
        self.time = time.time()

    def update(self):
        found = 0
        if os.path.exists('/proc/mounts'):
            fd = open('/proc/mounts')
            while 1:
                line = fd.readline()
                if not line:
                    break
                parts = string.split(line)
                mp = parts[1]
                if mp == self.mountpoint:
                    found = 1
                    if line != self.line:
                        self.line = line
                        self.time = time.time()
            fd.close()
        if not found:
            self.zero()

    def stable(self):
        self.update()
        if self.line and (time.time() - self.time > 60):
            return 1
        else:
            return 0

def anamon_loop():
    alog = WatchedFile("/tmp/anaconda.log", "anaconda.log")
    alog.lookfor("step installpackages$")

    slog = WatchedFile("/tmp/syslog", "sys.log")
    xlog = WatchedFile("/tmp/X.log", "X.log")
    llog = WatchedFile("/tmp/lvmout", "lvmout.log")
    storage_log = WatchedFile("/tmp/storage.log", "storage.log")
    prgm_log = WatchedFile("/tmp/program.log", "program.log")
    vnc_log = WatchedFile("/tmp/vncserver.log", "vncserver.log")
    kcfg = WatchedFile("/tmp/ks.cfg", "ks.cfg")
    scrlog = WatchedFile("/tmp/ks-script.log", "ks-script.log")
    dump = WatchedFile("/tmp/anacdump.txt", "anacdump.txt")
    mod = WatchedFile("/tmp/modprobe.conf", "modprobe.conf")
    kspre = WatchedFile("/tmp/ks-pre.log", "ks-pre.log")

    # Setup '/mnt/sysimage' watcher
    sysimage = MountWatcher("/mnt/sysimage")

    # Monitor for {install,upgrade}.log changes
    package_logs = list()
    package_logs.append(WatchedFile("/mnt/sysimage/root/install.log", "install.log"))
    package_logs.append(WatchedFile("/mnt/sysimage/tmp/install.log", "tmp+install.log"))
    package_logs.append(WatchedFile("/mnt/sysimage/root/upgrade.log", "upgrade.log"))
    package_logs.append(WatchedFile("/mnt/sysimage/tmp/upgrade.log", "tmp+upgrade.log"))

    # Monitor for bootloader configuration changes
    bootloader_cfgs = list()
    bootloader_cfgs.append(WatchedFile("/mnt/sysimage/boot/grub/grub.conf", "grub.conf"))
    bootloader_cfgs.append(WatchedFile("/mnt/sysimage/boot/etc/yaboot.conf", "yaboot.conf"))
    bootloader_cfgs.append(WatchedFile("/mnt/sysimage/boot/efi/efi/redhat/elilo.conf", "elilo.conf"))
    bootloader_cfgs.append(WatchedFile("/mnt/sysimage/etc/zipl.conf", "zipl.conf"))

    # Were we asked to watch specific files?
    watchlist = list()
    waitlist = list()
    if watchfiles:
        # Create WatchedFile objects for each requested file
        for watchfile in watchfiles:
            if os.path.exists(watchfile):
                watchfilebase = os.path.basename(watchfile)
                watchlog = WatchedFile(watchfile, watchfilebase)
                watchlist.append(watchlog)

    # Use the default watchlist and waitlist
    else:
        watchlist = [alog, slog, dump, scrlog, mod, llog, kcfg, storage_log, prgm_log, vnc_log, xlog, kspre]
        waitlist.extend(package_logs)
        waitlist.extend(bootloader_cfgs)

    # Monitor loop
    while 1:
        time.sleep(5)

        # Not all log files are available at the start, we'll loop through the
        # waitlist to determine when each file can be added to the watchlist
        for watch in waitlist:
            if alog.seen("step installpackages$") or (sysimage.stable() and watch.exists()):
                debug("Adding %s to watch list\n" % watch.alias)
                watchlist.append(watch)
                waitlist.remove(watch)

        # Send any updates
        for wf in watchlist:
            wf.update()

        # If asked to run_once, exit now
        if exit:
            break

# Establish some defaults
name = ""
server = ""
port = "80"
daemon = 1
debug = lambda x,**y: None
watchfiles = []
exit = False

# Process command-line args
n = 0
while n < len(sys.argv):
    arg = sys.argv[n]
    if arg == '--name':
        n = n+1
        name = sys.argv[n]
    elif arg == '--watchfile':
        n = n+1
        watchfiles.extend(shlex.split(sys.argv[n]))
    elif arg == '--exit':
        exit = True
    elif arg == '--server':
        n = n+1
        server = sys.argv[n]
    elif arg == '--port':
        n = n+1
        port = sys.argv[n]
    elif arg == '--debug':
        debug = lambda x,**y: sys.stderr.write(x % y)
    elif arg == '--fg':
        daemon = 0
    n = n+1

# Create an xmlrpc session handle
session = xmlrpclib.Server("http://%s:%s/cobbler_api" % (server, port))

# Fork and loop
if daemon:
    if not os.fork():
        # Redirect the standard I/O file descriptors to the specified file.
        DEVNULL = getattr(os, "devnull", "/dev/null")
        os.open(DEVNULL, os.O_RDWR) # standard input (0)
        os.dup2(0, 1)               # Duplicate standard input to standard output (1)
        os.dup2(0, 2)               # Duplicate standard input to standard error (2)

        anamon_loop()
        sys.exit(1)
    sys.exit(0)
else:
    anamon_loop()

anamon.init

#!/bin/bash
## BEGIN INIT INFO
# Provides: anamon
# Default-Start: 3 5
# Default-Stop: 0 1 2 4 6
# Required-Start:
# Should-Start: $network
# Short-Description: Starts the cobbler anamon boot notification program
# Description: anamon runs the first time a machine is booted after
#              installation.
## END INIT INFO

#
# anamon: Starts the cobbler post-install boot notification program
#
# chkconfig: 35 99 95
#
# description: anamon runs the first time a machine is booted after
#              installation.
#

LOCKFILE="/var/lock/subsys/anamon"
CFGFILE="/etc/sysconfig/anamon"

# Source function library.
. /etc/init.d/functions

# Source anamon config
. $CFGFILE

LOGFILES=${LOGFILES:-/var/log/boot.log}

# FIXME - can we rely on the koan snippet to update /etc/profile.d/cobbler.sh?
if [ -z "$COBBLER_SERVER" ]; then
    echo "No COBBLER_SERVER defined in $CFGFILE"
    exit 1
fi

if [ -z "$COBBLER_NAME" ]; then
    echo "No COBBLER_NAME defined in $CFGFILE"
    exit 1
fi

if [ -z "$LOGFILES" ]; then
    echo "No LOGFILES defined in $CFGFILE"
    exit 1
fi

start() {
    echo -n $"Starting anamon: "
    daemon /usr/local/sbin/anamon --watchfile \"$LOGFILES\" --name $COBBLER_NAME --server $COBBLER_SERVER --port ${COBBLER_PORT:-80} --exit
    RETVAL=$?
    [ $RETVAL -eq 0 ] && touch $LOCKFILE
    echo

    # Disable service start
    chkconfig anamon off

    return $RETVAL
}

stop () {
    echo -n $"Shutting down anamon: "
    killproc /usr/local/sbin/anamon
    RETVAL=$?
    [ $RETVAL -eq 0 ] && rm -f $LOCKFILE
    echo
    return $RETVAL
}

restart() {
    stop
    start
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    condrestart)
        if [ -f $LOCKFILE ]; then
            restart
        fi
        ;;
    status)
        status anamon
        RETVAL=$?
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart}"
        RETVAL=2
        ;;
esac

exit $RETVAL
posted on 2016-04-28 16:05  北京涛子  阅读(1252)  评论(0编辑  收藏  举报