From 94a1c8ca83a3fef22f9f6dd69bc5dd3cdd45b5e2 Mon Sep 17 00:00:00 2001 From: Mariia Solodovnik Date: Mon, 20 Mar 2023 17:40:01 +0200 Subject: [PATCH 1/6] Add geo_sites API endpoint Add new geo_sites API endpoint to supersede geo_nodes Changelog: added EE: true --- ee/lib/api/geo_sites.rb | 341 +++++++++++++++ ee/lib/ee/api/api.rb | 1 + ee/spec/requests/api/geo_sites_spec.rb | 552 +++++++++++++++++++++++++ 3 files changed, 894 insertions(+) create mode 100644 ee/lib/api/geo_sites.rb create mode 100644 ee/spec/requests/api/geo_sites_spec.rb diff --git a/ee/lib/api/geo_sites.rb b/ee/lib/api/geo_sites.rb new file mode 100644 index 00000000000000..8926f6e039f1c6 --- /dev/null +++ b/ee/lib/api/geo_sites.rb @@ -0,0 +1,341 @@ +# frozen_string_literal: true + +module API + class GeoSites < ::API::Base + include PaginationParams + include APIGuard + + feature_category :geo_replication + urgency :low + + before do + authenticate_admin_or_geo_node! + end + + helpers do + def authenticate_admin_or_geo_node! + if gitlab_geo_node_token? + bad_request! unless update_geo_sites_endpoint? + check_gitlab_geo_request_ip! + allow_paused_nodes! + authenticate_by_gitlab_geo_node_token! + else + authenticated_as_admin! + end + end + + def update_geo_sites_endpoint? + request.put? && request.path.match?(%r{/geo_sites/\d+}) + end + end + + resource :geo_sites do + # Example request: + # POST /geo_sites + desc 'Create a new Geo site' do + summary 'Creates a new Geo site' + success code: 200, model: EE::API::Entities::GeoNode + failure [ + { code: 400, message: 'Validation error' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' } + ] + tags %w[geo_sites] + end + params do + optional :primary, type: Boolean, desc: 'Specifying whether this site will be primary. Defaults to false.' + optional :enabled, type: Boolean, desc: 'Specifying whether this site will be enabled. Defaults to true.' + requires :name, type: String, + desc: 'The unique identifier for the Geo site. Must match `geo_node_name` if it is set in `gitlab.rb`, ' \ + 'otherwise it must match `external_url`' + requires :url, type: String, desc: 'The user-facing URL for the Geo site' + optional :internal_url, type: String, + desc: 'The URL defined on the primary site that secondary site should use to contact it. ' \ + 'Returns `url` if not set.' + optional :files_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of LFS/attachment backfill for this secondary site. Defaults to 10.' + optional :repos_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of repository backfill for this secondary site. Defaults to 25.' + optional :verification_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of repository verification for this site. Defaults to 100.' + optional :container_repositories_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of container repository sync for this site. Defaults to 10.' + optional :sync_object_storage, type: Boolean, + desc: 'Flag indicating if the secondary Geo site will replicate blobs in Object Storage. Defaults to false.' + optional :selective_sync_type, type: String, + desc: 'Limit syncing to only specific groups, or shards. Valid values: `"namespaces"`, `"shards"`, or `null`' + optional :selective_sync_shards, type: Array[String], + coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, + desc: 'The repository storages whose projects should be synced, if `selective_sync_type` == `shards`' + optional :selective_sync_namespace_ids, as: :namespace_ids, type: Array[Integer], + coerce_with: Validations::Types::CommaSeparatedToIntegerArray.coerce, + desc: 'The IDs of groups that should be synced, if `selective_sync_type` == `namespaces`' + optional :minimum_reverification_interval, type: Integer, + desc: 'The interval (in days) in which the repository verification is valid. Once expired, it ' \ + 'will be reverified. This has no effect when set on a secondary site.' + end + post do + create_params = declared_params(include_missing: false) + + new_geo_node = ::Geo::NodeCreateService.new(create_params).execute + + if new_geo_node.persisted? + present new_geo_node, with: EE::API::Entities::GeoNode + else + render_validation_error!(new_geo_node) + end + end + + # Example request: + # GET /geo_sites + desc 'Retrieves the available Geo sites' do + summary 'Retrieve configuration about all Geo sites' + success code: 200, model: EE::API::Entities::GeoNode + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' } + ] + is_array true + tags %w[geo_sites] + end + params do + use :pagination + end + + get do + nodes = GeoNode.all + + present paginate(nodes), with: EE::API::Entities::GeoNode + end + + # Example request: + # GET /geo_sites/status + desc 'Get status for all Geo sites' do + summary 'Get all Geo site statuses' + success code: 200, model: EE::API::Entities::GeoNodeStatus + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' } + ] + is_array true + tags %w[geo_sites] + end + params do + use :pagination + end + get '/status' do + status = GeoNodeStatus.all + + present paginate(status), with: EE::API::Entities::GeoNodeStatus + end + + # Example request: + # GET /geo_sites/current/failures + desc 'Get project sync or verification failures that occurred on the current site' do + summary 'Get project registry failures for the current Geo site' + success code: 200, model: ::GeoProjectRegistryEntity + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' }, + { code: 404, message: '404 Failure type unknown Not Found' } + ] + is_array true + tags %w[geo_sites] + end + params do + optional :type, type: String, values: %w[wiki repository], desc: 'Type of failure (repository/wiki)' + optional :failure_type, type: String, values: %w[sync checksum_mismatch verification], default: 'sync', + desc: 'Show verification failures' + use :pagination + end + get '/current/failures' do + not_found!('Geo site not found') unless Gitlab::Geo.current_node + forbidden!('Failures can only be requested from a secondary site') unless Gitlab::Geo.current_node.secondary? + + type = params[:type].to_s.to_sym + + project_registries = + case params[:failure_type] + when 'sync' + ::Geo::ProjectRegistry.sync_failed(type) + when 'verification' + ::Geo::ProjectRegistry.verification_failed(type) + when 'checksum_mismatch' + ::Geo::ProjectRegistry.mismatch(type) + else + not_found!('Failure type unknown') + end + + present paginate(project_registries), with: ::GeoProjectRegistryEntity + end + + route_param :id, type: Integer, desc: 'The ID of the site' do + helpers do + include ::Gitlab::Utils::StrongMemoize + + def geo_node + GeoNode.find(params[:id]) + end + strong_memoize_attr :geo_node + + def geo_node_status + status = GeoNodeStatus.fast_current_node_status if GeoNode.current?(geo_node) + status || geo_node.status + end + strong_memoize_attr :geo_node_status + end + + # Example request: + # GET /geo_sites/:id + desc 'Get a single GeoSite' do + summary 'Retrieve configuration about a specific Geo site' + success code: 200, model: EE::API::Entities::GeoNode + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' }, + { code: 404, message: '404 GeoSite Not Found' } + ] + tags %w[geo_sites] + end + get do + not_found!('GeoSite') unless geo_node + + present geo_node, with: EE::API::Entities::GeoNode + end + + # Example request: + # GET /geo_sites/:id/status + desc 'Get metrics for a single Geo site' do + summary 'Get Geo metrics for a single site' + success code: 200, model: EE::API::Entities::GeoNodeStatus + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' }, + { code: 404, message: '404 GeoSite Not Found' } + ] + tags %w[geo_sites] + end + params do + optional :refresh, type: Boolean, + desc: 'Attempt to fetch the latest status from the Geo site directly, ignoring the cache' + end + get 'status' do + not_found!('GeoSite') unless geo_node + + not_found!('Status for Geo site not found') unless geo_node_status + + present geo_node_status, with: EE::API::Entities::GeoNodeStatus + end + + # Example request: + # POST /geo_sites/:id/repair + desc 'Repair authentication of the Geo site' do + summary 'Repair authentication of the Geo site' + success code: 200, model: EE::API::Entities::GeoNodeStatus + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' }, + { code: 404, message: '404 GeoSite Not Found' } + ] + tags %w[geo_sites] + end + post 'repair' do + not_found!('GeoSite') unless geo_node + + if !geo_node.missing_oauth_application? || geo_node.repair + status 200 + present geo_node_status, with: EE::API::Entities::GeoNodeStatus + else + render_validation_error!(geo_node) + end + end + + # Example request: + # PUT /geo_sites/:id + desc 'Updates an existing Geo site' do + summary 'Edit a Geo site' + success code: 200, model: EE::API::Entities::GeoNode + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' }, + { code: 404, message: '404 GeoSite Not Found' } + ] + tags %w[geo_sites] + end + params do + optional :enabled, type: Boolean, desc: 'Flag indicating if the Geo site is enabled' + optional :name, type: String, + desc: 'The unique identifier for the Geo site. Must match `geo_node_name` if it is set in gitlab.rb, ' \ + 'otherwise it must match `external_url`' + optional :url, type: String, desc: 'The user-facing URL of the Geo site' + optional :internal_url, type: String, + desc: 'The URL defined on the primary site that secondary sites should use to contact it. ' \ + 'Returns `url` if not set.' + optional :files_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of LFS/attachment backfill for this secondary site' + optional :repos_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of repository backfill for this secondary site' + optional :verification_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of repository verification for this site' + optional :container_repositories_max_capacity, type: Integer, + desc: 'Control the maximum concurrency of container repository sync for this site' + optional :sync_object_storage, type: Boolean, + desc: 'Flag indicating if the secondary Geo site will replicate blobs in Object Storage' + optional :selective_sync_type, type: String, + desc: 'Limit syncing to only specific groups, or shards. Valid values: `"namespaces"`, `"shards"`, ' \ + 'or `null`' + optional :selective_sync_shards, type: Array[String], + coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, + desc: 'The repository storages whose projects should be synced, if `selective_sync_type` == `shards`' + optional :selective_sync_namespace_ids, as: :namespace_ids, type: Array[Integer], + coerce_with: Validations::Types::CommaSeparatedToIntegerArray.coerce, + desc: 'The IDs of groups that should be synced, if `selective_sync_type` == `namespaces`' + optional :minimum_reverification_interval, type: Integer, + desc: 'The interval (in days) in which the repository verification is valid. Once expired, it ' \ + 'will be reverified. This has no effect when set on a secondary node.' + end + put do + not_found!('GeoSite') unless geo_node + + update_params = declared_params(include_missing: false) + + updated_geo_node = ::Geo::NodeUpdateService.new(geo_node, update_params).execute + + if updated_geo_node + present geo_node, with: EE::API::Entities::GeoNode + else + render_validation_error!(geo_node) + end + end + + # Example request: + # DELETE /geo_sites/:id + desc 'Remove the Geo site' do + summary 'Delete a Geo site' + success code: 204, message: '204 No Content' + failure [ + { code: 400, message: '400 Bad request' }, + { code: 401, message: '401 Unauthorized' }, + { code: 403, message: '403 Forbidden' }, + { code: 404, message: '404 GeoSite Not Found' } + ] + tags %w[geo_sites] + end + delete do + not_found!('GeoSite') unless geo_node + + geo_node.destroy! + + no_content! + end + end + end + end +end diff --git a/ee/lib/ee/api/api.rb b/ee/lib/ee/api/api.rb index 4c7b8ecdb932f0..70fb986b0ad2df 100644 --- a/ee/lib/ee/api/api.rb +++ b/ee/lib/ee/api/api.rb @@ -26,6 +26,7 @@ module API mount ::API::Experiments mount ::API::GeoReplication mount ::API::GeoNodes + mount ::API::GeoSites mount ::API::Ldap mount ::API::LdapGroupLinks mount ::API::License diff --git a/ee/spec/requests/api/geo_sites_spec.rb b/ee/spec/requests/api/geo_sites_spec.rb new file mode 100644 index 00000000000000..770b91c0698277 --- /dev/null +++ b/ee/spec/requests/api/geo_sites_spec.rb @@ -0,0 +1,552 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::GeoSites, :request_store, :geo, :prometheus, api: true, feature_category: :geo_replication do + include ApiHelpers + include ::EE::GeoHelpers + + include_context 'custom session' + + let!(:admin) { create(:admin) } + let!(:user) { create(:user) } + let!(:primary) { create(:geo_node, :primary) } + let!(:secondary) { create(:geo_node) } + let!(:secondary_status) { create(:geo_node_status, :healthy, geo_node: secondary) } + let(:unexisting_site_id) { non_existing_record_id } + let(:group_to_sync) { create(:group) } + + describe 'POST /geo_sites' do + it 'denies access if not admin' do + post api('/geo_sites', user), params: {} + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'returns rendering error if params are missing' do + post api('/geo_sites', admin), params: {} + expect(response).to have_gitlab_http_status(:bad_request) + end + + it 'delegates the creation of the Geo site to Geo::NodeCreateService' do + geo_site_params = { + name: 'Test Site 1', + url: 'http://example.com', + selective_sync_type: "shards", + selective_sync_shards: %w[shard1 shard2], + selective_sync_namespace_ids: group_to_sync.id, + minimum_reverification_interval: 10 + } + expect_next_instance_of(Geo::NodeCreateService) do |instance| + expect(instance).to receive(:execute).once.and_call_original + end + post api('/geo_sites', admin), params: geo_site_params + expect(response).to have_gitlab_http_status(:created) + end + end + + describe 'GET /geo_sites' do + it 'retrieves the Geo sites if admin is logged in' do + get api("/geo_sites", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_nodes', dir: 'ee') + end + + it 'denies access if not admin' do + get api('/geo_sites', user) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + describe 'GET /geo_sites/:id' do + it 'retrieves the Geo sites if admin is logged in' do + get api("/geo_sites/#{primary.id}", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') + expect(json_response['web_edit_url']).to end_with("/admin/geo/sites/#{primary.id}/edit") + + links = json_response['_links'] + expect(links['self']).to end_with("/api/v4/geo_nodes/#{primary.id}") + expect(links['status']).to end_with("/api/v4/geo_nodes/#{primary.id}/status") + expect(links['repair']).to end_with("/api/v4/geo_nodes/#{primary.id}/repair") + end + + it_behaves_like '404 response' do + let(:request) { get api("/geo_sites/#{unexisting_site_id}", admin) } + end + + it 'denies access if not admin' do + get api('/geo_sites', user) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + describe 'GET /geo_sites/status' do + it 'retrieves all Geo sites statuses if admin is logged in' do + create(:geo_node_status, :healthy, geo_node: primary) + + get api("/geo_sites/status", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_statuses', dir: 'ee') + expect(json_response.size).to eq(2) + end + + it 'returns only one record if only one record exists' do + get api("/geo_sites/status", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_statuses', dir: 'ee') + expect(json_response.size).to eq(1) + end + + it 'denies access if not admin' do + get api('/geo_sites', user) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + describe 'GET /geo_sites/:id/status' do + it 'retrieves the Geo sites status if admin is logged in' do + stub_current_geo_node(primary) + secondary_status.update!(version: 'secondary-version', revision: 'secondary-revision') + + expect(GeoNodeStatus).not_to receive(:current_node_status) + + get api("/geo_sites/#{secondary.id}/status", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + + expect(json_response['version']).to eq('secondary-version') + expect(json_response['revision']).to eq('secondary-revision') + + links = json_response['_links'] + + expect(links['self']).to end_with("/api/v4/geo_nodes/#{secondary.id}/status") + expect(links['node']).to end_with("/api/v4/geo_nodes/#{secondary.id}") + end + + it 'fetches the current site status from redis' do + stub_current_geo_node(secondary) + + expect(GeoNodeStatus).to receive(:fast_current_node_status).and_return(secondary_status) + expect(GeoNode).to receive(:find).and_return(secondary) + + get api("/geo_sites/#{secondary.id}/status", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + end + + it 'shows the database-held response if current site status exists in the database, but not redis' do + stub_current_geo_node(secondary) + + expect(GeoNodeStatus).to receive(:fast_current_node_status).and_return(nil) + expect(GeoNode).to receive(:find).and_return(secondary) + + get api("/geo_sites/#{secondary.id}/status", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + end + + it 'the secondary shows 404 response if current site status does not exist in database or redis yet' do + stub_current_geo_node(secondary) + secondary_status.destroy! + + expect(GeoNodeStatus).to receive(:fast_current_node_status).and_return(nil) + expect(GeoNode).to receive(:find).and_return(secondary) + + get api("/geo_sites/#{secondary.id}/status", admin) + + expect(response).to have_gitlab_http_status(:not_found) + end + + it 'the primary shows 404 response if secondary site status does not exist in database yet' do + stub_current_geo_node(primary) + secondary_status.destroy! + + expect(GeoNode).to receive(:find).and_return(secondary) + + get api("/geo_sites/#{secondary.id}/status", admin) + + expect(response).to have_gitlab_http_status(:not_found) + end + + it_behaves_like '404 response' do + let(:request) { get api("/geo_sites/#{unexisting_site_id}/status", admin) } + end + + it 'denies access if not admin' do + get api("/geo_sites/#{secondary.id}/status", user) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + describe 'POST /geo_sites/:id/repair' do + it_behaves_like '404 response' do + let(:request) { post api("/geo_sites/#{unexisting_site_id}/status", admin) } + end + + it 'denies access if not admin' do + post api("/geo_sites/#{secondary.id}/repair", user) + + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'returns 200 for the primary site' do + stub_current_geo_node(primary) + create(:geo_node_status, :healthy, geo_node: primary) + + post api("/geo_sites/#{primary.id}/repair", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + end + + it 'returns 200 when site does not need repairing' do + allow_next_instance_of(GeoNode) do |instance| + allow(instance).to receive(:missing_oauth_application?).and_return(false) + end + + post api("/geo_sites/#{secondary.id}/repair", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + end + + it 'repairs a secondary with oauth application missing' do + allow_next_instance_of(GeoNode) do |instance| + allow(instance).to receive(:missing_oauth_application?).and_return(true) + end + + post api("/geo_sites/#{secondary.id}/repair", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + end + end + + describe 'PUT /geo_sites/:id' do + it_behaves_like '404 response' do + let(:request) { put api("/geo_sites/#{unexisting_site_id}", admin), params: {} } + end + + it 'denies access if not admin' do + put api("/geo_sites/#{secondary.id}", user), params: {} + + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'updates the parameters' do + params = { + enabled: false, + url: 'https://updated.example.com/', + internal_url: 'https://internal-com.com/', + files_max_capacity: 33, + repos_max_capacity: 44, + verification_max_capacity: 55, + selective_sync_type: "shards", + selective_sync_shards: %w[shard1 shard2], + selective_sync_namespace_ids: [group_to_sync.id], + minimum_reverification_interval: 10 + }.stringify_keys + + put api("/geo_sites/#{secondary.id}", admin), params: params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') + expect(json_response).to include(params) + end + + it 'can update primary' do + params = { + url: 'https://updated.example.com/' + }.stringify_keys + + put api("/geo_sites/#{primary.id}", admin), params: params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') + expect(json_response).to include(params) + end + + it 'cannot disable a primary' do + params = { + enabled: false + }.stringify_keys + + put api("/geo_sites/#{primary.id}", admin), params: params + + expect(response).to have_gitlab_http_status(:bad_request) + end + + context 'with auth with geo site token' do + let(:geo_base_request) { Gitlab::Geo::BaseRequest.new(scope: ::Gitlab::Geo::API_SCOPE) } + + before do + stub_current_geo_node(primary) + allow(geo_base_request).to receive(:requesting_node) { secondary } + end + + it 'enables the secondary site' do + secondary.update!(enabled: false) + + put api("/geo_sites/#{secondary.id}"), params: { enabled: true }, headers: geo_base_request.headers + + expect(response).to have_gitlab_http_status(:ok) + expect(secondary.reload).to be_enabled + end + + it 'disables the secondary site' do + secondary.update!(enabled: true) + + put api("/geo_sites/#{secondary.id}"), params: { enabled: false }, headers: geo_base_request.headers + + expect(response).to have_gitlab_http_status(:ok) + expect(secondary.reload).not_to be_enabled + end + + it 'returns bad request if you try to update the primary' do + put api("/geo_sites/#{primary.id}"), params: { enabled: false }, headers: geo_base_request.headers + + expect(response).to have_gitlab_http_status(:bad_request) + expect(primary.reload).to be_enabled + end + + it 'responds with 401 when IP is not allowed' do + stub_application_setting(geo_node_allowed_ips: '192.34.34.34') + + put api("/geo_sites/#{secondary.id}"), params: {}, headers: geo_base_request.headers + + expect(response).to have_gitlab_http_status(:unauthorized) + end + + it 'responds 401 if auth header is bad' do + allow_next_instance_of(Gitlab::Geo::JwtRequestDecoder) do |instance| + allow(instance).to receive(:decode).and_raise(Gitlab::Geo::InvalidDecryptionKeyError) + end + + put api("/geo_sites/#{secondary.id}"), params: {}, headers: geo_base_request.headers + + expect(response).to have_gitlab_http_status(:unauthorized) + end + end + end + + describe 'DELETE /geo_sites/:id' do + it_behaves_like '404 response' do + let(:request) { delete api("/geo_sites/#{unexisting_site_id}", admin) } + end + + it 'denies access if not admin' do + delete api("/geo_sites/#{secondary.id}", user) + + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'deletes the site' do + delete api("/geo_sites/#{secondary.id}", admin) + + expect(response).to have_gitlab_http_status(:no_content) + end + + it 'returns 500 if Geo Site could not be deleted' do + allow_any_instance_of(GeoNode).to receive(:destroy!).and_raise(StandardError, 'Something wrong') # rubocop:disable RSpec/AnyInstanceOf + + delete api("/geo_sites/#{secondary.id}", admin) + + expect(response).to have_gitlab_http_status(:internal_server_error) + end + end + + describe 'GET /geo_sites/current/failures' do + context 'when primary site' do + before do + stub_current_geo_node(primary) + end + + it 'forbids requests' do + get api("/geo_sites/current/failures", admin) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when secondary site' do + before do + stub_current_geo_node(secondary) + end + + it 'fetches the current site failures' do + create(:geo_project_registry, :sync_failed) + create(:geo_project_registry, :sync_failed) + + get api("/geo_sites/current/failures", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_project_registry', dir: 'ee') + end + + it 'does not show any registry when there is no failure' do + create(:geo_project_registry, :synced) + + get api("/geo_sites/current/failures", admin) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to be_zero + end + + context 'when wiki type' do + it 'only shows wiki failures' do + create(:geo_project_registry, :wiki_sync_failed) + create(:geo_project_registry, :repository_sync_failed) + + get api("/geo_sites/current/failures", admin), params: { type: :wiki } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to eq(1) + expect(json_response.first['wiki_retry_count']).to be > 0 + end + end + + context 'when repository type' do + it 'only shows repository failures' do + create(:geo_project_registry, :wiki_sync_failed) + create(:geo_project_registry, :repository_sync_failed) + + get api("/geo_sites/current/failures", admin), params: { type: :repository } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to eq(1) + expect(json_response.first['repository_retry_count']).to be > 0 + end + end + + context 'when nonexistent type' do + it 'returns a bad request' do + create(:geo_project_registry, :repository_sync_failed) + + get api("/geo_sites/current/failures", admin), params: { type: :nonexistent } + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + + it 'denies access if not admin' do + get api("/geo_sites/current/failures", user) + + expect(response).to have_gitlab_http_status(:forbidden) + end + + context 'when verification failures' do + before do + stub_current_geo_node(secondary) + end + + it 'fetches the current site checksum failures' do + create(:geo_project_registry, :repository_verification_failed) + create(:geo_project_registry, :wiki_verification_failed) + + get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification' } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_project_registry', dir: 'ee') + end + + it 'does not show any registry when there is no failure' do + create(:geo_project_registry, :repository_verified) + + get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification' } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to be_zero + end + + context 'when wiki type' do + it 'only shows wiki verification failures' do + create(:geo_project_registry, :repository_verification_failed) + create(:geo_project_registry, :wiki_verification_failed) + + get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification', type: :wiki } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to eq(1) + expect(json_response.first['last_wiki_verification_failure']).to be_present + end + end + + context 'when repository type' do + it 'only shows repository failures' do + create(:geo_project_registry, :repository_verification_failed) + create(:geo_project_registry, :wiki_verification_failed) + + get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification', type: :repository } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to eq(1) + expect(json_response.first['last_repository_verification_failure']).to be_present + end + end + end + + context 'when checksum mismatch failures' do + before do + stub_current_geo_node(secondary) + end + + it 'fetches the checksum mismatch failures from current site' do + create(:geo_project_registry, :repository_checksum_mismatch) + create(:geo_project_registry, :wiki_checksum_mismatch) + + get api("/geo_sites/current/failures", admin), params: { failure_type: 'checksum_mismatch' } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/geo_project_registry', dir: 'ee') + end + + it 'does not show any registry when there is no failure' do + create(:geo_project_registry, :repository_verified) + + get api("/geo_sites/current/failures", admin), params: { failure_type: 'checksum_mismatch' } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to be_zero + end + + context 'when wiki type' do + it 'only shows wiki checksum mismatch failures' do + create(:geo_project_registry, :repository_checksum_mismatch) + create(:geo_project_registry, :wiki_checksum_mismatch) + + get api("/geo_sites/current/failures", admin), params: { failure_type: 'checksum_mismatch', type: :wiki } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to eq(1) + expect(json_response.first['wiki_checksum_mismatch']).to be_truthy + end + end + + context 'when repository type' do + it 'only shows repository checksum mismatch failures' do + create(:geo_project_registry, :repository_checksum_mismatch) + create(:geo_project_registry, :wiki_checksum_mismatch) + + get api("/geo_sites/current/failures", admin), + params: { failure_type: 'checksum_mismatch', type: :repository } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.count).to eq(1) + expect(json_response.first['repository_checksum_mismatch']).to be_truthy + end + end + end + end + end +end -- GitLab From f53085d5304fe68ffdee116bc63c75e283e3d3c7 Mon Sep 17 00:00:00 2001 From: Mariia Solodovnik Date: Tue, 28 Mar 2023 19:15:13 +0300 Subject: [PATCH 2/6] Add missing tests for geo sites api --- ee/lib/api/geo_sites.rb | 2 - ee/spec/requests/api/geo_sites_spec.rb | 131 ++++++++++++++++--------- 2 files changed, 82 insertions(+), 51 deletions(-) diff --git a/ee/lib/api/geo_sites.rb b/ee/lib/api/geo_sites.rb index 8926f6e039f1c6..0380c252c1395b 100644 --- a/ee/lib/api/geo_sites.rb +++ b/ee/lib/api/geo_sites.rb @@ -165,8 +165,6 @@ def update_geo_sites_endpoint? ::Geo::ProjectRegistry.verification_failed(type) when 'checksum_mismatch' ::Geo::ProjectRegistry.mismatch(type) - else - not_found!('Failure type unknown') end present paginate(project_registries), with: ::GeoProjectRegistryEntity diff --git a/ee/spec/requests/api/geo_sites_spec.rb b/ee/spec/requests/api/geo_sites_spec.rb index 770b91c0698277..0edc876f1c422f 100644 --- a/ee/spec/requests/api/geo_sites_spec.rb +++ b/ee/spec/requests/api/geo_sites_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe API::GeoSites, :request_store, :geo, :prometheus, api: true, feature_category: :geo_replication do +RSpec.describe API::GeoSites, :aggregate_failures, :request_store, :geo, :prometheus, api: true, feature_category: :geo_replication do include ApiHelpers include ::EE::GeoHelpers @@ -16,6 +16,8 @@ let(:unexisting_site_id) { non_existing_record_id } let(:group_to_sync) { create(:group) } + # rubocop:disable RSpec/AnyInstanceOf + describe 'POST /geo_sites' do it 'denies access if not admin' do post api('/geo_sites', user), params: {} @@ -23,7 +25,7 @@ end it 'returns rendering error if params are missing' do - post api('/geo_sites', admin), params: {} + post api('/geo_sites', admin, admin_mode: true), params: {} expect(response).to have_gitlab_http_status(:bad_request) end @@ -39,14 +41,31 @@ expect_next_instance_of(Geo::NodeCreateService) do |instance| expect(instance).to receive(:execute).once.and_call_original end - post api('/geo_sites', admin), params: geo_site_params + post api('/geo_sites', admin, admin_mode: true), params: geo_site_params expect(response).to have_gitlab_http_status(:created) end + + it 'returns error if failed to create a geo node' do + geo_site_params = { + name: 'Test Site 1', + url: 'http://example.com', + primary: true, + enabled: false + } + + expect_next_instance_of(Geo::NodeCreateService) do |instance| + expect(instance).to receive(:execute).once.and_call_original + end + post api('/geo_sites', admin, admin_mode: true), params: geo_site_params + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to include({ 'message' => { 'enabled' => ['Geo primary node cannot be disabled'], + 'primary' => ['node already exists'] } }) + end end describe 'GET /geo_sites' do it 'retrieves the Geo sites if admin is logged in' do - get api("/geo_sites", admin) + get api("/geo_sites", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_nodes', dir: 'ee') @@ -61,7 +80,7 @@ describe 'GET /geo_sites/:id' do it 'retrieves the Geo sites if admin is logged in' do - get api("/geo_sites/#{primary.id}", admin) + get api("/geo_sites/#{primary.id}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') @@ -74,7 +93,7 @@ end it_behaves_like '404 response' do - let(:request) { get api("/geo_sites/#{unexisting_site_id}", admin) } + let(:request) { get api("/geo_sites/#{unexisting_site_id}", admin, admin_mode: true) } end it 'denies access if not admin' do @@ -88,7 +107,7 @@ it 'retrieves all Geo sites statuses if admin is logged in' do create(:geo_node_status, :healthy, geo_node: primary) - get api("/geo_sites/status", admin) + get api("/geo_sites/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_statuses', dir: 'ee') @@ -96,7 +115,7 @@ end it 'returns only one record if only one record exists' do - get api("/geo_sites/status", admin) + get api("/geo_sites/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_statuses', dir: 'ee') @@ -117,7 +136,7 @@ expect(GeoNodeStatus).not_to receive(:current_node_status) - get api("/geo_sites/#{secondary.id}/status", admin) + get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') @@ -137,7 +156,7 @@ expect(GeoNodeStatus).to receive(:fast_current_node_status).and_return(secondary_status) expect(GeoNode).to receive(:find).and_return(secondary) - get api("/geo_sites/#{secondary.id}/status", admin) + get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') @@ -149,7 +168,7 @@ expect(GeoNodeStatus).to receive(:fast_current_node_status).and_return(nil) expect(GeoNode).to receive(:find).and_return(secondary) - get api("/geo_sites/#{secondary.id}/status", admin) + get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') @@ -162,7 +181,7 @@ expect(GeoNodeStatus).to receive(:fast_current_node_status).and_return(nil) expect(GeoNode).to receive(:find).and_return(secondary) - get api("/geo_sites/#{secondary.id}/status", admin) + get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end @@ -173,13 +192,13 @@ expect(GeoNode).to receive(:find).and_return(secondary) - get api("/geo_sites/#{secondary.id}/status", admin) + get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end it_behaves_like '404 response' do - let(:request) { get api("/geo_sites/#{unexisting_site_id}/status", admin) } + let(:request) { get api("/geo_sites/#{unexisting_site_id}/status", admin, admin_mode: true) } end it 'denies access if not admin' do @@ -191,7 +210,7 @@ describe 'POST /geo_sites/:id/repair' do it_behaves_like '404 response' do - let(:request) { post api("/geo_sites/#{unexisting_site_id}/status", admin) } + let(:request) { post api("/geo_sites/#{unexisting_site_id}/status", admin, admin_mode: true) } end it 'denies access if not admin' do @@ -204,38 +223,48 @@ stub_current_geo_node(primary) create(:geo_node_status, :healthy, geo_node: primary) - post api("/geo_sites/#{primary.id}/repair", admin) + post api("/geo_sites/#{primary.id}/repair", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') end it 'returns 200 when site does not need repairing' do - allow_next_instance_of(GeoNode) do |instance| - allow(instance).to receive(:missing_oauth_application?).and_return(false) - end + allow_any_instance_of(GeoNode).to receive(:missing_oauth_application?).and_return(false) - post api("/geo_sites/#{secondary.id}/repair", admin) + post api("/geo_sites/#{secondary.id}/repair", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') end it 'repairs a secondary with oauth application missing' do - allow_next_instance_of(GeoNode) do |instance| - allow(instance).to receive(:missing_oauth_application?).and_return(true) - end + allow_any_instance_of(GeoNode).to receive(:missing_oauth_application?).and_return(true) - post api("/geo_sites/#{secondary.id}/repair", admin) + post api("/geo_sites/#{secondary.id}/repair", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') end + + context 'when geo site is invalid' do + before do + secondary.update_attribute(:name, '') + end + + it 'returns validation error' do + allow_any_instance_of(GeoNode).to receive(:missing_oauth_application?).and_return(true) + + post api("/geo_sites/#{secondary.id}/repair", admin, admin_mode: true) + + expect(response).to have_gitlab_http_status(:bad_request) + end + end end describe 'PUT /geo_sites/:id' do it_behaves_like '404 response' do - let(:request) { put api("/geo_sites/#{unexisting_site_id}", admin), params: {} } + let(:request) { put api("/geo_sites/#{unexisting_site_id}", admin, admin_mode: true), params: {} } end it 'denies access if not admin' do @@ -258,7 +287,7 @@ minimum_reverification_interval: 10 }.stringify_keys - put api("/geo_sites/#{secondary.id}", admin), params: params + put api("/geo_sites/#{secondary.id}", admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') @@ -270,7 +299,7 @@ url: 'https://updated.example.com/' }.stringify_keys - put api("/geo_sites/#{primary.id}", admin), params: params + put api("/geo_sites/#{primary.id}", admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') @@ -282,7 +311,7 @@ enabled: false }.stringify_keys - put api("/geo_sites/#{primary.id}", admin), params: params + put api("/geo_sites/#{primary.id}", admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:bad_request) end @@ -329,9 +358,8 @@ end it 'responds 401 if auth header is bad' do - allow_next_instance_of(Gitlab::Geo::JwtRequestDecoder) do |instance| - allow(instance).to receive(:decode).and_raise(Gitlab::Geo::InvalidDecryptionKeyError) - end + allow_any_instance_of(Gitlab::Geo::JwtRequestDecoder) + .to receive(:decode).and_raise(Gitlab::Geo::InvalidDecryptionKeyError) put api("/geo_sites/#{secondary.id}"), params: {}, headers: geo_base_request.headers @@ -342,7 +370,7 @@ describe 'DELETE /geo_sites/:id' do it_behaves_like '404 response' do - let(:request) { delete api("/geo_sites/#{unexisting_site_id}", admin) } + let(:request) { delete api("/geo_sites/#{unexisting_site_id}", admin, admin_mode: true) } end it 'denies access if not admin' do @@ -352,15 +380,15 @@ end it 'deletes the site' do - delete api("/geo_sites/#{secondary.id}", admin) + delete api("/geo_sites/#{secondary.id}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:no_content) end it 'returns 500 if Geo Site could not be deleted' do - allow_any_instance_of(GeoNode).to receive(:destroy!).and_raise(StandardError, 'Something wrong') # rubocop:disable RSpec/AnyInstanceOf + allow_any_instance_of(GeoNode).to receive(:destroy!).and_raise(StandardError, 'Something wrong') - delete api("/geo_sites/#{secondary.id}", admin) + delete api("/geo_sites/#{secondary.id}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:internal_server_error) end @@ -373,7 +401,7 @@ end it 'forbids requests' do - get api("/geo_sites/current/failures", admin) + get api("/geo_sites/current/failures", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:forbidden) end @@ -388,7 +416,7 @@ create(:geo_project_registry, :sync_failed) create(:geo_project_registry, :sync_failed) - get api("/geo_sites/current/failures", admin) + get api("/geo_sites/current/failures", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_project_registry', dir: 'ee') @@ -397,7 +425,7 @@ it 'does not show any registry when there is no failure' do create(:geo_project_registry, :synced) - get api("/geo_sites/current/failures", admin) + get api("/geo_sites/current/failures", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to be_zero @@ -408,7 +436,7 @@ create(:geo_project_registry, :wiki_sync_failed) create(:geo_project_registry, :repository_sync_failed) - get api("/geo_sites/current/failures", admin), params: { type: :wiki } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { type: :wiki } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to eq(1) @@ -421,7 +449,7 @@ create(:geo_project_registry, :wiki_sync_failed) create(:geo_project_registry, :repository_sync_failed) - get api("/geo_sites/current/failures", admin), params: { type: :repository } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { type: :repository } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to eq(1) @@ -433,7 +461,7 @@ it 'returns a bad request' do create(:geo_project_registry, :repository_sync_failed) - get api("/geo_sites/current/failures", admin), params: { type: :nonexistent } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { type: :nonexistent } expect(response).to have_gitlab_http_status(:bad_request) end @@ -454,7 +482,7 @@ create(:geo_project_registry, :repository_verification_failed) create(:geo_project_registry, :wiki_verification_failed) - get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification' } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { failure_type: 'verification' } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_project_registry', dir: 'ee') @@ -463,7 +491,7 @@ it 'does not show any registry when there is no failure' do create(:geo_project_registry, :repository_verified) - get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification' } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { failure_type: 'verification' } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to be_zero @@ -474,7 +502,8 @@ create(:geo_project_registry, :repository_verification_failed) create(:geo_project_registry, :wiki_verification_failed) - get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification', type: :wiki } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { failure_type: 'verification', + type: :wiki } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to eq(1) @@ -487,7 +516,8 @@ create(:geo_project_registry, :repository_verification_failed) create(:geo_project_registry, :wiki_verification_failed) - get api("/geo_sites/current/failures", admin), params: { failure_type: 'verification', type: :repository } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { failure_type: 'verification', + type: :repository } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to eq(1) @@ -505,7 +535,7 @@ create(:geo_project_registry, :repository_checksum_mismatch) create(:geo_project_registry, :wiki_checksum_mismatch) - get api("/geo_sites/current/failures", admin), params: { failure_type: 'checksum_mismatch' } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { failure_type: 'checksum_mismatch' } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/geo_project_registry', dir: 'ee') @@ -514,7 +544,7 @@ it 'does not show any registry when there is no failure' do create(:geo_project_registry, :repository_verified) - get api("/geo_sites/current/failures", admin), params: { failure_type: 'checksum_mismatch' } + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { failure_type: 'checksum_mismatch' } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to be_zero @@ -525,7 +555,8 @@ create(:geo_project_registry, :repository_checksum_mismatch) create(:geo_project_registry, :wiki_checksum_mismatch) - get api("/geo_sites/current/failures", admin), params: { failure_type: 'checksum_mismatch', type: :wiki } + get api("/geo_sites/current/failures", admin, admin_mode: true), + params: { failure_type: 'checksum_mismatch', type: :wiki } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to eq(1) @@ -538,7 +569,7 @@ create(:geo_project_registry, :repository_checksum_mismatch) create(:geo_project_registry, :wiki_checksum_mismatch) - get api("/geo_sites/current/failures", admin), + get api("/geo_sites/current/failures", admin, admin_mode: true), params: { failure_type: 'checksum_mismatch', type: :repository } expect(response).to have_gitlab_http_status(:ok) @@ -549,4 +580,6 @@ end end end + + # rubocop:enable RSpec/AnyInstanceOf end -- GitLab From a9cb920fc611a5f004a16184e34e6f65c3d5b93d Mon Sep 17 00:00:00 2001 From: Mariia Solodovnik Date: Tue, 4 Apr 2023 16:28:52 +0300 Subject: [PATCH 3/6] Use GeoSite entities for new endpoint Replace all GeoNode entities with GeoSite --- ee/lib/api/geo_sites.rb | 28 +++++++++++------------ ee/lib/ee/api/entities/geo_site.rb | 6 ++--- ee/lib/ee/api/entities/geo_site_status.rb | 4 ++-- ee/spec/requests/api/geo_sites_spec.rb | 10 ++++---- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ee/lib/api/geo_sites.rb b/ee/lib/api/geo_sites.rb index 0380c252c1395b..38e2b1749a26de 100644 --- a/ee/lib/api/geo_sites.rb +++ b/ee/lib/api/geo_sites.rb @@ -34,7 +34,7 @@ def update_geo_sites_endpoint? # POST /geo_sites desc 'Create a new Geo site' do summary 'Creates a new Geo site' - success code: 200, model: EE::API::Entities::GeoNode + success code: 200, model: EE::API::Entities::GeoSite failure [ { code: 400, message: 'Validation error' }, { code: 401, message: '401 Unauthorized' }, @@ -80,7 +80,7 @@ def update_geo_sites_endpoint? new_geo_node = ::Geo::NodeCreateService.new(create_params).execute if new_geo_node.persisted? - present new_geo_node, with: EE::API::Entities::GeoNode + present new_geo_node, with: EE::API::Entities::GeoSite else render_validation_error!(new_geo_node) end @@ -90,7 +90,7 @@ def update_geo_sites_endpoint? # GET /geo_sites desc 'Retrieves the available Geo sites' do summary 'Retrieve configuration about all Geo sites' - success code: 200, model: EE::API::Entities::GeoNode + success code: 200, model: EE::API::Entities::GeoSite failure [ { code: 400, message: '400 Bad request' }, { code: 401, message: '401 Unauthorized' }, @@ -106,14 +106,14 @@ def update_geo_sites_endpoint? get do nodes = GeoNode.all - present paginate(nodes), with: EE::API::Entities::GeoNode + present paginate(nodes), with: EE::API::Entities::GeoSite end # Example request: # GET /geo_sites/status desc 'Get status for all Geo sites' do summary 'Get all Geo site statuses' - success code: 200, model: EE::API::Entities::GeoNodeStatus + success code: 200, model: EE::API::Entities::GeoSiteStatus failure [ { code: 400, message: '400 Bad request' }, { code: 401, message: '401 Unauthorized' }, @@ -128,7 +128,7 @@ def update_geo_sites_endpoint? get '/status' do status = GeoNodeStatus.all - present paginate(status), with: EE::API::Entities::GeoNodeStatus + present paginate(status), with: EE::API::Entities::GeoSiteStatus end # Example request: @@ -190,7 +190,7 @@ def geo_node_status # GET /geo_sites/:id desc 'Get a single GeoSite' do summary 'Retrieve configuration about a specific Geo site' - success code: 200, model: EE::API::Entities::GeoNode + success code: 200, model: EE::API::Entities::GeoSite failure [ { code: 400, message: '400 Bad request' }, { code: 401, message: '401 Unauthorized' }, @@ -202,14 +202,14 @@ def geo_node_status get do not_found!('GeoSite') unless geo_node - present geo_node, with: EE::API::Entities::GeoNode + present geo_node, with: EE::API::Entities::GeoSite end # Example request: # GET /geo_sites/:id/status desc 'Get metrics for a single Geo site' do summary 'Get Geo metrics for a single site' - success code: 200, model: EE::API::Entities::GeoNodeStatus + success code: 200, model: EE::API::Entities::GeoSiteStatus failure [ { code: 400, message: '400 Bad request' }, { code: 401, message: '401 Unauthorized' }, @@ -227,14 +227,14 @@ def geo_node_status not_found!('Status for Geo site not found') unless geo_node_status - present geo_node_status, with: EE::API::Entities::GeoNodeStatus + present geo_node_status, with: EE::API::Entities::GeoSiteStatus end # Example request: # POST /geo_sites/:id/repair desc 'Repair authentication of the Geo site' do summary 'Repair authentication of the Geo site' - success code: 200, model: EE::API::Entities::GeoNodeStatus + success code: 200, model: EE::API::Entities::GeoSiteStatus failure [ { code: 400, message: '400 Bad request' }, { code: 401, message: '401 Unauthorized' }, @@ -248,7 +248,7 @@ def geo_node_status if !geo_node.missing_oauth_application? || geo_node.repair status 200 - present geo_node_status, with: EE::API::Entities::GeoNodeStatus + present geo_node_status, with: EE::API::Entities::GeoSiteStatus else render_validation_error!(geo_node) end @@ -258,7 +258,7 @@ def geo_node_status # PUT /geo_sites/:id desc 'Updates an existing Geo site' do summary 'Edit a Geo site' - success code: 200, model: EE::API::Entities::GeoNode + success code: 200, model: EE::API::Entities::GeoSite failure [ { code: 400, message: '400 Bad request' }, { code: 401, message: '401 Unauthorized' }, @@ -307,7 +307,7 @@ def geo_node_status updated_geo_node = ::Geo::NodeUpdateService.new(geo_node, update_params).execute if updated_geo_node - present geo_node, with: EE::API::Entities::GeoNode + present geo_node, with: EE::API::Entities::GeoSite else render_validation_error!(geo_node) end diff --git a/ee/lib/ee/api/entities/geo_site.rb b/ee/lib/ee/api/entities/geo_site.rb index bc760a075e27c3..5bddf7a7cd1f69 100644 --- a/ee/lib/ee/api/entities/geo_site.rb +++ b/ee/lib/ee/api/entities/geo_site.rb @@ -40,15 +40,15 @@ class GeoSite < Grape::Entity expose :_links do expose :self do |geo_node| - expose_url api_v4_geo_nodes_path(id: geo_node.id) + expose_url api_v4_geo_sites_path(id: geo_node.id) end expose :status do |geo_node| - expose_url api_v4_geo_nodes_status_path(id: geo_node.id) + expose_url api_v4_geo_sites_status_path(id: geo_node.id) end expose :repair do |geo_node| - expose_url api_v4_geo_nodes_repair_path(id: geo_node.id) + expose_url api_v4_geo_sites_repair_path(id: geo_node.id) end end diff --git a/ee/lib/ee/api/entities/geo_site_status.rb b/ee/lib/ee/api/entities/geo_site_status.rb index 5314c266bf48fa..14c4d686eea218 100644 --- a/ee/lib/ee/api/entities/geo_site_status.rb +++ b/ee/lib/ee/api/entities/geo_site_status.rb @@ -78,11 +78,11 @@ class GeoSiteStatus < Grape::Entity expose :_links do expose :self do |geo_node_status| - expose_url api_v4_geo_nodes_status_path(id: geo_node_status.geo_node_id) + expose_url api_v4_geo_sites_status_path(id: geo_node_status.geo_node_id) end expose :node do |geo_node_status| - expose_url api_v4_geo_nodes_path(id: geo_node_status.geo_node_id) + expose_url api_v4_geo_sites_path(id: geo_node_status.geo_node_id) end end diff --git a/ee/spec/requests/api/geo_sites_spec.rb b/ee/spec/requests/api/geo_sites_spec.rb index 0edc876f1c422f..b15ed1d8d20e69 100644 --- a/ee/spec/requests/api/geo_sites_spec.rb +++ b/ee/spec/requests/api/geo_sites_spec.rb @@ -87,9 +87,9 @@ expect(json_response['web_edit_url']).to end_with("/admin/geo/sites/#{primary.id}/edit") links = json_response['_links'] - expect(links['self']).to end_with("/api/v4/geo_nodes/#{primary.id}") - expect(links['status']).to end_with("/api/v4/geo_nodes/#{primary.id}/status") - expect(links['repair']).to end_with("/api/v4/geo_nodes/#{primary.id}/repair") + expect(links['self']).to end_with("/api/v4/geo_sites/#{primary.id}") + expect(links['status']).to end_with("/api/v4/geo_sites/#{primary.id}/status") + expect(links['repair']).to end_with("/api/v4/geo_sites/#{primary.id}/repair") end it_behaves_like '404 response' do @@ -146,8 +146,8 @@ links = json_response['_links'] - expect(links['self']).to end_with("/api/v4/geo_nodes/#{secondary.id}/status") - expect(links['node']).to end_with("/api/v4/geo_nodes/#{secondary.id}") + expect(links['self']).to end_with("/api/v4/geo_sites/#{secondary.id}/status") + expect(links['node']).to end_with("/api/v4/geo_sites/#{secondary.id}") end it 'fetches the current site status from redis' do -- GitLab From 1aedf7e31762c0c21a78eed3f582432550f15a86 Mon Sep 17 00:00:00 2001 From: Mariia Solodovnik Date: Thu, 20 Apr 2023 18:23:51 +0300 Subject: [PATCH 4/6] Update geo_sites links in the spec --- ee/spec/lib/ee/api/entities/geo_site_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ee/spec/lib/ee/api/entities/geo_site_spec.rb b/ee/spec/lib/ee/api/entities/geo_site_spec.rb index 7374a65928959c..70c742e6c291c7 100644 --- a/ee/spec/lib/ee/api/entities/geo_site_spec.rb +++ b/ee/spec/lib/ee/api/entities/geo_site_spec.rb @@ -24,15 +24,15 @@ end describe '#self' do - it { expect(subject[:_links][:self]).to eq expose_url(api_v4_geo_nodes_path(id: geo_node.id)) } + it { expect(subject[:_links][:self]).to eq expose_url(api_v4_geo_sites_path(id: geo_node.id)) } end describe '#status' do - it { expect(subject[:_links][:status]).to eq expose_url(api_v4_geo_nodes_status_path(id: geo_node.id)) } + it { expect(subject[:_links][:status]).to eq expose_url(api_v4_geo_sites_status_path(id: geo_node.id)) } end describe '#repair' do - it { expect(subject[:_links][:repair]).to eq expose_url(api_v4_geo_nodes_repair_path(id: geo_node.id)) } + it { expect(subject[:_links][:repair]).to eq expose_url(api_v4_geo_sites_repair_path(id: geo_node.id)) } end describe '#current' do -- GitLab From 41c37102c4ec76405532fd5bc8239020c2e6fdda Mon Sep 17 00:00:00 2001 From: Mariia Solodovnik Date: Tue, 25 Apr 2023 23:43:36 +0300 Subject: [PATCH 5/6] Update geo_node references to geo_sites Rename geo_nodes to geo_sites to make futher refactoring easier --- ee/lib/api/geo_sites.rb | 62 +++++++++++------------ ee/lib/ee/api/entities/geo_site.rb | 30 +++++------ ee/lib/ee/api/entities/geo_site_status.rb | 16 +++--- ee/spec/requests/api/geo_sites_spec.rb | 2 +- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/ee/lib/api/geo_sites.rb b/ee/lib/api/geo_sites.rb index 38e2b1749a26de..45d7135cae23d9 100644 --- a/ee/lib/api/geo_sites.rb +++ b/ee/lib/api/geo_sites.rb @@ -9,11 +9,11 @@ class GeoSites < ::API::Base urgency :low before do - authenticate_admin_or_geo_node! + authenticate_admin_or_geo_site! end helpers do - def authenticate_admin_or_geo_node! + def authenticate_admin_or_geo_site! if gitlab_geo_node_token? bad_request! unless update_geo_sites_endpoint? check_gitlab_geo_request_ip! @@ -77,12 +77,12 @@ def update_geo_sites_endpoint? post do create_params = declared_params(include_missing: false) - new_geo_node = ::Geo::NodeCreateService.new(create_params).execute + new_geo_site = ::Geo::NodeCreateService.new(create_params).execute - if new_geo_node.persisted? - present new_geo_node, with: EE::API::Entities::GeoSite + if new_geo_site.persisted? + present new_geo_site, with: EE::API::Entities::GeoSite else - render_validation_error!(new_geo_node) + render_validation_error!(new_geo_site) end end @@ -104,9 +104,9 @@ def update_geo_sites_endpoint? end get do - nodes = GeoNode.all + sites = GeoNode.all - present paginate(nodes), with: EE::API::Entities::GeoSite + present paginate(sites), with: EE::API::Entities::GeoSite end # Example request: @@ -174,16 +174,16 @@ def update_geo_sites_endpoint? helpers do include ::Gitlab::Utils::StrongMemoize - def geo_node + def geo_site GeoNode.find(params[:id]) end - strong_memoize_attr :geo_node + strong_memoize_attr :geo_site - def geo_node_status - status = GeoNodeStatus.fast_current_node_status if GeoNode.current?(geo_node) - status || geo_node.status + def geo_site_status + status = GeoNodeStatus.fast_current_node_status if GeoNode.current?(geo_site) + status || geo_site.status end - strong_memoize_attr :geo_node_status + strong_memoize_attr :geo_site_status end # Example request: @@ -200,9 +200,9 @@ def geo_node_status tags %w[geo_sites] end get do - not_found!('GeoSite') unless geo_node + not_found!('GeoSite') unless geo_site - present geo_node, with: EE::API::Entities::GeoSite + present geo_site, with: EE::API::Entities::GeoSite end # Example request: @@ -223,11 +223,11 @@ def geo_node_status desc: 'Attempt to fetch the latest status from the Geo site directly, ignoring the cache' end get 'status' do - not_found!('GeoSite') unless geo_node + not_found!('GeoSite') unless geo_site - not_found!('Status for Geo site not found') unless geo_node_status + not_found!('Status for Geo site not found') unless geo_site_status - present geo_node_status, with: EE::API::Entities::GeoSiteStatus + present geo_site_status, with: EE::API::Entities::GeoSiteStatus end # Example request: @@ -244,13 +244,13 @@ def geo_node_status tags %w[geo_sites] end post 'repair' do - not_found!('GeoSite') unless geo_node + not_found!('GeoSite') unless geo_site - if !geo_node.missing_oauth_application? || geo_node.repair + if !geo_site.missing_oauth_application? || geo_site.repair status 200 - present geo_node_status, with: EE::API::Entities::GeoSiteStatus + present geo_site_status, with: EE::API::Entities::GeoSiteStatus else - render_validation_error!(geo_node) + render_validation_error!(geo_site) end end @@ -297,19 +297,19 @@ def geo_node_status desc: 'The IDs of groups that should be synced, if `selective_sync_type` == `namespaces`' optional :minimum_reverification_interval, type: Integer, desc: 'The interval (in days) in which the repository verification is valid. Once expired, it ' \ - 'will be reverified. This has no effect when set on a secondary node.' + 'will be reverified. This has no effect when set on a secondary site.' end put do - not_found!('GeoSite') unless geo_node + not_found!('GeoSite') unless geo_site update_params = declared_params(include_missing: false) - updated_geo_node = ::Geo::NodeUpdateService.new(geo_node, update_params).execute + updated_geo_site = ::Geo::NodeUpdateService.new(geo_site, update_params).execute - if updated_geo_node - present geo_node, with: EE::API::Entities::GeoSite + if updated_geo_site + present geo_site, with: EE::API::Entities::GeoSite else - render_validation_error!(geo_node) + render_validation_error!(geo_site) end end @@ -327,9 +327,9 @@ def geo_node_status tags %w[geo_sites] end delete do - not_found!('GeoSite') unless geo_node + not_found!('GeoSite') unless geo_site - geo_node.destroy! + geo_site.destroy! no_content! end diff --git a/ee/lib/ee/api/entities/geo_site.rb b/ee/lib/ee/api/entities/geo_site.rb index 5bddf7a7cd1f69..39acaca46e830b 100644 --- a/ee/lib/ee/api/entities/geo_site.rb +++ b/ee/lib/ee/api/entities/geo_site.rb @@ -20,40 +20,40 @@ class GeoSite < Grape::Entity expose :selective_sync_shards expose :namespace_ids, as: :selective_sync_namespace_ids expose :minimum_reverification_interval - expose :sync_object_storage, if: ->(geo_node, _) { geo_node.secondary? } + expose :sync_object_storage, if: ->(geo_site, _) { geo_site.secondary? } # Retained for backwards compatibility. Remove in API v5 expose :clone_protocol do |_record, _options| 'http' end - expose :web_edit_url do |geo_node| - ::Gitlab::Routing.url_helpers.edit_admin_geo_node_url(geo_node) + expose :web_edit_url do |geo_site| + ::Gitlab::Routing.url_helpers.edit_admin_geo_node_url(geo_site) end # @deprecated in favor of web_geo_replication_details_url - expose :web_geo_projects_url, if: ->(geo_node) { geo_node.secondary? }, - proc: ->(geo_node) { geo_node.geo_projects_url } + expose :web_geo_projects_url, if: ->(geo_site) { geo_site.secondary? }, + proc: ->(geo_site) { geo_site.geo_projects_url } - expose :web_geo_replication_details_url, if: ->(geo_node) { geo_node.secondary? }, - proc: ->(geo_node) { geo_node.geo_replication_details_url } + expose :web_geo_replication_details_url, if: ->(geo_site) { geo_site.secondary? }, + proc: ->(geo_site) { geo_site.geo_replication_details_url } expose :_links do - expose :self do |geo_node| - expose_url api_v4_geo_sites_path(id: geo_node.id) + expose :self do |geo_site| + expose_url api_v4_geo_sites_path(id: geo_site.id) end - expose :status do |geo_node| - expose_url api_v4_geo_sites_status_path(id: geo_node.id) + expose :status do |geo_site| + expose_url api_v4_geo_sites_status_path(id: geo_site.id) end - expose :repair do |geo_node| - expose_url api_v4_geo_sites_repair_path(id: geo_node.id) + expose :repair do |geo_site| + expose_url api_v4_geo_sites_repair_path(id: geo_site.id) end end - expose :current do |geo_node| - ::GeoNode.current?(geo_node) + expose :current do |geo_site| + ::GeoNode.current?(geo_site) end end end diff --git a/ee/lib/ee/api/entities/geo_site_status.rb b/ee/lib/ee/api/entities/geo_site_status.rb index 14c4d686eea218..73d7759061f002 100644 --- a/ee/lib/ee/api/entities/geo_site_status.rb +++ b/ee/lib/ee/api/entities/geo_site_status.rb @@ -14,8 +14,8 @@ class GeoSiteStatus < Grape::Entity end ::GeoNodeStatus.percentage_methods.each do |method_name| - expose method_name do |node| - number_to_percentage(node[method_name], precision: 2) + expose method_name do |site| + number_to_percentage(site[method_name], precision: 2) end end @@ -27,8 +27,8 @@ class GeoSiteStatus < Grape::Entity expose :replication_slots_used_count expose :healthy?, as: :healthy - expose :health do |node| - node.healthy? ? 'Healthy' : node.health + expose :health do |site| + site.healthy? ? 'Healthy' : site.health end expose :health_status expose :missing_oauth_application @@ -77,12 +77,12 @@ class GeoSiteStatus < Grape::Entity expose :storage_shards_match?, as: :storage_shards_match expose :_links do - expose :self do |geo_node_status| - expose_url api_v4_geo_sites_status_path(id: geo_node_status.geo_node_id) + expose :self do |geo_site_status| + expose_url api_v4_geo_sites_status_path(id: geo_site_status.geo_node_id) end - expose :node do |geo_node_status| - expose_url api_v4_geo_sites_path(id: geo_node_status.geo_node_id) + expose :node do |geo_site_status| + expose_url api_v4_geo_sites_path(id: geo_site_status.geo_node_id) end end diff --git a/ee/spec/requests/api/geo_sites_spec.rb b/ee/spec/requests/api/geo_sites_spec.rb index b15ed1d8d20e69..5e55ede692b6f4 100644 --- a/ee/spec/requests/api/geo_sites_spec.rb +++ b/ee/spec/requests/api/geo_sites_spec.rb @@ -45,7 +45,7 @@ expect(response).to have_gitlab_http_status(:created) end - it 'returns error if failed to create a geo node' do + it 'returns error if failed to create a geo site' do geo_site_params = { name: 'Test Site 1', url: 'http://example.com', -- GitLab From 833c228df457f84aa905c46e0c8d6e96789864c2 Mon Sep 17 00:00:00 2001 From: Mariia Solodovnik Date: Wed, 26 Apr 2023 10:33:44 +0300 Subject: [PATCH 6/6] Use geo_sites schemas for spec, update node to site in API response --- ee/lib/ee/api/entities/geo_site_status.rb | 2 +- ee/spec/requests/api/geo_sites_spec.rb | 26 +++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ee/lib/ee/api/entities/geo_site_status.rb b/ee/lib/ee/api/entities/geo_site_status.rb index 73d7759061f002..f79962ff209288 100644 --- a/ee/lib/ee/api/entities/geo_site_status.rb +++ b/ee/lib/ee/api/entities/geo_site_status.rb @@ -81,7 +81,7 @@ class GeoSiteStatus < Grape::Entity expose_url api_v4_geo_sites_status_path(id: geo_site_status.geo_node_id) end - expose :node do |geo_site_status| + expose :site do |geo_site_status| expose_url api_v4_geo_sites_path(id: geo_site_status.geo_node_id) end end diff --git a/ee/spec/requests/api/geo_sites_spec.rb b/ee/spec/requests/api/geo_sites_spec.rb index 5e55ede692b6f4..58bcf87db7afc7 100644 --- a/ee/spec/requests/api/geo_sites_spec.rb +++ b/ee/spec/requests/api/geo_sites_spec.rb @@ -68,7 +68,7 @@ get api("/geo_sites", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_nodes', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_sites', dir: 'ee') end it 'denies access if not admin' do @@ -83,7 +83,7 @@ get api("/geo_sites/#{primary.id}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site', dir: 'ee') expect(json_response['web_edit_url']).to end_with("/admin/geo/sites/#{primary.id}/edit") links = json_response['_links'] @@ -110,7 +110,7 @@ get api("/geo_sites/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_statuses', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_statuses', dir: 'ee') expect(json_response.size).to eq(2) end @@ -118,7 +118,7 @@ get api("/geo_sites/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_statuses', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_statuses', dir: 'ee') expect(json_response.size).to eq(1) end @@ -139,7 +139,7 @@ get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_status', dir: 'ee') expect(json_response['version']).to eq('secondary-version') expect(json_response['revision']).to eq('secondary-revision') @@ -147,7 +147,7 @@ links = json_response['_links'] expect(links['self']).to end_with("/api/v4/geo_sites/#{secondary.id}/status") - expect(links['node']).to end_with("/api/v4/geo_sites/#{secondary.id}") + expect(links['site']).to end_with("/api/v4/geo_sites/#{secondary.id}") end it 'fetches the current site status from redis' do @@ -159,7 +159,7 @@ get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_status', dir: 'ee') end it 'shows the database-held response if current site status exists in the database, but not redis' do @@ -171,7 +171,7 @@ get api("/geo_sites/#{secondary.id}/status", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_status', dir: 'ee') end it 'the secondary shows 404 response if current site status does not exist in database or redis yet' do @@ -226,7 +226,7 @@ post api("/geo_sites/#{primary.id}/repair", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_status', dir: 'ee') end it 'returns 200 when site does not need repairing' do @@ -235,7 +235,7 @@ post api("/geo_sites/#{secondary.id}/repair", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_status', dir: 'ee') end it 'repairs a secondary with oauth application missing' do @@ -244,7 +244,7 @@ post api("/geo_sites/#{secondary.id}/repair", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node_status', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site_status', dir: 'ee') end context 'when geo site is invalid' do @@ -290,7 +290,7 @@ put api("/geo_sites/#{secondary.id}", admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site', dir: 'ee') expect(json_response).to include(params) end @@ -302,7 +302,7 @@ put api("/geo_sites/#{primary.id}", admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('public_api/v4/geo_node', dir: 'ee') + expect(response).to match_response_schema('public_api/v4/geo_site', dir: 'ee') expect(json_response).to include(params) end -- GitLab