summaryrefslogtreecommitdiff
path: root/nfsboot.write
diff options
context:
space:
mode:
Diffstat (limited to 'nfsboot.write')
-rwxr-xr-xnfsboot.write245
1 files changed, 0 insertions, 245 deletions
diff --git a/nfsboot.write b/nfsboot.write
deleted file mode 100755
index 34a7297..0000000
--- a/nfsboot.write
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2013 Codethink Limited
-#
-# 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; version 2 of the License.
-#
-# 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.
-
-
-'''A Morph deployment write extension for deploying to an nfsboot server
-
-An nfsboot server is defined as a baserock system that has tftp and nfs
-servers running, the tftp server is exporting the contents of
-/srv/nfsboot/tftp/ and the user has sufficient permissions to create nfs roots
-in /srv/nfsboot/nfs/
-
-'''
-
-
-import cliapp
-import os
-import glob
-
-import morphlib.writeexts
-
-
-class NFSBootWriteExtension(morphlib.writeexts.WriteExtension):
-
- '''Create an NFS root and kernel on TFTP during Morph's deployment.
-
- The location command line argument is the hostname of the nfsboot server.
- The user is expected to provide the location argument
- using the following syntax:
-
- HOST
-
- where:
-
- * HOST is the host of the nfsboot server
-
- The extension will connect to root@HOST via ssh to copy the kernel and
- rootfs, and configure the nfs server.
-
- It requires root because it uses systemd, and reads/writes to /etc.
-
- '''
-
- _nfsboot_root = '/srv/nfsboot'
-
- def process_args(self, args):
- if len(args) != 2:
- raise cliapp.AppException('Wrong number of command line args')
-
- temp_root, location = args
- hostname = self.get_hostname(temp_root)
- if hostname == 'baserock':
- raise cliapp.AppException('It is forbidden to nfsboot a system '
- 'with hostname "baserock"')
-
- self.test_good_server(location)
- version_label = os.getenv('VERSION_LABEL', 'factory')
- versioned_root = os.path.join(self._nfsboot_root, hostname, 'systems',
- version_label)
- if self.version_exists(versioned_root, location):
- raise cliapp.AppException('Version %s already exists on'
- ' this device. Deployment aborted'
- % version_label)
- self.copy_rootfs(temp_root, location, versioned_root, hostname)
- self.copy_kernel(temp_root, location, versioned_root, version_label,
- hostname)
- self.configure_nfs(location, hostname)
-
- def version_exists(self, versioned_root, location):
- try:
- cliapp.ssh_runcmd('root@%s' % location,
- ['test', '-d', versioned_root])
- except cliapp.AppException:
- return False
-
- return True
-
- def get_hostname(self, temp_root):
- hostnamepath = os.path.join(temp_root, 'etc', 'hostname')
- with open(hostnamepath) as f:
- return f.readline().strip()
-
- def create_local_state(self, location, hostname):
- statedir = os.path.join(self._nfsboot_root, hostname, 'state')
- subdirs = [os.path.join(statedir, 'home'),
- os.path.join(statedir, 'opt'),
- os.path.join(statedir, 'srv')]
- cliapp.ssh_runcmd('root@%s' % location,
- ['mkdir', '-p'] + subdirs)
-
- def copy_kernel(self, temp_root, location, versioned_root, version,
- hostname):
- bootdir = os.path.join(temp_root, 'boot')
- image_names = ['vmlinuz', 'zImage', 'uImage']
- for name in image_names:
- try_path = os.path.join(bootdir, name)
- if os.path.exists(try_path):
- kernel_src = try_path
- break
- else:
- raise cliapp.AppException(
- 'Could not find a kernel in the system: none of '
- '%s found' % ', '.join(image_names))
-
- kernel_dest = os.path.join(versioned_root, 'orig', 'kernel')
- rsync_dest = 'root@%s:%s' % (location, kernel_dest)
- self.status(msg='Copying kernel')
- cliapp.runcmd(
- ['rsync', '-s', kernel_src, rsync_dest])
-
- # Link the kernel to the right place
- self.status(msg='Creating links to kernel in tftp directory')
- tftp_dir = os.path.join(self._nfsboot_root , 'tftp')
- versioned_kernel_name = "%s-%s" % (hostname, version)
- kernel_name = hostname
- try:
- cliapp.ssh_runcmd('root@%s' % location,
- ['ln', '-f', kernel_dest,
- os.path.join(tftp_dir, versioned_kernel_name)])
-
- cliapp.ssh_runcmd('root@%s' % location,
- ['ln', '-sf', versioned_kernel_name,
- os.path.join(tftp_dir, kernel_name)])
- except cliapp.AppException:
- raise cliapp.AppException('Could not create symlinks to the '
- 'kernel at %s in %s on %s'
- % (kernel_dest, tftp_dir, location))
-
- def copy_rootfs(self, temp_root, location, versioned_root, hostname):
- rootfs_src = temp_root + '/'
- orig_path = os.path.join(versioned_root, 'orig')
- run_path = os.path.join(versioned_root, 'run')
-
- self.status(msg='Creating destination directories')
- try:
- cliapp.ssh_runcmd('root@%s' % location,
- ['mkdir', '-p', orig_path, run_path])
- except cliapp.AppException:
- raise cliapp.AppException('Could not create dirs %s and %s on %s'
- % (orig_path, run_path, location))
-
- self.status(msg='Creating \'orig\' rootfs')
- cliapp.runcmd(
- ['rsync', '-asXSPH', '--delete', rootfs_src,
- 'root@%s:%s' % (location, orig_path)])
-
- self.status(msg='Creating \'run\' rootfs')
- try:
- cliapp.ssh_runcmd('root@%s' % location,
- ['rm', '-rf', run_path])
- cliapp.ssh_runcmd('root@%s' % location,
- ['cp', '-al', orig_path, run_path])
- cliapp.ssh_runcmd('root@%s' % location,
- ['rm', '-rf', os.path.join(run_path, 'etc')])
- cliapp.ssh_runcmd('root@%s' % location,
- ['cp', '-a', os.path.join(orig_path, 'etc'),
- os.path.join(run_path, 'etc')])
- except cliapp.AppException:
- raise cliapp.AppException('Could not create \'run\' rootfs'
- ' from \'orig\'')
-
- self.status(msg='Linking \'default\' to latest system')
- try:
- cliapp.ssh_runcmd('root@%s' % location,
- ['ln', '-sfn', versioned_root,
- os.path.join(self._nfsboot_root, hostname, 'systems',
- 'default')])
- except cliapp.AppException:
- raise cliapp.AppException('Could not link \'default\' to %s'
- % versioned_root)
-
- def configure_nfs(self, location, hostname):
- exported_path = os.path.join(self._nfsboot_root, hostname)
- exports_path = '/etc/exports'
- # If that path is not already exported:
- try:
- cliapp.ssh_runcmd(
- 'root@%s' % location, ['grep', '-q', exported_path,
- exports_path])
- except cliapp.AppException:
- ip_mask = '*'
- options = 'rw,no_subtree_check,no_root_squash,async'
- exports_string = '%s %s(%s)\n' % (exported_path, ip_mask, options)
- exports_append_sh = '''\
-set -eu
-target="$1"
-temp=$(mktemp)
-cat "$target" > "$temp"
-cat >> "$temp"
-mv "$temp" "$target"
-'''
- cliapp.ssh_runcmd(
- 'root@%s' % location,
- ['sh', '-c', exports_append_sh, '--', exports_path],
- feed_stdin=exports_string)
- cliapp.ssh_runcmd(
- 'root@%s' % location, ['systemctl', 'restart',
- 'nfs-server.service'])
-
- def test_good_server(self, server):
- # Can be ssh'ed into
- try:
- cliapp.ssh_runcmd('root@%s' % server, ['true'])
- except cliapp.AppException:
- raise cliapp.AppException('You are unable to ssh into server %s'
- % server)
-
- # Is an NFS server
- try:
- cliapp.ssh_runcmd(
- 'root@%s' % server, ['test', '-e', '/etc/exports'])
- except cliapp.AppException:
- raise cliapp.AppException('server %s is not an nfs server'
- % server)
- try:
- cliapp.ssh_runcmd(
- 'root@%s' % server, ['systemctl', 'is-enabled',
- 'nfs-server.service'])
-
- except cliapp.AppException:
- raise cliapp.AppException('server %s does not control its '
- 'nfs server by systemd' % server)
-
- # TFTP server exports /srv/nfsboot/tftp
- try:
- cliapp.ssh_runcmd(
- 'root@%s' % server, ['test' , '-d', '/srv/nfsboot/tftp'])
- except cliapp.AppException:
- raise cliapp.AppException('server %s does not export '
- '/srv/nfsboot/tftp' % server)
-
-NFSBootWriteExtension().run()
-