Expose agent ci access authorizations
NOTE: This MR is built on top of Namespace CiAccess Cluster Authorizations (!116894 - merged).
What does this MR do and why?
This MR exposes the persisted ci_access authorizations for Show shared agents in deployment projects (#395498 - closed).
A few notes:
- This GraphQL query is behind
expose_authorized_cluster_agentsfeature flag, which is disabled by default.
Screenshots or screen recordings
Query:
query {
project(fullPath: "root/agent-ci-test") {
name
ciAccessAuthorizedAgents {
nodes {
agent {
id
name
project {
name
}
}
config
}
}
}
}
Response:
{
"data": {
"project": {
"name": "agent-ci-test",
"ciAccessAuthorizedAgents": {
"nodes": [
{
"agent": {
"id": "gid://gitlab/Clusters::Agent/37",
"name": "production",
"project": {
"name": "agent-ci-test"
}
},
"config": {}
},
{
"agent": {
"id": "gid://gitlab/Clusters::Agent/43",
"name": "production",
"project": {
"name": "agent-ci-test-2"
}
},
"config": {}
}
]
}
}
}
}
Database Query for Clusters::Agent#ci_access_authorized_for?
SELECT
1 AS one
FROM
(
(
SELECT
"projects".*
FROM
"projects"
INNER JOIN "agent_project_authorizations" ON "agent_project_authorizations"."project_id" = "projects"."id"
INNER JOIN "project_authorizations" ON "project_authorizations"."project_id" = "projects"."id"
WHERE
"agent_project_authorizations"."agent_id" = 57145
AND "project_authorizations"."user_id" = 758045
AND "project_authorizations"."access_level" >= 30
LIMIT
1
)
UNION
(
WITH "root_namespace" AS MATERIALIZED (
SELECT
traversal_ids [1] AS root_id
FROM
"namespaces"
WHERE
(
traversal_ids @> ARRAY(
SELECT
"projects"."namespace_id"
FROM
"projects"
INNER JOIN "cluster_agents" ON "cluster_agents"."project_id" = "projects"."id"
WHERE
"cluster_agents"."id" = 57145
LIMIT
1
)
)
LIMIT
1
), "all_authorized_namespaces" AS MATERIALIZED (
SELECT
traversal_ids [array_length(traversal_ids, 1)] AS id
FROM
"namespaces"
INNER JOIN root_namespace ON namespaces.traversal_ids @> ARRAY [root_namespace.root_id]
INNER JOIN agent_group_authorizations ON namespaces.traversal_ids @> ARRAY [agent_group_authorizations.group_id::integer]
WHERE
"agent_group_authorizations"."agent_id" = 57145
)
SELECT
"projects".*
FROM
"projects"
INNER JOIN all_authorized_namespaces ON all_authorized_namespaces.id = projects.namespace_id
INNER JOIN "project_authorizations" ON "project_authorizations"."project_id" = "projects"."id"
WHERE
"project_authorizations"."user_id" = 758045
AND "project_authorizations"."access_level" >= 30
LIMIT
1
)
) projects
LIMIT
1
Query plans (fetched on postgres console)
Limit (cost=5947.00..5947.22 rows=1 width=4) (actual time=0.254..0.258 rows=1 loops=1)
-> Subquery Scan on projects (cost=5947.00..5947.43 rows=2 width=4) (actual time=0.253..0.257 rows=1 loops=1)
-> Unique (cost=5947.00..5947.41 rows=2 width=4292) (actual time=0.252..0.256 rows=1 loops=1)
-> Sort (cost=5947.00..5947.00 rows=2 width=4292) (actual time=0.251..0.255 rows=1 loops=1)
Sort Key: projects_1.id, projects_1.name, projects_1.path, projects_1.description, projects_1.created_at, projects_1.updated_at, projects_1.creator_id, projects_1.namespace_id, projects_1.la
st_activity_at, projects_1.import_url, projects_1.visibility_level, projects_1.archived, projects_1.merge_requests_template, projects_1.star_count, projects_1.merge_requests_rebase_enabled, projects_1.import_typ
e, projects_1.import_source, projects_1.avatar, projects_1.approvals_before_merge, projects_1.reset_approvals_on_push, projects_1.merge_requests_ff_only_enabled, projects_1.issues_template, projects_1.mirror, pr
ojects_1.mirror_last_update_at, projects_1.mirror_last_successful_update_at, projects_1.mirror_user_id, projects_1.shared_runners_enabled, projects_1.runners_token, projects_1.build_allow_git_fetch, projects_1.b
uild_timeout, projects_1.mirror_trigger_builds, projects_1.public_builds, projects_1.pending_delete, projects_1.last_repository_check_failed, projects_1.last_repository_check_at, projects_1.only_allow_merge_if_p
ipeline_succeeds, projects_1.has_external_issue_tracker, projects_1.repository_storage, projects_1.request_access_enabled, projects_1.has_external_wiki, projects_1.repository_read_only, projects_1.lfs_enabled, p
rojects_1.description_html, projects_1.only_allow_merge_if_all_discussions_are_resolved, projects_1.repository_size_limit, projects_1.service_desk_enabled, projects_1.printing_merge_request_link_enabled, project
s_1.auto_cancel_pending_pipelines, projects_1.cached_markdown_version, projects_1.last_repository_updated_at, projects_1.ci_config_path, projects_1.disable_overriding_approvers_per_merge_request, projects_1.dele
te_error, projects_1.storage_version, projects_1.resolve_outdated_diff_discussions, projects_1.remote_mirror_available_overridden, projects_1.only_mirror_protected_branches, projects_1.pull_mirror_available_over
ridden, projects_1.jobs_cache_index, projects_1.external_authorization_classification_label, projects_1.mirror_overwrites_diverged_branches, projects_1.external_webhook_token, projects_1.pages_https_only, projec
ts_1.packages_enabled, projects_1.merge_requests_author_approval, projects_1.pool_repository_id, projects_1.runners_token_encrypted, projects_1.bfg_object_map, projects_1.detected_repository_languages, projects_
1.merge_requests_disable_committers_approval, projects_1.require_password_to_approve, projects_1.emails_disabled, projects_1.max_pages_size, projects_1.max_artifacts_size, projects_1.pull_mirror_branch_prefix, p
rojects_1.remove_source_branch_after_merge, projects_1.marked_for_deletion_at, projects_1.marked_for_deletion_by_user_id, projects_1.suggestion_commit_message, projects_1.autoclose_referenced_issues, projects_1.
project_namespace_id, projects_1.hidden
Sort Method: quicksort Memory: 25kB
-> Append (cost=1.42..5946.99 rows=2 width=4292) (actual time=0.074..0.167 rows=1 loops=1)
-> Limit (cost=1.42..7.64 rows=1 width=736) (actual time=0.074..0.075 rows=1 loops=1)
-> Nested Loop (cost=1.42..7.64 rows=1 width=736) (actual time=0.073..0.074 rows=1 loops=1)
Join Filter: (agent_project_authorizations.project_id = project_authorizations.project_id)
-> Nested Loop (cost=0.84..6.88 rows=1 width=744) (actual time=0.049..0.050 rows=1 loops=1)
-> Index Only Scan using index_agent_project_authorizations_on_agent_id_and_project_id on agent_project_authorizations (cost=0.28..3.30 rows=1 width=8) (actual time=0.023..0.023 rows=1 loops=1)
Index Cond: (agent_id = 57145)
Heap Fetches: 1
-> Index Scan using idx_projects_on_repository_storage_last_repository_updated_at on projects projects_1 (cost=0.56..3.58 rows=1 width=736) (actual time=0.022..0.022 rows=1 loops=1)
Index Cond: (id = agent_project_authorizations.project_id)
-> Index Only Scan using project_authorizations_pkey on project_authorizations (cost=0.57..0.75 rows=1 width=4) (actual time=0.021..0.021 rows=1 loops=1)
Index Cond: ((user_id = 758045) AND (project_id = projects_1.id) AND (access_level >= 30))
Heap Fetches: 0
-> Limit (cost=2127.41..5939.32 rows=1 width=736) (actual time=0.088..0.091 rows=0 loops=1)
CTE root_namespace
-> Limit (cost=7.45..13.37 rows=1 width=4) (never executed)
InitPlan 1 (returns $1)
-> Limit (cost=0.85..6.89 rows=1 width=4) (never executed)
-> Nested Loop (cost=0.85..6.89 rows=1 width=4) (never executed)
-> Index Scan using cluster_agents_pkey on cluster_agents (cost=0.29..3.31 rows=1 width=8) (never executed)
Index Cond: (id = 57145)
-> Index Scan using idx_projects_on_repository_storage_last_repository_updated_at on projects projects_3 (cost=0.56..3.58 rows=1 width=8) (never executed)
Index Cond: (id = cluster_agents.project_id)
-> Index Only Scan using index_btree_namespaces_traversal_ids on namespaces (cost=0.56..1414283.29 rows=238708 width=4) (never executed)
Filter: (traversal_ids @> $1)
Heap Fetches: 0
CTE all_authorized_namespaces
-> Nested Loop (cost=129.52..2074.09 rows=1194 width=4) (actual time=0.016..0.017 rows=0 loops=1)
-> Index Only Scan using index_agent_group_authorizations_on_agent_id_and_group_id on agent_group_authorizations (cost=0.28..3.30 rows=1 width=8) (actual time=0.016..0.016 rows=0 loops=1)
Index Cond: (agent_id = 57145)
Heap Fetches: 0
-> Nested Loop (cost=129.24..2055.87 rows=1194 width=28) (never executed)
-> CTE Scan on root_namespace (cost=0.00..0.02 rows=1 width=4) (never executed)
-> Bitmap Heap Scan on namespaces namespaces_1 (cost=129.24..2043.91 rows=1194 width=28) (never executed)
Recheck Cond: ((traversal_ids @> ARRAY[root_namespace.root_id]) AND (traversal_ids @> ARRAY[(agent_group_authorizations.group_id)::integer]))
-> Bitmap Index Scan on index_namespaces_on_traversal_ids (cost=0.00..128.94 rows=1194 width=0) (never executed)
Index Cond: ((traversal_ids @> ARRAY[root_namespace.root_id]) AND (traversal_ids @> ARRAY[(agent_group_authorizations.group_id)::integer]))
-> Hash Join (cost=39.94..7663.77 rows=2 width=736) (actual time=0.088..0.089 rows=0 loops=1)
Hash Cond: (projects_2.namespace_id = all_authorized_namespaces.id)
-> Nested Loop (cost=1.14..7318.81 rows=2024 width=736) (actual time=0.052..0.052 rows=1 loops=1)
-> Index Only Scan using project_authorizations_pkey on project_authorizations project_authorizations_1 (cost=0.57..98.39 rows=2024 width=4) (actual time=0.028..0.028 rows=1 loops=1)
Index Cond: ((user_id = 758045) AND (access_level >= 30))
Heap Fetches: 0
-> Index Scan using projects_pkey on projects projects_2 (cost=0.56..3.57 rows=1 width=736) (actual time=0.022..0.022 rows=1 loops=1)
Index Cond: (id = project_authorizations_1.project_id)
-> Hash (cost=23.88..23.88 rows=1194 width=4) (actual time=0.017..0.017 rows=0 loops=1)
Buckets: 2048 Batches: 1 Memory Usage: 16kB
-> CTE Scan on all_authorized_namespaces (cost=0.00..23.88 rows=1194 width=4) (actual time=0.017..0.017 rows=0 loops=1)
Planning Time: 15.944 ms
Execution Time: 0.632 ms
(56 rows)
(NOTE: The created agent is relatively new thus it might not appear on Postgres.ai due to the replication delay)
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.
Edited by Shinya Maeda