PageRenderTime 103ms CodeModel.GetById 31ms RepoModel.GetById 7ms app.codeStats 0ms

/slapos/cli/configure_local/__init__.py

https://github.com/SlapOS/slapos.core
Python | 265 lines | 209 code | 21 blank | 35 comment | 4 complexity | a8a884f37e6d39a7208a3fbf1ad83c1e MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # Copyright (c) 2013 Vifib SARL and Contributors.
  5. # All Rights Reserved.
  6. #
  7. # WARNING: This program as such is intended to be used by professional
  8. # programmers who take the whole responsibility of assessing all potential
  9. # consequences resulting from its eventual inadequacies and bugs
  10. # End users who are looking for a ready-to-use solution with commercial
  11. # guarantees and support are strongly advised to contract a Free Software
  12. # Service Company
  13. #
  14. # This program is Free Software; you can redistribute it and/or
  15. # modify it under the terms of the GNU General Public License
  16. # as published by the Free Software Foundation; either version 3
  17. # of the License, or (at your option) any later version.
  18. #
  19. # This program is distributed in the hope that it will be useful,
  20. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. # GNU General Public License for more details.
  23. #
  24. # You should have received a copy of the GNU General Public License
  25. # along with this program; if not, write to the Free Software
  26. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27. #
  28. ##############################################################################
  29. import os
  30. import pkg_resources
  31. import re
  32. import subprocess
  33. import sys
  34. from slapos.cli.command import must_be_root
  35. from slapos.format import FormatConfig
  36. from slapos.cli.config import ConfigCommand
  37. from slapos.grid.slapgrid import create_slapgrid_object
  38. from slapos.grid.utils import updateFile, createPrivateDirectory
  39. from slapos.grid.svcbackend import launchSupervisord
  40. from slapos.util import bytes2str
  41. DEFAULT_COMPUTER_ID = 'local_computer'
  42. class ConfigureLocalCommand(ConfigCommand):
  43. """
  44. Configure a slapos node, from scratch to ready-to-use, using slapproxy.
  45. """
  46. def get_parser(self, prog_name):
  47. ap = super(self.__class__, self).get_parser(prog_name)
  48. ap.add_argument('--interface-name',
  49. default='lo',
  50. help='Primary network interface. IP of Partitions '
  51. 'will be added to it'
  52. ' (default: %(default)s)')
  53. ap.add_argument('--partition-number',
  54. default=20,
  55. type=int,
  56. help='Number of partitions to create in the SlapOS Node'
  57. ' (default: %(default)s)')
  58. ap.add_argument('--ipv4-local-network',
  59. default='10.0.0.0/16',
  60. help='Subnetwork used to assign local IPv4 addresses. '
  61. 'It should be a not used network in order to'
  62. ' avoid conflicts (default: %(default)s)')
  63. ap.add_argument('--daemon-listen-ip',
  64. default='127.0.0.1',
  65. help='Listening IP of the "slapproxy" daemon'
  66. ' (default: %(default)s)')
  67. ap.add_argument('--daemon-listen-port',
  68. default='8080',
  69. help='Listening port of the "slapproxy" daemon'
  70. ' (default: %(default)s)')
  71. ap.add_argument('--slapos-instance-root',
  72. default='/srv/slapgrid',
  73. help='Target location of the SlapOS configuration'
  74. ' directory (default: %(default)s)')
  75. ap.add_argument('--slapos-software-root',
  76. default='/opt/slapgrid',
  77. help='Target location of the SlapOS configuration'
  78. ' directory (default: %(default)s)')
  79. ap.add_argument('--slapos-buildout-directory',
  80. default='/opt/slapos',
  81. help='Target location of the SlapOS configuration'
  82. ' directory (default: %(default)s)')
  83. ap.add_argument('--slapos-configuration-directory',
  84. default='/etc/opt/slapos',
  85. help='Target location of the SlapOS configuration'
  86. ' directory (default: %(default)s)')
  87. return ap
  88. @must_be_root
  89. def take_action(self, args):
  90. try:
  91. return_code = do_configure(args, self.fetch_config, self.app.log)
  92. except SystemExit as err:
  93. return_code = err
  94. sys.exit(return_code)
  95. def _createConfigurationDirectory(target_directory):
  96. target_directory = os.path.normpath(target_directory)
  97. if not os.path.exists(target_directory):
  98. os.makedirs(target_directory)
  99. def _replaceParameterValue(original_content, to_replace):
  100. """
  101. Replace in a .ini-like file the value of all parameters specified in
  102. to_replace by their value.
  103. """
  104. for key, value in to_replace:
  105. original_content = re.sub('%s\s+=.*' % key, '%s = %s' % (key, value),
  106. original_content)
  107. return original_content
  108. def _generateSlaposNodeConfigurationFile(slapos_node_config_path, args):
  109. template_arg_list = (__name__, '../../slapos.cfg.example')
  110. slapos_node_configuration_template = \
  111. bytes2str(pkg_resources.resource_string(*template_arg_list))
  112. master_url = 'http://%s:%s' % (args.daemon_listen_ip, args.daemon_listen_port)
  113. slapos_home = args.slapos_buildout_directory
  114. to_replace = [
  115. ('computer_id', DEFAULT_COMPUTER_ID),
  116. ('master_url', master_url),
  117. ('interface_name', args.interface_name),
  118. ('ipv4_local_network', args.ipv4_local_network),
  119. ('partition_amount', args.partition_number),
  120. ('instance_root', args.slapos_instance_root),
  121. ('software_root', args.slapos_software_root),
  122. ('computer_xml', '%s/slapos.xml' % slapos_home),
  123. ('log_file', '%s/log/slapos-node-format.log' % slapos_home)
  124. ]
  125. slapos_node_configuration_content = _replaceParameterValue(
  126. slapos_node_configuration_template, to_replace)
  127. slapos_node_configuration_content = re.sub(
  128. '(key_file|cert_file|certificate_repository_path).*=.*\n',
  129. '', slapos_node_configuration_content)
  130. with open(slapos_node_config_path, 'w') as fout:
  131. fout.write(slapos_node_configuration_content)
  132. def _generateSlaposProxyConfigurationFile(conf):
  133. template_arg_list = (__name__, '../../slapos-proxy.cfg.example')
  134. slapos_proxy_configuration_template = \
  135. bytes2str(pkg_resources.resource_string(*template_arg_list))
  136. slapos_proxy_configuration_path = os.path.join(
  137. conf.slapos_configuration_directory, 'slapos-proxy.cfg')
  138. listening_ip, listening_port = \
  139. conf.daemon_listen_ip, conf.daemon_listen_port
  140. to_replace = [
  141. ('host', listening_ip),
  142. ('port', listening_port),
  143. ('master_url', 'http://%s:%s/' % (listening_ip, listening_port)),
  144. ('computer_id', DEFAULT_COMPUTER_ID),
  145. ('instance_root', conf.instance_root),
  146. ('software_root', conf.software_root)
  147. ]
  148. slapos_proxy_configuration_content = _replaceParameterValue(
  149. slapos_proxy_configuration_template, to_replace)
  150. with open(slapos_proxy_configuration_path, 'w') as fout:
  151. fout.write(slapos_proxy_configuration_content)
  152. return slapos_proxy_configuration_path
  153. def _addProxyToSupervisor(conf):
  154. """
  155. Create a supervisord configuration file containing informations to run
  156. slapproxy as daemon
  157. """
  158. program_partition_template = """\
  159. [program:slapproxy]
  160. directory=%(slapos_buildout_directory)s
  161. command=%(program_command)s
  162. process_name=slapproxy
  163. autostart=true
  164. autorestart=true
  165. startsecs=0
  166. startretries=0
  167. exitcodes=0
  168. stopsignal=TERM
  169. stopwaitsecs=60
  170. user=0
  171. group=0
  172. serverurl=AUTO
  173. redirect_stderr=true
  174. stdout_logfile=%(log_file)s
  175. stdout_logfile_maxbytes=100KB
  176. stdout_logfile_backups=1
  177. stderr_logfile=%(log_file)s
  178. stderr_logfile_maxbytes=100KB
  179. stderr_logfile_backups=1
  180. """ % {'log_file': '%s/log/slapos-proxy.log' % conf.slapos_buildout_directory,
  181. 'slapos_buildout_directory': conf.slapos_buildout_directory,
  182. 'program_command': '%s/bin/slapos proxy start --cfg %s' % \
  183. (conf.slapos_buildout_directory, conf.proxy_configuration_file)}
  184. supervisord_conf_folder_path = os.path.join(conf.instance_root,
  185. 'etc', 'supervisord.conf.d')
  186. _createConfigurationDirectory(supervisord_conf_folder_path)
  187. updateFile(
  188. os.path.join(supervisord_conf_folder_path, 'slapproxy.conf'),
  189. program_partition_template)
  190. def _runFormat(slapos_directory):
  191. """
  192. Launch slapos node format.
  193. """
  194. subprocess.Popen(
  195. ["%s/bin/slapos" % slapos_directory,
  196. "node", "format", "--now"]).communicate()
  197. def do_configure(args, fetch_config_func, logger):
  198. """
  199. Generate configuration files,
  200. Create the instance path by running slapformat (but will crash),
  201. Add proxy to supervisor,
  202. Run supervisor, which will run the proxy,
  203. Run format, which will finish correctly.
  204. """
  205. slapos_node_config_path = os.path.join(
  206. args.slapos_configuration_directory, 'slapos.cfg')
  207. if os.path.exists(slapos_node_config_path):
  208. logger.error('A SlapOS configuration directory already exist at'
  209. ' %s. Aborting.' % slapos_node_config_path)
  210. raise SystemExit(1)
  211. if not getattr(args, 'cfg', None):
  212. args.cfg = slapos_node_config_path
  213. _createConfigurationDirectory(args.slapos_configuration_directory)
  214. _generateSlaposNodeConfigurationFile(slapos_node_config_path, args)
  215. configp = fetch_config_func(args)
  216. conf = FormatConfig(logger=logger)
  217. conf.mergeConfig(args, configp)
  218. # The First thing we have to do here is to generate slapproxy conf
  219. # for supervisord, then supervisord certainly start slapproxy.
  220. proxy_configuration_file = _generateSlaposProxyConfigurationFile(conf)
  221. conf.proxy_configuration_file = proxy_configuration_file
  222. _addProxyToSupervisor(conf)
  223. # Do the rest
  224. slapgrid = create_slapgrid_object(conf.__dict__, logger)
  225. createPrivateDirectory(os.path.join(conf.slapos_buildout_directory, 'log'))
  226. _runFormat(conf.slapos_buildout_directory)
  227. slapgrid.checkEnvironmentAndCreateStructure()
  228. home_folder_path = os.environ['HOME']
  229. createPrivateDirectory("%s/.slapos" % home_folder_path)
  230. slapos_client_cfg_path = '%s/.slapos/slapos-client.cfg' % home_folder_path
  231. if not os.path.exists(slapos_client_cfg_path):
  232. os.symlink(slapos_node_config_path, slapos_client_cfg_path)
  233. launchSupervisord(instance_root=conf.instance_root, logger=logger)
  234. _runFormat(conf.slapos_buildout_directory)
  235. return 0