Domain verification should initiate Enterprise Users Automatic Claim
What does this MR do and why?
Related to #388415 (closed)
This MR initiates Enterprise Users Automatic Claim for successful domain verification and re-verification.
This change is under enterprise_users_automatic_claim
FF.
See #388415 (closed) description for details and for "why?".
How to set up and validate locally
-
Familiarize with the Enterprise User definition to understand what context you should prepare in your GitLab instance for testing
-
Enable
enterprise_users_automatic_claim
FF. Guide: https://docs.gitlab.com/ee/administration/feature_flags.html#enable-or-disable-the-feature -
Make sure the GitLab instance simulates or a SaaS instance since Enterprise Users is a SaaS feature
-
Create a top-level paid group with Premium subscription as a minimum
-
Create a few users on the GitLab instance with emails that have a domain that you can verify
-
Verify the domain for the group, docs: https://docs.gitlab.com/ee/user/enterprise_user/#set-up-a-verified-domain
-
Confirm that
Groups::EnterpriseUsers::BulkAssociateByDomainWorker
has been scheduled and completed after successful domain verification -
Confirm that this worker scheduled
Groups::EnterpriseUsers::AssociateWorker
for all users with email domain that is equal to the verified domain. Confirm their execution is complete -
Confirm that those users have received user_associated_with_enterprise_group_email
-
Additionally, you can check logs.
'Associated the user with the enterprise group'
log entries should be added with the context data, likeuser_id
andgroup_id
-
You can also check from the rails console
User.find_by(email: 'EMAIL-HERE').user_detail.enterprise_group_id
attribute. Its value should be the same as the group's id -
Go to the domain and manually retry verification: https://docs.gitlab.com/ee/user/project/pages/custom_domains_ssl_tls_certification/#4-verify-the-domains-ownership
-
Confirm that
Groups::EnterpriseUsers::BulkAssociateByDomainWorker
has been scheduled and completed after successful domain verification -
Confirm that this worker didn't schedule
Groups::EnterpriseUsers::AssociateWorker
for users from previous steps since they had been marked as enterprise users of the group.
Since the Enterprise User definition consists of lots of items, we could reproduce lots of cases. You can read the specs https://gitlab.com/gitlab-org/gitlab/-/blob/af58ea0f4110b277120e8c45cbcc59d70c8a5ed9/ee/spec/services/groups/enterprise_users/associate_service_spec.rb (and ee/spec/workers/groups/enterprise_users/bulk_associate_by_domain_worker_spec.rb
in this MR) for detail.
DB
Migration
bin/rails db:migrate
bogdanvlviv@lenovo:~/gitlab-development-kit/gitlab$ bin/rails db:migrate RAILS_ENV=test
main: == [advisory_lock_connection] object_id: 221860, pg_backend_pid: 27819
main: == 20231009105056 IndexUsersOnEmailDomainAndId: migrating =====================
main: -- transaction_open?(nil)
main: -> 0.0000s
main: -- view_exists?(:postgres_partitions)
main: -> 0.0143s
main: -- index_exists?(:users, "LOWER(SPLIT_PART(email, '@', 2)), id", {:name=>"index_users_on_email_domain_and_id", :algorithm=>:concurrently})
main: -> 0.0124s
main: -- execute("SET statement_timeout TO 0")
main: -> 0.0005s
main: -- add_index(:users, "LOWER(SPLIT_PART(email, '@', 2)), id", {:name=>"index_users_on_email_domain_and_id", :algorithm=>:concurrently})
main: -> 0.0026s
main: -- execute("RESET statement_timeout")
main: -> 0.0006s
main: == 20231009105056 IndexUsersOnEmailDomainAndId: migrated (0.0468s) ============
main: == [advisory_lock_connection] object_id: 221860, pg_backend_pid: 27819
ci: == [advisory_lock_connection] object_id: 222080, pg_backend_pid: 27821
ci: == 20231009105056 IndexUsersOnEmailDomainAndId: migrating =====================
ci: -- transaction_open?(nil)
ci: -> 0.0000s
ci: -- view_exists?(:postgres_partitions)
ci: -> 0.0009s
ci: -- index_exists?(:users, "LOWER(SPLIT_PART(email, '@', 2)), id", {:name=>"index_users_on_email_domain_and_id", :algorithm=>:concurrently})
ci: -> 0.0136s
ci: -- execute("SET statement_timeout TO 0")
ci: -> 0.0007s
ci: -- add_index(:users, "LOWER(SPLIT_PART(email, '@', 2)), id", {:name=>"index_users_on_email_domain_and_id", :algorithm=>:concurrently})
ci: -> 0.0024s
ci: -- execute("RESET statement_timeout")
ci: -> 0.0005s
ci: == 20231009105056 IndexUsersOnEmailDomainAndId: migrated (0.0343s) ============
ci: == [advisory_lock_connection] object_id: 222080, pg_backend_pid: 27821
bin/rails db:rollback
bogdanvlviv@lenovo:~/gitlab-development-kit/gitlab$ bin/rails db:rollback:main RAILS_ENV=test
main: == [advisory_lock_connection] object_id: 221440, pg_backend_pid: 28194
main: == 20231009105056 IndexUsersOnEmailDomainAndId: reverting =====================
main: -- transaction_open?(nil)
main: -> 0.0000s
main: -- view_exists?(:postgres_partitions)
main: -> 0.0146s
main: -- indexes(:users)
main: -> 0.0120s
main: -- execute("SET statement_timeout TO 0")
main: -> 0.0005s
main: -- remove_index(:users, {:algorithm=>:concurrently, :name=>"index_users_on_email_domain_and_id"})
main: -> 0.0019s
main: -- execute("RESET statement_timeout")
main: -> 0.0006s
main: == 20231009105056 IndexUsersOnEmailDomainAndId: reverted (0.0446s) ============
main: == [advisory_lock_connection] object_id: 221440, pg_backend_pid: 28194
bogdanvlviv@lenovo:~/gitlab-development-kit/gitlab$ bin/rails db:rollback:ci RAILS_ENV=test
ci: == [advisory_lock_connection] object_id: 221360, pg_backend_pid: 28542
ci: == 20231009105056 IndexUsersOnEmailDomainAndId: reverting =====================
ci: -- transaction_open?(nil)
ci: -> 0.0000s
ci: -- view_exists?(:postgres_partitions)
ci: -> 0.0598s
ci: -- indexes(:users)
ci: -> 0.0578s
ci: -- execute("SET statement_timeout TO 0")
ci: -> 0.0034s
ci: -- remove_index(:users, {:algorithm=>:concurrently, :name=>"index_users_on_email_domain_and_id"})
ci: -> 0.0042s
ci: -- execute("RESET statement_timeout")
ci: -> 0.0031s
ci: == 20231009105056 IndexUsersOnEmailDomainAndId: reverted (0.1787s) ============
ci: == [advisory_lock_connection] object_id: 221360, pg_backend_pid: 28542
Query Plans
⚠ NOTE: The query plans's results might not be accurate since it used somewhat random users' ids because I have no access to see Postgres.ai instance data to figure out which ids to use.
⚠ UPDATE ON THIS NOTE: The query plans use appropriate id ranges now as per suggestion !133218 (comment 1596375599)
index_users_on_email_domain_and_id
index
Create CREATE INDEX index_users_on_email_domain_and_id ON users USING btree (lower(split_part((email)::text, '@'::text, 2)), id);
each_batch
finds the lowest id
for the query
SELECT "users"."id" FROM "users" WHERE (lower(split_part(email, '@', 2)) = 'gitlab.com') ORDER BY "users"."id" ASC LIMIT 1;
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/22998/commands/74087
each_batch
finds the next id
for the query based on the batch size configuration - 100.
SELECT "users"."id" FROM "users" WHERE (lower(split_part(email, '@', 2)) = 'gitlab.com') AND "users"."id" >= 1 ORDER BY "users"."id" ASC LIMIT 1 OFFSET 100;
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/22998/commands/74088
each_batch
query with the id
range for the batch
SELECT "users"."id" FROM "users" LEFT OUTER JOIN "user_details" ON "user_details"."user_id" = "users"."id" WHERE (lower(split_part(email, '@', 2)) = 'gitlab.com') AND "users"."id" >= 1 AND "users"."id" < 480804 AND (user_details.enterprise_group_id != 187 OR user_details.enterprise_group_id IS NULL);
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/22998/commands/74090
each_batch
query with the id
range for the last batch
SELECT "users"."id" FROM "users" LEFT OUTER JOIN "user_details" ON "user_details"."user_id" = "users"."id" WHERE (lower(split_part(email, '@', 2)) = 'gitlab.com') AND "users"."id" >= 15791577 AND (user_details.enterprise_group_id != 187 OR user_details.enterprise_group_id IS NULL);
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/22998/commands/74097
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.