Commit 306c6ff7 authored by Peter Hegman's avatar Peter Hegman

Merge branch '340882-enhance-agent-listing-with-version' into 'master'

Add version column to the Agent listing

See merge request gitlab-org/gitlab!78553
parents 083e8164 eed6b9a6
<script>
import { GlLink, GlTable, GlIcon, GlSprintf, GlTooltip, GlPopover } from '@gitlab/ui';
import { s__ } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import { helpPagePath } from '~/helpers/help_page_helper';
import { AGENT_STATUSES } from '../constants';
import { AGENT_STATUSES, I18N_AGENT_TABLE } from '../constants';
import { getAgentConfigPath } from '../clusters_util';
import DeleteAgentButton from './delete_agent_button.vue';
export default {
i18n: {
nameLabel: s__('ClusterAgents|Name'),
statusLabel: s__('ClusterAgents|Connection status'),
lastContactLabel: s__('ClusterAgents|Last contact'),
configurationLabel: s__('ClusterAgents|Configuration'),
troubleshootingText: s__('ClusterAgents|Learn how to troubleshoot'),
neverConnectedText: s__('ClusterAgents|Never'),
},
i18n: I18N_AGENT_TABLE,
components: {
GlLink,
GlTable,
......@@ -29,9 +21,13 @@ export default {
},
mixins: [timeagoMixin],
AGENT_STATUSES,
troubleshooting_link: helpPagePath('user/clusters/agent/index', {
troubleshootingLink: helpPagePath('user/clusters/agent/index', {
anchor: 'troubleshooting',
}),
versionUpdateLink: helpPagePath('user/clusters/agent/install/index', {
anchor: 'update-the-agent-version',
}),
inject: ['gitlabVersion'],
props: {
agents: {
required: true,
......@@ -67,6 +63,11 @@ export default {
label: this.$options.i18n.lastContactLabel,
tdClass,
},
{
key: 'version',
label: this.$options.i18n.versionLabel,
tdClass,
},
{
key: 'configuration',
label: this.$options.i18n.configurationLabel,
......@@ -79,19 +80,77 @@ export default {
},
];
},
agentsList() {
if (!this.agents.length) {
return [];
}
return this.agents.map((agent) => {
const versions = this.getAgentVersions(agent);
return { ...agent, versions };
});
},
},
methods: {
getCellId(item) {
getStatusCellId(item) {
return `connection-status-${item.name}`;
},
getVersionCellId(item) {
return `version-${item.name}`;
},
getPopoverTestId(item) {
return `popover-${item.name}`;
},
getAgentConfigPath,
getAgentVersions(agent) {
const agentConnections = agent.connections?.nodes || [];
const agentVersions = agentConnections.map((agentConnection) =>
agentConnection.metadata.version.replace('v', ''),
);
const uniqueAgentVersions = [...new Set(agentVersions)];
return uniqueAgentVersions.sort((a, b) => a.localeCompare(b));
},
getAgentVersionString(agent) {
return agent.versions[0] || '';
},
isVersionMismatch(agent) {
return agent.versions.length > 1;
},
isVersionOutdated(agent) {
if (!agent.versions.length) return false;
const [agentMajorVersion, agentMinorVersion] = this.getAgentVersionString(agent).split('.');
const [gitlabMajorVersion, gitlabMinorVersion] = this.gitlabVersion.split('.');
const majorVersionMismatch = agentMajorVersion !== gitlabMajorVersion;
// We should warn user if their current GitLab and agent versions are more than 1 minor version apart:
const minorVersionMismatch = Math.abs(agentMinorVersion - gitlabMinorVersion) > 1;
return majorVersionMismatch || minorVersionMismatch;
},
getVersionPopoverTitle(agent) {
if (this.isVersionMismatch(agent) && this.isVersionOutdated(agent)) {
return this.$options.i18n.versionMismatchOutdatedTitle;
} else if (this.isVersionMismatch(agent)) {
return this.$options.i18n.versionMismatchTitle;
} else if (this.isVersionOutdated(agent)) {
return this.$options.i18n.versionOutdatedTitle;
}
return null;
},
},
};
</script>
<template>
<gl-table
:items="agents"
:items="agentsList"
:fields="fields"
stacked="md"
head-variant="white"
......@@ -106,19 +165,23 @@ export default {
</template>
<template #cell(status)="{ item }">
<span :id="getCellId(item)" class="gl-md-pr-5" data-testid="cluster-agent-connection-status">
<span
:id="getStatusCellId(item)"
class="gl-md-pr-5"
data-testid="cluster-agent-connection-status"
>
<span :class="$options.AGENT_STATUSES[item.status].class" class="gl-mr-3">
<gl-icon :name="$options.AGENT_STATUSES[item.status].icon" :size="12" /></span
>{{ $options.AGENT_STATUSES[item.status].name }}
</span>
<gl-tooltip v-if="item.status === 'active'" :target="getCellId(item)" placement="right">
<gl-tooltip v-if="item.status === 'active'" :target="getStatusCellId(item)" placement="right">
<gl-sprintf :message="$options.AGENT_STATUSES[item.status].tooltip.title"
><template #timeAgo>{{ timeFormatted(item.lastContact) }}</template>
</gl-sprintf>
</gl-tooltip>
<gl-popover
v-else
:target="getCellId(item)"
:target="getStatusCellId(item)"
:title="$options.AGENT_STATUSES[item.status].tooltip.title"
placement="right"
container="viewport"
......@@ -129,7 +192,7 @@ export default {
>
</p>
<p class="gl-mb-0">
<gl-link :href="$options.troubleshooting_link" target="_blank" class="gl-font-sm">
<gl-link :href="$options.troubleshootingLink" target="_blank" class="gl-font-sm">
{{ $options.i18n.troubleshootingText }}</gl-link
>
</p>
......@@ -143,6 +206,52 @@ export default {
</span>
</template>
<template #cell(version)="{ item }">
<span :id="getVersionCellId(item)" data-testid="cluster-agent-version">
{{ getAgentVersionString(item) }}
<gl-icon
v-if="isVersionMismatch(item) || isVersionOutdated(item)"
name="warning"
class="gl-text-orange-500 gl-ml-2"
/>
</span>
<gl-popover
v-if="isVersionMismatch(item) || isVersionOutdated(item)"
:target="getVersionCellId(item)"
:title="getVersionPopoverTitle(item)"
:data-testid="getPopoverTestId(item)"
placement="right"
container="viewport"
>
<div v-if="isVersionMismatch(item) && isVersionOutdated(item)">
<p>{{ $options.i18n.versionMismatchText }}</p>
<p class="gl-mb-0">
<gl-sprintf :message="$options.i18n.versionOutdatedText">
<template #version>{{ gitlabVersion }}</template>
</gl-sprintf>
<gl-link :href="$options.versionUpdateLink" class="gl-font-sm">
{{ $options.i18n.viewDocsText }}</gl-link
>
</p>
</div>
<p v-else-if="isVersionMismatch(item)" class="gl-mb-0">
{{ $options.i18n.versionMismatchText }}
</p>
<p v-else-if="isVersionOutdated(item)" class="gl-mb-0">
<gl-sprintf :message="$options.i18n.versionOutdatedText">
<template #version>{{ gitlabVersion }}</template>
</gl-sprintf>
<gl-link :href="$options.versionUpdateLink" class="gl-font-sm">
{{ $options.i18n.viewDocsText }}</gl-link
>
</p>
</gl-popover>
</template>
<template #cell(configuration)="{ item }">
<span data-testid="cluster-agent-configuration-link">
<gl-link v-if="item.configFolder" :href="item.configFolder.webPath">
......
......@@ -64,6 +64,27 @@ export const STATUSES = {
creating: { title: __('Creating') },
};
export const I18N_AGENT_TABLE = {
nameLabel: s__('ClusterAgents|Name'),
statusLabel: s__('ClusterAgents|Connection status'),
lastContactLabel: s__('ClusterAgents|Last contact'),
versionLabel: __('Version'),
configurationLabel: s__('ClusterAgents|Configuration'),
optionsLabel: __('Options'),
troubleshootingText: s__('ClusterAgents|Learn how to troubleshoot'),
neverConnectedText: s__('ClusterAgents|Never'),
versionMismatchTitle: s__('ClusterAgents|Agent version mismatch'),
versionMismatchText: s__(
"ClusterAgents|The Agent version do not match each other across your cluster's pods. This can happen when a new Agent version was just deployed and Kubernetes is shutting down the old pods.",
),
versionOutdatedTitle: s__('ClusterAgents|Agent version update required'),
versionOutdatedText: s__(
'ClusterAgents|Your Agent version is out of sync with your GitLab version (v%{version}), which might cause compatibility problems. Update the Agent installed on your cluster to the most recent version.',
),
versionMismatchOutdatedTitle: s__('ClusterAgents|Agent version mismatch and update'),
viewDocsText: s__('ClusterAgents|How to update the Agent?'),
};
export const I18N_AGENT_MODAL = {
agent_registration: {
registerAgentButton: s__('ClusterAgents|Register'),
......
......@@ -2,6 +2,13 @@ fragment ClusterAgentFragment on ClusterAgent {
id
name
webPath
connections {
nodes {
metadata {
version
}
}
}
tokens {
nodes {
id
......
......@@ -27,6 +27,7 @@ export default () => {
clustersEmptyStateImage,
canAddCluster,
canAdminCluster,
gitlabVersion,
} = el.dataset;
return new Vue({
......@@ -42,6 +43,7 @@ export default () => {
clustersEmptyStateImage,
canAddCluster: parseBoolean(canAddCluster),
canAdminCluster: parseBoolean(canAdminCluster),
gitlabVersion,
},
store: createStore(el.dataset),
render(createElement) {
......
......@@ -29,7 +29,7 @@ module Resolvers
def get_connected_agents
kas_client.get_connected_agents(project: project)
rescue GRPC::BadStatus => e
rescue GRPC::BadStatus, Gitlab::Kas::Client::ConfigurationError => e
raise Gitlab::Graphql::Errors::ResourceNotAvailable, e.class.name
end
......
......@@ -39,7 +39,8 @@ module ClustersHelper
empty_state_image: image_path('illustrations/empty-state/empty-state-agents.svg'),
project_path: clusterable.full_path,
add_cluster_path: clusterable.new_path(tab: 'add'),
kas_address: Gitlab::Kas.external_url
kas_address: Gitlab::Kas.external_url,
gitlab_version: Gitlab.version_info
}.merge(js_clusters_list_data(clusterable))
end
......
......@@ -77,7 +77,7 @@ file and:
1. From your project's sidebar, select **Infrastructure > Kubernetes clusters**.
1. Select **Actions**.
1. From the **Select an Agent** dropdown list, select the Agent you want to register and select **Register an Agent**.
1. GitLab generates a registration token for this Agent. Securely store this secret token as you cannot view it again.
1. GitLab generates a registration token for this Agent. Securely store this secret token, as you need it to install the Agent onto your cluster and to [update the Agent](#update-the-agent-version) to another version.
1. Copy the command under **Recommended installation method**. You need it to install the Agent onto your cluster through the one-liner installation method.
### Install the Agent onto the cluster
......@@ -203,6 +203,35 @@ and you're good to go. You can create multiple Agents, for example:
- To reach your cluster from different projects.
- To connect multiple clusters to GitLab.
## Update the Agent version
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340882) in GitLab 14.8, GitLab warns you on the Agent's list page to update the Agent version installed on your cluster.
To update the Agent's version on your cluster, you need to re-run the [installation command](#install-the-agent-onto-the-cluster)
with a newer `--agent-version`. Make sure to specify the other required parameters: `--kas-address`, `--namespace`, and `--agent-token`.
You can find the available `agentk` versions in [the container registry](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/container_registry/1223205?sort=desc).
If you don't have access to your Agent's token, you can retrieve it from your cluster:
1. On your computer, open the terminal and connect to your cluster.
1. To retrieve the namespace, run:
```shell
kubectl get namespaces
```
1. To retrieve the secret, run:
```shell
kubectl -n <namespace> get secrets
```
1. To retrieve the token, run:
```shell
kubectl -n <namespace> get secret <secret-name> --template={{.data.token}} | base64 --decode
```
## Example projects
The following example projects can help you get started with the Agent.
......@@ -222,7 +251,8 @@ A feature introduced in a given GitLab minor version might work with other `agen
To make sure that it works, use at least the same `agentk` and `kas` minor version. For example,
if your GitLab version is 14.2, use at least `agentk` 14.2 and `kas` 14.2.
We recommend upgrading your `kas` installations together with GitLab instances' upgrades, and to upgrade the `agentk` installations after upgrading GitLab.
We recommend upgrading your `kas` installations together with GitLab instances' upgrades, and to
[upgrade the `agentk` installations](#update-the-agent-version) after upgrading GitLab.
The available `agentk` and `kas` versions can be found in
[the container registry](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/container_registry/).
......@@ -7613,6 +7613,15 @@ msgstr ""
msgid "ClusterAgents|Agent never connected to GitLab"
msgstr ""
msgid "ClusterAgents|Agent version mismatch"
msgstr ""
msgid "ClusterAgents|Agent version mismatch and update"
msgstr ""
msgid "ClusterAgents|Agent version update required"
msgstr ""
msgid "ClusterAgents|All"
msgstr ""
......@@ -7712,6 +7721,9 @@ msgstr ""
msgid "ClusterAgents|How to register an agent?"
msgstr ""
msgid "ClusterAgents|How to update the Agent?"
msgstr ""
msgid "ClusterAgents|Install new Agent"
msgstr ""
......@@ -7793,6 +7805,9 @@ msgstr ""
msgid "ClusterAgents|Tell us what you think"
msgstr ""
msgid "ClusterAgents|The Agent version do not match each other across your cluster's pods. This can happen when a new Agent version was just deployed and Kubernetes is shutting down the old pods."
msgstr ""
msgid "ClusterAgents|The GitLab Agent provides an increased level of security when connecting Kubernetes clusters to GitLab. %{linkStart}Learn more about the GitLab Agent.%{linkEnd}"
msgstr ""
......@@ -7846,6 +7861,9 @@ msgstr ""
msgid "ClusterAgents|You will need to create a token to connect to your agent"
msgstr ""
msgid "ClusterAgents|Your Agent version is out of sync with your GitLab version (v%{version}), which might cause compatibility problems. Update the Agent installed on your cluster to the most recent version."
msgstr ""
msgid "ClusterAgents|Your instance doesn't have the %{linkStart}GitLab Agent Server (KAS)%{linkEnd} set up. Ask a GitLab Administrator to install it."
msgstr ""
......
......@@ -15,6 +15,7 @@ RSpec.describe 'Cluster agent registration', :js do
double(agent_name: 'example-agent-1', path: '.gitlab/agents/example-agent-1/config.yaml'),
double(agent_name: 'example-agent-2', path: '.gitlab/agents/example-agent-2/config.yaml')
])
allow(client).to receive(:get_connected_agents).and_return([])
end
allow(Devise).to receive(:friendly_token).and_return('example-agent-token')
......
......@@ -10,6 +10,11 @@ RSpec.describe 'ClusterAgents', :js do
let(:user) { project.creator }
before do
allow(Gitlab::Kas).to receive(:enabled?).and_return(true)
allow_next_instance_of(Gitlab::Kas::Client) do |client|
allow(client).to receive(:get_connected_agents).and_return([])
end
gitlab_sign_in(user)
end
......
import { GlLink, GlIcon } from '@gitlab/ui';
import { sprintf } from '~/locale';
import AgentTable from '~/clusters_list/components/agent_table.vue';
import DeleteAgentButton from '~/clusters_list/components/delete_agent_button.vue';
import { ACTIVE_CONNECTION_TIME } from '~/clusters_list/constants';
import { I18N_AGENT_TABLE } from '~/clusters_list/constants';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
import timeagoMixin from '~/vue_shared/mixins/timeago';
const connectedTimeNow = new Date();
const connectedTimeInactive = new Date(connectedTimeNow.getTime() - ACTIVE_CONNECTION_TIME);
import { clusterAgents, connectedTimeNow, connectedTimeInactive } from './mock_data';
const provideData = {
projectPath: 'path/to/project',
gitlabVersion: '14.8',
};
const propsData = {
agents: [
{
name: 'agent-1',
id: 'agent-1-id',
configFolder: {
webPath: '/agent/full/path',
},
webPath: '/agent-1',
status: 'unused',
lastContact: null,
tokens: null,
},
{
name: 'agent-2',
id: 'agent-2-id',
webPath: '/agent-2',
status: 'active',
lastContact: connectedTimeNow.getTime(),
tokens: {
nodes: [
{
lastUsedAt: connectedTimeNow,
},
],
},
},
{
name: 'agent-3',
id: 'agent-3-id',
webPath: '/agent-3',
status: 'inactive',
lastContact: connectedTimeInactive.getTime(),
tokens: {
nodes: [
{
lastUsedAt: connectedTimeInactive,
},
],
},
},
],
agents: clusterAgents,
};
const DeleteAgentButtonStub = stubComponent(DeleteAgentButton, {
template: `<div></div>`,
});
const outdatedTitle = I18N_AGENT_TABLE.versionOutdatedTitle;
const mismatchTitle = I18N_AGENT_TABLE.versionMismatchTitle;
const mismatchOutdatedTitle = I18N_AGENT_TABLE.versionMismatchOutdatedTitle;
const outdatedText = sprintf(I18N_AGENT_TABLE.versionOutdatedText, {
version: provideData.gitlabVersion,
});
const mismatchText = I18N_AGENT_TABLE.versionMismatchText;
describe('AgentTable', () => {
let wrapper;
......@@ -67,6 +34,7 @@ describe('AgentTable', () => {
const findStatusIcon = (at) => wrapper.findAllComponents(GlIcon).at(at);
const findStatusText = (at) => wrapper.findAllByTestId('cluster-agent-connection-status').at(at);
const findLastContactText = (at) => wrapper.findAllByTestId('cluster-agent-last-contact').at(at);
const findVersionText = (at) => wrapper.findAllByTestId('cluster-agent-version').at(at);
const findConfiguration = (at) =>
wrapper.findAllByTestId('cluster-agent-configuration-link').at(at);
const findDeleteAgentButton = () => wrapper.findAllComponents(DeleteAgentButton);
......@@ -92,7 +60,7 @@ describe('AgentTable', () => {
agentName | link | lineNumber
${'agent-1'} | ${'/agent-1'} | ${0}
${'agent-2'} | ${'/agent-2'} | ${1}
`('displays agent link', ({ agentName, link, lineNumber }) => {
`('displays agent link for $agentName', ({ agentName, link, lineNumber }) => {
expect(findAgentLink(lineNumber).text()).toBe(agentName);
expect(findAgentLink(lineNumber).attributes('href')).toBe(link);
});
......@@ -102,33 +70,92 @@ describe('AgentTable', () => {
${'Never connected'} | ${'status-neutral'} | ${0}
${'Connected'} | ${'status-success'} | ${1}
${'Not connected'} | ${'severity-critical'} | ${2}
`('displays agent connection status', ({ status, iconName, lineNumber }) => {
expect(findStatusText(lineNumber).text()).toBe(status);
expect(findStatusIcon(lineNumber).props('name')).toBe(iconName);
});
`(
'displays agent connection status as "$status" at line $lineNumber',
({ status, iconName, lineNumber }) => {
expect(findStatusText(lineNumber).text()).toBe(status);
expect(findStatusIcon(lineNumber).props('name')).toBe(iconName);
},
);
it.each`
lastContact | lineNumber
${'Never'} | ${0}
${timeagoMixin.methods.timeFormatted(connectedTimeNow)} | ${1}
${timeagoMixin.methods.timeFormatted(connectedTimeInactive)} | ${2}
`('displays agent last contact time', ({ lastContact, lineNumber }) => {
expect(findLastContactText(lineNumber).text()).toBe(lastContact);
});
`(
'displays agent last contact time as "$lastContact" at line $lineNumber',
({ lastContact, lineNumber }) => {
expect(findLastContactText(lineNumber).text()).toBe(lastContact);
},
);
describe.each`
agent | version | podsNumber | versionMismatch | versionOutdated | title | texts | lineNumber
${'agent-1'} | ${''} | ${1} | ${false} | ${false} | ${''} | ${''} | ${0}
${'agent-2'} | ${'14.8'} | ${2} | ${false} | ${false} | ${''} | ${''} | ${1}
${'agent-3'} | ${'14.5'} | ${1} | ${false} | ${true} | ${outdatedTitle} | ${[outdatedText]} | ${2}
${'agent-4'} | ${'14.7'} | ${2} | ${true} | ${false} | ${mismatchTitle} | ${[mismatchText]} | ${3}
${'agent-5'} | ${'14.3'} | ${2} | ${true} | ${true} | ${mismatchOutdatedTitle} | ${[mismatchText, outdatedText]} | ${4}
`(
'agent version column at line $lineNumber',
({
agent,
version,
podsNumber,
versionMismatch,
versionOutdated,
title,
texts,
lineNumber,
}) => {
const findIcon = () => findVersionText(lineNumber).find(GlIcon);
const findPopover = () => wrapper.findByTestId(`popover-${agent}`);
const versionWarning = versionMismatch || versionOutdated;
it('shows the correct agent version', () => {
expect(findVersionText(lineNumber).text()).toBe(version);
});
if (versionWarning) {
it(`shows a warning icon when agent versions mismatch is ${versionMismatch} and outdated is ${versionOutdated} and the number of pods is ${podsNumber}`, () => {
expect(findIcon().props('name')).toBe('warning');
});
it(`renders correct title for the popover when agent versions mismatch is ${versionMismatch} and outdated is ${versionOutdated}`, () => {
expect(findPopover().props('title')).toBe(title);
});
it(`renders correct text for the popover when agent versions mismatch is ${versionMismatch} and outdated is ${versionOutdated}`, () => {
texts.forEach((text) => {
expect(findPopover().text()).toContain(text);
});
});
} else {
it(`doesn't show a warning icon with a popover when agent versions mismatch is ${versionMismatch} and outdated is ${versionOutdated} and the number of pods is ${podsNumber}`, () => {
expect(findIcon().exists()).toBe(false);
expect(findPopover().exists()).toBe(false);
});
}
},
);
it.each`
agentPath | hasLink | lineNumber
${'.gitlab/agents/agent-1'} | ${true} | ${0}
${'.gitlab/agents/agent-2'} | ${false} | ${1}
`('displays config file path', ({ agentPath, hasLink, lineNumber }) => {
const findLink = findConfiguration(lineNumber).find(GlLink);
`(
'displays config file path as "$agentPath" at line $lineNumber',
({ agentPath, hasLink, lineNumber }) => {
const findLink = findConfiguration(lineNumber).find(GlLink);
expect(findLink.exists()).toBe(hasLink);
expect(findConfiguration(lineNumber).text()).toBe(agentPath);
});
expect(findLink.exists()).toBe(hasLink);
expect(findConfiguration(lineNumber).text()).toBe(agentPath);
},
);
it('displays actions menu for each agent', () => {
expect(findDeleteAgentButton()).toHaveLength(3);
expect(findDeleteAgentButton()).toHaveLength(5);
});
});
});
......@@ -40,7 +40,13 @@ describe('Agents', () => {
data: {
project: {
id: '1',
clusterAgents: { nodes: agents, pageInfo, tokens: { nodes: [] }, count },
clusterAgents: {
nodes: agents,
pageInfo,
connections: { nodes: [] },
tokens: { nodes: [] },
count,
},
repository: { tree: { trees: { nodes: trees, pageInfo } } },
},
},
......@@ -89,12 +95,14 @@ describe('Agents', () => {
id: '1',
name: 'agent-1',
webPath: '/agent-1',
connections: null,
tokens: null,
},
{
id: '2',
name: 'agent-2',
webPath: '/agent-2',
connections: null,
tokens: {
nodes: [
{
......@@ -125,6 +133,7 @@ describe('Agents', () => {
configFolder: undefined,
status: 'unused',
lastContact: null,
connections: null,
tokens: null,
},
{
......@@ -138,6 +147,7 @@ describe('Agents', () => {
webPath: '/agent-2',
status: 'active',
lastContact: new Date(testDate).getTime(),
connections: null,
tokens: {
nodes: [
{
......
import { ACTIVE_CONNECTION_TIME } from '~/clusters_list/constants';
export const agentConfigurationsResponse = {
data: {
project: {
......@@ -10,3 +12,113 @@ export const agentConfigurationsResponse = {
},
},
};
export const connectedTimeNow = new Date();
export const connectedTimeInactive = new Date(connectedTimeNow.getTime() - ACTIVE_CONNECTION_TIME);
export const clusterAgents = [
{
name: 'agent-1',
id: 'agent-1-id',
configFolder: {
webPath: '/agent/full/path',
},
webPath: '/agent-1',
status: 'unused',
lastContact: null,
tokens: null,
},
{
name: 'agent-2',
id: 'agent-2-id',
webPath: '/agent-2',
status: 'active',
lastContact: connectedTimeNow.getTime(),
connections: {
nodes: [
{
metadata: { version: 'v14.8' },
},
{
metadata: { version: 'v14.8' },
},
],
},
tokens: {
nodes: [
{
lastUsedAt: connectedTimeNow,
},
],
},
},
{
name: 'agent-3',
id: 'agent-3-id',
webPath: '/agent-3',
status: 'inactive',
lastContact: connectedTimeInactive.getTime(),
connections: {
nodes: [
{
metadata: { version: 'v14.5' },
},
],
},
tokens: {
nodes: [
{
lastUsedAt: connectedTimeInactive,
},
],
},
},
{
name: 'agent-4',
id: 'agent-4-id',
webPath: '/agent-4',
status: 'inactive',
lastContact: connectedTimeInactive.getTime(),
connections: {
nodes: [
{
metadata: { version: 'v14.7' },
},
{
metadata: { version: 'v14.8' },
},
],
},
tokens: {
nodes: [
{
lastUsedAt: connectedTimeInactive,
},
],
},
},
{
name: 'agent-5',
id: 'agent-5-id',
webPath: '/agent-5',
status: 'inactive',
lastContact: connectedTimeInactive.getTime(),
connections: {
nodes: [
{
metadata: { version: 'v14.5' },
},
{
metadata: { version: 'v14.3' },
},
],
},
tokens: {
nodes: [
{
lastUsedAt: connectedTimeInactive,
},
],
},
},
];
......@@ -10,6 +10,9 @@ const token = {
const tokens = {
nodes: [token],
};
const connections = {
nodes: [],
};
const pageInfo = {
endCursor: '',
hasNextPage: false,
......@@ -23,6 +26,7 @@ export const createAgentResponse = {
createClusterAgent: {
clusterAgent: {
...agent,
connections,
tokens,
},
errors: [],
......@@ -35,6 +39,7 @@ export const createAgentErrorResponse = {
createClusterAgent: {
clusterAgent: {
...agent,
connections,
tokens,
},
errors: ['could not create agent'],
......@@ -66,7 +71,7 @@ export const getAgentResponse = {
data: {
project: {
id: 'project-1',
clusterAgents: { nodes: [{ ...agent, tokens }], pageInfo, count },
clusterAgents: { nodes: [{ ...agent, connections, tokens }], pageInfo, count },
repository: {
tree: {
trees: { nodes: [{ ...agent, path: null }], pageInfo },
......
......@@ -152,6 +152,10 @@ RSpec.describe ClustersHelper do
it 'displays kas address' do
expect(subject[:kas_address]).to eq(Gitlab::Kas.external_url)
end
it 'displays GitLab version' do
expect(subject[:gitlab_version]).to eq(Gitlab.version_info)
end
end
describe '#js_cluster_new' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment