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 cmd = ("%s stop-all; %s start %s" %
220 (pathutils.DAEMON_UTIL, pathutils.DAEMON_UTIL, constants.NODED))
221
222 result = utils.RunCmd(cmd, interactive=True)
223 if result.failed:
224 raise SetupError("Could not start the node daemon, command '%s'"
225 " failed: %s" % (result.cmd, result.fail_reason))
226
227 logging.info("Node daemon successfully configured")
228 except Exception, err:
229 logging.debug("Caught unhandled exception", exc_info=True)
230
231 (retcode, message) = cli.FormatError(err)
232 logging.error(message)
233
234 return retcode
235 else:
236 return constants.EXIT_SUCCESS
237