Commit 7c8110e7 authored by Emily Ring's avatar Emily Ring Committed by Tiger Watson

Add name field for cluster agent token

Added cluster agent token name field to database and GraphQL
Updated associated docs and tests
parent dbe5012f
...@@ -13,5 +13,6 @@ module Clusters ...@@ -13,5 +13,6 @@ module Clusters
before_save :ensure_token before_save :ensure_token
validates :description, length: { maximum: 1024 } validates :description, length: { maximum: 1024 }
validates :name, presence: true, length: { maximum: 255 }, on: :create
end end
end end
---
title: Add name field to cluster agent token
merge_request: 53920
author:
type: changed
# frozen_string_literal: true
class AddNameFieldToClusterAgentToken < ActiveRecord::Migration[6.0]
DOWNTIME = false
# rubocop:disable Migration/AddLimitToTextColumns
# limit is added in LimitClusterTokenSize
def change
add_column :cluster_agent_tokens, :name, :text
end
# rubocop:enable Migration/AddLimitToTextColumns
end
# frozen_string_literal: true
class LimitClusterTokenSize < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_text_limit :cluster_agent_tokens, :name, 255
end
def down
remove_text_limit :cluster_agent_tokens, :name
end
end
964e9f88018b2ab72fd370f6a8dccde218cfd4ffa3ccedf4f142ab341f5e858f
\ No newline at end of file
526174bd42327e0212b15ffbad99541887de1dec35cc4c592d4f02065026b3ca
\ No newline at end of file
...@@ -11029,6 +11029,8 @@ CREATE TABLE cluster_agent_tokens ( ...@@ -11029,6 +11029,8 @@ CREATE TABLE cluster_agent_tokens (
token_encrypted text NOT NULL, token_encrypted text NOT NULL,
created_by_user_id bigint, created_by_user_id bigint,
description text, description text,
name text,
CONSTRAINT check_2b79dbb315 CHECK ((char_length(name) <= 255)),
CONSTRAINT check_4e4ec5070a CHECK ((char_length(description) <= 1024)), CONSTRAINT check_4e4ec5070a CHECK ((char_length(description) <= 1024)),
CONSTRAINT check_c60daed227 CHECK ((char_length(token_encrypted) <= 255)) CONSTRAINT check_c60daed227 CHECK ((char_length(token_encrypted) <= 255))
); );
...@@ -865,6 +865,7 @@ Autogenerated return type of ClusterAgentDelete. ...@@ -865,6 +865,7 @@ Autogenerated return type of ClusterAgentDelete.
| `createdByUser` | User | The user who created the token. | | `createdByUser` | User | The user who created the token. |
| `description` | String | Description of the token. | | `description` | String | Description of the token. |
| `id` | ClustersAgentTokenID! | Global ID of the token. | | `id` | ClustersAgentTokenID! | Global ID of the token. |
| `name` | String | Name given to the token. |
### ClusterAgentTokenCreatePayload ### ClusterAgentTokenCreatePayload
......
...@@ -205,7 +205,13 @@ the Agent in subsequent steps. You can create an Agent record either: ...@@ -205,7 +205,13 @@ the Agent in subsequent steps. You can create an Agent record either:
} }
mutation createToken { mutation createToken {
clusterAgentTokenCreate(input: { clusterAgentId: <cluster-agent-id-taken-from-the-previous-mutation> }) { clusterAgentTokenCreate(
input: {
clusterAgentId: "<cluster-agent-id-taken-from-the-previous-mutation>"
description: "<optional-description-of-token>"
name: "<required-name-given-to-token>"
}
) {
secret # This is the value you need to use on the next step secret # This is the value you need to use on the next step
token { token {
createdAt createdAt
......
...@@ -20,6 +20,11 @@ module Mutations ...@@ -20,6 +20,11 @@ module Mutations
required: false, required: false,
description: 'Description of the token.' description: 'Description of the token.'
argument :name,
GraphQL::STRING_TYPE,
required: true,
description: 'Name of the token.'
field :secret, field :secret,
GraphQL::STRING_TYPE, GraphQL::STRING_TYPE,
null: true, null: true,
......
...@@ -34,6 +34,11 @@ module Types ...@@ -34,6 +34,11 @@ module Types
null: false, null: false,
description: 'Global ID of the token.' description: 'Global ID of the token.'
field :name,
GraphQL::STRING_TYPE,
null: true,
description: 'Name given to the token.'
def cluster_agent def cluster_agent
Gitlab::Graphql::Loaders::BatchModelLoader.new(::Clusters::Agent, object.agent_id).find Gitlab::Graphql::Loaders::BatchModelLoader.new(::Clusters::Agent, object.agent_id).find
end end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Clusters module Clusters
module AgentTokens module AgentTokens
class CreateService < ::BaseContainerService class CreateService < ::BaseContainerService
ALLOWED_PARAMS = %i[agent_id description].freeze ALLOWED_PARAMS = %i[agent_id description name].freeze
def execute def execute
return error_feature_not_available unless container.feature_available?(:cluster_agents) return error_feature_not_available unless container.feature_available?(:cluster_agents)
......
...@@ -19,8 +19,9 @@ RSpec.describe Mutations::Clusters::AgentTokens::Create do ...@@ -19,8 +19,9 @@ RSpec.describe Mutations::Clusters::AgentTokens::Create do
describe '#resolve' do describe '#resolve' do
let(:description) { 'new token!' } let(:description) { 'new token!' }
let(:name) { 'new name' }
subject { mutation.resolve(cluster_agent_id: cluster_agent.to_global_id, description: description) } subject { mutation.resolve(cluster_agent_id: cluster_agent.to_global_id, description: description, name: name) }
context 'without token permissions' do context 'without token permissions' do
it 'raises an error if the resource is not accessible to the user' do it 'raises an error if the resource is not accessible to the user' do
...@@ -50,8 +51,12 @@ RSpec.describe Mutations::Clusters::AgentTokens::Create do ...@@ -50,8 +51,12 @@ RSpec.describe Mutations::Clusters::AgentTokens::Create do
end end
it 'returns token information', :aggregate_failures do it 'returns token information', :aggregate_failures do
token = subject[:token]
expect(subject[:secret]).not_to be_nil expect(subject[:secret]).not_to be_nil
expect(subject[:token].description).to eq(description) expect(token.created_by_user).to eq(user)
expect(token.description).to eq(description)
expect(token.name).to eq(name)
end end
context 'invalid params' do context 'invalid params' do
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe GitlabSchema.types['ClusterAgentToken'] do RSpec.describe GitlabSchema.types['ClusterAgentToken'] do
let(:fields) { %i[cluster_agent created_at created_by_user description id] } let(:fields) { %i[cluster_agent created_at created_by_user description id name] }
it { expect(described_class.graphql_name).to eq('ClusterAgentToken') } it { expect(described_class.graphql_name).to eq('ClusterAgentToken') }
......
...@@ -9,10 +9,11 @@ RSpec.describe 'Create a new cluster agent token' do ...@@ -9,10 +9,11 @@ RSpec.describe 'Create a new cluster agent token' do
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
let(:description) { 'create token' } let(:description) { 'create token' }
let(:name) { 'token name' }
let(:mutation) do let(:mutation) do
graphql_mutation( graphql_mutation(
:cluster_agent_token_create, :cluster_agent_token_create,
{ cluster_agent_id: cluster_agent.to_global_id.to_s, description: description } { cluster_agent_id: cluster_agent.to_global_id.to_s, description: description, name: name }
) )
end end
...@@ -58,6 +59,7 @@ RSpec.describe 'Create a new cluster agent token' do ...@@ -58,6 +59,7 @@ RSpec.describe 'Create a new cluster agent token' do
expect(mutation_response['secret']).not_to be_nil expect(mutation_response['secret']).not_to be_nil
expect(mutation_response.dig('token', 'description')).to eq(description) expect(mutation_response.dig('token', 'description')).to eq(description)
expect(mutation_response.dig('token', 'name')).to eq(name)
end end
end end
end end
...@@ -8,7 +8,7 @@ RSpec.describe Clusters::AgentTokens::CreateService do ...@@ -8,7 +8,7 @@ RSpec.describe Clusters::AgentTokens::CreateService do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:cluster_agent) { create(:cluster_agent) } let(:cluster_agent) { create(:cluster_agent) }
let(:project) { cluster_agent.project } let(:project) { cluster_agent.project }
let(:params) { { agent_id: cluster_agent.id } } let(:params) { { agent_id: cluster_agent.id, description: 'token description', name: 'token name' } }
before do before do
stub_licensed_features(cluster_agents: false) stub_licensed_features(cluster_agents: false)
...@@ -28,9 +28,6 @@ RSpec.describe Clusters::AgentTokens::CreateService do ...@@ -28,9 +28,6 @@ RSpec.describe Clusters::AgentTokens::CreateService do
end end
context 'with premium plan' do context 'with premium plan' do
let(:description) { 'New token description' }
let(:params) { { agent_id: cluster_agent.id, description: description } }
before do before do
stub_licensed_features(cluster_agents: true) stub_licensed_features(cluster_agents: true)
end end
...@@ -64,7 +61,8 @@ RSpec.describe Clusters::AgentTokens::CreateService do ...@@ -64,7 +61,8 @@ RSpec.describe Clusters::AgentTokens::CreateService do
expect(subject.payload[:secret]).not_to be_nil expect(subject.payload[:secret]).not_to be_nil
expect(token.created_by_user).to eq(user) expect(token.created_by_user).to eq(user)
expect(token.description).to eq(description) expect(token.description).to eq(params[:description])
expect(token.name).to eq(params[:name])
end end
context 'when params are invalid' do context 'when params are invalid' do
...@@ -76,7 +74,7 @@ RSpec.describe Clusters::AgentTokens::CreateService do ...@@ -76,7 +74,7 @@ RSpec.describe Clusters::AgentTokens::CreateService do
it 'returns validation errors', :aggregate_failures do it 'returns validation errors', :aggregate_failures do
expect(subject.status).to eq(:error) expect(subject.status).to eq(:error)
expect(subject.message).to eq(['Agent must exist']) expect(subject.message).to eq(["Agent must exist", "Name can't be blank"])
end end
end end
end end
......
...@@ -32,7 +32,7 @@ module QA ...@@ -32,7 +32,7 @@ module QA
def api_post_body def api_post_body
<<~GQL <<~GQL
mutation createToken { mutation createToken {
clusterAgentTokenCreate(input: { clusterAgentId: "gid://gitlab/Clusters::Agent/#{agent.id}" }) { clusterAgentTokenCreate(input: { clusterAgentId: "gid://gitlab/Clusters::Agent/#{agent.id}" name: "token-#{agent.id}" }) {
secret # This is the value you need to use on the next step secret # This is the value you need to use on the next step
token { token {
createdAt createdAt
......
...@@ -5,5 +5,7 @@ FactoryBot.define do ...@@ -5,5 +5,7 @@ FactoryBot.define do
association :agent, factory: :cluster_agent association :agent, factory: :cluster_agent
token_encrypted { Gitlab::CryptoHelper.aes256_gcm_encrypt(SecureRandom.hex(50)) } token_encrypted { Gitlab::CryptoHelper.aes256_gcm_encrypt(SecureRandom.hex(50)) }
sequence(:name) { |n| "agent-token-#{n}" }
end end
end end
...@@ -6,6 +6,8 @@ RSpec.describe Clusters::AgentToken do ...@@ -6,6 +6,8 @@ RSpec.describe Clusters::AgentToken do
it { is_expected.to belong_to(:agent).class_name('Clusters::Agent').required } it { is_expected.to belong_to(:agent).class_name('Clusters::Agent').required }
it { is_expected.to belong_to(:created_by_user).class_name('User').optional } it { is_expected.to belong_to(:created_by_user).class_name('User').optional }
it { is_expected.to validate_length_of(:description).is_at_most(1024) } it { is_expected.to validate_length_of(:description).is_at_most(1024) }
it { is_expected.to validate_length_of(:name).is_at_most(255) }
it { is_expected.to validate_presence_of(:name) }
describe '#token' do describe '#token' do
it 'is generated on save' do it 'is generated on save' 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