Commit a85fd1a1 authored by Rafael Monnerat's avatar Rafael Monnerat

slapprepare: Removed Slapprepare from this repository

 If still required, slapprepare is present on several tags.
parent 815699aa
Changes
=======
1.2.3 (2013-04-24)
------------------
Fixes:
* Remove the "is it a VM" question, misleading and blocking. This allows to have a second disk (or... a VM) inside of your VM.
1.2.2 (2013-04-24)
------------------
Fixes:
* Correctly chown() SlapOS directories: don't try to chown links.
1.2.1 (2013-04-16)
------------------
Fixes:
* Start VPN if required before registering to SlapOS Master.
1.2.0 (2013-04-16)
------------------
Note: it is no longer possible to run slapprepare without either registering Node or having an existing Node configuration.
New features:
* Add support for any SlapOS Master, not only slapos.org
Fixes:
* Don't force install slapos if already installed.
* Only ask bridge question if it is not a VM.
1.1.2 (2013-04-15)
------------------
Fix:
* Don't raise if impossible to find slapos configuration while trying to setup bridge (bug introduced in 1.0).
1.1.1 (2013-04-15)
------------------
This is a re-release of 1.1.0, including correct "iniparse" dependency.
1.1.0 (2013-04-12)
------------------
New features:
* Will autoreboot after two minutes in case of a kernel panic.
* Ask if machine will host VMs.
1.0.0 (2013-03-07)
------------------
Initial stable release!
New features:
* Chown all files in software root and instance root when doing slapprepare.
It allows easier USB key replacement.
* Completely disable root password. Won't create random password.
1.0a7 (2013-01-24)
------------------
* Fixed a bug where the hostname would contain a newline.
1.0a6 (2013-01-15)
------------------
* Machine tweaks: raise max AIO NR and nofile, set semaphore limits. This
allows to run many instances of apache/mysql/zope on the same machine.
* Mount /var/log on disk in order not to touch USB key.
* When running slapupdate, will update slapprepare as well.
* update crontab so that it calls slapupdate randomly. It means: not all
nodes in the same timezone will try to update at the same time (thus not
kill cache system).
1.0a5 (2013-01-07)
------------------
* autoupdate through easy_install before running slapprepare
* Force start of VPN if defined
* Add limits.conf file preventing fork bombs and ensuring root can spawn lot
of processes
1.0a4 (2012-11-22)
------------------
* Re-release previous version with correct changes.
1.0a3 (2012-11-13)
------------------
* Minor release: doesn't show scary error when modprobe of some monitoring
module can't be done. [Cédric de Saint Martin]
* Change references of VIFIB to slapos.org.
1.0a2 (2012-11-12)
------------------
* Don't crash when we don't want to create slapos.cfg file. [Cédric de Saint
Martin]
1.0a1 (2012-10-30)
------------------
* Initial release on Pypi.
recursive-include slapprepare/template *.in
include slapprepare/script/slapos
include slapprepare/script/slapos_firstboot
include slapprepare/script/slapos.service
include slapprepare/script/run_slapformat
include CHANGES.txt
slapprepare
***********
Slapprepare is the script responsible of preparing an openSUSE computer to run slapos as a dedicated machine.
Process
-------------------------------------------
1. Will parse option and set basic parameters
2. Add slapos repositories with zypper
3. Install latest version of slapos but will deactivate slapos-node service
(Wait till everything is ready)
4. If option --update (-u) is given, it will skip the initial configuration step (disk formatting, etc)
5. Will ask a few questions:
* "Automatically register new computer to Vifib?" (Default is yes)
is yes choosen two more question will follow:
* "Define a unique name for this computer:"
* "Number of SlapOS partitions for this computer? Default is 20 :"
* "Is this a virtual Machine?" (Default is False)
* If not a virtual machine:
* "Do you want to use SlapOS with a second disk?" (Default is True)
If True selected the script slapos_firstboot will be run searching
for second a second disk.
* "Do you want to use vpn to provide ipv6?" (Default is Yes)
If False selected will remove openvpn-needed file in config directory
* "Do you want to force the use lxc on this computer?" (Default is No)
If Yes choosen will run "# touch /etc/opt/slapos/SlapContainer-needed"
* "Do you want a remote ssh access?" (Default is Yes)
If yes is choosen, will later ask for a web address
to download user' public ssh key and put it in root authorized_keys
6. If automatically register to vifib was choosen, it will run slapos node register which prepare slapos configuration
7. Display computer's reference ("Your Computer is : COMP-1234")
8. If remote ssh access was choosen will ask for public key address and download it.
9. Will prepare computer:
* Setting hostname
* Adding the hostname as a valid address
* Creating safe sshd_config
* Creating default bridge config
* If remote ssh: Writing ssh key
* Adding slapos_firstboot in case of MultiDisk usage
10. If multi-disk usage it will run slapos_firstboot and reinstall slapos
11. It will install boot script that are not included in package
* Boot script in "/usr/sbin/slapos-boot-dedicated" and its associated service in:
"/etc/systemd/system/slapos-boot-dedicated.service"
* clientipv4 (openvpn conf)
* Remove script form older versions of slapprepare
12. Configure NTP daemon
13. Will enable an start slapos-boot-dedicated service
About slapos-boot-dedicated
-------------------------------------------
It is in slapprepare/script/slapos
Process
+++++++
1. Deactivate slapos-node.service (daemon from package) to prepare quietly
2. Check ipv4-ipv6 and start openvpn if needed or asked
3. Reset root password
4. Check if slapos is installed (if not reinstall it)
5. Create PKI repository
6. If slapos.cfg is not in /etc/opt/slapos/ it correct path in package
script and cron file
7. Set dedicated cron file "/etc/cron.d/slapos"
- If SlapContainer-needed file in configuration directory will add a line to use it
8. Set various parameters to improve running performance of slapos
How to update you old Suse Image (Suse 12.1 or sooner)
------------------------------------------------------
Run this whole command as root:
# wget zypper remove -y slapos.node; rm -f /etc/opt/slapos/slapos.node*.rpm; easy_install slapparepare && slapprepare -u ;
Check your config
-------------------------------------------
Check your config file and your cron file
+++++++++++++++++++++++++++++++++++++++++
You can use the slapos.cfg.example config file as reference for slapos.cfg.
http://git.erp5.org/gitweb/slapos.core.git/blob_plain/HEAD:/slapos.cfg.example
Check dedicated cron file
+++++++++++++++++++++++++
::
# less /etc/cron.d/slapos
It should contain a call to slapupdate
Check your configuration directory
++++++++++++++++++++++++++++++++++
::
# ls /etc/opt/slapos/
It should only contain your slapos configuration files and \*-needed files
Configure your machine:
-------------------------------------------
LXC
++++
If you want to run lxc on you machine run these command:
# touch /etc/opt/slapos/SlapContainer-needed ; systemctl restart slapos-boot-dedicated.service
from setuptools import setup
version = '1.2.1'
name = 'slapprepare'
long_description = open("README.txt").read() + "\n" + \
open("CHANGES.txt").read() + "\n"
setup(name=name,
version=version,
description="SlapOS Setup kit for dedicated SuSE machines.",
long_description=long_description,
classifiers=[
"Programming Language :: Python",
],
keywords='slapos Setup Kit',
license='GPLv3',
url='http://www.slapos.org',
author='VIFIB',
packages=['slapprepare'],
include_package_data=True,
install_requires=[
'slapos.libnetworkcache',
'iniparse',
],
zip_safe=False,
entry_points={
'console_scripts': [
'slapprepare = slapprepare.autoupdate:main',
'slapprepare-raw = slapprepare.slapprepare:main',
'slapupdate = slapprepare.slapupdate:main',
]
},
)
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
import os
import subprocess
import sys
def do_update():
print 'Updating slapprepare'
subprocess.call(['easy_install', '-U', 'slapprepare'])
def main():
if '--no-update' in sys.argv:
sys.argv.remove('--no-update')
else:
do_update()
args = [
os.path.join(os.path.dirname(sys.argv[0]), 'slapprepare-raw')
] + sys.argv[1:]
subprocess.call(args)
#!/bin/sh
sleep 15
SLAPOS_CONFIGURATION='%(slapos_configuration)s'
i=0
false
while [[ $? != 0 ]]; do
sleep $(($i*60))
if [[ $i < 20 ]]; then
let i++
fi
echo "Retrying slapformat"
/opt/slapos/bin/slapformat --verbose --console $SLAPOS_CONFIGURATION/slapos.cfg
done
\ No newline at end of file
#!/bin/sh
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# 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 3
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
systemctl stop slapos-node.service
systemctl disable slapos-node.service
# clean the system
for service in rpcbind network-remotefs postfix ; do
chkconfig --del $service
/etc/init.d/$service stop
done
IPV6CHECK=ipv6.google.com
IPV4CHECK=google.com
IPV6WAITTIME=5
SLAPOS_CONFIGURATION='%(slapos_configuration)s'
ping -c 2 $IPV4CHECK
while [ $? != 0 ]; do
sleep 5
ping -c 2 $IPV4CHECK
done
echo """Ipv4 connection ok"""
# Wait for native ipv6 connection to be ready
i=0
ping6 -c 2 $IPV6CHECK
while [[ $? != 0 ]] && [[ $i < $IPV6WAITTIME ]]
do
let i++
sleep 1
ping6 -c 2 $IPV6CHECK
done
SLAP_INSTALL_LOG=/opt/slapos/slapos-install.log
while :; do
if [ -f /opt/slapos/bin/slapformat ] && [ -f /opt/slapos/bin/bang ]; then
zypper search -i slapos.node | grep slapos.node > /dev/null
if [ $? != 0 ]; then
echo -n "Installing SlapOS"
zypper --gpg-auto-import-keys install -fy slapos.node
fi
# slapos tools available, nothing to do
break
fi
# software not detected, force forever installation
echo -n "Installing SlapOS"
zypper --gpg-auto-import-keys install -fy slapos.node
done
# Create PKI repository
repo=`egrep ^certificate_repository_path $SLAPOS_CONFIGURATION/slapos.cfg | sed 's/^certificate_repository_path.*= *//'`
mkdir -v -p -m 0755 $repo
# Fix path in case of old config:
SLAPOS_GOOD_CONFIGURATION=/etc/opt/slapos/
if [ $SLAPOS_GOOD_CONFIGURATION != $SLAPOS_CONFIGURATION ]; then
sed -i "s|$SLAPOS_GOOD_CONFIGURATION|$SLAPOS_CONFIGURATION|g" /etc/cron.d/slapos-node
sed -i "s|$SLAPOS_GOOD_CONFIGURATION|$SLAPOS_CONFIGURATION|g" /usr/sbin/slapos-start
fi
# Set up cron
let HOUR=$RANDOM%%23;
let MINUTE=$RANDOM%%60;
echo """# BEWARE: This file will be automatically regenerated on each boot
SHELL=/bin/sh
PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/lib/news/bin
MAILTO=""
$MINUTE $HOUR * * * root /usr/local/bin/slapupdate -v --slapos-configuration $SLAPOS_CONFIGURATION/slapos.cfg >> /opt/slapos/slapupdate.log 2>&1
"""> /etc/cron.d/slapos
if [ -f ${SLAPOS_CONFIGURATION}/SlapContainer-needed ]; then
echo """
# XXX: SlapContainer
*/5 * * * * root if [ -x /opt/slapgrid/843c2b4de8c5579427b072d00ec2ec9e/bin/slapcontainer ] ; then /opt/slapgrid/843c2b4de8c5579427b072d00ec2ec9e/bin/slapcontainer --pid /opt/slapos/slapcontainer.pid ${SLAPOS_CONFIGURATION}slapos.cfg /opt/slapos/slapcontainer.db > /opt/slapos/slapcontainer.log 2>&1 ; fi
""" >> /etc/cron.d/slapos
fi
# Setup more server like network parameters in order to avoid
# "Neighbour table overflow."
# Those machines are itself has a lot of interfaces and are in
# heavily networked environment, so limit of ARP cache for IPv4
# and IPv6 is 4x higher then default
# More tuning can be applied from: http://www.enigma.id.au/linux_tuning.txt
sysctl -w \
net.ipv4.neigh.default.gc_thresh1=512 \
net.ipv4.neigh.default.gc_thresh2=1024 \
net.ipv4.neigh.default.gc_thresh3=2048 \
net.ipv6.neigh.default.gc_thresh1=512 \
net.ipv6.neigh.default.gc_thresh2=1024 \
net.ipv6.neigh.default.gc_thresh3=2048
# software detected, ready to run
systemctl enable slapos-node.service
systemctl start slapos-node.service
# Increase default aio-max-nr for sql servers
sysctl -w fs.aio-max-nr=16777216
# Increase semaphore limits
sysctl -w kernel.sem="1250 256000 100 1024"
# Force reboot after kernel panic
sysctl -w kernel.panic=120
# Enable noop scheduler for disk which have SLAPOS labeled partition
disk=`blkid -L SLAPOS | sed -r -e 's/(\/dev\/|[0-9]*$)//g'`
echo noop > /sys/block/$disk/queue/scheduler
# Set kvm up
modprobe kvm_intel
sleep 1
chmod 666 /dev/kvm
# Set power saving
modprobe acpi_cpufreq > /dev/null 2>&1
# Set hardware monitoring tools (for Shuttle xh61 machines)
modprobe coretemp > /dev/null 2>&1
modprobe f71882fg > /dev/null 2>&1
# Activate KSM (shared memory for KVM)
echo 1 > /sys/kernel/mm/ksm/run
[Unit]
Description=SlapOs Boot script
Requires=basic.target
Wants=network.target remote-fs.target
After=basic.target network.target remote-fs.target
Before=slapos-node.service
[Service]
Type=simple
ExecStart=/usr/sbin/slapos-boot-dedicated
StandardOutput=tty
TTYPath=/dev/console
[Install]
WantedBy=multi-user.target
#!/usr/bin/python
### BEGIN INIT INFO
# Provides: slapos_firstboot
# Required-Start:
# Required-Stop:
# Default-Start:
# Default-Stop:
# Description: Configures first boot of SlapOS
### END INIT INFO
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# 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 3
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import shutil
import subprocess
import tempfile
import time
# some constants
LABEL = "SLAPOS"
MINIMUM_FREE_SPACE_GB = 60
MINIMUM_FREE_SPACE = MINIMUM_FREE_SPACE_GB * 1024 * 1024 * 1024
SLAPOS_MARK = '# Added by SlapOS\n'
def callWithCheck(args):
"""Calls args in subprocesses, raises ValueError if command failed"""
if subprocess.call(args) != 0:
raise ValueError
def callWithIgnore(args):
"""Calls args in subprocess, ignores issues"""
subprocess.call(args)
def partprobe():
"""Calls partprobe utility"""
callWithIgnore("partprobe")
def env():
"""Returns language neutreal environment"""
env = {}
for k, v in os.environ.iteritems():
if 'LANG' not in k:
env[k] = v
env['LANG'] = 'C'
env['LANGUAGE'] = 'C'
return env
def getPartitionList(path):
"""Returns list of all partitions found on disk"""
partprobe()
result = subprocess.Popen(['fdisk', '-l', path], env=env(),
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
partition_list = []
for l in result.split('\n'):
if l.startswith(path):
partition_list.append(l.split()[0])
return partition_list
def setupFilesystem(path):
"""Setups partition on path"""
print "Setting up filesystem on %r" % path
partprobe()
callWithCheck(["mkfs", "-m", "1", "-L", LABEL, "-t", "ext4", path])
partprobe()
def prepareDisk(path):
"""Prepares disk and creates partition"""
callWithCheck(["parted", "--script", path, "mklabel", "msdos"])
callWithCheck(["parted", "--script", '--', path, "mkpart", "primary",
"ext2", "0", "-1"])
partition = path + '1'
setupFilesystem(partition)
def findEmptyDisk():
"""Tries to find not configured yet disk"""
result = subprocess.Popen(['parted', '--script', '-l'], env=env(),
stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]
for line in result.split('\n'):
if 'unrecognised disk label' in line:
disk = line.split(':')[1].strip()
fdisk = subprocess.Popen(['fdisk', '-l', disk], env=env(),
stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]
size = 0
for l in fdisk.split('\n'):
if l.startswith('Disk %s:' % disk):
size = int(l.split(' ')[4])
break
if size > MINIMUM_FREE_SPACE:
return disk
def deactivateSwap():
"""Disactivates swap in /etc/fstab and turns off any existing"""
old_fstab = open('/etc/fstab', 'r').readlines()
fstab = open('/etc/fstab', 'w')
for line in old_fstab:
if 'swap' in line:
line = '#deactivated by slapos#' + line
fstab.write(line)
fstab.close()
callWithIgnore(['swapoff', '-a'])
def prepareSlapOSPartition(mount_point):
"""Prepare SlapOS partitioning"""
new_fstab = open('/etc/fstab', 'r').readlines()
a = new_fstab.append
d = {'label': LABEL}
a(SLAPOS_MARK)
a('LABEL=%(label)s /mnt/%(label)s ext4 defaults,noatime 0 0\n'%
d)
a("/mnt/%(label)s/opt /opt none bind 0 0\n" % d)
a("/mnt/%(label)s/tmp /tmp none bind 0 0\n" % d)
a("/mnt/%(label)s/srv /srv none bind 0 0\n" % d)
a("/mnt/%(label)s/log /var/log none bind 0 0\n" % d)
open('/etc/fstab', 'w').write(''.join(new_fstab))
partprobe()
retry = 10
while True:
try:
print 'Trying to mount new partition, %s to go.' % retry
callWithCheck(['mount', '/mnt/'+LABEL])
except ValueError:
if retry > 0:
retry -= 1
# give some time
time.sleep(2)
else:
raise
else:
break
for d in ['opt', 'srv', 'tmp', 'log']:
p = '/mnt/'+LABEL+'/'+d
if not os.path.exists(p):
os.mkdir(p)
os.chmod(p, 0755)
os.chmod('/mnt/'+LABEL+'/tmp', 01777)
callWithCheck(['mount', '/opt'])
callWithCheck(['mount', '/tmp'])
callWithCheck(['mount', '/srv'])
callWithCheck(['mount', '/var/log'])
def getMountedPartitionList():
partition_list = []
for line in open('/etc/mtab', 'r').readlines():
if line.startswith('/dev'):
partition_list.append(line.split(' ')[0])
return partition_list
def getWidestFreeSpaceList(disk_dict):
free_space_disk_dict = {}
for disk in disk_dict.iterkeys():
v = disk_dict[disk]
for l in v:
size = int(l.split(':')[3].rstrip('B'))
free_space_disk_dict.setdefault(size, [])
free_space_disk_dict[size].append({'disk': disk, 'info': l})
if free_space_disk_dict:
m = max(free_space_disk_dict)
if m > MINIMUM_FREE_SPACE:
return free_space_disk_dict[max(free_space_disk_dict)]
return []
def findAndPrepareFreeSpace():
"""Finds free space, ignoring / mounted device
Prefers disk with correct empty partition table"""
mounted_partition_list = getMountedPartitionList()
disk_dict = {}
parted = subprocess.Popen(['parted', '--script', '-lm'], env=env(),
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
for line in parted.split('\n'):
line = line.strip()
if line.startswith('/dev'):
disk = line.split(':')[0]
if any([q.startswith(disk) for q in mounted_partition_list]):
continue
# disk found, time to fetch free space
disk_dict[disk] = []
free = subprocess.Popen(['parted', '--script', '-m', disk, 'unit', 'B', 'print',
'free'], env=env(),
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
for f in free.split('\n'):
if ':free;' in f:
disk_dict[disk].append(f.strip())
disk_space_list = getWidestFreeSpaceList(disk_dict)
if len(disk_space_list) == 0:
raise ValueError('Minumum of free space %sGB not found' % MINIMUM_FREE_SPACE_GB)
disk = disk_space_list[0]
beg = disk['info'].split(':')[1].rstrip('B')
end = disk['info'].split(':')[2].rstrip('B')
before = getPartitionList(disk['disk'])
callWithCheck(['parted', '--script', '-m', '-a', 'optimal', '--',
disk['disk'], 'unit', 'B', 'mkpart', 'primary', 'ext2', beg, end])
after = getPartitionList(disk['disk'])
new = [q for q in after if q not in before]
setupFilesystem(new[0])
return disk['disk']
def configureGrub(mount_point, slapos_label_file):
"""Configures grub on mount_point using disk"""
boot = os.path.join(mount_point, 'boot')
grub = os.path.join(boot, 'grub')
if not os.path.exists(boot):
os.mkdir(boot)
if os.path.exists(grub):
shutil.rmtree(grub)
shutil.copytree('/boot/grub', grub)
open(os.path.join(grub, 'menu.lst'), 'w').write("""timeout 3600
title SlapOS Error: The USB key is not first and bootable device
root (hd0,1)
chainloader +1
title Solution: Put the USB key
root (hd0,1)
chainloader +1
title Solution: Configure BIOS -- boot from USB key
root (hd0,1)
chainloader +1
title Solution: Configure BIOS -- USB key as first device
root (hd0,1)
chainloader +1
""")
new_map_path = tempfile.mkstemp()[1]
new_map = open(new_map_path, 'w')
disk = os.path.realpath(os.path.join(os.path.dirname(slapos_label_file),
os.readlink(slapos_label_file)))
# this represents /dev/sdXN, so simply let's remove all possible numbers
# from right
# Note: This method's perfectioness is same as rest in this script, high
# dependency on system configuration
disk = disk.rstrip('0123456789')
new_map.write(open('/boot/grub/device.map').read() + '\n(hd1) %s'% disk)
new_map.close()
grub_install = subprocess.Popen(['grub', '--batch', '--device-map=%s' %
new_map], stdin=subprocess.PIPE)
grub_install.communicate("""root (hd1,0)
setup (hd1)
quit
""")
os.unlink(new_map_path)
if grub_install.returncode is None or grub_install.returncode != 0:
raise ValueError('Issue during grub installation')
def run():
"""Prepares machine to run SlapOS"""
print "Running SUSE Studio first boot script..."
partprobe()
slapos_label_file='/dev/disk/by-label/' + LABEL
if not os.path.exists(slapos_label_file):
empty_disk = findEmptyDisk()
if empty_disk is not None:
print "Found empty disk %r, configuring it" % empty_disk
prepareDisk(empty_disk)
else:
print "No empty disk found, trying to find the biggest possible free space"
findAndPrepareFreeSpace()
deactivateSwap()
mount_point = '/mnt/' + LABEL
if not os.path.exists(mount_point):
os.mkdir(mount_point)
os.chmod(mount_point, 0755)
print 'Reconfiguring fstab'
prepareSlapOSPartition(mount_point)
print "Configuring fallback grub information"
configureGrub(mount_point, slapos_label_file)
if __name__ == '__main__':
try:
run()
except:
import traceback
sleep = 120
print "There was uncaught issue with SlapOS configuration"
print "System will be restarted in %ss" % sleep
print "Below traceback might be useful:"
traceback.print_exc()
time.sleep(sleep)
callWithIgnore(['init', '6'])
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# 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 3
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from optparse import OptionParser, Option
import ConfigParser
import os
import pkg_resources
import pwd
import socket
import subprocess
import sys
import time
import urllib2
import iniparse
SLAPOS_MARK = '# Added by SlapOS\n'
class Parser(OptionParser):
def __init__(self, usage=None, version=None):
"""
Initialize all possible options.
"""
OptionParser.__init__(self, usage=usage, version=version,
option_list=[
Option("-u", "--update",
default=False,
action="store_true",
help="Will only run an update for scripts."),
Option("-v", "--verbose",
default=False,
action="store_true",
help="Verbose output."),
Option("-n", "--dry-run",
help="Simulate the execution steps",
default=False,
action="store_true"),
]
)
def check_args(self):
"""
Check arguments
"""
(options, args) = self.parse_args()
return options
class SlapError(Exception):
"""
Slap error
"""
def __init__(self, message):
self.msg = message
class UsageError(SlapError):
pass
class ExecError(SlapError):
pass
def _call(cmd_args, stdout=None, stderr=None, dry_run=False):
"""
Wrapper for subprocess.call() which'll secure the usage of external program's.
Args:
cmd_args: list of strings representing the command and all it's needed args
stdout/stderr: only precise PIPE (from subprocess) if you don't want the
command to create output on the regular stream
"""
print "Calling: %s" % ' '.join(cmd_args)
try:
if subprocess.call(cmd_args, stdout=stdout, stderr=stderr) != 0:
raise ValueError('Issues during running %r' % cmd_args)
except OSError as e:
raise ExecError('Process responded: "%s" when calling "%s"' %
(e, ' '.join(cmd_args)))
# Utility function to get yes/no answers
def get_yes_no(prompt, default=None):
if default:
def_value = '/ Default yes'
elif default is False:
def_value = '/ Default no'
else:
def_value = ''
while True:
answer = raw_input(prompt + " [y,n] %s: " % def_value)
if answer.upper() in ['Y', 'YES']:
return True
if answer.upper() in ['N', 'NO']:
return False
if not answer and default is not None:
return default
def getSlaposConfiguration(slapos_configuration_file_path=None):
config = ConfigParser.RawConfigParser()
# Search slapos.cfg
if not slapos_configuration_file_path:
slapos_configuration_file_path = "/etc/opt/slapos/slapos.cfg"
slapos_configuration_file_path_old = "/etc/slapos/slapos.cfg"
if not os.path.isfile(slapos_configuration_file_path):
if os.path.isfile(slapos_configuration_file_path_old):
slapos_configuration_file_path = slapos_configuration_file_path_old
else:
# No configuration found : returning
return {}
# Reading slapos paths from configuration file
config.read(slapos_configuration_file_path)
return config
# Return OpenSUSE version if it is SuSE
def suse_version():
if not os.path.exists('/etc/SuSE-release'):
return 0
with open('/etc/SuSE-release') as f:
for line in f:
if "VERSION" in line:
dist = line.split()
return float(dist[2])
# Parse certificate to get computer name and return it
def get_computer_name(slapos_configuration):
try:
return getSlaposConfiguration(slapos_configuration).get('slapos',
'computer_id')
except:
print "Warning: slapos.cfg doesn't exist. Using current hostname."
return socket.gethostname()
def setup_bridge(slapos_configuration, create_tap):
slapos_cfg_path = os.path.join(slapos_configuration, 'slapos.cfg')
# using iniparse instead of ConfigParser, will retain the comments
slapos_cfg = iniparse.RawConfigParser()
slapos_cfg.read(slapos_cfg_path)
slapos_cfg.set('slapformat', 'create_tap', 'true' if create_tap else 'false')
with open(slapos_cfg_path, 'w') as fout:
slapos_cfg.write(fout)
# Function to get ssh key
def get_ssh(temp_dir):
# Downloading ssh_key
count = 10
gotten = True
while count > 0:
try:
print "Enter the url of your public ssh key"
ssh_web = raw_input('--> ')
try:
ssh_key_all = urllib2.urlopen(''.join(ssh_web))
gotten = True
except ValueError:
# add http:// if it is missing (needed by urllib2)
ssh_web = """http://""" + ssh_web
ssh_key_all = urllib2.urlopen(''.join(ssh_web))
gotten = True
except urllib2.URLError:
print " URL ERROR"
gotten = False
count -= 1
if gotten:
ssh_pub_key = ssh_key_all.read()
print ssh_pub_key
if get_yes_no('Is this your ssh public key?'):
break
else:
count -= 1
ssh_file = open(os.path.join(temp_dir, "authorized_keys"), "w")
ssh_file.write(''.join(ssh_pub_key))
ssh_file.close()
return 0
def remove_former_scripts(slapos_configuration):
"""
Will remove former scripts
"""
# Remove old-fashioned slapos service
try:
_call(['systemctl', 'disable', 'slapos.service'])
except:
pass
_call(['rm', '-f', os.path.join(slapos_configuration, 'slapos')])
_call(['rm', '-f', '/etc/systemd/system/slapos.service'])
_call(['rm', '-f', '/etc/openvpn/client.conf'])
_call(['rm', '-rf', '/etc/openvpn/keys/'])
_call(['rm', '-f', os.path.join(slapos_configuration, 'run_slapformat')])
# Specific function to configure SlapOS Image
def slapserver(config):
dry_run = config.dry_run
mount_dir_path = config.mount_dir_path
try:
# Setting hostname
hostname_path = os.path.normpath('/'.join([mount_dir_path,
config.hostname_path]))
print "Setting hostname in : %s" % hostname_path
if not dry_run:
open(hostname_path, 'w').write("%s\n" % config.computer_id)
# Adding the hostname as a valid address
host_path = os.path.normpath('/'.join([mount_dir_path,
config.host_path]))
print "Creating %r" % host_path
if not dry_run:
open(host_path, 'w').write(
pkg_resources.resource_stream(__name__,
'template/hosts.in').read() % dict(
computer_id=config.computer_id))
# Creating safe sshd_config
sshd_path = os.path.normpath('/'.join([mount_dir_path, 'etc', 'ssh',
'sshd_config']))
print "Creating %r" % sshd_path
if not dry_run:
open(sshd_path, 'w').write(
pkg_resources.resource_stream(__name__,
'template/sshd_config.in').read())
os.chmod(sshd_path, 0600)
# Creating default bridge config
br0_path = os.path.normpath('/'.join([mount_dir_path, 'etc',
'sysconfig', 'network', 'ifcfg-br0']))
print "Creating %r" % br0_path
if not dry_run:
open(br0_path, 'w').write(
pkg_resources.resource_stream(__name__,
'template/ifcfg-br0.in').read())
# Creating default limits config
limits_conf_path = os.path.join(mount_dir_path,
'etc', 'security', 'limits.conf')
print "Overriding %s" % limits_conf_path
if not dry_run:
open(limits_conf_path, 'w').write(
pkg_resources.resource_stream(__name__,
'template/limits.conf.in').read())
# Writing ssh key
if config.need_ssh:
user_path = os.path.normpath('/'.join([mount_dir_path, 'root']))
ssh_key_directory = os.path.normpath('/'.join([user_path, '.ssh']))
ssh_key_path = os.path.normpath('/'.join([ssh_key_directory,
'authorized_keys']))
stat_info = os.stat(user_path)
uid, gid = stat_info.st_uid, stat_info.st_gid
ssh_key_directory = os.path.dirname(ssh_key_path)
if not os.path.exists(ssh_key_directory):
print "Creating ssh directory: %s" % ssh_key_directory
if not dry_run:
os.mkdir(ssh_key_directory)
if not dry_run:
print "Setting uid:gid of %r to %s:%s" % (ssh_key_directory, uid, gid)
os.chown(ssh_key_directory, uid, gid)
os.chmod(ssh_key_directory, 0700)
print "Creating file: %s" % ssh_key_path
if not dry_run:
open(ssh_key_path, 'a').write(''.join(open(config.key_path, 'r').read()))
if not dry_run:
print "Setting uid:gid of %r to %s:%s" % (ssh_key_path, uid, gid)
os.chown(ssh_key_path, uid, gid)
os.chmod(ssh_key_path, 0600)
# Put file to force VPN if user asked
if config.force_slapcontainer:
if not dry_run:
open(os.path.join(config.slapos_configuration, 'SlapContainer-needed'), 'w')
# Adding slapos_firstboot in case of MultiDisk usage
if not config.one_disk:
for script in ['slapos_firstboot']:
path = os.path.join(mount_dir_path, 'etc', 'init.d', script)
print "Creating %r" % path
if not dry_run:
open(path, 'w').write(pkg_resources.resource_stream(__name__,
'script/%s' % script).read())
os.chmod(path, 0755)
else:
for script in ['slapos_firstboot']:
path = os.path.join(mount_dir_path, 'etc', 'init.d', script)
if os.path.exists(path):
print "Removing %r" % path
if not dry_run:
os.remove(path)
# Disable login by password for root
_call(['passwd', '-d', 'root'])
finally:
print "SlapOS Image configuration: DONE"
return 0
def prepare_scripts(config):
"""
Will prepare script for slapos dedicated computer
"""
dry_run = config.dry_run
# Get slapos.cfg path
if hasattr(config, 'slapos_configuration'):
slapos_configuration = config.slapos_configuration
else:
# Check for config file in /etc/slapos/
if os.path.exists('/etc/slapos/slapos.cfg'):
slapos_configuration = '/etc/slapos/'
else:
slapos_configuration = '/etc/opt/slapos/'
# Creating boot script
path = os.path.join('/', 'usr', 'sbin', 'slapos-boot-dedicated')
print "Creating %r" % path
if not dry_run:
open(path, 'w').write(
pkg_resources.resource_stream(__name__,
'script/%s' % 'slapos').read()
% {'slapos_configuration': slapos_configuration})
os.chmod(path, 0755)
path = os.path.join('/', 'etc',
'systemd', 'system',
'slapos-boot-dedicated.service')
print "Creating %r" % path
if not dry_run:
open(path, 'w').write(
pkg_resources.resource_stream(__name__,
'script/%s' % 'slapos.service').read()
% dict(slapos_configuration=slapos_configuration))
os.chmod(path, 0755)
# add clientipv4
path = os.path.join('/', 'etc', 'openvpn', 'clientipv4.conf')
print "Creating %r" % path
if not dry_run:
open(path, 'w').write(
pkg_resources.resource_stream(__name__,
'template/%s' % 'clientipv4.conf.in').read())
os.chmod(path, 0755)
# Remove old-timers scripts
remove_former_scripts(slapos_configuration)
def configureNtp():
"""Configures NTP daemon"""
server = "server pool.ntp.org"
old_ntp = open('/etc/ntp.conf', 'r').readlines()
new_ntp = open('/etc/ntp.conf', 'w')
for line in old_ntp:
if line.startswith('server'):
continue
new_ntp.write(line)
new_ntp.write(SLAPOS_MARK)
new_ntp.write(server + '\n')
new_ntp.close()
_call(['chkconfig', '--add', 'ntp'])
_call(['chkconfig', 'ntp', 'on'])
_call(['systemctl', 'enable', 'ntp.service'])
_call(['systemctl', 'restart', 'ntp.service'])
class Config:
def setConfig(self, option_dict):
"""
Set options given by parameters.
"""
# Set options parameters
for option, value in option_dict.__dict__.items():
setattr(self, option, value)
def slaposConfig(self,
mount_dir_path,
slapos_configuration,
hostname_path,
host_path, key_path,
master_url,
temp_dir,
computer_id):
"""
Set configuration for slapos
"""
self.slapos_configuration = slapos_configuration
self.hostname_path = hostname_path
self.host_path = host_path
self.key_path = key_path
self.master_url = master_url
self.mount_dir_path = mount_dir_path
self.temp_dir = temp_dir
self.computer_id = computer_id
def userConfig(self):
# XXX-Testme: test each possible scenario
# XXX don't use self.xx but return a dict so that it is stateless
# and easy to test
# XXX rename "get_yes_no" so that we don't have insane cases like
# "if not get_yes_no('...')"
already_configured = getSlaposConfiguration()
self.certificates = get_yes_no("Automatically register new computer to a SlapOS Master?", True)
if self.certificates:
if already_configured:
if not get_yes_no("A SlapOS Node configuration has been found. Do you want to overwrite it?", False):
print "Okay, let's start from scratch."
return False
self.master_url = raw_input("""SlapOS Master URL? Empty answer will make it use slapos.org Master: """)
if self.master_url:
self.master_url_web = raw_input("""SlapOS Master "web" URL?: """)
else:
self.master_url_web = ''
self.computer_name = raw_input("Define a unique name for this computer: ")
self.partition_amount = raw_input("""Number of SlapOS partitions for this computer? Default is 20: """)
if self.partition_amount == '':
self.partition_amount = '20'
elif not already_configured:
print "No existing Node configuration has been found. please either automatically register or manually setup Node configuration."
print "Starting from scratch..."
return False
self.one_disk = not get_yes_no("Do you want to use SlapOS with a second disk?", True)
self.need_bridge = get_yes_no("Do you want the setup to allow virtual machines inside this node?", True)
self.force_vpn = get_yes_no("Do you want to use vpn to provide ipv6?", True)
self.force_slapcontainer = get_yes_no("Do you want to force the use lxc on this computer?", False)
if self.force_vpn:
self.ipv6_interface = "tapVPN"
else:
self.ipv6_interface = ""
self.need_ssh = get_yes_no("Do you want to (re)configure remote SSH access?", True)
return True
def displayUserConfig(self):
# XXX print everything from configuration, not arbitrary members
if self.certificates:
print "Will register a computer on master"
if self.master_url:
print "URL of master: %s" % self.master_url
print "URL \"web\" of master: %s" % self.master_url_web
print "Number of partition: %s" % (self.partition_amount)
print "Computer name: %s" % self.computer_name
print "Network bridge for hosted VMs: %s" % self.need_bridge
print "Ipv6 over VPN: %s" % self.force_vpn
print "Remote ssh access: %s" % self.need_ssh
print "Prepared to use lxc: %s" % self.force_slapcontainer
print "Use a second disk: %s" % (not self.one_disk)
def prepare_from_scratch(config):
try:
temp_directory = os.path.join('/tmp/slaptemp/')
if not os.path.exists(temp_directory):
print "Creating directory: %s" % temp_directory
os.mkdir(temp_directory, 0711)
while True:
if config.userConfig():
print "\nThis is your configuration: \n"
config.displayUserConfig()
if get_yes_no("\nDo you confirm?"):
break
if config.certificates:
slapos_configuration = '/etc/opt/slapos/'
else:
# Check for config file in /etc/slapos/
if os.path.exists('/etc/slapos/slapos.cfg'):
slapos_configuration = '/etc/slapos/'
else:
slapos_configuration = '/etc/opt/slapos/'
# Prepare Slapos Configuration
if config.certificates:
if config.force_vpn:
print "Starting IPv6 tunnel..."
_call(['systemctl', 'start', 'openvpn.service'])
# XXX better way to check
time.sleep(10)
slapos_register_parameter_list = [
'slapos', 'node', 'register', config.computer_name,
'--interface-name', 'br0',
'--ipv6-interface', config.ipv6_interface,
'--partition-number', config.partition_amount
]
if config.master_url:
slapos_register_parameter_list.extend([
'--master-url', config.master_url,
'--master-url-web', config.master_url_web,
])
_call(slapos_register_parameter_list)
if getSlaposConfiguration():
if config.need_bridge:
setup_bridge(slapos_configuration, True)
else:
setup_bridge(slapos_configuration, False)
else:
print 'Warning: impossible to set up bridge because slapos configuration doesn\'t exist.'
computer_id = get_computer_name(
os.path.join('/', slapos_configuration, 'slapos.cfg'))
print "Your Computer is : %s" % computer_id
config.slaposConfig(mount_dir_path='/',
slapos_configuration=slapos_configuration,
hostname_path='/etc/HOSTNAME',
host_path='/etc/hosts',
key_path=os.path.join(temp_directory, 'authorized_keys'),
master_url="""https://slap.vifib.com""",
temp_dir=temp_directory,
computer_id=computer_id)
# Prepare SlapOS Suse Server confuguration
if config.need_ssh:
get_ssh(temp_directory)
slapserver(config)
if not config.one_disk:
_call(['/etc/init.d/slapos_firstboot'])
_call(['zypper', '--gpg-auto-import-keys', 'install', '-fy', 'slapos.node'])
_call(['systemctl', 'stop', 'slapos-node.service'])
return_code = 0
except ExecError as err:
print >>sys.stderr, err.msg
return_code = 16
except SystemExit as err:
# Catch exception raise by optparse
return_code = err
if os.path.exists(temp_directory):
print "Deleting directory: %s" % temp_directory
_call(['rm', '-rf', temp_directory])
# Add/remove VPN file forcing/forbidding start of VPN.
if not config.dry_run:
openvpn_needed_file_path = os.path.join(slapos_configuration,
'openvpn-needed')
if config.force_vpn:
# Force use of openvpn
open(openvpn_needed_file_path, 'w')
elif os.path.exists(openvpn_needed_file_path):
# Forbid use of openvpn if not explicitely defined
os.remove(openvpn_needed_file_path)
return return_code
def chownSlaposDirectory():
config = getSlaposConfiguration()
slapos_slapgrid_instance = config.get('slapos', 'instance_root')
slapos_slapgrid_software = config.get('slapos', 'software_root')
slapformat_partition = config.get('slapformat', 'partition_amount')
slapformat_partition_base_name = config.get('slapformat', 'partition_base_name')
slapformat_user_base_name = config.get('slapformat', 'user_base_name')
path = slapos_slapgrid_instance
print "Changing owners of software directory and partitions directories…"
for i in range(int(slapformat_partition)):
uid = pwd.getpwnam('%s%s' % (slapformat_user_base_name, i))[2]
gid = pwd.getpwnam('%s%s' % (slapformat_user_base_name, i))[3]
item = '%s%s' % (slapformat_partition_base_name, i)
if not os.path.islink(os.path.join(path, item)):
os.chown(os.path.join(path, item), uid, gid)
for i in range(int(slapformat_partition)):
path = "%s/%s%s" % (slapos_slapgrid_instance, slapformat_partition_base_name, i)
for root, dirs, files in os.walk(path):
for items in dirs, files:
for item in items:
if not os.path.islink(os.path.join(root, item)):
os.chown(os.path.join(root, item),
pwd.getpwnam('%s%s' % (slapformat_user_base_name, i))[2],
pwd.getpwnam('%s%s' % (slapformat_user_base_name, i))[3])
# chown of software root (/opt/slapgrid)
for root, dirs, files in os.walk(slapos_slapgrid_software):
for items in dirs, files:
for item in items:
if not os.path.islink(os.path.join(root, item)):
os.chown(os.path.join(root, item),
pwd.getpwnam('slapsoft')[2],
pwd.getpwnam('slapsoft')[3])
def slapprepare():
"""
Prepare SlapOS dedicated computer
"""
usage = "usage: %s [options] " % sys.argv[0]
try:
config = Config()
config.setConfig(Parser(usage=usage).check_args())
# Install/update slapos
try:
_call(['zypper', 'addrepo', '-fc', '-n', '"SlapOS Official repo"',
'http://download.opensuse.org/repositories/home:/VIFIBnexedi/openSUSE_%s/' % suse_version(), 'slapos'])
except:
pass
_call(['zypper', '--gpg-auto-import-keys', 'install', '-y', 'slapos.node'])
_call(['systemctl', 'stop', 'slapos-node.service'])
print "SlapOS has been updated"
if not config.update:
prepare_from_scratch(config)
prepare_scripts(config)
configureNtp()
try:
chownSlaposDirectory()
except:
print "Warning: Impossible to change owner of slapos directories."
# Restart sysctl in case of new mount points in /var/log
_call(['systemctl', 'restart', 'syslog.service'])
# Enable and run slapos-boot-dedicated.service
_call(['systemctl', 'enable', 'slapos-boot-dedicated.service'])
_call(['systemctl', 'start', 'slapos-boot-dedicated.service'])
return_code = 0
except UsageError as err:
print >>sys.stderr, err.msg
print >>sys.stderr, "For help use --help"
return_code = 16
except ExecError as err:
print >>sys.stderr, err.msg
return_code = 16
except SystemExit as err:
# Catch exception raise by optparse
return_code = err
sys.exit(return_code)
def main():
slapprepare()
#!/usr/bin/python
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2012 Vifib SARL and Contributors.
# All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# 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 3
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import ConfigParser
import datetime
import logging
from optparse import OptionParser, Option
import os
import subprocess as sub
import sys
import tempfile
import autoupdate
from slapos.networkcachehelper import helper_download_network_cached_to_file
# create console handler and set level to warning
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING)
# create formatter
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s")
# add formatter to ch
ch.setFormatter(formatter)
class Parser(OptionParser):
"""
Parse all arguments.
"""
def __init__(self, usage=None, version=None):
"""
Initialize all options possibles.
"""
OptionParser.__init__(self, usage=usage, version=version,
option_list=[
Option("--slapos-configuration",
default='/etc/opt/slapos/slapos.cfg',
help="Path to slapos configuration file"),
Option("--srv-file",
default='/srv/slapupdate',
help="Server status file."),
Option("-v", "--verbose",
default=False,
action="store_true",
help="Verbose output."),
Option("-n", "--dry-run",
help="Simulate the execution steps",
default=False,
action="store_true"),
])
def check_args(self):
"""
Check arguments
"""
(options, args) = self.parse_args()
return options
class NetworkCache ():
def __init__(self, slapos_conf):
if os.path.exists(slapos_conf):
network_cache_info = ConfigParser.RawConfigParser()
network_cache_info.read(slapos_conf)
self.download_binary_cache_url = network_cache_info.get('networkcache', 'download-binary-cache-url')
self.download_cache_url = network_cache_info.get('networkcache', 'download-cache-url')
self.download_binary_dir_url = network_cache_info.get('networkcache', 'download-binary-dir-url')
self.signature_certificate_list = network_cache_info.get('networkcache', 'signature-certificate-list')
else:
self.download_binary_cache_url = "http://www.shacache.org/shacache"
self.download_cache_url = "https://www.shacache.org/shacache"
self.download_binary_dir_url = "http://www.shacache.org/shadir"
self.signature_certificate_list = ""
self.signature_certificate_list = """
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJANd3qMXJcWPgMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtOTAyMCAXDTEyMDkwNDEyMDM1OFoYDzIxMTIwODExMTIwMzU4WjAT
MREwDwYDVQQDDAhDT01QLTkwMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
nhfhuGEO3gsQXkYjbhMFzY3b74bAcOvT3vwYd3V+V38XYC2Ds7ugyKIp3EisrREN
8bRzxLTJjEwNhBjdS3GfFt/8uxB7hoKul4lEtdYmM4NCIlLbmoXwoJOVYzL7QWNg
4uMEm9Bf46zhgY3ZNgCLELn8YgUDSr/dfdSDnN7wpoUCAwEAAaNQME4wHQYDVR0O
BBYEFHgf9WN8LY9BZvtAcWrGtk6rCTq3MB8GA1UdIwQYMBaAFHgf9WN8LY9BZvtA
cWrGtk6rCTq3MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAIFHRgb3D
7va0+kUmw6xidJf9t4X5bkhOt/FBKpJK3tXctIN6DYPlPcemktMmrnYtYimq387I
NYK/ZbWhfgv7VZqJ2OUvGaDQIm9oAuRfcu7QCbEzN10RibLLRKdDDgIhb34iLxVg
jlD7tZ2DbRKHu5FadsKWNZpqC9H0BRLjBwY=
-----END CERTIFICATE-----
""" + self.signature_certificate_list
def _call(cmd_args, stdout=sub.PIPE, stderr=sub.PIPE, dry_run=False):
"""
Wrapper for subprocess.call() which'll secure the usage of external program's.
Args:
cmd_args: list of strings representing the command and all it's needed args
stdout/stderr: only precise PIPE (from subprocess) if you don't want the
command to create output on the regular stream
"""
print ("Calling: %s" % ' '.join(cmd_args))
if not dry_run:
p = sub.Popen(cmd_args, stdout=stdout, stderr=stderr)
output, err = p.communicate()
return output, err
def suse_version():
"""
Return OpenSUSE version if it is SuSE
"""
if os.path.exists('/etc/SuSE-release'):
with open('/etc/SuSE-release') as f:
for line in f:
if "VERSION" in line:
dist = line.split()
return float(dist[2])
else:
return 0
def repositories_purge():
"""
Remove all repositories
"""
listing, err = _call(['zypper', 'lr'])
while listing.count('\n') > 2:
output, err = _call(['zypper', 'rr', '1'], stdout=None)
listing, err = _call(['zypper', 'lr'])
def repositories_add(url, alias):
""" Add a repository """
output, err = _call(['zypper', 'ar', '-fc', url, alias], stdout=None)
def update_software():
""" Upgrade softwares """
_call(['zypper', '--gpg-auto-import-keys', 'up', '-ly'], stdout=None)
def update_system():
""" Dist-Upgrade of system """
_call(['zypper', '--gpg-auto-import-keys', 'dup', '-ly'], stdout=None)
def update_slapprepare_scripts():
""" Run slapprepare -u (script that upgrade boot scripts and so on) """
_call(['slapprepare', '-u'], stdout=None)
def download_info_from_networkcache(path, slapos_conf):
"""
Download a tar of the repository from cache, and untar it.
"""
shacache = NetworkCache(slapos_conf)
def strategy(entry_list):
"""
Get the latest entry.
"""
timestamp = 0
best_entry = None
for entry in entry_list:
if entry['timestamp'] > timestamp:
best_entry = entry
return best_entry
return helper_download_network_cached_to_file(
path=path,
directory_key='slapos-upgrade',
required_key_list=['timestamp'],
strategy=strategy,
# Then we give a lot of not interesting things
dir_url=shacache.download_binary_dir_url,
cache_url=shacache.download_binary_cache_url,
signature_certificate_list=shacache.signature_certificate_list,
)
def get_info_from_master(config):
"""
Get status information and return its path
"""
info, path = tempfile.mkstemp()
if not download_info_from_networkcache(
path, config.slapos_configuration) == False:
print open(path).read()
return path
else:
raise ValueError("No result from shacache")
def repositories_process(repositories):
"""
Remove and then add needed repositories
"""
repositories_purge()
for key in repositories:
repositories_add(repositories[key], key)
def save_current_state(current_state, config):
"""
Will save ConfigParser to config file
"""
file = open(config.srv_file, "w")
current_state.write(file)
file.close()
def update_machine(config):
"""
Will fetch information from web and update and/or reboot
machine if needed
"""
# Define logger for update_machine
logger = logging.getLogger('Updating your machine')
logger.setLevel(logging.DEBUG)
# add ch to logger
logger.addHandler(ch)
# Get configuration
current_state = ConfigParser.RawConfigParser()
current_state.read(config.srv_file)
next_state = ConfigParser.RawConfigParser()
next_state_file = get_info_from_master(config)
next_state.read(next_state_file)
os.remove(next_state_file)
config.getSystemInfo(current_state, next_state)
config.displayConfig()
# Check if run for first time
if config.first_time:
current_state.add_section('system')
current_state.set('system', 'reboot', config.today.isoformat())
current_state.set('system', 'upgrade', config.today.isoformat())
save_current_state(current_state, config)
# Purge repositories list and add new ones
repositories_process(dict(next_state.items('repositories')))
# Check if dist-upgrade is needed
if suse_version() < config.opensuse_version:
logger.info("We will now upgrade your system")
update_slapprepare_scripts()
update_system()
os.system('reboot')
else:
logger.info("We will now upgrade your packages")
update_software()
autoupdate.do_update()
else:
if config.last_upgrade < config.upgrade:
# Purge repositories list and add new ones
repositories_process(dict(next_state.items('repositories')))
current_state.set('system', 'upgrade', config.today.isoformat())
save_current_state(current_state, config)
if suse_version() < config.opensuse_version:
logger.info("We will now upgrade your system")
update_system()
else:
logger.info("We will now upgrade your packages")
update_software()
autoupdate.do_update()
else:
logger.info("Your system is up to date")
if config.last_reboot < config.reboot:
current_state.set('system', 'reboot', config.today.isoformat())
save_current_state(current_state, config)
os.system('reboot')
# Class containing all parameters needed for configuration
class Config:
def setConfig(self, option_dict):
"""
Set options given by parameters.
"""
# Set options parameters
for option, value in option_dict.__dict__.items():
setattr(self, option, value)
self.today = datetime.date.today()
# Define logger for register
self.logger = logging.getLogger('slapupdate configuration')
self.logger.setLevel(logging.DEBUG)
# add ch to logger
self.logger.addHandler(ch)
if self.verbose:
ch.setLevel(logging.DEBUG)
def getSystemInfo(self, current_state, next_state):
"""
Extract information from config file and server file
"""
self.reboot = datetime.datetime.strptime(next_state.get('system', 'reboot'),
"%Y-%m-%d").date()
self.upgrade = datetime.datetime.strptime(next_state.get('system', 'upgrade'),
"%Y-%m-%d").date()
self.opensuse_version = next_state.getfloat('system', 'opensuse_version')
if not current_state.has_section('system'):
self.first_time = True
else:
self.first_time = False
self.last_reboot = datetime.datetime.strptime(
current_state.get('system', 'reboot'),
"%Y-%m-%d").date()
self.last_upgrade = datetime.datetime.strptime(
current_state.get('system', 'upgrade'),
"%Y-%m-%d").date()
def displayConfig(self):
"""
Display Config
"""
self.logger.debug("reboot %s" % self.reboot)
self.logger.debug("upgrade %s" % self.upgrade)
self.logger.debug("suse version %s" % self.opensuse_version)
if not self.first_time:
self.logger.debug("Last reboot : %s" % self.last_reboot)
self.logger.debug("Last upgrade : %s" % self.last_upgrade)
def main():
"""Update computer and slapos"""
usage = "usage: %s [options] " % sys.argv[0]
# Parse arguments
config = Config()
config.setConfig(Parser(usage=usage).check_args())
#config.displayUserConfig()
update_machine(config)
sys.exit()
#
# hosts This file describes a number of hostname-to-address
# mappings for the TCP/IP subsystem. It is mostly
# used at boot time, when no name servers are running.
# On small systems, this file can be used instead of a
# "named" name server.
# Syntax:
#
# IP-Address Full-Qualified-Hostname Short-Hostname
#
127.0.0.1 %(computer_id)s localhost
# special IPv6 addresses
::1 %(computer_id)s localhost ipv6-localhost ipv6-loopback
fe00::0 ipv6-localnet
ff00::0 ipv6-mcastprefix
ff02::1 ipv6-allnodes
ff02::2 ipv6-allrouters
ff02::3 ipv6-allhosts
BOOTPROTO='dhcp'
BRIDGE='yes'
BRIDGE_FORWARDDELAY='0'
BRIDGE_PORTS='eth0'
BRIDGE_STP='off'
BROADCAST=''
ETHTOOL_OPTIONS=''
IPADDR=''
MTU=''
NAME=''
NETMASK=''
NETWORK=''
REMOTE_IPADDR=''
STARTMODE='auto'
USERCONTROL='no'
* hard nproc 8096
* soft nproc 1024
* hard nofile 32768
* soft nofile 32768
root hard nofile 65535
root soft nofile 65535
PermitRootLogin without-password
AllowUsers root
AddressFamily any
RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile %h/.ssh/authorized_keys
# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no
PasswordAuthentication no
X11Forwarding yes
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL
Subsystem sftp /usr/lib64/ssh/sftp-server
UsePAM yes
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment