class EtFullSystem::LocalCommand

Constants

DEFAULT_BASE_URL
GEM_PATH
LOCK_FILE
PROJECT_PATH

Public Instance Methods

boot() click to toggle source
# File lib/et_full_system/cli/local.rb, line 20
def boot
  STDERR.puts "boot - base_url is #{options[:base_url]}"
  json_setup_file = File.absolute_path('../../../foreman/traefik.json', __dir__)
  connect_retry_countdown = 10
  begin
    resp = HTTParty.put "#{options[:base_url]}/api/providers/rest", body: File.read(json_setup_file) , headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}
    raise "Error from traefik when performing initial config says: #{resp.body}" unless (200..299).include? resp.code
    sleep 1
  rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED
    connect_retry_countdown -= 1
    if connect_retry_countdown.zero?
      raise "Could not connect to the traefik API after 10 retries (boot)"
    else
      STDERR.puts "boot - Retrying connection to traefik API in 5 seconds"
      sleep 5
      retry
    end
  end
end
disable_admin() click to toggle source
# File lib/et_full_system/cli/local.rb, line 260
def disable_admin
  invoker 'remove', 'admin_web'
  puts "Admin is now stopped"
end
disable_api() click to toggle source
# File lib/et_full_system/cli/local.rb, line 253
def disable_api
  invoker 'remove', 'api_web'
  invoker 'remove', 'api_sidekiq'
  puts "api is now stopped"
end
disable_atos_api() click to toggle source
# File lib/et_full_system/cli/local.rb, line 247
def disable_atos_api
  invoker 'remove', 'atos_api_web'
  puts "atos_api is now stopped"
end
disable_ccd_export() click to toggle source
# File lib/et_full_system/cli/local.rb, line 241
def disable_ccd_export
  invoker 'remove', 'et_ccd_export_sidekiq'
  puts "ccd_export is now stopped"
end
disable_et1() click to toggle source
# File lib/et_full_system/cli/local.rb, line 234
def disable_et1
  invoker 'remove', 'et1_web'
  invoker 'remove', 'et1_sidekiq'
  puts "ET1 is now stopped"
end
disable_et3() click to toggle source
# File lib/et_full_system/cli/local.rb, line 266
def disable_et3
  invoker 'remove', 'et3_web'
  puts "ET3 is now stopped"
end
enable_admin() click to toggle source
# File lib/et_full_system/cli/local.rb, line 222
def enable_admin
  invoker 'add', 'admin_web'
  puts "Admin is now running"
end
enable_api() click to toggle source
# File lib/et_full_system/cli/local.rb, line 215
def enable_api
  invoker 'add', 'api_web'
  invoker 'add', 'api_sidekiq'
  puts "api is now running"
end
enable_atos_api() click to toggle source
# File lib/et_full_system/cli/local.rb, line 209
def enable_atos_api
  invoker 'add', 'atos_api_web'
  puts "atos_api is now running"
end
enable_ccd_export() click to toggle source
# File lib/et_full_system/cli/local.rb, line 203
def enable_ccd_export
  invoker 'add', 'et_ccd_export_sidekiq'
  puts "ccd_export is now running"
end
enable_et1() click to toggle source
# File lib/et_full_system/cli/local.rb, line 196
def enable_et1
  invoker 'add', 'et1_web'
  invoker 'add', 'et1_sidekiq'
  puts "ET1 is now running"
end
enable_et3() click to toggle source
# File lib/et_full_system/cli/local.rb, line 228
def enable_et3
  invoker 'add', 'et3_web'
  puts "ET3 is now running"
end
invoker(*args) click to toggle source
# File lib/et_full_system/cli/local.rb, line 187
def invoker(*args)
  cmd = "invoker #{args.join(' ')}"
  puts cmd
  result = `#{cmd}`
  puts result
  result
end
restart_admin() click to toggle source
# File lib/et_full_system/cli/local.rb, line 292
def restart_admin
  invoker 'reload', 'admin_web'
  puts "admin Has been restarted"
end
restart_api() click to toggle source
# File lib/et_full_system/cli/local.rb, line 279
def restart_api
  invoker 'reload', 'api_web'
  invoker 'reload', 'api_sidekiq'
  puts "api Has been restarted"
end
restart_atos_api() click to toggle source
# File lib/et_full_system/cli/local.rb, line 298
def restart_atos_api
  invoker 'reload', 'atos_api_web'
  puts "atos_api Has been restarted"
end
restart_ccd_export() click to toggle source
# File lib/et_full_system/cli/local.rb, line 304
def restart_ccd_export
  invoker 'reload', 'et_ccd_export_sidekiq'
  puts "ccd_export Has been restarted"
end
restart_et1() click to toggle source
# File lib/et_full_system/cli/local.rb, line 272
def restart_et1
  invoker 'reload', 'et1_web'
  invoker 'reload', 'et1_sidekiq'
  puts "ET1 Has been restarted"
end
restart_et3() click to toggle source
# File lib/et_full_system/cli/local.rb, line 286
def restart_et3
  invoker 'reload', 'et3_web'
  puts "et3 Has been restarted"
end
server() click to toggle source
# File lib/et_full_system/cli/local.rb, line 88
def server
  puts "Scheduling traefik config and file storage config"
  pid = fork do
    self.class.start(['boot'])
    EtFullSystem::Cli::Local::FileStorageCommand.start(['setup'])
  end
  Process.detach(pid)

  puts "Starting Invoker"
  unbundled do
    without = options[:without]
    if options.minimal?
      without = ['et1', 'et3', 'admin', 'api', 'ccd_export', 'atos_api']
    end
    cmd = "CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} AZURITE_STORAGE_PATH=\"#{options[:azurite_storage_path]}\" MINIO_STORAGE_PATH=\"#{options[:minio_storage_path]}\" FS_ROOT_PATH=#{PROJECT_PATH} FOREMAN_PATH=#{GEM_PATH}/foreman godotenv -f #{GEM_PATH}/foreman/.env invoker start \"#{GEM_PATH}/foreman/Procfile\" --port=4000"
    STDERR.puts cmd
    unless without.empty?
      stop_cmds = without.reduce([]) do |acc, service|
        acc.concat(invoker_processes_for(service))
      end.map do |proc|
        "invoker remove #{proc}"
      end
      stop_cmd = stop_cmds.join(' && ')
      puts "---------------------- DISABLING SERVICES IN 30 SECONDS ---------------------------"
      puts "command is #{stop_cmd}"
      Process.fork do
        sleep 30
        puts `#{stop_cmd}`
      end
    end
    exec cmd
  end
end
service_env(service) click to toggle source
# File lib/et_full_system/cli/local.rb, line 168
def service_env(service)
  lookup = {
    'atos_api' => :et_atos,
    'admin' => :et_admin,
    'api' => :et_api,
    'et1' => :et1,
    'et3' => :et3,
    'et_ccd_export' => :et_ccd_export
  }
  file = lookup.fetch(service)
  parsed = Dotenv.parse("#{GEM_PATH}/foreman/.env", "#{GEM_PATH}/foreman/#{file}.env")
  parsed.each_pair do |name, value|
    puts "#{name}=#{value}"
  end
rescue KeyError
  puts "The service must be one of #{lookup.keys}"
end
setup() click to toggle source
# File lib/et_full_system/cli/local.rb, line 128
def setup
  setup_depencencies
  setup_ruby_versions
  setup_services
end
setup_depencencies() click to toggle source
# File lib/et_full_system/cli/local.rb, line 147
def setup_depencencies
  cmd = "bash --login -c \"cd /tmp && git clone https://github.com/ministryofjustice/et_fake_acas_server.git && cd et_fake_acas_server && gem build -o et_fake_acas_server.gem et_fake_acas_server && gem install et_fake_acas_server.gem && cd .. && rm -rf et_fake_acas_server\""
  STDERR.puts cmd
  external_command cmd, 'setup_dependencies'
end
setup_ruby_versions() click to toggle source
# File lib/et_full_system/cli/local.rb, line 154
def setup_ruby_versions
  versions = Dir.glob(File.join(PROJECT_PATH, 'systems', '*', '.ruby-version')).map do |version_file|
    File.read(version_file).split("\n").first.gsub(/\Aruby-/, '')
  end.uniq - [RUBY_VERSION]

  versions.each do |version|
    puts "------------------------------------------------ SETTING UP ruby #{version} ---------------------------------------------------"
    cmd = "bash --login -c \"rvm install #{version}\""
    puts cmd
    external_command cmd, "ruby #{version} install"
  end
end
setup_services() click to toggle source
# File lib/et_full_system/cli/local.rb, line 135
def setup_services
  unbundled do
    setup_et1_service
    setup_et3_service
    setup_api_service
    setup_admin_service
    setup_atos_service
    setup_ccd_service
  end
end
update_service_url(service, url) click to toggle source
# File lib/et_full_system/cli/local.rb, line 43
def update_service_url(service, url)
  within_rest_lock do
    update_rest_backend_url(service, url)
  end
end
wait_for_support() click to toggle source
# File lib/et_full_system/cli/local.rb, line 51
def wait_for_support
  connect_retry_countdown = 10
  setup_retry_countdown = 10

  begin
    resp = HTTParty.get "#{options[:base_url]}/api/providers/rest", headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}
    raise RestProviderNotConfigured if resp.code == 404
  rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED
    connect_retry_countdown -= 1
    if connect_retry_countdown.zero?
      raise "Could not connect to the traefik API after 10 retries (wait_for_support)"
    else
      STDERR.puts "wait_for_support - Retrying connection to traefik API in 5 seconds"
      sleep 5
      retry
    end
  rescue RestProviderNotConfigured
    setup_retry_countdown -= 1
    if setup_retry_countdown.zero?
      raise "Could not find the REST provider in traefik after 10 retries"
    else
      STDERR.puts "Re checking for the REST provider in traefik in 5 seconds"
      sleep 5
      retry
    end
  end
  STDERR.puts "Support services now ready"
end

Private Instance Methods

external_command(cmd, tag) click to toggle source
# File lib/et_full_system/cli/local.rb, line 335
def external_command(cmd, tag)
  IO.popen(cmd) do |io|
    io.each do |line|
      puts "| #{tag} | #{line}"
    end
  end
end
invoker_processes_for(service) click to toggle source
# File lib/et_full_system/cli/local.rb, line 316
def invoker_processes_for(service)
  case service
  when 'et1' then ['et1_web', 'et1_sidekiq']
  when 'et3' then ['et3_web']
  when 'api' then ['api_web', 'api_sidekiq']
  when 'admin' then ['admin_web']
  when 'atos_api' then ['atos_api_web']
  when 'ccd_export' then ['et_ccd_export_sidekiq']
  else raise "Unknown service #{service}"
  end
end
procfile_services() click to toggle source
# File lib/et_full_system/cli/local.rb, line 328
def procfile_services
  File.readlines("#{GEM_PATH}/foreman/Procfile").inject([]) do |acc, line|
    next if line.strip.start_with?('#')
    acc + [line.split(':').first]
  end
end
setup_admin_service() click to toggle source
# File lib/et_full_system/cli/local.rb, line 369
def setup_admin_service
  puts "------------------------------------------------ SETTING UP ADMIN SERVICE ---------------------------------------------------"
  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/admin && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et_admin.env\" gem install bundler:1.17.3 && bundle install --with=#{options[:rails_env]}\""
  puts cmd
  external_command cmd, 'admin setup'

  puts "|   Admin    | Running rake commands"
  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/admin && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et_admin.env\" bundle exec rake db:seed assets:precompile\""
  puts cmd
  external_command cmd, 'admin setup'
end
setup_api_service() click to toggle source
# File lib/et_full_system/cli/local.rb, line 381
def setup_api_service
  puts "------------------------------------------------ SETTING UP API SERVICE ---------------------------------------------------"
  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/api && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et_api.env\" gem install bundler:1.17.3 && bundle install --with=#{options[:rails_env]}\""
  puts cmd
  external_command cmd, 'api setup'

  puts "|   API      | Running rake commands"
  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/api && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et_api.env\" bundle exec rake db:create db:migrate db:seed\""
  puts cmd
  external_command cmd, 'api setup'
end
setup_atos_service() click to toggle source
# File lib/et_full_system/cli/local.rb, line 393
def setup_atos_service
  puts "------------------------------------------------ SETTING UP ATOS SERVICE ---------------------------------------------------"
  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/atos && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et_atos.env\" gem install bundler:1.17.3 && bundle install --with=#{options[:rails_env]}\""
  puts cmd
  external_command cmd, 'atos setup'
end
setup_ccd_service() click to toggle source
# File lib/et_full_system/cli/local.rb, line 400
def setup_ccd_service
  puts "------------------------------------------------ SETTING UP CCD EXPORT SERVICE ---------------------------------------------------"
  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/et_ccd_export && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et_ccd_export.env\" gem install bundler:1.17.3 && bundle install --with=#{options[:rails_env]}\""
  puts cmd
  external_command cmd, 'ccd setup'
end
setup_et1_service() click to toggle source
# File lib/et_full_system/cli/local.rb, line 343
def setup_et1_service
  puts "------------------------------------------------ SETTING UP ET1 SERVICE ---------------------------------------------------"
  cmd = "bash --login -c \"cd #{PROJECT_PATH}/systems/et1 && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et1.env\" gem install bundler:1.17.3 && bundle install --with=#{options[:rails_env]}\""
  puts cmd
  external_command cmd, 'et1 setup'

  cmd = "bash --login -c \"cd #{PROJECT_PATH}/systems/et1 && npm install\""
  puts cmd
  external_command cmd, 'et1 setup'

  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/et1 && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et1.env\" bundle exec rake db:create db:migrate assets:precompile\""
  puts cmd
  external_command cmd, 'et1 setup'
end
setup_et3_service() click to toggle source
# File lib/et_full_system/cli/local.rb, line 358
def setup_et3_service
  puts "------------------------------------------------ SETTING UP ET3 SERVICE ---------------------------------------------------"
  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/et3 && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et3.env\" gem install bundler:1.17.3 && bundle install --with=#{options[:rails_env]}\""
  puts cmd
  external_command cmd, 'et3 setup'

  cmd ="bash --login -c \"cd #{PROJECT_PATH}/systems/et3 && CLOUD_PROVIDER=#{options[:cloud_provider]} RAILS_ENV=#{options[:rails_env]} godotenv -f \"#{GEM_PATH}/foreman/.env\" godotenv -f \"#{GEM_PATH}/foreman/et3.env\" bundle exec rake db:create db:migrate assets:precompile\""
  puts cmd
  external_command cmd, 'et3 setup'
end
summarise_json(json) click to toggle source
# File lib/et_full_system/cli/local.rb, line 479
def summarise_json(json)
  json['backends'].inject({}) do |acc, (service, value)|
    acc[service] = value.dig('servers', 'web', 'url')
    acc
  end
end
unbundled(&block) click to toggle source
# File lib/et_full_system/cli/local.rb, line 311
def unbundled(&block)
  method = Bundler.respond_to?(:with_unbundled_env) ? :with_unbundled_env : :with_original_env
  Bundler.send(method, &block)
end
update_rest_backend_url(service, url) click to toggle source
# File lib/et_full_system/cli/local.rb, line 407
def update_rest_backend_url(service, url)
  connect_retry_countdown = 10
  setup_retry_countdown = 10
  begin
    resp = HTTParty.get "#{options[:base_url]}/api/providers/rest", headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
    raise RestProviderNotConfigured if resp.code == 404
  rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED
    connect_retry_countdown -= 1
    if !options[:wait]
      fail "Could not connect to the traefik API - specify --wait to keep retrying when this happens"
    elsif connect_retry_countdown.zero?
      fail "Could not connect to the traefik API after 10 retries (update_rest_backend_url)"
    else
      STDERR.puts "update_rest_backend_url - Retrying connection to traefik API in 5 seconds"
      sleep 5
      retry
    end
  rescue RestProviderNotConfigured
    setup_retry_countdown -= 1
    if !options[:wait]
      fail "The REST provider in traefik is not yet setup - specify --wait to keep retrying when this happens (i.e to wait for another command to set it up)"
    elsif setup_retry_countdown.zero?
      fail "Could not find the REST provider in traefik after 10 retries"
    else
      STDERR.puts "Re checking for the REST provider in traefik in 5 seconds"
      sleep 5
      retry
    end
  end

  json = resp.parsed_response.dup
  backend = json['backends'][service]
  raise "Unknown service called #{service} - valid options are #{json['backends'].keys.join(', ')}" if backend.nil?

  container = backend.dig('servers', 'web')
  raise "The service '#{service}' has no server called 'web' - it must have for this command to work" if container.nil?

  if container['url'] != url
    container['url'] = url
    put_resp = HTTParty.put "#{options[:base_url]}/api/providers/rest", body: json.to_json, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
    raise "Error from traefik says: #{put_resp.body}" unless (200..299).include? put_resp.code

    validate_rest_backend_url(service, url)
    STDERR.puts "The url for service '#{service}' is now '#{url}'"
  else
    STDERR.puts "The url for service '#{service}' was already '#{url}'"
  end
end
validate_rest_backend_url(service, url) click to toggle source
# File lib/et_full_system/cli/local.rb, line 456
def validate_rest_backend_url(service, url)
  retry_countdown = 10
  begin
    resp = HTTParty.get "#{options[:base_url]}/api/providers/rest", headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
    raise ServiceUrlIncorrect unless (200..299).include?(resp.code) && resp.parsed_response.dig('backends', service, 'servers', 'web', 'url') == url
    return
  rescue ServiceUrlIncorrect
    retry_countdown -= 1
    raise if retry_countdown.zero?

    STDERR.puts "Retrying request to validate the url of '#{service}' is '#{url}' in 1 second"
    sleep 1
    retry
  end
end
within_rest_lock(wait: 60 * 60 * 24, timeout: 60) { |file| ... } click to toggle source
# File lib/et_full_system/cli/local.rb, line 472
def within_rest_lock(wait: 60 * 60 * 24, timeout: 60)
  File.open(LOCK_FILE, File::RDWR|File::CREAT, 0644) do |file|
    Timeout::timeout(wait) { file.flock(File::LOCK_EX) }
    Timeout::timeout(timeout) { yield file }
  end
end