2016 |
2016 |
disk.unique_id, disk.dev_type)
|
2017 |
2017 |
|
2018 |
2018 |
|
2019 |
|
def ExportSnapshot(disk, dest_node, instance, cluster_name, idx, debug):
|
2020 |
|
"""Export a block device snapshot to a remote node.
|
2021 |
|
|
2022 |
|
@type disk: L{objects.Disk}
|
2023 |
|
@param disk: the description of the disk to export
|
2024 |
|
@type dest_node: str
|
2025 |
|
@param dest_node: the destination node to export to
|
2026 |
|
@type instance: L{objects.Instance}
|
2027 |
|
@param instance: the instance object to whom the disk belongs
|
2028 |
|
@type cluster_name: str
|
2029 |
|
@param cluster_name: the cluster name, needed for SSH hostalias
|
2030 |
|
@type idx: int
|
2031 |
|
@param idx: the index of the disk in the instance's disk list,
|
2032 |
|
used to export to the OS scripts environment
|
2033 |
|
@type debug: integer
|
2034 |
|
@param debug: debug level, passed to the OS scripts
|
2035 |
|
@rtype: None
|
2036 |
|
|
2037 |
|
"""
|
2038 |
|
inst_os = OSFromDisk(instance.os)
|
2039 |
|
export_env = OSEnvironment(instance, inst_os, debug)
|
2040 |
|
|
2041 |
|
export_script = inst_os.export_script
|
2042 |
|
|
2043 |
|
logfile = _InstanceLogName("export", inst_os.name, instance.name)
|
2044 |
|
if not os.path.exists(constants.LOG_OS_DIR):
|
2045 |
|
os.mkdir(constants.LOG_OS_DIR, 0750)
|
2046 |
|
|
2047 |
|
real_disk = _OpenRealBD(disk)
|
2048 |
|
|
2049 |
|
export_env['EXPORT_DEVICE'] = real_disk.dev_path
|
2050 |
|
export_env['EXPORT_INDEX'] = str(idx)
|
2051 |
|
|
2052 |
|
destdir = utils.PathJoin(constants.EXPORT_DIR, instance.name + ".new")
|
2053 |
|
destfile = disk.physical_id[1]
|
2054 |
|
|
2055 |
|
# the target command is built out of three individual commands,
|
2056 |
|
# which are joined by pipes; we check each individual command for
|
2057 |
|
# valid parameters
|
2058 |
|
expcmd = utils.BuildShellCmd("set -e; set -o pipefail; cd %s; %s 2>%s",
|
2059 |
|
inst_os.path, export_script, logfile)
|
2060 |
|
|
2061 |
|
comprcmd = "gzip"
|
2062 |
|
|
2063 |
|
destcmd = utils.BuildShellCmd("mkdir -p %s && cat > %s",
|
2064 |
|
destdir, utils.PathJoin(destdir, destfile))
|
2065 |
|
remotecmd = _GetSshRunner(cluster_name).BuildCmd(dest_node,
|
2066 |
|
constants.GANETI_RUNAS,
|
2067 |
|
destcmd)
|
2068 |
|
|
2069 |
|
# all commands have been checked, so we're safe to combine them
|
2070 |
|
command = '|'.join([expcmd, comprcmd, utils.ShellQuoteArgs(remotecmd)])
|
2071 |
|
|
2072 |
|
result = utils.RunCmd(["bash", "-c", command], env=export_env)
|
2073 |
|
|
2074 |
|
if result.failed:
|
2075 |
|
_Fail("OS snapshot export command '%s' returned error: %s"
|
2076 |
|
" output: %s", command, result.fail_reason, result.output)
|
2077 |
|
|
2078 |
|
|
2079 |
2019 |
def FinalizeExport(instance, snap_disks):
|
2080 |
2020 |
"""Write out the export configuration information.
|
2081 |
2021 |
|
... | ... | |
2175 |
2115 |
return config.Dumps()
|
2176 |
2116 |
|
2177 |
2117 |
|
2178 |
|
def ImportOSIntoInstance(instance, src_node, src_images, cluster_name, debug):
|
2179 |
|
"""Import an os image into an instance.
|
2180 |
|
|
2181 |
|
@type instance: L{objects.Instance}
|
2182 |
|
@param instance: instance to import the disks into
|
2183 |
|
@type src_node: string
|
2184 |
|
@param src_node: source node for the disk images
|
2185 |
|
@type src_images: list of string
|
2186 |
|
@param src_images: absolute paths of the disk images
|
2187 |
|
@type debug: integer
|
2188 |
|
@param debug: debug level, passed to the OS scripts
|
2189 |
|
@rtype: list of boolean
|
2190 |
|
@return: each boolean represent the success of importing the n-th disk
|
2191 |
|
|
2192 |
|
"""
|
2193 |
|
inst_os = OSFromDisk(instance.os)
|
2194 |
|
import_env = OSEnvironment(instance, inst_os, debug)
|
2195 |
|
import_script = inst_os.import_script
|
2196 |
|
|
2197 |
|
logfile = _InstanceLogName("import", instance.os, instance.name)
|
2198 |
|
if not os.path.exists(constants.LOG_OS_DIR):
|
2199 |
|
os.mkdir(constants.LOG_OS_DIR, 0750)
|
2200 |
|
|
2201 |
|
comprcmd = "gunzip"
|
2202 |
|
impcmd = utils.BuildShellCmd("(cd %s; %s >%s 2>&1)", inst_os.path,
|
2203 |
|
import_script, logfile)
|
2204 |
|
|
2205 |
|
final_result = []
|
2206 |
|
for idx, image in enumerate(src_images):
|
2207 |
|
if image:
|
2208 |
|
destcmd = utils.BuildShellCmd('cat %s', image)
|
2209 |
|
remotecmd = _GetSshRunner(cluster_name).BuildCmd(src_node,
|
2210 |
|
constants.GANETI_RUNAS,
|
2211 |
|
destcmd)
|
2212 |
|
command = '|'.join([utils.ShellQuoteArgs(remotecmd), comprcmd, impcmd])
|
2213 |
|
import_env['IMPORT_DEVICE'] = import_env['DISK_%d_PATH' % idx]
|
2214 |
|
import_env['IMPORT_INDEX'] = str(idx)
|
2215 |
|
result = utils.RunCmd(command, env=import_env)
|
2216 |
|
if result.failed:
|
2217 |
|
logging.error("Disk import command '%s' returned error: %s"
|
2218 |
|
" output: %s", command, result.fail_reason,
|
2219 |
|
result.output)
|
2220 |
|
final_result.append("error importing disk %d: %s, %s" %
|
2221 |
|
(idx, result.fail_reason, result.output[-100]))
|
2222 |
|
|
2223 |
|
if final_result:
|
2224 |
|
_Fail("; ".join(final_result), log=False)
|
2225 |
|
|
2226 |
|
|
2227 |
2118 |
def ListExports():
|
2228 |
2119 |
"""Return a list of exports currently available on this machine.
|
2229 |
2120 |
|