Skip to content

Commit

Permalink
Introduce host_resources model
Browse files Browse the repository at this point in the history
The HostResources extend the Host::Managed by creating a table to
track the quota-related resources of a host. Moreover, the quota-host
relation is replaced by an additional ResourceQuotaHost table.
  • Loading branch information
bastian-src committed Nov 20, 2024
1 parent 160eb0d commit ae6cb5f
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ module HostManagedExtensions
include ForemanResourceQuota::Exceptions

included do
validate :check_resource_quota_capacity

belongs_to :resource_quota, class_name: '::ForemanResourceQuota::ResourceQuota'
has_one :resource_quota_missing_resources, class_name: '::ForemanResourceQuota::ResourceQuotaMissingHost',
inverse_of: :missing_host, foreign_key: :missing_host_id, dependent: :destroy
validate :verify_resource_quota

has_one :host_resources, class_name: '::ForemanResourceQuota::HostResources',
inverse_of: :host, foreign_key: :host_id, dependent: :destroy
has_one :resource_quota_host, class_name: '::ForemanResourceQuota::ResourceQuotaHost',
inverse_of: :host, foreign_key: :host_id, dependent: :destroy
has_one :resource_quota, class_name: '::ForemanResourceQuota::ResourceQuota',
through: :resource_quota_host
scoped_search relation: :resource_quota, on: :name, complete_value: true, rename: :resource_quota

# A host shall always have a .host_resources attribute
before_validation :build_host_resources, unless: -> { host_resources.present? }
end

def check_resource_quota_capacity
handle_quota_check
def verify_resource_quota
handle_quota_check(resource_quota)
true
rescue ResourceQuotaException => e
handle_error('resource_quota_id',
Expand All @@ -32,13 +38,27 @@ def check_resource_quota_capacity
format('An unknown error occured while checking the resource quota capacity: %s', e))
end

def resource_quota_id
resource_quota&.id
end

def resource_quota_id=(val)
if val.blank?
resource_quota_host&.destroy
else
quota = ForemanResourceQuota::ResourceQuota.find_by(id: val)
raise ActiveRecord::RecordNotFound, "ResourceQuota with ID \"#{val}\" not found" unless quota
self.resource_quota = quota
end
end

private

def handle_quota_check
return if early_return?
quota_utilization = determine_quota_utilization
host_resources = determine_host_resources
verify_resource_quota_limits(quota_utilization, host_resources)
def handle_quota_check(quota)
return if early_return?(quota)
quota_utilization = determine_quota_utilization(quota)
current_host_resources = determine_host_resources(quota.active_resources)
check_resource_quota_limits(quota, quota_utilization, current_host_resources)
end

def handle_error(error_module, error_message, log_message)
Expand Down
43 changes: 43 additions & 0 deletions app/models/foreman_resource_quota/host_resources.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

module ForemanResourceQuota
class HostResources < ApplicationRecord
self.table_name = 'hosts_resources'

belongs_to :host, class_name: '::Host::Managed'
validates :host, { presence: true, uniqueness: true }

def resources
{
cpu_cores: cpu_cores,
memory_mb: memory_mb,
disk_gb: disk_gb,
}
end

def resources=(val)
allowed_attributes = val.slice(:cpu_cores, :memory_mb, :disk_gb)
assign_attributes(allowed_attributes) # Set multiple attributes at once (given a hash)
end

# Returns an array of unknown host resources (returns an empty array if all are known)
# For example, completely unknown host resources returns:
# [
# :cpu_cores,
# :memory_mb,
# :disk_gb,
# ]
# Consider only the resource_quota's active resources by default.
def missing_resources(only_active_resources: true)
empty_resources = []
resources_to_check = %i[cpu_cores memory_mb disk_gb]
resources_to_check = host.resource_quota.active_resources if only_active_resources && host.resource_quota.present?

resources_to_check.each do |single_resource|
empty_resources << single_resource if send(single_resource).nil?
end

empty_resources
end
end
end
8 changes: 4 additions & 4 deletions app/models/foreman_resource_quota/resource_quota.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ class ResourceQuota < ApplicationRecord

self.table_name = 'resource_quotas'

has_many :resource_quotas_hosts, class_name: 'ResourceQuotaHost', inverse_of: :resource_quota, dependent: :destroy
has_many :resource_quotas_users, class_name: 'ResourceQuotaUser', inverse_of: :resource_quota, dependent: :destroy
has_many :resource_quotas_usergroups, class_name: 'ResourceQuotaUsergroup', inverse_of: :resource_quota,
dependent: :destroy
has_many :resource_quotas_missing_hosts, class_name: 'ResourceQuotaMissingHost', inverse_of: :resource_quota,
dependent: :destroy
has_many :hosts, class_name: '::Host::Managed', dependent: :nullify
has_many :hosts, -> { distinct }, class_name: '::Host::Managed', through: :resource_quotas_hosts
has_many :hosts_resources, class_name: 'HostResources', through: :hosts
has_many :users, class_name: '::User', through: :resource_quotas_users
has_many :usergroups, class_name: '::Usergroup', through: :resource_quotas_usergroups

Expand Down Expand Up @@ -54,7 +54,7 @@ def number_of_missing_hosts
def missing_hosts(exclude: [])
missing_hosts = {}
active_resources.each do |single_resource|
hosts_resources.where(single_resource => nil).find_each do |host_resources_item|
hosts_resources.where(single_resource => nil).includes([:host]).find_each do |host_resources_item|
host_name = host_resources_item.host.name
next if exclude.include?(host_name)
missing_hosts[host_name] ||= []
Expand Down
10 changes: 10 additions & 0 deletions app/models/foreman_resource_quota/resource_quota_host.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

module ForemanResourceQuota
class ResourceQuotaHost < ApplicationRecord
self.table_name = 'resource_quotas_hosts'

belongs_to :resource_quota, class_name: 'ResourceQuota'
belongs_to :host, class_name: '::Host::Managed'
end
end
10 changes: 0 additions & 10 deletions app/models/foreman_resource_quota/resource_quota_missing_host.rb

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class RemoveUtilizationFromResourceQuotas < ActiveRecord::Migration[6.1]
def change
remove_column :resource_quotas, :utilization_cpu_cores, :integer
remove_column :resource_quotas, :utilization_memory_mb, :integer
remove_column :resource_quotas, :utilization_disk_gb, :integer
end
end
7 changes: 7 additions & 0 deletions db/migrate/20240611141939_drop_missing_hosts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class DropMissingHosts < ActiveRecord::Migration[6.1]
def up
drop_table :resource_quotas_missing_hosts
end
end
21 changes: 21 additions & 0 deletions db/migrate/20240611142813_create_hosts_resources.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

class CreateHostsResources < ActiveRecord::Migration[6.1]
def change
create_table :hosts_resources do |t|
t.belongs_to :host, index: { unique: true }, foreign_key: true, null: false
t.integer :cpu_cores, default: nil
t.integer :memory_mb, default: nil
t.integer :disk_gb, default: nil

t.timestamps
end

create_table :resource_quotas_hosts do |t|
t.belongs_to :host, index: { unique: true }, foreign_key: true, null: false
t.belongs_to :resource_quota, foreign_key: true, null: false

t.timestamps
end
end
end
7 changes: 7 additions & 0 deletions db/migrate/20240618163434_remove_resource_quota_from_hosts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class RemoveResourceQuotaFromHosts < ActiveRecord::Migration[6.1]
def change
remove_reference :hosts, :resource_quota, foreign_key: true
end
end

0 comments on commit ae6cb5f

Please sign in to comment.