From 57dc299ac1e3b132564b961e674802faa9b707a9 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Fri, 13 Jan 2012 11:57:59 +0100
Subject: [PATCH] Further fixes to instance policy validation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

As a followup from "Remove extraneous check in policy creation", there
are more places where we build an ipolicy, and then manually check for
its validity. This is very bad style, as it duplicates the
verification code across many places.

This patch removes all such explicit checks (except for one in
cmdlib.py which is correct), and instead does a bit more validation in
the builder functions or in the actual dedicated verification
functions. It also fixes cluster init which used the wrong,
non-completed ipolicy (this was not detected before as we did call
check on it, but otherwise we ignored it), and fixes a too-strong
assert (due to the call chain, we first create the ipolicy from
cmdline params, and only then we fill it).

Finally, it removes an extraneous logging.info which I forgot from
debugging.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: RenΓ© Nussbaumer <rn@google.com>
---
 lib/bootstrap.py          | 14 +++++---------
 lib/client/gnt_cluster.py |  2 --
 lib/client/gnt_group.py   |  4 +---
 lib/cmdlib.py             |  6 ++++--
 lib/objects.py            |  6 ++++++
 5 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/lib/bootstrap.py b/lib/bootstrap.py
index 66c166c9f..efc932d63 100644
--- a/lib/bootstrap.py
+++ b/lib/bootstrap.py
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2006, 2007, 2008, 2010, 2011 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -414,15 +414,10 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
   objects.UpgradeBeParams(beparams)
   utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
   utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
-  for key, val in ipolicy.items():
-    if key not in constants.IPOLICY_PARAMETERS:
-      raise errors.OpPrereqError("'%s' is not a valid key for instance policy"
-                                 " description", key)
-    utils.ForceDictType(val, constants.ISPECS_PARAMETER_TYPES)
 
   objects.NIC.CheckParameterSyntax(nicparams)
+
   full_ipolicy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy)
-  objects.InstancePolicy.CheckParameterSyntax(full_ipolicy)
 
   if ndparams is not None:
     utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
@@ -430,7 +425,8 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
     ndparams = dict(constants.NDC_DEFAULTS)
 
   # This is ugly, as we modify the dict itself
-  # FIXME: Make utils.ForceDictType pure functional or write a wrapper around it
+  # FIXME: Make utils.ForceDictType pure functional or write a wrapper
+  # around it
   if hv_state:
     for hvname, hvs_data in hv_state.items():
       utils.ForceDictType(hvs_data, constants.HVSTS_PARAMETER_TYPES)
@@ -526,7 +522,7 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
     primary_ip_family=ipcls.family,
     prealloc_wipe_disks=prealloc_wipe_disks,
     use_external_mip_script=use_external_mip_script,
-    ipolicy=ipolicy,
+    ipolicy=full_ipolicy,
     hv_state_static=hv_state,
     disk_state_static=disk_state,
     )
diff --git a/lib/client/gnt_cluster.py b/lib/client/gnt_cluster.py
index 6cbd4da86..f462504e2 100644
--- a/lib/client/gnt_cluster.py
+++ b/lib/client/gnt_cluster.py
@@ -149,8 +149,6 @@ def InitCluster(opts, args):
                                   ispecs_disk_templates=ispecs_dts,
                                   fill_all=True)
   ipolicy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy_raw)
-  for value in ipolicy.values():
-    utils.ForceDictType(value, constants.ISPECS_PARAMETER_TYPES)
 
   if opts.candidate_pool_size is None:
     opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT
diff --git a/lib/client/gnt_group.py b/lib/client/gnt_group.py
index b8d823646..a3951f5f8 100644
--- a/lib/client/gnt_group.py
+++ b/lib/client/gnt_group.py
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2010, 2011 Google Inc.
+# Copyright (C) 2010, 2011, 2012 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -55,8 +55,6 @@ def AddGroup(opts, args):
                                   ispecs_disk_size=opts.ispecs_disk_size,
                                   ispecs_nic_count=opts.ispecs_nic_count,
                                   group_ipolicy=True)
-  for key in ipolicy.keys():
-    utils.ForceDictType(ipolicy[key], constants.ISPECS_PARAMETER_TYPES)
 
   (group_name,) = args
   diskparams = dict(opts.diskparams)
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 1b612f733..cf9df7049 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -731,6 +731,9 @@ def _GetUpdatedIPolicy(old_ipolicy, new_ipolicy, group_policy=False):
   use_none = use_default = group_policy
   ipolicy = copy.deepcopy(old_ipolicy)
   for key, value in new_ipolicy.items():
+    if key not in constants.IPOLICY_ALL_KEYS:
+      raise errors.OpPrereqError("Invalid key in new ipolicy: %s" % key,
+                                 errors.ECODE_INVAL)
     if key in constants.IPOLICY_PARAMETERS:
       utils.ForceDictType(value, constants.ISPECS_PARAMETER_TYPES)
       ipolicy[key] = _GetUpdatedParams(old_ipolicy.get(key, {}), value,
@@ -747,7 +750,6 @@ def _GetUpdatedIPolicy(old_ipolicy, new_ipolicy, group_policy=False):
                                      " on the cluster'" % key,
                                      errors.ECODE_INVAL)
       else:
-        logging.info("Setting %s to %s", key, value)
         ipolicy[key] = list(value)
   try:
     objects.InstancePolicy.CheckParameterSyntax(ipolicy)
diff --git a/lib/objects.py b/lib/objects.py
index 3da52edd8..8cba493a0 100644
--- a/lib/objects.py
+++ b/lib/objects.py
@@ -224,6 +224,8 @@ def CreateIPolicyFromOpts(ispecs_mem_size=None,
   if ispecs_disk_templates is not None:
     ipolicy_out[constants.ISPECS_DTS] = list(ispecs_disk_templates)
 
+  assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
+
   return ipolicy_out
 
 
@@ -884,6 +886,10 @@ class InstancePolicy(ConfigObject):
       InstancePolicy.CheckISpecSyntax(ipolicy, param)
     if constants.ISPECS_DTS in ipolicy:
       InstancePolicy.CheckDiskTemplates(ipolicy[constants.ISPECS_DTS])
+    wrong_keys = frozenset(ipolicy.keys()) - constants.IPOLICY_ALL_KEYS
+    if wrong_keys:
+      raise errors.ConfigurationError("Invalid keys in ipolicy: %s" %
+                                      utils.CommaJoin(wrong_keys))
 
   @classmethod
   def CheckISpecSyntax(cls, ipolicy, name):
-- 
GitLab