Commit 038ff2b2 authored by Nikos Skalkotos's avatar Nikos Skalkotos
Browse files

Merge branch 'master' into debian-wheezy

parents e15f7ba8 94db968f
2014-01-08, v0.6
* Rename the dialog-based application to snf-image-creator and the
non-interactive command line one to snf-mkimage
* Support Windows Server 2012 R2
* Allow image creation for unsupported media
* Make winexe an optional dependency
* Fix bugs
2013-10-09, v0.5.3
* Fix a bug in snf-mkimage expert mode were the program could crash if
the image did not have any image properties
......
......@@ -5,5 +5,5 @@ snf-image-creator is a command line tool for creating OS images to be used with
synnefo.
It comes in 2 variants:
* snf-image-creator: A non-interactive command line program
* snf-mkimage: A user-friendly dialog-based program
* snf-image-creator: A user-friendly dialog-based program
* snf-mkimage: A non-interactive command line program
#!/bin/sh
set -e
PACKAGES_DIR=$1
PACKAGES_DIR="$1"
shift
TEMP_DIR=$(mktemp -d /tmp/devflow_autopkg_XXXXXXX)
TEMP_DIR="$(mktemp -d /tmp/devflow_autopkg_XXXXXXX)"
# Create the packages
devflow-autopkg snapshot -b $TEMP_DIR $@
devflow-autopkg snapshot -b "$TEMP_DIR" "$@"
# MOVE the packages
mkdir -p $PACKAGES_DIR
mv -n $TEMP_DIR/* $PACKAGES_DIR
mkdir -p "$PACKAGES_DIR"
mv -n "$TEMP_DIR"/* "$PACKAGES_DIR"
echo "Moved packages to: $(pwd)/$PACKAGES_DIR"
#!/bin/sh
set -e
DOCS_DIR=$1
DOCS_DIR="$1"
cd docs
make html
cd -
mkdir -p $DOCS_DIR
mv -n docs/_build/html/* $DOCS_DIR
mkdir -p "$DOCS_DIR"
mv -n docs/_build/html/* "$DOCS_DIR"
echo "Moved docs to to: $(pwd)/$DOCS_DIR"
......@@ -50,9 +50,9 @@ copyright = u'2012, 2013 GRNET S.A. All rights reserved'
# built documents.
#
# The short X.Y version.
version = '0.5.3'
version = '0.6'
# The full version, including alpha/beta/rc tags.
release = '0.5.3'
release = '0.6'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......@@ -238,10 +238,10 @@ latex_documents = [
# (source start file, name, description, authors, manual section).
man_pages = [
('man/snf-image-creator', 'snf-image-creator',
'Command line image creator for Synnefo',
'Dialog-based image creator for Synnefo',
'Synnefo development team <synnefo-devel@googlegroups.com>', 1),
('man/snf-mkimage', 'snf-mkimage',
'Dialog-based image creator for Synnefo',
'Command line image creator for Synnefo',
'Synnefo development team <synnefo-devel@googlegroups.com>', 1)
]
......
......@@ -6,69 +6,22 @@ snf-image-creator manual page
Synopsis
--------
**snf-image-creator** [OPTION] <INPUT MEDIA>
**snf-image-creator** [OPTION] [<INPUT MEDIA>]
Description
-----------
Create image out of an <INPUT MEDIA>. The <INPUT MEDIA> may be a block device,
a regular file that represents a hard disk or \`/' to bundle the host system
itself.
itself. If the <INPUT MEDIA> argument is missing, the user will be asked during
the program initializaton to specify one.
Options
-------
-a URL, --authentication-url=URL
use this authentication URL when uploading/registering images
-c CLOUD, --cloud=CLOUD
use this saved cloud account to authenticate against a cloud when
uploading/registering images
--disable-sysprep=SYSPREP
prevent SYSPREP operation from running on the input media
--enable-sysprep=SYSPREP
run SYSPREP operation on the input media
-f, --force
overwrite output files if they exist
--version
show program's version number and exit
-h, --help
show this help message and exit
-m KEY=VALUE, --metadata=KEY=VALUE
add custom KEY=VALUE metadata to the image
--no-shrink
don't shrink any partition
--no-sysprep
don't perform any system preparation operation
-o FILE, --outfile=FILE
dump image to FILE
--public
register image with the storage service as public
--print-sysprep
print the enabled and disabled system preparation operations for this
input media
-r IMAGENAME, --register=IMAGENAME
register the image with the compute service with name IMAGENAME
-s, --silent
output only errors
-t TOKEN, --token=TOKEN
use this token when uploading/registering images
-l FILE, --logfile=FILE
log all messages to FILE
--tmpdir=DIR
create large temporary image files under DIR
-u FILENAME, --upload=FILENAME
save the image to the storage service with remote name FILENAME
--version
show program's version number and exit
......@@ -6,22 +6,78 @@ snf-mkimage manual page
Synopsis
--------
**snf-mkimage** [OPTION] [<INPUT MEDIA>]
**snf-mkimage** [OPTION] <INPUT MEDIA>
Description
-----------
Create image out of an <INPUT MEDIA>. The <INPUT MEDIA> may be a block device,
a regular file that represents a hard disk or \`/' to bundle the host system
itself. If the <INPUT MEDIA> argument is missing, the user will be asked during
the program initializaton to specify one.
itself.
Options
-------
--version
show program's version number and exit
-a URL, --authentication-url=URL
use this authentication URL when uploading/registering images
--allow-unsupported
Proceed with the image creation even if the media is not supported
-c CLOUD, --cloud=CLOUD
use this saved cloud account to authenticate against a cloud when
uploading/registering images
--disable-sysprep=SYSPREP
prevent SYSPREP operation from running on the input media
--enable-sysprep=SYSPREP
run SYSPREP operation on the input media
-f, --force
overwrite output files if they exist
-h, --help
show this help message and exit
-l FILE, --logfile=FILE
log all messages to FILE
-m KEY=VALUE, --metadata=KEY=VALUE
add custom KEY=VALUE metadata to the image
--no-shrink
don't shrink any partition
--no-sysprep
don't perform any system preparation operation
-o FILE, --outfile=FILE
dump image to FILE
--public
register image with the storage service as public
--print-syspreps
print the enabled and disabled system preparation operations for this
input media
--print-sysprep-params
print the needed sysprep parameters for this input media
-r IMAGENAME, --register=IMAGENAME
register the image with the compute service with name IMAGENAME
-s, --silent
output only errors
--sysprep-param=SYSPREP_PARAMS
add KEY=VALUE system preparation parameter
-t TOKEN, --token=TOKEN
use this token when uploading/registering images
--tmpdir=DIR
create large temporary image files under DIR
-u FILENAME, --upload=FILENAME
save the image to the storage service with remote name FILENAME
--version
show program's version number and exit
......@@ -3,8 +3,8 @@ Usage
snf-image-creator comes in 2 variants:
* snf-image-creator: A non-interactive command line program
* snf-mkimage: A user-friendly dialog-based program
* snf-mkimage: A non-interactive command line program
* snf-image-creator: A user-friendly dialog-based program
Both expect the input media as first argument. The input media may be a local
file, a block device or *"/"* if you want to create an image out of the running
......@@ -13,12 +13,12 @@ system (see `host bundling operation`_).
Non-interactive version
=======================
snf-image-creator receives the following options:
snf-mkimage receives the following options:
.. code-block:: console
$ snf-image-creator --help
Usage: snf-image-creator [options] <input_media>
$ snf-mkimage --help
Usage: snf-mkimage [options] <input_media>
Options:
--version show program's version number and exit
......@@ -70,7 +70,7 @@ registered as *private*. Only the user that registers the image can create
VM's out of it. If you want the image to be visible by other user too, use the
*--public* option.
By default, before extracting the image, snf-image-creator will perform a
By default, before extracting the image, snf-mkimage will perform a
number of system preparation operations on the snapshot of the media and will
shrink the last partition found. Both actions can be disabled by specifying
*--no-sysprep* and *--no-shrink* respectively.
......@@ -81,15 +81,15 @@ input media. The user can enable or disable specific *syspreps*, using
*-{enable,disable}-sysprep* options. The user may specify those options
multiple times.
Running *snf-image-creator* with *--print-sysprep* on a raw file that hosts a
Running *snf-mkimage* with *--print-sysprep* on a raw file that hosts a
debian system, we print the following output:
.. _sysprep:
.. code-block:: console
$ snf-image-creator --print-sysprep ubuntu.raw
snf-image-creator 0.3
$ snf-mkimage --print-syspreps ubuntu.raw
snf-image-creator 0.6
=====================
Examining source media `ubuntu_hd.raw' ... looks like an image file
Snapshotting media source ... done
......@@ -150,17 +150,17 @@ removed, you should use *--enable-sysprep* option like this:
.. code-block:: console
$ snf-image-creator --enable-sysprep cleanup-mail --enable-sysprep remove-user-accounts ...
$ snf-mkimage --enable-sysprep cleanup-mail --enable-sysprep remove-user-accounts ...
Dialog-based version
====================
*snf-mkimage* receives the following options:
*snf-image-creator* receives the following options:
.. code-block:: console
$ snf-mkimage --help
Usage: snf-mkimage [options] [<input_media>]
$ snf-image-creator --help
Usage: snf-image-creator [options] [<input_media>]
Options:
--version show program's version number and exit
......@@ -179,12 +179,12 @@ button to create an image out of the running system (see
`Host bundling operation`_).
After the input media is examined and the program is initialized, the user will
be given the choice to run *snf-mkimage* in *wizard* or *expert* mode.
be given the choice to run *snf-image-creator* in *wizard* or *expert* mode.
Wizard mode
-----------
When *snf-mkimage* runs in *wizard* mode, the user is just asked to provide the
When *snf-image-creator* runs in *wizard* mode, the user is just asked to provide the
following basic information:
* Cloud: The cloud account to use to upload and register the resulting image
......@@ -278,13 +278,13 @@ You will be able to boot your installed OS and make any changes you want
$ sudo kvm -m 1G -boot c -drive file=ubuntu.raw,format=raw,cache=none,if=virtio
After you're done, you may use *snf-mkimage* as root to create and upload the
After you're done, you may use *snf-image-creator* as root to create and upload the
image:
.. code-block:: console
$ sudo -s
$ snf-mkimage ubuntu.raw
$ snf-image-creator ubuntu.raw
In the first screen you will be asked to choose if you want to run the program
in *Wizard* or *Expert* mode. Choose *Wizard*.
......
......@@ -101,6 +101,25 @@ def create_image(d, media, out, tmp):
"image": image,
"metadata": metadata}
if image.is_unsupported():
session['excluded_tasks'] = [-1]
session['task_metadata'] = ["EXCLUDE_ALL_TASKS"]
msg = "The system on the input media is not supported." \
"\n\nReason: %s\n\n" \
"We highly recommend not to create an image out of this, " \
"since the image won't be cleaned up and you will not be " \
"able to configure it during the deployment. Press <YES> if " \
"you still want to continue with the image creation process." \
% image._unsupported
if not d.yesno(msg, width=WIDTH, defaultno=1, height=12):
main_menu(session)
d.infobox("Thank you for using snf-image-creator. Bye", width=53)
return 0
msg = "snf-image-creator detected a %s system on the input media. " \
"Would you like to run a wizard to assist you through the " \
"image creation process?\n\nChoose <Wizard> to run the wizard," \
......
......@@ -217,13 +217,26 @@ def register_image(session):
"register it", width=SMALL_WIDTH)
return False
name = ""
description = session['metadata']['DESCRIPTION'] if 'DESCRIPTION' in \
session['metadata'] else ""
while 1:
(code, answer) = d.inputbox("Please provide a registration name:",
width=WIDTH)
fields = [
("Registration name:", name, 60),
("Description (optional):", description, 80)]
(code, output) = d.form(
"Please provide the following registration info:", height=11,
width=WIDTH, form_height=2, fields=fields)
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
return False
name = answer.strip()
name, description = output
name = name.strip()
description = description.strip()
if len(name) == 0:
d.msgbox("Registration name cannot be empty", width=SMALL_WIDTH)
continue
......@@ -238,6 +251,7 @@ def register_image(session):
break
session['metadata']['DESCRIPTION'] = description
metadata = {}
metadata.update(session['metadata'])
if 'task_metadata' in session:
......@@ -583,6 +597,12 @@ def delete_properties(session):
def exclude_tasks(session):
"""Exclude specific tasks from running during image deployment"""
d = session['dialog']
image = session['image']
if image.is_unsupported():
d.msgbox("Image deployment configuration is disabled for unsupported "
"images.", width=SMALL_WIDTH)
return False
index = 0
displayed_index = 1
......
......@@ -88,16 +88,26 @@ class Image(object):
self.out.output('Inspecting Operating System ...', False)
roots = self.g.inspect_os()
if len(roots) == 0:
raise FatalError("No operating system found")
if len(roots) > 1:
raise FatalError("Multiple operating systems found."
"We only support images with one OS.")
if len(roots) == 0 or len(roots) > 1:
self.root = None
self.ostype = "unsupported"
self.distro = "unsupported"
self.guestfs_device = '/dev/sda'
self.size = self.g.blockdev_getsize64(self.guestfs_device)
if len(roots) > 1:
reason = "Multiple operating systems found on the media."
else:
reason = "Unable to detect any operating system on the media."
self.set_unsupported(reason)
return
self.root = roots[0]
self.guestfs_device = self.g.part_to_dev(self.root)
self.meta['PARTITION_TABLE'] = self.g.part_get_parttype('/dev/sda')
self.guestfs_device = '/dev/sda' # self.g.part_to_dev(self.root)
self.size = self.g.blockdev_getsize64(self.guestfs_device)
self.meta['PARTITION_TABLE'] = \
self.g.part_get_parttype(self.guestfs_device)
self.ostype = self.g.inspect_get_type(self.root)
self.distro = self.g.inspect_get_distro(self.root)
......@@ -105,6 +115,20 @@ class Image(object):
'found a(n) %s system' %
self.ostype if self.distro == "unknown" else self.distro)
# Inspect the OS
self.os.inspect()
def set_unsupported(self, reason):
"""Flag this image us ansupported"""
self._unsupported = reason
self.meta['UNSUPPORTED'] = reason
self.out.warn('Media is not supported. Reason: %s' % reason)
def is_unsupported(self):
"""Returns if this image is unsupported"""
return hasattr(self, '_unsupported')
def enable_guestfs(self):
"""Enable the guestfs handler"""
......@@ -264,6 +288,10 @@ class Image(object):
self.out.output("Shrinking image (this may take a while) ...", False)
if self.is_unsupported():
self.out.warn("Shrinking is disabled for unsupported images")
return self.size
sector_size = self.g.blockdev_getss(self.guestfs_device)
last_part = None
......
......@@ -50,6 +50,7 @@ import optparse
import StringIO
import signal
import json
import textwrap
def check_writable_dir(option, opt_str, value, parser):
......@@ -140,6 +141,10 @@ def parse_options(input_args):
help="register image with the cloud as public",
action="store_true")
parser.add_option("--allow-unsupported", dest="allow_unsupported",
help="Proceed with the image creation even if the media "
"is not supported", default=False, action="store_true")
parser.add_option("--tmpdir", dest="tmp", type="string", default=None,
help="create large temporary image files under DIR",
metavar="DIR")
......@@ -273,6 +278,16 @@ def image_creator():
image = disk.get_image(snapshot, sysprep_params=options.sysprep_params)
if image.is_unsupported() and not options.allow_unsupported:
raise FatalError(
"The media seems to be unsupported.\n\n" +
textwrap.fill("To create an image from an unsupported media, "
"you'll need to use the`--allow-unsupported' "
"command line option. Using this is highly "
"discouraged, since the resulting image will "
"not be cleared out of sensitive data and will "
"not get customized during the deployment."))
for sysprep in options.disabled_syspreps:
image.os.disable_sysprep(image.os.get_sysprep_by_name(sysprep))
......@@ -298,6 +313,9 @@ def image_creator():
size = options.shrink and image.shrink() or image.size
metadata.update(image.meta)
if image.is_unsupported():
metadata['EXCLUDE_ALL_TASKS'] = "yes"
# Add command line metadata to the collected ones...
metadata.update(options.metadata)
......@@ -384,6 +402,10 @@ def main():
sys.exit(ret)
except FatalError as e:
colored = sys.stderr.isatty()
warning = \
"The name of the executable has changed. If you want to use the " \
"user-friendly dialog-based program try `snf-image-creator'"
SimpleOutput(colored).warn(warning)
SimpleOutput(colored).error(e)
sys.exit(1)
......
......@@ -144,6 +144,22 @@ class OSBase(object):
except RuntimeError:
self._scrub_support = False
def inspect(self):
"""Inspect the media to check if it is supported"""
if self.image.is_unsupported():
return
self.out.output('Running OS inspection:')
try:
if not self.mount(readonly=True):
raise FatalError("Unable to mount the media read-only")
self._do_inspect()
finally:
self.umount()
self.out.output()
def collect_metadata(self):
"""Collect metadata about the OS"""
try:
......@@ -239,7 +255,7 @@ class OSBase(object):
return
for name, param in self.needed_sysprep_params.items():
self.out.output("\t%s (%s): %s" %
self.out.output("\t%s [%s]: %s" %
(param.description, name,
self.sysprep_params[name] if name in
self.sysprep_params else "(none)"))
......@@ -247,12 +263,17 @@ class OSBase(object):
def do_sysprep(self):
"""Prepare system for image creation."""
self.out.output('Preparing system for image creation:')
if self.image.is_unsupported():
self.out.warn(
"System preparation is disabled for unsupported media")
return
try:
if not self.mount(readonly=False):
raise FatalError("Unable to mount the media read-write")
self.out.output('Preparing system for image creation:')
enabled = [task for task in self.list_syspreps() if task.enabled]
size = len(enabled)
......@@ -351,10 +372,20 @@ class OSBase(object):
if has_ftype(f, ftype):
action(full_path)
def _do_inspect(self):
"""helper method for inspect"""
pass
def _do_collect_metadata(self):
"""helper method for collect_metadata"""
self.meta['ROOT_PARTITION'] = \
"%d" % self.image.g.part_to_partnum(self.root)
try:
self.meta['ROOT_PARTITION'] = \
"%d" % self.image.g.part_to_partnum(self.root)
except RuntimeError:
self.out.warn("Unable to identify the partition number from root "
"partition: %s" % self.root)
self.meta['OSFAMILY'] = self.image.g.inspect_get_type(self.root)
self.meta['OS'] = self.image.g.inspect_get_distro(self.root)
if self.meta['OS'] == "unknown":
......
......@@ -82,6 +82,18 @@ class Freebsd(Unix):
self.out.warn("No passworded users found!")