Skip to content
Snippets Groups Projects
Commit e02b5398 authored by Michael Kozono's avatar Michael Kozono :two:
Browse files

Merge branch...

Merge branch '364725-geo-replicables-support-resync-and-reverify-actions-for-individual-replicable-via-graphql' into 'master'

Geo Support Resync/Reverify for registries via GraphQL

See merge request gitlab-org/gitlab!114673



Merged-by: Michael Kozono's avatarMichael Kozono <mkozono@gitlab.com>
Approved-by: default avatarAchilleas Pipinellis <axil@gitlab.com>
Approved-by: default avatarPedro Pombeiro <noreply@pedro.pombei.ro>
Approved-by: Michael Kozono's avatarMichael Kozono <mkozono@gitlab.com>
Reviewed-by: Michael Kozono's avatarMichael Kozono <mkozono@gitlab.com>
Reviewed-by: default avatarPedro Pombeiro <noreply@pedro.pombei.ro>
Co-authored-by: default avatarJaviera Tapia <jtapia@gitlab.com>
parents 37a726af 85b243fb
No related branches found
No related tags found
3 merge requests!122597doc/gitaly: Remove references to removed metrics,!120936Draft: Debugging commit to trigger pipeline (DO NOT MERGE),!114673Geo Support Resync/Reverify for registries via GraphQL
Pipeline #868281511 passed with warnings
Pipeline: E2E Omnibus GitLab EE

#868293351

    Pipeline: GitLab

    #868293346

      Pipeline: E2E GDK

      #868282866

        Showing
        with 282 additions and 1 deletion
        ......@@ -89,6 +89,22 @@
        "NugetMetadata",
        "PypiMetadata"
        ],
        "Registrable": [
        "CiSecureFileRegistry",
        "ContainerRepositoryRegistry",
        "DependencyProxyBlobRegistry",
        "DependencyProxyManifestRegistry",
        "JobArtifactRegistry",
        "LfsObjectRegistry",
        "MergeRequestDiffRegistry",
        "PackageFileRegistry",
        "PagesDeploymentRegistry",
        "PipelineArtifactRegistry",
        "ProjectWikiRepositoryRegistry",
        "SnippetRepositoryRegistry",
        "TerraformStateVersionRegistry",
        "UploadRegistry"
        ],
        "ResolvableInterface": [
        "Discussion",
        "Note"
        ......
        ......@@ -28,7 +28,7 @@ def errors_on_object(record)
        end
        def ready?(**args)
        raise_resource_not_available_error! ERROR_MESSAGE if Gitlab::Database.read_only?
        raise_resource_not_available_error!(ERROR_MESSAGE) if read_only?
        missing_args = self.class.arguments.values
        .reject { |arg| arg.accepts?(args.fetch(arg.keyword, :not_given)) }
        ......@@ -39,6 +39,10 @@ def ready?(**args)
        true
        end
        def read_only?
        Gitlab::Database.read_only?
        end
        def load_application_object(argument, id, context)
        ::Gitlab::Graphql::Lazy.new { super }
        end
        ......
        ......@@ -3406,6 +3406,33 @@ Input type: `ExternalAuditEventDestinationUpdateInput`
        | <a id="mutationexternalauditeventdestinationupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
        | <a id="mutationexternalauditeventdestinationupdateexternalauditeventdestination"></a>`externalAuditEventDestination` | [`ExternalAuditEventDestination`](#externalauditeventdestination) | Updated destination. |
         
        ### `Mutation.geoRegistriesUpdate`
        Mutates a Geo registry. Does not mutate the registry entry if `geo_registries_update_mutation` feature flag is disabled.
        WARNING:
        **Introduced** in 16.1.
        This feature is an Experiment. It can be changed or removed at any time.
        Input type: `GeoRegistriesUpdateInput`
        #### Arguments
        | Name | Type | Description |
        | ---- | ---- | ----------- |
        | <a id="mutationgeoregistriesupdateaction"></a>`action` | [`GeoRegistryAction!`](#georegistryaction) | Action to be executed on a Geo registry. |
        | <a id="mutationgeoregistriesupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
        | <a id="mutationgeoregistriesupdateregistryclass"></a>`registryClass` | [`GeoRegistryClass!`](#georegistryclass) | Class of the Geo registry to be updated. |
        | <a id="mutationgeoregistriesupdateregistryid"></a>`registryId` | [`GeoBaseRegistryID!`](#geobaseregistryid) | ID of the Geo registry entry to be updated. |
        #### Fields
        | Name | Type | Description |
        | ---- | ---- | ----------- |
        | <a id="mutationgeoregistriesupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
        | <a id="mutationgeoregistriesupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
        | <a id="mutationgeoregistriesupdateregistry"></a>`registry` | [`Registrable`](#registrable) | Updated Geo registry entry. |
        ### `Mutation.gitlabSubscriptionActivate`
         
        Input type: `GitlabSubscriptionActivateInput`
        ......@@ -24391,6 +24418,36 @@ Event action.
        | <a id="eventactionreopened"></a>`REOPENED` | Reopened action. |
        | <a id="eventactionupdated"></a>`UPDATED` | Updated action. |
         
        ### `GeoRegistryAction`
        Action to trigger on one or more Geo registries.
        | Value | Description |
        | ----- | ----------- |
        | <a id="georegistryactionresync"></a>`RESYNC` | Resync a registry. |
        | <a id="georegistryactionreverify"></a>`REVERIFY` | Reverify a registry. |
        ### `GeoRegistryClass`
        Geo registry class.
        | Value | Description |
        | ----- | ----------- |
        | <a id="georegistryclassci_secure_file_registry"></a>`CI_SECURE_FILE_REGISTRY` | Geo::CiSecureFileRegistry registry class. |
        | <a id="georegistryclasscontainer_repository_registry"></a>`CONTAINER_REPOSITORY_REGISTRY` | Geo::ContainerRepositoryRegistry registry class. |
        | <a id="georegistryclassdependency_proxy_blob_registry"></a>`DEPENDENCY_PROXY_BLOB_REGISTRY` | Geo::DependencyProxyBlobRegistry registry class. |
        | <a id="georegistryclassdependency_proxy_manifest_registry"></a>`DEPENDENCY_PROXY_MANIFEST_REGISTRY` | Geo::DependencyProxyManifestRegistry registry class. |
        | <a id="georegistryclassjob_artifact_registry"></a>`JOB_ARTIFACT_REGISTRY` | Geo::JobArtifactRegistry registry class. |
        | <a id="georegistryclasslfs_object_registry"></a>`LFS_OBJECT_REGISTRY` | Geo::LfsObjectRegistry registry class. |
        | <a id="georegistryclassmerge_request_diff_registry"></a>`MERGE_REQUEST_DIFF_REGISTRY` | Geo::MergeRequestDiffRegistry registry class. |
        | <a id="georegistryclasspackage_file_registry"></a>`PACKAGE_FILE_REGISTRY` | Geo::PackageFileRegistry registry class. |
        | <a id="georegistryclasspages_deployment_registry"></a>`PAGES_DEPLOYMENT_REGISTRY` | Geo::PagesDeploymentRegistry registry class. |
        | <a id="georegistryclasspipeline_artifact_registry"></a>`PIPELINE_ARTIFACT_REGISTRY` | Geo::PipelineArtifactRegistry registry class. |
        | <a id="georegistryclassproject_wiki_repository_registry"></a>`PROJECT_WIKI_REPOSITORY_REGISTRY` | Geo::ProjectWikiRepositoryRegistry registry class. |
        | <a id="georegistryclasssnippet_repository_registry"></a>`SNIPPET_REPOSITORY_REGISTRY` | Geo::SnippetRepositoryRegistry registry class. |
        | <a id="georegistryclassterraform_state_version_registry"></a>`TERRAFORM_STATE_VERSION_REGISTRY` | Geo::TerraformStateVersionRegistry registry class. |
        | <a id="georegistryclassupload_registry"></a>`UPLOAD_REGISTRY` | Geo::UploadRegistry registry class. |
        ### `GitlabSubscriptionsUserRole`
         
        Role of User.
        ......@@ -26154,6 +26211,12 @@ An example `EpicTreeSortingID` is: `"gid://gitlab/EpicTreeSorting/1"`.
         
        Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
         
        ### `GeoBaseRegistryID`
        A `GeoBaseRegistryID` is a global ID. It is encoded as a string.
        An example `GeoBaseRegistryID` is: `"gid://gitlab/Geo::BaseRegistry/1"`.
        ### `GitlabErrorTrackingDetailedErrorID`
         
        A `GitlabErrorTrackingDetailedErrorID` is a global ID. It is encoded as a string.
        ......@@ -26605,6 +26668,25 @@ One of:
        - [`NugetMetadata`](#nugetmetadata)
        - [`PypiMetadata`](#pypimetadata)
         
        #### `Registrable`
        One of:
        - [`CiSecureFileRegistry`](#cisecurefileregistry)
        - [`ContainerRepositoryRegistry`](#containerrepositoryregistry)
        - [`DependencyProxyBlobRegistry`](#dependencyproxyblobregistry)
        - [`DependencyProxyManifestRegistry`](#dependencyproxymanifestregistry)
        - [`JobArtifactRegistry`](#jobartifactregistry)
        - [`LfsObjectRegistry`](#lfsobjectregistry)
        - [`MergeRequestDiffRegistry`](#mergerequestdiffregistry)
        - [`PackageFileRegistry`](#packagefileregistry)
        - [`PagesDeploymentRegistry`](#pagesdeploymentregistry)
        - [`PipelineArtifactRegistry`](#pipelineartifactregistry)
        - [`ProjectWikiRepositoryRegistry`](#projectwikirepositoryregistry)
        - [`SnippetRepositoryRegistry`](#snippetrepositoryregistry)
        - [`TerraformStateVersionRegistry`](#terraformstateversionregistry)
        - [`UploadRegistry`](#uploadregistry)
        #### `SecurityPolicySource`
         
        Represents a policy source. Its fields depend on the source type.
        ......@@ -20,6 +20,7 @@ module MutationType
        mount_mutation ::Mutations::Epics::Create
        mount_mutation ::Mutations::Epics::SetSubscription
        mount_mutation ::Mutations::Epics::AddIssue
        mount_mutation ::Mutations::Geo::Registries::Update, alpha: { milestone: '16.1' }
        mount_mutation ::Mutations::GitlabSubscriptions::Activate
        mount_mutation ::Mutations::Projects::SetLocked
        mount_mutation ::Mutations::Iterations::Create
        ......
        # frozen_string_literal: true
        module Mutations
        module Geo
        module Registries
        # For a single update, this mutation expects an `registry_id` argument.
        # A registry_class argument must be included.
        class Update < BaseMutation
        graphql_name 'GeoRegistriesUpdate'
        description 'Mutates a Geo registry. Does not mutate the registry entry if ' \
        '`geo_registries_update_mutation` feature flag is disabled.'
        extend ::Gitlab::Utils::Override
        authorize :read_geo_registry
        argument :registry_class,
        ::Types::Geo::RegistryClassEnum,
        required: true,
        description: 'Class of the Geo registry to be updated.'
        argument :registry_id,
        Types::GlobalIDType[::Geo::BaseRegistry],
        required: true,
        description: 'ID of the Geo registry entry to be updated.'
        argument :action,
        ::Types::Geo::RegistryActionEnum,
        required: true,
        description: 'Action to be executed on a Geo registry.'
        field :registry, ::Types::Geo::RegistrableType, null: true, description: 'Updated Geo registry entry.'
        def resolve(action:, registry_id:, registry_class:)
        if Feature.disabled?(:geo_registries_update_mutation)
        raise Gitlab::Graphql::Errors::ResourceNotAvailable,
        '`geo_registries_update_mutation` feature flag is disabled.'
        end
        registry = authorized_find!(registry_id)
        result = ::Geo::RegistryUpdateService.new(action, registry_class, registry).execute
        { registry: result.payload[:registry], errors: result.errors }
        end
        override :read_only?
        def read_only?
        ::Gitlab.maintenance_mode?
        end
        private
        def find_object(id)
        GitlabSchema.find_by_gid(id)
        end
        end
        end
        end
        end
        ......@@ -11,5 +11,6 @@ class CiSecureFileRegistryType < BaseObject
        field :ci_secure_file_id, GraphQL::Types::ID, null: false, description: 'ID of the Ci Secure File.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class GroupWikiRepositoryRegistryType < BaseObject
        field :group_wiki_repository_id, GraphQL::Types::ID, null: false, description: 'ID of the Group Wiki Repository.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class JobArtifactRegistryType < BaseObject
        field :artifact_id, GraphQL::Types::ID, null: false, description: 'ID of the Job Artifact.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class MergeRequestDiffRegistryType < BaseObject
        field :merge_request_diff_id, GraphQL::Types::ID, null: false, description: 'ID of the Merge Request diff.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class PackageFileRegistryType < BaseObject
        field :package_file_id, GraphQL::Types::ID, null: false, description: 'ID of the PackageFile.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class PagesDeploymentRegistryType < BaseObject
        field :pages_deployment_id, GraphQL::Types::ID, null: false, description: 'ID of the Pages Deployment.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class PipelineArtifactRegistryType < BaseObject
        field :pipeline_artifact_id, GraphQL::Types::ID, null: false, description: 'ID of the pipeline artifact.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        # frozen_string_literal: true
        module Types
        module Geo
        class RegistrableType < BaseUnion
        RegistryTypeNotSupportedError = Class.new(StandardError)
        # Add new Geo registries here to use them as part of the RegistrableType union
        # registry class => registry type
        GEO_REGISTRY_TYPES = {
        ::Geo::CiSecureFileRegistry => Types::Geo::CiSecureFileRegistryType,
        ::Geo::ContainerRepositoryRegistry => Types::Geo::ContainerRepositoryRegistryType,
        ::Geo::DependencyProxyBlobRegistry => Types::Geo::DependencyProxyBlobRegistryType,
        ::Geo::DependencyProxyManifestRegistry => Types::Geo::DependencyProxyManifestRegistryType,
        ::Geo::JobArtifactRegistry => Types::Geo::JobArtifactRegistryType,
        ::Geo::LfsObjectRegistry => Types::Geo::LfsObjectRegistryType,
        ::Geo::MergeRequestDiffRegistry => Types::Geo::MergeRequestDiffRegistryType,
        ::Geo::PackageFileRegistry => Types::Geo::PackageFileRegistryType,
        ::Geo::PagesDeploymentRegistry => Types::Geo::PagesDeploymentRegistryType,
        ::Geo::PipelineArtifactRegistry => Types::Geo::PipelineArtifactRegistryType,
        ::Geo::ProjectWikiRepositoryRegistry => Types::Geo::ProjectWikiRepositoryRegistryType,
        ::Geo::SnippetRepositoryRegistry => Types::Geo::SnippetRepositoryRegistryType,
        ::Geo::TerraformStateVersionRegistry => Types::Geo::TerraformStateVersionRegistryType,
        ::Geo::UploadRegistry => Types::Geo::UploadRegistryType
        }.freeze
        possible_types(*GEO_REGISTRY_TYPES.values)
        def self.resolve_type(object, _)
        registry_type = GEO_REGISTRY_TYPES[object.class]
        raise RegistryTypeNotSupportedError unless registry_type
        registry_type
        end
        end
        end
        end
        # frozen_string_literal: true
        module Types
        module Geo
        class RegistryActionEnum < BaseEnum
        graphql_name 'GeoRegistryAction'
        description 'Action to trigger on one or more Geo registries'
        value 'REVERIFY', value: :reverify, description: 'Reverify a registry.'
        value 'RESYNC', value: :resync, description: 'Resync a registry.'
        end
        end
        end
        # frozen_string_literal: true
        module Types
        module Geo
        class RegistryClassEnum < BaseEnum
        graphql_name 'GeoRegistryClass'
        description 'Geo registry class'
        # Example format:
        # value "MERGE_REQUEST_DIFF_REGISTRY",
        # value: "Geo::MergeRequestDiffRegistry",
        # description: "Geo::MergeRequestDiffRegistry registry class"
        ::Geo::Secondary::RegistryConsistencyWorker::REGISTRY_CLASSES.each do |registry_class|
        next unless registry_class.graphql_mutable?
        value registry_class.to_s.gsub('Geo::', '').underscore.upcase,
        value: registry_class.to_s,
        description: "#{registry_class} registry class"
        end
        end
        end
        end
        ......@@ -11,5 +11,6 @@ class SnippetRepositoryRegistryType < BaseObject
        field :snippet_repository_id, GraphQL::Types::ID, null: false, description: 'ID of the Snippet Repository.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class TerraformStateVersionRegistryType < BaseObject
        field :terraform_state_version_id, GraphQL::Types::ID, null: false, description: 'ID of the terraform state version.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -11,5 +11,6 @@ class UploadRegistryType < BaseObject
        field :file_id, GraphQL::Types::ID, null: false, description: 'ID of the Upload.'
        end
        # rubocop:enable Graphql/AuthorizeTypes
        end
        end
        ......@@ -65,11 +65,34 @@ def handle_after_create_commit
        # Called by Gitlab::Geo::Replicator#consume
        def consume_event_created(**params)
        resync
        end
        def resync
        return unless in_replicables_for_current_secondary?
        # Race condition mitigation for mutable types.
        #
        # Within a created event, we know that the source primary has changed. If a
        # sync is currently running, then *this* sync will be deduplicated (exit
        # early due to not being able to take the exclusive lease). In that case,
        # moving the registry to "pending" will block the currently running sync
        # from moving it to "synced". The running sync will then reschedule
        # itself to ensure a sync begins *after* the last known change to the
        # source primary. See `ReplicableRegistry#mark_synced_atomically`.
        #
        # We avoid saving when unpersisted since this should only occur if a
        # resource was just created but not yet replicated. And all saves after
        # the first one will raise the error `ActiveRecord::RecordNotUnique` anyway.
        registry.pending! if registry.persisted? && mutable?
        download
        end
        def enqueue_sync
        Geo::EventWorker.perform_async(replicable_name, 'created', { model_record_id: model_record.id })
        end
        # Called by Gitlab::Geo::Replicator#consume
        # Keep in mind that in_replicables_for_current_secondary? is not called here
        # This is because delete event should be handled by all the nodes
        ......@@ -159,5 +182,9 @@ def immutable?
        # Override this in your specific Replicator class if needed.
        true
        end
        def mutable?
        !immutable?
        end
        end
        end
        ......@@ -34,6 +34,10 @@ def housekeeping_enabled?
        # Called by Gitlab::Geo::Replicator#consume
        def consume_event_updated(**params)
        resync
        end
        def resync
        return unless in_replicables_for_current_secondary?
        # Race condition mitigation for mutable types.
        ......@@ -75,6 +79,10 @@ def sync_repository
        Geo::FrameworkRepositorySyncService.new(self).execute
        end
        def enqueue_sync
        reschedule_sync
        end
        def reschedule_sync
        Geo::EventWorker.perform_async(replicable_name, 'updated', { model_record_id: model_record.id })
        end
        ......
        0% Loading or .
        You are about to add 0 people to the discussion. Proceed with caution.
        Finish editing this message first!
        Please register or to comment