neoppod.py 4.72 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
##############################################################################
#
# Copyright (c) 2012-2013 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################
27
import os
28
import shlex
29
from zc.buildout import UserError
30 31 32 33 34
from .librecipe import GenericBaseRecipe

class Cluster(object):

  def __init__(self, buildout, name, options):
35
    masters = options.setdefault('masters', '')
36 37 38 39 40
    result_dict = {
      'connection-admin': [],
      'connection-master': [],
    }
    node_list = []
41 42
    for node in sorted(options['nodes'].split()):
      node = buildout[node]
43 44 45 46 47
      node_list.append(node)
      for k, v in result_dict.iteritems():
        x = node[k]
        if x:
          v.append(x)
48
    options['admins'] = ' '.join(result_dict.pop('connection-admin'))
49 50
    x = ' '.join(result_dict.pop('connection-master'))
    if masters != x:
51
      options['masters'] = x
52 53
      for node in node_list:
        node['config-masters'] = x
54
        node.recipe.__init__(buildout, node.name, node)
55 56

  install = update = lambda self: None
57 58 59 60 61 62 63 64 65 66 67 68 69 70

class NeoBaseRecipe(GenericBaseRecipe):

  _binding_port_mandatory = True

  def install(self):
    options = self.options
    if not options['masters']:
      # All parameters are always provided.
      # This parameter needs special care, because it is initially generated
      # empty, until all requested master nodes get their partitions
      # allocated.
      # Only then can this recipe start succeeding and actually doing anything
      # useful, as per NEO deploying constraints.
71
      raise UserError('"masters" parameter is mandatory')
72 73
    args = [
      options['binary'],
74
      # Keep the -l option first, as expected by logrotate snippets.
75 76 77 78 79 80 81
      '-l', options['logfile'],
      '-m', options['masters'],
      '-b', self._getBindingAddress(),
      # TODO: reuse partition reference for better log readability.
      #'-n', options['name'],
      '-c', options['cluster'],
    ]
82
    if options['ssl']:
83
      etc = os.path.join(self.buildout['buildout']['directory'], 'etc', '')
84
      args += (
85 86 87
        '--ca', etc + 'ca.crt',
        '--cert', etc + 'neo.crt',
        '--key', etc + 'neo.key',
88
        )
89
    args += self._getOptionList()
90
    args += shlex.split(options.get('extra-options', ''))
91
    return self.createWrapper(options['wrapper'], args)
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

  def _getBindingAddress(self):
    options = self.options
    bind = options['ip']
    if 'port' in options:
      # Some node types support port auto-allocation when no binding port is
      # requested.
      bind = bind + ':' + options['port']
    elif self._binding_port_mandatory:
      raise ValueError('"port" option is mandatory.')
    return bind

  def _getOptionList(self):
    raise NotImplementedError

class Storage(NeoBaseRecipe):

  _binding_port_mandatory = False

  def _getOptionList(self):
112
    r = [
113 114 115 116
      '-d', self.options['database-parameters'],
      '-a', self.options['database-adapter'],
      '-w', self.options['wait-database'],
    ]
117 118 119
    engine = self.options.get('engine')
    if engine: # old versions of NEO don't support -e
      r  += '-e', engine
120 121
    if self.options.get('dedup'):
      r.append('--dedup')
122 123
    if self.options.get('disable-drop-partitions'):
      r.append('--disable-drop-partitions')
124
    return r
125 126 127 128 129 130 131 132

class Admin(NeoBaseRecipe):
  def _getOptionList(self):
    return []

class Master(NeoBaseRecipe):
  def _getOptionList(self):
    options = self.options
133
    r = [
134 135
      '-p', options['partitions'],
      '-r', options['replicas'],
136
      '-A', options['autostart'],
137
    ]
138 139 140 141 142
    for x in (('-C', options['upstream-cluster']),
              ('-M', options['upstream-masters'])):
      if x[1]:
        r += x
    return r