Skip to content

Introduce AvailableServices singleton for accessing data

What does this MR do and why?

Introduce CloudConnector::AvailableServices singleton

For SelfManaged

  • we will read CloudConnector::Access database record
  • we will use CDOT issued token

Goal

Use CloudConnector::AvailableServices singleton as an interface to get information about CC service.

Note: We currently have CloudConnecor::AccessService with a similar purpose. The goal is to provide a more generic interface. In this iteration, the legacy CloudConnecor::AccessService is still used. In this iteration, the CloudConnecor::AvailableServices singleton is not yet used. I plan to remove CloudConnecor::AccessService in a separate merge request and replace the hardcoded checks/and usage.

  service = CloudConnector::AvailableServices.find_by_name(:duo_chat)

  service.free_acccess?      # checks if service is available for free (the cut_off_date is in the future) 
  service.allowed_for?(user) # checks if the user is assigned to one of the add-on seats that are bundled with the service.
  service.access_token       # Returns access token

In the next iteration (!148543 (closed)), the plan is to reduce the gap between SM and Gitlab.com by using CloudConnector::AvailableServices singleton for both Gitlab.com and Self-Managed instances.

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

Before After

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

To simulate add-on purchases and seat assignments

add_on = GitlabSubscriptions::AddOn.find_or_create_by_name(:code_suggestions, nil)
add_on_purchase = ::GitlabSubscriptions::AddOnPurchases::CreateService.new(nil, add_on, {quantity: 10, expires_on: Time.current + 6.months, purchase_xid: 1})
seat_assigment = ::GitlabSubscriptions::UserAddOnAssignments::SelfManaged::CreateService.new(add_on_purchase: add_on_purchase, user: User.last).execute

To test Self Managed flow

To remove free access for duo_chat

Add cut_off_date: 2024-02-15 00:00:00 UTC in CloudConnector::Accesss data column:

   pry(main)> access_data = CloudConnector::Access.create(data: {"available_services"=>[{"name"=>"code_suggestions", "bundledWith"=>. 
      ["code_suggestions"], "minGitlabVersion"=>nil, 
      "serviceStartTime"=>"2024-02-15T00:00:00Z"}, {"name"=>"duo_chat", "serviceStartTime"=>"2024-02-15T00:00:00Z", "bundledWith"=>["code_suggestions"], "minGitlabVersion"=>"16.8", 
      "serviceStartTime"=>nil}]}

Test Steps

  1. Create new CloudConnector::Access record

      pry(main)> access_data = CloudConnector::Access.create(data: {"available_services"=>[{"name"=>"code_suggestions", "bundledWith"=>["code_suggestions"], "minGitlabVersion"=>nil, 
      "serviceStartTime"=>"2024-02-15T00:00:00Z"}, {"name"=>"duo_chat", "bundledWith"=>["code_suggestions"], "minGitlabVersion"=>"16.8", 
      "serviceStartTime"=>nil}]}
  2. Start rails console:

      bundle exec rails c
  3. Clear the cache:

      CloudConnector::AvailableServices.clear_services_cache!
  4. Use CloudConnector::AvailableServices.find_by_name to find the service

      pry(main)> service = CloudConnector::AvailableServices.find_by_name(:duo_chat)
      => #<CloudConnector::SelfManaged::AvailableServiceData:0x000000013d934d90 @add_on_names=["code_suggestions"], @allowed_scopes_during_free_access=[:duo_chat], @bundled_with={"code_suggestions"=>[:duo_chat]}, @cut_off_date=nil, @name=:duo_chat>
      
      pry(main)> service.free_access?
      => false
    
    
      pry(main)> service.access_token
      => "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI1NGM3ZWIzOS1mODQ4LTQxOTEtOTI5Yy0xODBkNTJiMWYzYjAiLCJhdWQiOiJnaXRsYWItYWktZ2F0ZXdheSIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC8iLCJpYXQiOjE3MDc0OTUzOTQsIm5iZiI6MTcwNzQ5NTM4OSwiZXhwIjoxNzA3NzU0NTk0LCJnaXRsYWJfcmVhbG0iOiJzZWxmLW1hbmFnZWQiLCJzY29wZXMiOlsiY29kZV9zdWdnZXN0aW9ucyIsImR1b19jaGF0Il19.hHZEDBkQY9aSlP3aUVj6TAQP2XBPv-7QvggB6DiAHZhhdZtLVkdSY-dYLdZ8XLKi9ng5HiA-5q55Taw3ZjErK-xLkE1uzd4_AbLFRSdtRvv7iMioWG4kCsy67-MaSQ-um4av_KUkEQEZRlEWeEBx6GgPdIPGypp02dtbK1Gr7aTpjyx15_pTg_aflu8BJTjVQGAgi1_38uwzKRZlFsSxDTUKGoMhL3UZURQCc-Y1rRe1he-tKrd_-95ae6ozOKzQhN_51ZMEfxsbYxhurr2YGas0V_-zFrnulQhco0jGQeL3OZPPW6CLtw1rRc5pQ1WI47IStPkeqyz-u4pBoNN7WQ"
    
     pry(main)> service.allowed_for?(User.last)
     User Load (1.6ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1 
     /*application:console,db_config_name:main,console_hostname:Nikolas-MacBook-Pro.local,console_username:nikola,line:(pry):9:in `__pry__'*/
     => true
    

Related to https://gitlab.com/gitlab-org/customers-gitlab-com/-/issues/8975

Edited by Nikola Milojevic

Merge request reports