Merge branch 'stable-2.16' into stable-2.17
[ganeti-github.git] / lib / config / verify.py
1 #
2 #
3
4 # Copyright (C) 2015 Google Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
9 # met:
10 #
11 # 1. Redistributions of source code must retain the above copyright notice,
12 # this list of conditions and the following disclaimer.
13 #
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
31 """Verification helpers for the configuration object."""
32
33 from ganeti import constants
34 from ganeti import errors
35 from ganeti import objects
36 from ganeti import utils
37
38
39 def ValidateConfig(data):
40 """Verifies that a configuration dict looks valid.
41
42 This only verifies the version of the configuration.
43
44 @raise errors.ConfigurationError: if the version differs from what
45 we expect
46
47 """
48 if data['version'] != constants.CONFIG_VERSION:
49 raise errors.ConfigVersionMismatch(constants.CONFIG_VERSION,
50 data['version'])
51
52
53 def VerifyType(owner, attr, value, template, callback):
54 """Checks if an attribute has correct form.
55
56 @type owner: str
57 @param owner: name of the object containing the attribute
58 @type attr: str
59 @param attr: name of the attribute
60 @type value: dict
61 @param value: actual value of the attribute
62 @type template: dict
63 @param template: expected types of the keys
64 @type callback: callable
65 @param callback: will be called if there is an error
66
67 """
68 try:
69 utils.ForceDictType(value, template)
70 except errors.GenericError, err:
71 return callback("%s has invalid %s: %s" % (owner, attr, err))
72
73
74 def VerifyNic(owner, params, callback):
75 """Checks if a NIC has correct form.
76
77 @type owner: str
78 @param owner: name of the object containing the attribute
79 @type params: dict
80 @param params: actual value of the NIC parameters
81 @type callback: callable
82 @param callback: will be called if there is an error
83
84 """
85 try:
86 objects.NIC.CheckParameterSyntax(params)
87 except errors.ConfigurationError, err:
88 callback("%s has invalid nicparams: %s" % (owner, err))
89
90
91 def VerifyIpolicy(owner, ipolicy, iscluster, callback):
92 """Checks if an ipolicy has correct form.
93
94 @type owner: str
95 @param owner: name of the object containing the attribute
96 @type ipolicy: dict
97 @param ipolicy: actual value of the ipolicy parameters
98 @type iscluster: bool
99 @param iscluster: True iff the owner is the cluster
100 @type callback: callable
101 @param callback: will be called if there is an error
102
103 """
104 try:
105 objects.InstancePolicy.CheckParameterSyntax(ipolicy, iscluster)
106 except errors.ConfigurationError, err:
107 callback("%s has invalid instance policy: %s" % (owner, err))
108 for key, value in ipolicy.items():
109 if key == constants.ISPECS_MINMAX:
110 for i, val in enumerate(value):
111 VerifyIspecs(owner, "ipolicy/%s[%s]" % (key, i), val, callback)
112 elif key == constants.ISPECS_STD:
113 VerifyType(owner, "ipolicy/" + key, value,
114 constants.ISPECS_PARAMETER_TYPES, callback)
115 else:
116 # FIXME: assuming list type
117 if key in constants.IPOLICY_PARAMETERS:
118 exp_type = float
119 # if the value is int, it can be converted into float
120 convertible_types = [int]
121 else:
122 exp_type = list
123 convertible_types = []
124 # Try to convert from allowed types, if necessary.
125 if any(isinstance(value, ct) for ct in convertible_types):
126 try:
127 value = exp_type(value)
128 ipolicy[key] = value
129 except ValueError:
130 pass
131 if not isinstance(value, exp_type):
132 callback("%s has invalid instance policy: for %s,"
133 " expecting %s, got %s" %
134 (owner, key, exp_type.__name__, type(value)))
135
136
137 def VerifyIspecs(owner, parentkey, params, callback):
138 """Checks if an ispec has correct form.
139
140 @type owner: str
141 @param owner: name of the object containing the attribute
142 @type parentkey: str
143 @param parentkey: the root name of the key
144 @type params: dict
145 @param params: actual value of the ispec parameters
146 @type callback: callable
147 @param callback: will be called if there is an error
148
149 """
150 for (key, value) in params.items():
151 fullkey = "/".join([parentkey, key])
152 VerifyType(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES,
153 callback)