1--- 2stage: Enablement 3group: Distribution 4info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments 5type: reference 6--- 7 8# GitLab Rails Console Cheat Sheet **(FREE SELF)** 9 10This is the GitLab Support Team's collection of information regarding the GitLab Rails 11console, for use while troubleshooting. It is listed here for transparency, 12and it may be useful for users with experience with these tools. If you are currently 13having an issue with GitLab, it is highly recommended that you first check 14our guide on [navigating our Rails console](navigating_gitlab_via_rails_console.md), 15and your [support options](https://about.gitlab.com/support/), before attempting to use 16this information. 17 18WARNING: 19Some of these scripts could be damaging if not run correctly, 20or under the right conditions. We highly recommend running them under the 21guidance of a Support Engineer, or running them in a test environment with a 22backup of the instance ready to be restored, just in case. 23 24WARNING: 25As GitLab changes, changes to the code are inevitable, 26and so some scripts may not work as they once used to. These are not kept 27up-to-date as these scripts/commands were added as they were found/needed. As 28mentioned above, we recommend running these scripts under the supervision of a 29Support Engineer, who can also verify that they continue to work as they 30should and, if needed, update the script for the latest version of GitLab. 31 32## Find specific methods for an object 33 34```ruby 35Array.methods.select { |m| m.to_s.include? "sing" } 36Array.methods.grep(/sing/) 37``` 38 39## Find method source 40 41```ruby 42instance_of_object.method(:foo).source_location 43 44# Example for when we would call project.private? 45project.method(:private?).source_location 46``` 47 48## Attributes 49 50View available attributes, formatted using pretty print (`pp`). 51 52For example, determine what attributes contain users' names and email addresses: 53 54```ruby 55u = User.find_by_username('someuser') 56pp u.attributes 57``` 58 59Partial output: 60 61```plaintext 62{"id"=>1234, 63 "email"=>"someuser@example.com", 64 "sign_in_count"=>99, 65 "name"=>"S User", 66 "username"=>"someuser", 67 "first_name"=>nil, 68 "last_name"=>nil, 69 "bot_type"=>nil} 70``` 71 72Then make use of the attributes, [testing SMTP, for example](https://docs.gitlab.com/omnibus/settings/smtp.html#testing-the-smtp-configuration): 73 74```ruby 75e = u.email 76n = u.name 77Notify.test_email(e, "Test email for #{n}", 'Test email').deliver_now 78# 79Notify.test_email(u.email, "Test email for #{u.name}", 'Test email').deliver_now 80``` 81 82## Query the database using an ActiveRecord Model 83 84```ruby 85m = Model.where('attribute like ?', 'ex%') 86 87# for example to query the projects 88projects = Project.where('path like ?', 'Oumua%') 89``` 90 91## View all keys in cache 92 93```ruby 94Rails.cache.instance_variable_get(:@data).keys 95``` 96 97## Profile a page 98 99```ruby 100url = '<url/of/the/page>' 101 102# Before 11.6.0 103logger = Logger.new($stdout) 104admin_token = User.find_by_username('<admin-username>').personal_access_tokens.first.token 105app.get("#{url}/?private_token=#{admin_token}") 106 107# From 11.6.0 108admin = User.find_by_username('<admin-username>') 109Gitlab::Profiler.with_user(admin) { app.get(url) } 110``` 111 112## Using the GitLab profiler inside console (used as of 10.5) 113 114```ruby 115logger = Logger.new($stdout) 116admin = User.find_by_username('<admin-username>') 117Gitlab::Profiler.profile('<url/of/the/page>', logger: logger, user: admin) 118``` 119 120## Time an operation 121 122```ruby 123# A single operation 124Benchmark.measure { <operation> } 125 126# A breakdown of multiple operations 127Benchmark.bm do |x| 128 x.report(:label1) { <operation_1> } 129 x.report(:label2) { <operation_2> } 130end 131``` 132 133## Feature flags 134 135### Show all feature flags that are enabled 136 137```ruby 138# Regular output 139Feature.all 140 141# Nice output 142Feature.all.map {|f| [f.name, f.state]} 143``` 144 145## Command Line 146 147### Check the GitLab version fast 148 149```shell 150grep -m 1 gitlab /opt/gitlab/version-manifest.txt 151``` 152 153### Debugging SSH 154 155```shell 156GIT_SSH_COMMAND="ssh -vvv" git clone <repository> 157``` 158 159### Debugging over HTTPS 160 161```shell 162GIT_CURL_VERBOSE=1 GIT_TRACE=1 git clone <repository> 163``` 164 165## Projects 166 167### Clear a project's cache 168 169```ruby 170ProjectCacheWorker.perform_async(project.id) 171``` 172 173### Expire the .exists? cache 174 175```ruby 176project.repository.expire_exists_cache 177``` 178 179### Make all projects private 180 181```ruby 182Project.update_all(visibility_level: 0) 183``` 184 185### Find projects that are pending deletion 186 187```ruby 188# 189# This section lists all the projects which are pending deletion 190# 191projects = Project.where(pending_delete: true) 192projects.each do |p| 193 puts "Project ID: #{p.id}" 194 puts "Project name: #{p.name}" 195 puts "Repository path: #{p.repository.full_path}" 196end 197 198# 199# Assign a user (the root user does) 200# 201user = User.find_by_username('root') 202 203# 204# For each project listed repeat these two commands 205# 206 207# Find the project, update the xxx-changeme values from above 208project = Project.find_by_full_path('group-changeme/project-changeme') 209 210# Immediately delete the project 211::Projects::DestroyService.new(project, user, {}).execute 212``` 213 214### Destroy a project 215 216```ruby 217project = Project.find_by_full_path('<project_path>') 218user = User.find_by_username('<username>') 219ProjectDestroyWorker.perform_async(project.id, user.id, {}) 220# or ProjectDestroyWorker.new.perform(project.id, user.id, {}) 221# or Projects::DestroyService.new(project, user).execute 222``` 223 224### Remove fork relationship manually 225 226```ruby 227p = Project.find_by_full_path('<project_path>') 228u = User.find_by_username('<username>') 229::Projects::UnlinkForkService.new(p, u).execute 230``` 231 232### Make a project read-only (can only be done in the console) 233 234```ruby 235# Make a project read-only 236project.repository_read_only = true; project.save 237 238# OR 239project.update!(repository_read_only: true) 240``` 241 242### Transfer project from one namespace to another 243 244```ruby 245p = Project.find_by_full_path('<project_path>') 246 247 # To set the owner of the project 248 current_user= p.creator 249 250# Namespace where you want this to be moved. 251namespace = Namespace.find_by_full_path("<new_namespace>") 252 253::Projects::TransferService.new(p, current_user).execute(namespace) 254``` 255 256### For Removing webhooks that is getting timeout due to large webhook logs 257 258```ruby 259# ID is the webhook_id 260hook=WebHook.find(ID) 261 262WebHooks::DestroyService.new(current_user).execute(hook) 263 264#In case the service gets timeout consider removing webhook_logs 265hook.web_hook_logs.limit(BATCH_SIZE).delete_all 266``` 267 268### Bulk update service integration password for _all_ projects 269 270For example, change the Jira user's password for all projects that have the Jira 271integration active: 272 273```ruby 274p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN services s ON p.id = s.project_id WHERE s.type = 'JiraService' AND s.active = true") 275 276p.each do |project| 277 project.jira_integration.update_attribute(:password, '<your-new-password>') 278end 279``` 280 281### Bulk update push rules for _all_ projects 282 283For example, enable **Check whether the commit author is a GitLab user** and **Do not allow users to remove Git tags with `git push`** checkboxes, and create a filter for allowing commits from a specific e-mail domain only: 284 285``` ruby 286Project.find_each do |p| 287 pr = p.push_rule || PushRule.new(project: p) 288 # Check whether the commit author is a GitLab user 289 pr.member_check = true 290 # Do not allow users to remove Git tags with `git push` 291 pr.deny_delete_tag = true 292 # Commit author's email 293 pr.author_email_regex = '@domain\.com$' 294 pr.save! 295end 296``` 297 298## Bulk update to change all the Jira integrations to Jira instance-level values 299 300To change all Jira project to use the instance-level integration settings: 301 3021. In a Rails console: 303 304 ```ruby 305 jira_integration_instance_id = Integrations::Jira.find_by(instance: true).id 306 Integrations::Jira.where(active: true, instance: false, template: false, inherit_from_id: nil).find_each do |integration| 307 integration.update_attribute(:inherit_from_id, jira_integration_instance_id) 308 end 309 ``` 310 3111. Modify and save again the instance-level integration from the UI to propagate the changes to all the group-level and project-level integrations. 312 313### Bulk update to disable the Slack Notification service 314 315To disable notifications for all projects that have Slack service enabled, do: 316 317```ruby 318# Grab all projects that have the Slack notifications enabled 319p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN services s ON p.id = s.project_id WHERE s.type = 'SlackService' AND s.active = true") 320 321# Disable the service on each of the projects that were found. 322p.each do |project| 323 project.slack_service.update_attribute(:active, false) 324end 325``` 326 327### Incorrect repository statistics shown in the GUI 328 329After [reducing a repository size with third-party tools](../../user/project/repository/reducing_the_repo_size_using_git.md) 330the displayed size may still show old sizes or commit numbers. To force an update, do: 331 332```ruby 333p = Project.find_by_full_path('<namespace>/<project>') 334pp p.statistics 335p.statistics.refresh! 336pp p.statistics 337# compare with earlier values 338 339# check the total artifact storage space separately 340builds_with_artifacts = p.builds.with_downloadable_artifacts.all 341 342artifact_storage = 0 343builds_with_artifacts.find_each do |build| 344 artifact_storage += build.artifacts_size 345end 346 347puts "#{artifact_storage} bytes" 348``` 349 350### Identify deploy keys associated with blocked and non-member users 351 352When the user who created a deploy key is blocked or removed from the project, the key 353can no longer be used to push to protected branches in a private project (see [issue #329742](https://gitlab.com/gitlab-org/gitlab/-/issues/329742)). 354The following script identifies unusable deploy keys: 355 356```ruby 357ghost_user_id = User.ghost.id 358 359DeployKeysProject.with_write_access.find_each do |deploy_key_mapping| 360 project = deploy_key_mapping.project 361 deploy_key = deploy_key_mapping.deploy_key 362 user = deploy_key.user 363 364 access_checker = Gitlab::DeployKeyAccess.new(deploy_key, container: project) 365 366 # can_push_for_ref? tests if deploy_key can push to default branch, which is likely to be protected 367 can_push = access_checker.can_do_action?(:push_code) 368 can_push_to_default = access_checker.can_push_for_ref?(project.repository.root_ref) 369 370 next if access_checker.allowed? && can_push && can_push_to_default 371 372 if user.nil? || user.id == ghost_user_id 373 username = 'none' 374 state = '-' 375 else 376 username = user.username 377 user_state = user.state 378 end 379 380 puts "Deploy key: #{deploy_key.id}, Project: #{project.full_path}, Can push?: " + (can_push ? 'YES' : 'NO') + 381 ", Can push to default branch #{project.repository.root_ref}?: " + (can_push_to_default ? 'YES' : 'NO') + 382 ", User: #{username}, User state: #{user_state}" 383end 384``` 385 386### Find projects using an SQL query 387 388Find and store an array of projects based on an SQL query: 389 390```ruby 391# Finds projects that end with '%ject' 392projects = Project.find_by_sql("SELECT * FROM projects WHERE name LIKE '%ject'") 393=> [#<Project id:12 root/my-first-project>>, #<Project id:13 root/my-second-project>>] 394``` 395 396## Wikis 397 398### Recreate 399 400WARNING: 401This is a destructive operation, the Wiki becomes empty. 402 403A Projects Wiki can be recreated by this command: 404 405```ruby 406p = Project.find_by_full_path('<username-or-group>/<project-name>') ### enter your projects path 407 408GitlabShellWorker.perform_in(0, :remove_repository, p.repository_storage, p.wiki.disk_path) ### deletes the wiki project from the filesystem 409 410p.create_wiki ### creates the wiki project on the filesystem 411``` 412 413## Issue boards 414 415### In case of issue boards not loading properly and it's getting time out. We need to call the Issue Rebalancing service to fix this 416 417```ruby 418p = Project.find_by_full_path('<username-or-group>/<project-name>') 419 420Issues::RelativePositionRebalancingService.new(p.root_namespace.all_projects).execute 421``` 422 423## Imports and exports 424 425### Import a project 426 427```ruby 428# Find the project and get the error 429p = Project.find_by_full_path('<username-or-group>/<project-name>') 430 431p.import_error 432 433# To finish the import on GitLab running version before 11.6 434p.import_finish 435 436# To finish the import on GitLab running version 11.6 or after 437p.import_state.mark_as_failed("Failed manually through console.") 438``` 439 440### Rename imported repository 441 442In a specific situation, an imported repository needed to be renamed. The Support 443Team was informed of a backup restore that failed on a single repository, which created 444the project with an empty repository. The project was successfully restored to a development 445instance, then exported, and imported into a new project under a different name. 446 447The Support Team was able to transfer the incorrectly named imported project into the 448correctly named empty project using the steps below. 449 450Move the new repository to the empty repository: 451 452```shell 453mv /var/opt/gitlab/git-data/repositories/<group>/<new-project> /var/opt/gitlab/git-data/repositories/<group>/<empty-project> 454``` 455 456Make sure the permissions are correct: 457 458```shell 459chown -R git:git <path-to-directory>.git 460``` 461 462Clear the cache: 463 464```shell 465sudo gitlab-rake cache:clear 466``` 467 468### Export a project 469 470It's typically recommended to export a project through [the web interface](../../user/project/settings/import_export.md#export-a-project-and-its-data) or through [the API](../../api/project_import_export.md). In situations where this is not working as expected, it may be preferable to export a project directly via the Rails console: 471 472```ruby 473user = User.find_by_username('<username>') 474# Sufficient permissions needed 475# Read https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions 476 477project = Project.find_by_full_path('<username-or-group>/<project-name') 478Projects::ImportExport::ExportService.new(project, user).execute 479``` 480 481If this all runs successfully, you see an output like the following before being returned to the Rails console prompt: 482 483```ruby 484=> nil 485``` 486 487The exported project is located within a `.tar.gz` file in `/var/opt/gitlab/gitlab-rails/uploads/-/system/import_export_upload/export_file/`. 488 489If this fails, [enable verbose logging](navigating_gitlab_via_rails_console.md#looking-up-database-persisted-objects), 490repeat the above procedure after, 491and report the output to 492[GitLab Support](https://about.gitlab.com/support/). 493 494## Repository 495 496### Search sequence of pushes to a repository 497 498If it seems that a commit has gone "missing", search the sequence of pushes to a repository. 499[This StackOverflow article](https://stackoverflow.com/questions/13468027/the-mystery-of-the-missing-commit-across-merges) 500describes how you can end up in this state without a force push. Another cause can be a misconfigured [server hook](../server_hooks.md) that changes a HEAD ref via a `git reset` operation. 501 502If you look at the output from the sample code below for the target branch, you 503see a discontinuity in the from/to commits as you step through the output. The `commit_from` of each new push should equal the `commit_to` of the previous push. A break in that sequence indicates one or more commits have been "lost" from the repository history. 504 505The following example checks the last 100 pushes and prints the `commit_from` and `commit_to` entries: 506 507```ruby 508p = Project.find_by_full_path('u/p') 509p.events.pushed_action.last(100).each do |e| 510 printf "%-20.20s %8s...%8s (%s) 511", e.push_event_payload[:ref], e.push_event_payload[:commit_from], e.push_event_payload[:commit_to], e.author.try(:username) 512end 513``` 514 515Example output showing break in sequence at line 4: 516 517```plaintext 518master f21b07713251e04575908149bdc8ac1f105aabc3...6bc56c1f46244792222f6c85b11606933af171de (root) 519master 6bc56c1f46244792222f6c85b11606933af171de...132da6064f5d3453d445fd7cb452b148705bdc1b (root) 520master 132da6064f5d3453d445fd7cb452b148705bdc1b...a62e1e693150a2e46ace0ce696cd4a52856dfa65 (root) 521master 58b07b719a4b0039fec810efa52f479ba1b84756...f05321a5b5728bd8a89b7bf530aa44043c951dce (root) 522master f05321a5b5728bd8a89b7bf530aa44043c951dce...7d02e575fd790e76a3284ee435368279a5eb3773 (root) 523``` 524 525## Mirrors 526 527### Find mirrors with "bad decrypt" errors 528 529This content has been converted to a Rake task, see the [Doctor Rake tasks docs](../raketasks/doctor.md). 530 531### Transfer mirror users and tokens to a single service account 532 533Use case: If you have multiple users using their own GitHub credentials to set up 534repository mirroring, mirroring breaks when people leave the company. Use this 535script to migrate disparate mirroring users and tokens into a single service account: 536 537```ruby 538svc_user = User.find_by(username: 'ourServiceUser') 539token = 'githubAccessToken' 540 541Project.where(mirror: true).each do |project| 542 import_url = project.import_url 543 544 # The url we want is https://token@project/path.git 545 repo_url = if import_url.include?('@') 546 # Case 1: The url is something like https://23423432@project/path.git 547 import_url.split('@').last 548 elsif import_url.include?('//') 549 # Case 2: The url is something like https://project/path.git 550 import_url.split('//').last 551 end 552 553 next unless repo_url 554 555 final_url = "https://#{token}@#{repo_url}" 556 557 project.mirror_user = svc_user 558 project.import_url = final_url 559 project.username_only_import_url = final_url 560 project.save 561end 562``` 563 564## Users 565 566### Create new user 567 568```ruby 569u = User.new(username: 'test_user', email: 'test@example.com', name: 'Test User', password: 'password', password_confirmation: 'password') 570u.skip_confirmation! # Use it only if you wish user to be automatically confirmed. If skipped, user receives confirmation e-mail 571u.save! 572``` 573 574### Skip reconfirmation 575 576```ruby 577user = User.find_by_username('<username>') 578user.skip_reconfirmation! 579``` 580 581### Disable 2fa for single user 582 583```ruby 584user = User.find_by_username('<username>') 585user.disable_two_factor! 586``` 587 588### Active users & Historical users 589 590```ruby 591# Active users on the instance, now 592User.active.count 593 594# Users taking a seat on the instance 595User.billable.count 596 597# The historical max on the instance as of the past year 598::HistoricalData.max_historical_user_count(from: 1.year.ago.beginning_of_day, to: Time.current.end_of_day) 599``` 600 601Using cURL and jq (up to a max 100, see the [pagination docs](../../api/index.md#pagination)): 602 603```shell 604curl --silent --header "Private-Token: ********************" \ 605 "https://gitlab.example.com/api/v4/users?per_page=100&active" | jq --compact-output '.[] | [.id,.name,.username]' 606``` 607 608### Update Daily Billable & Historical users 609 610```ruby 611# Forces recount of historical (max) users 612::HistoricalDataWorker.new.perform 613 614# Forces recount of daily billable users 615identifier = Analytics::UsageTrends::Measurement.identifiers[:billable_users] 616::Analytics::UsageTrends::CounterJobWorker.new.perform(identifier, User.minimum(:id), User.maximum(:id), Time.zone.now) 617``` 618 619### Block or Delete Users that have no projects or groups 620 621```ruby 622users = User.where('id NOT IN (select distinct(user_id) from project_authorizations)') 623 624# How many users are removed? 625users.count 626 627# If that count looks sane: 628 629# You can either block the users: 630users.each { |user| user.blocked? ? nil : user.block! } 631 632# Or you can delete them: 633 # need 'current user' (your user) for auditing purposes 634current_user = User.find_by(username: '<your username>') 635 636users.each do |user| 637 DeleteUserWorker.perform_async(current_user.id, user.id) 638end 639``` 640 641### Deactivate Users that have no recent activity 642 643```ruby 644days_inactive = 90 645inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago) 646 647inactive_users.each do |user| 648 puts "user '#{user.username}': #{user.last_activity_on}" 649 user.deactivate! 650end 651``` 652 653### Block Users that have no recent activity 654 655```ruby 656days_inactive = 90 657inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago) 658 659inactive_users.each do |user| 660 puts "user '#{user.username}': #{user.last_activity_on}" 661 user.block! 662end 663``` 664 665### Find a user's max permissions for project/group 666 667```ruby 668user = User.find_by_username 'username' 669project = Project.find_by_full_path 'group/project' 670user.max_member_access_for_project project.id 671``` 672 673```ruby 674user = User.find_by_username 'username' 675group = Group.find_by_full_path 'group' 676user.max_member_access_for_group group.id 677``` 678 679## Groups 680 681### Transfer group to another location 682 683```ruby 684user = User.find_by_username('<username>') 685group = Group.find_by_name("<group_name>") 686parent_group = Group.find_by(id: "<group_id>") 687service = ::Groups::TransferService.new(group, user) 688service.execute(parent_group) 689``` 690 691### Count unique users in a group and subgroups 692 693```ruby 694group = Group.find_by_path_or_name("groupname") 695members = [] 696for member in group.members_with_descendants 697 members.push(member.user_name) 698end 699 700members.uniq.length 701``` 702 703```ruby 704group = Group.find_by_path_or_name("groupname") 705 706# Count users from subgroup and up (inherited) 707group.members_with_parents.count 708 709# Count users from the parent group and down (specific grants) 710parent.members_with_descendants.count 711``` 712 713### Delete a group 714 715```ruby 716GroupDestroyWorker.perform_async(group_id, user_id) 717``` 718 719### Modify group project creation 720 721```ruby 722# Project creation levels: 0 - No one, 1 - Maintainers, 2 - Developers + Maintainers 723group = Group.find_by_path_or_name('group-name') 724group.project_creation_level=0 725``` 726 727### Modify group - disable 2FA requirement 728 729WARNING: 730When disabling the 2FA Requirement on a subgroup, the whole parent group (including all subgroups) is affected by this change. 731 732```ruby 733group = Group.find_by_path_or_name('group-name') 734group.require_two_factor_authentication=false 735group.save 736``` 737 738## Authentication 739 740### Re-enable standard web sign-in form 741 742Re-enable the standard username and password-based sign-in form if it was disabled as a [Sign-in restriction](../../user/admin_area/settings/sign_in_restrictions.md#password-authentication-enabled). 743 744You can use this method when a configured external authentication provider (through SSO or an LDAP configuration) is facing an outage and direct sign-in access to GitLab is required. 745 746```ruby 747Gitlab::CurrentSettings.update!(password_authentication_enabled_for_web: true) 748``` 749 750## SCIM 751 752### Fixing bad SCIM identities 753 754```ruby 755def delete_bad_scim(email, group_path) 756 output = "" 757 u = User.find_by_email(email) 758 uid = u.id 759 g = Group.find_by_full_path(group_path) 760 saml_prov_id = SamlProvider.find_by(group_id: g.id).id 761 saml = Identity.where(user_id: uid, saml_provider_id: saml_prov_id) 762 scim = ScimIdentity.where(user_id: uid , group_id: g.id) 763 if saml[0] 764 saml_eid = saml[0].extern_uid 765 output += "%s," % [email] 766 output += "SAML: %s," % [saml_eid] 767 if scim[0] 768 scim_eid = scim[0].extern_uid 769 output += "SCIM: %s" % [scim_eid] 770 if saml_eid == scim_eid 771 output += " Identities matched, not deleted \n" 772 else 773 scim[0].destroy 774 output += " Deleted \n" 775 end 776 else 777 output = "ERROR No SCIM identify found for: [%s]\n" % [email] 778 puts output 779 return 1 780 end 781 else 782 output = "ERROR No SAML identify found for: [%s]\n" % [email] 783 puts output 784 return 1 785 end 786 puts output 787 return 0 788end 789 790# In case of multiple emails 791emails = [email1, email2] 792 793emails.each do |e| 794 delete_bad_scim(e,'<group-path>') 795end 796``` 797 798### Find groups using an SQL query 799 800Find and store an array of groups based on an SQL query: 801 802```ruby 803# Finds groups and subgroups that end with '%oup' 804Group.find_by_sql("SELECT * FROM namespaces WHERE name LIKE '%oup'") 805=> [#<Group id:3 @test-group>, #<Group id:4 @template-group/template-subgroup>] 806``` 807 808## Routes 809 810### Remove redirecting routes 811 812See <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41758#note_54828133>. 813 814```ruby 815path = 'foo' 816conflicting_permanent_redirects = RedirectRoute.matching_path_and_descendants(path) 817 818# Check that conflicting_permanent_redirects is as expected 819conflicting_permanent_redirects.destroy_all 820``` 821 822## Merge Requests 823 824### Close a merge request properly (if merged but still marked as open) 825 826```ruby 827u = User.find_by_username('<username>') 828p = Project.find_by_full_path('<namespace/project>') 829m = p.merge_requests.find_by(iid: <iid>) 830MergeRequests::PostMergeService.new(project: p, current_user: u).execute(m) 831``` 832 833### Delete a merge request 834 835```ruby 836u = User.find_by_username('<username>') 837p = Project.find_by_full_path('<namespace/project>') 838m = p.merge_requests.find_by(iid: <iid>) 839Issuable::DestroyService.new(project: m.project, current_user: u).execute(m) 840``` 841 842### Rebase manually 843 844```ruby 845u = User.find_by_username('<username>') 846p = Project.find_by_full_path('<namespace/project>') 847m = p.merge_requests.find_by(iid: <iid>) 848MergeRequests::RebaseService.new(project: m.target_project, current_user: u).execute(m) 849``` 850 851## CI 852 853### Cancel stuck pending pipelines 854 855For more information, see the [confidential issue](../../user/project/issues/confidential_issues.md) 856`https://gitlab.com/gitlab-com/support-forum/issues/2449#note_41929707`. 857 858```ruby 859Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count 860Ci::Pipeline.where(project_id: p.id).where(status: 'pending').each {|p| p.cancel if p.stuck?} 861Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count 862``` 863 864### Remove artifacts more than a week old 865 866This section has been moved to the [job artifacts troubleshooting documentation](../job_artifacts.md#delete-job-artifacts-from-jobs-completed-before-a-specific-date). 867 868### Find reason failure (for when build trace is empty) (Introduced in 10.3.0) 869 870See <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41111>. 871 872```ruby 873build = Ci::Build.find(78420) 874 875build.failure_reason 876 877build.dependencies.each do |d| { puts "status: #{d.status}, finished at: #{d.finished_at}, 878 completed: #{d.complete?}, artifacts_expired: #{d.artifacts_expired?}, erased: #{d.erased?}" } 879``` 880 881### Try CI integration 882 883```ruby 884p = Project.find_by_full_path('<project_path>') 885m = project.merge_requests.find_by(iid: ) 886m.project.try(:ci_integration) 887``` 888 889### Validate the `.gitlab-ci.yml` 890 891```ruby 892project = Project.find_by_full_path 'group/project' 893content = project.repository.gitlab_ci_yml_for(project.repository.root_ref_sha) 894Gitlab::Ci::Lint.new(project: project, current_user: User.first).validate(content) 895``` 896 897### Disable AutoDevOps on Existing Projects 898 899```ruby 900Project.all.each do |p| 901 p.auto_devops_attributes={"enabled"=>"0"} 902 p.save 903end 904``` 905 906### Obtain runners registration token 907 908```ruby 909Gitlab::CurrentSettings.current_application_settings.runners_registration_token 910``` 911 912### Run pipeline schedules manually 913 914You can run pipeline schedules manually through the Rails console to reveal any errors that are usually not visible. 915 916```ruby 917# schedule_id can be obtained from Edit Pipeline Schedule page 918schedule = Ci::PipelineSchedule.find_by(id: <schedule_id>) 919 920# Select the user that you want to run the schedule for 921user = User.find_by_username('<username>') 922 923# Run the schedule 924ps = Ci::CreatePipelineService.new(schedule.project, user, ref: schedule.ref).execute!(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: schedule) 925``` 926 927## License 928 929### See current license information 930 931```ruby 932# License information (name, company, email address) 933License.current.licensee 934 935# Plan: 936License.current.plan 937 938# Uploaded: 939License.current.created_at 940 941# Started: 942License.current.starts_at 943 944# Expires at: 945License.current.expires_at 946 947# Is this a trial license? 948License.current.trial? 949``` 950 951### Check if a project feature is available on the instance 952 953Features listed in <https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb>. 954 955```ruby 956License.current.feature_available?(:jira_dev_panel_integration) 957``` 958 959### Check if a project feature is available in a project 960 961Features listed in [`license.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb). 962 963```ruby 964p = Project.find_by_full_path('<group>/<project>') 965p.feature_available?(:jira_dev_panel_integration) 966``` 967 968### Add a license through the console 969 970```ruby 971key = "<key>" 972license = License.new(data: key) 973license.save 974License.current # check to make sure it applied 975``` 976 977This is needed for example in a known edge-case with 978[expired license and multiple LDAP servers](../auth/ldap/ldap-troubleshooting.md#expired-license-causes-errors-with-multiple-ldap-servers). 979 980### Remove licenses 981 982To clean up the [License History table](../../user/admin_area/license.md#license-history): 983 984```ruby 985TYPE = :trial? 986# or :expired? 987 988License.select(&TYPE).each(&:destroy!) 989 990# or even License.all.each(&:destroy!) 991``` 992 993## Registry 994 995### Registry Disk Space Usage by Project 996 997As a GitLab administrator, you may need to reduce disk space consumption. 998A common culprit is Docker Registry images that are no longer in use. To find 999the storage broken down by each project, run the following in the 1000[GitLab Rails console](../troubleshooting/navigating_gitlab_via_rails_console.md): 1001 1002```ruby 1003projects_and_size = [["project_id", "creator_id", "registry_size_bytes", "project path"]] 1004# You need to specify the projects that you want to look through. You can get these in any manner. 1005projects = Project.last(100) 1006 1007projects.each do |p| 1008 project_total_size = 0 1009 container_repositories = p.container_repositories 1010 1011 container_repositories.each do |c| 1012 c.tags.each do |t| 1013 project_total_size = project_total_size + t.total_size unless t.total_size.nil? 1014 end 1015 end 1016 1017 if project_total_size > 0 1018 projects_and_size << [p.project_id, p.creator.id, project_total_size, p.full_path] 1019 end 1020end 1021 1022# projects_and_size is filled out now 1023# maybe print it as comma separated output? 1024projects_and_size.each do |ps| 1025 puts "%s,%s,%s,%s" % ps 1026end 1027``` 1028 1029### Run the Cleanup policy now 1030 1031Find this content in the [Container Registry troubleshooting docs](../packages/container_registry.md#run-the-cleanup-policy-now). 1032 1033## Sidekiq 1034 1035This content has been moved to the [Troubleshooting Sidekiq docs](sidekiq.md). 1036 1037## Redis 1038 1039### Connect to Redis (omnibus) 1040 1041```shell 1042/opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket 1043``` 1044 1045## LFS 1046 1047### Get information about LFS objects and associated project 1048 1049```ruby 1050o = LfsObject.find_by(oid: "<oid>") 1051p = Project.find(LfsObjectsProject.find_by_lfs_object_id(o.id).project_id) 1052``` 1053 1054You can then delete these records from the database with: 1055 1056```ruby 1057LfsObjectsProject.find_by_lfs_object_id(o.id).destroy 1058o.destroy 1059``` 1060 1061You would also want to combine this with deleting the LFS file in the LFS storage 1062area on disk. It remains to be seen exactly how or whether the deletion is useful, however. 1063 1064## Decryption Problems 1065 1066### Bad Decrypt Script (for encrypted variables) 1067 1068This content has been converted to a Rake task, see the [Doctor Rake tasks docs](../raketasks/doctor.md). 1069 1070As an example of repairing, if `ProjectImportData Bad count:` is detected and the decision is made to delete the 1071encrypted credentials to allow manual reentry: 1072 1073```ruby 1074 # Find the ids of the corrupt ProjectImportData objects 1075 total = 0 1076 bad = [] 1077 ProjectImportData.find_each do |data| 1078 begin 1079 total += 1 1080 data.credentials 1081 rescue => e 1082 bad << data.id 1083 end 1084 end 1085 1086 puts "Bad count: #{bad.count} / #{total}" 1087 1088 # See the bad ProjectImportData ids 1089 bad 1090 1091 # Remove the corrupted credentials 1092 import_data = ProjectImportData.where(id: bad) 1093 import_data.each do |data| 1094 data.update_columns({ encrypted_credentials: nil, encrypted_credentials_iv: nil, encrypted_credentials_salt: nil}) 1095 end 1096``` 1097 1098If `User OTP Secret Bad count:` is detected. For each user listed disable/enable 1099two-factor authentication. 1100 1101The following script searches in some of the tables for encrypted tokens that are 1102causing decryption errors, and update or reset as needed: 1103 1104```shell 1105wget -O /tmp/encrypted-tokens.rb https://gitlab.com/snippets/1876342/raw 1106gitlab-rails runner /tmp/encrypted-tokens.rb 1107``` 1108 1109### Decrypt Script for encrypted tokens 1110 1111This content has been converted to a Rake task, see the [Doctor Rake tasks docs](../raketasks/doctor.md). 1112 1113## Geo 1114 1115### Artifacts 1116 1117#### Find failed artifacts 1118 1119```ruby 1120Geo::JobArtifactRegistry.failed 1121``` 1122 1123#### Download artifact 1124 1125```ruby 1126Gitlab::Geo::JobArtifactDownloader.new(:job_artifact, <artifact_id>).execute 1127``` 1128 1129#### Get a count of the synced artifacts 1130 1131```ruby 1132Geo::JobArtifactRegistry.synced.count 1133``` 1134 1135#### Find `ID` of synced artifacts that are missing on primary 1136 1137```ruby 1138Geo::JobArtifactRegistry.synced.missing_on_primary.pluck(:artifact_id) 1139``` 1140 1141### Repository verification failures 1142 1143#### Get the number of verification failed repositories 1144 1145```ruby 1146Geo::ProjectRegistry.verification_failed('repository').count 1147``` 1148 1149#### Find the verification failed repositories 1150 1151```ruby 1152Geo::ProjectRegistry.verification_failed('repository') 1153``` 1154 1155### Find repositories that failed to sync 1156 1157```ruby 1158Geo::ProjectRegistry.sync_failed('repository') 1159``` 1160 1161### Resync repositories 1162 1163#### Queue up all repositories for resync. Sidekiq handles each sync 1164 1165```ruby 1166Geo::ProjectRegistry.update_all(resync_repository: true, resync_wiki: true) 1167``` 1168 1169#### Sync individual repository now 1170 1171```ruby 1172project = Project.find_by_full_path('<group/project>') 1173 1174Geo::RepositorySyncService.new(project).execute 1175``` 1176 1177### Blob types newer than uploads/artifacts/LFS 1178 1179- `Packages::PackageFile` 1180- `Terraform::StateVersion` 1181- `MergeRequestDiff` 1182 1183`Packages::PackageFile` is used in the following examples, but things generally work the same for the other Blob types. 1184 1185#### The Replicator 1186 1187The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it): 1188 1189```ruby 1190model_record = Packages::PackageFile.last 1191model_record.replicator.registry.replicator.model_record # just showing that these methods exist 1192``` 1193 1194#### Replicate a package file, synchronously, given an ID 1195 1196```ruby 1197model_record = Packages::PackageFile.find(id) 1198model_record.replicator.send(:download) 1199``` 1200 1201#### Replicate a package file, synchronously, given a registry ID 1202 1203```ruby 1204registry = Geo::PackageFileRegistry.find(registry_id) 1205registry.replicator.send(:download) 1206``` 1207 1208#### Verify package files on the secondary manually 1209 1210This iterates over all package files on the secondary, looking at the 1211`verification_checksum` stored in the database (which came from the primary) 1212and then calculate this value on the secondary to check if they match. This 1213does not change anything in the UI: 1214 1215```ruby 1216# Run on secondary 1217status = {} 1218 1219Packages::PackageFile.find_each do |package_file| 1220 primary_checksum = package_file.verification_checksum 1221 secondary_checksum = Packages::PackageFile.hexdigest(package_file.file.path) 1222 verification_status = (primary_checksum == secondary_checksum) 1223 1224 status[verification_status.to_s] ||= [] 1225 status[verification_status.to_s] << package_file.id 1226end 1227 1228# Count how many of each value we get 1229status.keys.each {|key| puts "#{key} count: #{status[key].count}"} 1230 1231# See the output in its entirety 1232status 1233``` 1234 1235### Repository types newer than project/wiki repositories 1236 1237- `SnippetRepository` 1238- `GroupWikiRepository` 1239 1240`SnippetRepository` is used in the examples below, but things generally work the same for the other Repository types. 1241 1242#### The Replicator 1243 1244The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it). 1245 1246```ruby 1247model_record = SnippetRepository.last 1248model_record.replicator.registry.replicator.model_record # just showing that these methods exist 1249``` 1250 1251#### Replicate a snippet repository, synchronously, given an ID 1252 1253```ruby 1254model_record = SnippetRepository.find(id) 1255model_record.replicator.send(:sync_repository) 1256``` 1257 1258#### Replicate a snippet repository, synchronously, given a registry ID 1259 1260```ruby 1261registry = Geo::SnippetRepositoryRegistry.find(registry_id) 1262registry.replicator.send(:sync_repository) 1263``` 1264 1265## Generate Service Ping 1266 1267The [Service Ping Guide](../../development/service_ping/index.md) in our developer documentation 1268has more information about Service Ping. 1269 1270### Generate or get the cached Service Ping 1271 1272```ruby 1273Gitlab::UsageData.to_json 1274``` 1275 1276### Generate a fresh new Service Ping 1277 1278This also refreshes the cached Service Ping displayed in the Admin Area 1279 1280```ruby 1281Gitlab::UsageData.to_json(force_refresh: true) 1282``` 1283 1284### Generate and print 1285 1286Generates Service Ping data in JSON format. 1287 1288```shell 1289rake gitlab:usage_data:generate 1290``` 1291 1292Generates Service Ping data in YAML format: 1293 1294```shell 1295rake gitlab:usage_data:dump_sql_in_yaml 1296``` 1297 1298### Generate and send Service Ping 1299 1300Prints the metrics saved in `conversational_development_index_metrics`. 1301 1302```shell 1303rake gitlab:usage_data:generate_and_send 1304``` 1305 1306## Kubernetes integration 1307 1308Find cluster: 1309 1310```ruby 1311cluster = Clusters::Cluster.find(1) 1312cluster = Clusters::Cluster.find_by(name: 'cluster_name') 1313``` 1314 1315Delete cluster without associated resources: 1316 1317```ruby 1318# Find users with the Administrator role 1319user = User.find_by(username: 'admin_user') 1320 1321# Find the cluster with the ID 1322cluster = Clusters::Cluster.find(1) 1323 1324# Delete the cluster 1325Clusters::DestroyService.new(user).execute(cluster) 1326``` 1327 1328## Elasticsearch 1329 1330### Configuration attributes 1331 1332Open the rails console (`gitlab rails c`) and run the following command to see all the available attributes: 1333 1334```ruby 1335ApplicationSetting.last.attributes 1336``` 1337 1338Among other attributes, the output contains all the settings available in the [Elasticsearch Integration page](../../integration/elasticsearch.md), such as `elasticsearch_indexing`, `elasticsearch_url`, `elasticsearch_replicas`, and `elasticsearch_pause_indexing`. 1339 1340#### Setting attributes 1341 1342You can then set anyone of Elasticsearch integration settings by issuing a command similar to: 1343 1344```ruby 1345ApplicationSetting.last.update(elasticsearch_url: '<your ES URL and port>') 1346 1347#or 1348 1349ApplicationSetting.last.update(elasticsearch_indexing: false) 1350``` 1351 1352#### Getting attributes 1353 1354You can then check if the settings have been set in the [Elasticsearch Integration page](../../integration/elasticsearch.md) or in the rails console by issuing: 1355 1356```ruby 1357Gitlab::CurrentSettings.elasticsearch_url 1358 1359#or 1360 1361Gitlab::CurrentSettings.elasticsearch_indexing 1362``` 1363