Revision a71f835e
b/lib/client/gnt_instance.py | ||
---|---|---|
65 | 65 |
] |
66 | 66 |
|
67 | 67 |
|
68 |
_MISSING = object() |
|
68 | 69 |
_ENV_OVERRIDE = frozenset(["list"]) |
69 | 70 |
|
70 | 71 |
|
... | ... | |
1267 | 1268 |
return retcode |
1268 | 1269 |
|
1269 | 1270 |
|
1271 |
def _ConvertNicDiskModifications(mods): |
|
1272 |
"""Converts NIC/disk modifications from CLI to opcode. |
|
1273 |
|
|
1274 |
When L{opcodes.OpInstanceSetParams} was changed to support adding/removing |
|
1275 |
disks at arbitrary indices, its parameter format changed. This function |
|
1276 |
converts legacy requests (e.g. "--net add" or "--disk add:size=4G") to the |
|
1277 |
newer format and adds support for new-style requests (e.g. "--new 4:add"). |
|
1278 |
|
|
1279 |
@type mods: list of tuples |
|
1280 |
@param mods: Modifications as given by command line parser |
|
1281 |
@rtype: list of tuples |
|
1282 |
@return: Modifications as understood by L{opcodes.OpInstanceSetParams} |
|
1283 |
|
|
1284 |
""" |
|
1285 |
result = [] |
|
1286 |
|
|
1287 |
for (idx, params) in mods: |
|
1288 |
if idx == constants.DDM_ADD: |
|
1289 |
# Add item as last item (legacy interface) |
|
1290 |
action = constants.DDM_ADD |
|
1291 |
idxno = -1 |
|
1292 |
elif idx == constants.DDM_REMOVE: |
|
1293 |
# Remove last item (legacy interface) |
|
1294 |
action = constants.DDM_REMOVE |
|
1295 |
idxno = -1 |
|
1296 |
else: |
|
1297 |
# Modifications and adding/removing at arbitrary indices |
|
1298 |
try: |
|
1299 |
idxno = int(idx) |
|
1300 |
except (TypeError, ValueError): |
|
1301 |
raise errors.OpPrereqError("Non-numeric index '%s'" % idx, |
|
1302 |
errors.ECODE_INVAL) |
|
1303 |
|
|
1304 |
add = params.pop(constants.DDM_ADD, _MISSING) |
|
1305 |
remove = params.pop(constants.DDM_REMOVE, _MISSING) |
|
1306 |
|
|
1307 |
if not (add is _MISSING or remove is _MISSING): |
|
1308 |
raise errors.OpPrereqError("Cannot add and remove at the same time", |
|
1309 |
errors.ECODE_INVAL) |
|
1310 |
elif add is not _MISSING: |
|
1311 |
action = constants.DDM_ADD |
|
1312 |
elif remove is not _MISSING: |
|
1313 |
action = constants.DDM_REMOVE |
|
1314 |
else: |
|
1315 |
action = constants.DDM_MODIFY |
|
1316 |
|
|
1317 |
assert not (constants.DDMS_VALUES_WITH_MODIFY & set(params.keys())) |
|
1318 |
|
|
1319 |
if action == constants.DDM_REMOVE and params: |
|
1320 |
raise errors.OpPrereqError("Not accepting parameters on removal", |
|
1321 |
errors.ECODE_INVAL) |
|
1322 |
|
|
1323 |
result.append((action, idxno, params)) |
|
1324 |
|
|
1325 |
return result |
|
1326 |
|
|
1327 |
|
|
1328 |
def _ParseDiskSizes(mods): |
|
1329 |
"""Parses disk sizes in parameters. |
|
1330 |
|
|
1331 |
""" |
|
1332 |
for (action, _, params) in mods: |
|
1333 |
if params and constants.IDISK_SIZE in params: |
|
1334 |
params[constants.IDISK_SIZE] = \ |
|
1335 |
utils.ParseUnit(params[constants.IDISK_SIZE]) |
|
1336 |
elif action == constants.DDM_ADD: |
|
1337 |
raise errors.OpPrereqError("Missing required parameter 'size'", |
|
1338 |
errors.ECODE_INVAL) |
|
1339 |
|
|
1340 |
return mods |
|
1341 |
|
|
1342 |
|
|
1270 | 1343 |
def SetInstanceParams(opts, args): |
1271 | 1344 |
"""Modifies an instance. |
1272 | 1345 |
|
... | ... | |
1301 | 1374 |
utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES, |
1302 | 1375 |
allowed_values=[constants.VALUE_DEFAULT]) |
1303 | 1376 |
|
1304 |
for idx, (nic_op, nic_dict) in enumerate(opts.nics): |
|
1305 |
try: |
|
1306 |
nic_op = int(nic_op) |
|
1307 |
opts.nics[idx] = (nic_op, nic_dict) |
|
1308 |
except (TypeError, ValueError): |
|
1309 |
pass |
|
1310 |
|
|
1311 |
for idx, (disk_op, disk_dict) in enumerate(opts.disks): |
|
1312 |
try: |
|
1313 |
disk_op = int(disk_op) |
|
1314 |
opts.disks[idx] = (disk_op, disk_dict) |
|
1315 |
except (TypeError, ValueError): |
|
1316 |
pass |
|
1317 |
if disk_op == constants.DDM_ADD: |
|
1318 |
if "size" not in disk_dict: |
|
1319 |
raise errors.OpPrereqError("Missing required parameter 'size'", |
|
1320 |
errors.ECODE_INVAL) |
|
1321 |
disk_dict["size"] = utils.ParseUnit(disk_dict["size"]) |
|
1377 |
nics = _ConvertNicDiskModifications(opts.nics) |
|
1378 |
disks = _ParseDiskSizes(_ConvertNicDiskModifications(opts.disks)) |
|
1322 | 1379 |
|
1323 | 1380 |
if (opts.disk_template and |
1324 | 1381 |
opts.disk_template in constants.DTS_INT_MIRROR and |
... | ... | |
1335 | 1392 |
offline = None |
1336 | 1393 |
|
1337 | 1394 |
op = opcodes.OpInstanceSetParams(instance_name=args[0], |
1338 |
nics=opts.nics,
|
|
1339 |
disks=opts.disks,
|
|
1395 |
nics=nics, |
|
1396 |
disks=disks, |
|
1340 | 1397 |
disk_template=opts.disk_template, |
1341 | 1398 |
remote_node=opts.node, |
1342 | 1399 |
hvparams=opts.hvparams, |
b/man/gnt-instance.rst | ||
---|---|---|
896 | 896 |
by ballooning it up or down to the new value. |
897 | 897 |
|
898 | 898 |
The ``--disk add:size=``*SIZE* option adds a disk to the instance. The |
899 |
optional ``vg=``*VG* option specifies LVM volume group other than |
|
900 |
default vg to create the disk on. For DRBD disks, the ``metavg=``*VG* |
|
901 |
option specifies the volume group for the metadata device. The |
|
902 |
``--disk remove`` option will remove the last disk of the |
|
903 |
instance. The ``--disk`` *N*``:mode=``*MODE* option will change the |
|
904 |
mode of the Nth disk of the instance between read-only (``ro``) and |
|
899 |
optional ``vg=``*VG* option specifies an LVM volume group other than |
|
900 |
the default volume group to create the disk on. For DRBD disks, the |
|
901 |
``metavg=``*VG* option specifies the volume group for the metadata |
|
902 |
device. ``--disk`` *N*``:add,size=``**SIZE** can be used to add a |
|
903 |
disk at a specific index. The ``--disk remove`` option will remove the |
|
904 |
last disk of the instance. Use ``--disk ``*N*``:remove`` to remove a |
|
905 |
disk by its index. The ``--disk`` *N*``:mode=``*MODE* option will change |
|
906 |
the mode of the Nth disk of the instance between read-only (``ro``) and |
|
905 | 907 |
read-write (``rw``). |
906 | 908 |
|
907 |
The ``--net add:``*options* option will add a new NIC to the |
|
908 |
instance. The available options are the same as in the **add** command |
|
909 |
(mac, ip, link, mode). The ``--net remove`` will remove the last NIC |
|
910 |
of the instance, while the ``--net`` *N*:*options* option will change |
|
911 |
the parameters of the Nth instance NIC. |
|
909 |
The ``--net add:``*options* and ``--net`` *N*``:add,``*options* option |
|
910 |
will add a new network interface to the instance. The available options |
|
911 |
are the same as in the **add** command (``mac``, ``ip``, ``link``, |
|
912 |
``mode``). The ``--net remove`` will remove the last network interface |
|
913 |
of the instance (``--net`` *N*``:remove`` for a specific index), while |
|
914 |
the ``--net`` *N*``:``*options* option will change the parameters of the Nth |
|
915 |
instance network interface. |
|
912 | 916 |
|
913 | 917 |
The option ``-o (--os-type)`` will change the OS name for the instance |
914 | 918 |
(without reinstallation). In case an OS variant is specified that is |
b/test/ganeti.client.gnt_instance_unittest.py | ||
---|---|---|
119 | 119 |
self.assertEqual(len(self._output), 0) |
120 | 120 |
|
121 | 121 |
|
122 |
class TestConvertNicDiskModifications(unittest.TestCase): |
|
123 |
def test(self): |
|
124 |
fn = gnt_instance._ConvertNicDiskModifications |
|
125 |
|
|
126 |
self.assertEqual(fn([]), []) |
|
127 |
|
|
128 |
# Error cases |
|
129 |
self.assertRaises(errors.OpPrereqError, fn, [ |
|
130 |
(constants.DDM_REMOVE, { "param": "value", }), |
|
131 |
]) |
|
132 |
self.assertRaises(errors.OpPrereqError, fn, [ |
|
133 |
(0, { constants.DDM_REMOVE: True, "param": "value", }), |
|
134 |
]) |
|
135 |
self.assertRaises(errors.OpPrereqError, fn, [ |
|
136 |
("Hello", {}), |
|
137 |
]) |
|
138 |
self.assertRaises(errors.OpPrereqError, fn, [ |
|
139 |
(0, { |
|
140 |
constants.DDM_REMOVE: True, |
|
141 |
constants.DDM_ADD: True, |
|
142 |
}), |
|
143 |
]) |
|
144 |
|
|
145 |
# Legacy calls |
|
146 |
for action in constants.DDMS_VALUES: |
|
147 |
self.assertEqual(fn([ |
|
148 |
(action, {}), |
|
149 |
]), [ |
|
150 |
(action, -1, {}), |
|
151 |
]) |
|
152 |
|
|
153 |
self.assertEqual(fn([ |
|
154 |
(constants.DDM_ADD, { |
|
155 |
constants.IDISK_SIZE: 1024, |
|
156 |
}), |
|
157 |
]), [ |
|
158 |
(constants.DDM_ADD, -1, { |
|
159 |
constants.IDISK_SIZE: 1024, |
|
160 |
}), |
|
161 |
]) |
|
162 |
|
|
163 |
# New-style calls |
|
164 |
self.assertEqual(fn([ |
|
165 |
(2, { |
|
166 |
constants.IDISK_MODE: constants.DISK_RDWR, |
|
167 |
}), |
|
168 |
]), [ |
|
169 |
(constants.DDM_MODIFY, 2, { |
|
170 |
constants.IDISK_MODE: constants.DISK_RDWR, |
|
171 |
}), |
|
172 |
]) |
|
173 |
|
|
174 |
self.assertEqual(fn([ |
|
175 |
(0, { |
|
176 |
constants.DDM_ADD: True, |
|
177 |
constants.IDISK_SIZE: 4096, |
|
178 |
}), |
|
179 |
]), [ |
|
180 |
(constants.DDM_ADD, 0, { |
|
181 |
constants.IDISK_SIZE: 4096, |
|
182 |
}), |
|
183 |
]) |
|
184 |
|
|
185 |
self.assertEqual(fn([ |
|
186 |
(-1, { |
|
187 |
constants.DDM_REMOVE: True, |
|
188 |
}), |
|
189 |
]), [ |
|
190 |
(constants.DDM_REMOVE, -1, {}), |
|
191 |
]) |
|
192 |
|
|
193 |
|
|
194 |
class TestParseDiskSizes(unittest.TestCase): |
|
195 |
def test(self): |
|
196 |
fn = gnt_instance._ParseDiskSizes |
|
197 |
|
|
198 |
self.assertEqual(fn([]), []) |
|
199 |
|
|
200 |
# Missing size parameter |
|
201 |
self.assertRaises(errors.OpPrereqError, fn, [ |
|
202 |
(constants.DDM_ADD, 0, {}), |
|
203 |
]) |
|
204 |
|
|
205 |
# Converting disk size |
|
206 |
self.assertEqual(fn([ |
|
207 |
(constants.DDM_ADD, 11, { |
|
208 |
constants.IDISK_SIZE: "9G", |
|
209 |
}), |
|
210 |
]), [ |
|
211 |
(constants.DDM_ADD, 11, { |
|
212 |
constants.IDISK_SIZE: 9216, |
|
213 |
}), |
|
214 |
]) |
|
215 |
|
|
216 |
# No size parameter |
|
217 |
self.assertEqual(fn([ |
|
218 |
(constants.DDM_REMOVE, 11, { |
|
219 |
"other": "24M", |
|
220 |
}), |
|
221 |
]), [ |
|
222 |
(constants.DDM_REMOVE, 11, { |
|
223 |
"other": "24M", |
|
224 |
}), |
|
225 |
]) |
|
226 |
|
|
227 |
|
|
122 | 228 |
if __name__ == "__main__": |
123 | 229 |
testutils.GanetiTestProgram() |
Also available in: Unified diff