Revision 3a9fe2bc
b/doc/rapi.rst | ||
---|---|---|
1262 | 1262 |
|
1263 | 1263 |
.. opcode_result:: OP_INSTANCE_STARTUP |
1264 | 1264 |
|
1265 |
.. _rapi-res-instances-instance_name-snapshot: |
|
1266 |
|
|
1267 |
``/2/instances/[instance_name]/reinstall`` |
|
1268 |
++++++++++++++++++++++++++++++++++++++++++++++ |
|
1269 |
|
|
1270 |
Snapshot an instance. |
|
1271 |
|
|
1272 |
.. rapi_resource_details:: /2/instances/[instance_name]/snapshot |
|
1273 |
|
|
1274 |
|
|
1275 |
.. _rapi-res-instances-instance_name-snapshot+post: |
|
1276 |
|
|
1277 |
``POST`` |
|
1278 |
~~~~~~~~ |
|
1265 | 1279 |
|
1266 | 1280 |
.. _rapi-res-instances-instance_name-reinstall: |
1267 | 1281 |
|
1282 |
Returns a job ID. |
|
1283 |
|
|
1284 |
Body parameters: |
|
1285 |
|
|
1286 |
``snapshot_name`` (string, required) |
|
1287 |
Name of the snapshot. |
|
1288 |
|
|
1289 |
|
|
1268 | 1290 |
``/2/instances/[instance_name]/reinstall`` |
1269 | 1291 |
++++++++++++++++++++++++++++++++++++++++++++++ |
1270 | 1292 |
|
b/lib/backend.py | ||
---|---|---|
2678 | 2678 |
_Fail("Failed to grow block device: %s", err, exc=True) |
2679 | 2679 |
|
2680 | 2680 |
|
2681 |
def BlockdevSnapshot(disk): |
|
2681 |
def BlockdevSnapshot(disk, snapshot_name=None):
|
|
2682 | 2682 |
"""Create a snapshot copy of a block device. |
2683 | 2683 |
|
2684 | 2684 |
This function is called recursively, and the snapshot is actually created |
... | ... | |
2695 | 2695 |
_Fail("DRBD device '%s' without backing storage cannot be snapshotted", |
2696 | 2696 |
disk.unique_id) |
2697 | 2697 |
return BlockdevSnapshot(disk.children[0]) |
2698 |
elif disk.dev_type == constants.LD_LV: |
|
2698 |
elif disk.dev_type == constants.LD_LV and not snapshot_name:
|
|
2699 | 2699 |
r_dev = _RecursiveFindBD(disk) |
2700 | 2700 |
if r_dev is not None: |
2701 | 2701 |
# FIXME: choose a saner value for the snapshot size |
... | ... | |
2703 | 2703 |
return r_dev.Snapshot(disk.size) |
2704 | 2704 |
else: |
2705 | 2705 |
_Fail("Cannot find block device %s", disk) |
2706 |
elif disk.dev_type == constants.DT_EXT: |
|
2707 |
r_dev = _RecursiveFindBD(disk) |
|
2708 |
if r_dev is not None: |
|
2709 |
r_dev.Snapshot(snapshot_name) |
|
2710 |
else: |
|
2711 |
_Fail("Cannot find block device %s", disk) |
|
2706 | 2712 |
else: |
2707 | 2713 |
_Fail("Cannot snapshot non-lvm block device '%s' of type '%s'", |
2708 | 2714 |
disk.unique_id, disk.dev_type) |
b/lib/bdev.py | ||
---|---|---|
3149 | 3149 |
_ExtStorageAction(constants.ES_ACTION_SETINFO, self.unique_id, |
3150 | 3150 |
self.ext_params, metadata=text) |
3151 | 3151 |
|
3152 |
def Snapshot(self, snapshot_name): |
|
3153 |
"""Take a snapshot of the block device. |
|
3154 |
|
|
3155 |
""" |
|
3156 |
# Call the External Storage's setinfo script, |
|
3157 |
# to set metadata for an existing Volume inside the External Storage |
|
3158 |
_ExtStorageAction(constants.ES_ACTION_SNAPSHOT, self.unique_id, |
|
3159 |
self.ext_params, snapshot_name=snapshot_name) |
|
3160 |
|
|
3152 | 3161 |
|
3153 | 3162 |
def _ExtStorageAction(action, unique_id, ext_params, |
3154 |
size=None, grow=None, metadata=None): |
|
3163 |
size=None, grow=None, metadata=None, |
|
3164 |
snapshot_name=None): |
|
3155 | 3165 |
"""Take an External Storage action. |
3156 | 3166 |
|
3157 | 3167 |
Take an External Storage action concerning or affecting |
... | ... | |
3183 | 3193 |
|
3184 | 3194 |
# Create the basic environment for the driver's scripts |
3185 | 3195 |
create_env = _ExtStorageEnvironment(unique_id, ext_params, size, |
3186 |
grow, metadata) |
|
3196 |
grow, metadata, snapshot_name)
|
|
3187 | 3197 |
|
3188 | 3198 |
# Do not use log file for action `attach' as we need |
3189 | 3199 |
# to get the output from RunResult |
... | ... | |
3295 | 3305 |
detach_script=es_files[constants.ES_SCRIPT_DETACH], |
3296 | 3306 |
setinfo_script=es_files[constants.ES_SCRIPT_SETINFO], |
3297 | 3307 |
verify_script=es_files[constants.ES_SCRIPT_VERIFY], |
3308 |
snapshot_script=es_files[constants.ES_SCRIPT_SNAPSHOT], |
|
3298 | 3309 |
supported_parameters=parameters) |
3299 | 3310 |
return True, es_obj |
3300 | 3311 |
|
3301 | 3312 |
|
3302 | 3313 |
def _ExtStorageEnvironment(unique_id, ext_params, |
3303 |
size=None, grow=None, metadata=None): |
|
3314 |
size=None, grow=None, metadata=None, |
|
3315 |
snapshot_name=None): |
|
3304 | 3316 |
"""Calculate the environment for an External Storage script. |
3305 | 3317 |
|
3306 | 3318 |
@type unique_id: tuple (driver, vol_name) |
... | ... | |
3335 | 3347 |
if metadata is not None: |
3336 | 3348 |
result["VOL_METADATA"] = metadata |
3337 | 3349 |
|
3350 |
if snapshot_name is not None: |
|
3351 |
result["VOL_SNAPSHOT_NAME"] = snapshot_name |
|
3352 |
|
|
3338 | 3353 |
return result |
3339 | 3354 |
|
3340 | 3355 |
|
b/lib/client/gnt_instance.py | ||
---|---|---|
403 | 403 |
return constants.EXIT_FAILURE |
404 | 404 |
|
405 | 405 |
|
406 |
def SnapshotInstance(opts, args): |
|
407 |
"""Snapshot an instance. |
|
408 |
|
|
409 |
@param opts: the command line options selected by the user |
|
410 |
@type args: list |
|
411 |
@param args: should contain only one element, the name of the |
|
412 |
instance to be reinstalled |
|
413 |
@rtype: int |
|
414 |
@return: the desired exit code |
|
415 |
|
|
416 |
""" |
|
417 |
instance_name = args[0] |
|
418 |
inames = _ExpandMultiNames(_EXPAND_INSTANCES, [instance_name]) |
|
419 |
if not inames: |
|
420 |
raise errors.OpPrereqError("Selection filter does not match any instances", |
|
421 |
errors.ECODE_INVAL) |
|
422 |
multi_on = len(inames) > 1 |
|
423 |
jex = JobExecutor(verbose=multi_on, opts=opts) |
|
424 |
for instance_name in inames: |
|
425 |
op = opcodes.OpInstanceSnapshot(instance_name=instance_name, |
|
426 |
disks=opts.disks) |
|
427 |
jex.QueueJob(instance_name, op) |
|
428 |
|
|
429 |
results = jex.WaitOrShow(not opts.submit_only) |
|
430 |
|
|
431 |
if compat.all(map(compat.fst, results)): |
|
432 |
return constants.EXIT_SUCCESS |
|
433 |
else: |
|
434 |
return constants.EXIT_FAILURE |
|
435 |
|
|
406 | 436 |
def RemoveInstance(opts, args): |
407 | 437 |
"""Remove an instance. |
408 | 438 |
|
... | ... | |
1524 | 1554 |
m_pri_node_tags_opt, m_sec_node_tags_opt, m_inst_tags_opt, SELECT_OS_OPT, |
1525 | 1555 |
SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT, OSPARAMS_OPT], |
1526 | 1556 |
"[-f] <instance>", "Reinstall a stopped instance"), |
1557 |
"snapshot": ( |
|
1558 |
SnapshotInstance, [ArgInstance(min=1,max=1)], |
|
1559 |
[DISK_OPT, SUBMIT_OPT, DRY_RUN_OPT], |
|
1560 |
"<instance>", "Snapshot an instance's disk(s)"), |
|
1527 | 1561 |
"remove": ( |
1528 | 1562 |
RemoveInstance, ARGS_ONE_INSTANCE, |
1529 | 1563 |
[FORCE_OPT, SHUTDOWN_TIMEOUT_OPT, IGNORE_FAILURES_OPT, SUBMIT_OPT, |
b/lib/cmdlib/__init__.py | ||
---|---|---|
88 | 88 |
LUInstanceStartup, \ |
89 | 89 |
LUInstanceShutdown, \ |
90 | 90 |
LUInstanceReinstall, \ |
91 |
LUInstanceSnapshot, \ |
|
91 | 92 |
LUInstanceReboot, \ |
92 | 93 |
LUInstanceConsole |
93 | 94 |
from ganeti.cmdlib.instance_query import \ |
b/lib/cmdlib/instance_operation.py | ||
---|---|---|
42 | 42 |
ShutdownInstanceDisks |
43 | 43 |
from ganeti.cmdlib.instance_utils import BuildInstanceHookEnvByObject, \ |
44 | 44 |
CheckInstanceBridgesExist, CheckNodeFreeMemory, CheckNodeHasOS |
45 |
from ganeti.cmdlib.instance import GetItemFromContainer |
|
45 | 46 |
|
46 | 47 |
|
47 | 48 |
class LUInstanceStartup(LogicalUnit): |
... | ... | |
500 | 501 |
logging.debug("Connecting to console of %s on %s", instance.name, node) |
501 | 502 |
|
502 | 503 |
return GetInstanceConsole(self.cfg.GetClusterInfo(), instance) |
504 |
|
|
505 |
|
|
506 |
class LUInstanceSnapshot(LogicalUnit): |
|
507 |
"""Take a snapshot of the instance. |
|
508 |
|
|
509 |
""" |
|
510 |
HPATH = "instance-snapshot" |
|
511 |
HTYPE = constants.HTYPE_INSTANCE |
|
512 |
REQ_BGL = False |
|
513 |
|
|
514 |
def ExpandNames(self): |
|
515 |
self._ExpandAndLockInstance() |
|
516 |
|
|
517 |
def BuildHooksEnv(self): |
|
518 |
"""Build hooks env. |
|
519 |
|
|
520 |
This runs on master, primary and secondary nodes of the instance. |
|
521 |
|
|
522 |
""" |
|
523 |
return BuildInstanceHookEnvByObject(self, self.instance) |
|
524 |
|
|
525 |
def BuildHooksNodes(self): |
|
526 |
"""Build hooks nodes. |
|
527 |
|
|
528 |
""" |
|
529 |
nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) |
|
530 |
return (nl, nl) |
|
531 |
|
|
532 |
def CheckPrereq(self): |
|
533 |
"""Check prerequisites. |
|
534 |
|
|
535 |
This checks that the instance is in the cluster and is not running. |
|
536 |
|
|
537 |
""" |
|
538 |
instance = self.cfg.GetInstanceInfo(self.op.instance_name) |
|
539 |
assert instance is not None, \ |
|
540 |
"Cannot retrieve locked instance %s" % self.op.instance_name |
|
541 |
CheckNodeOnline(self, instance.primary_node, "Instance primary node" |
|
542 |
" offline, cannot snapshot") |
|
543 |
|
|
544 |
self.snapshots = [] |
|
545 |
for ident, params in self.op.disks: |
|
546 |
idx, disk = GetItemFromContainer(ident, 'disk', instance.disks) |
|
547 |
snapshot_name = params.get("snapshot_name", None) |
|
548 |
if not snapshot_name: |
|
549 |
raise errors.CheckPrereq("No snapshot_name passed for disk %s", ident) |
|
550 |
self.snapshots.append((idx, disk, snapshot_name)) |
|
551 |
#if not instance.disk_template == constants.ST_EXT: |
|
552 |
# raise errors.OpPrereqError("Instance '%s' disk templates is not 'ext'" % |
|
553 |
# self.op.instance_name, |
|
554 |
# errors.ECODE_INVAL) |
|
555 |
#CheckInstanceState(self, instance, INSTANCE_DOWN, msg="cannot reinstall") |
|
556 |
|
|
557 |
self.instance = instance |
|
558 |
|
|
559 |
def Exec(self, feedback_fn): |
|
560 |
"""Take a snapshot of the instance the instance. |
|
561 |
|
|
562 |
""" |
|
563 |
inst = self.instance |
|
564 |
node_uuid = inst.primary_node |
|
565 |
for idx, disk, snapshot_name in self.snapshots: |
|
566 |
self.cfg.SetDiskID(disk, node_uuid) |
|
567 |
feedback_fn("Taking a snapshot of instance...") |
|
568 |
result = self.rpc.call_blockdev_snapshot(node_uuid, |
|
569 |
(disk, inst), |
|
570 |
snapshot_name) |
|
571 |
result.Raise("Could not take a snapshot for instance %s disk %s" |
|
572 |
" on node %s" % (inst, disk.uuid, inst.primary_node)) |
b/lib/constants.py | ||
---|---|---|
822 | 822 |
ES_ACTION_DETACH = "detach" |
823 | 823 |
ES_ACTION_SETINFO = "setinfo" |
824 | 824 |
ES_ACTION_VERIFY = "verify" |
825 |
ES_ACTION_SNAPSHOT = "snapshot" |
|
825 | 826 |
|
826 | 827 |
ES_SCRIPT_CREATE = ES_ACTION_CREATE |
827 | 828 |
ES_SCRIPT_REMOVE = ES_ACTION_REMOVE |
... | ... | |
830 | 831 |
ES_SCRIPT_DETACH = ES_ACTION_DETACH |
831 | 832 |
ES_SCRIPT_SETINFO = ES_ACTION_SETINFO |
832 | 833 |
ES_SCRIPT_VERIFY = ES_ACTION_VERIFY |
834 |
ES_SCRIPT_SNAPSHOT = ES_ACTION_SNAPSHOT |
|
833 | 835 |
ES_SCRIPTS = frozenset([ |
834 | 836 |
ES_SCRIPT_CREATE, |
835 | 837 |
ES_SCRIPT_REMOVE, |
... | ... | |
837 | 839 |
ES_SCRIPT_ATTACH, |
838 | 840 |
ES_SCRIPT_DETACH, |
839 | 841 |
ES_SCRIPT_SETINFO, |
840 |
ES_SCRIPT_VERIFY |
|
842 |
ES_SCRIPT_VERIFY, |
|
843 |
ES_SCRIPT_SNAPSHOT |
|
841 | 844 |
]) |
842 | 845 |
|
843 | 846 |
ES_PARAMETERS_FILE = "parameters.list" |
... | ... | |
970 | 973 |
HV_VNET_HDR = "vnet_hdr" |
971 | 974 |
HV_VIRIDIAN = "viridian" |
972 | 975 |
|
973 |
|
|
974 | 976 |
HVS_PARAMETER_TYPES = { |
975 | 977 |
HV_KVM_PATH: VTYPE_STRING, |
976 | 978 |
HV_BOOT_ORDER: VTYPE_STRING, |
b/lib/masterd/instance.py | ||
---|---|---|
1165 | 1165 |
|
1166 | 1166 |
# result.payload will be a snapshot of an lvm leaf of the one we |
1167 | 1167 |
# passed |
1168 |
result = self._lu.rpc.call_blockdev_snapshot(src_node, (disk, instance)) |
|
1168 |
result = self._lu.rpc.call_blockdev_snapshot(src_node, |
|
1169 |
(disk, instance), |
|
1170 |
None) |
|
1169 | 1171 |
new_dev = False |
1170 | 1172 |
msg = result.fail_msg |
1171 | 1173 |
if msg: |
b/lib/objects.py | ||
---|---|---|
1302 | 1302 |
"detach_script", |
1303 | 1303 |
"setinfo_script", |
1304 | 1304 |
"verify_script", |
1305 |
"snapshot_script", |
|
1305 | 1306 |
"supported_parameters", |
1306 | 1307 |
] |
1307 | 1308 |
|
b/lib/opcodes.py | ||
---|---|---|
1425 | 1425 |
OP_RESULT = ht.TNone |
1426 | 1426 |
|
1427 | 1427 |
|
1428 |
class OpInstanceSnapshot(OpCode): |
|
1429 |
"""Snapshot an instance.""" |
|
1430 |
OP_DSC_FIELD = "instance_name" |
|
1431 |
OP_PARAMS = [ |
|
1432 |
_PInstanceName, |
|
1433 |
("disks", ht.NoDefault, |
|
1434 |
ht.TListOf(ht.TItems([ht.TString, |
|
1435 |
ht.TDictOf(ht.TElemOf("snapshot_name"), |
|
1436 |
ht.TMaybeString) |
|
1437 |
])), |
|
1438 |
"Disks to snapshot"), |
|
1439 |
] |
|
1440 |
OP_RESULT = ht.TNone |
|
1441 |
|
|
1442 |
|
|
1428 | 1443 |
class OpInstanceRemove(OpCode): |
1429 | 1444 |
"""Remove an instance.""" |
1430 | 1445 |
OP_DSC_FIELD = "instance_name" |
b/lib/rapi/client.py | ||
---|---|---|
1120 | 1120 |
("/%s/instances/%s/reinstall" % |
1121 | 1121 |
(GANETI_RAPI_VERSION, instance)), query, None) |
1122 | 1122 |
|
1123 |
def SnapshotInstance(self, instance, disks, dry_run=False): |
|
1124 |
"""Snapshots disks on an instance. |
|
1125 |
|
|
1126 |
@type instance: str |
|
1127 |
@param instance: instance whose disks to replace |
|
1128 |
@type disks: list |
|
1129 |
@param disks: list of tuples (idend, snapshot_name) |
|
1130 |
|
|
1131 |
@rtype: string |
|
1132 |
@return: job id |
|
1133 |
|
|
1134 |
""" |
|
1135 |
|
|
1136 |
body = { |
|
1137 |
"disks": disks, |
|
1138 |
} |
|
1139 |
|
|
1140 |
query = [] |
|
1141 |
_AppendDryRunIf(query, dry_run) |
|
1142 |
|
|
1143 |
return self._SendRequest(HTTP_POST, |
|
1144 |
("/%s/instances/%s/snapshot" % |
|
1145 |
(GANETI_RAPI_VERSION, instance)), query, body) |
|
1146 |
|
|
1123 | 1147 |
def ReplaceInstanceDisks(self, instance, disks=None, mode=REPLACE_DISK_AUTO, |
1124 | 1148 |
remote_node=None, iallocator=None): |
1125 | 1149 |
"""Replaces disks on an instance. |
b/lib/rapi/connector.py | ||
---|---|---|
197 | 197 |
rlib2.R_2_instances_name_reboot, |
198 | 198 |
translate_fn("/2/instances/", instance_name, "/reinstall"): |
199 | 199 |
rlib2.R_2_instances_name_reinstall, |
200 |
translate_fn("/2/instances/", instance_name, "/snapshot"): |
|
201 |
rlib2.R_2_instances_name_snapshot, |
|
200 | 202 |
translate_fn("/2/instances/", instance_name, "/replace-disks"): |
201 | 203 |
rlib2.R_2_instances_name_replace_disks, |
202 | 204 |
translate_fn("/2/instances/", instance_name, "/shutdown"): |
b/lib/rapi/rlib2.py | ||
---|---|---|
1143 | 1143 |
|
1144 | 1144 |
return self.SubmitJob(ops) |
1145 | 1145 |
|
1146 |
class R_2_instances_name_snapshot(baserlib.OpcodeResource): |
|
1147 |
|
|
1148 |
"""/2/instances/[instance_name]/snapshot resource. |
|
1149 |
|
|
1150 |
Implements an instance snapshot. |
|
1151 |
|
|
1152 |
""" |
|
1153 |
POST_OPCODE = opcodes.OpInstanceSnapshot |
|
1154 |
|
|
1155 |
def GetPostOpInput(self): |
|
1156 |
"""Snapshot an instance. |
|
1157 |
|
|
1158 |
The URI takes os=name and nostartup=[0|1] optional |
|
1159 |
parameters. By default, the instance will be started |
|
1160 |
automatically. |
|
1161 |
|
|
1162 |
""" |
|
1163 |
|
|
1164 |
return (self.request_body, { |
|
1165 |
"instance_name": self.items[0], |
|
1166 |
"dry_run": self.dryRun(), |
|
1167 |
}) |
|
1146 | 1168 |
|
1147 | 1169 |
class R_2_instances_name_replace_disks(baserlib.OpcodeResource): |
1148 | 1170 |
"""/2/instances/[instance_name]/replace-disks resource. |
b/lib/rpc_defs.py | ||
---|---|---|
426 | 426 |
], None, None, "Export a given disk to another node"), |
427 | 427 |
("blockdev_snapshot", SINGLE, None, constants.RPC_TMO_NORMAL, [ |
428 | 428 |
("cf_bdev", ED_SINGLE_DISK_DICT_DP, None), |
429 |
("snapshot_name", None, None), |
|
429 | 430 |
], None, None, "Export a given disk to another node"), |
430 | 431 |
("blockdev_rename", SINGLE, None, constants.RPC_TMO_NORMAL, [ |
431 | 432 |
("devlist", ED_BLOCKDEV_RENAME, None), |
b/lib/server/noded.py | ||
---|---|---|
353 | 353 |
remove by calling the generic block device remove call. |
354 | 354 |
|
355 | 355 |
""" |
356 |
cfbd = objects.Disk.FromDict(params[0]) |
|
357 |
return backend.BlockdevSnapshot(cfbd) |
|
356 |
(disk, snapshot_name) = params |
|
357 |
cfbd = objects.Disk.FromDict(disk) |
|
358 |
return backend.BlockdevSnapshot(cfbd, snapshot_name) |
|
358 | 359 |
|
359 | 360 |
@staticmethod |
360 | 361 |
def perspective_blockdev_grow(params): |
b/src/Ganeti/OpCodes.hs | ||
---|---|---|
316 | 316 |
, pInstOs |
317 | 317 |
, pTempOsParams |
318 | 318 |
]) |
319 |
, ("OpInstanceSnapshot", |
|
320 |
[ pInstanceName |
|
321 |
, pInstSnaps |
|
322 |
]) |
|
319 | 323 |
, ("OpInstanceRemove", |
320 | 324 |
[ pInstanceName |
321 | 325 |
, pShutdownTimeout |
... | ... | |
577 | 581 |
opSummaryVal OpNodeEvacuate { opNodeName = s } = Just (fromNonEmpty s) |
578 | 582 |
opSummaryVal OpInstanceCreate { opInstanceName = s } = Just s |
579 | 583 |
opSummaryVal OpInstanceReinstall { opInstanceName = s } = Just s |
584 |
opSummaryVal OpInstanceSnapshot { opInstanceName = s } = Just s |
|
580 | 585 |
opSummaryVal OpInstanceRemove { opInstanceName = s } = Just s |
581 | 586 |
-- FIXME: instance rename should show both names; currently it shows none |
582 | 587 |
-- opSummaryVal OpInstanceRename { opInstanceName = s } = Just s |
b/src/Ganeti/OpParams.hs | ||
---|---|---|
45 | 45 |
, DiskAccess(..) |
46 | 46 |
, INicParams(..) |
47 | 47 |
, IDiskParams(..) |
48 |
, ISnapParams(..) |
|
48 | 49 |
, RecreateDisksInfo(..) |
49 | 50 |
, DdmOldChanges(..) |
50 | 51 |
, SetParamsMods(..) |
... | ... | |
98 | 99 |
, pKeepDisks |
99 | 100 |
, pAllowRuntimeChgs |
100 | 101 |
, pInstDisks |
102 |
, pInstSnaps |
|
101 | 103 |
, pDiskTemplate |
102 | 104 |
, pOptDiskTemplate |
103 | 105 |
, pFileDriver |
... | ... | |
419 | 421 |
, optionalField $ simpleField C.idiskName [t| NonEmptyString |] |
420 | 422 |
]) |
421 | 423 |
|
424 |
-- | Disk snapshot definition. |
|
425 |
$(buildObject "ISnapParams" "snapshot" |
|
426 |
[ optionalField $ simpleField C.idiskName [t| String |]]) |
|
427 |
|
|
422 | 428 |
-- | Disk changes type for OpInstanceRecreateDisks. This is a bit |
423 | 429 |
-- strange, because the type in Python is something like Either |
424 | 430 |
-- [DiskIndex] [DiskChanges], but we can't represent the type of an |
... | ... | |
743 | 749 |
pInstDisks :: Field |
744 | 750 |
pInstDisks = renameField "instDisks" $ simpleField "disks" [t| [IDiskParams] |] |
745 | 751 |
|
752 |
-- | List of instance snaps. |
|
753 |
pInstSnaps :: Field |
|
754 |
pInstSnaps = |
|
755 |
renameField "instSnaps" $ |
|
756 |
simpleField "disks" [t| SetParamsMods ISnapParams |] |
|
757 |
|
|
746 | 758 |
-- | Instance disk template. |
747 | 759 |
pDiskTemplate :: Field |
748 | 760 |
pDiskTemplate = simpleField "disk_template" [t| DiskTemplate |] |
Also available in: Unified diff