Commit ea9d3b40 authored by Bernardo Dal Seno's avatar Bernardo Dal Seno

Add command to print ipolicy options

The output of this command can be used to create an exact copy of the
current instance policy specs. The command could be expanded to print all
the options used to create a group or the cluster.
Signed-off-by: default avatarBernardo Dal Seno <bdalseno@google.com>
Reviewed-by: default avatarHelga Velroyen <helgav@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent d2d3935a
......@@ -108,6 +108,7 @@ __all__ = [
"IGNORE_REMOVE_FAILURES_OPT",
"IGNORE_SECONDARIES_OPT",
"IGNORE_SIZE_OPT",
"INCLUDEDEFAULTS_OPT",
"INTERVAL_OPT",
"MAC_PREFIX_OPT",
"MAINTAIN_NODE_HEALTH_OPT",
......@@ -237,6 +238,7 @@ __all__ = [
"FormatQueryResult",
"FormatParamsDictInfo",
"FormatPolicyInfo",
"PrintIPolicyCommand",
"PrintGenericInfo",
"GenerateTable",
"AskUser",
......@@ -1621,6 +1623,10 @@ NOCONFLICTSCHECK_OPT = cli_option("--no-conflicts-check",
action="store_false",
help="Don't check for conflicting IPs")
INCLUDEDEFAULTS_OPT = cli_option("--include-defaults", dest="include_defaults",
default=False, action="store_true",
help="Include default values")
#: Options provided by all commands
COMMON_OPTS = [DEBUG_OPT, REASON_OPT]
......@@ -3751,6 +3757,41 @@ def FormatPolicyInfo(custom_ipolicy, eff_ipolicy, iscluster):
return ret
def _PrintSpecsParameters(buf, specs):
values = ("%s=%s" % (par, val) for (par, val) in sorted(specs.items()))
buf.write(",".join(values))
def PrintIPolicyCommand(buf, ipolicy, isgroup):
"""Print the command option used to generate the given instance policy.
Currently only the parts dealing with specs are supported.
@type buf: StringIO
@param buf: stream to write into
@type ipolicy: dict
@param ipolicy: instance policy
@type isgroup: bool
@param isgroup: whether the policy is at group level
"""
if not isgroup:
stdspecs = ipolicy.get("std")
if stdspecs:
buf.write(" %s " % IPOLICY_STD_SPECS_STR)
_PrintSpecsParameters(buf, stdspecs)
minmax = ipolicy.get("minmax")
if minmax:
minspecs = minmax.get("min")
maxspecs = minmax.get("max")
if minspecs and maxspecs:
buf.write(" %s " % IPOLICY_BOUNDS_SPECS_STR)
buf.write("min:")
_PrintSpecsParameters(buf, minspecs)
buf.write("/max:")
_PrintSpecsParameters(buf, maxspecs)
def ConfirmOperation(names, list_type, text, extra=""):
"""Ask the user to confirm an operation on a list of list_type.
......
......@@ -26,6 +26,7 @@
# W0614: Unused import %s from wildcard import (since we need cli)
# C0103: Invalid name gnt-cluster
from cStringIO import StringIO
import os.path
import time
import OpenSSL
......@@ -1491,6 +1492,26 @@ def Epo(opts, args, cl=None, _on_fn=_EpoOn, _off_fn=_EpoOff,
return _off_fn(opts, node_list, inst_map)
def _GetCreateCommand(info):
buf = StringIO()
buf.write("gnt-cluster init")
PrintIPolicyCommand(buf, info["ipolicy"], False)
buf.write(" ")
buf.write(info["name"])
return buf.getvalue()
def ShowCreateCommand(opts, args):
"""Shows the command that can be used to re-create the cluster.
Currently it works only for ipolicy specs.
"""
cl = GetClient(query=True)
result = cl.QueryClusterInfo()
ToStdout(_GetCreateCommand(result))
commands = {
"init": (
InitCluster, [ArgHost(min=1, max=1)],
......@@ -1603,6 +1624,9 @@ commands = {
"deactivate-master-ip": (
DeactivateMasterIp, ARGS_NONE, [CONFIRM_OPT], "",
"Deactivates the master IP"),
"show-ispecs-cmd": (
ShowCreateCommand, ARGS_NONE, [], "",
"Show the command line to re-create the cluster"),
}
......
......@@ -24,6 +24,8 @@
# W0401: Wildcard import ganeti.cli
# W0614: Unused import %s from wildcard import (since we need cli)
from cStringIO import StringIO
from ganeti.cli import *
from ganeti import constants
from ganeti import opcodes
......@@ -313,6 +315,35 @@ def GroupInfo(_, args):
])
def _GetCreateCommand(group):
(name, ipolicy) = group
buf = StringIO()
buf.write("gnt-group add")
PrintIPolicyCommand(buf, ipolicy, True)
buf.write(" ")
buf.write(name)
return buf.getvalue()
def ShowCreateCommand(opts, args):
"""Shows the command that can be used to re-create a node group.
Currently it works only for ipolicy specs.
"""
cl = GetClient(query=True)
selected_fields = ["name"]
if opts.include_defaults:
selected_fields += ["ipolicy"]
else:
selected_fields += ["custom_ipolicy"]
result = cl.QueryGroups(names=args, fields=selected_fields,
use_locking=False)
for group in result:
ToStdout(_GetCreateCommand(group))
commands = {
"add": (
AddGroup, ARGS_ONE_GROUP,
......@@ -366,6 +397,10 @@ commands = {
"info": (
GroupInfo, ARGS_MANY_GROUPS, [], "[<group_name>...]",
"Show group information"),
"show-ispecs-cmd": (
ShowCreateCommand, ARGS_MANY_GROUPS, [INCLUDEDEFAULTS_OPT],
"[--include-defaults] [<group_name>...]",
"Show the command line to re-create a group"),
}
......
......@@ -152,6 +152,14 @@ Passing the ``--roman`` option gnt-cluster info will try to print
its integer fields in a latin friendly way. This allows further
diffusion of Ganeti among ancient cultures.
SHOW-ISPECS-CMD
~~~~~~~~~~~~~~~
**show-ispecs-cmd**
Shows the command line that can be used to recreate the cluster with the
same options relative to specs in the instance policies.
INIT
~~~~
......
......@@ -257,10 +257,23 @@ be interpreted as stdin.
INFO
~~~~
**info** [group...]
**info** [*group*...]
Shows config information for all (or given) groups.
SHOW-ISPECS-CMD
~~~~~~~~~~~~~~~
**show-ispecs-cmd** [\--include-defaults] [*group*...]
Shows the command line that can be used to recreate the given groups (or
all groups, if none is given) with the same options relative to specs in
the instance policies.
If ``--include-defaults`` is specified, include also the default values
(i.e. the cluster-level settings), and not only the configuration items
that a group overrides.
.. vim: set textwidth=72 :
.. Local Variables:
......
......@@ -1423,5 +1423,59 @@ class TestCreateIPolicyFromOpts(unittest.TestCase):
self._TestFullISpecsInner(skel_ipolicy, exp_minmax1, None,
False, fill_all)
class TestPrintIPolicyCommand(unittest.TestCase):
"""Test case for cli.PrintIPolicyCommand"""
_SPECS1 = {
"par1": 42,
"par2": "xyz",
}
_SPECS1_STR = "par1=42,par2=xyz"
_SPECS2 = {
"param": 10,
"another_param": 101,
}
_SPECS2_STR = "another_param=101,param=10"
def _CheckPrintIPolicyCommand(self, ipolicy, isgroup, expected):
buf = StringIO()
cli.PrintIPolicyCommand(buf, ipolicy, isgroup)
self.assertEqual(buf.getvalue(), expected)
def testIgnoreStdForGroup(self):
self._CheckPrintIPolicyCommand({"std": self._SPECS1}, True, "")
def testIgnoreEmpty(self):
policies = [
{},
{"std": {}},
{"minmax": {}},
{"minmax": {
"min": {},
"max": {},
}},
{"minmax": {
"min": self._SPECS1,
"max": {},
}},
]
for pol in policies:
self._CheckPrintIPolicyCommand(pol, False, "")
def testFullPolicies(self):
cases = [
({"std": self._SPECS1},
" %s %s" % (cli.IPOLICY_STD_SPECS_STR, self._SPECS1_STR)),
({"minmax": {
"min": self._SPECS1,
"max": self._SPECS2,
}},
" %s min:%s/max:%s" % (cli.IPOLICY_BOUNDS_SPECS_STR,
self._SPECS1_STR, self._SPECS2_STR)),
]
for (pol, exp) in cases:
self._CheckPrintIPolicyCommand(pol, False, exp)
if __name__ == "__main__":
testutils.GanetiTestProgram()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment