Revision da5f09ef

b/doc/rapi.rst
226 226

  
227 227
.. pyassert::
228 228

  
229
  constants.IPOLICY_ALL_KEYS == set([constants.ISPECS_MIN,
230
                                     constants.ISPECS_MAX,
229
  constants.IPOLICY_ALL_KEYS == set([constants.ISPECS_MINMAX,
231 230
                                     constants.ISPECS_STD,
232 231
                                     constants.IPOLICY_DTS,
233 232
                                     constants.IPOLICY_VCPU_RATIO,
......
249 248
.. |ispec-std| replace:: :pyeval:`constants.ISPECS_STD`
250 249

  
251 250

  
252
|ispec-min|, |ispec-max|, |ispec-std|
253
  A sub- `dict` with the following fields, which sets the limit and standard
254
  values of the instances:
255

  
256
  :pyeval:`constants.ISPEC_MEM_SIZE`
257
    The size in MiB of the memory used
258
  :pyeval:`constants.ISPEC_DISK_SIZE`
259
    The size in MiB of the disk used
260
  :pyeval:`constants.ISPEC_DISK_COUNT`
261
    The numbers of disks used
262
  :pyeval:`constants.ISPEC_CPU_COUNT`
263
    The numbers of cpus used
264
  :pyeval:`constants.ISPEC_NIC_COUNT`
265
    The numbers of nics used
266
  :pyeval:`constants.ISPEC_SPINDLE_USE`
267
    The numbers of virtual disk spindles used by this instance. They are
268
    not real in the sense of actual HDD spindles, but useful for
269
    accounting the spindle usage on the residing node
251
:pyeval:`constants.ISPECS_MINMAX`
252
  A dict with the following two fields:
253

  
254
  |ispec-min|, |ispec-max|
255
    A sub- `dict` with the following fields, which sets the limit of the
256
    instances:
257

  
258
    :pyeval:`constants.ISPEC_MEM_SIZE`
259
      The size in MiB of the memory used
260
    :pyeval:`constants.ISPEC_DISK_SIZE`
261
      The size in MiB of the disk used
262
    :pyeval:`constants.ISPEC_DISK_COUNT`
263
      The numbers of disks used
264
    :pyeval:`constants.ISPEC_CPU_COUNT`
265
      The numbers of cpus used
266
    :pyeval:`constants.ISPEC_NIC_COUNT`
267
      The numbers of nics used
268
    :pyeval:`constants.ISPEC_SPINDLE_USE`
269
      The numbers of virtual disk spindles used by this instance. They
270
      are not real in the sense of actual HDD spindles, but useful for
271
      accounting the spindle usage on the residing node
272
|ispec-std|
273
  A sub- `dict` with the same fields as |ispec-min| and |ispec-max| above,
274
  which sets the standard values of the instances.
270 275
:pyeval:`constants.IPOLICY_DTS`
271 276
  A `list` of disk templates allowed for instances using this policy
272 277
:pyeval:`constants.IPOLICY_VCPU_RATIO`
b/lib/cli.py
3717 3717
    utils.ForceDictType(specs, forced_type, allowed_values=allowed_values)
3718 3718

  
3719 3719
  # then transpose
3720
  ispecs = {
3721
    constants.ISPECS_MIN: {},
3722
    constants.ISPECS_MAX: {},
3723
    constants.ISPECS_STD: {},
3724
    }
3720 3725
  for (name, specs) in ispecs_transposed.iteritems():
3721 3726
    assert name in constants.ISPECS_PARAMETERS
3722 3727
    for key, val in specs.items(): # {min: .. ,max: .., std: ..}
3723
      ipolicy[key][name] = val
3728
      assert key in ispecs
3729
      ispecs[key][name] = val
3730
  for key in constants.ISPECS_MINMAX_KEYS:
3731
    ipolicy[constants.ISPECS_MINMAX][key] = ispecs[key]
3732
  ipolicy[constants.ISPECS_STD] = ispecs[constants.ISPECS_STD]
3724 3733

  
3725 3734

  
3726 3735
def CreateIPolicyFromOpts(ispecs_mem_size=None,
b/lib/client/gnt_cluster.py
476 476
    ("Instance policy - limits for instances",
477 477
     [
478 478
       (key,
479
        _FormatGroupedParams(result["ipolicy"][key], roman=opts.roman_integers))
480
       for key in constants.IPOLICY_ISPECS
479
        _FormatGroupedParams(result["ipolicy"][constants.ISPECS_MINMAX][key],
480
                             roman=opts.roman_integers))
481
       for key in constants.ISPECS_MINMAX_KEYS
481 482
       ] +
482 483
     [
484
       (constants.ISPECS_STD,
485
        _FormatGroupedParams(result["ipolicy"][constants.ISPECS_STD],
486
                             roman=opts.roman_integers)),
483 487
       ("enabled disk templates",
484 488
        utils.CommaJoin(result["ipolicy"][constants.IPOLICY_DTS])),
485 489
       ] +
b/lib/cmdlib.py
813 813
  return params_copy
814 814

  
815 815

  
816
def _UpdateMinMaxISpecs(ipolicy, new_minmax, group_policy):
817
  use_none = use_default = group_policy
818
  minmax = ipolicy.setdefault(constants.ISPECS_MINMAX, {})
819
  for (key, value) in new_minmax.items():
820
    if key not in constants.ISPECS_MINMAX_KEYS:
821
      raise errors.OpPrereqError("Invalid key in new ipolicy/%s: %s" %
822
                                 (constants.ISPECS_MINMAX, key),
823
                                 errors.ECODE_INVAL)
824
    old_spec = minmax.get(key, {})
825
    minmax[key] = _GetUpdatedParams(old_spec, value, use_none=use_none,
826
                                    use_default=use_default)
827
    utils.ForceDictType(minmax[key], constants.ISPECS_PARAMETER_TYPES)
828

  
829

  
816 830
def _GetUpdatedIPolicy(old_ipolicy, new_ipolicy, group_policy=False):
817
  """Return the new version of a instance policy.
831
  """Return the new version of an instance policy.
818 832

  
819 833
  @param group_policy: whether this policy applies to a group and thus
820 834
    we should support removal of policy entries
......
826 840
    if key not in constants.IPOLICY_ALL_KEYS:
827 841
      raise errors.OpPrereqError("Invalid key in new ipolicy: %s" % key,
828 842
                                 errors.ECODE_INVAL)
829
    if key in constants.IPOLICY_ISPECS:
843
    if key == constants.ISPECS_MINMAX:
844
      _UpdateMinMaxISpecs(ipolicy, value, group_policy)
845
    elif key == constants.ISPECS_STD:
830 846
      ipolicy[key] = _GetUpdatedParams(old_ipolicy.get(key, {}), value,
831 847
                                       use_none=use_none,
832 848
                                       use_default=use_default)
......
1203 1219
                     " is down")
1204 1220

  
1205 1221

  
1206
def _ComputeMinMaxSpec(name, qualifier, ipolicy, value):
1222
def _ComputeMinMaxSpec(name, qualifier, ispecs, value):
1207 1223
  """Computes if value is in the desired range.
1208 1224

  
1209 1225
  @param name: name of the parameter for which we perform the check
1210 1226
  @param qualifier: a qualifier used in the error message (e.g. 'disk/1',
1211 1227
      not just 'disk')
1212
  @param ipolicy: dictionary containing min, max and std values
1228
  @param ispecs: dictionary containing min and max values
1213 1229
  @param value: actual value that we want to use
1214
  @return: None or element not meeting the criteria
1215

  
1230
  @return: None or an error string
1216 1231

  
1217 1232
  """
1218 1233
  if value in [None, constants.VALUE_AUTO]:
1219 1234
    return None
1220
  max_v = ipolicy[constants.ISPECS_MAX].get(name, value)
1221
  min_v = ipolicy[constants.ISPECS_MIN].get(name, value)
1235
  max_v = ispecs[constants.ISPECS_MAX].get(name, value)
1236
  min_v = ispecs[constants.ISPECS_MIN].get(name, value)
1222 1237
  if value > max_v or min_v > value:
1223 1238
    if qualifier:
1224 1239
      fqn = "%s/%s" % (name, qualifier)
......
1273 1288
    ret.append("Disk template %s is not allowed (allowed templates: %s)" %
1274 1289
               (disk_template, utils.CommaJoin(allowed_dts)))
1275 1290

  
1291
  minmax = ipolicy[constants.ISPECS_MINMAX]
1276 1292
  return ret + filter(None,
1277
                      (_compute_fn(name, qualifier, ipolicy, value)
1293
                      (_compute_fn(name, qualifier, minmax, value)
1278 1294
                       for (name, qualifier, value) in test_settings))
1279 1295

  
1280 1296

  
b/lib/config.py
600 600
      except errors.ConfigurationError, err:
601 601
        result.append("%s has invalid nicparams: %s" % (owner, err))
602 602

  
603
    def _helper_ipolicy(owner, params, check_std):
603
    def _helper_ipolicy(owner, ipolicy, iscluster):
604 604
      try:
605
        objects.InstancePolicy.CheckParameterSyntax(params, check_std)
605
        objects.InstancePolicy.CheckParameterSyntax(ipolicy, iscluster)
606 606
      except errors.ConfigurationError, err:
607 607
        result.append("%s has invalid instance policy: %s" % (owner, err))
608

  
609
    def _helper_ispecs(owner, params):
610
      for key, value in params.items():
611
        if key in constants.IPOLICY_ISPECS:
612
          fullkey = "ipolicy/" + key
613
          _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES)
608
      for key, value in ipolicy.items():
609
        if key == constants.ISPECS_MINMAX:
610
          _helper_ispecs(owner, "ipolicy/" + key, value)
611
        elif key == constants.ISPECS_STD:
612
          _helper(owner, "ipolicy/" + key, value,
613
                  constants.ISPECS_PARAMETER_TYPES)
614 614
        else:
615 615
          # FIXME: assuming list type
616 616
          if key in constants.IPOLICY_PARAMETERS:
......
622 622
                          " expecting %s, got %s" %
623 623
                          (owner, key, exp_type.__name__, type(value)))
624 624

  
625
    def _helper_ispecs(owner, parentkey, params):
626
      for (key, value) in params.items():
627
        fullkey = "/".join([parentkey, key])
628
        _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES)
629

  
625 630
    # check cluster parameters
626 631
    _helper("cluster", "beparams", cluster.SimpleFillBE({}),
627 632
            constants.BES_PARAMETER_TYPES)
......
630 635
    _helper_nic("cluster", cluster.SimpleFillNIC({}))
631 636
    _helper("cluster", "ndparams", cluster.SimpleFillND({}),
632 637
            constants.NDS_PARAMETER_TYPES)
633
    _helper_ipolicy("cluster", cluster.SimpleFillIPolicy({}), True)
634
    _helper_ispecs("cluster", cluster.SimpleFillIPolicy({}))
638
    _helper_ipolicy("cluster", cluster.ipolicy, True)
635 639

  
636 640
    # per-instance checks
637 641
    for instance_name in data.instances:
......
762 766
      group_name = "group %s" % nodegroup.name
763 767
      _helper_ipolicy(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy),
764 768
                      False)
765
      _helper_ispecs(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy))
766 769
      if nodegroup.ndparams:
767 770
        _helper(group_name, "ndparams",
768 771
                cluster.SimpleFillND(nodegroup.ndparams),
b/lib/constants.py
1139 1139

  
1140 1140
ISPECS_PARAMETERS = frozenset(ISPECS_PARAMETER_TYPES.keys())
1141 1141

  
1142
ISPECS_MINMAX = "minmax"
1142 1143
ISPECS_MIN = "min"
1143 1144
ISPECS_MAX = "max"
1144 1145
ISPECS_STD = "std"
......
1146 1147
IPOLICY_VCPU_RATIO = "vcpu-ratio"
1147 1148
IPOLICY_SPINDLE_RATIO = "spindle-ratio"
1148 1149

  
1149
IPOLICY_ISPECS = compat.UniqueFrozenset([
1150
ISPECS_MINMAX_KEYS = compat.UniqueFrozenset([
1150 1151
  ISPECS_MIN,
1151 1152
  ISPECS_MAX,
1152
  ISPECS_STD,
1153 1153
  ])
1154 1154

  
1155 1155
IPOLICY_PARAMETERS = compat.UniqueFrozenset([
......
1157 1157
  IPOLICY_SPINDLE_RATIO,
1158 1158
  ])
1159 1159

  
1160
IPOLICY_ALL_KEYS = (IPOLICY_ISPECS |
1161
                    IPOLICY_PARAMETERS |
1162
                    frozenset([IPOLICY_DTS]))
1160
IPOLICY_ALL_KEYS = (IPOLICY_PARAMETERS |
1161
                    frozenset([ISPECS_MINMAX, ISPECS_STD, IPOLICY_DTS]))
1163 1162

  
1164 1163
# Node parameter names
1165 1164
ND_OOB_PROGRAM = "oob_program"
......
2182 2181

  
2183 2182
# All of the following values are quite arbitrarily - there are no
2184 2183
# "good" defaults, these must be customised per-site
2185
IPOLICY_DEFAULTS = {
2184
ISPECS_MINMAX_DEFAULTS = {
2186 2185
  ISPECS_MIN: {
2187 2186
    ISPEC_MEM_SIZE: 128,
2188 2187
    ISPEC_CPU_COUNT: 1,
......
2199 2198
    ISPEC_NIC_COUNT: MAX_NICS,
2200 2199
    ISPEC_SPINDLE_USE: 12,
2201 2200
    },
2201
  }
2202
IPOLICY_DEFAULTS = {
2203
  ISPECS_MINMAX: ISPECS_MINMAX_DEFAULTS,
2202 2204
  ISPECS_STD: {
2203 2205
    ISPEC_MEM_SIZE: 128,
2204 2206
    ISPEC_CPU_COUNT: 1,
b/lib/objects.py
82 82
  return ret_dict
83 83

  
84 84

  
85
def FillIPolicy(default_ipolicy, custom_ipolicy, skip_keys=None):
85
def _FillMinMaxISpecs(default_specs, custom_specs):
86
  assert frozenset(default_specs.keys()) == constants.ISPECS_MINMAX_KEYS
87
  ret_specs = {}
88
  for key in constants.ISPECS_MINMAX_KEYS:
89
    ret_specs[key] = FillDict(default_specs[key],
90
                              custom_specs.get(key, {}))
91
  return ret_specs
92

  
93

  
94
def FillIPolicy(default_ipolicy, custom_ipolicy):
86 95
  """Fills an instance policy with defaults.
87 96

  
88 97
  """
89 98
  assert frozenset(default_ipolicy.keys()) == constants.IPOLICY_ALL_KEYS
90 99
  ret_dict = {}
91
  for key in constants.IPOLICY_ISPECS:
92
    ret_dict[key] = FillDict(default_ipolicy[key],
93
                             custom_ipolicy.get(key, {}),
94
                             skip_keys=skip_keys)
100
  # Instance specs
101
  new_mm = _FillMinMaxISpecs(default_ipolicy[constants.ISPECS_MINMAX],
102
                             custom_ipolicy.get(constants.ISPECS_MINMAX, {}))
103
  ret_dict[constants.ISPECS_MINMAX] = new_mm
104
  new_std = FillDict(default_ipolicy[constants.ISPECS_STD],
105
                     custom_ipolicy.get(constants.ISPECS_STD, {}))
106
  ret_dict[constants.ISPECS_STD] = new_std
95 107
  # list items
96 108
  for key in [constants.IPOLICY_DTS]:
97 109
    ret_dict[key] = list(custom_ipolicy.get(key, default_ipolicy[key]))
......
186 198
  """Create empty IPolicy dictionary.
187 199

  
188 200
  """
189
  return dict([
190
    (constants.ISPECS_MIN, {}),
191
    (constants.ISPECS_MAX, {}),
192
    (constants.ISPECS_STD, {}),
193
    ])
201
  return {
202
    constants.ISPECS_MINMAX: {
203
      constants.ISPECS_MIN: {},
204
      constants.ISPECS_MAX: {},
205
      },
206
    constants.ISPECS_STD: {},
207
    }
194 208

  
195 209

  
196 210
class ConfigObject(outils.ValidatedSlots):
......
912 926
class InstancePolicy(ConfigObject):
913 927
  """Config object representing instance policy limits dictionary.
914 928

  
915

  
916 929
  Note that this object is not actually used in the config, it's just
917 930
  used as a placeholder for a few functions.
918 931

  
......
921 934
  def CheckParameterSyntax(cls, ipolicy, check_std):
922 935
    """ Check the instance policy for validity.
923 936

  
937
    @type ipolicy: dict
938
    @param ipolicy: dictionary with min/max/std specs and policies
939
    @type check_std: bool
940
    @param check_std: Whether to check std value or just assume compliance
941
    @raise errors.ConfigurationError: when the policy is not legal
942

  
924 943
    """
925
    for param in constants.ISPECS_PARAMETERS:
926
      InstancePolicy.CheckISpecSyntax(ipolicy, param, check_std)
944
    if constants.ISPECS_MINMAX in ipolicy:
945
      if check_std and constants.ISPECS_STD not in ipolicy:
946
        msg = "Missing key in ipolicy: %s" % constants.ISPECS_STD
947
        raise errors.ConfigurationError(msg)
948
      minmaxspecs = ipolicy[constants.ISPECS_MINMAX]
949
      stdspec = ipolicy.get(constants.ISPECS_STD)
950
      for param in constants.ISPECS_PARAMETERS:
951
        InstancePolicy.CheckISpecSyntax(minmaxspecs, stdspec, param, check_std)
927 952
    if constants.IPOLICY_DTS in ipolicy:
928 953
      InstancePolicy.CheckDiskTemplates(ipolicy[constants.IPOLICY_DTS])
929 954
    for key in constants.IPOLICY_PARAMETERS:
......
935 960
                                      utils.CommaJoin(wrong_keys))
936 961

  
937 962
  @classmethod
938
  def CheckISpecSyntax(cls, ipolicy, name, check_std):
939
    """Check the instance policy for validity on a given key.
963
  def CheckISpecSyntax(cls, minmaxspecs, stdspec, name, check_std):
964
    """Check the instance policy specs for validity on a given key.
940 965

  
941
    We check if the instance policy makes sense for a given key, that is
942
    if ipolicy[min][name] <= ipolicy[std][name] <= ipolicy[max][name].
966
    We check if the instance specs makes sense for a given key, that is
967
    if minmaxspecs[min][name] <= stdspec[name] <= minmaxspec[max][name].
943 968

  
944
    @type ipolicy: dict
945
    @param ipolicy: dictionary with min, max, std specs
969
    @type minmaxspecs: dict
970
    @param minmaxspecs: dictionary with min and max instance spec
971
    @type stdspec: dict
972
    @param stdspec: dictionary with standard instance spec
946 973
    @type name: string
947 974
    @param name: what are the limits for
948 975
    @type check_std: bool
949 976
    @param check_std: Whether to check std value or just assume compliance
950
    @raise errors.ConfigureError: when specs for given name are not valid
977
    @raise errors.ConfigurationError: when specs for the given name are not
978
        valid
951 979

  
952 980
    """
953
    min_v = ipolicy[constants.ISPECS_MIN].get(name, 0)
981
    missing = constants.ISPECS_MINMAX_KEYS - frozenset(minmaxspecs.keys())
982
    if missing:
983
      msg = "Missing instance specification: %s" % utils.CommaJoin(missing)
984
      raise errors.ConfigurationError(msg)
985

  
986
    minspec = minmaxspecs[constants.ISPECS_MIN]
987
    maxspec = minmaxspecs[constants.ISPECS_MAX]
988
    min_v = minspec.get(name, 0)
954 989

  
955 990
    if check_std:
956
      std_v = ipolicy[constants.ISPECS_STD].get(name, min_v)
991
      std_v = stdspec.get(name, min_v)
957 992
      std_msg = std_v
958 993
    else:
959 994
      std_v = min_v
960 995
      std_msg = "-"
961 996

  
962
    max_v = ipolicy[constants.ISPECS_MAX].get(name, std_v)
963
    err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
964
           (name,
965
            ipolicy[constants.ISPECS_MIN].get(name, "-"),
966
            ipolicy[constants.ISPECS_MAX].get(name, "-"),
967
            std_msg))
997
    max_v = maxspec.get(name, std_v)
968 998
    if min_v > std_v or std_v > max_v:
999
      err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
1000
             (name,
1001
              minspec.get(name, "-"),
1002
              maxspec.get(name, "-"),
1003
              std_msg))
969 1004
      raise errors.ConfigurationError(err)
970 1005

  
971 1006
  @classmethod
b/qa/qa_cluster.py
467 467
  policy = info["Instance policy - limits for instances"]
468 468
  ret_specs = {}
469 469
  ret_policy = {}
470
  ispec_keys = constants.ISPECS_MINMAX_KEYS | frozenset([constants.ISPECS_STD])
470 471
  for (key, val) in policy.items():
471
    if key in constants.IPOLICY_ISPECS:
472
    if key in ispec_keys:
472 473
      for (par, pval) in val.items():
473 474
        if par == "memory-size":
474 475
          par = "mem-size"
b/src/Ganeti/HTools/Backend/Text.hs
7 7

  
8 8
{-
9 9

  
10
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
10
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
11 11

  
12 12
This program is free software; you can redistribute it and/or modify
13 13
it under the terms of the GNU General Public License as published by
......
132 132
-- | Generate policy data from a given policy object.
133 133
serializeIPolicy :: String -> IPolicy -> String
134 134
serializeIPolicy owner ipol =
135
  let IPolicy stdspec minspec maxspec dts vcpu_ratio spindle_ratio = ipol
135
  let IPolicy minmax stdspec dts vcpu_ratio spindle_ratio = ipol
136
      MinMaxISpecs minspec maxspec = minmax
136 137
      strings = [ owner
137 138
                , serializeISpec stdspec
138 139
                , serializeISpec minspec
......
263 264
  xvcpu_ratio <- tryRead (owner ++ "/vcpu_ratio") vcpu_ratio
264 265
  xspindle_ratio <- tryRead (owner ++ "/spindle_ratio") spindle_ratio
265 266
  return (owner,
266
          IPolicy xstdspec xminspec xmaxspec xdts xvcpu_ratio xspindle_ratio)
267
          IPolicy (MinMaxISpecs xminspec xmaxspec) xstdspec
268
                xdts xvcpu_ratio xspindle_ratio)
267 269
loadIPolicy s = fail $ "Invalid ipolicy data: '" ++ show s ++ "'"
268 270

  
269 271
loadOnePolicy :: (IPolicy, Group.List) -> String
b/src/Ganeti/HTools/Instance.hs
7 7

  
8 8
{-
9 9

  
10
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
10
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
11 11

  
12 12
This program is free software; you can redistribute it and/or modify
13 13
it under the terms of the GNU General Public License as published by
......
280 280
-- | Checks if an instance matches a policy.
281 281
instMatchesPolicy :: Instance -> T.IPolicy -> T.OpResult ()
282 282
instMatchesPolicy inst ipol = do
283
  instAboveISpec inst (T.iPolicyMinSpec ipol)
284
  instBelowISpec inst (T.iPolicyMaxSpec ipol)
283
  let minmax = T.iPolicyMinMaxISpecs ipol
284
  instAboveISpec inst (T.minMaxISpecsMinSpec minmax)
285
  instBelowISpec inst (T.minMaxISpecsMaxSpec minmax)
285 286
  if diskTemplate inst `elem` T.iPolicyDiskTemplates ipol
286 287
    then Ok ()
287 288
    else Bad T.FailDisk
b/src/Ganeti/HTools/Program/Hspace.hs
443 443

  
444 444
  -- Run the tiered allocation
445 445

  
446
  let tspec = fromMaybe (rspecFromISpec (iPolicyMaxSpec ipol))
446
  let minmax = iPolicyMinMaxISpecs ipol
447
  let tspec = fromMaybe (rspecFromISpec (minMaxISpecsMaxSpec minmax))
447 448
              (optTieredSpec opts)
448 449

  
449 450
  (treason, trl_nl, _, spec_map) <-
b/src/Ganeti/HTools/Types.hs
6 6

  
7 7
{-
8 8

  
9
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
9
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
10 10

  
11 11
This program is free software; you can redistribute it and/or modify
12 12
it under the terms of the GNU General Public License as published by
......
69 69
  , opToResult
70 70
  , EvacMode(..)
71 71
  , ISpec(..)
72
  , MinMaxISpecs(..)
72 73
  , IPolicy(..)
73 74
  , defIPolicy
74 75
  , rspecFromISpec
......
168 169

  
169 170
-- | The default minimum ispec.
170 171
defMinISpec :: ISpec
171
defMinISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMinMemorySize
172
                    , iSpecCpuCount   = C.ipolicyDefaultsMinCpuCount
173
                    , iSpecDiskSize   = C.ipolicyDefaultsMinDiskSize
174
                    , iSpecDiskCount  = C.ipolicyDefaultsMinDiskCount
175
                    , iSpecNicCount   = C.ipolicyDefaultsMinNicCount
176
                    , iSpecSpindleUse = C.ipolicyDefaultsMinSpindleUse
172
defMinISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMinmaxMinMemorySize
173
                    , iSpecCpuCount   = C.ipolicyDefaultsMinmaxMinCpuCount
174
                    , iSpecDiskSize   = C.ipolicyDefaultsMinmaxMinDiskSize
175
                    , iSpecDiskCount  = C.ipolicyDefaultsMinmaxMinDiskCount
176
                    , iSpecNicCount   = C.ipolicyDefaultsMinmaxMinNicCount
177
                    , iSpecSpindleUse = C.ipolicyDefaultsMinmaxMinSpindleUse
177 178
                    }
178 179

  
179 180
-- | The default standard ispec.
......
188 189

  
189 190
-- | The default max ispec.
190 191
defMaxISpec :: ISpec
191
defMaxISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMaxMemorySize
192
                    , iSpecCpuCount   = C.ipolicyDefaultsMaxCpuCount
193
                    , iSpecDiskSize   = C.ipolicyDefaultsMaxDiskSize
194
                    , iSpecDiskCount  = C.ipolicyDefaultsMaxDiskCount
195
                    , iSpecNicCount   = C.ipolicyDefaultsMaxNicCount
196
                    , iSpecSpindleUse = C.ipolicyDefaultsMaxSpindleUse
192
defMaxISpec = ISpec { iSpecMemorySize = C.ipolicyDefaultsMinmaxMaxMemorySize
193
                    , iSpecCpuCount   = C.ipolicyDefaultsMinmaxMaxCpuCount
194
                    , iSpecDiskSize   = C.ipolicyDefaultsMinmaxMaxDiskSize
195
                    , iSpecDiskCount  = C.ipolicyDefaultsMinmaxMaxDiskCount
196
                    , iSpecNicCount   = C.ipolicyDefaultsMinmaxMaxNicCount
197
                    , iSpecSpindleUse = C.ipolicyDefaultsMinmaxMaxSpindleUse
197 198
                    }
198 199

  
200
-- | Minimum and maximum instance specs type.
201
$(THH.buildObject "MinMaxISpecs" "minMaxISpecs"
202
  [ THH.renameField "MinSpec" $ THH.simpleField "min" [t| ISpec |]
203
  , THH.renameField "MaxSpec" $ THH.simpleField "max" [t| ISpec |]
204
  ])
205

  
206
-- | Defult minimum and maximum instance specs.
207
defMinMaxISpecs :: MinMaxISpecs
208
defMinMaxISpecs = MinMaxISpecs { minMaxISpecsMinSpec = defMinISpec
209
                               , minMaxISpecsMaxSpec = defMaxISpec
210
                               }
211

  
199 212
-- | Instance policy type.
200 213
$(THH.buildObject "IPolicy" "iPolicy"
201
  [ THH.renameField "StdSpec" $ THH.simpleField C.ispecsStd [t| ISpec |]
202
  , THH.renameField "MinSpec" $ THH.simpleField C.ispecsMin [t| ISpec |]
203
  , THH.renameField "MaxSpec" $ THH.simpleField C.ispecsMax [t| ISpec |]
214
  [ THH.renameField "MinMaxISpecs" $
215
      THH.simpleField C.ispecsMinmax [t| MinMaxISpecs |]
216
  , THH.renameField "StdSpec" $ THH.simpleField C.ispecsStd [t| ISpec |]
204 217
  , THH.renameField "DiskTemplates" $
205 218
      THH.simpleField C.ipolicyDts [t| [DiskTemplate] |]
206 219
  , THH.renameField "VcpuRatio" $
......
218 231

  
219 232
-- | The default instance policy.
220 233
defIPolicy :: IPolicy
221
defIPolicy = IPolicy { iPolicyStdSpec = defStdISpec
222
                     , iPolicyMinSpec = defMinISpec
223
                     , iPolicyMaxSpec = defMaxISpec
234
defIPolicy = IPolicy { iPolicyMinMaxISpecs = defMinMaxISpecs
235
                     , iPolicyStdSpec = defStdISpec
224 236
                     -- hardcoding here since Constants.hs exports the
225 237
                     -- string values, not the actual type; and in
226 238
                     -- htools, we are mostly looking at DRBD
b/src/Ganeti/Objects.hs
66 66
  , PartialISpecParams(..)
67 67
  , fillISpecParams
68 68
  , allISpecParamFields
69
  , FilledMinMaxISpecs(..)
70
  , PartialMinMaxISpecs(..)
71
  , fillMinMaxISpecs
69 72
  , FilledIPolicy(..)
70 73
  , PartialIPolicy(..)
71 74
  , fillIPolicy
......
491 494
  , simpleField C.ispecSpindleUse  [t| Int |]
492 495
  ])
493 496

  
497
-- | Partial min-max instance specs. These is not built via buildParam since
498
-- it has a special 2-level inheritance mode.
499
$(buildObject "PartialMinMaxISpecs" "mmis"
500
  [ renameField "MinSpecP" $ simpleField "min" [t| PartialISpecParams |]
501
  , renameField "MaxSpecP" $ simpleField "max" [t| PartialISpecParams |]
502
  ])
503

  
504
-- | Filled min-max instance specs. This is not built via buildParam since
505
-- it has a special 2-level inheritance mode.
506
$(buildObject "FilledMinMaxISpecs" "mmis"
507
  [ renameField "MinSpec" $ simpleField "min" [t| FilledISpecParams |]
508
  , renameField "MaxSpec" $ simpleField "max" [t| FilledISpecParams |]
509
  ])
510

  
494 511
-- | Custom partial ipolicy. This is not built via buildParam since it
495 512
-- has a special 2-level inheritance mode.
496 513
$(buildObject "PartialIPolicy" "ipolicy"
497
  [ renameField "MinSpecP" $ simpleField "min" [t| PartialISpecParams |]
498
  , renameField "MaxSpecP" $ simpleField "max" [t| PartialISpecParams |]
514
  [ optionalField . renameField "MinMaxISpecsP"
515
                    $ simpleField C.ispecsMinmax [t| PartialMinMaxISpecs |]
499 516
  , renameField "StdSpecP" $ simpleField "std" [t| PartialISpecParams |]
500 517
  , optionalField . renameField "SpindleRatioP"
501 518
                    $ simpleField "spindle-ratio"  [t| Double |]
......
508 525
-- | Custom filled ipolicy. This is not built via buildParam since it
509 526
-- has a special 2-level inheritance mode.
510 527
$(buildObject "FilledIPolicy" "ipolicy"
511
  [ renameField "MinSpec" $ simpleField "min" [t| FilledISpecParams |]
512
  , renameField "MaxSpec" $ simpleField "max" [t| FilledISpecParams |]
528
  [ renameField "MinMaxISpecs"
529
    $ simpleField C.ispecsMinmax [t| FilledMinMaxISpecs |]
513 530
  , renameField "StdSpec" $ simpleField "std" [t| FilledISpecParams |]
514 531
  , simpleField "spindle-ratio"  [t| Double |]
515 532
  , simpleField "vcpu-ratio"     [t| Double |]
516 533
  , simpleField "disk-templates" [t| [DiskTemplate] |]
517 534
  ])
518 535

  
536
-- | Custom filler for the min-max instance specs.
537
fillMinMaxISpecs :: FilledMinMaxISpecs -> Maybe PartialMinMaxISpecs ->
538
                    FilledMinMaxISpecs
539
fillMinMaxISpecs fminmax Nothing = fminmax
540
fillMinMaxISpecs (FilledMinMaxISpecs { mmisMinSpec = fmin
541
                                     , mmisMaxSpec = fmax })
542
                 (Just PartialMinMaxISpecs { mmisMinSpecP = pmin
543
                                           , mmisMaxSpecP = pmax }) =
544
  FilledMinMaxISpecs { mmisMinSpec = fillISpecParams fmin pmin
545
                     , mmisMaxSpec = fillISpecParams fmax pmax }
546

  
519 547
-- | Custom filler for the ipolicy types.
520 548
fillIPolicy :: FilledIPolicy -> PartialIPolicy -> FilledIPolicy
521
fillIPolicy (FilledIPolicy { ipolicyMinSpec       = fmin
522
                           , ipolicyMaxSpec       = fmax
549
fillIPolicy (FilledIPolicy { ipolicyMinMaxISpecs  = fminmax
523 550
                           , ipolicyStdSpec       = fstd
524 551
                           , ipolicySpindleRatio  = fspindleRatio
525 552
                           , ipolicyVcpuRatio     = fvcpuRatio
526 553
                           , ipolicyDiskTemplates = fdiskTemplates})
527
            (PartialIPolicy { ipolicyMinSpecP       = pmin
528
                            , ipolicyMaxSpecP       = pmax
554
            (PartialIPolicy { ipolicyMinMaxISpecsP  = pminmax
529 555
                            , ipolicyStdSpecP       = pstd
530 556
                            , ipolicySpindleRatioP  = pspindleRatio
531 557
                            , ipolicyVcpuRatioP     = pvcpuRatio
532 558
                            , ipolicyDiskTemplatesP = pdiskTemplates}) =
533
  FilledIPolicy { ipolicyMinSpec       = fillISpecParams fmin pmin
534
                , ipolicyMaxSpec       = fillISpecParams fmax pmax
559
  FilledIPolicy { ipolicyMinMaxISpecs  = fillMinMaxISpecs fminmax pminmax
535 560
                , ipolicyStdSpec       = fillISpecParams fstd pstd
536 561
                , ipolicySpindleRatio  = fromMaybe fspindleRatio pspindleRatio
537 562
                , ipolicyVcpuRatio     = fromMaybe fvcpuRatio pvcpuRatio
b/test/data/htools/hail-alloc-drbd.json
14 14
          "cpu-count": 1,
15 15
          "spindle-use": 1
16 16
        },
17
        "min": {
18
          "nic-count": 1,
19
          "disk-size": 128,
20
          "disk-count": 1,
21
          "memory-size": 128,
22
          "cpu-count": 1,
23
          "spindle-use": 1
24
        },
25
        "max": {
26
          "nic-count": 8,
27
          "disk-size": 1048576,
28
          "disk-count": 16,
29
          "memory-size": 32768,
30
          "cpu-count": 8,
31
          "spindle-use": 8
17
        "minmax": {
18
	  "min": {
19
	    "nic-count": 1,
20
	    "disk-size": 128,
21
	    "disk-count": 1,
22
	    "memory-size": 128,
23
	    "cpu-count": 1,
24
	    "spindle-use": 1
25
	  },
26
	  "max": {
27
	    "nic-count": 8,
28
	    "disk-size": 1048576,
29
	    "disk-count": 16,
30
	    "memory-size": 32768,
31
	    "cpu-count": 8,
32
	    "spindle-use": 8
33
	  }
32 34
        },
33 35
        "vcpu-ratio": 4.0,
34 36
        "disk-templates": [
b/test/data/htools/hail-change-group.json
14 14
          "cpu-count": 1,
15 15
          "spindle-use": 1
16 16
        },
17
        "min": {
18
          "nic-count": 1,
19
          "disk-size": 128,
20
          "disk-count": 1,
21
          "memory-size": 128,
22
          "cpu-count": 1,
23
          "spindle-use": 1
24
        },
25
        "max": {
26
          "nic-count": 8,
27
          "disk-size": 1048576,
28
          "disk-count": 16,
29
          "memory-size": 32768,
30
          "cpu-count": 8,
31
          "spindle-use": 8
17
        "minmax": {
18
	  "min": {
19
	    "nic-count": 1,
20
	    "disk-size": 128,
21
	    "disk-count": 1,
22
	    "memory-size": 128,
23
	    "cpu-count": 1,
24
	    "spindle-use": 1
25
	  },
26
	  "max": {
27
	    "nic-count": 8,
28
	    "disk-size": 1048576,
29
	    "disk-count": 16,
30
	    "memory-size": 32768,
31
	    "cpu-count": 8,
32
	    "spindle-use": 8
33
	  }
32 34
        },
33 35
        "vcpu-ratio": 4.0,
34 36
        "disk-templates": [
......
56 58
          "cpu-count": 1,
57 59
          "spindle-use": 1
58 60
        },
59
        "min": {
60
          "nic-count": 1,
61
          "disk-size": 128,
62
          "disk-count": 1,
63
          "memory-size": 128,
64
          "cpu-count": 1,
65
          "spindle-use": 1
66
        },
67
        "max": {
68
          "nic-count": 8,
69
          "disk-size": 1048576,
70
          "disk-count": 16,
71
          "memory-size": 32768,
72
          "cpu-count": 8,
73
          "spindle-use": 8
61
        "minmax": {
62
	  "min": {
63
	    "nic-count": 1,
64
	    "disk-size": 128,
65
	    "disk-count": 1,
66
	    "memory-size": 128,
67
	    "cpu-count": 1,
68
	    "spindle-use": 1
69
	  },
70
	  "max": {
71
	    "nic-count": 8,
72
	    "disk-size": 1048576,
73
	    "disk-count": 16,
74
	    "memory-size": 32768,
75
	    "cpu-count": 8,
76
	    "spindle-use": 8
77
	  }
74 78
        },
75 79
        "vcpu-ratio": 4.0,
76 80
        "disk-templates": [
......
98 102
      "disk-count": 1,
99 103
      "spindle-use": 1
100 104
    },
101
    "min": {
102
      "nic-count": 1,
103
      "disk-size": 1024,
104
      "memory-size": 128,
105
      "cpu-count": 1,
106
      "disk-count": 1,
107
      "spindle-use": 1
108
    },
109
    "max": {
110
      "nic-count": 8,
111
      "disk-size": 1048576,
112
      "memory-size": 32768,
113
      "cpu-count": 8,
114
      "disk-count": 16,
115
      "spindle-use": 8
105
    "minmax": {
106
      "min": {
107
	"nic-count": 1,
108
	"disk-size": 1024,
109
	"memory-size": 128,
110
	"cpu-count": 1,
111
	"disk-count": 1,
112
	"spindle-use": 1
113
      },
114
      "max": {
115
	"nic-count": 8,
116
	"disk-size": 1048576,
117
	"memory-size": 32768,
118
	"cpu-count": 8,
119
	"disk-count": 16,
120
	"spindle-use": 8
121
      }
116 122
    },
117 123
    "vcpu-ratio": 4.0,
118 124
    "disk-templates": [
b/test/data/htools/hail-node-evac.json
14 14
          "cpu-count": 1,
15 15
          "spindle-use": 1
16 16
        },
17
        "min": {
18
          "nic-count": 1,
19
          "disk-size": 128,
20
          "disk-count": 1,
21
          "memory-size": 128,
22
          "cpu-count": 1,
23
          "spindle-use": 1
24
        },
25
        "max": {
26
          "nic-count": 8,
27
          "disk-size": 1048576,
28
          "disk-count": 16,
29
          "memory-size": 32768,
30
          "cpu-count": 8,
31
          "spindle-use": 8
17
        "minmax": {
18
	  "min": {
19
	    "nic-count": 1,
20
	    "disk-size": 128,
21
	    "disk-count": 1,
22
	    "memory-size": 128,
23
	    "cpu-count": 1,
24
	    "spindle-use": 1
25
	  },
26
	  "max": {
27
	    "nic-count": 8,
28
	    "disk-size": 1048576,
29
	    "disk-count": 16,
30
	    "memory-size": 32768,
31
	    "cpu-count": 8,
32
	    "spindle-use": 8
33
	  }
32 34
        },
33 35
        "vcpu-ratio": 4.0,
34 36
        "disk-templates": [
b/test/data/htools/hail-reloc-drbd.json
14 14
          "cpu-count": 1,
15 15
          "spindle-use": 1
16 16
        },
17
        "min": {
18
          "nic-count": 1,
19
          "disk-size": 128,
20
          "disk-count": 1,
21
          "memory-size": 128,
22
          "cpu-count": 1,
23
          "spindle-use": 1
24
        },
25
        "max": {
26
          "nic-count": 8,
27
          "disk-size": 1048576,
28
          "disk-count": 16,
29
          "memory-size": 32768,
30
          "cpu-count": 8,
31
          "spindle-use": 8
17
        "minmax": {
18
	  "min": {
19
	    "nic-count": 1,
20
	    "disk-size": 128,
21
	    "disk-count": 1,
22
	    "memory-size": 128,
23
	    "cpu-count": 1,
24
	    "spindle-use": 1
25
	  },
26
	  "max": {
27
	    "nic-count": 8,
28
	    "disk-size": 1048576,
29
	    "disk-count": 16,
30
	    "memory-size": 32768,
31
	    "cpu-count": 8,
32
	    "spindle-use": 8
33
	  }
32 34
        },
33 35
        "vcpu-ratio": 4.0,
34 36
        "disk-templates": [
b/test/data/htools/rapi/groups.json
11 11
        "disk-count": 1,
12 12
        "spindle-use": 1
13 13
      },
14
      "min": {
15
        "cpu-count": 1,
16
        "nic-count": 1,
17
        "disk-size": 1024,
18
        "memory-size": 128,
19
        "disk-count": 1,
20
        "spindle-use": 1
21
      },
22
      "max": {
23
        "cpu-count": 8,
24
        "nic-count": 8,
25
        "disk-size": 1048576,
26
        "memory-size": 32768,
27
        "disk-count": 16,
28
        "spindle-use": 8
14
      "minmax": {
15
	"min": {
16
	  "cpu-count": 1,
17
	  "nic-count": 1,
18
	  "disk-size": 1024,
19
	  "memory-size": 128,
20
	  "disk-count": 1,
21
	  "spindle-use": 1
22
	},
23
	"max": {
24
	  "cpu-count": 8,
25
	  "nic-count": 8,
26
	  "disk-size": 1048576,
27
	  "memory-size": 32768,
28
	  "disk-count": 16,
29
	  "spindle-use": 8
30
	}
29 31
      },
30 32
      "vcpu-ratio": 4.0,
31 33
      "disk-templates": [
b/test/data/htools/rapi/info.json
86 86
      "cpu-count": 1,
87 87
      "spindle-use": 1
88 88
    },
89
    "min": {
90
      "nic-count": 1,
91
      "disk-size": 128,
92
      "disk-count": 1,
93
      "memory-size": 128,
94
      "cpu-count": 1,
95
      "spindle-use": 1
96
    },
97
    "max": {
98
      "nic-count": 8,
99
      "disk-size": 1048576,
100
      "disk-count": 16,
101
      "memory-size": 32768,
102
      "cpu-count": 8,
103
      "spindle-use": 8
89
    "minmax": {
90
      "min": {
91
	"nic-count": 1,
92
	"disk-size": 128,
93
	"disk-count": 1,
94
	"memory-size": 128,
95
	"cpu-count": 1,
96
	"spindle-use": 1
97
      },
98
      "max": {
99
	"nic-count": 8,
100
	"disk-size": 1048576,
101
	"disk-count": 16,
102
	"memory-size": 32768,
103
	"cpu-count": 8,
104
	"spindle-use": 8
105
      }
104 106
    },
105 107
    "vcpu-ratio": 4.0,
106 108
    "disk-templates": [
b/test/hs/Test/Ganeti/HTools/Types.hs
110 110
    dts  <- genUniquesList num_tmpl arbitrary
111 111
    vcpu_ratio <- choose (1.0, maxVcpuRatio)
112 112
    spindle_ratio <- choose (1.0, maxSpindleRatio)
113
    return Types.IPolicy { Types.iPolicyMinSpec = imin
113
    return Types.IPolicy { Types.iPolicyMinMaxISpecs = Types.MinMaxISpecs
114
                           { Types.minMaxISpecsMinSpec = imin
115
                           , Types.minMaxISpecsMaxSpec = imax
116
                           }
114 117
                         , Types.iPolicyStdSpec = istd
115
                         , Types.iPolicyMaxSpec = imax
116 118
                         , Types.iPolicyDiskTemplates = dts
117 119
                         , Types.iPolicyVcpuRatio = vcpu_ratio
118 120
                         , Types.iPolicySpindleRatio = spindle_ratio
b/test/hs/Test/Ganeti/Objects.hs
139 139
-- | FIXME: This generates completely random data, without normal
140 140
-- validation rules.
141 141
$(genArbitrary ''PartialISpecParams)
142
$(genArbitrary ''PartialMinMaxISpecs)
142 143

  
143 144
-- | FIXME: This generates completely random data, without normal
144 145
-- validation rules.
145 146
$(genArbitrary ''PartialIPolicy)
146 147

  
147 148
$(genArbitrary ''FilledISpecParams)
149
$(genArbitrary ''FilledMinMaxISpecs)
148 150
$(genArbitrary ''FilledIPolicy)
149 151
$(genArbitrary ''IpFamily)
150 152
$(genArbitrary ''FilledNDParams)
b/test/hs/Test/Ganeti/TestHTools.hs
52 52
-- | Null iPolicy, and by null we mean very liberal.
53 53
nullIPolicy :: Types.IPolicy
54 54
nullIPolicy = Types.IPolicy
55
  { Types.iPolicyMinSpec = Types.ISpec { Types.iSpecMemorySize = 0
56
                                       , Types.iSpecCpuCount   = 0
57
                                       , Types.iSpecDiskSize   = 0
58
                                       , Types.iSpecDiskCount  = 0
59
                                       , Types.iSpecNicCount   = 0
60
                                       , Types.iSpecSpindleUse = 0
61
                                       }
62
  , Types.iPolicyMaxSpec = Types.ISpec { Types.iSpecMemorySize = maxBound
63
                                       , Types.iSpecCpuCount   = maxBound
64
                                       , Types.iSpecDiskSize   = maxBound
65
                                       , Types.iSpecDiskCount  = C.maxDisks
66
                                       , Types.iSpecNicCount   = C.maxNics
67
                                       , Types.iSpecSpindleUse = maxBound
68
                                       }
55
  { Types.iPolicyMinMaxISpecs = Types.MinMaxISpecs
56
    { Types.minMaxISpecsMinSpec = Types.ISpec { Types.iSpecMemorySize = 0
57
                                              , Types.iSpecCpuCount   = 0
58
                                              , Types.iSpecDiskSize   = 0
59
                                              , Types.iSpecDiskCount  = 0
60
                                              , Types.iSpecNicCount   = 0
61
                                              , Types.iSpecSpindleUse = 0
62
                                              }
63
    , Types.minMaxISpecsMaxSpec = Types.ISpec
64
      { Types.iSpecMemorySize = maxBound
65
      , Types.iSpecCpuCount   = maxBound
66
      , Types.iSpecDiskSize   = maxBound
67
      , Types.iSpecDiskCount  = C.maxDisks
68
      , Types.iSpecNicCount   = C.maxNics
69
      , Types.iSpecSpindleUse = maxBound
70
      }
71
    }
69 72
  , Types.iPolicyStdSpec = Types.ISpec { Types.iSpecMemorySize = Types.unitMem
70 73
                                       , Types.iSpecCpuCount   = Types.unitCpu
71 74
                                       , Types.iSpecDiskSize   = Types.unitDsk
b/test/py/ganeti.cli_unittest.py
1141 1141

  
1142 1142
  def testClusterPolicy(self):
1143 1143
    exp_pol0 = {
1144
      constants.ISPECS_MIN: {},
1145
      constants.ISPECS_MAX: {},
1144
      constants.ISPECS_MINMAX: {
1145
        constants.ISPECS_MIN: {},
1146
        constants.ISPECS_MAX: {},
1147
        },
1146 1148
      constants.ISPECS_STD: {},
1147 1149
      }
1148 1150
    exp_pol1 = {
1149
      constants.ISPECS_MIN: {
1150
        constants.ISPEC_CPU_COUNT: 2,
1151
        constants.ISPEC_DISK_COUNT: 1,
1152
        },
1153
      constants.ISPECS_MAX: {
1154
        constants.ISPEC_MEM_SIZE: 12*1024,
1155
        constants.ISPEC_DISK_COUNT: 2,
1151
      constants.ISPECS_MINMAX: {
1152
        constants.ISPECS_MIN: {
1153
          constants.ISPEC_CPU_COUNT: 2,
1154
          constants.ISPEC_DISK_COUNT: 1,
1155
          },
1156
        constants.ISPECS_MAX: {
1157
          constants.ISPEC_MEM_SIZE: 12*1024,
1158
          constants.ISPEC_DISK_COUNT: 2,
1159
          },
1156 1160
        },
1157 1161
      constants.ISPECS_STD: {
1158 1162
        constants.ISPEC_CPU_COUNT: 2,
......
1161 1165
      constants.IPOLICY_VCPU_RATIO: 3.1,
1162 1166
      }
1163 1167
    exp_pol2 = {
1164
      constants.ISPECS_MIN: {
1165
        constants.ISPEC_DISK_SIZE: 512,
1166
        constants.ISPEC_NIC_COUNT: 2,
1167
        },
1168
      constants.ISPECS_MAX: {
1169
        constants.ISPEC_NIC_COUNT: 3,
1168
      constants.ISPECS_MINMAX: {
1169
        constants.ISPECS_MIN: {
1170
          constants.ISPEC_DISK_SIZE: 512,
1171
          constants.ISPEC_NIC_COUNT: 2,
1172
          },
1173
        constants.ISPECS_MAX: {
1174
          constants.ISPEC_NIC_COUNT: 3,
1175
          },
1170 1176
        },
1171 1177
      constants.ISPECS_STD: {
1172 1178
        constants.ISPEC_CPU_COUNT: 2,
......
1245 1251
  def testAllowedValues(self):
1246 1252
    allowedv = "blah"
1247 1253
    exp_pol1 = {
1248
      constants.ISPECS_MIN: {
1249
        constants.ISPEC_CPU_COUNT: allowedv,
1250
        },
1251
      constants.ISPECS_MAX: {
1254
      constants.ISPECS_MINMAX: {
1255
        constants.ISPECS_MIN: {
1256
          constants.ISPEC_CPU_COUNT: allowedv,
1257
          },
1258
        constants.ISPECS_MAX: {
1259
          },
1252 1260
        },
1253 1261
      constants.ISPECS_STD: {
1254 1262
        },
b/test/py/ganeti.cmdlib_unittest.py
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2008, 2011, 2012 Google Inc.
4
# Copyright (C) 2008, 2011, 2012, 2013 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
589 589

  
590 590
class TestComputeMinMaxSpec(unittest.TestCase):
591 591
  def setUp(self):
592
    self.ipolicy = {
592
    self.ispecs = {
593 593
      constants.ISPECS_MAX: {
594 594
        constants.ISPEC_MEM_SIZE: 512,
595 595
        constants.ISPEC_DISK_SIZE: 1024,
......
602 602

  
603 603
  def testNoneValue(self):
604 604
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_MEM_SIZE, None,
605
                                              self.ipolicy, None) is None)
605
                                              self.ispecs, None) is None)
606 606

  
607 607
  def testAutoValue(self):
608 608
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_MEM_SIZE, None,
609
                                              self.ipolicy,
609
                                              self.ispecs,
610 610
                                              constants.VALUE_AUTO) is None)
611 611

  
612 612
  def testNotDefined(self):
613 613
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_NIC_COUNT, None,
614
                                              self.ipolicy, 3) is None)
614
                                              self.ispecs, 3) is None)
615 615

  
616 616
  def testNoMinDefined(self):
617 617
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_DISK_SIZE, None,
618
                                              self.ipolicy, 128) is None)
618
                                              self.ispecs, 128) is None)
619 619

  
620 620
  def testNoMaxDefined(self):
621 621
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_DISK_COUNT, None,
622
                                                self.ipolicy, 16) is None)
622
                                                self.ispecs, 16) is None)
623 623

  
624 624
  def testOutOfRange(self):
625 625
    for (name, val) in ((constants.ISPEC_MEM_SIZE, 64),
626 626
                        (constants.ISPEC_MEM_SIZE, 768),
627 627
                        (constants.ISPEC_DISK_SIZE, 4096),
628 628
                        (constants.ISPEC_DISK_COUNT, 0)):
629
      min_v = self.ipolicy[constants.ISPECS_MIN].get(name, val)
630
      max_v = self.ipolicy[constants.ISPECS_MAX].get(name, val)
629
      min_v = self.ispecs[constants.ISPECS_MIN].get(name, val)
630
      max_v = self.ispecs[constants.ISPECS_MAX].get(name, val)
631 631
      self.assertEqual(cmdlib._ComputeMinMaxSpec(name, None,
632
                                                 self.ipolicy, val),
632
                                                 self.ispecs, val),
633 633
                       "%s value %s is not in range [%s, %s]" %
634 634
                       (name, val,min_v, max_v))
635 635
      self.assertEqual(cmdlib._ComputeMinMaxSpec(name, "1",
636
                                                 self.ipolicy, val),
636
                                                 self.ispecs, val),
637 637
                       "%s/1 value %s is not in range [%s, %s]" %
638 638
                       (name, val,min_v, max_v))
639 639

  
......
645 645
                        (constants.ISPEC_DISK_SIZE, 0),
646 646
                        (constants.ISPEC_DISK_COUNT, 1),
647 647
                        (constants.ISPEC_DISK_COUNT, 5)):
648
      self.assertTrue(cmdlib._ComputeMinMaxSpec(name, None, self.ipolicy, val)
648
      self.assertTrue(cmdlib._ComputeMinMaxSpec(name, None, self.ispecs, val)
649 649
                      is None)
650 650

  
651 651

  
......
673 673
  # Minimal policy accepted by _ComputeIPolicySpecViolation()
674 674
  _MICRO_IPOL = {
675 675
    constants.IPOLICY_DTS: [constants.DT_PLAIN, constants.DT_DISKLESS],
676
    constants.ISPECS_MINMAX: NotImplemented,
676 677
    }
677 678

  
678 679
  def test(self):
......
1732 1733
  """Tests for cmdlib._GetUpdatedIPolicy()"""
1733 1734
  _OLD_CLUSTER_POLICY = {
1734 1735
    constants.IPOLICY_VCPU_RATIO: 1.5,
1735
    constants.ISPECS_MIN: {
1736
      constants.ISPEC_MEM_SIZE: 20,
1737
      constants.ISPEC_CPU_COUNT: 2,
1736
    constants.ISPECS_MINMAX: {
1737
      constants.ISPECS_MIN: {
1738
        constants.ISPEC_MEM_SIZE: 20,
1739
        constants.ISPEC_CPU_COUNT: 2,
1740
        },
1741
      constants.ISPECS_MAX: {},
1738 1742
      },
1739
    constants.ISPECS_MAX: {},
1740 1743
    constants.ISPECS_STD: {},
1741 1744
    }
1742

  
1743 1745
  _OLD_GROUP_POLICY = {
1744 1746
    constants.IPOLICY_SPINDLE_RATIO: 2.5,
1745
    constants.ISPECS_MIN: {
1746
      constants.ISPEC_DISK_SIZE: 20,
1747
      constants.ISPEC_NIC_COUNT: 2,
1747
    constants.ISPECS_MINMAX: {
1748
      constants.ISPECS_MIN: {
1749
        constants.ISPEC_DISK_SIZE: 20,
1750
        constants.ISPEC_NIC_COUNT: 2,
1751
        },
1752
      constants.ISPECS_MAX: {},
1748 1753
      },
1749
    constants.ISPECS_MAX: {},
1750 1754
    }
1751 1755

  
1752 1756
  def _TestSetSpecs(self, old_policy, isgroup):
......
1756 1760
      constants.ISPEC_DISK_SIZE: 30,
1757 1761
      }
1758 1762
    diff_policy = {
1759
      ispec_key: diff_ispec
1763
      constants.ISPECS_MINMAX: {
1764
        ispec_key: diff_ispec,
1765
        },
1760 1766
      }
1767
    if not isgroup:
1768
      diff_std = {
1769
        constants.ISPEC_CPU_COUNT: 3,
1770
        constants.ISPEC_DISK_COUNT: 3,
1771
        }
1772
      diff_policy[constants.ISPECS_STD] = diff_std
1761 1773
    new_policy = cmdlib._GetUpdatedIPolicy(old_policy, diff_policy,
1762 1774
                                           group_policy=isgroup)
1763
    new_ispec = new_policy[ispec_key]
1775

  
1776
    self.assertTrue(constants.ISPECS_MINMAX in new_policy)
1777
    new_ispec = new_policy[constants.ISPECS_MINMAX][ispec_key]
1764 1778
    for key in diff_ispec:
1765 1779
      self.assertTrue(key in new_ispec)
1766 1780
      self.assertEqual(new_ispec[key], diff_ispec[key])
......
1768 1782
      if not key in diff_policy:
1769 1783
        self.assertTrue(key in new_policy)
1770 1784
        self.assertEqual(new_policy[key], old_policy[key])
1771
    old_ispec = old_policy[ispec_key]
1772
    for key in old_ispec:
1773
      if not key in diff_ispec:
1774
        self.assertTrue(key in new_ispec)
1775
        self.assertEqual(new_ispec[key], old_ispec[key])
1785

  
1786
    if constants.ISPECS_MINMAX in old_policy:
1787
      old_minmax = old_policy[constants.ISPECS_MINMAX]
1788
      for key in old_minmax:
1789
        if key != ispec_key:
1790
          self.assertTrue(key in new_policy[constants.ISPECS_MINMAX])
1791
          self.assertEqual(new_policy[constants.ISPECS_MINMAX][key],
1792
                           old_minmax[key])
1793
      old_ispec = old_policy[constants.ISPECS_MINMAX][ispec_key]
1794
      for key in old_ispec:
1795
        if not key in diff_ispec:
1796
          self.assertTrue(key in new_ispec)
1797
          self.assertEqual(new_ispec[key], old_ispec[key])
1798

  
1799
    if not isgroup:
1800
      new_std = new_policy[constants.ISPECS_STD]
1801
      for key in diff_std:
1802
        self.assertTrue(key in new_std)
1803
        self.assertEqual(new_std[key], diff_std[key])
1804

  
1776 1805

  
1777 1806
  def _TestSet(self, old_policy, isgroup):
1778 1807
    diff_policy = {
......
1816 1845
    invalid_policy = INVALID_DICT
1817 1846
    self.assertRaises(errors.OpPrereqError, cmdlib._GetUpdatedIPolicy,
1818 1847
                      old_policy, invalid_policy, group_policy=isgroup)
1819
    for key in constants.IPOLICY_ISPECS:
1848
    invalid_ispecs = {
1849
      constants.ISPECS_MINMAX: INVALID_DICT,
1850
      }
1851
    self.assertRaises(errors.OpPrereqError, cmdlib._GetUpdatedIPolicy,
1852
                      old_policy, invalid_ispecs, group_policy=isgroup)
1853
    for key in constants.ISPECS_MINMAX_KEYS:
1820 1854
      invalid_ispec = {
1821
        key: INVALID_DICT,
1855
        constants.ISPECS_MINMAX: {
1856
          key: INVALID_DICT,
1857
          },
1822 1858
        }
1823 1859
      self.assertRaises(errors.TypeEnforcementError, cmdlib._GetUpdatedIPolicy,
1824 1860
                        old_policy, invalid_ispec, group_policy=isgroup)
b/test/py/ganeti.objects_unittest.py
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007, 2008, 2010, 2012 Google Inc.
4
# Copyright (C) 2006, 2007, 2008, 2010, 2012, 2013 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
414 414

  
415 415
  def _AssertIPolicyIsFull(self, policy):
416 416
    self.assertEqual(frozenset(policy.keys()), constants.IPOLICY_ALL_KEYS)
417
    for key in constants.IPOLICY_ISPECS:
418
      spec = policy[key]
419
      self.assertEqual(frozenset(spec.keys()), constants.ISPECS_PARAMETERS)
417
    minmax = policy[constants.ISPECS_MINMAX]
418
    self.assertEqual(frozenset(minmax.keys()), constants.ISPECS_MINMAX_KEYS)
419
    for key in constants.ISPECS_MINMAX_KEYS:
420
      self.assertEqual(frozenset(minmax[key].keys()),
421
                       constants.ISPECS_PARAMETERS)
422
    self.assertEqual(frozenset(policy[constants.ISPECS_STD].keys()),
423
                     constants.ISPECS_PARAMETERS)
420 424

  
421 425
  def testDefaultIPolicy(self):
422 426
    objects.InstancePolicy.CheckParameterSyntax(constants.IPOLICY_DEFAULTS,
......
426 430
  def testCheckISpecSyntax(self):
427 431
    par = "my_parameter"
428 432
    for check_std in [True, False]:
429
      if check_std:
430
        allkeys = constants.IPOLICY_ISPECS
431
      else:
432
        allkeys = constants.IPOLICY_ISPECS - frozenset([constants.ISPECS_STD])
433 433
      # Only one policy limit
434
      for key in allkeys:
435
        policy = dict((k, {}) for k in allkeys)
436
        policy[key][par] = 11
437
        objects.InstancePolicy.CheckISpecSyntax(policy, par, check_std)
434
      for key in constants.ISPECS_MINMAX_KEYS:
435
        minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
436
        minmax[key][par] = 11
437
        objects.InstancePolicy.CheckISpecSyntax(minmax, {}, par, check_std)
438
      if check_std:
439
        minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
440
        stdspec = {par: 11}
441
        objects.InstancePolicy.CheckISpecSyntax(minmax, stdspec, par, check_std)
442

  
438 443
      # Min and max only
439 444
      good_values = [(11, 11), (11, 40), (0, 0)]
440 445
      for (mn, mx) in good_values:
441
        policy = dict((k, {}) for k in allkeys)
442
        policy[constants.ISPECS_MIN][par] = mn
443
        policy[constants.ISPECS_MAX][par] = mx
444
        objects.InstancePolicy.CheckISpecSyntax(policy, par, check_std)
445
      policy = dict((k, {}) for k in allkeys)
446
      policy[constants.ISPECS_MIN][par] = 11
447
      policy[constants.ISPECS_MAX][par] = 5
446
        minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
447
        minmax[constants.ISPECS_MIN][par] = mn
448
        minmax[constants.ISPECS_MAX][par] = mx
449
        objects.InstancePolicy.CheckISpecSyntax(minmax, {}, par, check_std)
450
      minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
451
      minmax[constants.ISPECS_MIN][par] = 11
452
      minmax[constants.ISPECS_MAX][par] = 5
448 453
      self.assertRaises(errors.ConfigurationError,
449 454
                        objects.InstancePolicy.CheckISpecSyntax,
450
                        policy, par, check_std)
455
                        minmax, {}, par, check_std)
451 456
    # Min, std, max
452 457
    good_values = [
453 458
      (11, 11, 11),
......
455 460
      (11, 40, 40),
456 461
      ]
457 462
    for (mn, st, mx) in good_values:
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff