Ultimate is inaccurately counting guests and users without group/project as using a seat
Summary
In GitLab Ultimate, guests and users without a group or project are advertised as not consuming a seat in the license, originally introduced in !5816 (merged). During the process of working with a customer(internal only), and through my own local testing, both categories of user appear to be counting as billable users via the UI and historical data worker. This is creating confusion, and due to the historical data, preventing the application of an otherwise valid license.
Steps to reproduce
I launched a fresh gitlab-ee via docker gitlab/gitlab-ee:latest
(13.8.1-ee (e10a21e66ce)
) and first installed a Premium license for 5 seats. I added a regular user (with no projects), two guest users, and guest group in which I placed 1 guest user. In Premium, all of those users take a license seat, and my billable users and historical max accurately reflected 4 users (those 3 plus admin):
gitlabhq_production=# select * from historical_data order by id desc limit 1;
-[ RECORD 1 ]-----+------------------------------
id | 4
date |
active_user_count | 4
created_at | 2021-01-28 16:54:35.663305
updated_at | 2021-01-28 16:54:35.663305
recorded_at | 2021-01-28 16:54:35.661328+00
I created a project, added guest1 directly as a guest, and the guest group also as a guest:
http://localhost:8888/api/v4/projects/2/members/all
[{"id":1,"name":"Administrator","username":"root","state":"active","web_url":"http://c731d91d1d07/root","access_level":40,"created_at":"2021-01-28T16:39:13.433Z","expires_at":null},{"id":3,"name":"guest1","username":"guest1","state":"active","web_url":"http://c731d91d1d07/guest1","access_level":10,"created_at":"2021-01-28T16:39:26.289Z","expires_at":null},{"id":6,"name":"guest2","username":"guest2","state":"active","web_url":"http://c731d91d1d07/guest2","access_level":10,"created_at":"2021-01-28T16:48:29.229Z","expires_at":null}]
I then installed an Ultimate trial license, also for 5 users, and observed that my billable users count did not decrease to account for the now 2 free guests and 1 user without project. To further confirm, I added another regular user, and another guest which I added to the guest group. I used the regular user to create a project, so this user would take a seat.
At this point in time, I now have 5 users created, the 1 admin, and 2 bots created by GitLab. Observe my /admin/users
:
User page of a guest which shows its highest role as guest and it not taking a seat:
And yet, my billable users remains 6:
After running the usage statistics workers, my /admin/dashboard/stats
shows:
According to the user stats, those are 4 users (1 w/o group or project + 3 guests) that should not be counting as taking a license seat in GitLab Ultimate. Sidenote, the usage stats page states there are 8 billable users, which is also incorrect.
Interestingly, manually counting the users taking a seat from console reflects the true number:
irb(main):025:0> c = []
=> []
irb(main):026:1* User.all.each do |u|
irb(main):027:1* c.push(u) if u.using_license_seat?
irb(main):028:0> end
=> [#<User id:1 @root>, #<User id:2 @reggy1>, #<User id:3 @guest1>, #<User id:4 @alert-bot>, #<User id:5 @support-bot>, #<User id:6 @guest2>, #<User id:7 @reggy2>, #<User id:8 @guest3>]
irb(main):029:0> c.count
=> 2
irb(main):031:1* User.all.each do |u|
irb(main):032:2* if u.highest_role <= 10 and u.using_license_seat?
irb(main):033:2* puts u.name,u.projects,u.groups
irb(main):034:1* end
irb(main):035:0> end
=> [#<User id:1 @root>, #<User id:2 @reggy1>, #<User id:3 @guest1>, #<User id:4 @alert-bot>, #<User id:5 @support-bot>, #<User id:6 @guest2>, #<User id:7 @reggy2>, #<User id:8 @guest3>]
irb(main):036:0> # Outputs nothing because there are no guest users using_license_seat
irb(main):030:0> User.active.count
=> 6
The HistoricalDataWorker does not run when a trial license is present, so my historical max is still 4 at this point
irb(main):041:0> HistoricalData.max_historical_user_count
=> 4
Activating a non-trial license to allow it to run, my historical is incremented to 6:
irb(main):045:0> License.current.trial?
=> false
irb(main):046:0> HistoricalData.max_historical_user_count
=> 6
Finally, when applying a new license, it appears that the background processes that validate the license do correctly calculate the true billable users count, although historical usage is still a factor. Using my same test instance wherein only 2 users are actually taking a seat, if I truncate my historical data, GitLab allows me to upload and apply a license for only 2 users (and 0 previous, 0 true-ups), despite my dashboard showing 6 billable users
irb(main):048:0> HistoricalData.max_historical_user_count
=> 0
irb(main):049:0> c.count
=> 2
What is the current bug behavior?
Users that should not be taking a license seat in GitLab Ultimate are taking a license seat, which has an impact for both current customers of Ultimate (incorrect true-ups), and customers trying to upgrade to Ultimate (license wont activate due to inaccurate counts).
What is the expected correct behavior?
Guests and users without groups/projects should not be taking a license seat
Relevant logs and/or screenshots
On the customer's instance, we grabbed UsersStatistics:
=> #<UsersStatistics id: 250, created_at: "2021-01-27 15:02:08", updated_at: "2021-01-27 15:02:08", without_groups_and_projects: 6, with_highest_role_guest: 25, with_highest_role_reporter: 0, with_highest_role_developer: 10, with_highest_role_maintainer: 69, with_highest_role_owner: 24, bots: 24, blocked: 19>
without_groups_and_projects: 6
with_highest_role_guest: 25
31 total users that should not be taking a seat. I asked the customer to run the same using_license_seat?
count block from above:
103 + 31 for a total of 134, matching their admin dashboard:
Environment
My environment is a fresh install of latest GitLab (13.8.1-ee) via docker; no modifications or configurations. Customer running Omnibus GitLab 13.7.x.
Possible fixes or workarounds
Right now, the only workaround that I am aware of is to ship a license with inaccurate user counts, or manually manipulate the historical_data
table, since this number is possibly including guests that should not be in the maximum user count.