Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-masterd @ a478cd7e

History | View | Annotate | Download (11.9 kB)

1 685ee993 Iustin Pop
#!/usr/bin/python -u
2 ffeffa1d Iustin Pop
#
3 ffeffa1d Iustin Pop
4 ffeffa1d Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 ffeffa1d Iustin Pop
#
6 ffeffa1d Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 ffeffa1d Iustin Pop
# it under the terms of the GNU General Public License as published by
8 ffeffa1d Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 ffeffa1d Iustin Pop
# (at your option) any later version.
10 ffeffa1d Iustin Pop
#
11 ffeffa1d Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 ffeffa1d Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 ffeffa1d Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ffeffa1d Iustin Pop
# General Public License for more details.
15 ffeffa1d Iustin Pop
#
16 ffeffa1d Iustin Pop
# You should have received a copy of the GNU General Public License
17 ffeffa1d Iustin Pop
# along with this program; if not, write to the Free Software
18 ffeffa1d Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 ffeffa1d Iustin Pop
# 02110-1301, USA.
20 ffeffa1d Iustin Pop
21 ffeffa1d Iustin Pop
22 ffeffa1d Iustin Pop
"""Master daemon program.
23 ffeffa1d Iustin Pop
24 ffeffa1d Iustin Pop
Some classes deviates from the standard style guide since the
25 ffeffa1d Iustin Pop
inheritance from parent classes requires it.
26 ffeffa1d Iustin Pop
27 ffeffa1d Iustin Pop
"""
28 ffeffa1d Iustin Pop
29 ffeffa1d Iustin Pop
30 c1f2901b Iustin Pop
import sys
31 ffeffa1d Iustin Pop
import SocketServer
32 ffeffa1d Iustin Pop
import threading
33 ffeffa1d Iustin Pop
import time
34 ffeffa1d Iustin Pop
import collections
35 ffeffa1d Iustin Pop
import Queue
36 ffeffa1d Iustin Pop
import random
37 ffeffa1d Iustin Pop
import signal
38 ffeffa1d Iustin Pop
import simplejson
39 ffeffa1d Iustin Pop
40 ffeffa1d Iustin Pop
41 ffeffa1d Iustin Pop
from cStringIO import StringIO
42 c1f2901b Iustin Pop
from optparse import OptionParser
43 ffeffa1d Iustin Pop
44 39dcf2ef Guido Trotter
from ganeti import config
45 ffeffa1d Iustin Pop
from ganeti import constants
46 ffeffa1d Iustin Pop
from ganeti import mcpu
47 ffeffa1d Iustin Pop
from ganeti import opcodes
48 ffeffa1d Iustin Pop
from ganeti import jqueue
49 39dcf2ef Guido Trotter
from ganeti import locking
50 ffeffa1d Iustin Pop
from ganeti import luxi
51 ffeffa1d Iustin Pop
from ganeti import utils
52 c1f2901b Iustin Pop
from ganeti import errors
53 c1f2901b Iustin Pop
from ganeti import ssconf
54 c1f2901b Iustin Pop
55 c1f2901b Iustin Pop
56 c1f2901b Iustin Pop
EXIT_NOTMASTER = constants.EXIT_NOTMASTER
57 c1f2901b Iustin Pop
EXIT_NODESETUP_ERROR = constants.EXIT_NODESETUP_ERROR
58 ffeffa1d Iustin Pop
59 ffeffa1d Iustin Pop
60 ffeffa1d Iustin Pop
class IOServer(SocketServer.UnixStreamServer):
61 ffeffa1d Iustin Pop
  """IO thread class.
62 ffeffa1d Iustin Pop
63 ffeffa1d Iustin Pop
  This class takes care of initializing the other threads, setting
64 ffeffa1d Iustin Pop
  signal handlers (which are processed only in this thread), and doing
65 ffeffa1d Iustin Pop
  cleanup at shutdown.
66 ffeffa1d Iustin Pop
67 ffeffa1d Iustin Pop
  """
68 a478cd7e Guido Trotter
  QUEUE_PROCESSOR_SIZE = 5
69 ffeffa1d Iustin Pop
70 39dcf2ef Guido Trotter
  def __init__(self, address, rqhandler, context):
71 ce862cd5 Guido Trotter
    """IOServer constructor
72 ce862cd5 Guido Trotter
73 ce862cd5 Guido Trotter
    Args:
74 ce862cd5 Guido Trotter
      address: the address to bind this IOServer to
75 ce862cd5 Guido Trotter
      rqhandler: RequestHandler type object
76 39dcf2ef Guido Trotter
      context: Context Object common to all worker threads
77 ce862cd5 Guido Trotter
78 ce862cd5 Guido Trotter
    """
79 ffeffa1d Iustin Pop
    SocketServer.UnixStreamServer.__init__(self, address, rqhandler)
80 ffeffa1d Iustin Pop
    self.do_quit = False
81 ffeffa1d Iustin Pop
    self.queue = jqueue.QueueManager()
82 39dcf2ef Guido Trotter
    self.context = context
83 ffeffa1d Iustin Pop
    self.processors = []
84 c1f2901b Iustin Pop
    signal.signal(signal.SIGINT, self.handle_quit_signals)
85 c1f2901b Iustin Pop
    signal.signal(signal.SIGTERM, self.handle_quit_signals)
86 c1f2901b Iustin Pop
87 c1f2901b Iustin Pop
  def setup_processors(self):
88 c1f2901b Iustin Pop
    """Spawn the processors threads.
89 c1f2901b Iustin Pop
90 c1f2901b Iustin Pop
    This initializes the queue and the thread processors. It is done
91 c1f2901b Iustin Pop
    separately from the constructor because we want the clone()
92 c1f2901b Iustin Pop
    syscalls to happen after the daemonize part.
93 c1f2901b Iustin Pop
94 c1f2901b Iustin Pop
    """
95 ffeffa1d Iustin Pop
    for i in range(self.QUEUE_PROCESSOR_SIZE):
96 ffeffa1d Iustin Pop
      self.processors.append(threading.Thread(target=PoolWorker,
97 39dcf2ef Guido Trotter
                                              args=(i, self.queue.new_queue,
98 39dcf2ef Guido Trotter
                                                    self.context)))
99 ffeffa1d Iustin Pop
    for t in self.processors:
100 ffeffa1d Iustin Pop
      t.start()
101 ffeffa1d Iustin Pop
102 ffeffa1d Iustin Pop
  def process_request_thread(self, request, client_address):
103 ffeffa1d Iustin Pop
    """Process the request.
104 ffeffa1d Iustin Pop
105 ffeffa1d Iustin Pop
    This is copied from the code in ThreadingMixIn.
106 ffeffa1d Iustin Pop
107 ffeffa1d Iustin Pop
    """
108 ffeffa1d Iustin Pop
    try:
109 ffeffa1d Iustin Pop
      self.finish_request(request, client_address)
110 ffeffa1d Iustin Pop
      self.close_request(request)
111 ffeffa1d Iustin Pop
    except:
112 ffeffa1d Iustin Pop
      self.handle_error(request, client_address)
113 ffeffa1d Iustin Pop
      self.close_request(request)
114 ffeffa1d Iustin Pop
115 ffeffa1d Iustin Pop
  def process_request(self, request, client_address):
116 ffeffa1d Iustin Pop
    """Start a new thread to process the request.
117 ffeffa1d Iustin Pop
118 ffeffa1d Iustin Pop
    This is copied from the coode in ThreadingMixIn.
119 ffeffa1d Iustin Pop
120 ffeffa1d Iustin Pop
    """
121 ffeffa1d Iustin Pop
    t = threading.Thread(target=self.process_request_thread,
122 ffeffa1d Iustin Pop
                         args=(request, client_address))
123 ffeffa1d Iustin Pop
    t.start()
124 ffeffa1d Iustin Pop
125 c1f2901b Iustin Pop
  def handle_quit_signals(self, signum, frame):
126 ffeffa1d Iustin Pop
    print "received %s in %s" % (signum, frame)
127 ffeffa1d Iustin Pop
    self.do_quit = True
128 ffeffa1d Iustin Pop
129 ffeffa1d Iustin Pop
  def serve_forever(self):
130 ffeffa1d Iustin Pop
    """Handle one request at a time until told to quit."""
131 ffeffa1d Iustin Pop
    while not self.do_quit:
132 ffeffa1d Iustin Pop
      self.handle_request()
133 c1f2901b Iustin Pop
      print "served request, quit=%s" % (self.do_quit)
134 c1f2901b Iustin Pop
135 c1f2901b Iustin Pop
  def server_cleanup(self):
136 c1f2901b Iustin Pop
    """Cleanup the server.
137 c1f2901b Iustin Pop
138 c1f2901b Iustin Pop
    This involves shutting down the processor threads and the master
139 c1f2901b Iustin Pop
    socket.
140 c1f2901b Iustin Pop
141 c1f2901b Iustin Pop
    """
142 c1f2901b Iustin Pop
    self.server_close()
143 c1f2901b Iustin Pop
    utils.RemoveFile(constants.MASTER_SOCKET)
144 c1f2901b Iustin Pop
    for i in range(self.QUEUE_PROCESSOR_SIZE):
145 c1f2901b Iustin Pop
      self.queue.new_queue.put(None)
146 c1f2901b Iustin Pop
    for idx, t in enumerate(self.processors):
147 c1f2901b Iustin Pop
      print "waiting for processor thread %s..." % idx
148 c1f2901b Iustin Pop
      t.join()
149 c1f2901b Iustin Pop
    print "done threads"
150 ffeffa1d Iustin Pop
151 ffeffa1d Iustin Pop
152 ffeffa1d Iustin Pop
class ClientRqHandler(SocketServer.BaseRequestHandler):
153 ffeffa1d Iustin Pop
  """Client handler"""
154 ffeffa1d Iustin Pop
  EOM = '\3'
155 ffeffa1d Iustin Pop
  READ_SIZE = 4096
156 ffeffa1d Iustin Pop
157 ffeffa1d Iustin Pop
  def setup(self):
158 ffeffa1d Iustin Pop
    self._buffer = ""
159 ffeffa1d Iustin Pop
    self._msgs = collections.deque()
160 ffeffa1d Iustin Pop
    self._ops = ClientOps(self.server)
161 ffeffa1d Iustin Pop
162 ffeffa1d Iustin Pop
  def handle(self):
163 ffeffa1d Iustin Pop
    while True:
164 ffeffa1d Iustin Pop
      msg = self.read_message()
165 ffeffa1d Iustin Pop
      if msg is None:
166 ffeffa1d Iustin Pop
        print "client closed connection"
167 ffeffa1d Iustin Pop
        break
168 ffeffa1d Iustin Pop
      request = simplejson.loads(msg)
169 ffeffa1d Iustin Pop
      if not isinstance(request, dict):
170 ffeffa1d Iustin Pop
        print "wrong request received: %s" % msg
171 ffeffa1d Iustin Pop
        break
172 ffeffa1d Iustin Pop
      method = request.get('request', None)
173 ffeffa1d Iustin Pop
      data = request.get('data', None)
174 ffeffa1d Iustin Pop
      if method is None or data is None:
175 ffeffa1d Iustin Pop
        print "no method or data in request"
176 ffeffa1d Iustin Pop
        break
177 ffeffa1d Iustin Pop
      print "request:", method, data
178 ffeffa1d Iustin Pop
      result = self._ops.handle_request(method, data)
179 ffeffa1d Iustin Pop
      print "result:", result
180 ffeffa1d Iustin Pop
      self.send_message(simplejson.dumps({'success': True, 'result': result}))
181 ffeffa1d Iustin Pop
182 ffeffa1d Iustin Pop
  def read_message(self):
183 ffeffa1d Iustin Pop
    while not self._msgs:
184 ffeffa1d Iustin Pop
      data = self.request.recv(self.READ_SIZE)
185 ffeffa1d Iustin Pop
      if not data:
186 ffeffa1d Iustin Pop
        return None
187 ffeffa1d Iustin Pop
      new_msgs = (self._buffer + data).split(self.EOM)
188 ffeffa1d Iustin Pop
      self._buffer = new_msgs.pop()
189 ffeffa1d Iustin Pop
      self._msgs.extend(new_msgs)
190 ffeffa1d Iustin Pop
    return self._msgs.popleft()
191 ffeffa1d Iustin Pop
192 ffeffa1d Iustin Pop
  def send_message(self, msg):
193 ffeffa1d Iustin Pop
    #print "sending", msg
194 ffeffa1d Iustin Pop
    self.request.sendall(msg + self.EOM)
195 ffeffa1d Iustin Pop
196 ffeffa1d Iustin Pop
197 ffeffa1d Iustin Pop
class ClientOps:
198 ffeffa1d Iustin Pop
  """Class holding high-level client operations."""
199 ffeffa1d Iustin Pop
  def __init__(self, server):
200 ffeffa1d Iustin Pop
    self.server = server
201 ffeffa1d Iustin Pop
    self._cpu = None
202 ffeffa1d Iustin Pop
203 ffeffa1d Iustin Pop
  def _getcpu(self):
204 ffeffa1d Iustin Pop
    if self._cpu is None:
205 ffeffa1d Iustin Pop
      self._cpu = mcpu.Processor(lambda x: None)
206 ffeffa1d Iustin Pop
    return self._cpu
207 ffeffa1d Iustin Pop
208 ffeffa1d Iustin Pop
  def handle_request(self, operation, args):
209 ffeffa1d Iustin Pop
    print operation, args
210 ffeffa1d Iustin Pop
    if operation == "submit":
211 ffeffa1d Iustin Pop
      return self.put(args)
212 ffeffa1d Iustin Pop
    elif operation == "query":
213 7a1ecaed Iustin Pop
      return self.query(args)
214 ffeffa1d Iustin Pop
    else:
215 ffeffa1d Iustin Pop
      raise ValueError("Invalid operation")
216 ffeffa1d Iustin Pop
217 ffeffa1d Iustin Pop
  def put(self, args):
218 ffeffa1d Iustin Pop
    job = luxi.UnserializeJob(args)
219 ffeffa1d Iustin Pop
    rid = self.server.queue.put(job)
220 ffeffa1d Iustin Pop
    return rid
221 ffeffa1d Iustin Pop
222 ffeffa1d Iustin Pop
  def query(self, args):
223 ffeffa1d Iustin Pop
    path = args["object"]
224 ffeffa1d Iustin Pop
    fields = args["fields"]
225 ffeffa1d Iustin Pop
    names = args["names"]
226 ffeffa1d Iustin Pop
    if path == "instances":
227 ffeffa1d Iustin Pop
      opclass = opcodes.OpQueryInstances
228 7a1ecaed Iustin Pop
    elif path == "jobs":
229 7a1ecaed Iustin Pop
      # early exit because job query-ing is special (not via opcodes)
230 7a1ecaed Iustin Pop
      return self.query_jobs(fields, names)
231 ffeffa1d Iustin Pop
    else:
232 ffeffa1d Iustin Pop
      raise ValueError("Invalid object %s" % path)
233 ffeffa1d Iustin Pop
234 ffeffa1d Iustin Pop
    op = opclass(output_fields = fields, names=names)
235 ffeffa1d Iustin Pop
    cpu = self._getcpu()
236 ffeffa1d Iustin Pop
    result = cpu.ExecOpCode(op)
237 ffeffa1d Iustin Pop
    return result
238 ffeffa1d Iustin Pop
239 7a1ecaed Iustin Pop
  def query_jobs(self, fields, names):
240 7a1ecaed Iustin Pop
    return self.server.queue.query_jobs(fields, names)
241 ffeffa1d Iustin Pop
242 ffeffa1d Iustin Pop
243 39dcf2ef Guido Trotter
def JobRunner(proc, job, context):
244 ffeffa1d Iustin Pop
  """Job executor.
245 ffeffa1d Iustin Pop
246 ffeffa1d Iustin Pop
  This functions processes a single job in the context of given
247 ffeffa1d Iustin Pop
  processor instance.
248 ffeffa1d Iustin Pop
249 ce862cd5 Guido Trotter
  Args:
250 ce862cd5 Guido Trotter
    proc: Ganeti Processor to run the job on
251 ce862cd5 Guido Trotter
    job: The job to run (unserialized format)
252 39dcf2ef Guido Trotter
    context: Ganeti shared context
253 ce862cd5 Guido Trotter
254 ffeffa1d Iustin Pop
  """
255 ffeffa1d Iustin Pop
  job.SetStatus(opcodes.Job.STATUS_RUNNING)
256 35049ff2 Iustin Pop
  fail = False
257 35049ff2 Iustin Pop
  for idx, op in enumerate(job.data.op_list):
258 35049ff2 Iustin Pop
    job.data.op_status[idx] = opcodes.Job.STATUS_RUNNING
259 35049ff2 Iustin Pop
    try:
260 35049ff2 Iustin Pop
      job.data.op_result[idx] = proc.ExecOpCode(op)
261 35049ff2 Iustin Pop
      job.data.op_status[idx] = opcodes.Job.STATUS_SUCCESS
262 35049ff2 Iustin Pop
    except (errors.OpPrereqError, errors.OpExecError), err:
263 35049ff2 Iustin Pop
      fail = True
264 35049ff2 Iustin Pop
      job.data.op_result[idx] = str(err)
265 35049ff2 Iustin Pop
      job.data.op_status[idx] = opcodes.Job.STATUS_FAIL
266 35049ff2 Iustin Pop
  if fail:
267 35049ff2 Iustin Pop
    job.SetStatus(opcodes.Job.STATUS_FAIL)
268 35049ff2 Iustin Pop
  else:
269 35049ff2 Iustin Pop
    job.SetStatus(opcodes.Job.STATUS_SUCCESS)
270 ffeffa1d Iustin Pop
271 ffeffa1d Iustin Pop
272 39dcf2ef Guido Trotter
def PoolWorker(worker_id, incoming_queue, context):
273 ffeffa1d Iustin Pop
  """A worker thread function.
274 ffeffa1d Iustin Pop
275 ffeffa1d Iustin Pop
  This is the actual processor of a single thread of Job execution.
276 ffeffa1d Iustin Pop
277 ce862cd5 Guido Trotter
  Args:
278 ce862cd5 Guido Trotter
    worker_id: the unique id for this worker
279 ce862cd5 Guido Trotter
    incoming_queue: a queue to get jobs from
280 39dcf2ef Guido Trotter
    context: the common server context, containing all shared data and
281 39dcf2ef Guido Trotter
             synchronization structures.
282 ce862cd5 Guido Trotter
283 ffeffa1d Iustin Pop
  """
284 ffeffa1d Iustin Pop
  while True:
285 ffeffa1d Iustin Pop
    print "worker %s sleeping" % worker_id
286 ffeffa1d Iustin Pop
    item = incoming_queue.get(True)
287 ffeffa1d Iustin Pop
    if item is None:
288 ffeffa1d Iustin Pop
      break
289 ffeffa1d Iustin Pop
    print "worker %s processing job %s" % (worker_id, item.data.job_id)
290 685ee993 Iustin Pop
    #utils.Lock('cmd')
291 ffeffa1d Iustin Pop
    try:
292 1c901d13 Guido Trotter
      proc = mcpu.Processor(context, feedback=lambda x: None)
293 ffeffa1d Iustin Pop
      try:
294 39dcf2ef Guido Trotter
        JobRunner(proc, item, context)
295 ffeffa1d Iustin Pop
      except errors.GenericError, err:
296 ea6e6c2b Guido Trotter
        msg = "ganeti exception %s" % err
297 ea6e6c2b Guido Trotter
        item.SetStatus(opcodes.Job.STATUS_FAIL, result=[msg])
298 ea6e6c2b Guido Trotter
        print msg
299 0db7ac4d Guido Trotter
      except Exception, err:
300 0db7ac4d Guido Trotter
        msg = "unhandled exception %s" % err
301 0db7ac4d Guido Trotter
        item.SetStatus(opcodes.Job.STATUS_FAIL, result=[msg])
302 0db7ac4d Guido Trotter
        print msg
303 0db7ac4d Guido Trotter
      except:
304 0db7ac4d Guido Trotter
        msg = "unhandled unknown exception"
305 0db7ac4d Guido Trotter
        item.SetStatus(opcodes.Job.STATUS_FAIL, result=[msg])
306 0db7ac4d Guido Trotter
        print msg
307 0db7ac4d Guido Trotter
308 ffeffa1d Iustin Pop
    finally:
309 685ee993 Iustin Pop
      #utils.Unlock('cmd')
310 685ee993 Iustin Pop
      #utils.LockCleanup()
311 685ee993 Iustin Pop
      pass
312 ffeffa1d Iustin Pop
    print "worker %s finish job %s" % (worker_id, item.data.job_id)
313 ffeffa1d Iustin Pop
  print "worker %s exiting" % worker_id
314 ffeffa1d Iustin Pop
315 ffeffa1d Iustin Pop
316 39dcf2ef Guido Trotter
class GanetiContext(object):
317 39dcf2ef Guido Trotter
  """Context common to all ganeti threads.
318 39dcf2ef Guido Trotter
319 39dcf2ef Guido Trotter
  This class creates and holds common objects shared by all threads.
320 39dcf2ef Guido Trotter
321 39dcf2ef Guido Trotter
  """
322 39dcf2ef Guido Trotter
  _instance = None
323 39dcf2ef Guido Trotter
324 39dcf2ef Guido Trotter
  def __init__(self):
325 39dcf2ef Guido Trotter
    """Constructs a new GanetiContext object.
326 39dcf2ef Guido Trotter
327 39dcf2ef Guido Trotter
    There should be only a GanetiContext object at any time, so this
328 39dcf2ef Guido Trotter
    function raises an error if this is not the case.
329 39dcf2ef Guido Trotter
330 39dcf2ef Guido Trotter
    """
331 39dcf2ef Guido Trotter
    assert self.__class__._instance is None, "double GanetiContext instance"
332 39dcf2ef Guido Trotter
333 39dcf2ef Guido Trotter
    # Create a ConfigWriter...
334 39dcf2ef Guido Trotter
    self.cfg = config.ConfigWriter()
335 39dcf2ef Guido Trotter
    # And a GanetiLockingManager...
336 39dcf2ef Guido Trotter
    self.GLM = locking.GanetiLockManager(
337 39dcf2ef Guido Trotter
                self.cfg.GetNodeList(),
338 39dcf2ef Guido Trotter
                self.cfg.GetInstanceList())
339 39dcf2ef Guido Trotter
340 39dcf2ef Guido Trotter
    # setting this also locks the class against attribute modifications
341 39dcf2ef Guido Trotter
    self.__class__._instance = self
342 39dcf2ef Guido Trotter
343 39dcf2ef Guido Trotter
  def __setattr__(self, name, value):
344 39dcf2ef Guido Trotter
    """Setting GanetiContext attributes is forbidden after initialization.
345 39dcf2ef Guido Trotter
346 39dcf2ef Guido Trotter
    """
347 39dcf2ef Guido Trotter
    assert self.__class__._instance is None, "Attempt to modify Ganeti Context"
348 39dcf2ef Guido Trotter
    object.__setattr__(self, name, value)
349 39dcf2ef Guido Trotter
350 39dcf2ef Guido Trotter
351 c1f2901b Iustin Pop
def CheckMaster(debug):
352 c1f2901b Iustin Pop
  """Checks the node setup.
353 c1f2901b Iustin Pop
354 c1f2901b Iustin Pop
  If this is the master, the function will return. Otherwise it will
355 c1f2901b Iustin Pop
  exit with an exit code based on the node status.
356 c1f2901b Iustin Pop
357 c1f2901b Iustin Pop
  """
358 c1f2901b Iustin Pop
  try:
359 c1f2901b Iustin Pop
    ss = ssconf.SimpleStore()
360 c1f2901b Iustin Pop
    master_name = ss.GetMasterNode()
361 c1f2901b Iustin Pop
  except errors.ConfigurationError, err:
362 c1f2901b Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
363 c1f2901b Iustin Pop
    sys.exit(EXIT_NODESETUP_ERROR)
364 c1f2901b Iustin Pop
365 c1f2901b Iustin Pop
  try:
366 c1f2901b Iustin Pop
    myself = utils.HostInfo()
367 c1f2901b Iustin Pop
  except errors.ResolverError, err:
368 c1f2901b Iustin Pop
    sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0])
369 c1f2901b Iustin Pop
    sys.exit(EXIT_NODESETUP_ERROR)
370 c1f2901b Iustin Pop
371 c1f2901b Iustin Pop
  if myself.name != master_name:
372 c1f2901b Iustin Pop
    if debug:
373 c1f2901b Iustin Pop
      sys.stderr.write("Not master, exiting.\n")
374 c1f2901b Iustin Pop
    sys.exit(EXIT_NOTMASTER)
375 c1f2901b Iustin Pop
376 c1f2901b Iustin Pop
377 c1f2901b Iustin Pop
def ParseOptions():
378 c1f2901b Iustin Pop
  """Parse the command line options.
379 c1f2901b Iustin Pop
380 c1f2901b Iustin Pop
  Returns:
381 c1f2901b Iustin Pop
    (options, args) as from OptionParser.parse_args()
382 c1f2901b Iustin Pop
383 c1f2901b Iustin Pop
  """
384 c1f2901b Iustin Pop
  parser = OptionParser(description="Ganeti master daemon",
385 c1f2901b Iustin Pop
                        usage="%prog [-f] [-d]",
386 c1f2901b Iustin Pop
                        version="%%prog (ganeti) %s" %
387 c1f2901b Iustin Pop
                        constants.RELEASE_VERSION)
388 c1f2901b Iustin Pop
389 c1f2901b Iustin Pop
  parser.add_option("-f", "--foreground", dest="fork",
390 c1f2901b Iustin Pop
                    help="Don't detach from the current terminal",
391 c1f2901b Iustin Pop
                    default=True, action="store_false")
392 c1f2901b Iustin Pop
  parser.add_option("-d", "--debug", dest="debug",
393 c1f2901b Iustin Pop
                    help="Enable some debug messages",
394 c1f2901b Iustin Pop
                    default=False, action="store_true")
395 c1f2901b Iustin Pop
  options, args = parser.parse_args()
396 c1f2901b Iustin Pop
  return options, args
397 c1f2901b Iustin Pop
398 c1f2901b Iustin Pop
399 ffeffa1d Iustin Pop
def main():
400 ffeffa1d Iustin Pop
  """Main function"""
401 ffeffa1d Iustin Pop
402 c1f2901b Iustin Pop
  options, args = ParseOptions()
403 c1f2901b Iustin Pop
  utils.debug = options.debug
404 b74159ee Iustin Pop
  utils.no_fork = True
405 c1f2901b Iustin Pop
406 c1f2901b Iustin Pop
  CheckMaster(options.debug)
407 c1f2901b Iustin Pop
408 39dcf2ef Guido Trotter
  master = IOServer(constants.MASTER_SOCKET, ClientRqHandler, GanetiContext())
409 ffeffa1d Iustin Pop
410 c1f2901b Iustin Pop
  # become a daemon
411 c1f2901b Iustin Pop
  if options.fork:
412 c1f2901b Iustin Pop
    utils.Daemonize(logfile=constants.LOG_MASTERDAEMON,
413 c1f2901b Iustin Pop
                    noclose_fds=[master.fileno()])
414 c1f2901b Iustin Pop
415 c1f2901b Iustin Pop
  try:
416 a4af651e Iustin Pop
    utils.Lock('cmd', debug=options.debug)
417 a4af651e Iustin Pop
  except errors.LockError, err:
418 a4af651e Iustin Pop
    print >> sys.stderr, str(err)
419 c1f2901b Iustin Pop
    master.server_cleanup()
420 a4af651e Iustin Pop
    return
421 a4af651e Iustin Pop
422 a4af651e Iustin Pop
  try:
423 a4af651e Iustin Pop
    master.setup_processors()
424 a4af651e Iustin Pop
    try:
425 a4af651e Iustin Pop
      master.serve_forever()
426 a4af651e Iustin Pop
    finally:
427 a4af651e Iustin Pop
      master.server_cleanup()
428 a4af651e Iustin Pop
  finally:
429 a4af651e Iustin Pop
    utils.Unlock('cmd')
430 a4af651e Iustin Pop
    utils.LockCleanup()
431 a4af651e Iustin Pop
432 ffeffa1d Iustin Pop
433 ffeffa1d Iustin Pop
if __name__ == "__main__":
434 ffeffa1d Iustin Pop
  main()