Skip to content

Commit

Permalink
Initial plugin integration
Browse files Browse the repository at this point in the history
Integrate React UI for Resource Quota

* Add ResourceQuotaForm, CreateResourceQuotaModal, and UpdateResourceQuotaModal
* Add ActionableDetail from katello in webpack/lib
* Delete Template webpack/src example files
* Rely on local store instead of Redux state handling

Integrate Resource Quota Rails components

* Add Resource Quota model and concerns
* Add db migration
* Configure engine and register file
* Add Rails and API controller with corresponding templates
* Configure resourceful routing

Integrate Rails tests

* Add controller and API controller tests
* Add model and helper tests
* Add placeholders for service tests
  • Loading branch information
bastian-src committed Dec 20, 2023
1 parent ccc6333 commit 4b7fc9b
Show file tree
Hide file tree
Showing 111 changed files with 4,514 additions and 300 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ node_modules
package-lock.json
Gemfile.lock
coverage
tmp/
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "es5"
}
45 changes: 19 additions & 26 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
require:
- rubocop-performance
- rubocop-rails
- rubocop-minitest

AllCops:
TargetRubyVersion: 2.5
TargetRailsVersion: 6.0
Exclude:
- 'node_modules/**/*'
inherit_gem:
theforeman-rubocop:
- strictest.yml

inherit_mode:
merge:
- Exclude

Layout/ArgumentAlignment:
EnforcedStyle: with_fixed_indentation
IndentationWidth: 2

Layout/EmptyLineAfterGuardClause:
Gemspec/RequiredRubyVersion:
Enabled: false

Layout/LineLength:
Enabled: 111 # TODO: discuss and set this

Rails:
Enabled: true

Style/Alias:
EnforcedStyle: prefer_alias_method

# Don't enforce documentation
Style/Documentation:
Metrics/MethodLength:
Enabled: false

# Don't enforce frozen string literals
Style/FrozenStringLiteralComment:
Metrics/PerceivedComplexity:
Enabled: false

# Support both ruby19 and hash_rockets
Style/HashSyntax:
Naming/VariableNumber:
Exclude:
- 'test/**/*.rb'

Rails/SkipsModelValidations:
Exclude:
- 'db/migrate/**/*'

Style/FormatStringToken:
Enabled: false
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec

gem 'theforeman-rubocop', '~> 0.1.2'
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
# Foreman Resource Quota

When several users share a compute resource or infrastructure, there is a concern that some users could use more than its fair share of resources. Resource quotas are a tool for administrators to address this concern. They limit access to the shared resource in order to guarantee a fair collaboration.
Foreman plugin to allow resource management with resource quotas among users and usergroups.

Talking about Foreman, multiple users or groups usually share a fixed number of resources (limitation of compute resources like RAM, disk storage, and CPU power). As of now, a user cannot be limited when allocating resources. They can create hosts with as many resources as they want. This could lead to over-usage or unequal balancing of resources under the users. In order to prevent this, we want to introduce a new plugin: Foreman Resource Quota.
## Installation

This plugin introduces the configuration of quotas. A quota limits specific resources and can be applied to a user or a user group. If a user belongs to a user group, the group’s quota is automatically applied to the user as well.
_TODO_ Still under development: Will be updated as soon as the Ruby gem, foreman-installer, or rpm is available.

A user is hindered from deploying new hosts, if the new host would exceed the corresponding quota limits. In case, a user belongs to multiple user group with quota, the user can determine which quota new hosts belong to.

## Installation
## Compatibility

See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
for how to install Foreman plugins
| Foreman Version | Plugin Version |
| --------------- | -------------- |
| 3.5 | 0.0.1 |

## Usage

*Usage here*
_TODO_ Still under development: Official documentation will be added soon.

## TODO
When several users share a compute resource or infrastructure, there is a concern that some users could use more than its fair share of resources. Resource quotas are a tool for administrators to address this concern. They limit access to the shared resource in order to guarantee a fair collaboration.

In the context of Foreman, multiple users or groups usually share a fixed number of resources (limitation of compute resources like RAM, disk space, and CPU cores). As of now, a user cannot be limited when allocating resources. They can create hosts with as many resources as they want. This could lead to over-usage or unequal balancing of resources under the users.

This plugin introduces the configuration of resource quotas. A quota limits specific resources and can be applied to a user or a user group. If a user belongs to a user group, the group’s quota is automatically applied to the user as well. When deploying a new host, a user has to choose a resource quota that the host counts to.

A user is hindered from deploying new hosts, if the new host would exceed the corresponding quota limits. In case, a user belongs to multiple user group with quota, the user can determine which quota new hosts belong to.

*Todo list here*

## Contributing

Fork and send a Pull Request. Thanks!

## Copyright

Copyright (c) *year* *your name*
Copyright (c) 2023 ATIX AG - https://atix.de

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down
8 changes: 5 additions & 3 deletions Rakefile
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#!/usr/bin/env rake
# frozen_string_literal: true

begin
require 'bundler/setup'
rescue LoadError
Expand All @@ -14,13 +16,13 @@ end

RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'ForemanPluginTemplate'
rdoc.title = 'ForemanResourceQuota'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end

APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)

Bundler::GemHelper.install_tasks

Expand All @@ -38,7 +40,7 @@ task default: :test
begin
require 'rubocop/rake_task'
RuboCop::RakeTask.new
rescue => _
rescue StandardError => _e
puts 'Rubocop not loaded.'
end

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

module Foreman
module Controller
module Parameters
module ResourceQuota
extend ActiveSupport::Concern

class_methods do
def resource_quota_params_filter
Foreman::ParameterFilter.new(::ForemanResourceQuota::ResourceQuota).tap do |filter|
filter.permit :name
filter.permit :description
filter.permit :cpu_cores
filter.permit :memory_mb
filter.permit :disk_gb
end
end
end

def resource_quota_params
param_name = parameter_filter_context.api? ? 'resource_quota' : 'foreman_resource_quota_resource_quota'
self.class.resource_quota_params_filter.filter_params(params, parameter_filter_context, param_name)
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# frozen_string_literal: true

module ForemanResourceQuota
module Api
module V2
class ResourceQuotasController < ::Api::V2::BaseController
include ::Api::Version2
include Foreman::Controller::Parameters::ResourceQuota

resource_description do
resource_id 'resource_quota'
api_version 'v2'
api_base_url '/foreman_resource_quota/api'
end

before_action :find_resource, only: %i[show update destroy]
before_action :custom_find_resource, only: %i[utilization hosts users usergroups]

api :GET, '/resource_quotas', N_('List all resource quotas')
param_group :search_and_pagination, ::Api::V2::BaseController
add_scoped_search_description_for(ForemanResourceQuota::ResourceQuota)
def index
@resource_quotas = resource_scope_for_index
end

api :GET, '/resource_quotas/:id/', N_('Show resource quota')
param :id, :identifier, required: true
def show
end

api :GET, '/resource_quotas/:id/utilization', N_('Show used resources of assigned hosts')
param :id, :identifier, required: true
def utilization
@resource_quota.determine_utilization
process_response @resource_quota
end

api :GET, '/resource_quotas/:id/hosts', N_('Show hosts of a resource quota')
param :id, :identifier, required: true
def hosts
process_response @resource_quota.hosts
end

api :GET, '/resource_quotas/:id/users', N_('Show users of a resource quota')
param :id, :identifier, required: true
def users
process_response @resource_quota.users
end

api :GET, '/resource_quotas/:id/usergroups', N_('Show usergroups of a resource quota')
param :id, :identifier, required: true
def usergroups
process_response @resource_quota.usergroups
end

def_param_group :resource_quota do
param :resource_quota, Hash, required: true, action_aware: true do
param :name, String, required: true
# param :operatingsystem_ids, Array, :desc => N_("Operating system IDs")
end
end

api :POST, '/resource_quotas/', N_('Create a resource quota')
param_group :resource_quota, as: :create
def create
@resource_quota = ForemanResourceQuota::ResourceQuota.new(resource_quota_params)
process_response @resource_quota.save
end

api :PUT, '/resource_quotas/:id/', N_('Update a resource quota')
param :id, :identifier, required: true
param_group :resource_quota
def update
process_response @resource_quota.update(resource_quota_params)
end

api :DELETE, '/resource_quotas/:id/', N_('Delete a resource quota')
param :id, :identifier, required: true
def destroy
process_response @resource_quota.destroy
end

def resource_class
ForemanResourceQuota::ResourceQuota
end

private

def custom_find_resource
@resource_quota = ForemanResourceQuota::ResourceQuota.find_by(id: params[:resource_quota_id])
not_found unless @resource_quota
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module ForemanResourceQuota
class ApplicationController < ::ApplicationController
def resource_class
"ForemanResourceQuota::#{controller_name.singularize.classify}".constantize
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

module ForemanResourceQuota
class ResourceQuotasController < ::ForemanResourceQuota::ApplicationController
include Foreman::Controller::AutoCompleteSearch
include Foreman::Controller::Parameters::ResourceQuota

before_action :find_resource, only: %i[edit update destroy]

def index
@resource_quotas = resource_base.search_for(params[:search], order: params[:order]).paginate(page: params[:page],
per_page: params[:per_page])
# TODO: Check necessitiy/purpose of authorizer
# AuthorizerHelper#authorizer uses controller_name as variable name, but it fails with namespaces
# @authorizer = Authorizer.new(User.current, collection: @resource_quotas)
end

def new
@resource_quota = ResourceQuota.new
end

def create
@resource_quota = ResourceQuota.new(resource_quota_params)
if @resource_quota.save
process_success
else
process_error
end
end

def edit
end

def update
if @resource_quota.update(resource_quota_params)
process_success
else
process_error
end
end

def destroy
if @resource_quota.destroy
process_success
else
process_error
end
end
end
end
18 changes: 18 additions & 0 deletions app/helpers/foreman_resource_quota/hosts_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module ForemanResourceQuota
module HostsHelper
def resource_quota_select(form, user_quotas)
blank_opt = { include_blank: true }
select_items = user_quotas.order(:name)
select_f form,
:resource_quota_id,
select_items,
:id,
:to_label,
blank_opt,
label: _('Resource Quota'),
help_inline: _('Define the Resource Quota this host counts to.')
end
end
end
Loading

0 comments on commit 4b7fc9b

Please sign in to comment.