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