Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-08-25 00:09:18 +00:00
parent 18ca66076f
commit 42f9b96246
9 changed files with 244 additions and 31 deletions

View File

@ -3670,7 +3670,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/github_import/logger_spec.rb'
- 'spec/lib/gitlab/github_import/markdown_text_spec.rb'
- 'spec/lib/gitlab/github_import/milestone_finder_spec.rb'
- 'spec/lib/gitlab/github_import/object_counter_spec.rb'
- 'spec/lib/gitlab/github_import/parallel_importer_spec.rb'
- 'spec/lib/gitlab/github_import/representation/diff_note_spec.rb'
- 'spec/lib/gitlab/github_import/representation/diff_notes/suggestion_formatter_spec.rb'

View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
class AddCurrentUserTodosWidgetToEpicWorkItemType < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
EPIC_ENUM_VALUE = 7
WIDGET_NAME = 'Current user todos'
WIDGET_ENUM_VALUE = 15
class MigrationWorkItemType < MigrationRecord
self.table_name = 'work_item_types'
end
class MigrationWidgetDefinition < MigrationRecord
self.table_name = 'work_item_widget_definitions'
end
def up
epic_work_item_type = MigrationWorkItemType.find_by(base_type: EPIC_ENUM_VALUE, namespace_id: nil)
# Epic type should exist in production applications, checking here to avoid failures
# if inconsistent data is present.
return say('Epic work item type does not exist, skipping widget creation') unless epic_work_item_type
widgets = [
{
work_item_type_id: epic_work_item_type.id,
name: WIDGET_NAME,
widget_type: WIDGET_ENUM_VALUE
}
]
MigrationWidgetDefinition.upsert_all(
widgets,
unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
)
end
def down
epic_work_item_type = MigrationWorkItemType.find_by(base_type: EPIC_ENUM_VALUE, namespace_id: nil)
return say('Epic work item type does not exist, skipping widget removal') unless epic_work_item_type
widget_definition = MigrationWidgetDefinition.find_by(
work_item_type_id: epic_work_item_type.id,
widget_type: WIDGET_ENUM_VALUE,
name: WIDGET_NAME,
namespace_id: nil
)
return say('Widget definition not found, skipping widget removal') unless widget_definition
widget_definition.destroy
end
end

View File

@ -0,0 +1 @@
ab5b2cd527a1eb799f7f1c3d2f48c850853e498e50693dbe8148c08d52465da8

View File

@ -95,7 +95,14 @@ This causes all SSH requests to the newly promoted **primary** site to
fail due to SSH host key mismatch. To prevent this, the primary SSH host
keys must be manually replicated to the **secondary** site.
1. SSH into **each node on your secondary** site and login as the `root` user:
The SSH host key path depends on the used software:
- If you use OpenSSH, the path is `/etc/ssh`.
- If you use [`gitlab-sshd`](../../operations/gitlab_sshd.md), the path is `/var/opt/gitlab/gitlab-sshd`.
In the following steps, replace `<ssh_host_key_path>` with the one you're using:
1. SSH into **each Rails node on your secondary** site and log in as the `root` user:
```shell
sudo -i
@ -104,40 +111,40 @@ keys must be manually replicated to the **secondary** site.
1. Make a backup of any existing SSH host keys:
```shell
find /etc/ssh -iname 'ssh_host_*' -exec cp {} {}.backup.`date +%F` \;
find <ssh_host_key_path> -iname 'ssh_host_*' -exec cp {} {}.backup.`date +%F` \;
```
1. Copy OpenSSH host keys from the **primary** site:
1. Copy the SSH host keys from the **primary** site:
If you can access one of the **nodes on your primary** site serving SSH traffic (usually, the main GitLab Rails application nodes) using the **root** user:
```shell
# Run this from the secondary site, change `<primary_site_fqdn>` for the IP or FQDN of the server
scp root@<primary_node_fqdn>:/etc/ssh/ssh_host_*_key* /etc/ssh
scp root@<primary_node_fqdn>:<ssh_host_key_path>/ssh_host_*_key* <ssh_host_key_path>
```
If you only have access through a user with `sudo` privileges:
```shell
# Run this from the node on your primary site:
sudo tar --transform 's/.*\///g' -zcvf ~/geo-host-key.tar.gz /etc/ssh/ssh_host_*_key*
sudo tar --transform 's/.*\///g' -zcvf ~/geo-host-key.tar.gz <ssh_host_key_path>/ssh_host_*_key*
# Run this on each node on your secondary site:
scp <user_with_sudo>@<primary_site_fqdn>:geo-host-key.tar.gz .
tar zxvf ~/geo-host-key.tar.gz -C /etc/ssh
tar zxvf ~/geo-host-key.tar.gz -C <ssh_host_key_path>
```
1. On **each node on your secondary** site, ensure the file permissions are correct:
1. On **each Rails node on your secondary** site, ensure the file permissions are correct:
```shell
chown root:root /etc/ssh/ssh_host_*_key*
chmod 0600 /etc/ssh/ssh_host_*_key
chown root:root <ssh_host_key_path>/ssh_host_*_key*
chmod 0600 <ssh_host_key_path>/ssh_host_*_key
```
1. To verify key fingerprint matches, execute the following command on both primary and secondary nodes on each site:
```shell
for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
for file in <ssh_host_key_path>/ssh_host_*_key; do ssh-keygen -lf $file; done
```
You should get an output similar to this one and they should be identical on both nodes:
@ -153,24 +160,32 @@ keys must be manually replicated to the **secondary** site.
```shell
# This will print the fingerprint for private keys:
for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
for file in <ssh_host_key_path>/ssh_host_*_key; do ssh-keygen -lf $file; done
# This will print the fingerprint for public keys:
for file in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
for file in <ssh_host_key_path>/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
```
NOTE:
The output for private keys and public keys command should generate the same fingerprint.
1. Restart `sshd` on **each node on your secondary** site:
1. Restart either `sshd` for OpenSSH or the `gitlab-sshd` service on **each Rails node on your secondary** site:
```shell
# Debian or Ubuntu installations
sudo service ssh reload
- For OpenSSH:
# CentOS installations
sudo service sshd reload
```
```shell
# Debian or Ubuntu installations
sudo service ssh reload
# CentOS installations
sudo service sshd reload
```
- For `gitlab-sshd`:
```shell
sudo gitlab-ctl restart gitlab-sshd
```
1. Verify SSH is still functional.

View File

@ -46,13 +46,13 @@ To unlock a locked user:
sudo -u git -H bundle exec rails console -e production
```
1. Find the user to unlock. You can search by email or ID.
1. Find the user to unlock. You can search by email:
```ruby
user = User.find_by(email: 'admin@local.host')
```
or
Or you can search by ID:
```ruby
user = User.where(id: 1).first
@ -64,7 +64,7 @@ To unlock a locked user:
user.unlock_access!
```
1. Exit the console with <kbd>Control</kbd>+<kbd>d</kbd>
1. Exit the console with <kbd>Control</kbd>+<kbd>d</kbd>.
The user should now be able to sign in.

View File

@ -20,7 +20,7 @@ module Gitlab
requirement_legacy: 'Requirement legacy',
test_reports: 'Test reports',
notifications: 'Notifications',
current_user_todos: "Current user todos",
current_user_todos: 'Current user todos',
award_emoji: 'Award emoji',
linked_items: 'Linked items'
}.freeze
@ -124,6 +124,7 @@ module Gitlab
:health_status,
:status,
:notifications,
:current_user_todos,
:award_emoji,
:linked_items
],

View File

@ -14,6 +14,8 @@ module Gitlab
CACHING = Gitlab::Cache::Import::Caching
IMPORT_CACHING_TIMEOUT = 2.weeks.to_i
class << self
# Increments the project and the global counters if the given value is >= 1
def increment(project, object_type, operation, value: 1)
@ -50,7 +52,7 @@ module Gitlab
.sort
.each do |counter|
object_type = counter.split('/').last
result[operation][object_type] = CACHING.read_integer(counter)
result[operation][object_type] = CACHING.read_integer(counter) || 0
end
end
end
@ -84,11 +86,11 @@ module Gitlab
add_counter_to_list(project, operation, counter_key)
CACHING.increment_by(counter_key, value)
CACHING.increment_by(counter_key, value, timeout: IMPORT_CACHING_TIMEOUT)
end
def add_counter_to_list(project, operation, key)
CACHING.set_add(counter_list_key(project, operation), key)
CACHING.set_add(counter_list_key(project, operation), key, timeout: IMPORT_CACHING_TIMEOUT)
end
def counter_list_key(project, operation)

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache do
RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache, feature_category: :importers do
let_it_be(:project) { create(:project, :import_started, import_type: 'github', import_url: 'https://github.com/vim/vim.git') }
it 'validates the operation being incremented' do
@ -38,9 +38,6 @@ RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache do
expect(Gitlab::Metrics)
.not_to receive(:counter)
expect(Gitlab::Metrics)
.not_to receive(:counter)
described_class.increment(project, :issue, :fetched, value: 0)
described_class.increment(project, :issue, :imported, value: nil)
@ -73,6 +70,27 @@ RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache do
end
end
context 'when import is in progress but cache expired' do
before do
described_class.increment(project, :issue, :fetched, value: 10)
described_class.increment(project, :issue, :imported, value: 8)
allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(nil)
end
it 'returns 0 instead of nil so process can complete' do
expect(described_class.summary(project)).to eq(
{
"fetched" => {
"issue" => 0
},
"imported" => {
"issue" => 0
}
}
)
end
end
context 'when there are no cached import statistics' do
context 'when project import is in progress' do
it 'includes an empty object counts stats in response' do

View File

@ -0,0 +1,121 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe AddCurrentUserTodosWidgetToEpicWorkItemType, :migration, feature_category: :team_planning do
include MigrationHelpers::WorkItemTypesHelper
let(:work_item_types) { table(:work_item_types) }
let(:work_item_widget_definitions) { table(:work_item_widget_definitions) }
let(:base_types) do
{
issue: 0,
incident: 1,
test_case: 2,
requirement: 3,
task: 4,
objective: 5,
key_result: 6,
epic: 7
}
end
let(:epic_widgets) do
{
'Assignees' => 0,
'Description' => 1,
'Hierarchy' => 2,
'Labels' => 3,
'Notes' => 5,
'Start and due date' => 6,
'Health status' => 7,
'Status' => 11,
'Notifications' => 14,
'Award emoji' => 16
}.freeze
end
after(:all) do
# Make sure base types are recreated after running the migration
# because migration specs are not run in a transaction
reset_work_item_types
end
before do
reset_db_state_prior_to_migration
end
describe '#up' do
it 'adds current user todos widget to epic work item type', :aggregate_failures do
expect do
migrate!
end.to change { work_item_widget_definitions.count }.by(1)
epic_type = work_item_types.find_by(namespace_id: nil, base_type: described_class::EPIC_ENUM_VALUE)
created_widget = work_item_widget_definitions.last
expect(created_widget).to have_attributes(
widget_type: described_class::WIDGET_ENUM_VALUE,
name: described_class::WIDGET_NAME,
work_item_type_id: epic_type.id
)
end
context 'when epic type does not exist' do
it 'skips creating the new widget definition' do
work_item_types.where(namespace_id: nil, base_type: base_types[:epic]).delete_all
expect do
migrate!
end.to not_change(work_item_widget_definitions, :count)
end
end
end
describe '#down' do
it 'removes current user todos widget from epic work item type' do
migrate!
expect { schema_migrate_down! }.to change { work_item_widget_definitions.count }.by(-1)
end
end
def reset_db_state_prior_to_migration
# Database needs to be in a similar state as when this migration was created
work_item_types.delete_all
create_work_item!('Issue', :issue, 'issue-type-issue')
create_work_item!('Incident', :incident, 'issue-type-incident')
create_work_item!('Test Case', :test_case, 'issue-type-test-case')
create_work_item!('Requirement', :requirement, 'issue-type-requirements')
create_work_item!('Task', :task, 'issue-type-task')
create_work_item!('Objective', :objective, 'issue-type-objective')
create_work_item!('Key Result', :key_result, 'issue-type-keyresult')
epic_type = create_work_item!('Epic', :epic, 'issue-type-epic')
widgets = epic_widgets.map do |widget_name, widget_enum_value|
{
work_item_type_id: epic_type.id,
name: widget_name,
widget_type: widget_enum_value
}
end
# Creating all widgets for the type so the state in the DB is as close as possible to the actual state
work_item_widget_definitions.upsert_all(
widgets,
unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
)
end
def create_work_item!(type_name, base_type, icon_name)
work_item_types.create!(
name: type_name,
namespace_id: nil,
base_type: base_types[base_type],
icon_name: icon_name
)
end
end