check.rake 27.4 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
Riyad Preukschas's avatar
Riyad Preukschas committed
4
                 gitlab:sidekiq:check
5
                 gitlab:incoming_email:check
6
                 gitlab:ldap:check
Riyad Preukschas's avatar
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's avatar
Riyad Preukschas committed
14 15 16
      warn_user_is_not_gitlab
      start_checking "GitLab"

17
      check_git_config
Riyad Preukschas's avatar
Riyad Preukschas committed
18 19
      check_database_config_exists
      check_migrations_are_up
20
      check_orphaned_group_members
Riyad Preukschas's avatar
Riyad Preukschas committed
21 22 23 24
      check_gitlab_config_exists
      check_gitlab_config_not_outdated
      check_log_writable
      check_tmp_writable
Ben Bodenmiller's avatar
Ben Bodenmiller committed
25
      check_uploads
Riyad Preukschas's avatar
Riyad Preukschas committed
26 27
      check_init_script_exists
      check_init_script_up_to_date
Hiroyuki Sato's avatar
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's avatar
Riyad Preukschas committed
33 34 35 36 37 38 39 40

      finished_checking "GitLab"
    end


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

41 42 43 44 45 46 47 48
    def check_git_config
      print "Git configured with autocrlf=input? ... "

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

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

      if correct_options.all?
53
        puts "yes".color(:green)
54 55 56 57
      else
        print "Trying to fix Git error automatically. ..."

        if auto_fix_git_config(options)
58
          puts "Success".color(:green)
59
        else
60
          puts "Failed".color(:red)
61 62 63 64 65 66 67 68 69 70
          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's avatar
Riyad Preukschas committed
71 72 73 74 75 76
    def check_database_config_exists
      print "Database config exists? ... "

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

      if File.exists?(database_config_file)
77
        puts "yes".color(:green)
Riyad Preukschas's avatar
Riyad Preukschas committed
78
      else
79
        puts "no".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
80 81 82 83 84 85 86 87
        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's avatar
Riyad Preukschas committed
88
        fix_and_rerun
Riyad Preukschas's avatar
Riyad Preukschas committed
89 90 91 92 93 94 95 96 97
      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)
98
        puts "yes".color(:green)
Riyad Preukschas's avatar
Riyad Preukschas committed
99
      else
100
        puts "no".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
101 102 103 104 105 106 107
        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's avatar
Riyad Preukschas committed
108
        fix_and_rerun
Riyad Preukschas's avatar
Riyad Preukschas committed
109 110 111 112
      end
    end

    def check_gitlab_config_not_outdated
Riyad Preukschas's avatar
Riyad Preukschas committed
113
      print "GitLab config outdated? ... "
Riyad Preukschas's avatar
Riyad Preukschas committed
114 115 116

      gitlab_config_file = Rails.root.join("config", "gitlab.yml")
      unless File.exists?(gitlab_config_file)
117
        puts "can't check because of previous errors".color(:magenta)
Riyad Preukschas's avatar
Riyad Preukschas committed
118 119 120
      end

      # omniauth or ldap could have been deleted from the file
121
      unless Gitlab.config['git_host']
122
        puts "no".color(:green)
Riyad Preukschas's avatar
Riyad Preukschas committed
123
      else
124
        puts "yes".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
125
        try_fixing_it(
Riyad Preukschas's avatar
Riyad Preukschas committed
126
          "Backup your config/gitlab.yml",
Riyad Preukschas's avatar
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's avatar
Riyad Preukschas committed
133
        fix_and_rerun
Riyad Preukschas's avatar
Riyad Preukschas committed
134 135
      end
    end
136

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

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

Riyad Preukschas's avatar
Riyad Preukschas committed
145 146 147
      script_path = "/etc/init.d/gitlab"

      if File.exists?(script_path)
148
        puts "yes".color(:green)
Nihad Abbasov's avatar
Nihad Abbasov committed
149
      else
150
        puts "no".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
151 152 153 154 155 156
        try_fixing_it(
          "Install the init script"
        )
        for_more_information(
          see_installation_guide_section "Install Init Script"
        )
Riyad Preukschas's avatar
Riyad Preukschas committed
157
        fix_and_rerun
Riyad Preukschas's avatar
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
      if omnibus_gitlab?
165
        puts 'skipped (omnibus-gitlab has no init script)'.color(:magenta)
166 167 168
        return
      end

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

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

177
      recipe_content = File.read(recipe_path)
Riyad Preukschas's avatar
Riyad Preukschas committed
178 179 180
      script_content = File.read(script_path)

      if recipe_content == script_content
181
        puts "yes".color(:green)
Riyad Preukschas's avatar
Riyad Preukschas committed
182
      else
183
        puts "no".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
184 185 186 187 188 189
        try_fixing_it(
          "Redownload the init script"
        )
        for_more_information(
          see_installation_guide_section "Install Init Script"
        )
Riyad Preukschas's avatar
Riyad Preukschas committed
190
        fix_and_rerun
Riyad Preukschas's avatar
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's avatar
Riyad Preukschas committed
198 199

      unless migration_status =~ /down\s+\d{14}/
200
        puts "yes".color(:green)
201
      else
202
        puts "no".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
203
        try_fixing_it(
204
          sudo_gitlab("bundle exec rake db:migrate RAILS_ENV=production")
Riyad Preukschas's avatar
Riyad Preukschas committed
205
        )
Riyad Preukschas's avatar
Riyad Preukschas committed
206
        fix_and_rerun
Riyad Preukschas's avatar
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".color(: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
      else
219
        puts "no".color(:green)
220 221 222
      end
    end

Riyad Preukschas's avatar
Riyad Preukschas committed
223 224 225 226 227 228
    def check_log_writable
      print "Log directory writable? ... "

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

      if File.writable?(log_path)
229
        puts "yes".color(:green)
Riyad Preukschas's avatar
Riyad Preukschas committed
230
      else
231
        puts "no".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
232 233
        try_fixing_it(
          "sudo chown -R gitlab #{log_path}",
bassrock's avatar
bassrock committed
234
          "sudo chmod -R u+rwX #{log_path}"
Riyad Preukschas's avatar
Riyad Preukschas committed
235 236 237 238
        )
        for_more_information(
          see_installation_guide_section "GitLab"
        )
Riyad Preukschas's avatar
Riyad Preukschas committed
239
        fix_and_rerun
Riyad Preukschas's avatar
Riyad Preukschas committed
240 241 242 243 244 245 246 247 248
      end
    end

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

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

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

Ben Bodenmiller's avatar
Ben Bodenmiller committed
263 264 265 266
    def check_uploads
      print "Uploads directory setup correctly? ... "

      unless File.directory?(Rails.root.join('public/uploads'))
267
        puts "no".color(:red)
Ben Bodenmiller's avatar
Ben Bodenmiller committed
268
        try_fixing_it(
269
          "sudo -u #{gitlab_user} mkdir #{Rails.root}/public/uploads"
Ben Bodenmiller's avatar
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's avatar
Ben Bodenmiller committed
282
        unless Dir.exists?(upload_path_tmp)
283
          puts 'skipped (no tmp uploads folder yet)'.color(:magenta)
Ben Bodenmiller's avatar
Ben Bodenmiller committed
284 285 286
          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)
290
          puts "yes".color(:green)
Ben Bodenmiller's avatar
Ben Bodenmiller committed
291
        else
292
          puts "no".color(:red)
Ben Bodenmiller's avatar
Ben Bodenmiller committed
293 294 295
          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's avatar
Ben Bodenmiller committed
297 298 299 300 301 302 303
          )
          for_more_information(
            see_installation_guide_section "GitLab"
          )
          fix_and_rerun
        end
      else
304
        puts "no".color(:red)
Ben Bodenmiller's avatar
Ben Bodenmiller committed
305
        try_fixing_it(
306
          "sudo chmod 700 #{upload_path}"
Ben Bodenmiller's avatar
Ben Bodenmiller committed
307 308
        )
        for_more_information(
Riyad Preukschas's avatar
Riyad Preukschas committed
309 310
          see_installation_guide_section "GitLab"
        )
Riyad Preukschas's avatar
Riyad Preukschas committed
311
        fix_and_rerun
Riyad Preukschas's avatar
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

319
      redis_version = run_command(%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".color(:green)
324
      else
325
        puts "no".color(:red)
326
        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's avatar
Riyad Preukschas committed
340
      warn_user_is_not_gitlab
Ben Bodenmiller's avatar
Ben Bodenmiller committed
341
      start_checking "GitLab Shell"
Riyad Preukschas's avatar
Riyad Preukschas committed
342

343
      check_gitlab_shell
Riyad Preukschas's avatar
Riyad Preukschas committed
344
      check_repo_base_exists
345
      check_repo_base_is_not_symlink
Riyad Preukschas's avatar
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's avatar
Riyad Preukschas committed
350

Ben Bodenmiller's avatar
Ben Bodenmiller committed
351
      finished_checking "GitLab Shell"
Riyad Preukschas's avatar
Riyad Preukschas committed
352 353 354 355 356 357 358
    end


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

    def check_repo_base_exists
359
      puts "Repo base directory exists?"
Riyad Preukschas's avatar
Riyad Preukschas committed
360

361 362
      Gitlab.config.repositories.storages.each do |name, repo_base_path|
        print "#{name}... "
Riyad Preukschas's avatar
Riyad Preukschas committed
363

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

382
    def check_repo_base_is_not_symlink
383
      puts "Repo storage directories are symlinks?"
384

385 386
      Gitlab.config.repositories.storages.each do |name, repo_base_path|
        print "#{name}... "
387

388 389 390 391 392 393 394 395 396 397 398 399 400 401
        unless File.exists?(repo_base_path)
          puts "can't check because of previous errors".color(:magenta)
          return
        end

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

Riyad Preukschas's avatar
Riyad Preukschas committed
405
    def check_repo_base_permissions
406
      puts "Repo paths access is drwxrws---?"
Riyad Preukschas's avatar
Riyad Preukschas committed
407

408 409
      Gitlab.config.repositories.storages.each do |name, repo_base_path|
        print "#{name}... "
410

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
        unless File.exists?(repo_base_path)
          puts "can't check because of previous errors".color(:magenta)
          return
        end

        if File.stat(repo_base_path).mode.to_s(8).ends_with?("2770")
          puts "yes".color(:green)
        else
          puts "no".color(:red)
          try_fixing_it(
            "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}",
            "sudo chmod -R ug-s #{repo_base_path}",
            "sudo find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s"
          )
          for_more_information(
            see_installation_guide_section "GitLab Shell"
          )
          fix_and_rerun
        end
Riyad Preukschas's avatar
Riyad Preukschas committed
430 431 432 433
      end
    end

    def check_repo_base_user_and_group
434 435
      gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user
      gitlab_shell_owner_group = Gitlab.config.gitlab_shell.owner_group
436
      puts "Repo paths owned by #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group}?"
Riyad Preukschas's avatar
Riyad Preukschas committed
437

438 439
      Gitlab.config.repositories.storages.each do |name, repo_base_path|
        print "#{name}... "
440

441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
        unless File.exists?(repo_base_path)
          puts "can't check because of previous errors".color(:magenta)
          return
        end

        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
          puts "yes".color(:green)
        else
          puts "no".color(:red)
          puts "  User id for #{gitlab_shell_ssh_user}: #{uid}. Groupd id for #{gitlab_shell_owner_group}: #{gid}".color(:blue)
          try_fixing_it(
            "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}"
          )
          for_more_information(
            see_installation_guide_section "GitLab Shell"
          )
          fix_and_rerun
        end
Riyad Preukschas's avatar
Riyad Preukschas committed
461 462 463
      end
    end

464 465
    def check_repos_hooks_directory_is_link
      print "hooks directories in repos are links: ... "
Riyad Preukschas's avatar
Riyad Preukschas committed
466

467
      gitlab_shell_hooks_path = Gitlab.config.gitlab_shell.hooks_path
468

Riyad Preukschas's avatar
Riyad Preukschas committed
469
      unless Project.count > 0
470
        puts "can't check, you have no projects".color(:magenta)
Riyad Preukschas's avatar
Riyad Preukschas committed
471 472 473
        return
      end
      puts ""
474

Riyad Preukschas's avatar
Riyad Preukschas committed
475
      Project.find_each(batch_size: 100) do |project|
Marin Jankovski's avatar
Marin Jankovski committed
476
        print sanitized_message(project)
477
        project_hook_directory = File.join(project.repository.path_to_repo, "hooks")
478

Riyad Preukschas's avatar
Riyad Preukschas committed
479
        if project.empty_repo?
480
          puts "repository is empty".color(:magenta)
481 482
        elsif File.directory?(project_hook_directory) && File.directory?(gitlab_shell_hooks_path) &&
            (File.realpath(project_hook_directory) == File.realpath(gitlab_shell_hooks_path))
483
          puts 'ok'.color(:green)
Riyad Preukschas's avatar
Riyad Preukschas committed
484
        else
485
          puts "wrong or missing hooks".color(:red)
486
          try_fixing_it(
487
            sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')} #{repository_storage_paths_args.join(' ')}"),
488 489 490 491 492 493 494
            '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
495
        end
496

497
      end
498
    end
Riyad Preukschas's avatar
Riyad Preukschas committed
499

500
    def check_gitlab_shell_self_test
501
      gitlab_shell_repo_base = gitlab_shell_path
502 503 504
      check_cmd = File.expand_path('bin/check', gitlab_shell_repo_base)
      puts "Running #{check_cmd}"
      if system(check_cmd, chdir: gitlab_shell_repo_base)
505
        puts 'gitlab-shell self-check successful'.color(:green)
506
      else
507
        puts 'gitlab-shell self-check failed'.color(:red)
508 509 510 511 512 513 514 515 516
        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's avatar
Hiroyuki Sato committed
517 518 519 520
    def check_projects_have_namespace
      print "projects have namespace: ... "

      unless Project.count > 0
521
        puts "can't check, you have no projects".color(:magenta)
Hiroyuki Sato's avatar
Hiroyuki Sato committed
522 523 524 525 526
        return
      end
      puts ""

      Project.find_each(batch_size: 100) do |project|
Marin Jankovski's avatar
Marin Jankovski committed
527
        print sanitized_message(project)
Hiroyuki Sato's avatar
Hiroyuki Sato committed
528 529

        if project.namespace
530
          puts "yes".color(:green)
Hiroyuki Sato's avatar
Hiroyuki Sato committed
531
        else
532
          puts "no".color(:red)
Hiroyuki Sato's avatar
Hiroyuki Sato committed
533 534 535 536 537 538 539 540 541 542
          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's avatar
Riyad Preukschas committed
543 544 545 546

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

547 548
    def gitlab_shell_path
      Gitlab.config.gitlab_shell.path
Riyad Preukschas's avatar
Riyad Preukschas committed
549 550
    end

551
    def gitlab_shell_version
552
      Gitlab::Shell.new.version
Riyad Preukschas's avatar
Riyad Preukschas committed
553 554
    end

555
    def gitlab_shell_major_version
556
      Gitlab::Shell.version_required.split('.')[0].to_i
557 558 559
    end

    def gitlab_shell_minor_version
560
      Gitlab::Shell.version_required.split('.')[1].to_i
561 562 563
    end

    def gitlab_shell_patch_version
564
      Gitlab::Shell.version_required.split('.')[2].to_i
565
    end
566
  end
567

Riyad Preukschas's avatar
Riyad Preukschas committed
568 569


Riyad Preukschas's avatar
Riyad Preukschas committed
570
  namespace :sidekiq do
571
    desc "GitLab | Check the configuration of Sidekiq"
572
    task check: :environment  do
Riyad Preukschas's avatar
Riyad Preukschas committed
573
      warn_user_is_not_gitlab
Riyad Preukschas's avatar
Riyad Preukschas committed
574
      start_checking "Sidekiq"
Riyad Preukschas's avatar
Riyad Preukschas committed
575

Riyad Preukschas's avatar
Riyad Preukschas committed
576
      check_sidekiq_running
577
      only_one_sidekiq_running
Riyad Preukschas's avatar
Riyad Preukschas committed
578

Riyad Preukschas's avatar
Riyad Preukschas committed
579
      finished_checking "Sidekiq"
Riyad Preukschas's avatar
Riyad Preukschas committed
580 581 582 583 584 585
    end


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

Riyad Preukschas's avatar
Riyad Preukschas committed
586
    def check_sidekiq_running
Riyad Preukschas's avatar
Riyad Preukschas committed
587 588
      print "Running? ... "

589
      if sidekiq_process_count > 0
590
        puts "yes".color(:green)
Riyad Preukschas's avatar
Riyad Preukschas committed
591
      else
592
        puts "no".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
593
        try_fixing_it(
594
          sudo_gitlab("RAILS_ENV=production bin/background_jobs start")
Riyad Preukschas's avatar
Riyad Preukschas committed
595 596 597
        )
        for_more_information(
          see_installation_guide_section("Install Init Script"),
598
          "see log/sidekiq.log for possible errors"
Riyad Preukschas's avatar
Riyad Preukschas committed
599
        )
Riyad Preukschas's avatar
Riyad Preukschas committed
600
        fix_and_rerun
Riyad Preukschas's avatar
Riyad Preukschas committed
601 602
      end
    end
603 604

    def only_one_sidekiq_running
605 606
      process_count = sidekiq_process_count
      return if process_count.zero?
607 608

      print 'Number of Sidekiq processes ... '
609
      if process_count == 1
610
        puts '1'.color(:green)
611
      else
612
        puts "#{process_count}".color(:red)
613 614
        try_fixing_it(
          'sudo service gitlab stop',
615 616
          "sudo pkill -u #{gitlab_user} -f sidekiq",
          "sleep 10 && sudo pkill -9 -u #{gitlab_user} -f sidekiq",
617 618 619 620 621 622
          'sudo service gitlab start'
        )
        fix_and_rerun
      end
    end

623
    def sidekiq_process_count
624 625
      ps_ux, _ = Gitlab::Popen.popen(%W(ps ux))
      ps_ux.scan(/sidekiq \d+\.\d+\.\d+/).count
626
    end
Riyad Preukschas's avatar
Riyad Preukschas committed
627 628
  end

629

630
  namespace :incoming_email do
631 632 633 634 635
    desc "GitLab | Check the configuration of Reply by email"
    task check: :environment  do
      warn_user_is_not_gitlab
      start_checking "Reply by email"

636
      if Gitlab.config.incoming_email.enabled
637
        check_imap_authentication
638

639 640 641 642 643 644
        if Rails.env.production?
          check_initd_configured_correctly
          check_mail_room_running
        else
          check_foreman_configured_correctly
        end
645 646 647 648 649 650 651 652 653 654 655 656 657 658
      else
        puts 'Reply by email is disabled in config/gitlab.yml'
      end

      finished_checking "Reply by email"
    end


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

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

659
      if omnibus_gitlab?
660
        puts 'skipped (omnibus-gitlab has no init script)'.color(:magenta)
661 662 663
        return
      end

664 665 666
      path = "/etc/default/gitlab"

      if File.exist?(path) && File.read(path).include?("mail_room_enabled=true")
667
        puts "yes".color(:green)
668
      else
669
        puts "no".color(:red)
670 671 672 673
        try_fixing_it(
          "Enable mail_room in the init.d configuration."
        )
        for_more_information(
674
          "doc/incoming_email/README.md"
675 676 677 678 679
        )
        fix_and_rerun
      end
    end

680 681 682 683 684
    def check_foreman_configured_correctly
      print "Foreman configured correctly? ... "

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

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

699 700 701 702 703 704
    def check_mail_room_running
      print "MailRoom running? ... "

      path = "/etc/default/gitlab"

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

Douwe Maan's avatar
Douwe Maan committed
709
      if mail_room_running?
710
        puts "yes".color(:green)
711
      else
712
        puts "no".color(:red)
713 714 715 716 717 718 719 720 721 722 723 724 725 726
        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? ... "

727 728 729
      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
730 731 732

      if config
        begin
733 734 735
          imap = Net::IMAP.new(config[:host], port: config[:port], ssl: config[:ssl])
          imap.starttls if config[:start_tls]
          imap.login(config[:email], config[:password])
736 737 738 739 740 741 742
          connected = true
        rescue
          connected = false
        end
      end

      if connected
743
        puts "yes".color(:green)
744
      else
745
        puts "no".color(:red)
746
        try_fixing_it(
747
          "Check that the information in config/gitlab.yml is correct"
748 749
        )
        for_more_information(
750
          "doc/incoming_email/README.md"
751 752 753 754 755
        )
        fix_and_rerun
      end
    end

Douwe Maan's avatar
Douwe Maan committed
756
    def mail_room_running?
757
      ps_ux, _ = Gitlab::Popen.popen(%W(ps ux))
Douwe Maan's avatar
Douwe Maan committed
758
      ps_ux.include?("mail_room")
759 760 761
    end
  end

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

770
      if Gitlab::LDAP::Config.enabled?
771
        print_users(args.limit)
772 773 774
      else
        puts 'LDAP is disabled in config/gitlab.yml'
      end
775 776 777 778

      finished_checking "LDAP"
    end

779
    def print_users(limit)
780
      puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)"
781

782
      servers = Gitlab::LDAP::Config.providers
783

784 785
      servers.each do |server|
        puts "Server: #{server}"
786
        Gitlab::LDAP::Adapter.open(server) do |adapter|
787
          users = adapter.users(adapter.config.uid, '*', limit)
788 789 790 791
          users.each do |user|
            puts "\tDN: #{user.dn}\t #{adapter.config.uid}: #{user.uid}"
          end
        end
792
      end
793 794
    end
  end
Riyad Preukschas's avatar
Riyad Preukschas committed
795

Vinnie Okada's avatar
Vinnie Okada committed
796
  namespace :repo do
797
    desc "GitLab | Check the integrity of the repositories managed by GitLab"
Vinnie Okada's avatar
Vinnie Okada committed
798
    task check: :environment do
799 800
      Gitlab.config.repositories.storages.each do |name, path|
        namespace_dirs = Dir.glob(File.join(path, '*'))
Vinnie Okada's avatar
Vinnie Okada committed
801

802 803 804 805
        namespace_dirs.each do |namespace_dir|
          repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
          repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
        end
806 807 808 809 810 811 812
      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|
813
      username = args[:username] || prompt("Check repository integrity for fsername? ".color(:blue))
814 815 816 817
      user = User.find_by(username: username)
      if user
        repo_dirs = user.authorized_projects.map do |p|
                      File.join(
818
                        p.repository_storage_path,
819 820 821 822 823 824
                        "#{p.path_with_namespace}.git"
                      )
                    end

        repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
      else
825
        puts "\nUser '#{username}' not found".color(:red)
Vinnie Okada's avatar
Vinnie Okada committed
826 827 828 829
      end
    end
  end

Riyad Preukschas's avatar
Riyad Preukschas committed
830 831 832
  # Helper methods
  ##########################

Riyad Preukschas's avatar
Riyad Preukschas committed
833
  def fix_and_rerun
834
    puts "  Please #{"fix the error above"} and rerun the checks.".color(:red)
Riyad Preukschas's avatar
Riyad Preukschas committed
835 836 837 838 839
  end

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

840
    puts "  For more information see:".color(:blue)
Riyad Preukschas's avatar
Riyad Preukschas committed
841 842 843 844 845 846 847
    sources.each do |source|
      puts "  #{source}"
    end
  end

  def finished_checking(component)
    puts ""
848
    puts "Checking #{component.color(:yellow)} ... #{"Finished".color(:green)}"
Riyad Preukschas's avatar
Riyad Preukschas committed
849 850 851 852 853 854 855 856 857 858 859
    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

860 861 862 863
  def sudo_gitlab(command)
    "sudo -u #{gitlab_user} -H #{command}"
  end

864 865 866 867
  def gitlab_user
    Gitlab.config.gitlab.user
  end

Riyad Preukschas's avatar
Riyad Preukschas committed
868
  def start_checking(component)
869
    puts "Checking #{component.color(:yellow)} ..."
Riyad Preukschas's avatar
Riyad Preukschas committed
870 871 872 873 874 875
    puts ""
  end

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

876
    puts "  Try fixing it:".color(:blue)
Riyad Preukschas's avatar
Riyad Preukschas committed
877 878 879 880
    steps.each do |step|
      puts "  #{step}"
    end
  end
881 882

  def check_gitlab_shell
883
    required_version = Gitlab::VersionInfo.new(gitlab_shell_major_version, gitlab_shell_minor_version, gitlab_shell_patch_version)
884
    current_version = Gitlab::VersionInfo.parse(gitlab_shell_version)
885

886
    print "GitLab Shell version >= #{required_version} ? ... "
Sato Hiroyuki's avatar
Sato Hiroyuki committed
887
    if current_version.valid? && required_version <= current_version
888
      puts "OK (#{current_version})".color(:green)
889
    else
890
      puts "FAIL. Please update gitlab-shell to #{required_version} from #{current_version}".color(:red)
891 892
    end
  end
893

894
  def check_ruby_version
895
    required_version = Gitlab::VersionInfo.new(2, 1, 0)
896
    current_version = Gitlab::VersionInfo.parse(run_command(%W(ruby --version)))
897 898 899 900

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

    if current_version.valid? && required_version <= current_version
901
      puts "yes (#{current_version})".color(:green)
902
    else
903
      puts "no".color(:red)
904 905 906 907 908 909 910
      try_fixing_it(
        "Update your ruby to a version >= #{required_version} from #{current_version}"
      )
      fix_and_rerun
    end
  end

911
  def check_git_version
912
    required_version = Gitlab::VersionInfo.new(2, 7, 3)
913
    current_version = Gitlab::VersionInfo.parse(run_command(%W(#{Gitlab.config.git.bin_path} --version)))
Sato Hiroyuki's avatar
Sato Hiroyuki committed
914

915
    puts "Your git bin path is \"#{Gitlab.config.git.bin_path}\""
Sato Hiroyuki's avatar
Sato Hiroyuki committed
916 917
    print "Git version >= #{required_version} ? ... "

Sato Hiroyuki's avatar
Sato Hiroyuki committed
918
    if current_version.valid? && required_version <= current_version
919
      puts "yes (#{current_version})".color(:green)
920
    else
921
      puts "no".color(:red)
922
      try_fixing_it(
Sato Hiroyuki's avatar
Sato Hiroyuki committed
923
        "Update your git to a version >= #{required_version} from #{current_version}"
924 925 926 927
      )
      fix_and_rerun
    end
  end
928

929 930 931 932
  def check_active_users
    puts "Active users: #{User.active.count}"
  end

933 934 935
  def omnibus_gitlab?
    Dir.pwd == '/opt/gitlab/embedded/service/gitlab-rails'
  end
936

Marin Jankovski's avatar
Marin Jankovski committed
937
  def sanitized_message(project)
938
    if should_sanitize?
939
      "#{project.namespace_id.to_s.color(:yellow)}/#{project.id.to_s.color(:yellow)} ... "
Marin Jankovski's avatar
Marin Jankovski committed
940
    else
941
      "#{project.name_with_namespace.color(:yellow)} ... "
Marin Jankovski's avatar
Marin Jankovski committed
942 943 944
    end
  end

945
  def should_sanitize?
946 947 948 949 950 951
    if ENV['SANITIZE'] == "true"
      true
    else
      false
    end
  end
952 953

  def check_repo_integrity(repo_dir)
954
    puts "\nChecking repo at #{repo_dir.color(:yellow)}"
955 956 957 958 959 960 961

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

  def git_fsck(repo_dir)
962
    puts "Running `git fsck`".color(:yellow)
963 964 965 966 967
    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'))
968 969
    config_output = config_exists ? 'yes'.color(:red) : 'no'.color(:green)
    puts "'config.lock' file exists?".color(:yellow) + " ... #{config_output}"
970 971 972 973 974
  end

  def check_ref_locks(repo_dir)
    lock_files = Dir.glob(File.join(repo_dir,'refs/heads/*.lock'))
    if lock_files.present?
975
      puts "Ref lock files exist:".color(:red)
976 977 978 979
      lock_files.each do |lock_file|
        puts "  #{lock_file}"
      end
    else
980
      puts "No ref lock files exist".color(:green)
981 982
    end
  end
983
end