Skip to content

Commit

Permalink
Merge 81f53d3 into 893446d
Browse files Browse the repository at this point in the history
  • Loading branch information
relf committed Apr 5, 2020
2 parents 893446d + 81f53d3 commit a1fa3fe
Show file tree
Hide file tree
Showing 80 changed files with 4,217 additions and 645 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,5 @@ config/configuration.yml
config/database.yml
config/ldap.yml

# Ignore OneraMDAO
services/whatsopt_server/optimizer_store/oneramdao
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ install:
- pip install salib
- pip install thrift
- pip install openturns
- pip install -e services
- python --version
- pip list

Expand All @@ -65,7 +66,7 @@ install:
before_script:
- cp config/configuration.yml.example config/configuration.yml
- cp config/database.yml.example config/database.yml
- mkdir -p upload/logs upload/surrogate_store
- mkdir -p upload/store
- RAILS_ENV=test bundle exec rake db:schema:load
- bundle exec rake db:test:prepare
- RAILS_ENV=test bundle exec rake webpacker:compile
Expand Down
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ RUN bundle install --jobs 20 --retry 5

COPY . ./

RUN pip install -e services/whatsopt_server/optimizer_store/oneramdao/doe \
&& pip install -e services/whatsopt_server/optimizer_store/oneramdao/kpls \
&& pip install -e services/whatsopt_server/optimizer_store/oneramdao/mfk \
&& pip install -e services/whatsopt_server/optimizer_store/oneramdao/moe \
&& pip install -e services/whatsopt_server/optimizer_store/oneramdao/sego \
&& pip install -e services

EXPOSE 3000

CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
Expand Down
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ gem "jbuilder", "~> 2.7"
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", ">= 1.4.2", require: false

# Protect from rogue client
gem "rack-attack"

# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ GEM
pundit (2.1.0)
activesupport (>= 3.0.0)
rack (2.0.7)
rack-attack (6.2.2)
rack (>= 1.0, < 3)
rack-cors (1.1.0)
rack (>= 2.0.0)
rack-proxy (0.6.5)
Expand Down Expand Up @@ -444,6 +446,7 @@ DEPENDENCIES
popper
puma (~> 4.1)
pundit
rack-attack
rack-cors (>= 1.0.5)
rails (~> 6.0.1)
rails-assets-tether (>= 1.1.0)!
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.6.1
1.7.0
49 changes: 49 additions & 0 deletions app/controllers/api/v1/optimizations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

class Api::V1::OptimizationsController < Api::ApiController
before_action :set_optimization, only: [:show, :update, :destroy]

# GET /api/v1/optimizations/1
def show
json_response @optim
end

# POST /api/v1/optimizations
def create
@optim = Optimization.new(optim_params)
authorize @optim
@optim.save!
@optim.create_optimizer
@optim.set_owner(current_user)
json_response @optim, :created
end

# PATCH /api/v1/optimizations/1
def update
@optim.check_optimization_inputs(optim_params)
inputs = {x: optim_params['x'], y: optim_params['y']}
@optim.update!(inputs: inputs, outputs: {status: Optimization::RUNNING, x_suggested: nil})
OptimizationJob.perform_later(@optim)
head :no_content
end

# DELETE /api/v1/optimizations/1
def destroy
@proxy.destroy_optimizer
@optim.destroy!
head :no_content
end

private

def set_optimization
@optim = Optimization.find(params[:id])
@proxy = @optim.proxy
authorize @optim
end

def optim_params
params.require(:optimization).permit!
end

end
15 changes: 15 additions & 0 deletions app/controllers/concerns/exception_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,20 @@ module ExceptionHandler
json_response({ message: e.message }, :forbidden)
end

rescue_from Optimization::ConfigurationInvalid do |e|
Rails.logger.error "Invalid configuration : " + e.message
json_response({ message: e.message }, :bad_request)
end

rescue_from Optimization::InputInvalid do |e|
Rails.logger.error "Invalid inputs : " + e.message
json_response({ message: e.message }, :bad_request)
end

# Never catch here as the optimizer computation is asynchronous now
# rescue_from WhatsOpt::Services::OptimizerException do |e|
# Rails.logger.error "Optimization error : " + e.message
# json_response({ message: e.message }, :unprocessable_entity)
# end
end
end
7 changes: 7 additions & 0 deletions app/jobs/optimization_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class OptimizationJob < ActiveJob::Base
def perform(optim)
optim.perform
end
end
55 changes: 55 additions & 0 deletions app/lib/whats_opt/optimizer_proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require "thrift"
require "optimizer_store"

module WhatsOpt
class OptimizerProxy < ServiceProxy

CSTRS_TYPES = {
'<' => WhatsOpt::Services::ConstraintType::LESS,
'=' => WhatsOpt::Services::ConstraintType::EQUAL,
'>' => WhatsOpt::Services::ConstraintType::GREATER,
}

def _initialize
@protocol = Thrift::MultiplexedProtocol.new(
@protocol, "OptimizerStoreService"
)
@client = Services::OptimizerStore::Client.new(@protocol)
end

def create_optimizer(optimizer_kind, xlimits, cstr_specs=[], options={})
opts = {}
options.each do |ks, v|
k = ks.to_s
opts[k] = Services::OptionValue.new(matrix: v) if v.to_s =~ /^\[\[.*\]\]$/
opts[k] = Services::OptionValue.new(vector: v) if (!opts[k] && v.to_s =~ /^\[.*\]$/)
opts[k] = Services::OptionValue.new(integer: v.to_i) if (!opts[k] && v.to_s == v.to_i.to_s)
opts[k] = Services::OptionValue.new(number: v.to_f) if (!opts[k] && v.to_s =~ /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/)
opts[k] = Services::OptionValue.new(str: v.to_s) unless opts[k]
end
cspecs = cstr_specs.map do |cspec|
Services::ConstraintSpec.new(type: CSTRS_TYPES[cspec[:type]] || '?', bound: cspec[:bound])
end
_send { @client.create_optimizer(@id, optimizer_kind, xlimits, cspecs.compact, opts) }
end

def ask()
res = nil
_send { res = @client.ask(@id) }
res
end

def tell(x, y)
_send {
@client.tell(@id, x, y)
}
end

def destroy_optimizer
_send { @client.destroy_optimizer(@id) }
end

end
end
95 changes: 95 additions & 0 deletions app/lib/whats_opt/service_proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# frozen_string_literal: true

require "thrift"
require "securerandom"
require "administration"

module WhatsOpt
class ServiceProxy
attr_reader :id, :pid, :host, :port

PYTHON = APP_CONFIG["python_cmd"] || "python"
OUTDIR = File.join(Rails.root, "upload", "store")

DEFAULT_HOST = "localhost"
DEFAULT_PORT = 41400

def initialize(id: nil, host: DEFAULT_HOST, port: DEFAULT_PORT, server_start: true)
@host = host
@port = port
socket = Thrift::Socket.new(@host, @port)
@transport = Thrift::BufferedTransport.new(socket)
@protocol = Thrift::BinaryProtocol.new(@transport)

@admin_protocol = Thrift::MultiplexedProtocol.new(
@protocol, "AdministrationService"
)
@admin_client = Services::Administration::Client.new(@admin_protocol)

@id = id || SecureRandom.uuid

self._initialize

if server_start && !server_available?
cmd = "#{PYTHON} #{File.join(Rails.root, 'services', 'run_server.py')} --outdir #{OUTDIR}"
Rails.logger.info cmd
@pid = spawn(cmd, [:out, :err] => File.join(Rails.root, "log", "whatsopt_server.log"))
retries = 0
while retries < 10 && !server_available? # wait for server start
retries += 1
sleep(1)
end
end

end

def _initialize
raise "not yet implemented"
end

def self.shutdown_server(host: DEFAULT_HOST, port: DEFAULT_PORT)
socket = Thrift::Socket.new(host, port)
transport = Thrift::BufferedTransport.new(socket)
protocol = Thrift::BinaryProtocol.new(transport)
admin_protocol = Thrift::MultiplexedProtocol.new(
protocol, "AdministrationService"
)
client = Services::Administration::Client.new(admin_protocol)
transport.open()
client.shutdown
rescue => e
Rails.logger.warn e
else
transport.close()
end

def self.kill_server(pid)
if pid
p "KILL #{pid}"
Process.kill("TERM", pid)
Process.waitpid pid
end
end

def server_available?
_send { @admin_client.ping }
end

def _send
@transport.open()
yield
rescue Services::SurrogateException => e
# puts "#{e}: #{e.msg}"
Rails.logger.warn "#{e}: #{e.msg}"
raise
rescue Thrift::TransportException => e
# puts "#{e}"
Rails.logger.warn e
false
else
true
ensure
@transport.close()
end
end
end

0 comments on commit a1fa3fe

Please sign in to comment.