Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
de92b67d77
commit
62cf14d9de
|
|
@ -1 +1 @@
|
|||
6abde2303696a63f9eec85365b144c3b208d8043
|
||||
2bde9ceaa35d824fa4a22cc04488da02f7522197
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
<script>
|
||||
import { GlFilteredSearch } from '@gitlab/ui';
|
||||
import { setUrlParams, visitUrl } from '~/lib/utils/url_utility';
|
||||
import { TOKENS, TOKEN_TYPES } from '../constants';
|
||||
import { initializeValues } from '../utils';
|
||||
|
||||
export default {
|
||||
name: 'AdminUsersFilterApp',
|
||||
components: {
|
||||
GlFilteredSearch,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
values: initializeValues(),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
availableTokens() {
|
||||
// Once a token is selected, discard the rest
|
||||
const tokenType = this.values.find(({ type }) => TOKEN_TYPES.includes(type))?.type;
|
||||
|
||||
if (tokenType) {
|
||||
return TOKENS.filter(({ type }) => type === tokenType);
|
||||
}
|
||||
|
||||
return TOKENS;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleSearch(filters) {
|
||||
const newParams = {};
|
||||
|
||||
filters?.forEach((filter) => {
|
||||
if (typeof filter === 'string') {
|
||||
newParams.search_query = filter;
|
||||
} else {
|
||||
newParams.filter = filter.value.data;
|
||||
}
|
||||
});
|
||||
|
||||
const newUrl = setUrlParams(newParams, window.location.href, true);
|
||||
visitUrl(newUrl);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-filtered-search
|
||||
v-model="values"
|
||||
:placeholder="s__('AdminUsers|Search by name, email, or username')"
|
||||
:available-tokens="availableTokens"
|
||||
class="gl-mb-4"
|
||||
terms-as-tokens
|
||||
@submit="handleSearch"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
import { GlFilteredSearchToken } from '@gitlab/ui';
|
||||
|
||||
import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import { s__, __ } from '~/locale';
|
||||
|
||||
export const I18N_USER_ACTIONS = {
|
||||
|
|
@ -21,63 +18,3 @@ export const I18N_USER_ACTIONS = {
|
|||
trust: s__('AdminUsers|Trust user'),
|
||||
untrust: s__('AdminUsers|Untrust user'),
|
||||
};
|
||||
|
||||
const OPTION_ADMINS = 'admins';
|
||||
const OPTION_2FA_ENABLED = 'two_factor_enabled';
|
||||
const OPTION_2FA_DISABLED = 'two_factor_disabled';
|
||||
const OPTION_EXTERNAL = 'external';
|
||||
const OPTION_BLOCKED = 'blocked';
|
||||
const OPTION_BANNED = 'banned';
|
||||
const OPTION_BLOCKED_PENDING_APPROVAL = 'blocked_pending_approval';
|
||||
const OPTION_DEACTIVATED = 'deactivated';
|
||||
const OPTION_WOP = 'wop';
|
||||
const OPTION_TRUSTED = 'trusted';
|
||||
|
||||
export const TOKEN_ACCESS_LEVEL = 'access_level';
|
||||
export const TOKEN_STATE = 'state';
|
||||
export const TOKEN_2FA = '2fa';
|
||||
|
||||
export const TOKEN_TYPES = [TOKEN_ACCESS_LEVEL, TOKEN_STATE, TOKEN_2FA];
|
||||
|
||||
export const TOKENS = [
|
||||
{
|
||||
title: s__('AdminUsers|Access level'),
|
||||
type: TOKEN_ACCESS_LEVEL,
|
||||
token: GlFilteredSearchToken,
|
||||
operators: OPERATORS_IS,
|
||||
unique: true,
|
||||
options: [
|
||||
{ value: OPTION_ADMINS, title: s__('AdminUsers|Administrator') },
|
||||
{ value: OPTION_EXTERNAL, title: s__('AdminUsers|External') },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: __('State'),
|
||||
type: TOKEN_STATE,
|
||||
token: GlFilteredSearchToken,
|
||||
operators: OPERATORS_IS,
|
||||
unique: true,
|
||||
options: [
|
||||
{ value: OPTION_BANNED, title: s__('AdminUsers|Banned') },
|
||||
{ value: OPTION_BLOCKED, title: s__('AdminUsers|Blocked') },
|
||||
{ value: OPTION_DEACTIVATED, title: s__('AdminUsers|Deactivated') },
|
||||
{
|
||||
value: OPTION_BLOCKED_PENDING_APPROVAL,
|
||||
title: s__('AdminUsers|Pending approval'),
|
||||
},
|
||||
{ value: OPTION_TRUSTED, title: s__('AdminUsers|Trusted') },
|
||||
{ value: OPTION_WOP, title: s__('AdminUsers|Without projects') },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: s__('AdminUsers|Two-factor authentication'),
|
||||
type: TOKEN_2FA,
|
||||
token: GlFilteredSearchToken,
|
||||
operators: OPERATORS_IS,
|
||||
unique: true,
|
||||
options: [
|
||||
{ value: OPTION_2FA_ENABLED, title: __('On') },
|
||||
{ value: OPTION_2FA_DISABLED, title: __('Off') },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import createDefaultClient from '~/lib/graphql';
|
|||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
import AdminUsersApp from './components/app.vue';
|
||||
import AdminUsersFilterApp from './components/admin_users_filter_app.vue';
|
||||
import DeleteUserModal from './components/modals/delete_user_modal.vue';
|
||||
import UserActions from './components/user_actions.vue';
|
||||
|
||||
|
|
@ -35,19 +34,12 @@ const initApp = (el, component, userPropKey, props = {}) => {
|
|||
});
|
||||
};
|
||||
|
||||
export const initAdminUsersFilterApp = () => {
|
||||
return new Vue({
|
||||
el: document.querySelector('#js-admin-users-filter-app'),
|
||||
render: (createElement) => createElement(AdminUsersFilterApp),
|
||||
});
|
||||
};
|
||||
export const initAdminUsersApp = (el = document.querySelector('#js-admin-users-app')) =>
|
||||
initApp(el, AdminUsersApp, 'users');
|
||||
|
||||
export const initAdminUserActions = (el = document.querySelector('#js-admin-user-actions')) =>
|
||||
initApp(el, UserActions, 'user', { showButtonLabels: true });
|
||||
|
||||
export const initAdminUsersApp = (el = document.querySelector('#js-admin-users-app')) =>
|
||||
initApp(el, AdminUsersApp, 'users');
|
||||
|
||||
export const initDeleteUserModals = () => {
|
||||
return new Vue({
|
||||
functional: true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
import { queryToObject } from '~/lib/utils/url_utility';
|
||||
import { TOKENS } from './constants';
|
||||
|
||||
export const generateUserPaths = (paths, id) => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(paths).map(([action, genericPath]) => {
|
||||
|
|
@ -8,33 +5,3 @@ export const generateUserPaths = (paths, id) => {
|
|||
}),
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize values based on the URL parameters
|
||||
* @param {string} query
|
||||
*/
|
||||
export function initializeValues(query = document.location.search) {
|
||||
const values = [];
|
||||
|
||||
const { filter, search_query: searchQuery } = queryToObject(query);
|
||||
|
||||
if (filter) {
|
||||
const token = TOKENS.find(({ options }) => options.some(({ value }) => value === filter));
|
||||
|
||||
if (token) {
|
||||
values.push({
|
||||
type: token.type,
|
||||
value: {
|
||||
data: filter,
|
||||
operator: token.operators[0].value,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (searchQuery) {
|
||||
values.push(searchQuery);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
GlForm,
|
||||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlFormText,
|
||||
GlCollapsibleListbox,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
|
|
@ -28,6 +29,7 @@ export default {
|
|||
GlForm,
|
||||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlFormText,
|
||||
GlCollapsibleListbox,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
|
|
@ -60,6 +62,10 @@ export default {
|
|||
},
|
||||
},
|
||||
i18n: {
|
||||
agentSelectorHelp: s__(
|
||||
'Environments|Select an agent with Kubernetes access to the project or group.',
|
||||
),
|
||||
agentSelectorLinkText: s__('Environments|How do I grant Kubernetes access?'),
|
||||
header: __('Environments'),
|
||||
helpNewMessage: ENVIRONMENT_NEW_HELP_TEXT,
|
||||
helpEditMessage: ENVIRONMENT_EDIT_HELP_TEXT,
|
||||
|
|
@ -75,6 +81,7 @@ export default {
|
|||
cancel: __('Cancel'),
|
||||
reset: __('Reset'),
|
||||
},
|
||||
agentSelectorHelpPagePath: helpPagePath('user/clusters/agent/user_access.md'),
|
||||
environmentsHelpPagePath: helpPagePath('ci/environments/index.md'),
|
||||
renamingDisabledHelpPagePath: helpPagePath('ci/environments/index.md', {
|
||||
anchor: 'rename-an-environment',
|
||||
|
|
@ -283,6 +290,12 @@ export default {
|
|||
@select="onAgentChange"
|
||||
@reset="onChange({ ...environment, clusterAgentId: null })"
|
||||
/>
|
||||
<gl-form-text>
|
||||
{{ $options.i18n.agentSelectorHelp }}
|
||||
<gl-link :href="$options.agentSelectorHelpPagePath" target="_blank"
|
||||
>{{ $options.i18n.agentSelectorLinkText }}
|
||||
</gl-link>
|
||||
</gl-form-text>
|
||||
</gl-form-group>
|
||||
|
||||
<environment-namespace-selector
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<section>
|
||||
<h4 class="gl-mt-0">
|
||||
<h4 v-if="section.title" class="gl-mt-0">
|
||||
{{ section.title
|
||||
}}<gl-badge
|
||||
v-if="section.plan"
|
||||
|
|
|
|||
|
|
@ -48,10 +48,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div class="discussion-with-resolve-btn clearfix">
|
||||
<discussion-reply-placeholder
|
||||
data-testid="discussion-reply-tab"
|
||||
@focus="$emit('showReplyForm')"
|
||||
/>
|
||||
<discussion-reply-placeholder @focus="$emit('showReplyForm')" />
|
||||
|
||||
<div v-if="userCanResolveDiscussion" class="btn-group discussion-actions" role="group">
|
||||
<div class="btn-group">
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
<script>
|
||||
import { GlFormInput } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
name: 'ReplyPlaceholder',
|
||||
components: {
|
||||
GlFormInput,
|
||||
},
|
||||
props: {
|
||||
placeholderText: {
|
||||
type: String,
|
||||
|
|
@ -19,12 +23,11 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<textarea
|
||||
ref="textarea"
|
||||
rows="1"
|
||||
class="reply-placeholder-text-field js-vue-discussion-reply"
|
||||
<gl-form-input
|
||||
class="reply-placeholder-input-field"
|
||||
data-testid="discussion-reply-tab"
|
||||
:placeholder="placeholderText"
|
||||
:aria-label="labelText"
|
||||
@focus="$emit('focus')"
|
||||
></textarea>
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -78,7 +78,9 @@ export default {
|
|||
|
||||
<template>
|
||||
<div data-testid="container-expiration-policy-project-settings">
|
||||
<h4 data-testid="title">{{ $options.i18n.CONTAINER_CLEANUP_POLICY_TITLE }}</h4>
|
||||
<h3 data-testid="title" class="gl-heading-3 gl-mt-3!">
|
||||
{{ $options.i18n.CONTAINER_CLEANUP_POLICY_TITLE }}
|
||||
</h3>
|
||||
<p data-testid="description">
|
||||
<gl-sprintf :message="$options.i18n.CONTAINER_CLEANUP_POLICY_DESCRIPTION">
|
||||
<template #link="{ content }">
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
<section class="settings-section">
|
||||
<div class="settings-sticky-header">
|
||||
<div class="settings-sticky-header-inner">
|
||||
<h4 class="gl-my-0">
|
||||
<h3 class="gl-heading-3 gl-mb-0!">
|
||||
<slot name="title"></slot>
|
||||
</h4>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p class="gl-text-secondary">
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
import {
|
||||
initAdminUsersApp,
|
||||
initAdminUsersFilterApp,
|
||||
initDeleteUserModals,
|
||||
initAdminUserActions,
|
||||
} from '~/admin/users';
|
||||
import { initAdminUsersApp, initDeleteUserModals, initAdminUserActions } from '~/admin/users';
|
||||
import initConfirmModal from '~/confirm_modal';
|
||||
|
||||
initAdminUsersApp();
|
||||
initAdminUsersFilterApp();
|
||||
initAdminUserActions();
|
||||
initDeleteUserModals();
|
||||
initConfirmModal();
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ export default {
|
|||
'ProjectSettings|Highlight the usage of hidden unicode characters. These have innocent uses for right-to-left languages, but can also be used in potential exploits.',
|
||||
),
|
||||
confirmButtonText: __('Save changes'),
|
||||
emailsLabel: s__('ProjectSettings|Email notifications'),
|
||||
showDiffPreviewLabel: s__('ProjectSettings|Include diff previews'),
|
||||
showDiffPreviewHelpText: s__(
|
||||
'ProjectSettings|Emails are not encrypted. Concerned administrators may want to disable diff previews.',
|
||||
),
|
||||
},
|
||||
VISIBILITY_LEVEL_PRIVATE_INTEGER,
|
||||
VISIBILITY_LEVEL_INTERNAL_INTEGER,
|
||||
|
|
@ -125,6 +130,11 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
canSetDiffPreviewInEmail: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
canChangeVisibilityLevel: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -282,6 +292,7 @@ export default {
|
|||
enforceAuthChecksOnUploads: true,
|
||||
highlightChangesClass: false,
|
||||
emailsEnabled: true,
|
||||
showDiffPreviewInEmail: true,
|
||||
cveIdRequestEnabled: true,
|
||||
featureAccessLevelEveryone,
|
||||
featureAccessLevelMembers,
|
||||
|
|
@ -382,6 +393,14 @@ export default {
|
|||
monitorOperationsFeatureAccessLevelOptions() {
|
||||
return this.featureAccessLevelOptions.filter(([value]) => value <= this.monitorAccessLevel);
|
||||
},
|
||||
findDiffPreviewValue: {
|
||||
get() {
|
||||
return this.emailsEnabled && this.showDiffPreviewInEmail;
|
||||
},
|
||||
set(newValue) {
|
||||
this.showDiffPreviewInEmail = newValue;
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
|
@ -1021,8 +1040,10 @@ export default {
|
|||
/>
|
||||
</project-setting-row>
|
||||
</div>
|
||||
|
||||
<project-setting-row v-if="canDisableEmails" ref="email-settings" class="mb-3">
|
||||
<label class="js-emails-enabled">
|
||||
<h5>{{ $options.i18n.emailsLabel }}</h5>
|
||||
<input
|
||||
:value="emailsEnabled"
|
||||
type="hidden"
|
||||
|
|
@ -1035,6 +1056,21 @@ export default {
|
|||
}}</template>
|
||||
</gl-form-checkbox>
|
||||
</label>
|
||||
<project-setting-row
|
||||
v-if="canSetDiffPreviewInEmail"
|
||||
ref="enable-diff-preview-settings"
|
||||
class="gl-px-7"
|
||||
>
|
||||
<input
|
||||
:value="findDiffPreviewValue"
|
||||
type="hidden"
|
||||
name="project[project_setting_attributes][show_diff_preview_in_email]"
|
||||
/>
|
||||
<gl-form-checkbox v-model="findDiffPreviewValue" :disabled="!emailsEnabled">
|
||||
{{ $options.i18n.showDiffPreviewLabel }}
|
||||
<template #help>{{ $options.i18n.showDiffPreviewHelpText }}</template>
|
||||
</gl-form-checkbox>
|
||||
</project-setting-row>
|
||||
</project-setting-row>
|
||||
<project-setting-row class="mb-3">
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -387,11 +387,3 @@ input[type='search'] {
|
|||
}
|
||||
}
|
||||
/* stylelint-enable property-no-vendor-prefix */
|
||||
|
||||
.admin-users-search {
|
||||
grid-template-columns: 1fr auto;
|
||||
|
||||
.gl-filtered-search-term-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -358,6 +358,12 @@ table {
|
|||
border: 1px solid $gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-placeholder-input-field {
|
||||
@include media-breakpoint-down(xs) {
|
||||
margin-bottom: $gl-padding-8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.comment-toolbar {
|
||||
|
|
|
|||
|
|
@ -49,9 +49,6 @@ class Import::BitbucketServerController < Import::BaseController
|
|||
session[bitbucket_server_username_key] = params[:bitbucket_server_username]
|
||||
session[bitbucket_server_url_key] = params[:bitbucket_server_url]
|
||||
|
||||
experiment(:default_to_import_tab, actor: current_user)
|
||||
.track(:authentication, property: provider_name)
|
||||
|
||||
redirect_to status_import_bitbucket_server_path(namespace_id: params[:namespace_id])
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,6 @@ class Import::FogbugzController < Import::BaseController
|
|||
session[:fogbugz_token] = res.get_token.to_s
|
||||
session[:fogbugz_uri] = params[:uri]
|
||||
|
||||
experiment(:default_to_import_tab, actor: current_user)
|
||||
.track(:successfully_authenticated, property: provider_name)
|
||||
|
||||
redirect_to new_user_map_import_fogbugz_path(namespace_id: params[:namespace_id])
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@ class Import::GithubController < Import::BaseController
|
|||
end
|
||||
|
||||
def personal_access_token
|
||||
experiment(:default_to_import_tab, actor: current_user)
|
||||
.track(:authentication, property: provider_name)
|
||||
|
||||
session[access_token_key] = params[:personal_access_token]&.strip
|
||||
redirect_to status_import_url
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ class Import::GitlabProjectsController < Import::BaseController
|
|||
@project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute
|
||||
|
||||
if @project.saved?
|
||||
experiment(:default_to_import_tab, actor: current_user)
|
||||
.track(:successfully_imported, property: 'gitlab_export')
|
||||
|
||||
redirect_to(
|
||||
project_path(@project),
|
||||
notice: _("Project '%{project_name}' is being imported.") % { project_name: @project.name }
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ class Import::ManifestController < Import::BaseController
|
|||
if manifest.valid?
|
||||
manifest_import_metadata.save(manifest.projects, group.id)
|
||||
|
||||
experiment(:default_to_import_tab, actor: current_user)
|
||||
.track(:successfully_imported, property: provider_name)
|
||||
|
||||
redirect_to status_import_manifest_path
|
||||
else
|
||||
@errors = manifest.errors
|
||||
|
|
|
|||
|
|
@ -469,6 +469,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
def project_setting_attributes
|
||||
%i[
|
||||
show_default_award_emojis
|
||||
show_diff_preview_in_email
|
||||
squash_option
|
||||
mr_default_target_self
|
||||
warn_about_potentially_unwanted_characters
|
||||
|
|
|
|||
|
|
@ -74,3 +74,5 @@ module UserSettings
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
UserSettings::PersonalAccessTokensController.prepend_mod
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
# label_name: string
|
||||
# sort: string
|
||||
# non_archived: boolean
|
||||
# merged_without_event_source: boolean
|
||||
# my_reaction_emoji: string
|
||||
# source_branch: string
|
||||
# target_branch: string
|
||||
|
|
@ -78,6 +79,7 @@ class MergeRequestsFinder < IssuableFinder
|
|||
items = by_deployments(items)
|
||||
items = by_reviewer(items)
|
||||
items = by_source_project_id(items)
|
||||
items = by_resource_event_state(items)
|
||||
|
||||
by_approved(items)
|
||||
end
|
||||
|
|
@ -164,6 +166,12 @@ class MergeRequestsFinder < IssuableFinder
|
|||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def by_resource_event_state(items)
|
||||
return items unless params[:merged_without_event_source].present?
|
||||
|
||||
items.merged_without_state_event_source
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def by_draft(items)
|
||||
draft_param = Gitlab::Utils.to_boolean(params.fetch(:draft) { params.fetch(:wip, nil) })
|
||||
|
|
|
|||
|
|
@ -21,6 +21,13 @@ module GroupsHelper
|
|||
can?(current_user, :set_emails_disabled, group) && !group.parent&.emails_disabled?
|
||||
end
|
||||
|
||||
def can_set_group_diff_preview_in_email?(group)
|
||||
return false unless Feature.enabled?(:diff_preview_in_email, group)
|
||||
return false if group.parent&.show_diff_preview_in_email?.equal?(false)
|
||||
|
||||
can?(current_user, :set_show_diff_preview_in_email, group)
|
||||
end
|
||||
|
||||
def can_admin_group_member?(group)
|
||||
Ability.allowed?(current_user, :admin_group_member, group)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ module MarkupHelper
|
|||
# as Markdown. HTML tags in the parsed output are not counted toward the
|
||||
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
||||
# the tag contents are truncated without removing the closing tag.
|
||||
def first_line_in_markdown(object, attribute, max_chars = nil, is_todo: false, **options)
|
||||
def first_line_in_markdown(object, attribute, max_chars = nil, **options)
|
||||
md = markdown_field(object, attribute, options.merge(post_process: false))
|
||||
return unless md.present?
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,13 @@ module ProjectsHelper
|
|||
can?(current_user, :set_emails_disabled, project)
|
||||
end
|
||||
|
||||
def can_set_diff_preview_in_email?(project, current_user)
|
||||
return false unless Feature.enabled?(:diff_preview_in_email, project.group)
|
||||
return false if project.group&.show_diff_preview_in_email?.equal?(false)
|
||||
|
||||
can?(current_user, :set_show_diff_preview_in_email, project)
|
||||
end
|
||||
|
||||
def last_push_event
|
||||
current_user&.recent_push(@project)
|
||||
end
|
||||
|
|
@ -387,6 +394,7 @@ module ProjectsHelper
|
|||
packagesHelpPath: help_page_path('user/packages/index'),
|
||||
currentSettings: project_permissions_settings(project),
|
||||
canAddCatalogResource: can_add_catalog_resource?(project),
|
||||
canSetDiffPreviewInEmail: can_set_diff_preview_in_email?(project, current_user),
|
||||
canChangeVisibilityLevel: can_change_visibility_level?(project, current_user),
|
||||
canDisableEmails: can_disable_emails?(project, current_user),
|
||||
allowedVisibilityOptions: project_allowed_visibility_levels(project),
|
||||
|
|
@ -767,6 +775,7 @@ module ProjectsHelper
|
|||
containerRegistryEnabled: !!project.container_registry_enabled,
|
||||
lfsEnabled: !!project.lfs_enabled,
|
||||
emailsEnabled: project.emails_enabled?,
|
||||
showDiffPreviewInEmail: project.show_diff_preview_in_email?,
|
||||
monitorAccessLevel: feature.monitor_access_level,
|
||||
showDefaultAwardEmojis: project.show_default_award_emojis?,
|
||||
warnAboutPotentiallyUnwantedCharacters: project.warn_about_potentially_unwanted_characters?,
|
||||
|
|
|
|||
|
|
@ -350,12 +350,6 @@ module UsersHelper
|
|||
def preload_project_associations(_)
|
||||
# Overridden in EE
|
||||
end
|
||||
|
||||
def admin_user_tab_classes
|
||||
return 'js-users-tabs gl-w-full' unless request.path == admin_users_path
|
||||
|
||||
'js-users-tabs gl-w-full gl-border-0'
|
||||
end
|
||||
end
|
||||
|
||||
UsersHelper.prepend_mod_with('UsersHelper')
|
||||
|
|
|
|||
|
|
@ -481,6 +481,11 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
}
|
||||
|
||||
scope :merged_without_state_event_source, -> {
|
||||
joins(:resource_state_events)
|
||||
.merge(ResourceStateEvent.merged_with_no_event_source)
|
||||
}
|
||||
|
||||
def self.total_time_to_merge
|
||||
join_metrics
|
||||
.where(
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ class NamespaceSetting < ApplicationRecord
|
|||
all_ancestors_have_emails_enabled?
|
||||
end
|
||||
|
||||
# Where this function is used, a returned "nil" is considered a truthy value
|
||||
def show_diff_preview_in_email?
|
||||
return show_diff_preview_in_email unless namespace.has_parent?
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ class ResourceStateEvent < ResourceEvent
|
|||
|
||||
after_create :issue_usage_metrics
|
||||
|
||||
scope :merged_with_no_event_source, -> do
|
||||
where(state: :merged, source_merge_request: nil, source_commit: nil)
|
||||
end
|
||||
|
||||
def self.issuable_attrs
|
||||
%i[issue merge_request].freeze
|
||||
end
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ class StateNote < SyntheticNote
|
|||
end
|
||||
end
|
||||
|
||||
return "merged manually" if event.state == 'merged' && event_source.is_a?(Commit)
|
||||
|
||||
body = event.state.dup
|
||||
body << " via #{event_source.gfm_reference(project)}" if event_source
|
||||
body
|
||||
|
|
|
|||
|
|
@ -349,12 +349,7 @@ class IssuableBaseService < ::BaseContainerService
|
|||
|
||||
issuable.updated_by = current_user if should_touch
|
||||
|
||||
# `issuable` could create a ghost user when updating `last_edited_by`.
|
||||
# Users::Internal.ghost will obtain an ExclusiveLease within this transaction.
|
||||
# See issue: https://gitlab.com/gitlab-org/gitlab/-/issues/441526
|
||||
Gitlab::ExclusiveLease.skipping_transaction_check do
|
||||
transaction_update(issuable, { save_with_touch: should_touch })
|
||||
end
|
||||
transaction_update(issuable, { save_with_touch: should_touch })
|
||||
end
|
||||
|
||||
if issuable_saved
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module MergeRequests
|
|||
|
||||
MAX_RETARGET_MERGE_REQUESTS = 4
|
||||
|
||||
def execute(merge_request)
|
||||
def execute(merge_request, source = nil)
|
||||
return if merge_request.merged?
|
||||
|
||||
# Mark the merge request as merged, everything that happens afterwards is
|
||||
|
|
@ -23,7 +23,7 @@ module MergeRequests
|
|||
|
||||
merge_request_activity_counter.track_merge_mr_action(user: current_user)
|
||||
|
||||
create_note(merge_request)
|
||||
create_note(merge_request, source)
|
||||
close_issues(merge_request)
|
||||
notification_service.merge_mr(merge_request, current_user)
|
||||
invalidate_cache_counts(merge_request, users: merge_request.assignees | merge_request.reviewers)
|
||||
|
|
@ -37,6 +37,16 @@ module MergeRequests
|
|||
execute_hooks(merge_request, 'merge')
|
||||
end
|
||||
|
||||
def create_note(merge_request, source)
|
||||
SystemNoteService.change_status(
|
||||
merge_request,
|
||||
merge_request.target_project,
|
||||
current_user,
|
||||
merge_request.state,
|
||||
source
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def close_issues(merge_request)
|
||||
|
|
|
|||
|
|
@ -98,9 +98,24 @@ module MergeRequests
|
|||
merge_request.merge_commit_sha = sha
|
||||
merge_request.merged_commit_sha = sha
|
||||
|
||||
# Look for a merged MR that includes the SHA to associate it with
|
||||
# the MR we're about to mark as merged.
|
||||
# Only the merged MRs without the event source would be considered
|
||||
# to avoid associating it with other MRs that we may have marked as merged here.
|
||||
source_merge_request = MergeRequestsFinder.new(
|
||||
@current_user,
|
||||
project_id: @project.id,
|
||||
merged_without_event_source: true,
|
||||
state: 'merged',
|
||||
sort: 'merged_at',
|
||||
commit_sha: sha
|
||||
).execute.first
|
||||
|
||||
source = source_merge_request || @project.commit(sha)
|
||||
|
||||
MergeRequests::PostMergeService
|
||||
.new(project: merge_request.target_project, current_user: @current_user)
|
||||
.execute(merge_request)
|
||||
.execute(merge_request, source)
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
= gl_tabs_nav({ class: admin_user_tab_classes }) do
|
||||
= gl_tabs_nav({ class: 'js-users-tabs' }) do
|
||||
= gl_tab_link_to s_('AdminUsers|Users'), admin_users_path
|
||||
= gl_tab_link_to s_('AdminUsers|Cohorts'), admin_cohorts_path
|
||||
|
|
|
|||
|
|
@ -7,11 +7,66 @@
|
|||
- c.with_body do
|
||||
= render 'shared/registration_features_discovery_message', feature_title: s_('RegistrationFeatures|send emails to users')
|
||||
|
||||
.admin-users-search.row-content-block.gl-lg-display-grid.gl-border-bottom-0.gl-border-top-0{ data: { testid: "filtered-search-block" } }
|
||||
#js-admin-users-filter-app.gl-mb-4
|
||||
.dropdown.gl-lg-ml-3
|
||||
= label_tag s_('AdminUsers|Sort by')
|
||||
= gl_redirect_listbox_tag admin_users_sort_options(filter: params[:filter], search_query: params[:search_query]), @sort, data: { placement: 'right' }
|
||||
.top-area
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
|
||||
%button.fade-left{ type: 'button', title: _('Scroll left'), 'aria-label': _('Scroll left') }
|
||||
= sprite_icon('chevron-lg-left', size: 12)
|
||||
%button.fade-right{ type: 'button', title: _('Scroll right'), 'aria-label': _('Scroll right') }
|
||||
= sprite_icon('chevron-lg-right', size: 12)
|
||||
= gl_tabs_nav({ class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-w-full' }) do
|
||||
= gl_tab_link_to admin_users_path, { item_active: active_when(params[:filter].nil?), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|Active')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.active_without_ghosts))
|
||||
= gl_tab_link_to admin_users_path(filter: "admins"), { item_active: active_when(params[:filter] == 'admins'), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|Admins')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.admins))
|
||||
= gl_tab_link_to admin_users_path(filter: 'two_factor_enabled'), { item_active: active_when(params[:filter] == 'two_factor_enabled'), class: 'filter-two-factor-enabled gl-border-0!' } do
|
||||
= s_('AdminUsers|2FA Enabled')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.with_two_factor))
|
||||
= gl_tab_link_to admin_users_path(filter: 'two_factor_disabled'), { item_active: active_when(params[:filter] == 'two_factor_disabled'), class: 'filter-two-factor-disabled gl-border-0!' } do
|
||||
= s_('AdminUsers|2FA Disabled')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.without_two_factor))
|
||||
= gl_tab_link_to admin_users_path(filter: 'external'), { item_active: active_when(params[:filter] == 'external'), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|External')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.external))
|
||||
= gl_tab_link_to admin_users_path(filter: "blocked"), { item_active: active_when(params[:filter] == 'blocked'), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|Blocked')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.blocked))
|
||||
= gl_tab_link_to admin_users_path(filter: "banned"), { item_active: active_when(params[:filter] == 'banned'), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|Banned')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.banned))
|
||||
= gl_tab_link_to admin_users_path(filter: "blocked_pending_approval"), { item_active: active_when(params[:filter] == 'blocked_pending_approval'), class: 'filter-blocked-pending-approval gl-border-0!', data: { testid: 'pending-approval-tab' } } do
|
||||
= s_('AdminUsers|Pending approval')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.blocked_pending_approval))
|
||||
= gl_tab_link_to admin_users_path(filter: "deactivated"), { item_active: active_when(params[:filter] == 'deactivated'), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|Deactivated')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.deactivated))
|
||||
= gl_tab_link_to admin_users_path(filter: "wop"), { item_active: active_when(params[:filter] == 'wop'), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|Without projects')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.without_projects))
|
||||
= gl_tab_link_to admin_users_path(filter: "trusted"), { item_active: active_when(params[:filter] == 'trusted'), class: 'gl-border-0!' } do
|
||||
= s_('AdminUsers|Trusted')
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(User.trusted))
|
||||
.nav-controls
|
||||
= render_if_exists 'admin/users/admin_email_users'
|
||||
= render_if_exists 'admin/users/admin_export_user_permissions'
|
||||
= render Pajamas::ButtonComponent.new(variant: :confirm, href: new_admin_user_path) do
|
||||
= s_('AdminUsers|New user')
|
||||
|
||||
.row-content-block.gl-border-0{ data: { testid: "filtered-search-block" } }
|
||||
= form_tag admin_users_path, method: :get do
|
||||
- if params[:filter].present?
|
||||
= hidden_field_tag "filter", h(params[:filter])
|
||||
.search-holder
|
||||
.search-field-holder
|
||||
= search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email, or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { testid: 'user-search-field' }
|
||||
- if @sort.present?
|
||||
= hidden_field_tag :sort, @sort
|
||||
= sprite_icon('search', css_class: 'search-icon')
|
||||
= button_tag s_('AdminUsers|Search users') if Rails.env.test?
|
||||
.dropdown.gl-sm-ml-3
|
||||
= label_tag s_('AdminUsers|Sort by')
|
||||
= gl_redirect_listbox_tag admin_users_sort_options(filter: params[:filter], search_query: params[:search_query]), @sort, data: { placement: 'right' }
|
||||
|
||||
#js-admin-users-app{ data: admin_users_data_attributes(@users) }
|
||||
= render Pajamas::SpinnerComponent.new(size: :lg, class: 'gl-my-7')
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
- page_title _("Users")
|
||||
|
||||
.top-area.gl-display-flex.justify-content-between
|
||||
= render 'tabs'
|
||||
.nav-controls.gl-mt-3
|
||||
= render_if_exists 'admin/users/admin_email_users'
|
||||
= render_if_exists 'admin/users/admin_export_user_permissions'
|
||||
= render Pajamas::ButtonComponent.new(variant: :confirm, href: new_admin_user_path) do
|
||||
= s_('AdminUsers|New user')
|
||||
= render 'tabs'
|
||||
|
||||
.tab-content
|
||||
.tab-pane.active
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
\.
|
||||
- if todo.note.present?
|
||||
%span.action-description<
|
||||
= first_line_in_markdown(todo, :body, 125, is_todo: true, project: todo.project, group: todo.group)
|
||||
= first_line_in_markdown(todo, :body, 125, project: todo.project, group: todo.group)
|
||||
|
||||
= render_if_exists "dashboard/todos/review_summary", local_assigns: { todo: todo }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
%h5= _('Email notifications')
|
||||
|
||||
.form-group.gl-mb-3
|
||||
= f.gitlab_ui_checkbox_component :emails_enabled,
|
||||
s_('GroupSettings|Enable email notifications'),
|
||||
checkbox_options: { checked: @group.emails_enabled?, disabled: !can_disable_group_emails?(@group) },
|
||||
help_text: s_('GroupSettings|Enable sending email notifications for this group and all its subgroups and projects')
|
||||
- if Feature.enabled?(:diff_preview_in_email, @group)
|
||||
.gl-px-7
|
||||
= f.gitlab_ui_checkbox_component :show_diff_preview_in_email,
|
||||
s_('GroupSettings|Include diff previews'),
|
||||
checkbox_options: { checked: @group.show_diff_preview_in_email? & @group.emails_enabled?,
|
||||
disabled: !@group.emails_enabled? || !can_set_group_diff_preview_in_email?(@group) },
|
||||
help_text: s_('GroupSettings|Emails are not encrypted. Concerned administrators may want to disable diff previews.')
|
||||
|
|
@ -17,12 +17,6 @@
|
|||
checkbox_options: { disabled: !can_change_share_with_group_lock?(@group) },
|
||||
help_text: share_with_group_lock_help_text(@group)
|
||||
|
||||
.form-group.gl-mb-3
|
||||
= f.gitlab_ui_checkbox_component :emails_enabled,
|
||||
s_('GroupSettings|Enable email notifications'),
|
||||
checkbox_options: { checked: @group.emails_enabled?, disabled: !can_disable_group_emails?(@group) },
|
||||
help_text: s_('GroupSettings|Enable sending email notifications for this group and all its subgroups and projects')
|
||||
|
||||
.form-group.gl-mb-3
|
||||
= f.gitlab_ui_checkbox_component :mentions_disabled,
|
||||
s_('GroupSettings|Group mentions are disabled'),
|
||||
|
|
@ -30,6 +24,7 @@
|
|||
help_text: s_('GroupSettings|Group members are not notified if the group is mentioned.')
|
||||
|
||||
= render 'groups/settings/resource_access_token_creation', f: f, group: @group
|
||||
= render 'groups/settings/email_settings', f: f, group: @group
|
||||
= render 'groups/settings/ip_restriction_registration_features_cta', f: f
|
||||
= render_if_exists 'groups/settings/ip_restriction', f: f, group: @group
|
||||
= render_if_exists 'groups/settings/allowed_email_domain', f: f, group: @group
|
||||
|
|
@ -50,6 +45,7 @@
|
|||
= render 'groups/settings/two_factor_auth', f: f, group: @group
|
||||
= render_if_exists 'groups/personal_access_token_expiration_policy', f: f, group: @group
|
||||
= render 'groups/settings/membership', f: f, group: @group
|
||||
= render_if_exists 'groups/settings/personal_access_tokens', f: f, group: @group
|
||||
|
||||
%h5= _('Customer relations')
|
||||
.form-group.gl-mb-3
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
- note = local_assigns.fetch(:note, @note)
|
||||
- show_no_diff_preview_message = true
|
||||
- unless note.nil?
|
||||
- discussion = local_assigns.fetch(:discussion) { note.discussion } if note.part_of_discussion?
|
||||
- project = local_assigns.fetch(:project, @project)
|
||||
- show_no_diff_preview_message = discussion&.diff_discussion? && discussion.on_text? && !project.show_diff_preview_in_email?
|
||||
|
||||
%html{ lang: I18n.locale }
|
||||
%head
|
||||
%meta{ content: "text/html; charset=utf-8", "http-equiv" => "Content-Type" }
|
||||
|
|
@ -20,6 +27,9 @@
|
|||
%p
|
||||
—
|
||||
%br
|
||||
- if show_no_diff_preview_message
|
||||
= _('This project does not include diff previews in email notifications.')
|
||||
%br
|
||||
- if @target_url
|
||||
- if @reply_by_email
|
||||
= _('Reply to this email directly or %{view_it_on_gitlab}.').html_safe % { view_it_on_gitlab: link_to(_("view it on GitLab"), @target_url) }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,18 @@
|
|||
<% note = local_assigns.fetch(:note, @note) -%>
|
||||
<% show_no_diff_preview_message = true -%>
|
||||
<% unless @note.nil? -%>
|
||||
<% discussion = local_assigns.fetch(:discussion) { note.discussion } if note.part_of_discussion? -%>
|
||||
<% project = local_assigns.fetch(:project, @project) -%>
|
||||
<% show_no_diff_preview_message = discussion&.diff_discussion? && discussion.on_text? && !project.show_diff_preview_in_email? -%>
|
||||
<% end -%>
|
||||
<%= text_header_message %>
|
||||
|
||||
<%= yield -%>
|
||||
|
||||
-- <%# signature marker %>
|
||||
<% if show_no_diff_preview_message -%>
|
||||
<%= "This project does not include diff previews in email notifications.\n" -%>
|
||||
<% end -%>
|
||||
<% if @target_url -%>
|
||||
<% if @reply_by_email -%>
|
||||
<%= "Reply to this email directly or view it on GitLab: #{@target_url}" -%>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
- author = local_assigns.fetch(:author) { note.author }
|
||||
- discussion = local_assigns.fetch(:discussion) { note.discussion } if note.part_of_discussion?
|
||||
- project = local_assigns.fetch(:project, @project)
|
||||
|
||||
%p{ style: "color: #777777;" }
|
||||
= succeed ':' do
|
||||
|
|
@ -23,7 +24,7 @@
|
|||
- else
|
||||
= link_to 'discussion', target_url
|
||||
|
||||
- if discussion&.diff_discussion? && discussion.on_text?
|
||||
- if discussion&.diff_discussion? && discussion.on_text? && project.show_diff_preview_in_email?
|
||||
- if include_stylesheet_link
|
||||
= content_for :head do
|
||||
= stylesheet_link_tag 'mailers/highlighted_diff_email'
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<% target_url = local_assigns.fetch(:target_url, @target_url) -%>
|
||||
<% author = local_assigns.fetch(:author) { note.author } -%>
|
||||
<% discussion = local_assigns.fetch(:discussion) { note.discussion } if note.part_of_discussion? -%>
|
||||
<% project = local_assigns.fetch(:project, @project) -%>
|
||||
|
||||
<%= sanitize_name(author.name) -%>
|
||||
<% if discussion.nil? -%>
|
||||
|
|
@ -21,10 +22,10 @@
|
|||
<%= " #{target_url}" -%>
|
||||
|
||||
|
||||
<% if discussion&.diff_discussion? && discussion.on_text? -%>
|
||||
<% if discussion&.diff_discussion? && discussion.on_text? && project.show_diff_preview_in_email? -%>
|
||||
<% discussion.truncated_diff_lines(highlight: false, diff_limit: diff_limit).each do |line| -%>
|
||||
<%= "> #{line.text}\n" -%>
|
||||
<% end -%>
|
||||
|
||||
<%= "> #{line.text}\n" -%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
||||
<%= note.note -%>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
- active_tab = local_assigns.fetch(:active_tab, 'blank')
|
||||
- track_label = local_assigns.fetch(:track_label, 'import_project')
|
||||
- namespace_id = local_assigns.fetch(:destination_namespace_id, nil)
|
||||
|
||||
.project-import
|
||||
|
|
@ -18,45 +17,45 @@
|
|||
.import-buttons
|
||||
- if gitlab_project_import_enabled?
|
||||
.import_gitlab_project.has-tooltip{ data: { container: 'body', testid: 'gitlab-import-button' } }
|
||||
= render Pajamas::ButtonComponent.new(href: '#', icon: 'tanuki', button_options: { class: 'btn_import_gitlab_project js-import-project-btn', data: { href: new_import_gitlab_project_path, platform: 'gitlab_export', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'gitlab_export') } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: '#', icon: 'tanuki', button_options: { class: 'btn_import_gitlab_project js-import-project-btn', data: { href: new_import_gitlab_project_path, platform: 'gitlab_export', **tracking_attrs_data('import_project', 'click_button', 'gitlab_export') } }) do
|
||||
= _('GitLab export')
|
||||
|
||||
- if github_import_enabled?
|
||||
%div
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_github_path(namespace_id: namespace_id), icon: 'github', button_options: { class: 'js-import-github js-import-project-btn', data: { platform: 'github', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'github') } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_github_path(namespace_id: namespace_id), icon: 'github', button_options: { class: 'js-import-github js-import-project-btn', data: { platform: 'github', **tracking_attrs_data('import_project', 'click_button', 'github') } }) do
|
||||
GitHub
|
||||
|
||||
- if bitbucket_import_enabled?
|
||||
%div
|
||||
= render Pajamas::ButtonComponent.new(href: status_import_bitbucket_path(namespace_id: namespace_id), icon: 'bitbucket', button_options: { class: "import_bitbucket js-import-project-btn #{'js-how-to-import-link' unless bitbucket_import_configured?}", data: { modal_title: _("Import projects from Bitbucket"), modal_message: import_from_bitbucket_message, platform: 'bitbucket_cloud', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'bitbucket_cloud') } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: status_import_bitbucket_path(namespace_id: namespace_id), icon: 'bitbucket', button_options: { class: "import_bitbucket js-import-project-btn #{'js-how-to-import-link' unless bitbucket_import_configured?}", data: { modal_title: _("Import projects from Bitbucket"), modal_message: import_from_bitbucket_message, platform: 'bitbucket_cloud', **tracking_attrs_data('import_project', 'click_button', 'bitbucket_cloud') } }) do
|
||||
Bitbucket Cloud
|
||||
|
||||
- if bitbucket_server_import_enabled?
|
||||
%div
|
||||
= render Pajamas::ButtonComponent.new(href: status_import_bitbucket_server_path(namespace_id: namespace_id), icon: 'bitbucket', button_options: { class: 'import_bitbucket js-import-project-btn', data: { platform: 'bitbucket_server', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'bitbucket_server') } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: status_import_bitbucket_server_path(namespace_id: namespace_id), icon: 'bitbucket', button_options: { class: 'import_bitbucket js-import-project-btn', data: { platform: 'bitbucket_server', **tracking_attrs_data('import_project', 'click_button', 'bitbucket_server') } }) do
|
||||
Bitbucket Server
|
||||
|
||||
- if fogbugz_import_enabled?
|
||||
%div
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_fogbugz_path(namespace_id: namespace_id), icon: 'bug', button_options: { class: 'import_fogbugz js-import-project-btn', data: { platform: 'fogbugz', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'fogbugz') } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_fogbugz_path(namespace_id: namespace_id), icon: 'bug', button_options: { class: 'import_fogbugz js-import-project-btn', data: { platform: 'fogbugz', **tracking_attrs_data('import_project', 'click_button', 'fogbugz') } }) do
|
||||
FogBugz
|
||||
|
||||
- if gitea_import_enabled?
|
||||
%div
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_gitea_path(namespace_id: namespace_id), icon: 'gitea', button_options: { class: 'import_gitea js-import-project-btn', data: { platform: 'gitea', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'gitea') } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_gitea_path(namespace_id: namespace_id), icon: 'gitea', button_options: { class: 'import_gitea js-import-project-btn', data: { platform: 'gitea', **tracking_attrs_data('import_project', 'click_button', 'gitea') } }) do
|
||||
Gitea
|
||||
|
||||
- if git_import_enabled?
|
||||
%div
|
||||
= render Pajamas::ButtonComponent.new(icon: 'link', button_options: { class: 'js-toggle-button js-import-git-toggle-button js-import-project-btn', data: { platform: 'repo_url', toggle_open_class: 'active', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'repo_url') } }) do
|
||||
= render Pajamas::ButtonComponent.new(icon: 'link', button_options: { class: 'js-toggle-button js-import-git-toggle-button js-import-project-btn', data: { platform: 'repo_url', toggle_open_class: 'active', **tracking_attrs_data('import_project', 'click_button', 'repo_url') } }) do
|
||||
= _('Repository by URL')
|
||||
|
||||
- if manifest_import_enabled?
|
||||
%div
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_manifest_path(namespace_id: namespace_id), icon: 'doc-text', button_options: { class: 'import_manifest js-import-project-btn', data: { platform: 'manifest_file', track_experiment: local_assigns[:track_experiment], **tracking_attrs_data(track_label, 'click_button', 'manifest_file') } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: new_import_manifest_path(namespace_id: namespace_id), icon: 'doc-text', button_options: { class: 'import_manifest js-import-project-btn', data: { platform: 'manifest_file', **tracking_attrs_data('import_project', 'click_button', 'manifest_file') } }) do
|
||||
= _('Manifest file')
|
||||
|
||||
= render_if_exists "projects/gitee_import_button", namespace_id: namespace_id, track_label: track_label
|
||||
= render_if_exists "projects/gitee_import_button", namespace_id: namespace_id, track_label: 'import_project'
|
||||
|
||||
|
||||
.js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: default_to_import_tab
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139681
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435211
|
||||
milestone: '16.8'
|
||||
type: experiment
|
||||
group: group::activation
|
||||
name: diff_preview_in_email
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60007
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382055
|
||||
milestone: '15.6'
|
||||
type: gitlab_com_derisk
|
||||
group: group::code review
|
||||
default_enabled: false
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: sync_epic_to_work_item
|
||||
feature_issue_url:
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140232
|
||||
rollout_issue_url:
|
||||
milestone: '16.9'
|
||||
group: group::product planning
|
||||
type: wip
|
||||
default_enabled: false
|
||||
|
|
@ -7,4 +7,13 @@ feature_categories:
|
|||
description: Used to track the generation status of export files for groups or projects
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59976
|
||||
milestone: '13.12'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
allow_cross_joins:
|
||||
- gitlab_main_clusterwide
|
||||
allow_cross_transactions:
|
||||
- gitlab_main_clusterwide
|
||||
allow_cross_foreign_keys:
|
||||
- gitlab_main_clusterwide
|
||||
sharding_key:
|
||||
project_id: projects
|
||||
group_id: namespaces
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddDisablePersonalAccessTokensToNamespaceSettings < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.11'
|
||||
|
||||
def change
|
||||
add_column :namespace_settings, :disable_personal_access_tokens, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
bd1e2bdc4fda7c033a3407516450f15b45bfab4d6600a7bc940d10ca38f3e491
|
||||
|
|
@ -11882,6 +11882,7 @@ CREATE TABLE namespace_settings (
|
|||
lock_math_rendering_limits_enabled boolean DEFAULT false NOT NULL,
|
||||
duo_features_enabled boolean,
|
||||
lock_duo_features_enabled boolean DEFAULT false NOT NULL,
|
||||
disable_personal_access_tokens boolean DEFAULT false NOT NULL,
|
||||
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)),
|
||||
CONSTRAINT namespace_settings_unique_project_download_limit_alertlist_size CHECK ((cardinality(unique_project_download_limit_alertlist) <= 100)),
|
||||
CONSTRAINT namespace_settings_unique_project_download_limit_allowlist_size CHECK ((cardinality(unique_project_download_limit_allowlist) <= 100))
|
||||
|
|
|
|||
|
|
@ -94,35 +94,33 @@ You can combine the filter options. For example, to list only public projects wi
|
|||
|
||||
## Administering users
|
||||
|
||||
> - Filtering users [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238183) in GitLab 16.11.
|
||||
|
||||
You can administer all users in the GitLab instance from the Admin Area's Users page:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **Overview > Users**.
|
||||
|
||||
You can use the user search box to search and filter users by:
|
||||
To list users matching a specific criteria, select one of the following tabs on the **Users** page:
|
||||
|
||||
- User **access level**.
|
||||
- Whether **two-factor authentication** is enabled or disabled.
|
||||
- User **state**.
|
||||
|
||||
You can also type text into the search box. For example, the name of a specific user.
|
||||
This text search is case insensitive, and applies partial matching to name and username.
|
||||
To search for an email address, you must provide the complete email address.
|
||||
- **Active**
|
||||
- **Admins**
|
||||
- **2FA Enabled**
|
||||
- **2FA Disabled**
|
||||
- **External**
|
||||
- **[Blocked](../administration/moderate_users.md#block-a-user)**
|
||||
- **[Deactivated](../administration/moderate_users.md#deactivate-a-user)**
|
||||
- **Without projects**
|
||||
|
||||
For each user, the following are listed:
|
||||
|
||||
- Username.
|
||||
- Email address.
|
||||
- Project membership count.
|
||||
- Group membership count.
|
||||
- Date of account creation.
|
||||
- Date of last activity.
|
||||
1. Username
|
||||
1. Email address
|
||||
1. Project membership count
|
||||
1. Group membership count ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276215) in GitLab 13.12)
|
||||
1. Date of account creation
|
||||
1. Date of last activity
|
||||
|
||||
To edit a user, in the user's row, select **Edit**. To delete the user, or delete
|
||||
the user and their contributions, select the cog dropdown list in that user's row,
|
||||
and select the desired option.
|
||||
To edit a user, in the user's row, select **Edit**. To delete the user, or delete the user and their contributions, select the cog dropdown list in
|
||||
that user's row, and select the desired option.
|
||||
|
||||
To change the sort order:
|
||||
|
||||
|
|
@ -131,6 +129,10 @@ To change the sort order:
|
|||
|
||||
By default the sort dropdown list shows **Name**.
|
||||
|
||||
To search for users, enter your criteria in the search field. The user search is case
|
||||
insensitive, and applies partial matching to name and username. To search for an email address,
|
||||
you must provide the complete email address.
|
||||
|
||||
### User impersonation
|
||||
|
||||
An administrator can "impersonate" any other user, including other administrators.
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ The following are required to run Geo:
|
|||
- [Ubuntu](https://ubuntu.com) 16.04 or later
|
||||
- Where possible, you should also use the same operating system version on all
|
||||
Geo sites. If using different operating system versions between Geo sites, you
|
||||
**must** [check OS locale data compatibility](replication/troubleshooting/index.md#check-os-locale-data-compatibility)
|
||||
**must** [check OS locale data compatibility](replication/troubleshooting/common.md#check-os-locale-data-compatibility)
|
||||
across Geo sites to avoid silent corruption of database indexes.
|
||||
- [Supported PostgreSQL versions](https://handbook.gitlab.com/handbook/engineering/infrastructure/core-platform/data_stores/database/postgresql-upgrade-cadence/) for your GitLab releases with [Streaming Replication](https://wiki.postgresql.org/wiki/Streaming_Replication).
|
||||
- [PostgreSQL Logical replication](https://www.postgresql.org/docs/current/logical-replication.html) is not supported.
|
||||
|
|
|
|||
|
|
@ -148,8 +148,8 @@ You can run the Geo tracking database on a single node as follows:
|
|||
|
||||
```shell
|
||||
gitlab-ctl pg-password-md5 gitlab_geo
|
||||
# Enter password: <your_password_here>
|
||||
# Confirm password: <your_password_here>
|
||||
# Enter password: <your_tracking_db_password_here>
|
||||
# Confirm password: <your_tracking_db_password_here>
|
||||
# fca0b89a972d69f00eb3ec98a5838484
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
---
|
||||
stage: Systems
|
||||
group: Geo
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Troubleshooting Geo client and HTTP response code errors
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** Self-managed
|
||||
|
||||
## Fixing client errors
|
||||
|
||||
### Authorization errors from LFS HTTP(S) client requests
|
||||
|
||||
You may have problems if you're running a version of [Git LFS](https://git-lfs.com/) before 2.4.2.
|
||||
As noted in [this authentication issue](https://github.com/git-lfs/git-lfs/issues/3025),
|
||||
requests redirected from the secondary to the primary site do not properly send the
|
||||
Authorization header. This may result in either an infinite `Authorization <-> Redirect`
|
||||
loop, or Authorization error messages.
|
||||
|
||||
### Error: Net::ReadTimeout when pushing through SSH on a Geo secondary
|
||||
|
||||
When you push large repositories through SSH on a Geo secondary site, you may encounter a timeout.
|
||||
This is because Rails proxies the push to the primary and has a 60 second default timeout,
|
||||
[as described in this Geo issue](https://gitlab.com/gitlab-org/gitlab/-/issues/7405).
|
||||
|
||||
Current workarounds are:
|
||||
|
||||
- Push through HTTP instead, where Workhorse proxies the request to the primary (or redirects to the primary if Geo proxying is not enabled).
|
||||
- Push directly to the primary.
|
||||
|
||||
Example log (`gitlab-shell.log`):
|
||||
|
||||
```plaintext
|
||||
Failed to contact primary https://primary.domain.com/namespace/push_test.git\\nError: Net::ReadTimeout\",\"result\":null}" code=500 method=POST pid=5483 url="http://127.0.0.1:3000/api/v4/geo/proxy_git_push_ssh/push"
|
||||
```
|
||||
|
||||
### Repair OAuth authorization between Geo sites
|
||||
|
||||
When upgrading a Geo site, you might not be able to log in into a secondary site that only uses OAuth for authentication. In that case, start a [Rails console](../../../operations/rails_console.md) session on your primary site and perform the following steps:
|
||||
|
||||
1. To find the affected node, first list all the Geo Nodes you have:
|
||||
|
||||
```ruby
|
||||
GeoNode.all
|
||||
```
|
||||
|
||||
1. Repair the affected Geo node by specifying the ID:
|
||||
|
||||
```ruby
|
||||
GeoNode.find(<id>).repair
|
||||
```
|
||||
|
||||
## HTTP response code errors
|
||||
|
||||
### Secondary site returns 502 errors with Geo proxying
|
||||
|
||||
When [Geo proxying for secondary sites](../../secondary_proxy/index.md) is enabled, and the secondary site user interface returns
|
||||
502 errors, it is possible that the response header proxied from the primary site is too large.
|
||||
|
||||
Check the NGINX logs for errors similar to this example:
|
||||
|
||||
```plaintext
|
||||
2022/01/26 00:02:13 [error] 26641#0: *829148 upstream sent too big header while reading response header from upstream, client: 10.0.2.2, server: geo.staging.gitlab.com, request: "POST /users/sign_in HTTP/2.0", upstream: "http://unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket:/users/sign_in", host: "geo.staging.gitlab.com", referrer: "https://geo.staging.gitlab.com/users/sign_in"
|
||||
```
|
||||
|
||||
To resolve this issue:
|
||||
|
||||
1. Set `nginx['proxy_custom_buffer_size'] = '8k'` in `/etc/gitlab.rb` on all web nodes on the secondary site.
|
||||
1. Reconfigure the **secondary** using `sudo gitlab-ctl reconfigure`.
|
||||
|
||||
If you still get this error, you can further increase the buffer size by repeating the steps above
|
||||
and changing the `8k` size, for example by doubling it to `16k`.
|
||||
|
||||
### Geo Admin Area shows 'Unknown' for health status and 'Request failed with status code 401'
|
||||
|
||||
If using a load balancer, ensure that the load balancer's URL is set as the `external_url` in the
|
||||
`/etc/gitlab/gitlab.rb` of the nodes behind the load balancer.
|
||||
|
||||
### Primary site returns 500 error when accessing `/admin/geo/replication/projects`
|
||||
|
||||
Navigating to **Admin > Geo > Replication** (or `/admin/geo/replication/projects`) on a primary Geo site, shows a 500 error, while that same link on the secondary works fine. The primary's `production.log` has a similar entry to the following:
|
||||
|
||||
```plaintext
|
||||
Geo::TrackingBase::SecondaryNotConfigured: Geo secondary database is not configured
|
||||
from ee/app/models/geo/tracking_base.rb:26:in `connection'
|
||||
[..]
|
||||
from ee/app/views/admin/geo/projects/_all.html.haml:1
|
||||
```
|
||||
|
||||
On a Geo primary site this error can be ignored.
|
||||
|
||||
This happens because GitLab is attempting to display registries from the [Geo tracking database](../../../../administration/geo/index.md#geo-tracking-database) which doesn't exist on the primary site (only the original projects exist on the primary; no replicated projects are present, therefore no tracking database exists).
|
||||
|
||||
### Secondary site returns 400 error "Request header or cookie too large"
|
||||
|
||||
This error can happen when the internal URL of the primary site is incorrect.
|
||||
|
||||
For example, when you use a unified URL and the primary site's internal URL is also equal to the external URL. This causes a loop when a secondary site proxies requests to the primary site's internal URL.
|
||||
|
||||
To fix this issue, set the primary site's internal URL to a URL that is:
|
||||
|
||||
- Unique to the primary site.
|
||||
- Accessible from all secondary sites.
|
||||
|
||||
1. Visit the primary site.
|
||||
1. [Set up the internal URLs](../../../../administration/geo_sites.md#set-up-the-internal-urls).
|
||||
|
||||
### Secondary site returns `Received HTTP code 403 from proxy after CONNECT`
|
||||
|
||||
If you have installed GitLab using the Linux package (Omnibus) and have configured the `no_proxy` [custom environment variable](https://docs.gitlab.com/omnibus/settings/environment-variables.html) for Gitaly, you may experience this issue. Affected versions:
|
||||
|
||||
- `15.4.6`
|
||||
- `15.5.0`-`15.5.6`
|
||||
- `15.6.0`-`15.6.3`
|
||||
- `15.7.0`-`15.7.1`
|
||||
|
||||
This is due to [a bug introduced in the included version of cURL](https://github.com/curl/curl/issues/10122) shipped with
|
||||
the Linux package 15.4.6 and later. You should upgrade to a later version where this has been
|
||||
[fixed](https://about.gitlab.com/releases/2023/01/09/security-release-gitlab-15-7-2-released/).
|
||||
|
||||
The bug causes all wildcard domains (`.example.com`) to be ignored except for the last on in the `no_proxy` environment variable list. Therefore, if for any reason you cannot upgrade to a newer version, you can work around the issue by moving your wildcard domain to the end of the list:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
gitaly['env'] = {
|
||||
"no_proxy" => "sever.yourdomain.org, .yourdomain.com",
|
||||
}
|
||||
```
|
||||
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
You can have only one wildcard domain in the `no_proxy` list.
|
||||
|
||||
### Geo Admin Area returns 404 error for a secondary site
|
||||
|
||||
Sometimes `sudo gitlab-rake gitlab:geo:check` indicates that **Rails nodes of the secondary** sites are
|
||||
healthy, but a 404 Not Found error message for the **secondary** site is returned in the Geo Admin Area on the web interface for
|
||||
the **primary** site.
|
||||
|
||||
To resolve this issue:
|
||||
|
||||
- Try restarting **each Rails, Sidekiq and Gitaly nodes on your secondary site** using `sudo gitlab-ctl restart`.
|
||||
- Check `/var/log/gitlab/gitlab-rails/geo.log` on Sidekiq nodes to see if the **secondary** site is
|
||||
using IPv6 to send its status to the **primary** site. If it is, add an entry to
|
||||
the **primary** site using IPv4 in the `/etc/hosts` file. Alternatively, you should
|
||||
[enable IPv6 on the **primary** site](https://docs.gitlab.com/omnibus/settings/nginx.html#setting-the-nginx-listen-address-or-addresses).
|
||||
|
|
@ -0,0 +1,633 @@
|
|||
---
|
||||
stage: Systems
|
||||
group: Geo
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Troubleshooting common Geo errors
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** Self-managed
|
||||
|
||||
## Basic troubleshooting
|
||||
|
||||
Before attempting more advanced troubleshooting:
|
||||
|
||||
- Check [the health of the Geo sites](#check-the-health-of-the-geo-sites).
|
||||
- Check [if PostgreSQL replication is working](#check-if-postgresql-replication-is-working).
|
||||
|
||||
### Check the health of the Geo sites
|
||||
|
||||
On the **primary** site:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **Geo > Sites**.
|
||||
|
||||
We perform the following health checks on each **secondary** site
|
||||
to help identify if something is wrong:
|
||||
|
||||
- Is the site running?
|
||||
- Is the secondary site's database configured for streaming replication?
|
||||
- Is the secondary site's tracking database configured?
|
||||
- Is the secondary site's tracking database connected?
|
||||
- Is the secondary site's tracking database up-to-date?
|
||||
- Is the secondary site's status less than 10 minutes old?
|
||||
|
||||
A site shows as "Unhealthy" if the site's status is more than 10 minutes old. In that case, try running the following in the [Rails console](../../../operations/rails_console.md) on the affected secondary site:
|
||||
|
||||
```ruby
|
||||
Geo::MetricsUpdateWorker.new.perform
|
||||
```
|
||||
|
||||
If it raises an error, then the error is probably also preventing the jobs from completing. If it takes longer than 10 minutes, then there may be a performance issue, and the UI may always show "Unhealthy" even if the status eventually does get updated.
|
||||
|
||||
If it successfully updates the status, then something may be wrong with Sidekiq. Is it running? Do the logs show errors? This job is supposed to be enqueued every minute and might not run if a [job deduplication idempotency](../../../sidekiq/sidekiq_troubleshooting.md#clearing-a-sidekiq-job-deduplication-idempotency-key) key was not cleared properly. It takes an exclusive lease in Redis to ensure that only one of these jobs can run at a time. The primary site updates its status directly in the PostgreSQL database. Secondary sites send an HTTP Post request to the primary site with their status data.
|
||||
|
||||
A site also shows as "Unhealthy" if certain health checks fail. You can reveal the failure by running the following in the [Rails console](../../../operations/rails_console.md) on the affected secondary site:
|
||||
|
||||
```ruby
|
||||
Gitlab::Geo::HealthCheck.new.perform_checks
|
||||
```
|
||||
|
||||
If it returns `""` (an empty string) or `"Healthy"`, then the checks succeeded. If it returns anything else, then the message should explain what failed, or show the exception message.
|
||||
|
||||
For information about how to resolve common error messages reported from the user interface,
|
||||
see [Fixing Common Errors](#fixing-common-errors).
|
||||
|
||||
If the user interface is not working, or you are unable to sign in, you can run the Geo
|
||||
health check manually to get this information and a few more details.
|
||||
|
||||
#### Health check Rake task
|
||||
|
||||
> - The use of a custom NTP server was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105514) in GitLab 15.7.
|
||||
|
||||
This Rake task can be run on a **Rails** node in the **primary** or **secondary**
|
||||
Geo sites:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... yes
|
||||
GitLab Geo is enabled ... yes
|
||||
This machine's Geo node name matches a database record ... yes, found a secondary node named "Shanghai"
|
||||
GitLab Geo tracking database is correctly configured ... yes
|
||||
Database replication enabled? ... yes
|
||||
Database replication working? ... yes
|
||||
GitLab Geo HTTP(S) connectivity ...
|
||||
* Can connect to the primary node ... yes
|
||||
HTTP/HTTPS repository cloning is enabled ... yes
|
||||
Machine clock is synchronized ... yes
|
||||
Git user has default SSH configuration? ... yes
|
||||
OpenSSH configured to use AuthorizedKeysCommand ... yes
|
||||
GitLab configured to disable writing to authorized_keys file ... yes
|
||||
GitLab configured to store new projects in hashed storage? ... yes
|
||||
All projects are in hashed storage? ... yes
|
||||
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
You can also specify a custom NTP server using environment variables. For example:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check NTP_HOST="ntp.ubuntu.com" NTP_TIMEOUT="30"
|
||||
```
|
||||
|
||||
The following environment variables are supported.
|
||||
|
||||
| Variable | Description | Default value |
|
||||
| ----------- | ----------- | ------------- |
|
||||
|`NTP_HOST` | The NTP host. | `pool.ntp.org` |
|
||||
|`NTP_PORT` | The NTP port the host listens on. |`ntp`|
|
||||
|`NTP_TIMEOUT`| The NTP timeout in seconds. | The value defined in the `net-ntp` Ruby library ([60 seconds](https://github.com/zencoder/net-ntp/blob/3d0990214f439a5127782e0f50faeaf2c8ca7023/lib/net/ntp/ntp.rb#L6)). |
|
||||
|
||||
If the Rake task skips the `OpenSSH configured to use AuthorizedKeysCommand` check, the
|
||||
following output displays:
|
||||
|
||||
```plaintext
|
||||
OpenSSH configured to use AuthorizedKeysCommand ... skipped
|
||||
Reason:
|
||||
Cannot access OpenSSH configuration file
|
||||
Try fixing it:
|
||||
This is expected if you are using SELinux. You may want to check configuration manually
|
||||
For more information see:
|
||||
doc/administration/operations/fast_ssh_key_lookup.md
|
||||
```
|
||||
|
||||
This issue may occur if:
|
||||
|
||||
- You [use SELinux](../../../operations/fast_ssh_key_lookup.md#selinux-support-and-limitations).
|
||||
- You don't use SELinux, and the `git` user cannot access the OpenSSH configuration file due to restricted file permissions.
|
||||
|
||||
In the latter case, the following output shows that only the `root` user can read this file:
|
||||
|
||||
```plaintext
|
||||
sudo stat -c '%G:%U %A %a %n' /etc/ssh/sshd_config
|
||||
|
||||
root:root -rw------- 600 /etc/ssh/sshd_config
|
||||
```
|
||||
|
||||
To allow the `git` user to read the OpenSSH configuration file, without changing the file owner or permissions, use `acl`:
|
||||
|
||||
```plaintext
|
||||
sudo setfacl -m u:git:r /etc/ssh/sshd_config
|
||||
```
|
||||
|
||||
#### Sync status Rake task
|
||||
|
||||
Current sync information can be found manually by running this Rake task on any
|
||||
node running Rails (Puma, Sidekiq, or Geo Log Cursor) on the Geo **secondary** site.
|
||||
|
||||
GitLab does **not** verify objects that are stored in Object Storage. If you are using Object Storage, you will see all of the "verified" checks showing 0 successes. This is expected and not a cause for concern.
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake geo:status
|
||||
```
|
||||
|
||||
The output includes:
|
||||
|
||||
- a count of "failed" items if any failures occurred
|
||||
- the percentage of "succeeded" items, relative to the "total"
|
||||
|
||||
Example:
|
||||
|
||||
```plaintext
|
||||
http://secondary.example.com/
|
||||
-----------------------------------------------------
|
||||
GitLab Version: 14.9.2-ee
|
||||
Geo Role: Secondary
|
||||
Health Status: Healthy
|
||||
Project Repositories: succeeded 12345 / total 12345 (100%)
|
||||
Project Wiki Repositories: succeeded 6789 / total 6789 (100%)
|
||||
Attachments: succeeded 4 / total 4 (100%)
|
||||
CI job artifacts: succeeded 0 / total 0 (0%)
|
||||
Design management repositories: succeeded 1 / total 1 (100%)
|
||||
LFS Objects: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Merge Request Diffs: succeeded 0 / total 0 (0%)
|
||||
Package Files: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Terraform State Versions: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Snippet Repositories: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Group Wiki Repositories: succeeded 4 / total 4 (100%)
|
||||
Pipeline Artifacts: failed 3 / succeeded 0 / total 3 (0%)
|
||||
Pages Deployments: succeeded 0 / total 0 (0%)
|
||||
Repositories Checked: failed 5 / succeeded 0 / total 5 (0%)
|
||||
Package Files Verified: succeeded 0 / total 10 (0%)
|
||||
Terraform State Versions Verified: succeeded 0 / total 10 (0%)
|
||||
Snippet Repositories Verified: succeeded 99 / total 100 (99%)
|
||||
Pipeline Artifacts Verified: succeeded 0 / total 10 (0%)
|
||||
Project Repositories Verified: succeeded 12345 / total 12345 (100%)
|
||||
Project Wiki Repositories Verified: succeeded 6789 / total 6789 (100%)
|
||||
Sync Settings: Full
|
||||
Database replication lag: 0 seconds
|
||||
Last event ID seen from primary: 12345 (about 2 minutes ago)
|
||||
Last event ID processed: 12345 (about 2 minutes ago)
|
||||
Last status report was: 1 minute ago
|
||||
```
|
||||
|
||||
Each item can have up to three statuses. For example, for `Project Repositories`, you see the following lines:
|
||||
|
||||
```plaintext
|
||||
Project Repositories: succeeded 12345 / total 12345 (100%)
|
||||
Project Repositories Verified: succeeded 12345 / total 12345 (100%)
|
||||
Repositories Checked: failed 5 / succeeded 0 / total 5 (0%)
|
||||
```
|
||||
|
||||
The 3 status items are defined as follows:
|
||||
|
||||
- The `Project Repositories` output shows how many project repositories are synced from the primary to the secondary.
|
||||
- The `Project Verified Repositories` output shows how many project repositories on this secondary have a matching repository checksum with the Primary.
|
||||
- The `Repositories Checked` output shows how many project repositories have passed a local Git repository check (`git fsck`) on the secondary.
|
||||
|
||||
To find more details about failed items, check
|
||||
[the `gitlab-rails/geo.log` file](../../../logs/log_parsing.md#find-most-common-geo-sync-errors)
|
||||
|
||||
If you notice replication or verification failures, you can try to [resolve them](replication.md#fixing-non-postgresql-replication-failures).
|
||||
|
||||
If there are Repository check failures, you can try to [resolve them](synchronization.md#find-repository-check-failures-in-a-geo-secondary-site).
|
||||
|
||||
##### Fixing errors found when running the Geo check Rake task
|
||||
|
||||
When running this Rake task, you may see error messages if the nodes are not properly configured:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check
|
||||
```
|
||||
|
||||
- Rails did not provide a password when connecting to the database.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... Exception: fe_sendauth: no password supplied
|
||||
GitLab Geo is enabled ... Exception: fe_sendauth: no password supplied
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Ensure you have the `gitlab_rails['db_password']` set to the plain-text
|
||||
password used when creating the hash for `postgresql['sql_user_password']`.
|
||||
|
||||
- Rails is unable to connect to the database.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
|
||||
FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
|
||||
GitLab Geo is enabled ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
|
||||
FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Ensure you have the IP address of the rails node included in `postgresql['md5_auth_cidr_addresses']`.
|
||||
Also, ensure you have included the subnet mask on the IP address: `postgresql['md5_auth_cidr_addresses'] = ['1.1.1.1/32']`.
|
||||
|
||||
- Rails has supplied the incorrect password.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
GitLab Geo is available ... Exception: FATAL: password authentication failed for user "gitlab"
|
||||
FATAL: password authentication failed for user "gitlab"
|
||||
GitLab Geo is enabled ... Exception: FATAL: password authentication failed for user "gitlab"
|
||||
FATAL: password authentication failed for user "gitlab"
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Verify the correct password is set for `gitlab_rails['db_password']` that was
|
||||
used when creating the hash in `postgresql['sql_user_password']` by running
|
||||
`gitlab-ctl pg-password-md5 gitlab` and entering the password.
|
||||
|
||||
- Check returns `not a secondary node`.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... yes
|
||||
GitLab Geo is enabled ... yes
|
||||
GitLab Geo tracking database is correctly configured ... not a secondary node
|
||||
Database replication enabled? ... not a secondary node
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Ensure you have added the secondary site in the Admin Area under **Geo > Sites** on the web interface for the **primary** site.
|
||||
Also ensure you entered the `gitlab_rails['geo_node_name']`
|
||||
when adding the secondary site in the Admin Area of the **primary** site.
|
||||
In GitLab 12.3 and earlier, edit the secondary site in the Admin Area of the **primary**
|
||||
site and ensure that there is a trailing `/` in the `Name` field.
|
||||
|
||||
- Check returns `Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist`.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... no
|
||||
Try fixing it:
|
||||
Add a new license that includes the GitLab Geo feature
|
||||
For more information see:
|
||||
https://about.gitlab.com/features/gitlab-geo/
|
||||
GitLab Geo is enabled ... Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist
|
||||
LINE 8: WHERE a.attrelid = '"geo_nodes"'::regclass
|
||||
^
|
||||
: SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
||||
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
||||
c.collname, col_description(a.attrelid, a.attnum) AS comment
|
||||
FROM pg_attribute a
|
||||
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
||||
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
||||
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
|
||||
WHERE a.attrelid = '"geo_nodes"'::regclass
|
||||
AND a.attnum > 0 AND NOT a.attisdropped
|
||||
ORDER BY a.attnum
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
When performing a PostgreSQL major version (9 > 10), update this is expected. Follow
|
||||
the [initiate-the-replication-process](../../setup/database.md#step-3-initiate-the-replication-process).
|
||||
|
||||
- Rails does not appear to have the configuration necessary to connect to the Geo tracking database.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... yes
|
||||
GitLab Geo is enabled ... yes
|
||||
GitLab Geo tracking database is correctly configured ... no
|
||||
Try fixing it:
|
||||
Rails does not appear to have the configuration necessary to connect to the Geo tracking database. If the tracking database is running on a node other than this one, then you may need to add configuration.
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
- If you are running the secondary site on a single node for all services, then follow [Geo database replication - Configure the secondary server](../../setup/database.md#step-2-configure-the-secondary-server).
|
||||
- If you are running the secondary site's tracking database on its own node, then follow [Geo for multiple servers - Configure the Geo tracking database on the Geo secondary site](../multiple_servers.md#step-2-configure-the-geo-tracking-database-on-the-geo-secondary-site)
|
||||
- If you are running the secondary site's tracking database in a Patroni cluster, then follow [Geo database replication - Configuring Patroni cluster for the tracking PostgreSQL database](../../setup/database.md#configuring-patroni-cluster-for-the-tracking-postgresql-database)
|
||||
- If you are running the secondary site's tracking database in an external database, then follow [Geo with external PostgreSQL instances](../../setup/external_database.md#configure-the-tracking-database)
|
||||
- If the Geo check task was run on a node which is not running a service which runs the GitLab Rails app (Puma, Sidekiq, or Geo Log Cursor), then this error can be ignored. The node does not need Rails to be configured.
|
||||
|
||||
##### Message: Machine clock is synchronized ... Exception
|
||||
|
||||
The Rake task attempts to verify that the server clock is synchronized with NTP. Synchronized clocks
|
||||
are required for Geo to function correctly. As an example, for security, when the server time on the
|
||||
primary site and secondary site differ by about a minute or more, requests between Geo sites
|
||||
fail. If this check task fails to complete due to a reason other than mismatching times, it
|
||||
does not necessarily mean that Geo will not work.
|
||||
|
||||
The Ruby gem which performs the check is hard coded with `pool.ntp.org` as its reference time source.
|
||||
|
||||
- Exception message `Machine clock is synchronized ... Exception: Timeout::Error`
|
||||
|
||||
This issue occurs when your server cannot access the host `pool.ntp.org`.
|
||||
|
||||
- Exception message `Machine clock is synchronized ... Exception: No route to host - recvfrom(2)`
|
||||
|
||||
This issue occurs when the hostname `pool.ntp.org` resolves to a server which does not provide a time service.
|
||||
|
||||
In this case, in GitLab 15.7 and later, [specify a custom NTP server using environment variables](#health-check-rake-task).
|
||||
|
||||
In GitLab 15.6 and earlier, use one of the following workarounds:
|
||||
|
||||
- Add entries in `/etc/hosts` for `pool.ntp.org` to direct the request to valid local time servers.
|
||||
This fixes the long timeout and the timeout error.
|
||||
- Direct the check to any valid IP address. This resolves the timeout issue, but the check fails
|
||||
with the `No route to host` error, as noted above.
|
||||
|
||||
[Cloud native GitLab deployments](https://docs.gitlab.com/charts/advanced/geo/#set-the-geo-primary-site)
|
||||
generate an error because containers in Kubernetes do not have access to the host clock:
|
||||
|
||||
```plaintext
|
||||
Machine clock is synchronized ... Exception: getaddrinfo: Servname not supported for ai_socktype
|
||||
```
|
||||
|
||||
##### Message: `ActiveRecord::StatementInvalid: PG::ReadOnlySqlTransaction: ERROR: cannot execute INSERT in a read-only transaction`
|
||||
|
||||
When this error is encountered on a secondary site, it likely affects all usages of GitLab Rails such as `gitlab-rails` or `gitlab-rake` commands, as well the Puma, Sidekiq, and Geo Log Cursor services.
|
||||
|
||||
```plaintext
|
||||
ActiveRecord::StatementInvalid: PG::ReadOnlySqlTransaction: ERROR: cannot execute INSERT in a read-only transaction
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/application_record.rb:86:in `block in safe_find_or_create_by'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/concerns/cross_database_modification.rb:92:in `block in transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/database.rb:332:in `block in transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/database.rb:331:in `transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/concerns/cross_database_modification.rb:83:in `transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/application_record.rb:86:in `safe_find_or_create_by'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:21:in `by_name'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:17:in `block in populate!'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:17:in `map'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:17:in `populate!'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/config/initializers/fill_shards.rb:9:in `<top (required)>'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/config/environment.rb:7:in `<top (required)>'
|
||||
/opt/gitlab/embedded/bin/bundle:23:in `load'
|
||||
/opt/gitlab/embedded/bin/bundle:23:in `<main>'
|
||||
```
|
||||
|
||||
The PostgreSQL read-replica database would be producing these errors:
|
||||
|
||||
```plaintext
|
||||
2023-01-17_17:44:54.64268 ERROR: cannot execute INSERT in a read-only transaction
|
||||
2023-01-17_17:44:54.64271 STATEMENT: /*application:web,db_config_name:main*/ INSERT INTO "shards" ("name") VALUES ('storage1') RETURNING "id"
|
||||
```
|
||||
|
||||
This situation can occur during initial configuration when a secondary site is not yet aware that it is a secondary site.
|
||||
|
||||
To resolve the error, follow [Step 3. Add the secondary site](../configuration.md#step-3-add-the-secondary-site).
|
||||
|
||||
### Check if PostgreSQL replication is working
|
||||
|
||||
To check if PostgreSQL replication is working, check if:
|
||||
|
||||
- [Sites are pointing to the correct database node](#are-sites-pointing-to-the-correct-database-node).
|
||||
- [Geo can detect the current site correctly](#can-geo-detect-the-current-site-correctly).
|
||||
|
||||
If you're still having problems, see the [advanced replication troubleshooting](replication.md).
|
||||
|
||||
#### Are sites pointing to the correct database node?
|
||||
|
||||
You should make sure your **primary** Geo [site](../../glossary.md) points to
|
||||
the database node that has write permissions.
|
||||
|
||||
Any **secondary** sites should point only to read-only database nodes.
|
||||
|
||||
#### Can Geo detect the current site correctly?
|
||||
|
||||
Geo finds the current Puma or Sidekiq node's Geo [site](../../glossary.md) name in
|
||||
`/etc/gitlab/gitlab.rb` with the following logic:
|
||||
|
||||
1. Get the "Geo node name" (there is
|
||||
[an issue to rename the settings to "Geo site name"](https://gitlab.com/gitlab-org/gitlab/-/issues/335944)):
|
||||
- Linux package: get the `gitlab_rails['geo_node_name']` setting.
|
||||
- GitLab Helm charts: get the `global.geo.nodeName` setting (see [Charts with GitLab Geo](https://docs.gitlab.com/charts/advanced/geo/index.html)).
|
||||
1. If that is not defined, then get the `external_url` setting.
|
||||
|
||||
This name is used to look up the Geo site with the same **Name** in the **Geo Sites**
|
||||
dashboard.
|
||||
|
||||
To check if the current machine has a site name that matches a site in the
|
||||
database, run the check task:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check
|
||||
```
|
||||
|
||||
It displays the current machine's site name and whether the matching database
|
||||
record is a **primary** or **secondary** site.
|
||||
|
||||
```plaintext
|
||||
This machine's Geo node name matches a database record ... yes, found a secondary node named "Shanghai"
|
||||
```
|
||||
|
||||
```plaintext
|
||||
This machine's Geo node name matches a database record ... no
|
||||
Try fixing it:
|
||||
You could add or update a Geo node database record, setting the name to "https://example.com/".
|
||||
Or you could set this machine's Geo node name to match the name of an existing database record: "London", "Shanghai"
|
||||
For more information see:
|
||||
doc/administration/geo/replication/troubleshooting/index.md#can-geo-detect-the-current-node-correctly
|
||||
```
|
||||
|
||||
For more information about recommended site names in the description of the Name field, see
|
||||
[Geo Admin Area Common Settings](../../../../administration/geo_sites.md#common-settings).
|
||||
|
||||
### Check OS locale data compatibility
|
||||
|
||||
If different operating systems or different operating system versions are deployed across Geo sites, you **must** perform a locale data compatibility check before setting up Geo.
|
||||
|
||||
Geo uses PostgreSQL and Streaming Replication to replicate data across Geo sites. PostgreSQL uses locale data provided by the operating system's C library for sorting text. If the locale data in the C library is incompatible across Geo sites, it causes erroneous query results that lead to [incorrect behavior on secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/360723).
|
||||
|
||||
For example, Ubuntu 18.04 (and earlier) and RHEL/Centos7 (and earlier) are incompatible with their later releases.
|
||||
See the [PostgreSQL wiki for more details](https://wiki.postgresql.org/wiki/Locale_data_changes).
|
||||
|
||||
On all hosts running PostgreSQL, across all Geo sites, run the following shell command:
|
||||
|
||||
```shell
|
||||
( echo "1-1"; echo "11" ) | LC_COLLATE=en_US.UTF-8 sort
|
||||
```
|
||||
|
||||
The output looks like either:
|
||||
|
||||
```plaintext
|
||||
1-1
|
||||
11
|
||||
```
|
||||
|
||||
or the reverse order:
|
||||
|
||||
```plaintext
|
||||
11
|
||||
1-1
|
||||
```
|
||||
|
||||
If the output is **identical** on all hosts, then they running compatible versions of locale data and you may proceed with Geo configuration.
|
||||
|
||||
If the output **differs** on any hosts, PostgreSQL replication will not work properly: indexes will become corrupted on the database replicas. You **must** select operating system versions that are compatible.
|
||||
|
||||
A full index rebuild is required if the on-disk data is transferred 'at rest' to an operating system with an incompatible locale, or through replication.
|
||||
|
||||
This check is also required when using a mixture of GitLab deployments. The locale might be different between an Linux package install, a GitLab Docker container, a Helm chart deployment, or external database services.
|
||||
|
||||
## Fixing common errors
|
||||
|
||||
This section documents common error messages reported in the Admin Area on the web interface, and how to fix them.
|
||||
|
||||
### Geo database configuration file is missing
|
||||
|
||||
GitLab cannot find or doesn't have permission to access the `database_geo.yml` configuration file.
|
||||
|
||||
In a Linux package installation, the file should be in `/var/opt/gitlab/gitlab-rails/etc`.
|
||||
If it doesn't exist or inadvertent changes have been made to it, run `sudo gitlab-ctl reconfigure` to restore it to its correct state.
|
||||
|
||||
If this path is mounted on a remote volume, ensure your volume configuration
|
||||
has the correct permissions.
|
||||
|
||||
### An existing tracking database cannot be reused
|
||||
|
||||
Geo cannot reuse an existing tracking database.
|
||||
|
||||
It is safest to use a fresh secondary, or reset the whole secondary by following
|
||||
[Resetting Geo secondary site replication](replication.md#resetting-geo-secondary-site-replication).
|
||||
|
||||
It is risky to reuse a secondary site without resetting it because the secondary site may have missed some Geo events. For example, missed deletion events lead to the secondary site permanently having data that should be deleted. Similarly, losing an event which physically moves the location of data leads to data permanently orphaned in one location, and missing in the other location until it is re-verified. This is why GitLab switched to hashed storage, since it makes moving data unnecessary. There may be other unknown problems due to lost events.
|
||||
|
||||
If these kinds of risks do not apply, for example in a test environment, or if you know that the main Postgres database still contains all Geo events since the Geo site was added, then you can bypass this health check:
|
||||
|
||||
1. Get the last processed event time. In Rails console in the secondary site, run:
|
||||
|
||||
```ruby
|
||||
Geo::EventLogState.last.created_at.utc
|
||||
```
|
||||
|
||||
1. Copy the output, for example `2024-02-21 23:50:50.676918 UTC`.
|
||||
1. Update the created time of the secondary site to make it appear older. In Rails console in the primary site, run:
|
||||
|
||||
```ruby
|
||||
GeoNode.secondary_nodes.last.update_column(:created_at, DateTime.parse('2024-02-21 23:50:50.676918 UTC') - 1.second)
|
||||
```
|
||||
|
||||
This command assumes that the affected secondary site is the one that was created last.
|
||||
|
||||
1. Update the secondary site's status in **Admin > Geo > Sites**. In Rails console in the secondary site, run:
|
||||
|
||||
```ruby
|
||||
Geo::MetricsUpdateWorker.new.perform
|
||||
```
|
||||
|
||||
1. The secondary site should appear healthy. If it does not, run `gitlab-rake gitlab:geo:check` on the secondary site, or try restarting Rails if you haven't done so since re-adding the secondary site.
|
||||
1. To resync missing or out-of-date data, go to **Admin > Geo > Sites**.
|
||||
1. Under the secondary site select **Replication Details**.
|
||||
1. Select **Reverify all** for every data type.
|
||||
|
||||
### Geo site has a database that is writable which is an indication it is not configured for replication with the primary site
|
||||
|
||||
This error message refers to a problem with the database replica on a **secondary** site,
|
||||
which Geo expects to have access to. It usually means, either:
|
||||
|
||||
- An unsupported replication method was used (for example, logical replication).
|
||||
- The instructions to set up a [Geo database replication](../../setup/database.md) were not followed correctly.
|
||||
- Your database connection details are incorrect, that is you have specified the wrong
|
||||
user in your `/etc/gitlab/gitlab.rb` file.
|
||||
|
||||
Geo **secondary** sites require two separate PostgreSQL instances:
|
||||
|
||||
- A read-only replica of the **primary** site.
|
||||
- A regular, writable instance that holds replication metadata. That is, the Geo tracking database.
|
||||
|
||||
This error message indicates that the replica database in the **secondary** site is misconfigured and replication has stopped.
|
||||
|
||||
To restore the database and resume replication, you can do one of the following:
|
||||
|
||||
- [Reset the Geo secondary site replication](replication.md#resetting-geo-secondary-site-replication).
|
||||
- [Set up a new Geo secondary using the Linux package](../../setup/index.md#using-linux-package-installations).
|
||||
|
||||
If you set up a new secondary from scratch, you must also [remove the old site from the Geo cluster](../remove_geo_site.md#removing-secondary-geo-sites).
|
||||
|
||||
### Geo site does not appear to be replicating the database from the primary site
|
||||
|
||||
The most common problems that prevent the database from replicating correctly are:
|
||||
|
||||
- **Secondary** sites cannot reach the **primary** site. Check credentials and
|
||||
[firewall rules](../../index.md#firewall-rules).
|
||||
- SSL certificate problems. Make sure you copied `/etc/gitlab/gitlab-secrets.json` from the **primary** site.
|
||||
- Database storage disk is full.
|
||||
- Database replication slot is misconfigured.
|
||||
- Database is not using a replication slot or another alternative and cannot catch-up because WAL files were purged.
|
||||
|
||||
Make sure you follow the [Geo database replication](../../setup/database.md) instructions for supported configuration.
|
||||
|
||||
### Geo database version (...) does not match latest migration (...)
|
||||
|
||||
If you are using the Linux package installation, something might have failed during upgrade. You can:
|
||||
|
||||
- Run `sudo gitlab-ctl reconfigure`.
|
||||
- Manually trigger the database migration by running: `sudo gitlab-rake db:migrate:geo` as root on the **secondary** site.
|
||||
|
||||
### GitLab indicates that more than 100% of repositories were synced
|
||||
|
||||
This can be caused by orphaned records in the project registry. They are being cleaned
|
||||
periodically using a registry worker, so give it some time to fix it itself.
|
||||
|
||||
### Secondary site shows "Unhealthy" in UI after changing the value of `external_url` for the primary site
|
||||
|
||||
If you have updated the value of `external_url` in `/etc/gitlab/gitlab.rb` for the primary site or changed the protocol from `http` to `https`, you may see that secondary sites are shown as `Unhealthy`. You may also find the following error in `geo.log`:
|
||||
|
||||
```plaintext
|
||||
"class": "Geo::NodeStatusRequestService",
|
||||
...
|
||||
"message": "Failed to Net::HTTP::Post to primary url: http://primary-site.gitlab.tld/api/v4/geo/status",
|
||||
"error": "Failed to open TCP connection to <PRIMARY_IP_ADDRESS>:80 (Connection refused - connect(2) for \"<PRIMARY_ID_ADDRESS>\" port 80)"
|
||||
```
|
||||
|
||||
In this case, make sure to update the changed URL on all your sites:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **Geo > Sites**.
|
||||
1. Change the URL and save the change.
|
||||
|
||||
### Message: `ERROR: canceling statement due to conflict with recovery` during backup
|
||||
|
||||
Running a backup on a Geo **secondary** [is not supported](https://gitlab.com/gitlab-org/gitlab/-/issues/211668).
|
||||
|
||||
When running a backup on a **secondary** you might encounter the following error message:
|
||||
|
||||
```plaintext
|
||||
Dumping PostgreSQL database gitlabhq_production ...
|
||||
pg_dump: error: Dumping the contents of table "notes" failed: PQgetResult() failed.
|
||||
pg_dump: error: Error message from server: ERROR: canceling statement due to conflict with recovery
|
||||
DETAIL: User query might have needed to see row versions that must be removed.
|
||||
pg_dump: error: The command was: COPY public.notes (id, note, [...], last_edited_at) TO stdout;
|
||||
```
|
||||
|
||||
To prevent a database backup being made automatically during GitLab upgrades on your Geo **secondaries**,
|
||||
create the following empty file:
|
||||
|
||||
```shell
|
||||
sudo touch /etc/gitlab/skip-auto-backup
|
||||
```
|
||||
|
|
@ -10,787 +10,10 @@ DETAILS:
|
|||
**Tier:** Premium, Ultimate
|
||||
**Offering:** Self-managed
|
||||
|
||||
Setting up Geo requires careful attention to details, and sometimes it's easy to
|
||||
miss a step.
|
||||
When working with Geo, you might encounter the following issues:
|
||||
|
||||
Here is a list of steps you should take to attempt to fix problem:
|
||||
|
||||
1. Perform [basic troubleshooting](#basic-troubleshooting).
|
||||
1. Fix any [PostgreSQL database replication errors](replication.md#fixing-postgresql-database-replication-errors).
|
||||
1. Fix any [common](#fixing-common-errors) errors.
|
||||
1. Fix any [non-PostgreSQL replication failures](replication.md#fixing-non-postgresql-replication-failures).
|
||||
|
||||
## Basic troubleshooting
|
||||
|
||||
Before attempting more advanced troubleshooting:
|
||||
|
||||
- Check [the health of the Geo sites](#check-the-health-of-the-geo-sites).
|
||||
- Check [if PostgreSQL replication is working](#check-if-postgresql-replication-is-working).
|
||||
|
||||
### Check the health of the Geo sites
|
||||
|
||||
On the **primary** site:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **Geo > Sites**.
|
||||
|
||||
We perform the following health checks on each **secondary** site
|
||||
to help identify if something is wrong:
|
||||
|
||||
- Is the site running?
|
||||
- Is the secondary site's database configured for streaming replication?
|
||||
- Is the secondary site's tracking database configured?
|
||||
- Is the secondary site's tracking database connected?
|
||||
- Is the secondary site's tracking database up-to-date?
|
||||
- Is the secondary site's status less than 10 minutes old?
|
||||
|
||||
A site shows as "Unhealthy" if the site's status is more than 10 minutes old. In that case, try running the following in the [Rails console](../../../operations/rails_console.md) on the affected secondary site:
|
||||
|
||||
```ruby
|
||||
Geo::MetricsUpdateWorker.new.perform
|
||||
```
|
||||
|
||||
If it raises an error, then the error is probably also preventing the jobs from completing. If it takes longer than 10 minutes, then there may be a performance issue, and the UI may always show "Unhealthy" even if the status eventually does get updated.
|
||||
|
||||
If it successfully updates the status, then something may be wrong with Sidekiq. Is it running? Do the logs show errors? This job is supposed to be enqueued every minute and might not run if a [job deduplication idempotency](../../../sidekiq/sidekiq_troubleshooting.md#clearing-a-sidekiq-job-deduplication-idempotency-key) key was not cleared properly. It takes an exclusive lease in Redis to ensure that only one of these jobs can run at a time. The primary site updates its status directly in the PostgreSQL database. Secondary sites send an HTTP Post request to the primary site with their status data.
|
||||
|
||||
A site also shows as "Unhealthy" if certain health checks fail. You can reveal the failure by running the following in the [Rails console](../../../operations/rails_console.md) on the affected secondary site:
|
||||
|
||||
```ruby
|
||||
Gitlab::Geo::HealthCheck.new.perform_checks
|
||||
```
|
||||
|
||||
If it returns `""` (an empty string) or `"Healthy"`, then the checks succeeded. If it returns anything else, then the message should explain what failed, or show the exception message.
|
||||
|
||||
For information about how to resolve common error messages reported from the user interface,
|
||||
see [Fixing Common Errors](#fixing-common-errors).
|
||||
|
||||
If the user interface is not working, or you are unable to sign in, you can run the Geo
|
||||
health check manually to get this information and a few more details.
|
||||
|
||||
#### Health check Rake task
|
||||
|
||||
> - The use of a custom NTP server was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105514) in GitLab 15.7.
|
||||
|
||||
This Rake task can be run on a **Rails** node in the **primary** or **secondary**
|
||||
Geo sites:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... yes
|
||||
GitLab Geo is enabled ... yes
|
||||
This machine's Geo node name matches a database record ... yes, found a secondary node named "Shanghai"
|
||||
GitLab Geo tracking database is correctly configured ... yes
|
||||
Database replication enabled? ... yes
|
||||
Database replication working? ... yes
|
||||
GitLab Geo HTTP(S) connectivity ...
|
||||
* Can connect to the primary node ... yes
|
||||
HTTP/HTTPS repository cloning is enabled ... yes
|
||||
Machine clock is synchronized ... yes
|
||||
Git user has default SSH configuration? ... yes
|
||||
OpenSSH configured to use AuthorizedKeysCommand ... yes
|
||||
GitLab configured to disable writing to authorized_keys file ... yes
|
||||
GitLab configured to store new projects in hashed storage? ... yes
|
||||
All projects are in hashed storage? ... yes
|
||||
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
You can also specify a custom NTP server using environment variables. For example:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check NTP_HOST="ntp.ubuntu.com" NTP_TIMEOUT="30"
|
||||
```
|
||||
|
||||
The following environment variables are supported.
|
||||
|
||||
| Variable | Description | Default value |
|
||||
| ----------- | ----------- | ------------- |
|
||||
|`NTP_HOST` | The NTP host. | `pool.ntp.org` |
|
||||
|`NTP_PORT` | The NTP port the host listens on. |`ntp`|
|
||||
|`NTP_TIMEOUT`| The NTP timeout in seconds. | The value defined in the `net-ntp` Ruby library ([60 seconds](https://github.com/zencoder/net-ntp/blob/3d0990214f439a5127782e0f50faeaf2c8ca7023/lib/net/ntp/ntp.rb#L6)). |
|
||||
|
||||
If the Rake task skips the `OpenSSH configured to use AuthorizedKeysCommand` check, the
|
||||
following output displays:
|
||||
|
||||
```plaintext
|
||||
OpenSSH configured to use AuthorizedKeysCommand ... skipped
|
||||
Reason:
|
||||
Cannot access OpenSSH configuration file
|
||||
Try fixing it:
|
||||
This is expected if you are using SELinux. You may want to check configuration manually
|
||||
For more information see:
|
||||
doc/administration/operations/fast_ssh_key_lookup.md
|
||||
```
|
||||
|
||||
This issue may occur if:
|
||||
|
||||
- You [use SELinux](../../../operations/fast_ssh_key_lookup.md#selinux-support-and-limitations).
|
||||
- You don't use SELinux, and the `git` user cannot access the OpenSSH configuration file due to restricted file permissions.
|
||||
|
||||
In the latter case, the following output shows that only the `root` user can read this file:
|
||||
|
||||
```plaintext
|
||||
sudo stat -c '%G:%U %A %a %n' /etc/ssh/sshd_config
|
||||
|
||||
root:root -rw------- 600 /etc/ssh/sshd_config
|
||||
```
|
||||
|
||||
To allow the `git` user to read the OpenSSH configuration file, without changing the file owner or permissions, use `acl`:
|
||||
|
||||
```plaintext
|
||||
sudo setfacl -m u:git:r /etc/ssh/sshd_config
|
||||
```
|
||||
|
||||
#### Sync status Rake task
|
||||
|
||||
Current sync information can be found manually by running this Rake task on any
|
||||
node running Rails (Puma, Sidekiq, or Geo Log Cursor) on the Geo **secondary** site.
|
||||
|
||||
GitLab does **not** verify objects that are stored in Object Storage. If you are using Object Storage, you will see all of the "verified" checks showing 0 successes. This is expected and not a cause for concern.
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake geo:status
|
||||
```
|
||||
|
||||
The output includes:
|
||||
|
||||
- a count of "failed" items if any failures occurred
|
||||
- the percentage of "succeeded" items, relative to the "total"
|
||||
|
||||
Example:
|
||||
|
||||
```plaintext
|
||||
http://secondary.example.com/
|
||||
-----------------------------------------------------
|
||||
GitLab Version: 14.9.2-ee
|
||||
Geo Role: Secondary
|
||||
Health Status: Healthy
|
||||
Project Repositories: succeeded 12345 / total 12345 (100%)
|
||||
Project Wiki Repositories: succeeded 6789 / total 6789 (100%)
|
||||
Attachments: succeeded 4 / total 4 (100%)
|
||||
CI job artifacts: succeeded 0 / total 0 (0%)
|
||||
Design management repositories: succeeded 1 / total 1 (100%)
|
||||
LFS Objects: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Merge Request Diffs: succeeded 0 / total 0 (0%)
|
||||
Package Files: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Terraform State Versions: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Snippet Repositories: failed 1 / succeeded 2 / total 3 (67%)
|
||||
Group Wiki Repositories: succeeded 4 / total 4 (100%)
|
||||
Pipeline Artifacts: failed 3 / succeeded 0 / total 3 (0%)
|
||||
Pages Deployments: succeeded 0 / total 0 (0%)
|
||||
Repositories Checked: failed 5 / succeeded 0 / total 5 (0%)
|
||||
Package Files Verified: succeeded 0 / total 10 (0%)
|
||||
Terraform State Versions Verified: succeeded 0 / total 10 (0%)
|
||||
Snippet Repositories Verified: succeeded 99 / total 100 (99%)
|
||||
Pipeline Artifacts Verified: succeeded 0 / total 10 (0%)
|
||||
Project Repositories Verified: succeeded 12345 / total 12345 (100%)
|
||||
Project Wiki Repositories Verified: succeeded 6789 / total 6789 (100%)
|
||||
Sync Settings: Full
|
||||
Database replication lag: 0 seconds
|
||||
Last event ID seen from primary: 12345 (about 2 minutes ago)
|
||||
Last event ID processed: 12345 (about 2 minutes ago)
|
||||
Last status report was: 1 minute ago
|
||||
```
|
||||
|
||||
Each item can have up to three statuses. For example, for `Project Repositories`, you see the following lines:
|
||||
|
||||
```plaintext
|
||||
Project Repositories: succeeded 12345 / total 12345 (100%)
|
||||
Project Repositories Verified: succeeded 12345 / total 12345 (100%)
|
||||
Repositories Checked: failed 5 / succeeded 0 / total 5 (0%)
|
||||
```
|
||||
|
||||
The 3 status items are defined as follows:
|
||||
|
||||
- The `Project Repositories` output shows how many project repositories are synced from the primary to the secondary.
|
||||
- The `Project Verified Repositories` output shows how many project repositories on this secondary have a matching repository checksum with the Primary.
|
||||
- The `Repositories Checked` output shows how many project repositories have passed a local Git repository check (`git fsck`) on the secondary.
|
||||
|
||||
To find more details about failed items, check
|
||||
[the `gitlab-rails/geo.log` file](../../../logs/log_parsing.md#find-most-common-geo-sync-errors)
|
||||
|
||||
If you notice replication or verification failures, you can try to [resolve them](replication.md#fixing-non-postgresql-replication-failures).
|
||||
|
||||
If there are Repository check failures, you can try to [resolve them](synchronization.md#find-repository-check-failures-in-a-geo-secondary-site).
|
||||
|
||||
##### Fixing errors found when running the Geo check Rake task
|
||||
|
||||
When running this Rake task, you may see error messages if the nodes are not properly configured:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check
|
||||
```
|
||||
|
||||
- Rails did not provide a password when connecting to the database.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... Exception: fe_sendauth: no password supplied
|
||||
GitLab Geo is enabled ... Exception: fe_sendauth: no password supplied
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Ensure you have the `gitlab_rails['db_password']` set to the plain-text
|
||||
password used when creating the hash for `postgresql['sql_user_password']`.
|
||||
|
||||
- Rails is unable to connect to the database.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
|
||||
FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
|
||||
GitLab Geo is enabled ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
|
||||
FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Ensure you have the IP address of the rails node included in `postgresql['md5_auth_cidr_addresses']`.
|
||||
Also, ensure you have included the subnet mask on the IP address: `postgresql['md5_auth_cidr_addresses'] = ['1.1.1.1/32']`.
|
||||
|
||||
- Rails has supplied the incorrect password.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
GitLab Geo is available ... Exception: FATAL: password authentication failed for user "gitlab"
|
||||
FATAL: password authentication failed for user "gitlab"
|
||||
GitLab Geo is enabled ... Exception: FATAL: password authentication failed for user "gitlab"
|
||||
FATAL: password authentication failed for user "gitlab"
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Verify the correct password is set for `gitlab_rails['db_password']` that was
|
||||
used when creating the hash in `postgresql['sql_user_password']` by running
|
||||
`gitlab-ctl pg-password-md5 gitlab` and entering the password.
|
||||
|
||||
- Check returns `not a secondary node`.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... yes
|
||||
GitLab Geo is enabled ... yes
|
||||
GitLab Geo tracking database is correctly configured ... not a secondary node
|
||||
Database replication enabled? ... not a secondary node
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
Ensure you have added the secondary site in the Admin Area under **Geo > Sites** on the web interface for the **primary** site.
|
||||
Also ensure you entered the `gitlab_rails['geo_node_name']`
|
||||
when adding the secondary site in the Admin Area of the **primary** site.
|
||||
In GitLab 12.3 and earlier, edit the secondary site in the Admin Area of the **primary**
|
||||
site and ensure that there is a trailing `/` in the `Name` field.
|
||||
|
||||
- Check returns `Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist`.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... no
|
||||
Try fixing it:
|
||||
Add a new license that includes the GitLab Geo feature
|
||||
For more information see:
|
||||
https://about.gitlab.com/features/gitlab-geo/
|
||||
GitLab Geo is enabled ... Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist
|
||||
LINE 8: WHERE a.attrelid = '"geo_nodes"'::regclass
|
||||
^
|
||||
: SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
||||
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
||||
c.collname, col_description(a.attrelid, a.attnum) AS comment
|
||||
FROM pg_attribute a
|
||||
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
||||
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
||||
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
|
||||
WHERE a.attrelid = '"geo_nodes"'::regclass
|
||||
AND a.attnum > 0 AND NOT a.attisdropped
|
||||
ORDER BY a.attnum
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
When performing a PostgreSQL major version (9 > 10), update this is expected. Follow
|
||||
the [initiate-the-replication-process](../../setup/database.md#step-3-initiate-the-replication-process).
|
||||
|
||||
- Rails does not appear to have the configuration necessary to connect to the Geo tracking database.
|
||||
|
||||
```plaintext
|
||||
Checking Geo ...
|
||||
|
||||
GitLab Geo is available ... yes
|
||||
GitLab Geo is enabled ... yes
|
||||
GitLab Geo tracking database is correctly configured ... no
|
||||
Try fixing it:
|
||||
Rails does not appear to have the configuration necessary to connect to the Geo tracking database. If the tracking database is running on a node other than this one, then you may need to add configuration.
|
||||
...
|
||||
Checking Geo ... Finished
|
||||
```
|
||||
|
||||
- If you are running the secondary site on a single node for all services, then follow [Geo database replication - Configure the secondary server](../../setup/database.md#step-2-configure-the-secondary-server).
|
||||
- If you are running the secondary site's tracking database on its own node, then follow [Geo for multiple servers - Configure the Geo tracking database on the Geo secondary site](../multiple_servers.md#step-2-configure-the-geo-tracking-database-on-the-geo-secondary-site)
|
||||
- If you are running the secondary site's tracking database in a Patroni cluster, then follow [Geo database replication - Configuring Patroni cluster for the tracking PostgreSQL database](../../setup/database.md#configuring-patroni-cluster-for-the-tracking-postgresql-database)
|
||||
- If you are running the secondary site's tracking database in an external database, then follow [Geo with external PostgreSQL instances](../../setup/external_database.md#configure-the-tracking-database)
|
||||
- If the Geo check task was run on a node which is not running a service which runs the GitLab Rails app (Puma, Sidekiq, or Geo Log Cursor), then this error can be ignored. The node does not need Rails to be configured.
|
||||
|
||||
##### Message: Machine clock is synchronized ... Exception
|
||||
|
||||
The Rake task attempts to verify that the server clock is synchronized with NTP. Synchronized clocks
|
||||
are required for Geo to function correctly. As an example, for security, when the server time on the
|
||||
primary site and secondary site differ by about a minute or more, requests between Geo sites
|
||||
fail. If this check task fails to complete due to a reason other than mismatching times, it
|
||||
does not necessarily mean that Geo will not work.
|
||||
|
||||
The Ruby gem which performs the check is hard coded with `pool.ntp.org` as its reference time source.
|
||||
|
||||
- Exception message `Machine clock is synchronized ... Exception: Timeout::Error`
|
||||
|
||||
This issue occurs when your server cannot access the host `pool.ntp.org`.
|
||||
|
||||
- Exception message `Machine clock is synchronized ... Exception: No route to host - recvfrom(2)`
|
||||
|
||||
This issue occurs when the hostname `pool.ntp.org` resolves to a server which does not provide a time service.
|
||||
|
||||
In this case, in GitLab 15.7 and later, [specify a custom NTP server using environment variables](#health-check-rake-task).
|
||||
|
||||
In GitLab 15.6 and earlier, use one of the following workarounds:
|
||||
|
||||
- Add entries in `/etc/hosts` for `pool.ntp.org` to direct the request to valid local time servers.
|
||||
This fixes the long timeout and the timeout error.
|
||||
- Direct the check to any valid IP address. This resolves the timeout issue, but the check fails
|
||||
with the `No route to host` error, as noted above.
|
||||
|
||||
[Cloud native GitLab deployments](https://docs.gitlab.com/charts/advanced/geo/#set-the-geo-primary-site)
|
||||
generate an error because containers in Kubernetes do not have access to the host clock:
|
||||
|
||||
```plaintext
|
||||
Machine clock is synchronized ... Exception: getaddrinfo: Servname not supported for ai_socktype
|
||||
```
|
||||
|
||||
##### Message: `ActiveRecord::StatementInvalid: PG::ReadOnlySqlTransaction: ERROR: cannot execute INSERT in a read-only transaction`
|
||||
|
||||
When this error is encountered on a secondary site, it likely affects all usages of GitLab Rails such as `gitlab-rails` or `gitlab-rake` commands, as well the Puma, Sidekiq, and Geo Log Cursor services.
|
||||
|
||||
```plaintext
|
||||
ActiveRecord::StatementInvalid: PG::ReadOnlySqlTransaction: ERROR: cannot execute INSERT in a read-only transaction
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/application_record.rb:86:in `block in safe_find_or_create_by'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/concerns/cross_database_modification.rb:92:in `block in transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/database.rb:332:in `block in transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/database.rb:331:in `transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/concerns/cross_database_modification.rb:83:in `transaction'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/application_record.rb:86:in `safe_find_or_create_by'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:21:in `by_name'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:17:in `block in populate!'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:17:in `map'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/app/models/shard.rb:17:in `populate!'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/config/initializers/fill_shards.rb:9:in `<top (required)>'
|
||||
/opt/gitlab/embedded/service/gitlab-rails/config/environment.rb:7:in `<top (required)>'
|
||||
/opt/gitlab/embedded/bin/bundle:23:in `load'
|
||||
/opt/gitlab/embedded/bin/bundle:23:in `<main>'
|
||||
```
|
||||
|
||||
The PostgreSQL read-replica database would be producing these errors:
|
||||
|
||||
```plaintext
|
||||
2023-01-17_17:44:54.64268 ERROR: cannot execute INSERT in a read-only transaction
|
||||
2023-01-17_17:44:54.64271 STATEMENT: /*application:web,db_config_name:main*/ INSERT INTO "shards" ("name") VALUES ('storage1') RETURNING "id"
|
||||
```
|
||||
|
||||
This situation can occur during initial configuration when a secondary site is not yet aware that it is a secondary site.
|
||||
|
||||
To resolve the error, follow [Step 3. Add the secondary site](../configuration.md#step-3-add-the-secondary-site).
|
||||
|
||||
### Check if PostgreSQL replication is working
|
||||
|
||||
To check if PostgreSQL replication is working, check if:
|
||||
|
||||
- [Sites are pointing to the correct database node](#are-sites-pointing-to-the-correct-database-node).
|
||||
- [Geo can detect the current site correctly](#can-geo-detect-the-current-site-correctly).
|
||||
|
||||
#### Are sites pointing to the correct database node?
|
||||
|
||||
You should make sure your **primary** Geo [site](../../glossary.md) points to
|
||||
the database node that has write permissions.
|
||||
|
||||
Any **secondary** sites should point only to read-only database nodes.
|
||||
|
||||
#### Can Geo detect the current site correctly?
|
||||
|
||||
Geo finds the current Puma or Sidekiq node's Geo [site](../../glossary.md) name in
|
||||
`/etc/gitlab/gitlab.rb` with the following logic:
|
||||
|
||||
1. Get the "Geo node name" (there is
|
||||
[an issue to rename the settings to "Geo site name"](https://gitlab.com/gitlab-org/gitlab/-/issues/335944)):
|
||||
- Linux package: get the `gitlab_rails['geo_node_name']` setting.
|
||||
- GitLab Helm charts: get the `global.geo.nodeName` setting (see [Charts with GitLab Geo](https://docs.gitlab.com/charts/advanced/geo/index.html)).
|
||||
1. If that is not defined, then get the `external_url` setting.
|
||||
|
||||
This name is used to look up the Geo site with the same **Name** in the **Geo Sites**
|
||||
dashboard.
|
||||
|
||||
To check if the current machine has a site name that matches a site in the
|
||||
database, run the check task:
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake gitlab:geo:check
|
||||
```
|
||||
|
||||
It displays the current machine's site name and whether the matching database
|
||||
record is a **primary** or **secondary** site.
|
||||
|
||||
```plaintext
|
||||
This machine's Geo node name matches a database record ... yes, found a secondary node named "Shanghai"
|
||||
```
|
||||
|
||||
```plaintext
|
||||
This machine's Geo node name matches a database record ... no
|
||||
Try fixing it:
|
||||
You could add or update a Geo node database record, setting the name to "https://example.com/".
|
||||
Or you could set this machine's Geo node name to match the name of an existing database record: "London", "Shanghai"
|
||||
For more information see:
|
||||
doc/administration/geo/replication/troubleshooting/index.md#can-geo-detect-the-current-node-correctly
|
||||
```
|
||||
|
||||
For more information about recommended site names in the description of the Name field, see
|
||||
[Geo Admin Area Common Settings](../../../../administration/geo_sites.md#common-settings).
|
||||
|
||||
### Check OS locale data compatibility
|
||||
|
||||
If different operating systems or different operating system versions are deployed across Geo sites, you **must** perform a locale data compatibility check before setting up Geo.
|
||||
|
||||
Geo uses PostgreSQL and Streaming Replication to replicate data across Geo sites. PostgreSQL uses locale data provided by the operating system's C library for sorting text. If the locale data in the C library is incompatible across Geo sites, it causes erroneous query results that lead to [incorrect behavior on secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/360723).
|
||||
|
||||
For example, Ubuntu 18.04 (and earlier) and RHEL/Centos7 (and earlier) are incompatible with their later releases.
|
||||
See the [PostgreSQL wiki for more details](https://wiki.postgresql.org/wiki/Locale_data_changes).
|
||||
|
||||
On all hosts running PostgreSQL, across all Geo sites, run the following shell command:
|
||||
|
||||
```shell
|
||||
( echo "1-1"; echo "11" ) | LC_COLLATE=en_US.UTF-8 sort
|
||||
```
|
||||
|
||||
The output looks like either:
|
||||
|
||||
```plaintext
|
||||
1-1
|
||||
11
|
||||
```
|
||||
|
||||
or the reverse order:
|
||||
|
||||
```plaintext
|
||||
11
|
||||
1-1
|
||||
```
|
||||
|
||||
If the output is **identical** on all hosts, then they running compatible versions of locale data and you may proceed with Geo configuration.
|
||||
|
||||
If the output **differs** on any hosts, PostgreSQL replication will not work properly: indexes will become corrupted on the database replicas. You **must** select operating system versions that are compatible.
|
||||
|
||||
A full index rebuild is required if the on-disk data is transferred 'at rest' to an operating system with an incompatible locale, or through replication.
|
||||
|
||||
This check is also required when using a mixture of GitLab deployments. The locale might be different between an Linux package install, a GitLab Docker container, a Helm chart deployment, or external database services.
|
||||
|
||||
## Replication errors
|
||||
|
||||
See [replication troubleshooting](replication.md).
|
||||
|
||||
## Synchronization errors
|
||||
|
||||
See [synchronization troubleshooting](synchronization.md).
|
||||
|
||||
## Failover errors
|
||||
|
||||
See [failover troubleshooting](failover.md).
|
||||
|
||||
## HTTP response code errors
|
||||
|
||||
### Secondary site returns 502 errors with Geo proxying
|
||||
|
||||
When [Geo proxying for secondary sites](../../secondary_proxy/index.md) is enabled, and the secondary site user interface returns
|
||||
502 errors, it is possible that the response header proxied from the primary site is too large.
|
||||
|
||||
Check the NGINX logs for errors similar to this example:
|
||||
|
||||
```plaintext
|
||||
2022/01/26 00:02:13 [error] 26641#0: *829148 upstream sent too big header while reading response header from upstream, client: 10.0.2.2, server: geo.staging.gitlab.com, request: "POST /users/sign_in HTTP/2.0", upstream: "http://unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket:/users/sign_in", host: "geo.staging.gitlab.com", referrer: "https://geo.staging.gitlab.com/users/sign_in"
|
||||
```
|
||||
|
||||
To resolve this issue:
|
||||
|
||||
1. Set `nginx['proxy_custom_buffer_size'] = '8k'` in `/etc/gitlab.rb` on all web nodes on the secondary site.
|
||||
1. Reconfigure the **secondary** using `sudo gitlab-ctl reconfigure`.
|
||||
|
||||
If you still get this error, you can further increase the buffer size by repeating the steps above
|
||||
and changing the `8k` size, for example by doubling it to `16k`.
|
||||
|
||||
### Geo Admin Area shows 'Unknown' for health status and 'Request failed with status code 401'
|
||||
|
||||
If using a load balancer, ensure that the load balancer's URL is set as the `external_url` in the
|
||||
`/etc/gitlab/gitlab.rb` of the nodes behind the load balancer.
|
||||
|
||||
### Primary site returns 500 error when accessing `/admin/geo/replication/projects`
|
||||
|
||||
Navigating to **Admin > Geo > Replication** (or `/admin/geo/replication/projects`) on a primary Geo site, shows a 500 error, while that same link on the secondary works fine. The primary's `production.log` has a similar entry to the following:
|
||||
|
||||
```plaintext
|
||||
Geo::TrackingBase::SecondaryNotConfigured: Geo secondary database is not configured
|
||||
from ee/app/models/geo/tracking_base.rb:26:in `connection'
|
||||
[..]
|
||||
from ee/app/views/admin/geo/projects/_all.html.haml:1
|
||||
```
|
||||
|
||||
On a Geo primary site this error can be ignored.
|
||||
|
||||
This happens because GitLab is attempting to display registries from the [Geo tracking database](../../../../administration/geo/index.md#geo-tracking-database) which doesn't exist on the primary site (only the original projects exist on the primary; no replicated projects are present, therefore no tracking database exists).
|
||||
|
||||
### Secondary site returns 400 error "Request header or cookie too large"
|
||||
|
||||
This error can happen when the internal URL of the primary site is incorrect.
|
||||
|
||||
For example, when you use a unified URL and the primary site's internal URL is also equal to the external URL. This causes a loop when a secondary site proxies requests to the primary site's internal URL.
|
||||
|
||||
To fix this issue, set the primary site's internal URL to a URL that is:
|
||||
|
||||
- Unique to the primary site.
|
||||
- Accessible from all secondary sites.
|
||||
|
||||
1. Visit the primary site.
|
||||
1. [Set up the internal URLs](../../../../administration/geo_sites.md#set-up-the-internal-urls).
|
||||
|
||||
### Secondary site returns `Received HTTP code 403 from proxy after CONNECT`
|
||||
|
||||
If you have installed GitLab using the Linux package (Omnibus) and have configured the `no_proxy` [custom environment variable](https://docs.gitlab.com/omnibus/settings/environment-variables.html) for Gitaly, you may experience this issue. Affected versions:
|
||||
|
||||
- `15.4.6`
|
||||
- `15.5.0`-`15.5.6`
|
||||
- `15.6.0`-`15.6.3`
|
||||
- `15.7.0`-`15.7.1`
|
||||
|
||||
This is due to [a bug introduced in the included version of cURL](https://github.com/curl/curl/issues/10122) shipped with
|
||||
the Linux package 15.4.6 and later. You should upgrade to a later version where this has been
|
||||
[fixed](https://about.gitlab.com/releases/2023/01/09/security-release-gitlab-15-7-2-released/).
|
||||
|
||||
The bug causes all wildcard domains (`.example.com`) to be ignored except for the last on in the `no_proxy` environment variable list. Therefore, if for any reason you cannot upgrade to a newer version, you can work around the issue by moving your wildcard domain to the end of the list:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
gitaly['env'] = {
|
||||
"no_proxy" => "sever.yourdomain.org, .yourdomain.com",
|
||||
}
|
||||
```
|
||||
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
You can have only one wildcard domain in the `no_proxy` list.
|
||||
|
||||
### Geo Admin Area returns 404 error for a secondary site
|
||||
|
||||
Sometimes `sudo gitlab-rake gitlab:geo:check` indicates that **Rails nodes of the secondary** sites are
|
||||
healthy, but a 404 Not Found error message for the **secondary** site is returned in the Geo Admin Area on the web interface for
|
||||
the **primary** site.
|
||||
|
||||
To resolve this issue:
|
||||
|
||||
- Try restarting **each Rails, Sidekiq and Gitaly nodes on your secondary site** using `sudo gitlab-ctl restart`.
|
||||
- Check `/var/log/gitlab/gitlab-rails/geo.log` on Sidekiq nodes to see if the **secondary** site is
|
||||
using IPv6 to send its status to the **primary** site. If it is, add an entry to
|
||||
the **primary** site using IPv4 in the `/etc/hosts` file. Alternatively, you should
|
||||
[enable IPv6 on the **primary** site](https://docs.gitlab.com/omnibus/settings/nginx.html#setting-the-nginx-listen-address-or-addresses).
|
||||
|
||||
## Fixing common errors
|
||||
|
||||
This section documents common error messages reported in the Admin Area on the web interface, and how to fix them.
|
||||
|
||||
### Geo database configuration file is missing
|
||||
|
||||
GitLab cannot find or doesn't have permission to access the `database_geo.yml` configuration file.
|
||||
|
||||
In a Linux package installation, the file should be in `/var/opt/gitlab/gitlab-rails/etc`.
|
||||
If it doesn't exist or inadvertent changes have been made to it, run `sudo gitlab-ctl reconfigure` to restore it to its correct state.
|
||||
|
||||
If this path is mounted on a remote volume, ensure your volume configuration
|
||||
has the correct permissions.
|
||||
|
||||
### An existing tracking database cannot be reused
|
||||
|
||||
Geo cannot reuse an existing tracking database.
|
||||
|
||||
It is safest to use a fresh secondary, or reset the whole secondary by following
|
||||
[Resetting Geo secondary site replication](replication.md#resetting-geo-secondary-site-replication).
|
||||
|
||||
It is risky to reuse a secondary site without resetting it because the secondary site may have missed some Geo events. For example, missed deletion events lead to the secondary site permanently having data that should be deleted. Similarly, losing an event which physically moves the location of data leads to data permanently orphaned in one location, and missing in the other location until it is re-verified. This is why GitLab switched to hashed storage, since it makes moving data unnecessary. There may be other unknown problems due to lost events.
|
||||
|
||||
If these kinds of risks do not apply, for example in a test environment, or if you know that the main Postgres database still contains all Geo events since the Geo site was added, then you can bypass this health check:
|
||||
|
||||
1. Get the last processed event time. In Rails console in the secondary site, run:
|
||||
|
||||
```ruby
|
||||
Geo::EventLogState.last.created_at.utc
|
||||
```
|
||||
|
||||
1. Copy the output, for example `2024-02-21 23:50:50.676918 UTC`.
|
||||
1. Update the created time of the secondary site to make it appear older. In Rails console in the primary site, run:
|
||||
|
||||
```ruby
|
||||
GeoNode.secondary_nodes.last.update_column(:created_at, DateTime.parse('2024-02-21 23:50:50.676918 UTC') - 1.second)
|
||||
```
|
||||
|
||||
This command assumes that the affected secondary site is the one that was created last.
|
||||
|
||||
1. Update the secondary site's status in **Admin > Geo > Sites**. In Rails console in the secondary site, run:
|
||||
|
||||
```ruby
|
||||
Geo::MetricsUpdateWorker.new.perform
|
||||
```
|
||||
|
||||
1. The secondary site should appear healthy. If it does not, run `gitlab-rake gitlab:geo:check` on the secondary site, or try restarting Rails if you haven't done so since re-adding the secondary site.
|
||||
1. To resync missing or out-of-date data, go to **Admin > Geo > Sites**.
|
||||
1. Under the secondary site select **Replication Details**.
|
||||
1. Select **Reverify all** for every data type.
|
||||
|
||||
### Geo site has a database that is writable which is an indication it is not configured for replication with the primary site
|
||||
|
||||
This error message refers to a problem with the database replica on a **secondary** site,
|
||||
which Geo expects to have access to. It usually means, either:
|
||||
|
||||
- An unsupported replication method was used (for example, logical replication).
|
||||
- The instructions to set up a [Geo database replication](../../setup/database.md) were not followed correctly.
|
||||
- Your database connection details are incorrect, that is you have specified the wrong
|
||||
user in your `/etc/gitlab/gitlab.rb` file.
|
||||
|
||||
Geo **secondary** sites require two separate PostgreSQL instances:
|
||||
|
||||
- A read-only replica of the **primary** site.
|
||||
- A regular, writable instance that holds replication metadata. That is, the Geo tracking database.
|
||||
|
||||
This error message indicates that the replica database in the **secondary** site is misconfigured and replication has stopped.
|
||||
|
||||
To restore the database and resume replication, you can do one of the following:
|
||||
|
||||
- [Reset the Geo secondary site replication](replication.md#resetting-geo-secondary-site-replication).
|
||||
- [Set up a new Geo secondary using the Linux package](../../setup/index.md#using-linux-package-installations).
|
||||
|
||||
If you set up a new secondary from scratch, you must also [remove the old site from the Geo cluster](../remove_geo_site.md#removing-secondary-geo-sites).
|
||||
|
||||
### Geo site does not appear to be replicating the database from the primary site
|
||||
|
||||
The most common problems that prevent the database from replicating correctly are:
|
||||
|
||||
- **Secondary** sites cannot reach the **primary** site. Check credentials and
|
||||
[firewall rules](../../index.md#firewall-rules).
|
||||
- SSL certificate problems. Make sure you copied `/etc/gitlab/gitlab-secrets.json` from the **primary** site.
|
||||
- Database storage disk is full.
|
||||
- Database replication slot is misconfigured.
|
||||
- Database is not using a replication slot or another alternative and cannot catch-up because WAL files were purged.
|
||||
|
||||
Make sure you follow the [Geo database replication](../../setup/database.md) instructions for supported configuration.
|
||||
|
||||
### Geo database version (...) does not match latest migration (...)
|
||||
|
||||
If you are using the Linux package installation, something might have failed during upgrade. You can:
|
||||
|
||||
- Run `sudo gitlab-ctl reconfigure`.
|
||||
- Manually trigger the database migration by running: `sudo gitlab-rake db:migrate:geo` as root on the **secondary** site.
|
||||
|
||||
### GitLab indicates that more than 100% of repositories were synced
|
||||
|
||||
This can be caused by orphaned records in the project registry. They are being cleaned
|
||||
periodically using a registry worker, so give it some time to fix it itself.
|
||||
|
||||
### Secondary site shows "Unhealthy" in UI after changing the value of `external_url` for the primary site
|
||||
|
||||
If you have updated the value of `external_url` in `/etc/gitlab/gitlab.rb` for the primary site or changed the protocol from `http` to `https`, you may see that secondary sites are shown as `Unhealthy`. You may also find the following error in `geo.log`:
|
||||
|
||||
```plaintext
|
||||
"class": "Geo::NodeStatusRequestService",
|
||||
...
|
||||
"message": "Failed to Net::HTTP::Post to primary url: http://primary-site.gitlab.tld/api/v4/geo/status",
|
||||
"error": "Failed to open TCP connection to <PRIMARY_IP_ADDRESS>:80 (Connection refused - connect(2) for \"<PRIMARY_ID_ADDRESS>\" port 80)"
|
||||
```
|
||||
|
||||
In this case, make sure to update the changed URL on all your sites:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **Geo > Sites**.
|
||||
1. Change the URL and save the change.
|
||||
|
||||
### Message: `ERROR: canceling statement due to conflict with recovery` during backup
|
||||
|
||||
Running a backup on a Geo **secondary** [is not supported](https://gitlab.com/gitlab-org/gitlab/-/issues/211668).
|
||||
|
||||
When running a backup on a **secondary** you might encounter the following error message:
|
||||
|
||||
```plaintext
|
||||
Dumping PostgreSQL database gitlabhq_production ...
|
||||
pg_dump: error: Dumping the contents of table "notes" failed: PQgetResult() failed.
|
||||
pg_dump: error: Error message from server: ERROR: canceling statement due to conflict with recovery
|
||||
DETAIL: User query might have needed to see row versions that must be removed.
|
||||
pg_dump: error: The command was: COPY public.notes (id, note, [...], last_edited_at) TO stdout;
|
||||
```
|
||||
|
||||
To prevent a database backup being made automatically during GitLab upgrades on your Geo **secondaries**,
|
||||
create the following empty file:
|
||||
|
||||
```shell
|
||||
sudo touch /etc/gitlab/skip-auto-backup
|
||||
```
|
||||
|
||||
## Fixing client errors
|
||||
|
||||
### Authorization errors from LFS HTTP(S) client requests
|
||||
|
||||
You may have problems if you're running a version of [Git LFS](https://git-lfs.com/) before 2.4.2.
|
||||
As noted in [this authentication issue](https://github.com/git-lfs/git-lfs/issues/3025),
|
||||
requests redirected from the secondary to the primary site do not properly send the
|
||||
Authorization header. This may result in either an infinite `Authorization <-> Redirect`
|
||||
loop, or Authorization error messages.
|
||||
|
||||
### Error: Net::ReadTimeout when pushing through SSH on a Geo secondary
|
||||
|
||||
When you push large repositories through SSH on a Geo secondary site, you may encounter a timeout.
|
||||
This is because Rails proxies the push to the primary and has a 60 second default timeout,
|
||||
[as described in this Geo issue](https://gitlab.com/gitlab-org/gitlab/-/issues/7405).
|
||||
|
||||
Current workarounds are:
|
||||
|
||||
- Push through HTTP instead, where Workhorse proxies the request to the primary (or redirects to the primary if Geo proxying is not enabled).
|
||||
- Push directly to the primary.
|
||||
|
||||
Example log (`gitlab-shell.log`):
|
||||
|
||||
```plaintext
|
||||
Failed to contact primary https://primary.domain.com/namespace/push_test.git\\nError: Net::ReadTimeout\",\"result\":null}" code=500 method=POST pid=5483 url="http://127.0.0.1:3000/api/v4/geo/proxy_git_push_ssh/push"
|
||||
```
|
||||
|
||||
### Repair OAuth authorization between Geo sites
|
||||
|
||||
When upgrading a Geo site, you might not be able to log in into a secondary site that only uses OAuth for authentication. In that case, start a [Rails console](../../../operations/rails_console.md) session on your primary site and perform the following steps:
|
||||
|
||||
1. To find the affected node, first list all the Geo Nodes you have:
|
||||
|
||||
```ruby
|
||||
GeoNode.all
|
||||
```
|
||||
|
||||
1. Repair the affected Geo node by specifying the ID:
|
||||
|
||||
```ruby
|
||||
GeoNode.find(<id>).repair
|
||||
```
|
||||
- Basic troubleshooting and [common errors](common.md)
|
||||
- [Client and HTTP response code errors](client_http.md)
|
||||
- [Replication errors](replication.md)
|
||||
- [Synchronization errors](synchronization.md)
|
||||
- [Failover errors](failover.md)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ DETAILS:
|
|||
## Fixing PostgreSQL database replication errors
|
||||
|
||||
The following sections outline troubleshooting steps for fixing replication error messages (indicated by `Database replication working? ... no` in the
|
||||
[`geo:check` output](index.md#health-check-rake-task).
|
||||
[`geo:check` output](common.md#health-check-rake-task).
|
||||
The instructions present here mostly assume a single-node Geo Linux package deployment, and might need to be adapted to different environments.
|
||||
|
||||
### Removing an inactive replication slot
|
||||
|
|
@ -206,7 +206,7 @@ The workaround is to increase the memory available to the secondary site's Postg
|
|||
|
||||
## Fixing non-PostgreSQL replication failures
|
||||
|
||||
If you notice replication failures in `Admin > Geo > Sites` or the [Sync status Rake task](index.md#sync-status-rake-task), you can try to resolve the failures with the following general steps:
|
||||
If you notice replication failures in `Admin > Geo > Sites` or the [Sync status Rake task](common.md#sync-status-rake-task), you can try to resolve the failures with the following general steps:
|
||||
|
||||
1. Geo automatically retries failures. If the failures are new and few in number, or if you suspect the root cause is already resolved, then you can wait to see if the failures go away.
|
||||
1. If failures were present for a long time, then many retries have already occurred, and the interval between automatic retries has increased to up to 4 hours depending on the type of failure. If you suspect the root cause is already resolved, you can [manually retry replication or verification](#manually-retry-replication-or-verification).
|
||||
|
|
|
|||
|
|
@ -103,8 +103,8 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
|
|||
|
||||
```shell
|
||||
gitlab-ctl pg-password-md5 gitlab
|
||||
# Enter password: <your_password_here>
|
||||
# Confirm password: <your_password_here>
|
||||
# Enter password: <your_db_password_here>
|
||||
# Confirm password: <your_db_password_here>
|
||||
# fca0b89a972d69f00eb3ec98a5838484
|
||||
```
|
||||
|
||||
|
|
@ -112,12 +112,12 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
|
|||
|
||||
```ruby
|
||||
# Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_db_password>'
|
||||
|
||||
# Every node that runs Puma or Sidekiq needs to have the database
|
||||
# password specified as below. If you have a high-availability setup, this
|
||||
# must be present in all application nodes.
|
||||
gitlab_rails['db_password'] = '<your_password_here>'
|
||||
gitlab_rails['db_password'] = '<your_db_password_here>'
|
||||
```
|
||||
|
||||
1. Define a password for the database [replication user](https://wiki.postgresql.org/wiki/Streaming_Replication).
|
||||
|
|
@ -130,8 +130,8 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
|
|||
|
||||
```shell
|
||||
gitlab-ctl pg-password-md5 gitlab_replicator
|
||||
# Enter password: <your_password_here>
|
||||
# Confirm password: <your_password_here>
|
||||
# Enter password: <your_replication_password_here>
|
||||
# Confirm password: <your_replication_password_here>
|
||||
# 950233c0dfc2f39c64cf30457c3b7f1e
|
||||
```
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
|
|||
|
||||
```ruby
|
||||
# Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab_replicator`
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_replication_password>'
|
||||
```
|
||||
|
||||
If you are using an external database not managed by your Linux package installation, you need
|
||||
|
|
@ -432,9 +432,9 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
|
|||
## Database credentials password (defined previously in primary site)
|
||||
## - replicate same values here as defined in primary site
|
||||
##
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
|
||||
gitlab_rails['db_password'] = '<your_password_here>'
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_replication_password>'
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_db_password>'
|
||||
gitlab_rails['db_password'] = '<your_db_password_here>'
|
||||
```
|
||||
|
||||
For external PostgreSQL instances, see [additional instructions](external_database.md).
|
||||
|
|
@ -557,8 +557,8 @@ On the GitLab Geo **primary** site:
|
|||
|
||||
```shell
|
||||
sudo gitlab-ctl pg-password-md5 gitlab_replicator
|
||||
# Enter password: <your_password_here>
|
||||
# Confirm password: <your_password_here>
|
||||
# Enter password: <your_replication_password_here>
|
||||
# Confirm password: <your_replication_password_here>
|
||||
# 950233c0dfc2f39c64cf30457c3b7f1e
|
||||
```
|
||||
|
||||
|
|
@ -566,7 +566,7 @@ On the GitLab Geo **primary** site:
|
|||
|
||||
```ruby
|
||||
# Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab_replicator`
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_replication_password>'
|
||||
```
|
||||
|
||||
1. Save the file and reconfigure GitLab to change the replication user's password in PostgreSQL:
|
||||
|
|
@ -598,7 +598,7 @@ On all GitLab Geo **secondary** sites:
|
|||
|
||||
```ruby
|
||||
# Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab_replicator` on the Geo primary
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_replication_password>'
|
||||
```
|
||||
|
||||
1. During the initial replication setup, the `gitlab-ctl replicate-geo-database` command writes the plaintext
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ To configure the connection to the external read-replica database and enable Log
|
|||
|
||||
# note this is shared between both databases,
|
||||
# make sure you define the same password in both
|
||||
gitlab_rails['db_password'] = '<your_password_here>'
|
||||
gitlab_rails['db_password'] = '<your_primary_db_password_here>'
|
||||
|
||||
gitlab_rails['db_username'] = 'gitlab'
|
||||
gitlab_rails['db_host'] = '<database_read_replica_host>'
|
||||
|
|
@ -257,7 +257,7 @@ Configure GitLab to use this database. These steps are for Linux package and Doc
|
|||
|
||||
```ruby
|
||||
geo_secondary['db_username'] = 'gitlab_geo'
|
||||
geo_secondary['db_password'] = '<your_password_here>'
|
||||
geo_secondary['db_password'] = '<your_tracking_db_password_here>'
|
||||
|
||||
geo_secondary['db_host'] = '<tracking_database_host>'
|
||||
geo_secondary['db_port'] = <tracking_database_port> # change to the correct port
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ To configure the connection to the external read-replica database:
|
|||
|
||||
# note this is shared between both databases,
|
||||
# make sure you define the same password in both
|
||||
gitlab_rails['db_password'] = '<your_password_here>'
|
||||
gitlab_rails['db_password'] = '<your_db_password_here>'
|
||||
|
||||
gitlab_rails['db_username'] = 'gitlab'
|
||||
gitlab_rails['db_host'] = '<database_read_replica_host>'
|
||||
|
|
@ -459,7 +459,7 @@ Configure GitLab to use this database. These steps are for Linux package and Doc
|
|||
|
||||
```ruby
|
||||
geo_secondary['db_username'] = 'gitlab_geo'
|
||||
geo_secondary['db_password'] = '<your_password_here>'
|
||||
geo_secondary['db_password'] = '<your_tracking_db_password_here>'
|
||||
|
||||
geo_secondary['db_host'] = '<tracking_database_host>'
|
||||
geo_secondary['db_port'] = <tracking_database_port> # change to the correct port
|
||||
|
|
|
|||
|
|
@ -61,14 +61,19 @@ Prerequisites:
|
|||
|
||||
This command uses the `external_url` defined in `/etc/gitlab/gitlab.rb`.
|
||||
|
||||
1. Create a password for the `gitlab` database user.
|
||||
1. Create a password for the `gitlab` database user and update Rail to use the new password.
|
||||
|
||||
NOTE:
|
||||
The values configured for the `gitlab_rails['db_password']` and `postgresql['sql_user_password']` settings need to match.
|
||||
However, only the `postgresql['sql_user_password']` value should be the MD5 encrypted password.
|
||||
Changes to this are being discussed in [Rethink how we handle PostgreSQL passwords in cookbooks](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5713).
|
||||
|
||||
1. Generate a MD5 hash of the desired password:
|
||||
|
||||
```shell
|
||||
gitlab-ctl pg-password-md5 gitlab
|
||||
# Enter password: <your_password_here>
|
||||
# Confirm password: <your_password_here>
|
||||
# Enter password: <your_db_password_here>
|
||||
# Confirm password: <your_db_password_here>
|
||||
# fca0b89a972d69f00eb3ec98a5838484
|
||||
```
|
||||
|
||||
|
|
@ -76,12 +81,12 @@ Prerequisites:
|
|||
|
||||
```ruby
|
||||
# Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_db_password>'
|
||||
|
||||
# Every node that runs Puma or Sidekiq needs to have the database
|
||||
# password specified as below. If you have a high-availability setup, this
|
||||
# must be present in all application nodes.
|
||||
gitlab_rails['db_password'] = '<your_password_here>'
|
||||
gitlab_rails['db_password'] = '<your_db_password_here>'
|
||||
```
|
||||
|
||||
1. Define a password for the database [replication user](https://wiki.postgresql.org/wiki/Streaming_Replication).
|
||||
|
|
@ -93,8 +98,8 @@ Prerequisites:
|
|||
```shell
|
||||
gitlab-ctl pg-password-md5 gitlab_replicator
|
||||
|
||||
# Enter password: <your_password_here>
|
||||
# Confirm password: <your_password_here>
|
||||
# Enter password: <your_replication_password_here>
|
||||
# Confirm password: <your_replication_password_here>
|
||||
# 950233c0dfc2f39c64cf30457c3b7f1e
|
||||
```
|
||||
|
||||
|
|
@ -102,7 +107,7 @@ Prerequisites:
|
|||
|
||||
```ruby
|
||||
# Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab_replicator`
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_replication_password>'
|
||||
```
|
||||
|
||||
1. Optional. If you use an external database not managed by the Linux package, you must
|
||||
|
|
@ -320,9 +325,9 @@ Prerequisites:
|
|||
## Database credentials password (defined previously in primary site)
|
||||
## - replicate same values here as defined in primary site
|
||||
##
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_password>'
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
|
||||
gitlab_rails['db_password'] = '<your_password_here>'
|
||||
postgresql['sql_replication_password'] = '<md5_hash_of_your_replication_password>'
|
||||
postgresql['sql_user_password'] = '<md5_hash_of_your_db_password>'
|
||||
gitlab_rails['db_password'] = '<your_db_password_here>'
|
||||
```
|
||||
|
||||
Be sure to replace the IP addresses with addresses appropriate to your network configuration.
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ for example.
|
|||
|
||||
#### Find most common Geo sync errors
|
||||
|
||||
If [the `geo:status` Rake task](../geo/replication/troubleshooting/index.md#sync-status-rake-task)
|
||||
If [the `geo:status` Rake task](../geo/replication/troubleshooting/common.md#sync-status-rake-task)
|
||||
repeatedly reports that some items never reach 100%,
|
||||
the following command helps to focus on the most common errors.
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ The `gitlab:check` Rake task runs the following Rake tasks:
|
|||
It checks that each component was set up according to the installation guide and suggest fixes
|
||||
for issues found. This command must be run from your application server and doesn't work correctly on
|
||||
component servers like [Gitaly](../gitaly/configure_gitaly.md#run-gitaly-on-its-own-server).
|
||||
If you're running Geo, see also the [Geo Health check Rake task](../geo/replication/troubleshooting/index.md#health-check-rake-task).
|
||||
If you're running Geo, see also the [Geo Health check Rake task](../geo/replication/troubleshooting/common.md#health-check-rake-task).
|
||||
|
||||
You may also have a look at our troubleshooting guides for:
|
||||
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ PANIC: could not write to file 'pg_xlog/xlogtemp.123': No space left on device
|
|||
|
||||
When troubleshooting problems with Geo, you should:
|
||||
|
||||
- Review [common Geo errors](../geo/replication/troubleshooting/index.md#fixing-common-errors).
|
||||
- Review [common Geo errors](../geo/replication/troubleshooting/common.md#fixing-common-errors).
|
||||
- [Review your Geo configuration](../geo/replication/troubleshooting/index.md), including:
|
||||
- Reconfiguring hosts and ports.
|
||||
- Reviewing and fixing the user and password mappings.
|
||||
|
|
|
|||
|
|
@ -92,6 +92,10 @@ Most secrets are pushed into HashiCorp Vault and various chunks of our infrastru
|
|||
|
||||
**What will GitLab.com Cells do:**
|
||||
|
||||
The provisioning secrets and shared infrastructure secrets will be managed in Hashicorp Vault, both to be used strictly for management of tenants (Amp, CI, ...).
|
||||
Each cell will have their own set of unique secrets which will be managed in Google Secret Manager.
|
||||
The Kubernetes secrets will be synced from Google Secret Manager by the [External Secrets operator](https://external-secrets.io/).
|
||||
|
||||
[Being discussed](https://gitlab.com/gitlab-com/gl-infra/production-engineering/-/issues/25076).
|
||||
|
||||
### HAProxy
|
||||
|
|
|
|||
|
|
@ -190,15 +190,11 @@ For a deeper exploration of the impact on select features, see the [list of feat
|
|||
|
||||
### Alignment between Organization and Fulfillment
|
||||
|
||||
Fulfillment is supportive of an entity above top-level groups. Their perspective is outlined in issue [#1138](https://gitlab.com/gitlab-org/fulfillment-meta/-/issues/1138).
|
||||
Fulfillment enhancements for Organizations will happen in a different timeline to the [Cells](../cells/index.md) project and should not be seen as blockers to any Cells timelines.
|
||||
|
||||
#### Goals of Fulfillment
|
||||
For Cells 1.0, Billing remains at the top-level Group. Said otherwise, Billing will not occur at the Organization level. The guidance for Cells 1.0 is for GitLab.com SaaS customers to use a single top-level Group to keep Billing consolidated.
|
||||
|
||||
- Fulfillment has a longstanding plan to move billing from the top-level Group to a level above. This would mean that a license applies to an Organization and all its top-level Groups.
|
||||
- Fulfillment uses Zuora for billing and would like to have a 1-to-1 relationship between an Organization and their Zuora entity called BillingAccount. They want to move away from tying a license to a single top-level Group.
|
||||
- If a customer needs multiple Organizations, they will need to have a separate BillingAccount per each.
|
||||
- Ideally, a self-managed instance has a single Organization by default, which should be enough for most customers.
|
||||
- Fulfillment prefers only one additional entity.
|
||||
We are currently [evaluating future architecture designs](https://gitlab.com/gitlab-org/gitlab/-/issues/443708) (e.g. Zuora Billing Accounts being aligned to Organizations) but have yet to determine the North star direction and how/if it aligns to the Cells iterations.
|
||||
|
||||
### Open-source Contributions in Organizations
|
||||
|
||||
|
|
|
|||
|
|
@ -6,82 +6,189 @@ info: "To determine the technical writer assigned to the Stage/Group associated
|
|||
|
||||
# Contribute to built-in project templates
|
||||
|
||||
## Adding a new built-in project template
|
||||
GitLab provides some
|
||||
[built-in project templates](../user/project/index.md#create-a-project-from-a-built-in-template)
|
||||
that you can use when creating a new project.
|
||||
|
||||
If you'd like to contribute a new built-in project template to be distributed with GitLab, do the following:
|
||||
Built-in templates are sourced from the following groups:
|
||||
|
||||
1. Create a new public project with the project content you'd like to contribute in a namespace of your choosing. You can view a working example [here](https://gitlab.com/gitlab-org/project-templates/dotnetcore).
|
||||
- [`gitlab-org/project-templates`](https://gitlab.com/gitlab-org/project-templates)
|
||||
- [`pages`](https://gitlab.com/pages)
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have a working [GitLab Development Kit (GDK) environment](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/index.md).
|
||||
In particular, PostgreSQL, Praefect, and `sshd` must be working.
|
||||
- `wget` should be installed.
|
||||
|
||||
## Add a new built-in project template
|
||||
|
||||
If you'd like to contribute a new built-in project template to be distributed
|
||||
with GitLab, there are a few steps to follow.
|
||||
|
||||
### Create the project
|
||||
|
||||
1. Create a new public project with the project content you'd like to contribute in a namespace of your choosing. You can view a [working example](https://gitlab.com/gitlab-org/project-templates/dotnetcore).
|
||||
- Projects should be as simple as possible and free of any unnecessary assets or dependencies.
|
||||
1. When the project is ready for review, create a new issue in [GitLab](https://gitlab.com/gitlab-org/gitlab/issues) with a link to your project.
|
||||
1. When the project is ready for review, [create a new issue](https://gitlab.com/gitlab-org/gitlab/issues/new) with a link to your project.
|
||||
- In your issue, `@` mention the relevant Backend Engineering Manager and Product Manager for the [Create:Source Code group](https://handbook.gitlab.com/handbook/product/categories/#source-code-group).
|
||||
|
||||
To make the project template available when creating a new project, the vendoring process will have to be completed:
|
||||
### Add the logo in `gitlab-svgs`
|
||||
|
||||
1. Create a working template ([example](https://gitlab.com/gitlab-org/project-templates/dotnetcore))
|
||||
- 2 types of built-in templates are available within GitLab:
|
||||
- **Standard templates**: Available in GitLab Core, Starter and above (this is the most common type of built-in template).
|
||||
- To contribute a standard template:
|
||||
- Add details of the template in the `localized_templates_table` method in `gitlab/lib/gitlab/project_template.rb`,
|
||||
- Add details of the template in `spec/lib/gitlab/project_template_spec.rb`, in the test for the `all` method, and
|
||||
- Add details of the template in `gitlab/app/assets/javascripts/projects/default_project_templates.js`.
|
||||
- See MR [!25318](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25318) for an example
|
||||
- **Enterprise templates**: Introduced in GitLab 12.10, that are available only in GitLab Gold & Ultimate.
|
||||
- To contribute an Enterprise template:
|
||||
- Add details of the template in the `localized_ee_templates_table` method in `gitlab/ee/lib/ee/gitlab/project_template.rb`,
|
||||
- Add details of the template in `gitlab/ee/spec/lib/gitlab/project_template_spec.rb`, in the `enterprise_templates` method, and
|
||||
- Add details of the template in `gitlab/ee/app/assets/javascripts/projects/default_project_templates.js`.
|
||||
- See MR [!28187](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28187) for an example.
|
||||
All templates fetch their icons from the
|
||||
[`gitlab-svgs`](https://gitlab.com/gitlab-org/gitlab-svgs) library, so if the
|
||||
icon of the template you add is not present, you have to submit one.
|
||||
|
||||
1. Run the following in the `gitlab` project, where `$name` is the name you gave the template in `gitlab/project_template.rb`:
|
||||
See how to add a [third-party logo](https://gitlab.com/gitlab-org/gitlab-svgs/-/tree/main#adding-third-party-logos-or-trademarks).
|
||||
|
||||
```shell
|
||||
bin/rake gitlab:update_project_templates[$name]
|
||||
After the logo is added to the `main` branch,
|
||||
[the bot](https://gitlab.com/gitlab-org/frontend/renovate-gitlab-bot/) will pick the
|
||||
new release up and create an MR in `gitlab-org/gitlab`. You can now proceed to
|
||||
the next step.
|
||||
|
||||
### Add the template details
|
||||
|
||||
Two types of built-in templates are available within GitLab:
|
||||
|
||||
- **Standard templates**: Available in all GitLab tiers.
|
||||
- **Enterprise templates**: Available only in GitLab Premium and Ultimate.
|
||||
|
||||
To make the project template available when creating a new project, you must
|
||||
follow the vendoring process to create a working template.
|
||||
|
||||
#### Standard template
|
||||
|
||||
NOTE:
|
||||
See merge request [25318](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25318) for an example.
|
||||
|
||||
To contribute a standard template:
|
||||
|
||||
1. Add the details of the template in the `localized_templates_table` method in [`lib/gitlab/project_template.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/project_template.rb) using the following scheme:
|
||||
|
||||
```ruby
|
||||
ProjectTemplate.new('<template_name>', '<template_short_description>', _('<template_long_description>'), '<template_project_link>', 'illustrations/logos/<template_logo_name>.svg'),
|
||||
```
|
||||
|
||||
1. Add the details of the template in [`app/assets/javascripts/projects/default_project_templates.js`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/projects/default_project_templates.js).
|
||||
|
||||
#### Enterprise template
|
||||
|
||||
NOTE:
|
||||
See merge request [28187](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28187) for an example.
|
||||
|
||||
To contribute an Enterprise template:
|
||||
|
||||
1. Add details of the template in the `localized_ee_templates_table` method in [`ee/lib/ee/gitlab/project_template.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/ee/gitlab/project_template.rb) using the following scheme:
|
||||
|
||||
```ruby
|
||||
ProjectTemplate.new('<template_name>', '<template_short_description>', _('<template_long_description>'), '<template_project_link>', 'illustrations/logos/<template_logo_name>.svg'),
|
||||
```
|
||||
|
||||
1. Add the template name in the list of `let(:enterprise_templates)` in [`ee/spec/lib/gitlab/project_template_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/spec/lib/gitlab/project_template_spec.rb).
|
||||
1. Add details of the template in [`ee/app/assets/javascripts/projects/default_project_templates.js`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/assets/javascripts/projects/default_project_templates.js).
|
||||
|
||||
### Populate the template details
|
||||
|
||||
1. Start GDK:
|
||||
|
||||
```shell
|
||||
gdk start
|
||||
```
|
||||
|
||||
1. Run the following in the `gitlab` project, where `<template_name>` is the name you
|
||||
gave the template in `gitlab/project_template.rb`:
|
||||
|
||||
```shell
|
||||
bin/rake "gitlab:update_project_templates[<template_name>]"
|
||||
```
|
||||
|
||||
1. Regenerate the localization file in the `gitlab` project and commit the new `.pot` file:
|
||||
|
||||
```shell
|
||||
bin/rake gettext:regenerate
|
||||
```
|
||||
|
||||
1. Run the `bundle_repo` script. Make sure to pass the correct arguments, or the script may damage the folder structure.
|
||||
1. Add exported project (`$name.tar.gz`) to `gitlab/vendor/project_templates` and remove the resulting build folders `tar-base` and `project`.
|
||||
1. Run `tooling/bin/gettext_extractor locale/gitlab.pot` in the `gitlab` project and commit new `.pot` file.
|
||||
1. Add a changelog entry in the commit message (for example, `Changelog: added`).
|
||||
For more information, see [Changelog entries](changelog.md).
|
||||
1. Add an icon to [`gitlab-svgs`](https://gitlab.com/gitlab-org/gitlab-svgs), as shown in
|
||||
[this example](https://gitlab.com/gitlab-org/gitlab-svgs/merge_requests/195). If a logo
|
||||
is not available for the project, use the default 'Tanuki' logo instead.
|
||||
1. Run `yarn run svgs` on `gitlab-svgs` project and commit result.
|
||||
1. Forward changes in `gitlab-svgs` project to the `main` branch. This involves:
|
||||
- Merging your MR in `gitlab-svgs`
|
||||
- [The bot](https://gitlab.com/gitlab-org/frontend/renovate-gitlab-bot/)
|
||||
will pick the new release up and create an MR in `gitlab-org/gitlab`.
|
||||
1. After the bot-created MR created above is merged, you can rebase your template MR onto the updated `master` to pick up the new SVGs.
|
||||
1. Test everything is working.
|
||||
|
||||
### Contributing an improvement to an existing template
|
||||
## Update an existing built-in project template
|
||||
|
||||
Existing templates are available in the [project-templates](https://gitlab.com/gitlab-org/project-templates)
|
||||
group.
|
||||
To contribute a change:
|
||||
|
||||
To contribute a change, open a merge request in the relevant project
|
||||
and mention `@gitlab-org/manage/import/backend` when you are ready for a review.
|
||||
1. Open a merge request in the relevant project, and leave the following comment
|
||||
when you are ready for a review:
|
||||
|
||||
Then, if your merge request gets accepted, either open an issue on
|
||||
`gitlab` to ask for it to get updated, or open a merge request updating
|
||||
the vendored template using [these instructions](rake_tasks.md#update-project-templates).
|
||||
```plaintext
|
||||
@gitlab-org/manage/import/backend this is a contribution to update the project
|
||||
template and is ready for review!
|
||||
|
||||
### Test your built-in project with the GitLab Development Kit
|
||||
@gitlab-bot ready
|
||||
```
|
||||
|
||||
Complete the following steps to test the project template in your own GitLab Development Kit instance:
|
||||
1. If your merge request gets accepted:
|
||||
|
||||
1. Run the following Rake task, where `<path>/<name>` is the
|
||||
name you gave the template in `lib/gitlab/project_template.rb`:
|
||||
- Either [open an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new)
|
||||
to ask for it to get updated.
|
||||
- Or update the vendored template and open a merge request:
|
||||
|
||||
```shell
|
||||
bin/rake "gitlab:update_project_templates[<template_name>]"
|
||||
```
|
||||
|
||||
## Test your built-in project with the GitLab Development Kit
|
||||
|
||||
Complete the following steps to test the project template in your own
|
||||
GDK instance:
|
||||
|
||||
1. Start GDK:
|
||||
|
||||
```shell
|
||||
bin/rake gitlab:update_project_templates\[<path>/<name>\]
|
||||
gdk start
|
||||
```
|
||||
|
||||
1. Run the following Rake task, where `<template_name>` is the
|
||||
name of the template in `lib/gitlab/project_template.rb`:
|
||||
|
||||
```shell
|
||||
bin/rake "gitlab:update_project_templates[<template_name>]"
|
||||
```
|
||||
|
||||
1. Visit GitLab in your browser and create a new project by selecting the
|
||||
project template.
|
||||
|
||||
## For GitLab team members
|
||||
|
||||
Ensure the merge request has been reviewed by the Security Counterpart before merging.
|
||||
Ensure all merge requests have been reviewed by the Security counterpart before merging.
|
||||
|
||||
To review a merge request which changes a vendored project template, run the `check-template-changes` script:
|
||||
### Update all templates
|
||||
|
||||
Starting a project from a template needs this project to be exported. On a
|
||||
up to date default branch run:
|
||||
|
||||
```shell
|
||||
gdk start # postgres, praefect, and sshd are required
|
||||
bin/rake gitlab:update_project_templates
|
||||
git checkout -b update-project-templates
|
||||
git add vendor/project_templates
|
||||
git commit
|
||||
git push -u origin update-project-templates
|
||||
```
|
||||
|
||||
Now create a merge request and assign to a Security counterpart to merge.
|
||||
|
||||
### Update a single template
|
||||
|
||||
To update just a single template instead of all of them, specify the template name
|
||||
between square brackets. For example, for the `jekyll` template, run:
|
||||
|
||||
```shell
|
||||
bin/rake "gitlab:update_project_templates[jekyll]"
|
||||
```
|
||||
|
||||
### Review a template merge request
|
||||
|
||||
To review a merge request which changes one or more vendored project templates,
|
||||
run the `check-template-changes` script:
|
||||
|
||||
```shell
|
||||
scripts/check-template-changes vendor/project_templates/<template_name>.tar.gz
|
||||
|
|
|
|||
|
|
@ -401,26 +401,7 @@ task, then check the dimensions of the new sprite sheet and update the
|
|||
|
||||
## Update project templates
|
||||
|
||||
Starting a project from a template needs this project to be exported. On a
|
||||
up to date main branch run:
|
||||
|
||||
```shell
|
||||
gdk start
|
||||
bundle exec rake gitlab:update_project_templates
|
||||
git checkout -b update-project-templates
|
||||
git add vendor/project_templates
|
||||
git commit
|
||||
git push -u origin update-project-templates
|
||||
```
|
||||
|
||||
Now create a merge request and merge that to main.
|
||||
|
||||
To update just a single template instead of all of them, specify the template name
|
||||
between square brackets. For example, for the `cluster_management` template, run:
|
||||
|
||||
```shell
|
||||
bundle exec rake gitlab:update_project_templates\[cluster_management\]
|
||||
```
|
||||
See [contributing to project templates for GitLab team members](project_templates.md#for-gitlab-team-members).
|
||||
|
||||
## Generate route lists
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ It is recommended to review the [full requirements for running Geo](../administr
|
|||
Changes to locale data in `glibc` means that PostgreSQL database files are not fully compatible
|
||||
between different OS releases.
|
||||
|
||||
To avoid index corruption, [check for locale compatibility](../administration/geo/replication/troubleshooting/index.md#check-os-locale-data-compatibility)
|
||||
To avoid index corruption, [check for locale compatibility](../administration/geo/replication/troubleshooting/common.md#check-os-locale-data-compatibility)
|
||||
when:
|
||||
|
||||
- Moving binary PostgreSQL data between servers.
|
||||
|
|
|
|||
|
|
@ -20,26 +20,18 @@ Sign in to DingTalk Open Platform and create an application on it. DingTalk gene
|
|||
|
||||
1. On the top bar, select **Application development > Enterprise internal development** and then select **Create Application**.
|
||||
|
||||

|
||||
|
||||
1. Fill in the application details:
|
||||
|
||||
- **Application Name**: This can be anything. Consider something like `<Organization>'s GitLab`, `<Your Name>'s GitLab`, or something else descriptive.
|
||||
- **Application Description**: Create a description.
|
||||
- **Application icon**: Upload qualified icons if needed.
|
||||
|
||||

|
||||
|
||||
1. Select **Confirm and create**.
|
||||
|
||||
1. On the left sidebar, select **DingTalk Application** and find your application. Select it and go to the application information page.
|
||||
|
||||

|
||||
|
||||
1. In the **Application Credentials** section, note the **AppKey** and **AppSecret** as you use these values later.
|
||||
|
||||

|
||||
|
||||
1. On your GitLab server, open the configuration file.
|
||||
|
||||
For Linux package installations:
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 76 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 84 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB |
|
|
@ -215,9 +215,9 @@ For more information, see [Enable or disable service ping](../../administration/
|
|||
In GitLab 15.4 and 15.5, Gitaly Cluster assumes `pool.ntp.org` is accessible. If `pool.ntp.org` is not accessible, [customize the time server setting](../../administration/gitaly/praefect.md#customize-time-server-setting) on the Gitaly
|
||||
and Praefect servers so they can use an accessible NTP server.
|
||||
|
||||
On offline instances, the [GitLab Geo check Rake task](../../administration/geo/replication/troubleshooting/index.md#can-geo-detect-the-current-site-correctly)
|
||||
On offline instances, the [GitLab Geo check Rake task](../../administration/geo/replication/troubleshooting/common.md#can-geo-detect-the-current-site-correctly)
|
||||
always fails because it uses `pool.ntp.org`. This error can be ignored but you can
|
||||
[read more about how to work around it](../../administration/geo/replication/troubleshooting/index.md#message-machine-clock-is-synchronized--exception).
|
||||
[read more about how to work around it](../../administration/geo/replication/troubleshooting/common.md#message-machine-clock-is-synchronized--exception).
|
||||
|
||||
## Enabling the Package Metadata Database
|
||||
|
||||
|
|
|
|||
|
|
@ -620,7 +620,7 @@ DETAILS:
|
|||
|
||||
## 15.4.6
|
||||
|
||||
- Due to a [bug introduced in curl in GitLab 15.4.6](https://github.com/curl/curl/issues/10122), the [`no_proxy` environment variable may not work properly](../../administration/geo/replication/troubleshooting/index.md#secondary-site-returns-received-http-code-403-from-proxy-after-connect). Either downgrade to GitLab 15.4.5, or upgrade to GitLab 15.5.7 or a later version.
|
||||
- Due to a [bug introduced in curl in GitLab 15.4.6](https://github.com/curl/curl/issues/10122), the [`no_proxy` environment variable may not work properly](../../administration/geo/replication/troubleshooting/client_http.md#secondary-site-returns-received-http-code-403-from-proxy-after-connect). Either downgrade to GitLab 15.4.5, or upgrade to GitLab 15.5.7 or a later version.
|
||||
- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
|
||||
|
||||
## 15.4.5
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ DETAILS:
|
|||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
The following troubleshooting scenarios have been collected from customer support cases. If you
|
||||
experience a problem not addressed here, or the information here does not fix your problem, create a
|
||||
support ticket. For more details, see the [GitLab Support](https://about.gitlab.com/support/) page.
|
||||
experience a problem not addressed here, or the information here does not fix your problem, see the
|
||||
[GitLab Support](https://about.gitlab.com/support/) page for ways to get help.
|
||||
|
||||
## Debugging DAST jobs
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Security Policies
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Merge request approval policies (Previously: Scan result policies)
|
||||
# Merge request approval policies
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Ultimate
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ DETAILS:
|
|||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
The following troubleshooting scenarios have been collected from customer support cases. If you
|
||||
experience a problem not addressed here, or the information here does not fix your problem, create a
|
||||
support ticket. For more details, see the [GitLab Support](https://about.gitlab.com/support/) page.
|
||||
experience a problem not addressed here, or the information here does not fix your problem, see the
|
||||
[GitLab Support](https://about.gitlab.com/support/) page for ways to get help.
|
||||
|
||||
## Debug-level logging
|
||||
|
||||
|
|
|
|||
|
|
@ -75,3 +75,26 @@ To delete a compliance framework from the compliance frameworks report:
|
|||
1. On the page, select the **Frameworks** tab.
|
||||
1. Hover over framework and select **Edit the framework**.
|
||||
1. Select the **Delete framework** to delete compliance framework.
|
||||
|
||||
## Export a report of compliance frameworks in a group
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/413736) in GitLab 16.11 [with a flag](../../../administration/feature_flags.md) named `compliance_frameworks_report_csv_export`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md)
|
||||
named `compliance_frameworks_report_csv_export`. On GitLab.com, this feature is not available. The feature is not ready for production use.
|
||||
|
||||
Exports the contents of a compliance frameworks report in a group. Reports are truncated at 15 MB to avoid a large email attachment.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must be an administrator or have the Owner role for the group.
|
||||
|
||||
To export the standards adherence report for projects in a group:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. Select **Secure > Compliance center**.
|
||||
1. In the top-right corner, select **Export**.
|
||||
1. Select **Export framework report**.
|
||||
|
||||
A report is compiled and delivered to your email inbox as an attachment.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ module Gitlab
|
|||
# )
|
||||
# ```
|
||||
class Keep
|
||||
def initialize(logger: nil)
|
||||
@logger = logger || Logger.new(nil)
|
||||
end
|
||||
|
||||
# The each_change method must update local working copy files and yield a Change object which describes the
|
||||
# specific changed files and other data that will be used to generate a merge request. This is the core
|
||||
# implementation details for a specific housekeeper keep. This does not need to commit the changes or create the
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@ module Gitlab
|
|||
LIMIT_FIXES = 20
|
||||
RUBOCOP_TODO_DIR_PATTERN = ".rubocop_todo/**/*.yml"
|
||||
|
||||
def initialize(todo_dir_pattern: RUBOCOP_TODO_DIR_PATTERN, limit_fixes: LIMIT_FIXES)
|
||||
def initialize(logger: nil, todo_dir_pattern: RUBOCOP_TODO_DIR_PATTERN, limit_fixes: LIMIT_FIXES)
|
||||
super(logger: logger)
|
||||
@todo_dir_pattern = todo_dir_pattern
|
||||
@limit_fixes = limit_fixes
|
||||
end
|
||||
|
||||
def each_change
|
||||
each_allowed_rubocop_rule do |rule, rule_file_path, violating_files|
|
||||
@logger.puts "RubopCop rule #{rule}"
|
||||
remove_allow_rule = true
|
||||
|
||||
if violating_files.count > @limit_fixes
|
||||
|
|
@ -41,6 +43,7 @@ module Gitlab
|
|||
begin
|
||||
::Gitlab::Housekeeper::Shell.execute('rubocop', '--autocorrect', *violating_files)
|
||||
rescue ::Gitlab::Housekeeper::Shell::Error
|
||||
@logger.warn "Failed to autocorrect files. Reverting"
|
||||
# Ignore when it cannot be automatically fixed. But we need to checkout any files we might have updated.
|
||||
::Gitlab::Housekeeper::Shell.execute('git', 'checkout', rule_file_path, *violating_files)
|
||||
next
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Housekeeper
|
||||
class Logger < ::Logger
|
||||
def initialize(...)
|
||||
super
|
||||
|
||||
self.formatter = Formatter.new
|
||||
end
|
||||
|
||||
def puts(*args)
|
||||
args = [nil] if args.empty?
|
||||
args.each { |arg| self << "#{arg}\n" }
|
||||
end
|
||||
|
||||
class Formatter < ::Logger::Formatter
|
||||
def call(severity, _time, _progname, msg)
|
||||
format("%s: %s\n", severity, msg2str(msg))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'active_support/core_ext/string'
|
||||
require 'gitlab/housekeeper/logger'
|
||||
require 'gitlab/housekeeper/keep'
|
||||
require 'gitlab/housekeeper/keeps/rubocop_fixer'
|
||||
require 'gitlab/housekeeper/gitlab_client'
|
||||
|
|
@ -34,10 +35,11 @@ module Gitlab
|
|||
|
||||
git.with_clean_state do
|
||||
@keeps.each do |keep_class|
|
||||
keep = keep_class.new
|
||||
@logger.puts "Running keep #{keep_class}"
|
||||
keep = keep_class.new(logger: @logger)
|
||||
keep.each_change do |change|
|
||||
unless change.valid?
|
||||
puts "Ignoring invalid change from: #{keep_class}"
|
||||
@logger.warn "Ignoring invalid change from: #{keep_class}"
|
||||
next
|
||||
end
|
||||
|
||||
|
|
@ -56,9 +58,10 @@ module Gitlab
|
|||
git.create_commit(change)
|
||||
end
|
||||
|
||||
puts "Skipping change: #{change.identifiers} due to not matching filter."
|
||||
puts "Modified files have been committed to branch #{branch_name.yellowish}, but will not be pushed."
|
||||
puts
|
||||
@logger.puts "Skipping change: #{change.identifiers} due to not matching filter."
|
||||
@logger.puts "Modified files have been committed to branch #{branch_name.yellowish}," \
|
||||
"but will not be pushed."
|
||||
@logger.puts
|
||||
|
||||
next
|
||||
end
|
||||
|
|
@ -99,8 +102,8 @@ module Gitlab
|
|||
"Housekeeper created #{mr_count_string}."
|
||||
end
|
||||
|
||||
puts completion_message.yellowish
|
||||
puts
|
||||
@logger.puts completion_message.yellowish
|
||||
@logger.puts
|
||||
end
|
||||
|
||||
def add_standard_change_data(change)
|
||||
|
|
@ -122,28 +125,28 @@ module Gitlab
|
|||
base_message = "Merge request URL: #{change.mr_web_url || '(known after create)'}, on branch #{branch_name}."
|
||||
base_message << " CI skipped." if change.push_options.ci_skip
|
||||
|
||||
puts base_message.yellowish
|
||||
puts "=> #{change.identifiers.join(': ')}".purple
|
||||
@logger.puts base_message.yellowish
|
||||
@logger.puts "=> #{change.identifiers.join(': ')}".purple
|
||||
|
||||
puts '=> Title:'.purple
|
||||
puts change.title.purple
|
||||
puts
|
||||
@logger.puts '=> Title:'.purple
|
||||
@logger.puts change.title.purple
|
||||
@logger.puts
|
||||
|
||||
puts '=> Description:'
|
||||
puts change.description
|
||||
puts
|
||||
@logger.puts '=> Description:'
|
||||
@logger.puts change.description
|
||||
@logger.puts
|
||||
|
||||
if change.labels.present? || change.reviewers.present?
|
||||
puts '=> Attributes:'
|
||||
puts "Labels: #{change.labels.join(', ')}"
|
||||
puts "Reviewers: #{change.reviewers.join(', ')}"
|
||||
puts
|
||||
@logger.puts '=> Attributes:'
|
||||
@logger.puts "Labels: #{change.labels.join(', ')}"
|
||||
@logger.puts "Reviewers: #{change.reviewers.join(', ')}"
|
||||
@logger.puts
|
||||
end
|
||||
|
||||
puts '=> Diff:'
|
||||
puts Shell.execute('git', '--no-pager', 'diff', '--color=always', @target_branch, branch_name, '--',
|
||||
@logger.puts '=> Diff:'
|
||||
@logger.puts Shell.execute('git', '--no-pager', 'diff', '--color=always', @target_branch, branch_name, '--',
|
||||
*change.changed_files)
|
||||
puts
|
||||
@logger.puts
|
||||
end
|
||||
|
||||
def create(change, branch_name)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'stringio'
|
||||
require 'gitlab/housekeeper/logger'
|
||||
|
||||
RSpec.describe ::Gitlab::Housekeeper::Logger do
|
||||
let(:output) { StringIO.new }
|
||||
let(:logged) { output.string }
|
||||
|
||||
subject(:logger) { described_class.new(output) }
|
||||
|
||||
describe 'formatting' do
|
||||
it 'only prints severity and message' do
|
||||
logger.info
|
||||
logger.debug 42
|
||||
logger.error RuntimeError.new('test')
|
||||
logger.warn :hello
|
||||
|
||||
expect(logged).to eq(<<~OUTPUT)
|
||||
INFO: nil
|
||||
DEBUG: 42
|
||||
ERROR: test (RuntimeError)
|
||||
|
||||
WARN: :hello
|
||||
OUTPUT
|
||||
end
|
||||
end
|
||||
|
||||
describe '#puts' do
|
||||
it 'mimics Kernel#puts and logs without any tags' do
|
||||
logger.puts
|
||||
logger.puts :hello
|
||||
logger.puts "world"
|
||||
|
||||
expect(logged).to eq(<<~OUTPUT)
|
||||
|
||||
hello
|
||||
world
|
||||
OUTPUT
|
||||
end
|
||||
end
|
||||
|
||||
%i[debug info warn error fatal].each do |severity|
|
||||
describe "##{severity}" do
|
||||
it 'tags message with severity only' do
|
||||
tag = severity.to_s.upcase
|
||||
|
||||
logger.public_send(severity, :hello)
|
||||
|
||||
expect(logged).to eq("#{tag}: :hello\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -40,7 +40,7 @@ module Keeps
|
|||
|
||||
def prepare_change(feature_flag)
|
||||
if feature_flag.milestone.nil?
|
||||
puts "#{feature_flag.name} has no milestone set!"
|
||||
@logger.puts "#{feature_flag.name} has no milestone set!"
|
||||
return
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ module Keeps
|
|||
class OverdueFinalizeBackgroundMigration < ::Gitlab::Housekeeper::Keep
|
||||
CUTOFF_MILESTONE = '16.8' # Only finalize migrations added before this
|
||||
|
||||
def initialize; end
|
||||
|
||||
def each_change
|
||||
each_batched_background_migration do |migration_yaml_file, migration|
|
||||
next unless before_cuttoff_milestone?(migration['milestone'])
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ module API
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
expose :release, using: Entities::TagRelease, if: ->(*) { can_read_release? } do |repo_tag, options|
|
||||
options[:project].releases.find_by(tag: repo_tag.name)
|
||||
options[:releases]&.find { |r| r.tag == repo_tag.name }
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ module API
|
|||
optional :subgroup_creation_level, type: String, values: ::Gitlab::Access.subgroup_creation_string_values, desc: 'Allowed to create subgroups', as: :subgroup_creation_level_str
|
||||
optional :emails_disabled, type: Boolean, desc: '_(Deprecated)_ Disable email notifications. Use: emails_enabled'
|
||||
optional :emails_enabled, type: Boolean, desc: 'Enable email notifications'
|
||||
optional :show_diff_preview_in_email, type: Boolean, desc: 'Include the code diff preview in merge request notification emails'
|
||||
optional :mentions_disabled, type: Boolean, desc: 'Disable a group from getting mentioned'
|
||||
optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
|
||||
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
|
||||
|
|
|
|||
|
|
@ -12,6 +12,14 @@ module API
|
|||
not_found! unless user_project.repo_exists?
|
||||
end
|
||||
|
||||
helpers do
|
||||
def find_releases(tags)
|
||||
tag_names = [tags].flatten.map(&:name)
|
||||
|
||||
user_project.releases.by_tag(tag_names)
|
||||
end
|
||||
end
|
||||
|
||||
params do
|
||||
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
|
||||
end
|
||||
|
|
@ -48,6 +56,7 @@ module API
|
|||
present_cached paginated_tags,
|
||||
with: Entities::Tag,
|
||||
project: user_project,
|
||||
releases: find_releases(paginated_tags),
|
||||
current_user: current_user,
|
||||
cache_context: -> (_tag) do
|
||||
[user_project.cache_key, can?(current_user, :read_release, user_project)].join(':')
|
||||
|
|
@ -74,7 +83,7 @@ module API
|
|||
tag = user_project.repository.find_tag(params[:tag_name])
|
||||
not_found!('Tag') unless tag
|
||||
|
||||
present tag, with: Entities::Tag, project: user_project, current_user: current_user
|
||||
present tag, with: Entities::Tag, project: user_project, releases: find_releases(tag), current_user: current_user
|
||||
end
|
||||
|
||||
desc 'Create a new repository tag' do
|
||||
|
|
@ -100,7 +109,8 @@ module API
|
|||
if result[:status] == :success
|
||||
present result[:tag],
|
||||
with: Entities::Tag,
|
||||
project: user_project
|
||||
project: user_project,
|
||||
releases: find_releases(result[:tag])
|
||||
else
|
||||
render_api_error!(result[:message], 400)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,7 +21,10 @@ module Sidebars
|
|||
|
||||
override :render?
|
||||
def render?
|
||||
!!context.current_user && !Gitlab::CurrentSettings.personal_access_tokens_disabled?
|
||||
return false unless context.current_user
|
||||
return false if Gitlab::CurrentSettings.personal_access_tokens_disabled?
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
|
|
@ -37,3 +40,5 @@ module Sidebars
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Sidebars::UserSettings::Menus::AccessTokensMenu.prepend_mod
|
||||
|
|
|
|||
|
|
@ -4018,6 +4018,12 @@ msgstr ""
|
|||
msgid "AdminUsers|(Pending approval)"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|2FA Disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|2FA Enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|A user can validate themselves by inputting a credit/debit card, or an admin can manually validate a user. Validated users can use free CI minutes on instance runners."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -4039,6 +4045,9 @@ msgstr ""
|
|||
msgid "AdminUsers|Activate user %{username}?"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|Active"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|Adjust the user cap setting on your instance"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -4048,6 +4057,9 @@ msgstr ""
|
|||
msgid "AdminUsers|Administrator"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|Admins"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -4252,6 +4264,9 @@ msgstr ""
|
|||
msgid "AdminUsers|Search by name, email, or username"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|Search users"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|Send email to users"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -4306,9 +4321,6 @@ msgstr ""
|
|||
msgid "AdminUsers|Trusted"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|Two-factor authentication"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminUsers|Unban user"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -12956,6 +12968,9 @@ msgstr ""
|
|||
msgid "Compliance Center Export|Example: 2dc6aa3"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance Center Export|Export a list of compliance frameworks for a project as a CSV file."
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance Center Export|Export chain of custody report"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -12965,6 +12980,9 @@ msgstr ""
|
|||
msgid "Compliance Center Export|Export chain of custody report of a specific commit as a CSV file (limited to 15MB)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance Center Export|Export contents of the compliance frameworks report as a CSV file."
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance Center Export|Export contents of the standards adherence report as a CSV file."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -12974,10 +12992,10 @@ msgstr ""
|
|||
msgid "Compliance Center Export|Export custody report of a specific commit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance Center Export|Export list of project frameworks"
|
||||
msgid "Compliance Center Export|Export frameworks report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance Center Export|Export list of project frameworks as a CSV file."
|
||||
msgid "Compliance Center Export|Export list of project frameworks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance Center Export|Export merge request violations as a CSV file."
|
||||
|
|
@ -13028,6 +13046,9 @@ msgstr ""
|
|||
msgid "ComplianceFrameworksReport|Edit framework"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFrameworksReport|Policies"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFrameworks| Frameworks export"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19296,6 +19317,9 @@ msgstr ""
|
|||
msgid "Email notification for unknown sign-ins"
|
||||
msgstr ""
|
||||
|
||||
msgid "Email notifications"
|
||||
msgstr ""
|
||||
|
||||
msgid "Email patch"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19920,6 +19944,9 @@ msgstr ""
|
|||
msgid "Environments|HelmReleases"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|How do I grant Kubernetes access?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Job"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19995,6 +20022,9 @@ msgstr ""
|
|||
msgid "Environments|Select agent"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Select an agent with Kubernetes access to the project or group."
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Select namespace"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -24782,9 +24812,15 @@ msgstr ""
|
|||
msgid "GroupSettings|Default to Auto DevOps pipeline for all projects within this group"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Disable personal access tokens"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Duo features"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Emails are not encrypted. Concerned administrators may want to disable diff previews."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Enable GitLab Duo features for this group %{link_start}Learn more%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -24830,6 +24866,9 @@ msgstr ""
|
|||
msgid "GroupSettings|How do I manage group SSH certificates?"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|If enabled, enterprise user accounts will not be able to use personal access tokens."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|If enabled, individual user accounts will be able to use only issued SSH certificates for Git access. It doesn't apply to service accounts, deploy keys, and other types of internal accounts."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -24839,6 +24878,9 @@ msgstr ""
|
|||
msgid "GroupSettings|If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Include diff previews"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Members cannot invite groups outside of %{group} and its subgroups"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -36858,6 +36900,9 @@ msgstr ""
|
|||
msgid "Personal access token"
|
||||
msgstr ""
|
||||
|
||||
msgid "Personal access tokens"
|
||||
msgstr ""
|
||||
|
||||
msgid "Personal projects"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -40023,6 +40068,12 @@ msgstr ""
|
|||
msgid "ProjectSettings|Do not allow"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Email notifications"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Emails are not encrypted. Concerned administrators may want to disable diff previews."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Enable \"Delete source branch\" option by default"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -40110,6 +40161,9 @@ msgstr ""
|
|||
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Include diff previews"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Infrastructure"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -49434,9 +49488,6 @@ msgstr ""
|
|||
msgid "Starts: %{startsAt}"
|
||||
msgstr ""
|
||||
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
msgid "State your message to activate"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -52623,6 +52674,9 @@ msgstr ""
|
|||
msgid "This project does not have a wiki homepage yet"
|
||||
msgstr ""
|
||||
|
||||
msgid "This project does not include diff previews in email notifications."
|
||||
msgstr ""
|
||||
|
||||
msgid "This project has no active access tokens."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
"@gitlab/cluster-client": "^2.1.0",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/svgs": "3.95.0",
|
||||
"@gitlab/svgs": "3.96.0",
|
||||
"@gitlab/ui": "78.12.0",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "^0.0.1-dev-20240411155529",
|
||||
|
|
|
|||
|
|
@ -6,16 +6,21 @@ module QA
|
|||
module Overview
|
||||
module Users
|
||||
class Index < QA::Page::Base
|
||||
view 'app/views/admin/users/_users.html.haml' do
|
||||
element 'user-search-field'
|
||||
element 'pending-approval-tab'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/vue_shared/components/users_table/users_table.vue' do
|
||||
element 'user-row-content'
|
||||
end
|
||||
|
||||
def search_user(username)
|
||||
submit_search_term(username)
|
||||
find_element('user-search-field').set(username).send_keys(:return)
|
||||
end
|
||||
|
||||
def choose_pending_approval_filter
|
||||
select_tokens('state', '=', 'Pending approval', submit: true)
|
||||
def click_pending_approval_tab
|
||||
click_element 'pending-approval-tab'
|
||||
end
|
||||
|
||||
def click_user(username)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ module QA
|
|||
end
|
||||
|
||||
base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do
|
||||
element 'discussion-reply-tab'
|
||||
element 'resolve-discussion-button'
|
||||
end
|
||||
|
||||
|
|
@ -36,6 +35,10 @@ module QA
|
|||
element 'discussion-filter-container'
|
||||
end
|
||||
|
||||
base.view 'app/assets/javascripts/notes/components/discussion_reply_placeholder.vue' do
|
||||
element 'discussion-reply-tab'
|
||||
end
|
||||
|
||||
base.view 'app/assets/javascripts/notes/components/noteable_discussion.vue' do
|
||||
element 'discussion-content'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
module QA
|
||||
RSpec.shared_examples 'registration and login' do
|
||||
it 'allows the user to register and login' do
|
||||
|
|
@ -159,7 +157,7 @@ module QA
|
|||
Page::Main::Menu.perform(&:go_to_admin_area)
|
||||
Page::Admin::Menu.perform(&:go_to_users_overview)
|
||||
Page::Admin::Overview::Users::Index.perform do |index|
|
||||
index.choose_pending_approval_filter
|
||||
index.click_pending_approval_tab
|
||||
index.search_user(user.username)
|
||||
index.click_user(user.name)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ module QA
|
|||
tags_for_rspec = []
|
||||
|
||||
return tags_for_rspec if Runtime::Scenario.attributes[:test_metadata_only]
|
||||
return tags_for_rspec if Runtime::Env.rspec_retried?
|
||||
|
||||
if tags.any?
|
||||
tags.each { |tag| tags_for_rspec.push(['--tag', tag.to_s]) }
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ RSpec.describe Import::BitbucketServerController, feature_category: :importers d
|
|||
let(:token) { 'token' }
|
||||
let(:username) { 'bitbucket-user' }
|
||||
let(:url) { 'http://localhost:7990/bitbucket' }
|
||||
let(:experiment) { instance_double(ApplicationExperiment) }
|
||||
|
||||
it 'clears out existing session' do
|
||||
post :configure
|
||||
|
|
@ -125,17 +124,6 @@ RSpec.describe Import::BitbucketServerController, feature_category: :importers d
|
|||
expect(response).to redirect_to(status_import_bitbucket_server_path)
|
||||
end
|
||||
|
||||
it 'tracks default_to_import_tab experiment' do
|
||||
allow(controller)
|
||||
.to receive(:experiment)
|
||||
.with(:default_to_import_tab, actor: user)
|
||||
.and_return(experiment)
|
||||
|
||||
expect(experiment).to receive(:track).with(:authentication, property: :bitbucket_server)
|
||||
|
||||
post :configure
|
||||
end
|
||||
|
||||
it 'sets the session variables' do
|
||||
allow(controller).to receive(:allow_local_requests?).and_return(true)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ RSpec.describe Import::FogbugzController, feature_category: :importers do
|
|||
end
|
||||
|
||||
describe 'POST #callback' do
|
||||
let(:experiment) { instance_double(ApplicationExperiment) }
|
||||
let(:xml_response) { %(<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><token><![CDATA[#{token}]]></token></response>) }
|
||||
|
||||
before do
|
||||
|
|
@ -32,17 +31,6 @@ RSpec.describe Import::FogbugzController, feature_category: :importers do
|
|||
expect(response).to redirect_to(new_user_map_import_fogbugz_path)
|
||||
end
|
||||
|
||||
it 'tracks default_to_import_tab experiment' do
|
||||
allow(controller)
|
||||
.to receive(:experiment)
|
||||
.with(:default_to_import_tab, actor: user)
|
||||
.and_return(experiment)
|
||||
|
||||
expect(experiment).to receive(:track).with(:successfully_authenticated, property: :fogbugz)
|
||||
|
||||
post :callback, params: { uri: uri, email: 'test@example.com', password: 'mypassword' }
|
||||
end
|
||||
|
||||
it 'preserves namespace_id query param on success' do
|
||||
post :callback, params: { uri: uri, email: 'test@example.com', password: 'mypassword', namespace_id: namespace_id }
|
||||
|
||||
|
|
@ -68,17 +56,6 @@ RSpec.describe Import::FogbugzController, feature_category: :importers do
|
|||
|
||||
expect(response).to redirect_to(new_import_fogbugz_url)
|
||||
end
|
||||
|
||||
it 'does not track default_to_import_tab experiment when client raises authentication exception' do
|
||||
allow(controller)
|
||||
.to receive(:experiment)
|
||||
.with(:default_to_import_tab, actor: user)
|
||||
.and_return(experiment)
|
||||
|
||||
expect(experiment).not_to receive(:track)
|
||||
|
||||
post :callback, params: { uri: uri, email: 'test@example.com', password: 'mypassword' }
|
||||
end
|
||||
end
|
||||
|
||||
context 'verify url' do
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue