BigW Consortium Gitlab

check.rake 26.7 KB
Newer Older
1
namespace :gitlab do
2
  desc "GitLab | Check the configuration of GitLab and its environment"
3
  task check: %w{gitlab:gitlab_shell:check
4
                 gitlab:sidekiq:check
5
                 gitlab:incoming_email:check
6
                 gitlab:ldap:check
Riyad Preukschas committed
7 8 9
                 gitlab:app:check}


10

11
  namespace :app do
12
    desc "GitLab | Check the configuration of the GitLab Rails app"
13
    task check: :environment  do
Riyad Preukschas committed
14 15 16
      warn_user_is_not_gitlab
      start_checking "GitLab"

17
      check_git_config
Riyad Preukschas committed
18 19
      check_database_config_exists
      check_migrations_are_up
20
      check_orphaned_group_members
Riyad Preukschas committed
21 22 23 24
      check_gitlab_config_exists
      check_gitlab_config_not_outdated
      check_log_writable
      check_tmp_writable
Ben Bodenmiller committed
25
      check_uploads
Riyad Preukschas committed
26 27
      check_init_script_exists
      check_init_script_up_to_date
Hiroyuki Sato committed
28
      check_projects_have_namespace
29
      check_redis_version
30
      check_ruby_version
31
      check_git_version
32
      check_active_users
Riyad Preukschas committed
33 34 35 36 37 38 39 40

      finished_checking "GitLab"
    end


    # Checks
    ########################

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
    def check_git_config
      print "Git configured with autocrlf=input? ... "

      options = {
        "core.autocrlf" => "input"
      }

      correct_options = options.map do |name, value|
        run(%W(#{Gitlab.config.git.bin_path} config --global --get #{name})).try(:squish) == value
      end

      if correct_options.all?
        puts "yes".green
      else
        print "Trying to fix Git error automatically. ..."

        if auto_fix_git_config(options)
          puts "Success".green
        else
          puts "Failed".red
          try_fixing_it(
            sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global core.autocrlf \"#{options["core.autocrlf"]}\"")
          )
          for_more_information(
            see_installation_guide_section "GitLab"
          )
       end
      end
    end

Riyad Preukschas committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    def check_database_config_exists
      print "Database config exists? ... "

      database_config_file = Rails.root.join("config", "database.yml")

      if File.exists?(database_config_file)
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          "Copy config/database.yml.<your db> to config/database.yml",
          "Check that the information in config/database.yml is correct"
        )
        for_more_information(
          see_database_guide,
          "http://guides.rubyonrails.org/getting_started.html#configuring-a-database"
        )
Riyad Preukschas committed
88
        fix_and_rerun
Riyad Preukschas committed
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
      end
    end

    def check_gitlab_config_exists
      print "GitLab config exists? ... "

      gitlab_config_file = Rails.root.join("config", "gitlab.yml")

      if File.exists?(gitlab_config_file)
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          "Copy config/gitlab.yml.example to config/gitlab.yml",
          "Update config/gitlab.yml to match your setup"
        )
        for_more_information(
          see_installation_guide_section "GitLab"
        )
Riyad Preukschas committed
108
        fix_and_rerun
Riyad Preukschas committed
109 110 111 112
      end
    end

    def check_gitlab_config_not_outdated
113
      print "GitLab config outdated? ... "
Riyad Preukschas committed
114 115 116 117 118 119 120

      gitlab_config_file = Rails.root.join("config", "gitlab.yml")
      unless File.exists?(gitlab_config_file)
        puts "can't check because of previous errors".magenta
      end

      # omniauth or ldap could have been deleted from the file
121
      unless Gitlab.config['git_host']
122
        puts "no".green
Riyad Preukschas committed
123
      else
124
        puts "yes".red
Riyad Preukschas committed
125
        try_fixing_it(
126
          "Backup your config/gitlab.yml",
Riyad Preukschas committed
127 128 129 130 131 132
          "Copy config/gitlab.yml.example to config/gitlab.yml",
          "Update config/gitlab.yml to match your setup"
        )
        for_more_information(
          see_installation_guide_section "GitLab"
        )
Riyad Preukschas committed
133
        fix_and_rerun
Riyad Preukschas committed
134 135
      end
    end
136

Riyad Preukschas committed
137 138 139
    def check_init_script_exists
      print "Init script exists? ... "

140 141 142 143 144
      if omnibus_gitlab?
        puts 'skipped (omnibus-gitlab has no init script)'.magenta
        return
      end

Riyad Preukschas committed
145 146 147 148
      script_path = "/etc/init.d/gitlab"

      if File.exists?(script_path)
        puts "yes".green
Nihad Abbasov committed
149
      else
Riyad Preukschas committed
150 151 152 153 154 155 156
        puts "no".red
        try_fixing_it(
          "Install the init script"
        )
        for_more_information(
          see_installation_guide_section "Install Init Script"
        )
Riyad Preukschas committed
157
        fix_and_rerun
Riyad Preukschas committed
158 159 160 161 162 163
      end
    end

    def check_init_script_up_to_date
      print "Init script up-to-date? ... "

164 165 166 167 168
      if omnibus_gitlab?
        puts 'skipped (omnibus-gitlab has no init script)'.magenta
        return
      end

169
      recipe_path = Rails.root.join("lib/support/init.d/", "gitlab")
Riyad Preukschas committed
170
      script_path = "/etc/init.d/gitlab"
171

Riyad Preukschas committed
172 173
      unless File.exists?(script_path)
        puts "can't check because of previous errors".magenta
174 175 176
        return
      end

177
      recipe_content = File.read(recipe_path)
Riyad Preukschas committed
178 179 180 181 182 183 184 185 186 187 188 189
      script_content = File.read(script_path)

      if recipe_content == script_content
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          "Redownload the init script"
        )
        for_more_information(
          see_installation_guide_section "Install Init Script"
        )
Riyad Preukschas committed
190
        fix_and_rerun
Riyad Preukschas committed
191 192 193 194 195 196
      end
    end

    def check_migrations_are_up
      print "All migrations up? ... "

197
      migration_status, _ = Gitlab::Popen.popen(%W(bundle exec rake db:migrate:status))
Riyad Preukschas committed
198 199 200

      unless migration_status =~ /down\s+\d{14}/
        puts "yes".green
201
      else
Riyad Preukschas committed
202 203
        puts "no".red
        try_fixing_it(
204
          sudo_gitlab("bundle exec rake db:migrate RAILS_ENV=production")
Riyad Preukschas committed
205
        )
Riyad Preukschas committed
206
        fix_and_rerun
Riyad Preukschas committed
207 208 209
      end
    end

210
    def check_orphaned_group_members
211 212
      print "Database contains orphaned GroupMembers? ... "
      if GroupMember.where("user_id not in (select id from users)").count > 0
213
        puts "yes".red
214 215
        try_fixing_it(
          "You can delete the orphaned records using something along the lines of:",
216
          sudo_gitlab("bundle exec rails runner -e production 'GroupMember.where(\"user_id NOT IN (SELECT id FROM users)\").delete_all'")
217
        )
218 219 220 221 222
      else
        puts "no".green
      end
    end

Riyad Preukschas committed
223 224 225 226 227 228 229 230 231 232 233
    def check_log_writable
      print "Log directory writable? ... "

      log_path = Rails.root.join("log")

      if File.writable?(log_path)
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          "sudo chown -R gitlab #{log_path}",
bassrock committed
234
          "sudo chmod -R u+rwX #{log_path}"
Riyad Preukschas committed
235 236 237 238
        )
        for_more_information(
          see_installation_guide_section "GitLab"
        )
Riyad Preukschas committed
239
        fix_and_rerun
Riyad Preukschas committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253
      end
    end

    def check_tmp_writable
      print "Tmp directory writable? ... "

      tmp_path = Rails.root.join("tmp")

      if File.writable?(tmp_path)
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          "sudo chown -R gitlab #{tmp_path}",
bassrock committed
254
          "sudo chmod -R u+rwX #{tmp_path}"
Riyad Preukschas committed
255 256
        )
        for_more_information(
Ben Bodenmiller committed
257 258 259 260 261
          see_installation_guide_section "GitLab"
        )
        fix_and_rerun
      end
    end
262

Ben Bodenmiller committed
263 264 265 266 267 268
    def check_uploads
      print "Uploads directory setup correctly? ... "

      unless File.directory?(Rails.root.join('public/uploads'))
        puts "no".red
        try_fixing_it(
269
          "sudo -u #{gitlab_user} mkdir #{Rails.root}/public/uploads"
Ben Bodenmiller committed
270 271 272 273 274 275 276 277 278 279 280
        )
        for_more_information(
          see_installation_guide_section "GitLab"
        )
        fix_and_rerun
        return
      end

      upload_path = File.realpath(Rails.root.join('public/uploads'))
      upload_path_tmp = File.join(upload_path, 'tmp')

281
      if File.stat(upload_path).mode == 040700
Ben Bodenmiller committed
282 283 284 285 286
        unless Dir.exists?(upload_path_tmp)
          puts 'skipped (no tmp uploads folder yet)'.magenta
          return
        end

287 288 289
        # If tmp upload dir has incorrect permissions, assume others do as well
        # Verify drwx------ permissions
        if File.stat(upload_path_tmp).mode == 040700 && File.owned?(upload_path_tmp)
Ben Bodenmiller committed
290 291 292 293 294 295
          puts "yes".green
        else
          puts "no".red
          try_fixing_it(
            "sudo chown -R #{gitlab_user} #{upload_path}",
            "sudo find #{upload_path} -type f -exec chmod 0644 {} \\;",
296
            "sudo find #{upload_path} -type d -not -path #{upload_path} -exec chmod 0700 {} \\;"
Ben Bodenmiller committed
297 298 299 300 301 302 303 304 305
          )
          for_more_information(
            see_installation_guide_section "GitLab"
          )
          fix_and_rerun
        end
      else
        puts "no".red
        try_fixing_it(
306
          "sudo find #{upload_path} -type d -not -path #{upload_path} -exec chmod 0700 {} \\;"
Ben Bodenmiller committed
307 308
        )
        for_more_information(
Riyad Preukschas committed
309 310
          see_installation_guide_section "GitLab"
        )
Riyad Preukschas committed
311
        fix_and_rerun
Riyad Preukschas committed
312
      end
313
    end
314

315
    def check_redis_version
316
      min_redis_version = "2.8.0"
317
      print "Redis version >= #{min_redis_version}? ... "
318

tonic committed
319
      redis_version = run(%W(redis-cli --version))
320
      redis_version = redis_version.try(:match, /redis-cli (\d+\.\d+\.\d+)/)
321 322
      if redis_version &&
          (Gem::Version.new(redis_version[1]) > Gem::Version.new(min_redis_version))
323
        puts "yes".green
324
      else
325 326
        puts "no".red
        try_fixing_it(
327
          "Update your redis server to a version >= #{min_redis_version}"
328 329 330 331 332 333
        )
        for_more_information(
          "gitlab-public-wiki/wiki/Trouble-Shooting-Guide in section sidekiq"
        )
        fix_and_rerun
      end
334
    end
335 336
  end

337
  namespace :gitlab_shell do
338
    desc "GitLab | Check the configuration of GitLab Shell"
339
    task check: :environment  do
Riyad Preukschas committed
340
      warn_user_is_not_gitlab
341
      start_checking "GitLab Shell"
Riyad Preukschas committed
342

343
      check_gitlab_shell
Riyad Preukschas committed
344
      check_repo_base_exists
345
      check_repo_base_is_not_symlink
Riyad Preukschas committed
346 347
      check_repo_base_user_and_group
      check_repo_base_permissions
348
      check_repos_hooks_directory_is_link
349
      check_gitlab_shell_self_test
Riyad Preukschas committed
350

351
      finished_checking "GitLab Shell"
Riyad Preukschas committed
352 353 354 355 356 357 358 359 360
    end


    # Checks
    ########################

    def check_repo_base_exists
      print "Repo base directory exists? ... "

361
      repo_base_path = Gitlab.config.gitlab_shell.repos_path
Riyad Preukschas committed
362 363 364 365 366 367 368

      if File.exists?(repo_base_path)
        puts "yes".green
      else
        puts "no".red
        puts "#{repo_base_path} is missing".red
        try_fixing_it(
369
          "This should have been created when setting up GitLab Shell.",
Riyad Preukschas committed
370
          "Make sure it's set correctly in config/gitlab.yml",
371
          "Make sure GitLab Shell is installed correctly."
Riyad Preukschas committed
372 373
        )
        for_more_information(
374
          see_installation_guide_section "GitLab Shell"
Riyad Preukschas committed
375
        )
Riyad Preukschas committed
376
        fix_and_rerun
Riyad Preukschas committed
377 378 379
      end
    end

380 381 382
    def check_repo_base_is_not_symlink
      print "Repo base directory is a symlink? ... "

383
      repo_base_path = Gitlab.config.gitlab_shell.repos_path
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
      unless File.exists?(repo_base_path)
        puts "can't check because of previous errors".magenta
        return
      end

      unless File.symlink?(repo_base_path)
        puts "no".green
      else
        puts "yes".red
        try_fixing_it(
          "Make sure it's set to the real directory in config/gitlab.yml"
        )
        fix_and_rerun
      end
    end

Riyad Preukschas committed
400
    def check_repo_base_permissions
401
      print "Repo base access is drwxrws---? ... "
Riyad Preukschas committed
402

403
      repo_base_path = Gitlab.config.gitlab_shell.repos_path
Riyad Preukschas committed
404 405
      unless File.exists?(repo_base_path)
        puts "can't check because of previous errors".magenta
406 407 408
        return
      end

409
      if File.stat(repo_base_path).mode.to_s(8).ends_with?("2770")
Riyad Preukschas committed
410 411 412 413
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
414
          "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}",
415
          "sudo chmod -R ug-s #{repo_base_path}",
416
          "sudo find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s"
Riyad Preukschas committed
417 418
        )
        for_more_information(
419
          see_installation_guide_section "GitLab Shell"
Riyad Preukschas committed
420
        )
Riyad Preukschas committed
421
        fix_and_rerun
Riyad Preukschas committed
422 423 424 425
      end
    end

    def check_repo_base_user_and_group
426 427 428
      gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user
      gitlab_shell_owner_group = Gitlab.config.gitlab_shell.owner_group
      print "Repo base owned by #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group}? ... "
Riyad Preukschas committed
429

430
      repo_base_path = Gitlab.config.gitlab_shell.repos_path
Riyad Preukschas committed
431 432
      unless File.exists?(repo_base_path)
        puts "can't check because of previous errors".magenta
433 434 435
        return
      end

436 437 438
      uid = uid_for(gitlab_shell_ssh_user)
      gid = gid_for(gitlab_shell_owner_group)
      if File.stat(repo_base_path).uid == uid && File.stat(repo_base_path).gid == gid
Riyad Preukschas committed
439
        puts "yes".green
440
      else
Riyad Preukschas committed
441
        puts "no".red
442
        puts "  User id for #{gitlab_shell_ssh_user}: #{uid}. Groupd id for #{gitlab_shell_owner_group}: #{gid}".blue
Riyad Preukschas committed
443
        try_fixing_it(
444
          "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}"
Riyad Preukschas committed
445 446
        )
        for_more_information(
447
          see_installation_guide_section "GitLab Shell"
Riyad Preukschas committed
448
        )
Riyad Preukschas committed
449
        fix_and_rerun
Riyad Preukschas committed
450 451 452
      end
    end

453 454
    def check_repos_hooks_directory_is_link
      print "hooks directories in repos are links: ... "
Riyad Preukschas committed
455

456
      gitlab_shell_hooks_path = Gitlab.config.gitlab_shell.hooks_path
457

Riyad Preukschas committed
458 459 460 461 462
      unless Project.count > 0
        puts "can't check, you have no projects".magenta
        return
      end
      puts ""
463

Riyad Preukschas committed
464
      Project.find_each(batch_size: 100) do |project|
465
        print sanitized_message(project)
466
        project_hook_directory = File.join(project.repository.path_to_repo, "hooks")
467

468 469
        if project.empty_repo?
          puts "repository is empty".magenta
470 471
        elsif File.directory?(project_hook_directory) && File.directory?(gitlab_shell_hooks_path) &&
            (File.realpath(project_hook_directory) == File.realpath(gitlab_shell_hooks_path))
472
          puts 'ok'.green
Riyad Preukschas committed
473
        else
474 475
          puts "wrong or missing hooks".red
          try_fixing_it(
476
            sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')}"),
477 478 479 480 481 482 483
            'Check the hooks_path in config/gitlab.yml',
            'Check your gitlab-shell installation'
          )
          for_more_information(
            see_installation_guide_section "GitLab Shell"
          )
          fix_and_rerun
484
        end
485

486
      end
487
    end
Riyad Preukschas committed
488

489
    def check_gitlab_shell_self_test
490
      gitlab_shell_repo_base = gitlab_shell_path
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
      check_cmd = File.expand_path('bin/check', gitlab_shell_repo_base)
      puts "Running #{check_cmd}"
      if system(check_cmd, chdir: gitlab_shell_repo_base)
        puts 'gitlab-shell self-check successful'.green
      else
        puts 'gitlab-shell self-check failed'.red
        try_fixing_it(
          'Make sure GitLab is running;',
          'Check the gitlab-shell configuration file:',
          sudo_gitlab("editor #{File.expand_path('config.yml', gitlab_shell_repo_base)}")
        )
        fix_and_rerun
      end
    end

Hiroyuki Sato committed
506 507 508 509 510 511 512 513 514 515
    def check_projects_have_namespace
      print "projects have namespace: ... "

      unless Project.count > 0
        puts "can't check, you have no projects".magenta
        return
      end
      puts ""

      Project.find_each(batch_size: 100) do |project|
516
        print sanitized_message(project)
Hiroyuki Sato committed
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531

        if project.namespace
          puts "yes".green
        else
          puts "no".red
          try_fixing_it(
            "Migrate global projects"
          )
          for_more_information(
            "doc/update/5.4-to-6.0.md in section \"#global-projects\""
          )
          fix_and_rerun
        end
      end
    end
Riyad Preukschas committed
532 533 534 535

    # Helper methods
    ########################

536 537
    def gitlab_shell_path
      Gitlab.config.gitlab_shell.path
Riyad Preukschas committed
538 539
    end

540
    def gitlab_shell_version
541
      Gitlab::Shell.new.version
Riyad Preukschas committed
542 543
    end

544
    def gitlab_shell_major_version
545
      Gitlab::Shell.version_required.split('.')[0].to_i
546 547 548
    end

    def gitlab_shell_minor_version
549
      Gitlab::Shell.version_required.split('.')[1].to_i
550 551 552
    end

    def gitlab_shell_patch_version
553
      Gitlab::Shell.version_required.split('.')[2].to_i
554
    end
555
  end
556

Riyad Preukschas committed
557 558


559
  namespace :sidekiq do
560
    desc "GitLab | Check the configuration of Sidekiq"
561
    task check: :environment  do
Riyad Preukschas committed
562
      warn_user_is_not_gitlab
563
      start_checking "Sidekiq"
Riyad Preukschas committed
564

565
      check_sidekiq_running
566
      only_one_sidekiq_running
Riyad Preukschas committed
567

568
      finished_checking "Sidekiq"
Riyad Preukschas committed
569 570 571 572 573 574
    end


    # Checks
    ########################

575
    def check_sidekiq_running
Riyad Preukschas committed
576 577
      print "Running? ... "

578
      if sidekiq_process_count > 0
Riyad Preukschas committed
579 580 581 582
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
583
          sudo_gitlab("RAILS_ENV=production bin/background_jobs start")
Riyad Preukschas committed
584 585 586
        )
        for_more_information(
          see_installation_guide_section("Install Init Script"),
587
          "see log/sidekiq.log for possible errors"
Riyad Preukschas committed
588
        )
Riyad Preukschas committed
589
        fix_and_rerun
Riyad Preukschas committed
590 591
      end
    end
592 593

    def only_one_sidekiq_running
594 595
      process_count = sidekiq_process_count
      return if process_count.zero?
596 597

      print 'Number of Sidekiq processes ... '
598
      if process_count == 1
599 600
        puts '1'.green
      else
601
        puts "#{process_count}".red
602 603
        try_fixing_it(
          'sudo service gitlab stop',
604 605
          "sudo pkill -u #{gitlab_user} -f sidekiq",
          "sleep 10 && sudo pkill -9 -u #{gitlab_user} -f sidekiq",
606 607 608 609 610 611
          'sudo service gitlab start'
        )
        fix_and_rerun
      end
    end

612
    def sidekiq_process_count
613 614
      ps_ux, _ = Gitlab::Popen.popen(%W(ps ux))
      ps_ux.scan(/sidekiq \d+\.\d+\.\d+/).count
615
    end
Riyad Preukschas committed
616 617
  end

618

619
  namespace :incoming_email do
620 621 622 623 624
    desc "GitLab | Check the configuration of Reply by email"
    task check: :environment  do
      warn_user_is_not_gitlab
      start_checking "Reply by email"

625
      if Gitlab.config.incoming_email.enabled
626 627
        check_address_formatted_correctly
        check_imap_authentication
628

629 630 631 632 633 634
        if Rails.env.production?
          check_initd_configured_correctly
          check_mail_room_running
        else
          check_foreman_configured_correctly
        end
635 636 637 638 639 640 641 642 643 644 645 646 647 648
      else
        puts 'Reply by email is disabled in config/gitlab.yml'
      end

      finished_checking "Reply by email"
    end


    # Checks
    ########################

    def check_address_formatted_correctly
      print "Address formatted correctly? ... "

649
      if Gitlab::IncomingEmail.address_formatted_correctly?
650 651 652 653
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
654
          "Make sure that the address in config/gitlab.yml includes the '%{key}' placeholder."
655 656 657 658 659 660 661 662
        )
        fix_and_rerun
      end
    end

    def check_initd_configured_correctly
      print "Init.d configured correctly? ... "

663 664 665 666 667
      if omnibus_gitlab?
        puts 'skipped (omnibus-gitlab has no init script)'.magenta
        return
      end

668 669 670 671 672 673 674 675 676 677
      path = "/etc/default/gitlab"

      if File.exist?(path) && File.read(path).include?("mail_room_enabled=true")
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          "Enable mail_room in the init.d configuration."
        )
        for_more_information(
678
          "doc/incoming_email/README.md"
679 680 681 682 683
        )
        fix_and_rerun
      end
    end

684 685 686 687 688
    def check_foreman_configured_correctly
      print "Foreman configured correctly? ... "

      path = Rails.root.join("Procfile")

689
      if File.exist?(path) && File.read(path) =~ /^mail_room:/
690 691 692 693 694 695 696
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          "Enable mail_room in your Procfile."
        )
        for_more_information(
697
          "doc/incoming_email/README.md"
698 699 700 701 702
        )
        fix_and_rerun
      end
    end

703 704 705 706 707 708 709 710 711 712
    def check_mail_room_running
      print "MailRoom running? ... "

      path = "/etc/default/gitlab"

      unless File.exist?(path) && File.read(path).include?("mail_room_enabled=true")
        puts "can't check because of previous errors".magenta
        return
      end

713
      if mail_room_running?
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
          sudo_gitlab("RAILS_ENV=production bin/mail_room start")
        )
        for_more_information(
          see_installation_guide_section("Install Init Script"),
          "see log/mail_room.log for possible errors"
        )
        fix_and_rerun
      end
    end

    def check_imap_authentication
      print "IMAP server credentials are correct? ... "

731 732 733
      config_path = Rails.root.join('config', 'mail_room.yml')
      config_file = YAML.load(ERB.new(File.read(config_path)).result)
      config = config_file[:mailboxes].first
734 735 736

      if config
        begin
737 738 739
          imap = Net::IMAP.new(config[:host], port: config[:port], ssl: config[:ssl])
          imap.starttls if config[:start_tls]
          imap.login(config[:email], config[:password])
740 741 742 743 744 745 746 747 748 749 750
          connected = true
        rescue
          connected = false
        end
      end

      if connected
        puts "yes".green
      else
        puts "no".red
        try_fixing_it(
751
          "Check that the information in config/gitlab.yml is correct"
752 753
        )
        for_more_information(
754
          "doc/incoming_email/README.md"
755 756 757 758 759
        )
        fix_and_rerun
      end
    end

760
    def mail_room_running?
761
      ps_ux, _ = Gitlab::Popen.popen(%W(ps ux))
762
      ps_ux.include?("mail_room")
763 764 765
    end
  end

766
  namespace :ldap do
767
    task :check, [:limit] => :environment do |t, args|
768 769
      # Only show up to 100 results because LDAP directories can be very big.
      # This setting only affects the `rake gitlab:check` script.
770
      args.with_defaults(limit: 100)
771 772 773
      warn_user_is_not_gitlab
      start_checking "LDAP"

774
      if Gitlab::LDAP::Config.enabled?
775
        print_users(args.limit)
776 777 778
      else
        puts 'LDAP is disabled in config/gitlab.yml'
      end
779 780 781 782

      finished_checking "LDAP"
    end

783
    def print_users(limit)
784
      puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)"
785

786
      servers = Gitlab::LDAP::Config.providers
787

788 789
      servers.each do |server|
        puts "Server: #{server}"
790
        Gitlab::LDAP::Adapter.open(server) do |adapter|
791 792 793 794 795
          users = adapter.users(adapter.config.uid, '*', 100)
          users.each do |user|
            puts "\tDN: #{user.dn}\t #{adapter.config.uid}: #{user.uid}"
          end
        end
796
      end
797 798
    end
  end
Riyad Preukschas committed
799

Vinnie Okada committed
800
  namespace :repo do
801
    desc "GitLab | Check the integrity of the repositories managed by GitLab"
Vinnie Okada committed
802 803 804 805 806 807 808
    task check: :environment do
      namespace_dirs = Dir.glob(
        File.join(Gitlab.config.gitlab_shell.repos_path, '*')
      )

      namespace_dirs.each do |namespace_dir|
        repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
        repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
      end
    end
  end

  namespace :user do
    desc "GitLab | Check the integrity of a specific user's repositories"
    task :check_repos, [:username] => :environment do |t, args|
      username = args[:username] || prompt("Check repository integrity for which username? ".blue)
      user = User.find_by(username: username)
      if user
        repo_dirs = user.authorized_projects.map do |p|
                      File.join(
                        Gitlab.config.gitlab_shell.repos_path,
                        "#{p.path_with_namespace}.git"
                      )
                    end

        repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
      else
        puts "\nUser '#{username}' not found".red
Vinnie Okada committed
830 831 832 833
      end
    end
  end

Riyad Preukschas committed
834 835 836
  # Helper methods
  ##########################

Riyad Preukschas committed
837
  def fix_and_rerun
Riyad Preukschas committed
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
    puts "  Please #{"fix the error above"} and rerun the checks.".red
  end

  def for_more_information(*sources)
    sources = sources.shift if sources.first.is_a?(Array)

    puts "  For more information see:".blue
    sources.each do |source|
      puts "  #{source}"
    end
  end

  def finished_checking(component)
    puts ""
    puts "Checking #{component.yellow} ... #{"Finished".green}"
    puts ""
  end

  def see_database_guide
    "doc/install/databases.md"
  end

  def see_installation_guide_section(section)
    "doc/install/installation.md in section \"#{section}\""
  end

864 865 866 867
  def sudo_gitlab(command)
    "sudo -u #{gitlab_user} -H #{command}"
  end

868 869 870 871
  def gitlab_user
    Gitlab.config.gitlab.user
  end

Riyad Preukschas committed
872 873 874 875 876 877 878 879 880 881 882 883 884
  def start_checking(component)
    puts "Checking #{component.yellow} ..."
    puts ""
  end

  def try_fixing_it(*steps)
    steps = steps.shift if steps.first.is_a?(Array)

    puts "  Try fixing it:".blue
    steps.each do |step|
      puts "  #{step}"
    end
  end
885 886

  def check_gitlab_shell
887
    required_version = Gitlab::VersionInfo.new(gitlab_shell_major_version, gitlab_shell_minor_version, gitlab_shell_patch_version)
888
    current_version = Gitlab::VersionInfo.parse(gitlab_shell_version)
889

890
    print "GitLab Shell version >= #{required_version} ? ... "
891
    if current_version.valid? && required_version <= current_version
892
      puts "OK (#{current_version})".green
893
    else
894
      puts "FAIL. Please update gitlab-shell to #{required_version} from #{current_version}".red
895 896
    end
  end
897

898
  def check_ruby_version
899
    required_version = Gitlab::VersionInfo.new(2, 1, 0)
900 901 902 903 904
    current_version = Gitlab::VersionInfo.parse(run(%W(ruby --version)))

    print "Ruby version >= #{required_version} ? ... "

    if current_version.valid? && required_version <= current_version
905
      puts "yes (#{current_version})".green
906 907 908 909 910 911 912 913 914
    else
      puts "no".red
      try_fixing_it(
        "Update your ruby to a version >= #{required_version} from #{current_version}"
      )
      fix_and_rerun
    end
  end

915
  def check_git_version
916
    required_version = Gitlab::VersionInfo.new(2, 7, 3)
917
    current_version = Gitlab::VersionInfo.parse(run(%W(#{Gitlab.config.git.bin_path} --version)))
Sato Hiroyuki committed
918

919
    puts "Your git bin path is \"#{Gitlab.config.git.bin_path}\""
Sato Hiroyuki committed
920 921
    print "Git version >= #{required_version} ? ... "

922
    if current_version.valid? && required_version <= current_version
923
      puts "yes (#{current_version})".green
924 925 926
    else
      puts "no".red
      try_fixing_it(
Sato Hiroyuki committed
927
        "Update your git to a version >= #{required_version} from #{current_version}"
928 929 930 931
      )
      fix_and_rerun
    end
  end
932

933 934 935 936
  def check_active_users
    puts "Active users: #{User.active.count}"
  end

937 938 939
  def omnibus_gitlab?
    Dir.pwd == '/opt/gitlab/embedded/service/gitlab-rails'
  end
940

941
  def sanitized_message(project)
942
    if should_sanitize?
943 944 945 946 947 948
      "#{project.namespace_id.to_s.yellow}/#{project.id.to_s.yellow} ... "
    else
      "#{project.name_with_namespace.yellow} ... "
    end
  end

949
  def should_sanitize?
950 951 952 953 954 955
    if ENV['SANITIZE'] == "true"
      true
    else
      false
    end
  end
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986

  def check_repo_integrity(repo_dir)
    puts "\nChecking repo at #{repo_dir.yellow}"

    git_fsck(repo_dir)
    check_config_lock(repo_dir)
    check_ref_locks(repo_dir)
  end

  def git_fsck(repo_dir)
    puts "Running `git fsck`".yellow
    system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: repo_dir)
  end

  def check_config_lock(repo_dir)
    config_exists = File.exist?(File.join(repo_dir,'config.lock'))
    config_output = config_exists ? 'yes'.red : 'no'.green
    puts "'config.lock' file exists?".yellow + " ... #{config_output}"
  end

  def check_ref_locks(repo_dir)
    lock_files = Dir.glob(File.join(repo_dir,'refs/heads/*.lock'))
    if lock_files.present?
      puts "Ref lock files exist:".red
      lock_files.each do |lock_file|
        puts "  #{lock_file}"
      end
    else
      puts "No ref lock files exist".green
    end
  end
987
end