create: Allow creating LXC/OpenVZ app containers

Simple adds a new install method that allows selecting a local binary,
defaulting to /bin/sh. No support for full OS containers yet.
This commit is contained in:
Cole Robinson 2011-06-07 17:42:50 -04:00
parent a493789fa7
commit 0e11be79a4
3 changed files with 311 additions and 85 deletions

View File

@ -320,6 +320,9 @@ class vmmConnection(vmmGObject):
def is_local(self):
return bool(self.get_uri_hostname() == "localhost")
def is_container(self):
return self.is_lxc() or self.is_openvz()
def is_lxc(self):
if self._is_virtinst_test_uri:
self.get_uri().count(",lxc")

View File

@ -53,7 +53,8 @@ INSTALL_PAGE_ISO = 0
INSTALL_PAGE_URL = 1
INSTALL_PAGE_PXE = 2
INSTALL_PAGE_IMPORT = 3
INSTALL_PAGE_CONTAINER_APP = 4
INSTALL_PAGE_CONTAINER_OS = 5
class vmmCreate(vmmGObjectUI):
def __init__(self, engine):
@ -110,6 +111,7 @@ class vmmCreate(vmmGObjectUI):
"on_install_local_box_changed": self.detect_media_os,
"on_install_local_browse_clicked": self.browse_iso,
"on_install_import_browse_clicked": self.browse_import,
"on_install_app_browse_clicked": self.browse_app,
"on_install_detect_os_toggled": self.toggle_detect_os,
"on_install_os_type_changed": self.change_os_type,
@ -218,7 +220,6 @@ class vmmCreate(vmmGObjectUI):
error)
def set_initial_state(self):
self.window.get_widget("create-pages").set_show_tabs(False)
self.window.get_widget("install-method-pages").set_show_tabs(False)
@ -315,7 +316,6 @@ class vmmCreate(vmmGObjectUI):
uihelpers.set_sparse_tooltip(sparse_info)
def reset_state(self, urihint=None):
self.failed_guest = None
self.have_startup_error = False
self.guest = None
@ -368,6 +368,9 @@ class vmmCreate(vmmGObjectUI):
# Install import
self.window.get_widget("install-import-entry").set_text("")
# Install container app
self.window.get_widget("install-app-entry").set_text("/bin/sh")
# Mem / CPUs
self.window.get_widget("config-mem").set_value(DEFAULT_MEM)
self.window.get_widget("config-cpus").set_value(1)
@ -442,11 +445,13 @@ class vmmCreate(vmmGObjectUI):
is_local = not self.conn.is_remote()
is_storage_capable = self.conn.is_storage_capable()
is_pv = (self.capsguest.os_type == "xen")
is_container = self.conn.is_container()
# Install Options
method_tree = self.window.get_widget("method-tree")
method_pxe = self.window.get_widget("method-pxe")
method_local = self.window.get_widget("method-local")
method_container_app = self.window.get_widget("method-container-app")
method_tree.set_sensitive(is_local)
method_local.set_sensitive(not is_pv)
@ -482,6 +487,13 @@ class vmmCreate(vmmGObjectUI):
util.tooltip_wrapper(method_local, local_tt)
util.tooltip_wrapper(method_pxe, pxe_tt)
# Container install options
method_container_app.set_active(True)
self.window.get_widget("virt-install-box").set_property(
"visible", not is_container)
self.window.get_widget("container-install-box").set_property(
"visible", is_container)
# Install local
iso_option = self.window.get_widget("install-local-iso")
cdrom_option = self.window.get_widget("install-local-cdrom")
@ -778,6 +790,10 @@ class vmmCreate(vmmGObjectUI):
install = _("PXE Install")
elif instmethod == INSTALL_PAGE_IMPORT:
install = _("Import existing OS image")
elif instmethod == INSTALL_PAGE_CONTAINER_APP:
install = _("Application container")
elif instmethod == INSTALL_PAGE_CONTAINER_APP:
install = _("Operating system container")
if len(self.guest.disks) == 0:
storage = _("None")
@ -815,14 +831,20 @@ class vmmCreate(vmmGObjectUI):
return curpage == PAGE_INSTALL
def get_config_install_page(self):
if self.window.get_widget("method-local").get_active():
return INSTALL_PAGE_ISO
elif self.window.get_widget("method-tree").get_active():
return INSTALL_PAGE_URL
elif self.window.get_widget("method-pxe").get_active():
return INSTALL_PAGE_PXE
elif self.window.get_widget("method-import").get_active():
return INSTALL_PAGE_IMPORT
if self.window.get_widget("virt-install-box").get_property("visible"):
if self.window.get_widget("method-local").get_active():
return INSTALL_PAGE_ISO
elif self.window.get_widget("method-tree").get_active():
return INSTALL_PAGE_URL
elif self.window.get_widget("method-pxe").get_active():
return INSTALL_PAGE_PXE
elif self.window.get_widget("method-import").get_active():
return INSTALL_PAGE_IMPORT
else:
if self.window.get_widget("method-container-app").get_active():
return INSTALL_PAGE_CONTAINER_APP
if self.window.get_widget("method-container-os").get_active():
return INSTALL_PAGE_CONTAINER_OS
def get_config_os_info(self):
d_list = self.window.get_widget("install-os-type")
@ -878,6 +900,9 @@ class vmmCreate(vmmGObjectUI):
def get_config_import_path(self):
return self.window.get_widget("install-import-entry").get_text()
def get_config_container_app_path(self):
return self.window.get_widget("install-app-entry").get_text()
def get_default_path(self, name):
# Don't generate a new path if the install failed
if self.failed_guest:
@ -1073,6 +1098,12 @@ class vmmCreate(vmmGObjectUI):
else:
nodetect_label.show()
def browse_app(self, ignore1=None, ignore2=None):
def set_app_path(ignore, path):
self.window.get_widget("install-app-entry").set_text(path)
self._browse_file(set_app_path, is_media=False)
def browse_import(self, ignore1=None, ignore2=None):
def set_import_path(ignore, path):
self.window.get_widget("install-import-entry").set_text(path)
@ -1107,8 +1138,15 @@ class vmmCreate(vmmGObjectUI):
def set_install_page(self):
instnotebook = self.window.get_widget("install-method-pages")
detectbox = self.window.get_widget("install-detect-os-box")
osbox = self.window.get_widget("install-os-distro-box")
instpage = self.get_config_install_page()
# Setting OS value for a container guest doesn't really matter
# at the moment
iscontainer = instpage in [INSTALL_PAGE_CONTAINER_APP,
INSTALL_PAGE_CONTAINER_OS]
osbox.set_property("visible", iscontainer)
# Detection only works/ is valid for URL,
# FIXME: Also works for CDROM if running as root (since we need to
# mount the iso/cdrom), but we should probably make this work for
@ -1125,17 +1163,25 @@ class vmmCreate(vmmGObjectUI):
else:
instnotebook.show()
instnotebook.set_current_page(instpage)
def container_install(self):
return self.get_config_install_page() in [INSTALL_PAGE_CONTAINER_APP,
INSTALL_PAGE_CONTAINER_OS]
def skip_disk_page(self):
return self.get_config_install_page() in [INSTALL_PAGE_IMPORT,
INSTALL_PAGE_CONTAINER_APP,
INSTALL_PAGE_CONTAINER_OS]
def back(self, src_ignore):
notebook = self.window.get_widget("create-pages")
curpage = notebook.get_current_page()
is_import = (self.get_config_install_page() == INSTALL_PAGE_IMPORT)
next_page = curpage - 1
if curpage == PAGE_INSTALL:
self.reset_guest_type()
elif curpage == PAGE_FINISH and is_import:
elif curpage == PAGE_FINISH and self.skip_disk_page():
# Skip over storage page
next_page -= 1
@ -1144,7 +1190,6 @@ class vmmCreate(vmmGObjectUI):
def forward(self, src_ignore=None):
notebook = self.window.get_widget("create-pages")
curpage = notebook.get_current_page()
is_import = (self.get_config_install_page() == INSTALL_PAGE_IMPORT)
if self.have_startup_error:
return
@ -1163,7 +1208,7 @@ class vmmCreate(vmmGObjectUI):
self.guest_from_install_type()
next_page = curpage + 1
if next_page == PAGE_STORAGE and is_import:
if next_page == PAGE_STORAGE and self.skip_disk_page():
# Skip storage page for import installs
next_page += 1
@ -1186,6 +1231,9 @@ class vmmCreate(vmmGObjectUI):
if pagenum == PAGE_INSTALL:
self.detect_media_os()
self.window.get_widget("install-os-distro-box").set_property(
"visible",
not self.container_install())
if pagenum != PAGE_FINISH:
self.window.get_widget("create-forward").show()
@ -1293,9 +1341,9 @@ class vmmCreate(vmmGObjectUI):
ks = None
cdrom = False
is_import = False
init = None
distro, variant, ignore1, ignore2 = self.get_config_os_info()
if instmethod == INSTALL_PAGE_ISO:
instclass = virtinst.DistroInstaller
media = self.get_config_local_media()
@ -1326,6 +1374,13 @@ class vmmCreate(vmmGObjectUI):
if not import_path:
return self.verr(_("A storage path to import is required."))
elif instmethod == INSTALL_PAGE_CONTAINER_APP:
instclass = virtinst.ContainerInstaller
init = self.get_config_container_app_path()
if not init:
return self.verr(_("An application path is required."))
# Build the installer and Guest instance
try:
installer = self.build_installer(instclass)
@ -1351,6 +1406,10 @@ class vmmCreate(vmmGObjectUI):
if extraargs:
self.guest.installer.extraargs = extraargs
if init:
self.guest.installer.init = init
except Exception, e:
return self.verr(_("Error setting install media location."),
str(e))
@ -1383,8 +1442,6 @@ class vmmCreate(vmmGObjectUI):
uihelpers.check_path_search_for_qemu(self.topwin,
self.conn, path)
# Validation passed, store the install path (if there is one) in
# gconf
self.get_config_local_media(store_media=True)

View File

@ -259,91 +259,164 @@
<child>
<widget class="GtkVBox" id="install-box">
<property name="visible">True</property>
<property name="spacing">8</property>
<child>
<widget class="GtkLabel" id="label12">
<widget class="GtkVBox" id="virt-install-box">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Choose how you would like to install the operating system</property>
<property name="spacing">8</property>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Choose how you would like to install the operating system</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment20">
<property name="visible">True</property>
<property name="left_padding">15</property>
<child>
<widget class="GtkVBox" id="vbox19">
<property name="visible">True</property>
<property name="spacing">3</property>
<child>
<widget class="GtkRadioButton" id="method-local">
<property name="label" translatable="yes">_Local install media (ISO image or CDROM)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="method-tree">
<property name="label" translatable="yes">Network _Install (HTTP, FTP, or NFS)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">method-local</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="method-pxe">
<property name="label" translatable="yes">Network _Boot (PXE)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">method-local</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="method-import">
<property name="label" translatable="yes">Import _existing disk image</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">method-local</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">3</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment20">
<widget class="GtkVBox" id="container-install-box">
<property name="visible">True</property>
<property name="left_padding">15</property>
<property name="spacing">8</property>
<child>
<widget class="GtkVBox" id="vbox19">
<widget class="GtkLabel" id="label44">
<property name="visible">True</property>
<property name="spacing">3</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Choose the container type</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment25">
<property name="visible">True</property>
<property name="left_padding">15</property>
<child>
<widget class="GtkRadioButton" id="method-local">
<property name="label" translatable="yes">_Local install media (ISO image or CDROM)</property>
<widget class="GtkVBox" id="vbox23">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="spacing">3</property>
<child>
<widget class="GtkRadioButton" id="method-container-app">
<property name="label" translatable="yes">Application container</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="method-container-os">
<property name="label" translatable="yes">Operating system container</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">method-container-app</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="method-tree">
<property name="label" translatable="yes">Network _Install (HTTP, FTP, or NFS)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">method-local</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="method-pxe">
<property name="label" translatable="yes">Network _Boot (PXE)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">method-local</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="method-import">
<property name="label" translatable="yes">Import _existing disk image</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">method-local</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">3</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
@ -816,6 +889,99 @@ User shouldn't see this.</property>
<property name="type">tab</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox5678">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label43">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Provide the application path:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment24">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkHBox" id="hbox15">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkEntry" id="install-app-entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="install-app-browse">
<property name="label" translatable="yes">Browse...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="activate" handler="on_install_app_browse_activate"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">4</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="labellas40">
<property name="visible">True</property>
<property name="label">App Container</property>
</widget>
<packing>
<property name="position">4</property>
<property name="tab_fill">False</property>
<property name="type">tab</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbozzz">
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="position">5</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="labell444">
<property name="visible">True</property>
<property name="label">OS Container</property>
</widget>
<packing>
<property name="position">5</property>
<property name="tab_fill">False</property>
<property name="type">tab</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
@ -824,7 +990,7 @@ User shouldn't see this.</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox8">
<widget class="GtkVBox" id="install-os-distro-box">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>