1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """Script to configure the node daemon.
22
23 """
24
25 import os
26 import os.path
27 import optparse
28 import sys
29 import logging
30 import OpenSSL
31 from cStringIO import StringIO
32
33 from ganeti import cli
34 from ganeti import constants
35 from ganeti import errors
36 from ganeti import pathutils
37 from ganeti import utils
38 from ganeti import serializer
39 from ganeti import runtime
40 from ganeti import ht
41 from ganeti import ssconf
42
43
44 _DATA_CHECK = ht.TStrictDict(False, True, {
45 constants.NDS_CLUSTER_NAME: ht.TNonEmptyString,
46 constants.NDS_NODE_DAEMON_CERTIFICATE: ht.TNonEmptyString,
47 constants.NDS_SSCONF: ht.TDictOf(ht.TNonEmptyString, ht.TString),
48 constants.NDS_START_NODE_DAEMON: ht.TBool,
49 })
50
51
53 """Local class for reporting errors.
54
55 """
56
57
59 """Parses the options passed to the program.
60
61 @return: Options and arguments
62
63 """
64 parser = optparse.OptionParser(usage="%prog [--dry-run]",
65 prog=os.path.basename(sys.argv[0]))
66 parser.add_option(cli.DEBUG_OPT)
67 parser.add_option(cli.VERBOSE_OPT)
68 parser.add_option(cli.DRY_RUN_OPT)
69
70 (opts, args) = parser.parse_args()
71
72 return VerifyOptions(parser, opts, args)
73
74
76 """Verifies options and arguments for correctness.
77
78 """
79 if args:
80 parser.error("No arguments are expected")
81
82 return opts
83
84
86 """Verifies a certificate against the local node daemon certificate.
87
88 @type cert_pem: string
89 @param cert_pem: Certificate and key in PEM format
90 @rtype: string
91 @return: Formatted key and certificate
92
93 """
94 try:
95 cert = \
96 OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_pem)
97 except Exception, err:
98 raise errors.X509CertError("(stdin)",
99 "Unable to load certificate: %s" % err)
100
101 try:
102 key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, cert_pem)
103 except OpenSSL.crypto.Error, err:
104 raise errors.X509CertError("(stdin)",
105 "Unable to load private key: %s" % err)
106
107
108
109 x509_check_fn = utils.PrepareX509CertKeyCheck(cert, key)
110 try:
111 x509_check_fn()
112 except OpenSSL.SSL.Error:
113 raise errors.X509CertError("(stdin)",
114 "Certificate is not signed with given key")
115
116
117
118 _check_fn(cert)
119
120
121 buf = StringIO()
122 buf.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
123 buf.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
124 return buf.getvalue()
125
126
128 """Verifies cluster certificate.
129
130 @type data: dict
131 @rtype: string
132 @return: Formatted key and certificate
133
134 """
135 cert = data.get(constants.NDS_NODE_DAEMON_CERTIFICATE)
136 if not cert:
137 raise SetupError("Node daemon certificate must be specified")
138
139 return _verify_fn(cert)
140
141
143 """Verifies cluster name.
144
145 @type data: dict
146 @rtype: string
147 @return: Cluster name
148
149 """
150 name = data.get(constants.NDS_CLUSTER_NAME)
151 if not name:
152 raise SetupError("Cluster name must be specified")
153
154 _verify_fn(name)
155
156 return name
157
158
160 """Verifies ssconf names.
161
162 @type data: dict
163
164 """
165 items = data.get(constants.NDS_SSCONF)
166
167 if not items:
168 raise SetupError("Ssconf values must be specified")
169
170
171
172 _verify_fn(items.keys())
173
174 if items.get(constants.SS_CLUSTER_NAME) != cluster_name:
175 raise SetupError("Cluster name in ssconf does not match")
176
177 return items
178
179
187
188
190 """Main routine.
191
192 """
193 opts = ParseOptions()
194
195 utils.SetupToolLogging(opts.debug, opts.verbose)
196
197 try:
198 getent = runtime.GetEnts()
199
200 data = LoadData(sys.stdin.read())
201
202 cluster_name = VerifyClusterName(data)
203 cert_pem = VerifyCertificate(data)
204 ssdata = VerifySsconf(data, cluster_name)
205
206 logging.info("Writing ssconf files ...")
207 ssconf.WriteSsconfFiles(ssdata, dry_run=opts.dry_run)
208
209 logging.info("Writing node daemon certificate ...")
210 utils.WriteFile(pathutils.NODED_CERT_FILE, data=cert_pem,
211 mode=pathutils.NODED_CERT_MODE,
212 uid=getent.masterd_uid, gid=getent.masterd_gid,
213 dry_run=opts.dry_run)
214
215 if (data.get(constants.NDS_START_NODE_DAEMON) and
216 not opts.dry_run):
217 logging.info("Restarting node daemon ...")
218
219 stop_cmd = "%s stop-all" % pathutils.DAEMON_UTIL
220 noded_cmd = "%s start %s" % (pathutils.DAEMON_UTIL, constants.NODED)
221 mond_cmd = ""
222 if constants.ENABLE_MOND:
223 mond_cmd = "%s start %s" % (pathutils.DAEMON_UTIL, constants.MOND)
224
225 cmd = "; ".join([stop_cmd, noded_cmd, mond_cmd])
226
227 result = utils.RunCmd(cmd, interactive=True)
228 if result.failed:
229 raise SetupError("Could not start the node daemons, command '%s'"
230 " failed: %s" % (result.cmd, result.fail_reason))
231
232 logging.info("Node daemon successfully configured")
233 except Exception, err:
234 logging.debug("Caught unhandled exception", exc_info=True)
235
236 (retcode, message) = cli.FormatError(err)
237 logging.error(message)
238
239 return retcode
240 else:
241 return constants.EXIT_SUCCESS
242