Skip to content

Commit

Permalink
add per-user leasing strategy to policies
Browse files Browse the repository at this point in the history
  • Loading branch information
ezekg committed May 9, 2024
1 parent 54f6501 commit 131b884
Show file tree
Hide file tree
Showing 13 changed files with 3,129 additions and 637 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,18 @@ To run Cucumber features, run:

```bash
bundle exec rake test:cucumber
bundle exec rake test:cucumber[features/api/v1/licenses/create.feature]
bundle exec rake test:cucumber[features/api/v1/licenses/actions/validations.feature:369]
bundle exec rake test:cucumber[features/api/v1/licenses/actions/validations.feature]
bundle exec rake test:cucumber[features/api/v1/licenses]
```

To run Rspec specs, run:

```bash
bundle exec rake test:rspec
bundle exec rake test:rspec[spec/models/license_spec.rb:199]
bundle exec rake test:rspec[spec/models/license_spec.rb]
bundle exec rake test:rspec[spec/models]
```

## License
Expand Down
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ def render_unprocessable_resource(resource)
in source: { pointer: %r{/attributes/([^/]+)} }
s << '-attrs-' << $1
else
s
end
}

Expand Down
41 changes: 11 additions & 30 deletions app/models/license.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class License < ApplicationRecord
next if license.uses.nil? || license.max_uses.nil?
next if license.uses <= license.max_uses

license.errors.add :uses, :limit_exceeded, message: "usage exceeds maximum allowed by current policy (#{license.max_uses})"
license.errors.add :uses, :limit_exceeded, message: "usage exceeds maximum allowed for license (#{license.max_uses})"
end

validate on: :update do |license|
Expand Down Expand Up @@ -607,7 +607,7 @@ class License < ApplicationRecord
:strict?, :pool?, :node_locked?, :floating?,
:always_allow_overage?, :allow_overage?, :allow_1_25x_overage?, :allow_1_5x_overage?, :allow_2x_overage?, :no_overage?,
:revoke_access?, :restrict_access?, :maintain_access?, :allow_access?,
:lease_per_machine?, :lease_per_license?,
:lease_per_machine?, :lease_per_license?, :lease_per_user?,
:expire_from_creation?,
:expire_from_first_validation?,
:expire_from_first_activation?,
Expand Down Expand Up @@ -722,50 +722,31 @@ def status
end
end


def max_machines = max_machines_override? ? max_machines_override : policy&.max_machines
def max_machines? = max_machines.present?
def max_machines=(value)
self.max_machines_override = value
end

def max_machines
return max_machines_override if
max_machines_override?

policy&.max_machines
end

def max_cores = max_cores_override? ? max_cores_override : policy&.max_cores
def max_cores? = max_cores.present?
def max_cores=(value)
self.max_cores_override = value
end

def max_cores
return max_cores_override if
max_cores_override?

policy&.max_cores
end

def max_uses = max_uses_override? ? max_uses_override : policy&.max_uses
def max_uses? = max_uses.present?
def max_uses=(value)
self.max_uses_override = value
end

def max_uses
return max_uses_override if
max_uses_override?

policy&.max_uses
end

def max_processes = max_processes_override? ? max_processes_override : policy&.max_processes
def max_processes? = max_processes.present?
def max_processes=(value)
self.max_processes_override = value
end

def max_processes
return max_processes_override if
max_processes_override?

policy&.max_processes
end

def max_users = max_users_override? ? max_users_override : policy&.max_users
def max_users? = max_users.present?
def max_users=(value)
Expand Down
106 changes: 75 additions & 31 deletions app/models/machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,50 +124,94 @@ class ResurrectionExpiredError < StandardError; end
next if
machine.license.max_machines.nil? || machine.license.always_allow_overage?

prev_machines_count = machine.license.machines_count || 0
next if
prev_machines_count == 0
case
when license.lease_per_machine?,
license.lease_per_license?
prev_machines_count = machine.license.machines_count || 0
next if
prev_machines_count == 0

next_machine_count = prev_machines_count + 1
next unless
next_machine_count > machine.license.max_machines
next_machine_count = prev_machines_count + 1
next unless
next_machine_count > machine.license.max_machines

next if
machine.license.allow_1_25x_overage? && next_machine_count <= machine.license.max_machines * 1.25
next if
machine.license.allow_1_25x_overage? && next_machine_count <= machine.license.max_machines * 1.25

next if
machine.license.allow_1_5x_overage? && next_machine_count <= machine.license.max_machines * 1.5
next if
machine.license.allow_1_5x_overage? && next_machine_count <= machine.license.max_machines * 1.5

next if
machine.license.allow_2x_overage? && next_machine_count <= machine.license.max_machines * 2
next if
machine.license.allow_2x_overage? && next_machine_count <= machine.license.max_machines * 2

machine.errors.add :base, :limit_exceeded, message: "machine count has exceeded maximum allowed by current policy (#{machine.license.max_machines})"
end
machine.errors.add :base, :limit_exceeded, message: "machine count has exceeded maximum allowed for license (#{machine.license.max_machines})"
when license.lease_per_user?
prev_machines_count = license.machines.where(owner:) # nil owner is significant
.count
next if
prev_machines_count == 0

# Disallow machine core overages according to policy overage strategy
validate on: [:create, :update] do |machine|
next if machine.license.nil?
next if
machine.license.max_cores.nil? || machine.license.always_allow_overage?
next_machine_count = prev_machines_count + 1
next unless
next_machine_count > machine.license.max_machines

prev_core_count = machine.license.machines.where.not(id: machine.id).sum(:cores) || 0
next_core_count = prev_core_count + machine.cores.to_i
next if
next_core_count == 0
next if
machine.license.allow_1_25x_overage? && next_machine_count <= machine.license.max_machines * 1.25

next unless
next_core_count > machine.license.max_cores
next if
machine.license.allow_1_5x_overage? && next_machine_count <= machine.license.max_machines * 1.5

next if
machine.license.allow_1_25x_overage? && next_core_count <= machine.license.max_cores * 1.25
next if
machine.license.allow_2x_overage? && next_machine_count <= machine.license.max_machines * 2

next if
machine.license.allow_1_5x_overage? && next_core_count <= machine.license.max_cores * 1.5
machine.errors.add :base, :limit_exceeded, message: "machine count has exceeded maximum allowed for user (#{machine.license.max_machines})"
end
end

# Disallow machine core overages according to policy overage strategy
validate on: %i[create update] do |machine|
next if machine.license.nil?
next if
machine.license.allow_2x_overage? && next_core_count <= machine.license.max_cores * 2
machine.license.max_cores.nil? || machine.license.always_allow_overage?

machine.errors.add :base, :core_limit_exceeded, message: "machine core count has exceeded maximum allowed by current policy (#{machine.license.max_cores})"
case
when license.lease_per_machine?,
license.lease_per_license?
prev_core_count = machine.license.machines.where.not(id: machine.id)
.sum(:cores)
next_core_count = prev_core_count + machine.cores.to_i
next unless
next_core_count > machine.license.max_cores

next if
machine.license.allow_1_25x_overage? && next_core_count <= machine.license.max_cores * 1.25

next if
machine.license.allow_1_5x_overage? && next_core_count <= machine.license.max_cores * 1.5

next if
machine.license.allow_2x_overage? && next_core_count <= machine.license.max_cores * 2

machine.errors.add :base, :core_limit_exceeded, message: "machine core count has exceeded maximum allowed for license (#{machine.license.max_cores})"
when license.lease_per_user?
prev_core_count = machine.license.machines.where.not(id: machine.id)
.where(owner:) # nil owner is significant
.sum(:cores)
next_core_count = prev_core_count + machine.cores.to_i
next unless
next_core_count > machine.license.max_cores

next if
machine.license.allow_1_25x_overage? && next_core_count <= machine.license.max_cores * 1.25

next if
machine.license.allow_1_5x_overage? && next_core_count <= machine.license.max_cores * 1.5

next if
machine.license.allow_2x_overage? && next_core_count <= machine.license.max_cores * 2

machine.errors.add :base, :core_limit_exceeded, message: "machine core count has exceeded maximum allowed for user (#{machine.license.max_cores})"
end
end

# Fingerprint uniqueness on create
Expand Down
19 changes: 18 additions & 1 deletion app/models/machine_process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class ResurrectionExpiredError < StandardError; end
before_validation -> { self.last_heartbeat_at ||= Time.current },
on: :create

delegate :leasing_strategy, :lease_per_license?, :lease_per_machine?,
delegate :leasing_strategy, :lease_per_license?, :lease_per_machine?, :lease_per_user?,
:resurrect_dead?, :always_resurrect_dead?, :lazarus_ttl,
allow_nil: true,
to: :policy
Expand Down Expand Up @@ -89,6 +89,23 @@ class ResurrectionExpiredError < StandardError; end
license.allow_2x_overage? && next_process_count <= license.max_processes * 2

errors.add :base, :limit_exceeded, message: "process count has exceeded maximum allowed for license (#{license.max_processes})"
when lease_per_user?
next_process_count = license.processes.left_outer_joins(:owner)
.where(owner: { id: owner }) # nil owner is significant
.count + 1
next unless
next_process_count > license.max_processes

next if
license.allow_1_25x_overage? && next_process_count <= license.max_processes * 1.25

next if
license.allow_1_5x_overage? && next_process_count <= license.max_processes * 1.5

next if
license.allow_2x_overage? && next_process_count <= license.max_processes * 2

errors.add :base, :limit_exceeded, message: "process count has exceeded maximum allowed for user (#{license.max_processes})"
end
end

Expand Down
5 changes: 5 additions & 0 deletions app/models/policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class EmptyPoolError < StandardError; end
LEASING_STRATEGIES = %w[
PER_LICENSE
PER_MACHINE
PER_USER
].freeze

OVERAGE_STATEGIES = %w[
Expand Down Expand Up @@ -603,6 +604,10 @@ def lease_per_machine?
leasing_strategy == 'PER_MACHINE'
end

def lease_per_user?
leasing_strategy == 'PER_USER'
end

def always_allow_overage?
overage_strategy == 'ALWAYS_ALLOW_OVERAGE'
end
Expand Down
Loading

0 comments on commit 131b884

Please sign in to comment.