Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
cd4d8b60a0
commit
b52c116c99
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
# Base Markdownlint configuration
|
||||
# Extended Markdownlint configuration in doc/.markdownlint/
|
||||
"default": true
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.40.0
|
||||
1.41.0
|
||||
|
|
|
@ -42,7 +42,7 @@ export default class Activities {
|
|||
}
|
||||
|
||||
updateTooltips() {
|
||||
localTimeAgo($('.js-timeago', '.content_list'));
|
||||
localTimeAgo(document.querySelectorAll('.content_list .js-timeago'));
|
||||
}
|
||||
|
||||
reloadActivities() {
|
||||
|
|
|
@ -93,7 +93,7 @@ export default class CommitsList {
|
|||
.text(n__('%d commit', '%d commits', commitsCount));
|
||||
}
|
||||
|
||||
localTimeAgo($processedData.find('.js-timeago'));
|
||||
localTimeAgo($processedData.find('.js-timeago').get());
|
||||
|
||||
return processedData;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import $ from 'jquery';
|
||||
import * as timeago from 'timeago.js';
|
||||
import { languageCode, s__, createDateTimeFormat } from '../../../locale';
|
||||
import { formatDate } from './date_format_utility';
|
||||
|
@ -97,21 +96,21 @@ export const getTimeago = () =>
|
|||
|
||||
/**
|
||||
* For the given elements, sets a tooltip with a formatted date.
|
||||
* @param {JQuery} $timeagoEls
|
||||
* @param {Boolean} setTimeago
|
||||
* @param {Array<Node>|NodeList} elements
|
||||
* @param {Boolean} updateTooltip
|
||||
*/
|
||||
export const localTimeAgo = ($timeagoEls, setTimeago = true) => {
|
||||
export const localTimeAgo = (elements, updateTooltip = true) => {
|
||||
const { format } = getTimeago();
|
||||
$timeagoEls.each((i, el) => {
|
||||
$(el).text(format($(el).attr('datetime'), timeagoLanguageCode));
|
||||
elements.forEach((el) => {
|
||||
el.innerText = format(el.dateTime, timeagoLanguageCode);
|
||||
});
|
||||
|
||||
if (!setTimeago) {
|
||||
if (!updateTooltip) {
|
||||
return;
|
||||
}
|
||||
|
||||
function addTimeAgoTooltip() {
|
||||
$timeagoEls.each((i, el) => {
|
||||
elements.forEach((el) => {
|
||||
// Recreate with custom template
|
||||
el.setAttribute('title', formatDate(el.dateTime));
|
||||
});
|
||||
|
|
|
@ -183,7 +183,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
return true;
|
||||
});
|
||||
|
||||
localTimeAgo($('abbr.timeago, .js-timeago'), true);
|
||||
localTimeAgo(document.querySelectorAll('abbr.timeago, .js-timeago'), true);
|
||||
|
||||
/**
|
||||
* This disables form buttons while a form is submitting
|
||||
|
|
|
@ -38,6 +38,7 @@ export default {
|
|||
usersName: user.name,
|
||||
source: source.fullName,
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -333,8 +333,9 @@ export default class MergeRequestTabs {
|
|||
axios
|
||||
.get(`${source}.json`)
|
||||
.then(({ data }) => {
|
||||
document.querySelector('div#commits').innerHTML = data.html;
|
||||
localTimeAgo($('.js-timeago', 'div#commits'));
|
||||
const commitsDiv = document.querySelector('div#commits');
|
||||
commitsDiv.innerHTML = data.html;
|
||||
localTimeAgo(commitsDiv.querySelectorAll('.js-timeago'));
|
||||
this.commitsLoaded = true;
|
||||
this.scrollToContainerElement('#commits');
|
||||
|
||||
|
@ -407,7 +408,7 @@ export default class MergeRequestTabs {
|
|||
|
||||
initChangesDropdown(this.stickyTop);
|
||||
|
||||
localTimeAgo($('.js-timeago', 'div#diffs'));
|
||||
localTimeAgo(document.querySelectorAll('#diffs .js-timeago'));
|
||||
syntaxHighlight($('#diffs .js-syntax-highlight'));
|
||||
|
||||
if (this.isDiffAction(this.currentAction)) {
|
||||
|
|
|
@ -358,7 +358,7 @@ export default class Notes {
|
|||
|
||||
setupNewNote($note) {
|
||||
// Update datetime format on the recent note
|
||||
localTimeAgo($note.find('.js-timeago'), false);
|
||||
localTimeAgo($note.find('.js-timeago').get(), false);
|
||||
|
||||
this.collapseLongCommitList();
|
||||
this.taskList.init();
|
||||
|
@ -511,7 +511,7 @@ export default class Notes {
|
|||
Notes.animateAppendNote(noteEntity.html, discussionContainer);
|
||||
}
|
||||
|
||||
localTimeAgo($('.js-timeago'), false);
|
||||
localTimeAgo(document.querySelectorAll('.js-timeago'), false);
|
||||
Notes.checkMergeRequestStatus();
|
||||
return this.updateNotesCount(1);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
modalTitle() {
|
||||
return sprintf(this.title, { username: this.username });
|
||||
return sprintf(this.title, { username: this.username }, false);
|
||||
},
|
||||
secondaryButtonLabel() {
|
||||
return s__('AdminUsers|Block user');
|
||||
|
@ -112,7 +112,7 @@ export default {
|
|||
</gl-sprintf>
|
||||
</p>
|
||||
|
||||
<oncall-schedules-list v-if="schedules.length" :schedules="schedules" />
|
||||
<oncall-schedules-list v-if="schedules.length" :schedules="schedules" :user-name="username" />
|
||||
|
||||
<p>
|
||||
<gl-sprintf :message="s__('AdminUsers|To confirm, type %{username}')">
|
||||
|
|
|
@ -15,7 +15,7 @@ const updateCommitList = (url, $loadingIndicator, $commitList, params) => {
|
|||
.then(({ data }) => {
|
||||
$loadingIndicator.hide();
|
||||
$commitList.html(data);
|
||||
localTimeAgo($('.js-timeago', $commitList));
|
||||
localTimeAgo($commitList.get(0).querySelectorAll('.js-timeago'));
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ export default class UserTabs {
|
|||
const tabSelector = `div#${action}`;
|
||||
this.$parentEl.find(tabSelector).html(data.html);
|
||||
this.loaded[action] = true;
|
||||
localTimeAgo($('.js-timeago', tabSelector));
|
||||
localTimeAgo(document.querySelectorAll(`${tabSelector} .js-timeago`));
|
||||
|
||||
this.toggleLoading(false);
|
||||
})
|
||||
|
@ -209,7 +209,7 @@ export default class UserTabs {
|
|||
container,
|
||||
url: $(`${container} .overview-content-list`).data('href'),
|
||||
...options,
|
||||
postRenderCallback: () => localTimeAgo($('.js-timeago', container)),
|
||||
postRenderCallback: () => localTimeAgo(document.querySelectorAll(`${container} .js-timeago`)),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,13 @@ export default {
|
|||
title() {
|
||||
return this.isCurrentUser
|
||||
? s__('OnCallSchedules|You are currently a part of:')
|
||||
: sprintf(s__('OnCallSchedules|User %{name} is currently part of:'), {
|
||||
: sprintf(
|
||||
s__('OnCallSchedules|User %{name} is currently part of:'),
|
||||
{
|
||||
name: this.userName,
|
||||
});
|
||||
},
|
||||
false,
|
||||
);
|
||||
},
|
||||
footer() {
|
||||
return this.isCurrentUser
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
# rubocop:disable Style/SignalException
|
||||
|
||||
DATA_WAREHOUSE_LABELS = [
|
||||
"Data Warehouse::Impact Check",
|
||||
"Data Warehouse::Impacted",
|
||||
"Data Warehouse::Not Impacted"
|
||||
].freeze
|
||||
|
||||
CHANGED_SCHEMA_MESSAGE = <<~MSG
|
||||
Mentioning @gitlab-data/engineers to notify the team about changes to the db/structure.sql file.
|
||||
Notification to the Data Team about changes to the db/structure.sql file, add label `Data Warehouse::Impact Check`.
|
||||
|
||||
/label ~"Data Warehouse::Impact Check"
|
||||
|
||||
MSG
|
||||
|
||||
db_schema_updated = !git.modified_files.grep(%r{\Adb/structure\.sql}).empty?
|
||||
|
||||
if db_schema_updated
|
||||
no_data_warehouse_labels = (gitlab.mr_labels & DATA_WAREHOUSE_LABELS).empty?
|
||||
|
||||
if db_schema_updated && no_data_warehouse_labels
|
||||
|
||||
markdown(CHANGED_SCHEMA_MESSAGE)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
# Extended Markdown configuration to enforce no-trailing-spaces rule
|
||||
"extends": "../../.markdownlint.yml"
|
||||
"no-trailing-spaces": true
|
||||
|
|
|
@ -120,6 +120,7 @@ exceptions:
|
|||
- PUT
|
||||
- RAID
|
||||
- RAM
|
||||
- RBAC
|
||||
- RDP
|
||||
- REST
|
||||
- RFC
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
# Error: gitlab.HeaderGerunds
|
||||
# Suggestion: gitlab.HeaderGerunds
|
||||
#
|
||||
# Checks for headers that start with gerunds (ing words).
|
||||
# Related to: https://docs.gitlab.com/ee/development/documentation/structure.html
|
||||
|
|
|
@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
To enable the Authentiq OmniAuth provider for passwordless authentication you must register an application with Authentiq.
|
||||
|
||||
Authentiq will generate a Client ID and the accompanying Client Secret for you to use.
|
||||
Authentiq generates a Client ID and the accompanying Client Secret for you to use.
|
||||
|
||||
1. Get your Client credentials (Client ID and Client Secret) at [Authentiq](https://www.authentiq.com/developers).
|
||||
|
||||
|
@ -67,15 +67,17 @@ Authentiq will generate a Client ID and the accompanying Client Secret for you t
|
|||
|
||||
1. [Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) or [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect if you installed GitLab via Omnibus or from source respectively.
|
||||
|
||||
On the sign in page there should now be an Authentiq icon below the regular sign in form. Click the icon to begin the authentication process.
|
||||
On the sign in page there should now be an Authentiq icon below the regular sign in form. Click the
|
||||
icon to begin the authentication process. If the user:
|
||||
|
||||
- If the user has the Authentiq ID app installed in their iOS or Android device, they can:
|
||||
- Has the Authentiq ID app installed in their iOS or Android device, they can:
|
||||
1. Scan the QR code.
|
||||
1. Decide what personal details to share.
|
||||
1. Sign in to your GitLab installation.
|
||||
- If not they will be prompted to download the app and then follow the procedure above.
|
||||
- Does not have the app installed, they are prompted to download the app and then follow the
|
||||
procedure above.
|
||||
|
||||
If everything goes right, the user will be returned to GitLab and will be signed in.
|
||||
If everything works, the user is returned to GitLab and is signed in.
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
||||
|
|
|
@ -186,7 +186,8 @@ Gitaly Cluster supports:
|
|||
- [Strong consistency](praefect.md#strong-consistency) of the secondary replicas.
|
||||
- [Automatic failover](praefect.md#automatic-failover-and-primary-election-strategies) from the primary to the secondary.
|
||||
- Reporting of possible data loss if replication queue is non-empty.
|
||||
- Marking repositories as [read-only](praefect.md#read-only-mode) if data loss is detected to prevent data inconsistencies.
|
||||
- From GitLab 13.0 to GitLab 14.0, marking repositories as [read-only](praefect.md#read-only-mode)
|
||||
if data loss is detected to prevent data inconsistencies.
|
||||
|
||||
Follow the [Gitaly Cluster epic](https://gitlab.com/groups/gitlab-org/-/epics/1489)
|
||||
for improvements including
|
||||
|
|
|
@ -1239,24 +1239,30 @@ The `per_repository` election strategy solves this problem by electing a primary
|
|||
repository. Combined with [configurable replication factors](#configure-replication-factor), you can
|
||||
horizontally scale storage capacity and distribute write load across Gitaly nodes.
|
||||
|
||||
Primary elections are run when:
|
||||
Primary elections are run:
|
||||
|
||||
- Praefect starts up.
|
||||
- The cluster's consensus of a Gitaly node's health changes.
|
||||
- In GitLab 14.1 and later, lazily. This means that Praefect doesn't immediately elect
|
||||
a new primary node if the current one is unhealthy. A new primary is elected if it is
|
||||
necessary to serve a request while the current primary is unavailable.
|
||||
- In GitLab 13.12 to GitLab 14.0 when:
|
||||
- Praefect starts up.
|
||||
- The cluster's consensus of a Gitaly node's health changes.
|
||||
|
||||
A Gitaly node is considered:
|
||||
A valid primary node candidate is a Gitaly node that:
|
||||
|
||||
- Healthy if `>=50%` Praefect nodes have successfully health checked the Gitaly node in the
|
||||
previous ten seconds.
|
||||
- Unhealthy otherwise.
|
||||
- Is healthy. A Gitaly node is considered healthy if `>=50%` Praefect nodes have
|
||||
successfully health checked the Gitaly node in the previous ten seconds.
|
||||
- Has a fully up to date copy of the repository.
|
||||
|
||||
During an election run, Praefect elects a new primary Gitaly node for each repository that has
|
||||
an unhealthy primary Gitaly node. The election is made:
|
||||
If there are multiple primary node candidates, Praefect:
|
||||
|
||||
- Randomly from healthy secondary Gitaly nodes that are the most up to date.
|
||||
- Only from Gitaly nodes assigned to the host repository.
|
||||
- Picks one of them randomly.
|
||||
- Prioritizes promoting a Gitaly node that is assigned to host the repository. If
|
||||
there are no assigned Gitaly nodes to elect as the primary, Praefect may temporarily
|
||||
elect an unassigned one. The unassigned primary is demoted in favor of an assigned
|
||||
one when one becomes available.
|
||||
|
||||
If there are no healthy secondary nodes for a repository:
|
||||
If there are no valid primary candidates for a repository:
|
||||
|
||||
- The unhealthy primary node is demoted and the repository is left without a primary node.
|
||||
- Operations that require a primary node fail until a primary is successfully elected.
|
||||
|
@ -1351,23 +1357,37 @@ Migrate to [repository-specific primary nodes](#repository-specific-primary-node
|
|||
Gitaly Cluster recovers from a failing primary Gitaly node by promoting a healthy secondary as the
|
||||
new primary.
|
||||
|
||||
To minimize data loss, Gitaly Cluster:
|
||||
In GitLab 14.1 and later, Gitaly Cluster:
|
||||
|
||||
- Elects a healthy secondary with a fully up to date copy of the repository as the new primary.
|
||||
- Repository becomes unavailable if there are no fully up to date copies of it on healthy secondaries.
|
||||
|
||||
To minimize data loss in GitLab 13.0 to 14.0, Gitaly Cluster:
|
||||
|
||||
- Switches repositories that are outdated on the new primary to [read-only mode](#read-only-mode).
|
||||
- Elects the secondary with the least unreplicated writes from the primary to be the new primary.
|
||||
Because there can still be some unreplicated writes, [data loss can occur](#check-for-data-loss).
|
||||
- Elects the secondary with the least unreplicated writes from the primary to be the new
|
||||
primary. Because there can still be some unreplicated writes,
|
||||
[data loss can occur](#check-for-data-loss).
|
||||
|
||||
### Read-only mode
|
||||
|
||||
> - Introduced in GitLab 13.0 as [generally available](https://about.gitlab.com/handbook/product/gitlab-the-product/#generally-available-ga).
|
||||
> - Between GitLab 13.0 and GitLab 13.2, read-only mode applied to the whole virtual storage and occurred whenever failover occurred.
|
||||
> - [In GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitaly/-/issues/2862), read-only mode applies on a per-repository basis and only occurs if a new primary is out of date.
|
||||
new primary. If the failed primary contained unreplicated writes, [data loss can occur](#check-for-data-loss).
|
||||
> - Removed in GitLab 14.1. Instead, repositories [become unavailable](#unavailable-repositories).
|
||||
|
||||
When Gitaly Cluster switches to a new primary, repositories enter read-only mode if they are out of
|
||||
date. This can happen after failing over to an outdated secondary. Read-only mode eases data
|
||||
recovery efforts by preventing writes that may conflict with the unreplicated writes on other nodes.
|
||||
In GitLab 13.0 to 14.0, when Gitaly Cluster switches to a new primary, repositories enter
|
||||
read-only mode if they are out of date. This can happen after failing over to an outdated
|
||||
secondary. Read-only mode eases data recovery efforts by preventing writes that may conflict
|
||||
with the unreplicated writes on other nodes.
|
||||
|
||||
To enable writes again, an administrator can:
|
||||
When Gitaly Cluster switches to a new primary In GitLab 13.0 to 14.0, repositories enter
|
||||
read-only mode if they are out of date. This can happen after failing over to an outdated
|
||||
secondary. Read-only mode eases data recovery efforts by preventing writes that may conflict
|
||||
with the unreplicated writes on other nodes.
|
||||
|
||||
To enable writes again in GitLab 13.0 to 14.0, an administrator can:
|
||||
|
||||
1. [Check](#check-for-data-loss) for data loss.
|
||||
1. Attempt to [recover](#data-recovery) missing data.
|
||||
|
@ -1375,21 +1395,38 @@ To enable writes again, an administrator can:
|
|||
[accept data loss](#enable-writes-or-accept-data-loss) if necessary, depending on the version of
|
||||
GitLab.
|
||||
|
||||
## Unavailable repositories
|
||||
|
||||
> - From GitLab 13.0 through 14.0, repositories became read-only if they were outdated on the primary but fully up to date on a healthy secondary. `dataloss` sub-command displays read-only repositories by default through these versions.
|
||||
> - Since GitLab 14.1, Praefect contains more responsive failover logic which immediately fails over to one of the fully up to date secondaries rather than placing the repository in read-only mode. Since GitLab 14.1, the `dataloss` sub-command displays repositories which are unavailable due to having no fully up to date copies on healthy Gitaly nodes.
|
||||
|
||||
A repository is unavailable if all of its up to date replicas are unavailable. Unavailable repositories are
|
||||
not accessible through Praefect to prevent serving stale data that may break automated tooling.
|
||||
|
||||
### Check for data loss
|
||||
|
||||
The Praefect `dataloss` sub-command identifies replicas that are likely to be outdated. This can help
|
||||
identify potential data loss after a failover. The following parameters are
|
||||
available:
|
||||
The Praefect `dataloss` subcommand identifies:
|
||||
|
||||
- `-virtual-storage` that specifies which virtual storage to check. The default behavior is to
|
||||
display outdated replicas of read-only repositories as they might require administrator action.
|
||||
- In GitLab 13.3 and later, `-partially-replicated` that specifies whether to display a list of
|
||||
[outdated replicas of writable repositories](#outdated-replicas-of-writable-repositories).
|
||||
- Copies of repositories in GitLab 13.0 to GitLab 14.0 that at are likely to be outdated.
|
||||
This can help identify potential data loss after a failover.
|
||||
- Repositories in GitLab 14.1 and later that are unavailable. This helps identify potential
|
||||
data loss and repositories which are no longer accessible because all of their up-to-date
|
||||
replicas copies are unavailable.
|
||||
|
||||
The following parameters are available:
|
||||
|
||||
- `-virtual-storage` that specifies which virtual storage to check. Because they might require
|
||||
an administrator to intervene, the default behavior is to display:
|
||||
- In GitLab 13.0 to 14.0, copies of read-only repositories.
|
||||
- In GitLab 14.1 and later, unavailable repositories.
|
||||
- In GitLab 14.1 and later, [`-partially-unavailable`](#unavailable-replicas-of-available-repositories)
|
||||
that specifies whether to include in the output repositories that are available but have
|
||||
some assigned copies that are not available.
|
||||
|
||||
NOTE:
|
||||
`dataloss` is still in beta and the output format is subject to change.
|
||||
|
||||
To check for repositories with outdated primaries, run:
|
||||
To check for repositories with outdated primaries or for unavailable repositories, run:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss [-virtual-storage <virtual-storage>]
|
||||
|
@ -1401,13 +1438,20 @@ Every configured virtual storage is checked if none is specified:
|
|||
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss
|
||||
```
|
||||
|
||||
Repositories which have assigned storage nodes that contain an outdated copy of the repository are listed
|
||||
in the output. This information is printed for each repository:
|
||||
Repositories are listed in the output that have either:
|
||||
|
||||
- An outdated copy of the repository on the primary, in GitLab 13.0 to GitLab 14.0.
|
||||
- No healthy and fully up-to-date copies available, in GitLab 14.1 and later.
|
||||
|
||||
The following information is printed for each repository:
|
||||
|
||||
- A repository's relative path to the storage directory identifies each repository and groups the related
|
||||
information.
|
||||
- The repository's current status is printed in parentheses next to the disk path. If the repository's primary
|
||||
is outdated, the repository is in `read-only` mode and can't accept writes. Otherwise, the mode is `writable`.
|
||||
- The repository's current status is printed in parentheses next to the disk path:
|
||||
- In GitLab 13.0 to 14.0, either `(read-only)` if the repository's primary node is outdated
|
||||
and can't accept writes. Otherwise, `(writable)`.
|
||||
- In GitLab 14.1 and later, `(unavailable)` is printed next to the disk path if the
|
||||
repository is unavailable.
|
||||
- The primary field lists the repository's current primary. If the repository has no primary, the field shows
|
||||
`No Primary`.
|
||||
- The In-Sync Storages lists replicas which have replicated the latest successful write and all writes
|
||||
|
@ -1417,44 +1461,51 @@ in the output. This information is printed for each repository:
|
|||
is listed next to replica. It's important to notice that the outdated replicas may be fully up to date or contain
|
||||
later changes but Praefect can't guarantee it.
|
||||
|
||||
Whether a replica is assigned to host the repository is listed with each replica's status. `assigned host` is printed
|
||||
next to replicas which are assigned to store the repository. The text is omitted if the replica contains a copy of
|
||||
the repository but is not assigned to store the repository. Such replicas aren't kept in-sync by Praefect, but may
|
||||
act as replication sources to bring assigned replicas up to date.
|
||||
Additional information includes:
|
||||
|
||||
- Whether a node is assigned to host the repository is listed with each node's status.
|
||||
`assigned host` is printed next to nodes that are assigned to store the repository. The
|
||||
text is omitted if the node contains a copy of the repository but is not assigned to store
|
||||
the repository. Such copies aren't kept in sync by Praefect, but may act as replication
|
||||
sources to bring assigned copies up to date.
|
||||
- In GitLab 14.1 and later, `unhealthy` is printed next to the copies that are located
|
||||
on unhealthy Gitaly nodes.
|
||||
|
||||
Example output:
|
||||
|
||||
```shell
|
||||
Virtual storage: default
|
||||
Outdated repositories:
|
||||
@hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git (read-only):
|
||||
@hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git (unavailable):
|
||||
Primary: gitaly-1
|
||||
In-Sync Storages:
|
||||
gitaly-2, assigned host
|
||||
gitaly-2, assigned host, unhealthy
|
||||
Outdated Storages:
|
||||
gitaly-1 is behind by 3 changes or less, assigned host
|
||||
gitaly-3 is behind by 3 changes or less
|
||||
```
|
||||
|
||||
A confirmation is printed out when every repository is writable. For example:
|
||||
A confirmation is printed out when every repository is available. For example:
|
||||
|
||||
```shell
|
||||
Virtual storage: default
|
||||
All repositories are writable!
|
||||
All repositories are available!
|
||||
```
|
||||
|
||||
#### Outdated replicas of writable repositories
|
||||
#### Unavailable replicas of available repositories
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/3019) in GitLab 13.3.
|
||||
NOTE:
|
||||
In GitLab 14.0 and earlier, the flag is `-partially-replicated` and the output shows any repositories with assigned nodes with outdated
|
||||
copies.
|
||||
|
||||
To also list information of repositories whose primary is up to date but one or more assigned
|
||||
replicas are outdated, use the `-partially-replicated` flag.
|
||||
To also list information of repositories which are available but are unavailable from some of the assigned nodes,
|
||||
use the `-partially-unavailable` flag.
|
||||
|
||||
A repository is writable if the primary has the latest changes. Secondaries might be temporarily
|
||||
outdated while they are waiting to replicate the latest changes.
|
||||
A repository is available if there is a healthy, up to date replica available. Some of the assigned secondary
|
||||
replicas may be temporarily unavailable for access while they are waiting to replicate the latest changes.
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss [-virtual-storage <virtual-storage>] [-partially-replicated]
|
||||
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss [-virtual-storage <virtual-storage>] [-partially-unavailable]
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
@ -1462,7 +1513,7 @@ Example output:
|
|||
```shell
|
||||
Virtual storage: default
|
||||
Outdated repositories:
|
||||
@hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git (writable):
|
||||
@hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git:
|
||||
Primary: gitaly-1
|
||||
In-Sync Storages:
|
||||
gitaly-1, assigned host
|
||||
|
@ -1471,14 +1522,14 @@ Virtual storage: default
|
|||
gitaly-3 is behind by 3 changes or less
|
||||
```
|
||||
|
||||
With the `-partially-replicated` flag set, a confirmation is printed out if every assigned replica is fully up to
|
||||
date.
|
||||
With the `-partially-unavailable` flag set, a confirmation is printed out if every assigned replica is fully up to
|
||||
date and healthy.
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
Virtual storage: default
|
||||
All repositories are up to date!
|
||||
All repositories are fully available on all assigned storages!
|
||||
```
|
||||
|
||||
### Check repository checksums
|
||||
|
@ -1486,30 +1537,50 @@ Virtual storage: default
|
|||
To check a project's repository checksums across on all Gitaly nodes, run the
|
||||
[replicas Rake task](../raketasks/praefect.md#replica-checksums) on the main GitLab node.
|
||||
|
||||
### Accept data loss
|
||||
|
||||
WARNING:
|
||||
`accept-dataloss` causes permanent data loss by overwriting other versions of the repository. Data
|
||||
[recovery efforts](#data-recovery) must be performed before using it.
|
||||
|
||||
If it is not possible to bring one of the up to date replicas back online, you may have to accept data
|
||||
loss. When accepting data loss, Praefect marks the chosen replica of the repository as the latest version
|
||||
and replicates it to the other assigned Gitaly nodes. This process overwrites any other version of the
|
||||
repository so care must be taken.
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss
|
||||
-virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
|
||||
```
|
||||
|
||||
### Enable writes or accept data loss
|
||||
|
||||
Praefect provides the following sub-commands to re-enable writes:
|
||||
WARNING:
|
||||
`accept-dataloss` causes permanent data loss by overwriting other versions of the repository.
|
||||
Data [recovery efforts](#data-recovery) must be performed before using it.
|
||||
|
||||
- In GitLab 13.2 and earlier, `enable-writes` to re-enable virtual storage for writes after data
|
||||
recovery attempts.
|
||||
Praefect provides the following subcommands to re-enable writes or accept data loss:
|
||||
|
||||
- In GitLab 13.2 and earlier, `enable-writes` to re-enable virtual storage for writes after
|
||||
data recovery attempts:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml enable-writes -virtual-storage <virtual-storage>
|
||||
```
|
||||
|
||||
- [In GitLab 13.3](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2415) and later,
|
||||
`accept-dataloss` to accept data loss and re-enable writes for repositories after data recovery
|
||||
attempts have failed. Accepting data loss causes current version of the repository on the
|
||||
authoritative storage to be considered latest. Other storages are brought up to date with the
|
||||
authoritative storage by scheduling replication jobs.
|
||||
- In GitLab 13.3 and later, if it is not possible to bring one of the up to date nodes back
|
||||
online, you may have to accept data loss:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss -virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
|
||||
```
|
||||
|
||||
WARNING:
|
||||
`accept-dataloss` causes permanent data loss by overwriting other versions of the repository. Data
|
||||
[recovery efforts](#data-recovery) must be performed before using it.
|
||||
When accepting data loss, Praefect:
|
||||
|
||||
1. Marks the chosen copy of the repository as the latest version.
|
||||
1. Replicates the copy to the other assigned Gitaly nodes.
|
||||
|
||||
This process overwrites any other copy of the repository so care must be taken.
|
||||
|
||||
## Data recovery
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ milestone: "<%= milestone %>"
|
|||
introduced_by_url:
|
||||
time_frame: <%= time_frame %>
|
||||
data_source:
|
||||
data_category: Operational
|
||||
data_category: Optional
|
||||
distribution:
|
||||
<%= distribution %>
|
||||
tier:
|
||||
|
|
|
@ -48,7 +48,10 @@ module QA
|
|||
Resource::Issue.fabricate_via_api!.visit!
|
||||
end
|
||||
|
||||
it 'comments on an issue with an attachment', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1742' do
|
||||
# The following example is excluded from running in `review-qa-smoke` job
|
||||
# as it proved to be flaky when running against Review App
|
||||
# See https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/11568#note_621999351
|
||||
it 'comments on an issue with an attachment', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1742', exclude: { job: 'review-qa-smoke' } do
|
||||
Page::Project::Issue::Show.perform do |show|
|
||||
show.comment('See attached image for scale', attachment: file_to_attach)
|
||||
|
||||
|
|
|
@ -81,14 +81,14 @@ RSpec.describe 'Dashboard Issues filtering', :js do
|
|||
sort_by('Created date')
|
||||
visit_issues(assignee_username: user.username)
|
||||
|
||||
expect(find('.issues-filters')).to have_content('Created date')
|
||||
expect(page).to have_button('Created date')
|
||||
end
|
||||
|
||||
it 'keeps sorting issues after visiting Projects Issues page' do
|
||||
sort_by('Created date')
|
||||
visit project_issues_path(project)
|
||||
|
||||
expect(find('.issues-filters')).to have_content('Created date')
|
||||
expect(page).to have_button('Created date')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ RSpec.describe "User sorts issues" do
|
|||
create(:award_emoji, :upvote, awardable: issue2)
|
||||
|
||||
sign_in(user)
|
||||
|
||||
visit(project_issues_path(project))
|
||||
end
|
||||
|
||||
it 'keeps the sort option' do
|
||||
visit(project_issues_path(project))
|
||||
|
||||
find('.filter-dropdown-container .dropdown').click
|
||||
|
||||
page.within('ul.dropdown-menu.dropdown-menu-right li') do
|
||||
|
@ -47,11 +47,10 @@ RSpec.describe "User sorts issues" do
|
|||
end
|
||||
|
||||
it 'sorts by popularity', :js do
|
||||
find('.filter-dropdown-container .dropdown').click
|
||||
visit(project_issues_path(project))
|
||||
|
||||
page.within('ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link("Popularity")
|
||||
end
|
||||
click_button 'Created date'
|
||||
click_on 'Popularity'
|
||||
|
||||
page.within(".issues-list") do
|
||||
page.within("li.issue:nth-child(1)") do
|
||||
|
@ -129,7 +128,7 @@ RSpec.describe "User sorts issues" do
|
|||
it 'filters by none' do
|
||||
visit project_issues_path(project, due_date: Issue::NoDueDate.name)
|
||||
|
||||
page.within '.issues-holder' do
|
||||
page.within '.issues-list' do
|
||||
expect(page).not_to have_content('foo')
|
||||
expect(page).not_to have_content('bar')
|
||||
expect(page).to have_content('baz')
|
||||
|
@ -139,7 +138,7 @@ RSpec.describe "User sorts issues" do
|
|||
it 'filters by any' do
|
||||
visit project_issues_path(project, due_date: Issue::AnyDueDate.name)
|
||||
|
||||
page.within '.issues-holder' do
|
||||
page.within '.issues-list' do
|
||||
expect(page).to have_content('foo')
|
||||
expect(page).to have_content('bar')
|
||||
expect(page).to have_content('baz')
|
||||
|
@ -153,7 +152,7 @@ RSpec.describe "User sorts issues" do
|
|||
|
||||
visit project_issues_path(project, due_date: Issue::DueThisWeek.name)
|
||||
|
||||
page.within '.issues-holder' do
|
||||
page.within '.issues-list' do
|
||||
expect(page).to have_content('foo')
|
||||
expect(page).to have_content('bar')
|
||||
expect(page).not_to have_content('baz')
|
||||
|
@ -167,7 +166,7 @@ RSpec.describe "User sorts issues" do
|
|||
|
||||
visit project_issues_path(project, due_date: Issue::DueThisMonth.name)
|
||||
|
||||
page.within '.issues-holder' do
|
||||
page.within '.issues-list' do
|
||||
expect(page).to have_content('foo')
|
||||
expect(page).to have_content('bar')
|
||||
expect(page).not_to have_content('baz')
|
||||
|
@ -181,7 +180,7 @@ RSpec.describe "User sorts issues" do
|
|||
|
||||
visit project_issues_path(project, due_date: Issue::Overdue.name)
|
||||
|
||||
page.within '.issues-holder' do
|
||||
page.within '.issues-list' do
|
||||
expect(page).not_to have_content('foo')
|
||||
expect(page).not_to have_content('bar')
|
||||
expect(page).to have_content('baz')
|
||||
|
@ -195,7 +194,7 @@ RSpec.describe "User sorts issues" do
|
|||
|
||||
visit project_issues_path(project, due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name)
|
||||
|
||||
page.within '.issues-holder' do
|
||||
page.within '.issues-list' do
|
||||
expect(page).not_to have_content('foo')
|
||||
expect(page).not_to have_content('bar')
|
||||
expect(page).to have_content('baz')
|
||||
|
|
|
@ -60,7 +60,7 @@ RSpec.describe 'User sorts merge requests' do
|
|||
|
||||
visit(project_issues_path(project))
|
||||
|
||||
expect(find('.issues-filters a.is-active')).not_to have_content('Milestone')
|
||||
expect(page).not_to have_button('Milestone')
|
||||
end
|
||||
|
||||
context 'when merge requests have awards' do
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import $ from 'jquery';
|
||||
import { getTimeago, localTimeAgo, timeFor } from '~/lib/utils/datetime/timeago_utility';
|
||||
import { s__ } from '~/locale';
|
||||
import '~/commons/bootstrap';
|
||||
|
@ -81,16 +80,16 @@ describe('TimeAgo utils', () => {
|
|||
`With User Setting timeDisplayRelative: $timeDisplayRelative`,
|
||||
({ timeDisplayRelative, text }) => {
|
||||
it.each`
|
||||
timeagoArg | title
|
||||
updateTooltip | title
|
||||
${false} | ${'some time'}
|
||||
${true} | ${'Feb 18, 2020 10:22pm UTC'}
|
||||
`(
|
||||
`has content: '${text}' and tooltip: '$title' with timeagoArg = $timeagoArg`,
|
||||
({ timeagoArg, title }) => {
|
||||
`has content: '${text}' and tooltip: '$title' with updateTooltip = $updateTooltip`,
|
||||
({ updateTooltip, title }) => {
|
||||
window.gon = { time_display_relative: timeDisplayRelative };
|
||||
|
||||
const element = document.querySelector('time');
|
||||
localTimeAgo($(element), timeagoArg);
|
||||
localTimeAgo([element], updateTooltip);
|
||||
|
||||
jest.runAllTimers();
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
|
|||
|
||||
<oncall-schedules-list-stub
|
||||
schedules="schedule1,schedule2"
|
||||
username="username"
|
||||
/>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -18,7 +18,7 @@ const mockSchedules = [
|
|||
},
|
||||
];
|
||||
|
||||
const userName = 'User 1';
|
||||
const userName = "O'User";
|
||||
|
||||
describe('On-call schedules list', () => {
|
||||
let wrapper;
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec::Matchers.define :have_issuable_counts do |opts|
|
|||
end
|
||||
|
||||
match do |actual|
|
||||
actual.within '.issues-state-filters' do
|
||||
actual.within '.top-area' do
|
||||
expected_counts.each do |expected_count|
|
||||
expect(actual).to have_content(expected_count)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue