PV/ramdisk, PV/args and PV/bootloader\_args will be passed to the
bootloader unmodified, and interpretation of those fields is then specific
to the bootloader itself, including the possibility that the bootloader
-will ignore some or all of those given values.
+will ignore some or all of those given values. Finally the paths of all
+bootable disks are added to the bootloader commandline (a disk is bootable
+if its VBD has the bootable flag set). There may be zero, one or many
+bootable disks; the bootloader decides which disk (if any) to boot from.
If the bootloader is pygrub, then the menu.lst is parsed if present in the
guest's filesystem, otherwise the specified kernel and ramdisk are used, or
$\mathit{RW}$ & {\tt VM} & VM ref & the virtual machine \\
$\mathit{RW}$ & {\tt VDI} & VDI ref & the virtual disk \\
$\mathit{RW}$ & {\tt device} & string & device seen by the guest e.g. hda1 \\
-$\mathit{RW}$ & {\tt mode} & vbd\_mode & the mode the disk should be mounted with \\
+$\mathit{RW}$ & {\tt bootable} & bool & true if this VBD is bootable \\
+$\mathit{RW}$ & {\tt mode} & vbd\_mode & the mode the VBD should be mounted with \\
$\mathit{RW}$ & {\tt type} & vbd\_type & how the VBD will appear to the guest (e.g. disk or CD) \\
$\mathit{RW}$ & {\tt driver} & driver\_type & the style of driver \\
$\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s) \\
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_bootable}
+
+{\bf Overview:}
+Get the bootable field of the given VBD.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_bootable (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_bootable}
+
+{\bf Overview:}
+Set the bootable field of the given VBD.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_bootable (session_id s, VBD ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & reference to the object \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
\vspace{0.3cm}
\vspace{0.3cm}
\vspace{0.3cm}
struct xen_vdi_record_opt *vdi;
char *device;
char *image;
+ bool bootable;
enum xen_vbd_mode mode;
enum xen_driver_type driver;
double io_read_kbs;
xen_vbd_get_device(xen_session *session, char **result, xen_vbd vbd);
+/**
+ * Get the bootable field of the given VBD.
+ */
+extern bool
+xen_vbd_get_bootable(xen_session *session, bool *result, xen_vbd vbd);
+
+
/**
* Get the mode field of the given VBD.
*/
xen_vbd_set_device(xen_session *session, xen_vbd vbd, char *device);
+/**
+ * Set the bootable field of the given VBD.
+ */
+extern bool
+xen_vbd_set_bootable(xen_session *session, xen_vbd vbd, bool bootable);
+
+
/**
* Set the mode field of the given VBD.
*/
{ .key = "image",
.type = &abstract_type_string,
.offset = offsetof(xen_vbd_record, image) },
+ { .key = "bootable",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vbd_record, bootable) },
{ .key = "mode",
.type = &xen_vbd_mode_abstract_type_,
.offset = offsetof(xen_vbd_record, mode) },
}
+bool
+xen_vbd_get_bootable(xen_session *session, bool *result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VBD.get_bootable");
+ return session->ok;
+}
+
+
bool
xen_vbd_get_mode(xen_session *session, enum xen_vbd_mode *result, xen_vbd vbd)
{
}
+bool
+xen_vbd_set_bootable(xen_session *session, xen_vbd vbd, bool bootable)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd },
+ { .type = &abstract_type_bool,
+ .u.bool_val = bootable }
+ };
+
+ xen_call_(session, "VBD.set_bootable", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
bool
xen_vbd_set_mode(xen_session *session, xen_vbd vbd, enum xen_vbd_mode mode)
{
VBD_attr_rw = ['VM',
'VDI',
'device',
+ 'bootable',
'mode',
'type',
'driver']
xendom = XendDomain.instance()
return xen_api_success(xendom.get_dev_property_by_uuid('vbd', vbd_ref,
'device'))
+ def VBD_get_bootable(self, session, vbd_ref):
+ xendom = XendDomain.instance()
+ return xen_api_success(xendom.get_dev_property_by_uuid('vbd', vbd_ref,
+ 'bootable'))
def VBD_get_mode(self, session, vbd_ref):
xendom = XendDomain.instance()
return xen_api_success(xendom.get_dev_property_by_uuid('vbd', vbd_ref,
return xen_api_success(xendom.get_dev_property_by_uuid('vbd', vbd_ref,
'io_read_kbs'))
+ def VBD_set_bootable(self, session, vbd_ref, bootable):
+ bootable = bool(bootable)
+ xd = XendDomain.instance()
+ vm = xd.get_vm_with_dev_uuid('vbd', vbd_ref)
+ vm.set_dev_property('vbd', vbd_ref, 'bootable', bootable)
+ xd.managed_config_save(vm)
+ return xen_api_success_void()
+
def VBD_get_all(self, session):
xendom = XendDomain.instance()
vbds = [d.get_vbds() for d in XendDomain.instance().list('all')]
from xen.xend.XendConstants import DOM_STATE_HALTED
log = logging.getLogger("xend.XendConfig")
-log.setLevel(logging.WARN)
+log.setLevel(logging.DEBUG)
"""
controller = domain.getDeviceController(cls)
configs = controller.configurations()
for config in configs:
+ if sxp.name(config) in ('vbd', 'tap'):
+ # The bootable flag is never written to the
+ # store as part of the device config.
+ uuid = sxp.child_value(sxpr, 'uuid')
+ sxpr.append(
+ 'bootable',
+ self['devices'][dev_uuid]['bootable'])
sxpr.append(['device', config])
found = True
pass
if dev_type == 'vbd':
+ dev_info['bootable'] = False
if dev_info.get('dev', '').startswith('ioemu:'):
dev_info['driver'] = 'ioemu'
else:
if param not in target:
target[param] = []
if dev_uuid not in target[param]:
+ if dev_type == 'vbd' and not target[param]:
+ # Compat hack -- this is the first disk, so mark it
+ # bootable.
+ dev_info['bootable'] = True
target[param].append(dev_uuid)
- elif dev_type in ('tap',):
+ elif dev_type == 'tap':
if 'vbd_refs' not in target:
target['vbd_refs'] = []
if dev_uuid not in target['vbd_refs']:
+ if not target['vbd_refs']:
+ # Compat hack -- this is the first disk, so mark it
+ # bootable.
+ dev_info['bootable'] = True
target['vbd_refs'].append(dev_uuid)
- elif dev_type in ('console',):
+ elif dev_type == 'console':
if 'console_refs' not in target:
target['console_refs'] = []
if dev_uuid not in target['console_refs']:
dev_info['uname'] = cfg_xenapi.get('image', '')
dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
old_vbd_type)
+ dev_info['bootable'] = cfg_xenapi.get('bootable', False)
dev_info['driver'] = cfg_xenapi.get('driver')
dev_info['VDI'] = cfg_xenapi.get('VDI', '')
blexec = osdep.pygrub_path
blcfg = None
- for (devtype, devinfo) in self.info.all_devices_sxpr():
- if not devtype or not devinfo or devtype not in ('vbd', 'tap'):
- continue
- disk = None
- for param in devinfo:
- if param[0] == 'uname':
- disk = param[1]
- break
-
- if disk is None:
- continue
- fn = blkdev_uname_to_file(disk)
- mounted = devtype == 'tap' and not os.stat(fn).st_rdev
- if mounted:
- # This is a file, not a device. pygrub can cope with a
- # file if it's raw, but if it's QCOW or other such formats
- # used through blktap, then we need to mount it first.
+ disks = [x for x in self.info['vbd_refs']
+ if self.info['devices'][x][1]['bootable']]
- log.info("Mounting %s on %s." %
- (fn, BOOTLOADER_LOOPBACK_DEVICE))
+ if not disks:
+ msg = "Had a bootloader specified, but no disks are bootable"
+ log.error(msg)
+ raise VmError(msg)
- vbd = {
- 'mode': 'RO',
- 'device': BOOTLOADER_LOOPBACK_DEVICE,
- }
+ disk = disks[0]
- from xen.xend import XendDomain
- dom0 = XendDomain.instance().privilegedDomain()
- dom0._waitForDeviceUUID(dom0.create_vbd(vbd, fn))
- fn = BOOTLOADER_LOOPBACK_DEVICE
+ fn = blkdev_uname_to_file(disk)
+ mounted = devtype == 'tap' and not os.stat(fn).st_rdev
+ if mounted:
+ # This is a file, not a device. pygrub can cope with a
+ # file if it's raw, but if it's QCOW or other such formats
+ # used through blktap, then we need to mount it first.
- try:
- blcfg = bootloader(blexec, fn, self, False,
- bootloader_args, kernel, ramdisk, args)
- finally:
- if mounted:
- log.info("Unmounting %s from %s." %
- (fn, BOOTLOADER_LOOPBACK_DEVICE))
+ log.info("Mounting %s on %s." %
+ (fn, BOOTLOADER_LOOPBACK_DEVICE))
- dom0.destroyDevice('tap', '/dev/xvdp')
+ vbd = {
+ 'mode': 'RO',
+ 'device': BOOTLOADER_LOOPBACK_DEVICE,
+ }
- break
+ from xen.xend import XendDomain
+ dom0 = XendDomain.instance().privilegedDomain()
+ dom0._waitForDeviceUUID(dom0.create_vbd(vbd, fn))
+ fn = BOOTLOADER_LOOPBACK_DEVICE
+
+ try:
+ blcfg = bootloader(blexec, fn, self, False,
+ bootloader_args, kernel, ramdisk, args)
+ finally:
+ if mounted:
+ log.info("Unmounting %s from %s." %
+ (fn, BOOTLOADER_LOOPBACK_DEVICE))
+
+ dom0.destroyDevice('tap', '/dev/xvdp')
if blcfg is None:
msg = "Had a bootloader specified, but can't find disk"
except KeyError:
raise XendError('Invalid property for device: %s' % field)
+ def set_dev_property(self, dev_class, dev_uuid, field, value):
+ self.info['devices'][dev_uuid][1][field] = value
+
def get_vcpus_util(self):
vcpu_util = {}
xennode = XendNode.instance()