configure_environment.rb 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env ruby
  2. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  3. require 'yaml'
  4. require 'resolv'
  5. require 'fileutils'
  6. #
  7. # Configures the CI system
  8. # - either (randomly) mysql or postgresql, if it is available
  9. # - (randomly) Redis or File as web socket session back end, if Redis is available
  10. #
  11. # Database config happens directly in config/database.yml, other settings are written to
  12. # .gitlab/environment.env which must be sourced in the CI configuration.
  13. #
  14. class ConfigureEnvironment
  15. @env_file_content = <<~ENV_FILE_CONTENT
  16. #!/bin/bash
  17. FRESHENVFILE=fresh.env && test -f $FRESHENVFILE && source $FRESHENVFILE
  18. true
  19. ENV_FILE_CONTENT
  20. def self.configure_database # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
  21. if File.exist? File.join(__dir__, '../config/database.yml')
  22. puts "'config/database.yml' already exists and will not be changed."
  23. return
  24. end
  25. cnf = YAML.load_file(File.join(__dir__, '../config/database/database.yml'))
  26. cnf.delete('default')
  27. database = ENV['ENFORCE_DB_SERVICE']
  28. # Lookup in /etc/hosts first: gitlab uses that if FF_NETWORK_PER_BUILD is not set.
  29. if !database
  30. hostsfile = '/etc/hosts'
  31. database = %w[postgresql mysql].shuffle.find do |possible_database|
  32. File.foreach(hostsfile).any? { |l| l[possible_database] }
  33. end
  34. end
  35. # Lookup via DNS if needed: gitlab uses that if FF_NETWORK_PER_BUILD is enabled.
  36. if !database
  37. dns = Resolv::DNS.new
  38. dns.timeouts = 3
  39. database = %w[postgresql mysql].shuffle.find do |possible_database|
  40. # Perform a lookup of the database host to check if it is configured as a service.
  41. if dns.getaddress possible_database
  42. next possible_database
  43. end
  44. rescue Resolv::ResolvError
  45. # Ignore DNS lookup errors
  46. end
  47. end
  48. raise "Can't find any supported database." if database.nil?
  49. puts "Using #{database} as database service."
  50. db_settings_map = {
  51. 'postgresql' => {
  52. 'adapter' => 'postgresql',
  53. 'username' => 'zammad',
  54. 'password' => 'zammad',
  55. 'host' => 'postgresql', # db alias from gitlab-ci.yml
  56. },
  57. 'mysql' => {
  58. 'adapter' => 'mysql2',
  59. 'username' => 'root',
  60. 'password' => 'zammad',
  61. 'host' => 'mysql', # db alias from gitlab-ci.yml
  62. }
  63. }
  64. # fetch DB settings from settings map and fallback to postgresql
  65. db_settings = db_settings_map.fetch(database) { db_settings_map['postgresql'] }
  66. %w[development test production].each do |environment|
  67. cnf[environment].merge!(db_settings)
  68. end
  69. File.write(File.join(__dir__, '../config/database.yml'), Psych.dump(cnf))
  70. end
  71. def self.configure_redis
  72. if ENV['REDIS_URL'].nil? || ENV['REDIS_URL'].empty? # rubocop:disable Rails/Blank
  73. if database_type == 'mysql'
  74. raise 'Redis was not found, but is required for ActionCable on MySQL based systems.'
  75. end
  76. puts 'Redis is not available, using File as web socket session store.'
  77. puts 'Redis is not available, using the PostgreSQL adapter for ActionCable.'
  78. return
  79. end
  80. if database_type == 'mysql' || [true, false].sample
  81. puts 'Using Redis as web socket session store.'
  82. puts 'Using the Redis adapter for ActionCable.'
  83. return
  84. end
  85. puts 'Using File as web socket session store.'
  86. puts 'Using the PostgreSQL adapter for ActionCable.'
  87. @env_file_content += "unset REDIS_URL\n"
  88. end
  89. def self.configure_memcached
  90. if ENV['MEMCACHE_SERVERS'].nil? || ENV['MEMCACHE_SERVERS'].empty? # rubocop:disable Rails/Blank
  91. puts 'Memcached is not available, using File as Rails cache store.'
  92. return
  93. end
  94. if [true, false].sample
  95. puts 'Using memcached as Rails cache store.'
  96. return
  97. end
  98. puts "Using Zammad's file store as Rails cache store."
  99. @env_file_content += "unset MEMCACHE_SERVERS\n"
  100. end
  101. # Since configure_database skips if database.yml already exists, check the
  102. # content of that file to reliably determine the database type in all cases.
  103. def self.database_type
  104. database = File.read(File.join(__dir__, '../config/database.yml')).match(%r{^\s*adapter:\s*(mysql|postgresql)})[1]
  105. if !database
  106. raise 'Could not determine database type, cannot setup cable.yml'
  107. end
  108. database
  109. end
  110. def self.write_env_file
  111. File.write(File.join(__dir__, 'environment.env'), @env_file_content)
  112. end
  113. def self.run
  114. configure_database
  115. configure_redis
  116. configure_memcached
  117. write_env_file
  118. end
  119. end
  120. ConfigureEnvironment.run