diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md
index 0a102cce2fbba38049b60de85b64fbf773836fd6..03acc8a50a6dc2826f66f589468b67742c24f56d 100644
--- a/doc/api/graphql/reference/_index.md
+++ b/doc/api/graphql/reference/_index.md
@@ -34178,7 +34178,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
-| `filter` | [`NamespaceClusterAgentFilter!`](#namespaceclusteragentfilter) | Filter the types of cluster agents to return. |
+| `filter` | [`OrganizationClusterAgentFilter!`](#organizationclusteragentfilter) | Filter the types of cluster agents to return. |
### `OrganizationStateCounts`
@@ -45208,6 +45208,7 @@ Possible filter types for remote development cluster agents in a namespace.
| Value | Description |
| ----- | ----------- |
+| `ALL` | All cluster agents in the namespace that can be used for hosting worksapces. |
| `AVAILABLE` | Cluster agents in the namespace that can be used for hosting workspaces. |
| `DIRECTLY_MAPPED` | Cluster agents that are directly mapped to the given namespace. |
| `UNMAPPED` | Cluster agents within a namespace that are not directly mapped to it. |
@@ -45290,6 +45291,15 @@ Enum defining the type of OpenTelemetry metric.
| `HISTOGRAM_TYPE` | Histogram Type type. |
| `SUM_TYPE` | Sum Type type. |
+### `OrganizationClusterAgentFilter`
+
+Possible filter types for remote development cluster agents in an organization.
+
+| Value | Description |
+| ----- | ----------- |
+| `ALL` | All cluster agents in the organization that can be used for hosting workspaces. |
+| `DIRECTLY_MAPPED` | Cluster agents that are directly mapped to the given organization. |
+
### `OrganizationGroupProjectDisplay`
Default list view for organization groups and projects.
diff --git a/ee/app/finders/remote_development/namespace_cluster_agents_finder.rb b/ee/app/finders/remote_development/namespace_cluster_agents_finder.rb
index 5d899fc46c3de7cf887bebfec962b472e4ff4925..f450b725aba09c60c848d5adbaf3de567609952e 100644
--- a/ee/app/finders/remote_development/namespace_cluster_agents_finder.rb
+++ b/ee/app/finders/remote_development/namespace_cluster_agents_finder.rb
@@ -18,6 +18,11 @@ def self.execute(namespace:, filter:, user:)
# @return [ActiveRecord::Relation]
def self.fetch_agents(namespace:, filter:, user:)
case filter
+ when :all
+ return Clusters::Agent.none unless user_can_read_namespace_agent_mappings?(user: user, namespace: namespace)
+
+ # Returns all agents with remote development enabled
+ namespace.cluster_agents.with_remote_development_enabled
when :unmapped
return Clusters::Agent.none unless user_can_read_namespace_agent_mappings?(user: user, namespace: namespace)
diff --git a/ee/app/finders/remote_development/organization_cluster_agents_finder.rb b/ee/app/finders/remote_development/organization_cluster_agents_finder.rb
index cefac8fdb933ac116cc51485dc892e64d351e3e3..60487e6a9275839ef402f1e44b71f2374d47ff35 100644
--- a/ee/app/finders/remote_development/organization_cluster_agents_finder.rb
+++ b/ee/app/finders/remote_development/organization_cluster_agents_finder.rb
@@ -10,7 +10,7 @@ def self.execute(organization:, filter:, user:)
return Clusters::Agent.none unless organization && user.can?(:read_organization_cluster_agent_mapping,
organization)
- fetch_agents(filter: filter, organization: organization)
+ fetch_agents(filter: filter, organization: organization).ordered_by_name
end
# @param [RemoteDevelopment::Organization] organization
@@ -18,17 +18,10 @@ def self.execute(organization:, filter:, user:)
# @return [ActiveRecord::Relation]
def self.fetch_agents(organization:, filter:)
case filter
- when :unmapped
- # rubocop: disable CodeReuse/ActiveRecord -- activerecord is convenient for filtering for records
- # noinspection RailsParamDefResolve -- RubyMine is not finding organization_cluster_agent_mapping
- Clusters::Agent.for_organizations([organization.id])
- .left_joins(:organization_cluster_agent_mapping)
- .where(organization_cluster_agent_mapping: { id: nil })
- .select('"cluster_agents".*')
- # rubocop: enable CodeReuse/ActiveRecord
+ when :all
+ # Returns all agents that have remote development enabled
+ Clusters::Agent.for_organizations([organization.id]).with_remote_development_enabled
when :directly_mapped
- organization.mapped_agents
- when :available
organization.mapped_agents.with_remote_development_enabled
else
raise "Unsupported value for filter: #{filter}"
diff --git a/ee/app/graphql/resolvers/remote_development/organization/cluster_agents_resolver.rb b/ee/app/graphql/resolvers/remote_development/organization/cluster_agents_resolver.rb
index 5ed91c94f8e23d5c2759d7f4d5c7656033113186..e262ed06927a5cabe796a7858ce0541a5b944456 100644
--- a/ee/app/graphql/resolvers/remote_development/organization/cluster_agents_resolver.rb
+++ b/ee/app/graphql/resolvers/remote_development/organization/cluster_agents_resolver.rb
@@ -8,7 +8,7 @@ class ClusterAgentsResolver < ::Resolvers::BaseResolver
type Types::Clusters::AgentType.connection_type, null: true
- argument :filter, Types::RemoteDevelopment::NamespaceClusterAgentFilterEnum,
+ argument :filter, Types::RemoteDevelopment::OrganizationClusterAgentFilterEnum,
required: true,
description: 'Filter the types of cluster agents to return.'
diff --git a/ee/app/graphql/types/remote_development/namespace_cluster_agent_filter_enum.rb b/ee/app/graphql/types/remote_development/namespace_cluster_agent_filter_enum.rb
index 71aead69e0d40d5b6a2aaecba5d6a5a8eff57413..0c73b98e51a9c7552464ccd34b7bafe5fba289d0 100644
--- a/ee/app/graphql/types/remote_development/namespace_cluster_agent_filter_enum.rb
+++ b/ee/app/graphql/types/remote_development/namespace_cluster_agent_filter_enum.rb
@@ -14,6 +14,9 @@ class NamespaceClusterAgentFilterEnum < BaseEnum
value 'UNMAPPED',
description: "Cluster agents within a namespace that are not directly mapped to it.", value: 'UNMAPPED'
+
+ value 'ALL',
+ description: "All cluster agents in the namespace that can be used for hosting worksapces.", value: 'ALL'
end
end
end
diff --git a/ee/app/graphql/types/remote_development/organization_cluster_agent_filter_enum.rb b/ee/app/graphql/types/remote_development/organization_cluster_agent_filter_enum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..63d6be4e004a1f0e7bf44c6975b00f8011345656
--- /dev/null
+++ b/ee/app/graphql/types/remote_development/organization_cluster_agent_filter_enum.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Types
+ module RemoteDevelopment
+ class OrganizationClusterAgentFilterEnum < BaseEnum
+ graphql_name 'OrganizationClusterAgentFilter'
+ description 'Possible filter types for remote development cluster agents in an organization'
+
+ value 'DIRECTLY_MAPPED',
+ description: "Cluster agents that are directly mapped to the given organization.", value: 'DIRECTLY_MAPPED'
+
+ value 'ALL',
+ description: "All cluster agents in the organization that can be used for hosting workspaces.", value: 'ALL'
+ end
+ end
+end
diff --git a/ee/spec/finders/remote_development/namespace_cluster_agents_finder_spec.rb b/ee/spec/finders/remote_development/namespace_cluster_agents_finder_spec.rb
index 04645897338c21a48f1d7cd6666009832ee7d859..4d6611566aff88e58b891f15f95a4091210c78f5 100644
--- a/ee/spec/finders/remote_development/namespace_cluster_agents_finder_spec.rb
+++ b/ee/spec/finders/remote_development/namespace_cluster_agents_finder_spec.rb
@@ -81,6 +81,14 @@
).to_a
end
+ shared_examples 'when user does not have adequate permissions' do
+ let(:user) { developer }
+
+ it 'returns an empty response' do
+ expect(response).to eq([])
+ end
+ end
+
context 'with filter_type set to available' do
context 'when cluster agents are mapped to the namespace' do
it 'returns cluster agents mapped to the namespace excluding those with remote dev disabled' do
@@ -129,13 +137,7 @@
end
end
- context 'when user does not have adequate permissions' do
- let(:user) { developer }
-
- it 'returns an empty response' do
- expect(response).to eq([])
- end
- end
+ it_behaves_like 'when user does not have adequate permissions'
end
context 'with filter_type set to unmapped' do
@@ -156,13 +158,18 @@
end
end
- context 'when user does not have adequate permissions' do
- let(:user) { developer }
+ it_behaves_like 'when user does not have adequate permissions'
+ end
- it 'returns an empty response' do
- expect(response).to eq([])
- end
+ context 'with filter_type set to all' do
+ let(:filter) { :all }
+ let_it_be(:user) { maintainer }
+
+ it 'returns all cluster agents within a namespace' do
+ expect(response).to match_array([root_agent, nested_agent, unmapped_root_agent])
end
+
+ it_behaves_like 'when user does not have adequate permissions'
end
context 'with an invalid value for filter_type' do
diff --git a/ee/spec/finders/remote_development/organization_cluster_agents_finder_spec.rb b/ee/spec/finders/remote_development/organization_cluster_agents_finder_spec.rb
index 3955829efe8c5d3292d6cbe4081895141171e50f..bb3038e727c5f068a992ef3d90b83c7fc913669b 100644
--- a/ee/spec/finders/remote_development/organization_cluster_agents_finder_spec.rb
+++ b/ee/spec/finders/remote_development/organization_cluster_agents_finder_spec.rb
@@ -12,7 +12,7 @@
end
end
- let(:filter) { :available }
+ let(:filter) { :directly_mapped }
let_it_be(:mapped_agent_in_org) do
project = create(:project, organization: organization, namespace: create(:group))
@@ -29,14 +29,6 @@
end
end
- let_it_be(:agent_in_org_with_remote_dev_disabled) do
- project = create(:project, organization: organization)
- create(:ee_cluster_agent, project: project, name: "agent-in-org-unavailable").tap do |agent|
- create(:workspaces_agent_config, agent: agent, enabled: false)
- create(:organization_cluster_agent_mapping, user: user, agent: agent, organization: organization)
- end
- end
-
describe '#execute' do
subject(:response) do
# noinspection RubyMismatchedArgumentType -- We are passing a test double
@@ -47,27 +39,9 @@
).to_a
end
- context 'with filter_type set to available' do
- context 'when cluster agents are mapped to the organization' do
- it 'returns cluster agents mapped to the organization excluding those with remote dev disabled' do
- expect(response).to eq([mapped_agent_in_org])
- end
- end
- end
-
context 'with filter_type set to directly_mapped' do
- let(:filter) { :directly_mapped }
-
it 'returns cluster agents that are mapped directly to the organization, including those disabled' do
- expect(response).to match_array([mapped_agent_in_org, agent_in_org_with_remote_dev_disabled])
- end
- end
-
- context 'with filter_type set to unmapped' do
- let(:filter) { :unmapped }
-
- it 'returns cluster agents that are unmapped to the organization' do
- expect(response).to eq([unmapped_agent_in_org])
+ expect(response).to match_array([mapped_agent_in_org])
end
end
@@ -79,6 +53,14 @@
end
end
+ context 'with filter_type set to all' do
+ let(:filter) { :all }
+
+ it "returns all cluster agents with remote development enabled within the organization" do
+ expect(response).to match_array([mapped_agent_in_org, unmapped_agent_in_org])
+ end
+ end
+
context 'with an invalid value for filter_type' do
let(:filter) { "some_invalid_value" }
diff --git a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/shared.rb b/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/shared.rb
index d72e5dbed48bf0db6a8a7b9690a0d4febdc91b55..53d25f75e4a356d773fe595863bd69684b3c613e 100644
--- a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/shared.rb
+++ b/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/shared.rb
@@ -16,7 +16,7 @@
let_it_be(:unauthorized_user) { create(:user) }
- let_it_be(:available_agent) do
+ let_it_be(:mapped_agent) do
project = create(:project, organization: organization, namespace: create(:group))
create(:ee_cluster_agent, project: project, name: "agent-in-org-available").tap do |agent|
create(:workspaces_agent_config, agent: agent)
@@ -24,14 +24,6 @@
end
end
- let_it_be(:directly_mapped_but_disabled_agent) do
- project = create(:project, organization: organization)
- create(:ee_cluster_agent, project: project, name: "agent-in-org-mapped").tap do |agent|
- create(:workspaces_agent_config, agent: agent, enabled: false)
- create(:organization_cluster_agent_mapping, user: authorized_user, agent: agent, organization: organization)
- end
- end
-
let_it_be(:unmapped_agent) do
project = create(:project, organization: organization)
create(:ee_cluster_agent, project: project, name: "agent-in-org-unmapped").tap do |agent|
@@ -109,15 +101,13 @@
end
# noinspection RubyArgCount -- Rubymine detecting wrong types, thinks some #create are from Minitest, not FactoryBot
- context "when the user is authorized only on mapped and available agents" do
+ context "when the user is authorized only on mapped agents" do
let_it_be(:current_user) do
create(:user).tap do |u|
create(:organization_user, organization: organization, user: u)
end
end
- let_it_be(:unavailable_and_unmapped_agents) { [unmapped_agent.name, directly_mapped_but_disabled_agent.name] }
-
it_behaves_like "query is a working graphql query"
context "when the user requests agents" do
@@ -126,7 +116,7 @@
end
it "does not include unmapped and unavailable agents", :unlimited_max_formatted_output_length do
- expect(agent_names.sort).not_to include(*unavailable_and_unmapped_agents)
+ expect(agent_names.sort).not_to include(unmapped_agent.name)
end
end
end
diff --git a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_available_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_all_filter_arg_spec.rb
similarity index 73%
rename from ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_available_filter_arg_spec.rb
rename to ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_all_filter_arg_spec.rb
index bf430daee066e2b21f5c78f14874662542f5b019..bae3dabe1cc3a1dd3ea0dfc28b47fc8e476a6e68 100644
--- a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_available_filter_arg_spec.rb
+++ b/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_all_filter_arg_spec.rb
@@ -3,9 +3,9 @@
require "spec_helper"
require_relative "./shared"
-RSpec.describe "Query.organization.workspaces_cluster_agents(filter: AVAILABLE)", feature_category: :workspaces do
- let(:filter) { :AVAILABLE }
- let(:expected_agents) { [available_agent] }
+RSpec.describe "Query.organization.workspaces_cluster_agents(filter: ALL)", feature_category: :workspaces do
+ let(:filter) { :ALL }
+ let(:expected_agents) { [mapped_agent, unmapped_agent] }
include_context "with agents and users setup in an organization"
include_context "for a Query.organization.workspaces_cluster_agents query"
diff --git a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb
index 4a7504fe7ba79ba29f2fd26ef366d6b39def3aa7..a0dafbd50d8f7656707453880dc16f2a29fa300e 100644
--- a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb
+++ b/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb
@@ -5,7 +5,7 @@
RSpec.describe "Query.organization.workspaces_cluster_agents (filter: DIRECTLY_MAPPED)", feature_category: :workspaces do
let(:filter) { :DIRECTLY_MAPPED }
- let(:expected_agents) { [directly_mapped_but_disabled_agent, available_agent] }
+ let(:expected_agents) { [mapped_agent] }
include_context "with agents and users setup in an organization"
include_context "for a Query.organization.workspaces_cluster_agents query"
diff --git a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb
deleted file mode 100644
index f87b0431a78d5c7ff030842361db7657813ce94c..0000000000000000000000000000000000000000
--- a/ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_relative './shared'
-
-RSpec.describe 'Query.organization.workspaces_cluster_agents (filter: UNMAPPED)', feature_category: :workspaces do
- let(:filter) { :UNMAPPED }
- let(:expected_agents) { [unmapped_agent] }
-
- include_context "with agents and users setup in an organization"
- include_context "for a Query.organization.workspaces_cluster_agents query"
-
- it_behaves_like "multiple agents in organization query"
-end
diff --git a/scripts/verify-tff-mapping b/scripts/verify-tff-mapping
index 76a741bd0ce7b6b5eee65a0dea0779289e357aa2..85615d94159cb4185524dde3329703f9ef131cbb 100755
--- a/scripts/verify-tff-mapping
+++ b/scripts/verify-tff-mapping
@@ -534,7 +534,7 @@ tests = [
changed_file: 'ee/app/graphql/resolvers/remote_development/organization/cluster_agents_resolver.rb',
# rubocop:disable Layout/LineLength -- fix CI failures - not sure why other lines in this file don't get errors
expected: %w[
- ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_available_filter_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_all_filter_arg_spec.rb
ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb
ee/spec/requests/api/graphql/remote_development/organization/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb
]