Commit 9cf06220 authored by BAIRE Anthony's avatar BAIRE Anthony
Browse files

per-app memory limit configuration

fix #55
parent f19328b8
......@@ -4,19 +4,6 @@
# # number of cpus allocated to each job (default: no limit)
# cpus: 1
#
# # soft memory limit (default: no limit)
# mem_soft_limit: "1G"
#
# # hard memory limit (default: no limit)
# mem_hard_limit: "2g"
#
#
# # list of applications that require more memory (default: [])
# bigmem_apps: ["app1", "app42"]
#
# # hard memory limit for bigmem_apps (default: no limit)
# bigmem_hard_limit: "8G"
#
#
# ############ swarm and sandbox configuration ################
# #
......
......@@ -923,12 +923,10 @@ class JobManager(Manager):
class JobInfo:
__slots__ = "job_id", "ver_id", "ctr_id", "version", "ctr_name", "client", "cpu", "mem", "node_id", "timeout"
def __init__(self, ctrl, bigmem_apps=()):
def __init__(self, ctrl):
super().__init__(0)
self.ctrl = ctrl
self.bigmem_apps = bigmem_apps
@asyncio.coroutine
def __iter__(self):
......@@ -975,12 +973,8 @@ class JobManager(Manager):
cpu_quota = (None if info.cpu is None else (info.cpu * 1024)),
cpu_period = (None if info.cpu is None else 1024),
# cpu_shares = info.cpu,
# mem_reservation = ctrl.mem_soft_limit,
mem_limit = info.mem,
)
if ctrl.mem_soft_limit:
# TODO: upgrade docker-py (and use create_host_config)
hc["MemoryReservation"] = ctrl.mem_soft_limit
# NOTE: cpu_shares has a different meaining in docker swarm and docker engine
# - swarm: nb of cpus
# - engine: 1/1024 share of the total cpu resouces of the machine
......@@ -1202,7 +1196,7 @@ class JobManager(Manager):
# a new job. They do not apply to already created jobs (by a
# previous instance of the controller)
info.cpu = ctrl.cpu_shares
info.mem = ctrl.bigmem_hard_limit if docker_name in self.bigmem_apps else ctrl.mem_hard_limit
info.mem = job.webapp.memory_limit
if job.version == "sandbox":
......@@ -1477,11 +1471,6 @@ class DockerController:
raise ValueError("%s: %s" % (cfg.path(key), e))
self.cpu_shares = cfg.get("cpus", None, int)
self.mem_soft_limit = cfg.get("mem_soft_limit", None, str, cast=docker.utils.parse_bytes)
self.mem_hard_limit = cfg.get("mem_hard_limit", None, str, cast=docker.utils.parse_bytes)
self.bigmem_hard_limit = cfg.get("bigmem_hard_limit", None, str, cast=docker.utils.parse_bytes)
bigmem_apps = cfg.get("bigmem_apps", [], list)
self.sandbox = SharedSwarmClient(sandbox_host, config=cfg.get("sandbox", {}, dict), alias="sandbox")
if sandbox_host == swarm_host:
......@@ -1502,7 +1491,7 @@ class DockerController:
self.image_manager = ImageManager(self)
self.sandbox_manager = SandboxManager(self)
self.job_manager = JobManager(self, bigmem_apps)
self.job_manager = JobManager(self)
self.registry = registry
......
......@@ -48,6 +48,7 @@ class Webapp(Base):
docker_os_id = Column(Integer, ForeignKey('docker_os.id'))
exec_time = Column(Integer)
entrypoint = Column(String)
memory_limit = Column(Integer)
versions = relationship("WebappVersion", foreign_keys="[WebappVersion.webapp_id]")
sandbox_version = relationship("WebappVersion", foreign_keys=[sandbox_version_id])
......
......@@ -55,6 +55,7 @@ class WebappsController < ApplicationController
def new
@webapp = Webapp.new
@webapp.contact = current_user.email
set_memory_limit_mb Rails.configuration.webapp_default_memory_limit
@dockeros_name = DockerOs.select(:name).group(:name)
@dockeros = DockerOs.all
@default_os = default_os
......@@ -73,6 +74,9 @@ class WebappsController < ApplicationController
wp = webapp_params #must have a copy to modify the array
wp = Webapp.validator(wp)
wp[:user_id] = current_user.id
if not current_user.admin?
wp[:memory_limit] = Rails.configuration.webapp_default_memory_limit
end
# unless wp[:source_file].nil?
# manage_source_upload(wp)
# end
......@@ -108,6 +112,7 @@ class WebappsController < ApplicationController
#TODO
#@webapp = Webapp.find(params[:id])
@user = User.find(@webapp.user_id)
set_memory_limit_mb @webapp.memory_limit
end
# PATCH/PUT /webapps/1
......@@ -324,6 +329,10 @@ class WebappsController < ApplicationController
end
end
def set_memory_limit_mb(lim)
@memory_limit_mb = lim && (lim/1.megabyte)
end
# 'admin' access is granted to the app owner and to the admin users
#
def verify_webapp_admin_permission
......@@ -374,11 +383,18 @@ class WebappsController < ApplicationController
# split in different method for each action (create, update, delete)
def webapp_params
# FIXME: do not permit to update user_id
params.require(:webapp).permit(:id, :name, :description, :contact, :entrypoint, :logo, :tag_list, :user_id, :default_quota, :source_file, :private,
wp = params.require(:webapp).permit(:id, :name, :description, :contact, :entrypoint, :logo, :tag_list, :user_id, :default_quota, :source_file, :private,
:sandbox_state, :docker_os_id, :from_showapps, :readme, :input_demo, :output_demo, :update_demos, :update_parameters, :version, :default_job_queue_id,
webapp_parameters_attributes: [:id, :name, :value, :detail],
#webapp_demos_attributes: [:id, :name, :extension, :file_type],
webapp_versions_attributes: [:id, :number, :changelog] )
# setting memory_limit permitted to admins only
if params.has_key? :memory_limit_mb and current_user and current_user.admin?
lim = params[:memory_limit_mb]
wp[:memory_limit] = lim.empty? ? nil : lim.to_i.megabytes
end
return wp
end
end
......@@ -65,6 +65,15 @@
<span class="help-block"> A private app won't be display on the main page, and won't be accessible without the link. </span>
</div>
<% if current_user.admin? %>
<div class="form-group">
<%= f.label :access_token, "Memory limit", class: "col-sm-2 control-label" %>
<div class="col-sm-1"><%= text_field_tag :memory_limit_mb, @memory_limit_mb, {placeholder: "no limit", class: "form-control", style: "text-align: right"} %></div>
<span class="help-block"> megabytes</span>
</div>
<% end %>
<!-- <div class="form-group">
<%= f.label :default_quota, "Quota per user (in MB) ", class: "col-sm-2 control-label" %>
<div class="col-sm-5"><%= f.text_field :default_quota, value: "50", class: "form-control" %></div>
......
......@@ -34,6 +34,9 @@ module Allgo
"ask a question" => "https://helpdesk.inria.fr/categories/228/submit",
}
# Memory limit (in bytes) set when new webapps are created
config.webapp_default_memory_limit = nil
# Conventions inside the docker container
config.datastore = "/vol/rw/datastore"
config.paths["log"] = "/vol/log/rails/rails.log"
......
class AddMemoryLimit < ActiveRecord::Migration[5.0]
def change
add_column :webapps, :memory_limit, :integer, limit: 8
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20171115133031) do
ActiveRecord::Schema.define(version: 20171116132928) do
create_table "datasets", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "name", null: false
......@@ -171,6 +171,7 @@ ActiveRecord::Schema.define(version: 20171115133031) do
t.integer "sandbox_state", default: 0, null: false
t.integer "sandbox_version_id"
t.integer "default_job_queue_id", null: false
t.bigint "memory_limit"
t.index ["docker_os_id"], name: "index_webapps_on_docker_os_id", using: :btree
t.index ["name"], name: "index_webapps_on_name", unique: true, using: :btree
t.index ["user_id"], name: "index_webapps_on_user_id", using: :btree
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment