Revision ea9d3b40

b/lib/cli.py
108 108
  "IGNORE_REMOVE_FAILURES_OPT",
109 109
  "IGNORE_SECONDARIES_OPT",
110 110
  "IGNORE_SIZE_OPT",
111
  "INCLUDEDEFAULTS_OPT",
111 112
  "INTERVAL_OPT",
112 113
  "MAC_PREFIX_OPT",
113 114
  "MAINTAIN_NODE_HEALTH_OPT",
......
237 238
  "FormatQueryResult",
238 239
  "FormatParamsDictInfo",
239 240
  "FormatPolicyInfo",
241
  "PrintIPolicyCommand",
240 242
  "PrintGenericInfo",
241 243
  "GenerateTable",
242 244
  "AskUser",
......
1621 1623
                                  action="store_false",
1622 1624
                                  help="Don't check for conflicting IPs")
1623 1625

  
1626
INCLUDEDEFAULTS_OPT = cli_option("--include-defaults", dest="include_defaults",
1627
                                 default=False, action="store_true",
1628
                                 help="Include default values")
1629

  
1624 1630
#: Options provided by all commands
1625 1631
COMMON_OPTS = [DEBUG_OPT, REASON_OPT]
1626 1632

  
......
3751 3757
  return ret
3752 3758

  
3753 3759

  
3760
def _PrintSpecsParameters(buf, specs):
3761
  values = ("%s=%s" % (par, val) for (par, val) in sorted(specs.items()))
3762
  buf.write(",".join(values))
3763

  
3764

  
3765
def PrintIPolicyCommand(buf, ipolicy, isgroup):
3766
  """Print the command option used to generate the given instance policy.
3767

  
3768
  Currently only the parts dealing with specs are supported.
3769

  
3770
  @type buf: StringIO
3771
  @param buf: stream to write into
3772
  @type ipolicy: dict
3773
  @param ipolicy: instance policy
3774
  @type isgroup: bool
3775
  @param isgroup: whether the policy is at group level
3776

  
3777
  """
3778
  if not isgroup:
3779
    stdspecs = ipolicy.get("std")
3780
    if stdspecs:
3781
      buf.write(" %s " % IPOLICY_STD_SPECS_STR)
3782
      _PrintSpecsParameters(buf, stdspecs)
3783
  minmax = ipolicy.get("minmax")
3784
  if minmax:
3785
    minspecs = minmax.get("min")
3786
    maxspecs = minmax.get("max")
3787
    if minspecs and maxspecs:
3788
      buf.write(" %s " % IPOLICY_BOUNDS_SPECS_STR)
3789
      buf.write("min:")
3790
      _PrintSpecsParameters(buf, minspecs)
3791
      buf.write("/max:")
3792
      _PrintSpecsParameters(buf, maxspecs)
3793

  
3794

  
3754 3795
def ConfirmOperation(names, list_type, text, extra=""):
3755 3796
  """Ask the user to confirm an operation on a list of list_type.
3756 3797

  
b/lib/client/gnt_cluster.py
26 26
# W0614: Unused import %s from wildcard import (since we need cli)
27 27
# C0103: Invalid name gnt-cluster
28 28

  
29
from cStringIO import StringIO
29 30
import os.path
30 31
import time
31 32
import OpenSSL
......
1491 1492
    return _off_fn(opts, node_list, inst_map)
1492 1493

  
1493 1494

  
1495
def _GetCreateCommand(info):
1496
  buf = StringIO()
1497
  buf.write("gnt-cluster init")
1498
  PrintIPolicyCommand(buf, info["ipolicy"], False)
1499
  buf.write(" ")
1500
  buf.write(info["name"])
1501
  return buf.getvalue()
1502

  
1503

  
1504
def ShowCreateCommand(opts, args):
1505
  """Shows the command that can be used to re-create the cluster.
1506

  
1507
  Currently it works only for ipolicy specs.
1508

  
1509
  """
1510
  cl = GetClient(query=True)
1511
  result = cl.QueryClusterInfo()
1512
  ToStdout(_GetCreateCommand(result))
1513

  
1514

  
1494 1515
commands = {
1495 1516
  "init": (
1496 1517
    InitCluster, [ArgHost(min=1, max=1)],
......
1603 1624
  "deactivate-master-ip": (
1604 1625
    DeactivateMasterIp, ARGS_NONE, [CONFIRM_OPT], "",
1605 1626
    "Deactivates the master IP"),
1627
  "show-ispecs-cmd": (
1628
    ShowCreateCommand, ARGS_NONE, [], "",
1629
    "Show the command line to re-create the cluster"),
1606 1630
  }
1607 1631

  
1608 1632

  
b/lib/client/gnt_group.py
24 24
# W0401: Wildcard import ganeti.cli
25 25
# W0614: Unused import %s from wildcard import (since we need cli)
26 26

  
27
from cStringIO import StringIO
28

  
27 29
from ganeti.cli import *
28 30
from ganeti import constants
29 31
from ganeti import opcodes
......
313 315
    ])
314 316

  
315 317

  
318
def _GetCreateCommand(group):
319
  (name, ipolicy) = group
320
  buf = StringIO()
321
  buf.write("gnt-group add")
322
  PrintIPolicyCommand(buf, ipolicy, True)
323
  buf.write(" ")
324
  buf.write(name)
325
  return buf.getvalue()
326

  
327

  
328
def ShowCreateCommand(opts, args):
329
  """Shows the command that can be used to re-create a node group.
330

  
331
  Currently it works only for ipolicy specs.
332

  
333
  """
334
  cl = GetClient(query=True)
335
  selected_fields = ["name"]
336
  if opts.include_defaults:
337
    selected_fields += ["ipolicy"]
338
  else:
339
    selected_fields += ["custom_ipolicy"]
340
  result = cl.QueryGroups(names=args, fields=selected_fields,
341
                          use_locking=False)
342

  
343
  for group in result:
344
    ToStdout(_GetCreateCommand(group))
345

  
346

  
316 347
commands = {
317 348
  "add": (
318 349
    AddGroup, ARGS_ONE_GROUP,
......
366 397
  "info": (
367 398
    GroupInfo, ARGS_MANY_GROUPS, [], "[<group_name>...]",
368 399
    "Show group information"),
400
  "show-ispecs-cmd": (
401
    ShowCreateCommand, ARGS_MANY_GROUPS, [INCLUDEDEFAULTS_OPT],
402
    "[--include-defaults] [<group_name>...]",
403
    "Show the command line to re-create a group"),
369 404
  }
370 405

  
371 406

  
b/man/gnt-cluster.rst
152 152
its integer fields in a latin friendly way. This allows further
153 153
diffusion of Ganeti among ancient cultures.
154 154

  
155
SHOW-ISPECS-CMD
156
~~~~~~~~~~~~~~~
157

  
158
**show-ispecs-cmd**
159

  
160
Shows the command line that can be used to recreate the cluster with the
161
same options relative to specs in the instance policies.
162

  
155 163
INIT
156 164
~~~~
157 165

  
b/man/gnt-group.rst
257 257
INFO
258 258
~~~~
259 259

  
260
**info** [group...]
260
**info** [*group*...]
261 261

  
262 262
Shows config information for all (or given) groups.
263 263

  
264
SHOW-ISPECS-CMD
265
~~~~~~~~~~~~~~~
266

  
267
**show-ispecs-cmd** [\--include-defaults] [*group*...]
268

  
269
Shows the command line that can be used to recreate the given groups (or
270
all groups, if none is given) with the same options relative to specs in
271
the instance policies.
272

  
273
If ``--include-defaults`` is specified, include also the default values
274
(i.e. the cluster-level settings), and not only the configuration items
275
that a group overrides.
276

  
264 277

  
265 278
.. vim: set textwidth=72 :
266 279
.. Local Variables:
b/test/py/ganeti.cli_unittest.py
1423 1423
      self._TestFullISpecsInner(skel_ipolicy, exp_minmax1, None,
1424 1424
                                False, fill_all)
1425 1425

  
1426

  
1427
class TestPrintIPolicyCommand(unittest.TestCase):
1428
  """Test case for cli.PrintIPolicyCommand"""
1429
  _SPECS1 = {
1430
    "par1": 42,
1431
    "par2": "xyz",
1432
    }
1433
  _SPECS1_STR = "par1=42,par2=xyz"
1434
  _SPECS2 = {
1435
    "param": 10,
1436
    "another_param": 101,
1437
    }
1438
  _SPECS2_STR = "another_param=101,param=10"
1439

  
1440
  def _CheckPrintIPolicyCommand(self, ipolicy, isgroup, expected):
1441
    buf = StringIO()
1442
    cli.PrintIPolicyCommand(buf, ipolicy, isgroup)
1443
    self.assertEqual(buf.getvalue(), expected)
1444

  
1445
  def testIgnoreStdForGroup(self):
1446
    self._CheckPrintIPolicyCommand({"std": self._SPECS1}, True, "")
1447

  
1448
  def testIgnoreEmpty(self):
1449
    policies = [
1450
      {},
1451
      {"std": {}},
1452
      {"minmax": {}},
1453
      {"minmax": {
1454
        "min": {},
1455
        "max": {},
1456
        }},
1457
      {"minmax": {
1458
        "min": self._SPECS1,
1459
        "max": {},
1460
        }},
1461
      ]
1462
    for pol in policies:
1463
      self._CheckPrintIPolicyCommand(pol, False, "")
1464

  
1465
  def testFullPolicies(self):
1466
    cases = [
1467
      ({"std": self._SPECS1},
1468
       " %s %s" % (cli.IPOLICY_STD_SPECS_STR, self._SPECS1_STR)),
1469
      ({"minmax": {
1470
        "min": self._SPECS1,
1471
        "max": self._SPECS2,
1472
        }},
1473
       " %s min:%s/max:%s" % (cli.IPOLICY_BOUNDS_SPECS_STR,
1474
                              self._SPECS1_STR, self._SPECS2_STR)),
1475
      ]
1476
    for (pol, exp) in cases:
1477
      self._CheckPrintIPolicyCommand(pol, False, exp)
1478

  
1479

  
1426 1480
if __name__ == "__main__":
1427 1481
  testutils.GanetiTestProgram()

Also available in: Unified diff