fixed a few errors and typos
diff --git a/README.md b/README.md
index e69de29..5e25b9e 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,89 @@
+# Apache OpenWhisk runtimes for Ruby
+
+### Give it a try today
+To use as a docker action
+```
+wsk action update myAction my_action.rb --docker openwhisk/action-ruby-v2.5
+```
+This works on any deployment of Apache OpenWhisk
+
+### To use on deployment that contains the rutime as a kind
+To use as a kind action
+```
+wsk action update myAction my_action.rb --kind ruby:2.5
+```
+
+### Local development
+```
+./gradlew core:ruby2.5Action:distDocker
+```
+This will produce the image `whisk/action-ruby-v2.5`
+
+Build and Push image
+```
+docker login
+./gradlew core:ruby2.5Action:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io
+```
+
+Deploy OpenWhisk using ansible environment that contains the kind `ruby:2.5`
+Assuming you have OpenWhisk already deploy localy and `OPENWHISK_HOME` pointing to root directory of OpenWhisk core repository.
+
+Set `ROOTDIR` to the root directory of this repository.
+
+Redeploy OpenWhisk
+```
+cd $OPENWHISK_HOME/ansible
+ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local"
+$ANSIBLE_CMD setup.yml
+$ANSIBLE_CMD couchdb.yml
+$ANSIBLE_CMD initdb.yml
+$ANSIBLE_CMD wipe.yml
+$ANSIBLE_CMD openwhisk.yml
+```
+
+Or you can use `wskdev` and create a soft link to the target ansible environment, for example:
+```
+ln -s ${ROOTDIR}/ansible/environments/local ${OPENWHISK_HOME}/ansible/environments/local-ruby
+wskdev fresh -t local-ruby
+```
+
+To use as docker action push to your own dockerhub account
+```
+docker tag whisk/ruby2.5Action $user_prefix/action-ruby-v2.5
+docker push $user_prefix/action-ruby-v2.5
+```
+Then create the action using your the image from dockerhub
+```
+wsk action update myAction my_action.rb --docker $user_prefix/action-ruby-v2.5
+```
+The `$user_prefix` is usually your dockerhub user id.
+
+### Testing
+Install dependencies from the root directory on $OPENWHISK_HOME repository
+```
+./gradlew install
+```
+
+Using gradle for the ActionContainer tests you need to use a proxy if running on Mac, if Linux then don't use proxy options
+You can pass the flags `-Dhttp.proxyHost=localhost -Dhttp.proxyPort=3128` directly in gradle command.
+Or save in your `$HOME/.gradle/gradle.properties`
+```
+systemProp.http.proxyHost=localhost
+systemProp.http.proxyPort=3128
+```
+Using gradle to run all tests
+```
+./gradlew :tests:test
+```
+Using gradle to run some tests
+```
+./gradlew :tests:test --tests *ActionContainerTests*
+```
+Using IntelliJ:
+- Import project as gradle project.
+- Make sure working directory is root of the project/repo
+- Add the following Java VM properties in ScalaTests Run Configuration, easiest is to change the Defaults for all ScalaTests to use this VM properties
+```
+-Dhttp.proxyHost=localhost
+-Dhttp.proxyPort=3128
+```
diff --git a/core/ruby2.5Action/config.ru b/core/ruby2.5Action/config.ru
index 6b478fc..93c460d 100644
--- a/core/ruby2.5Action/config.ru
+++ b/core/ruby2.5Action/config.ru
@@ -4,40 +4,6 @@
require 'json'
require 'zip'
require 'base64'
-
-#====== For Debugging Purpose Only
-module RackHelper
- require 'uri'
- require 'net/http'
- class << self
- def _p(name, value)
- "#{name}: #{value}\n\n-------\n"
- end
-
- def log(value)
- url = URI("http://SOME_URL_SUCH_AS_MOCKBIN/")
- http = Net::HTTP.new(url.host, url.port)
-
- req = Net::HTTP::Post.new(url)
- req["accept"] = 'application/json'
- req["content-type"] = 'application/x-www-form-urlencoded'
- req.body = value
- response = http.request(req)
- end
-
- def debug(env)
- request = Rack::Request.new(env)
- log _p(:ENV, ENV.to_a) +
- _p(:request_params, request.params.to_a) +
- _p(:request_env, request.env) +
- _p(:request_POST, request.POST) +
- _p(:body, request.body.read)
- end
-
- end
-end
-#====== For Debugging Purpose Only
-
require "#{__dir__}/rackapp/middleware/post_method_validation.rb"
require "#{__dir__}/rackapp/middleware/sentinel_handler.rb"
require "#{__dir__}/rackapp/init.rb"
@@ -47,26 +13,10 @@
use HTTPPostMethodValidation
use SentinelHandler
- # {
- # "value":{
- # "name": "myAction",
- # "binary": false,
- # "main": "main",
- # "code": "def main(params) {\\n {payload: \\\"length = \\\" + params.to_s}\\n}\\n\"
- # }
- # }
map '/init' do
run InitApp.new
end
- # {
- # "activation_id": "91f9fa332a424e35b9fa332a423e35fd",
- # "action_name": "/guest/myAction",
- # "deadline": "1526980345727",
- # "api_key": "23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP",
- # "value": {\"message\":\"hello\"},
- # "namespace": "guest"
- # }
map "/run" do
run RunApp.new
end
diff --git a/core/ruby2.5Action/rackapp/init.rb b/core/ruby2.5Action/rackapp/init.rb
index 3f85770..d5316e8 100644
--- a/core/ruby2.5Action/rackapp/init.rb
+++ b/core/ruby2.5Action/rackapp/init.rb
@@ -3,11 +3,11 @@
require "#{__dir__}/filepath.rb"
class InitApp
+ include Filepath
+
def call(env)
- # RackHelper.debug env
# Expect JSON data input
body = Rack::Request.new(env).body.read
- RackHelper.log body
data = JSON.parse(body)['value'] || {}
name = data['name'] || '' # action name
main = data['main'] || '' # function to call
@@ -19,50 +19,44 @@
return ErrorResponse.new 'Invalid Parameters: failed to handle the request', 500
end
- RackHelper.log env.to_json
- env = {'BUNDLE_GEMFILE' => Filepath::PROGRAM_DIR + 'Gemfile'}
+ env = {'BUNDLE_GEMFILE' => PROGRAM_DIR + 'Gemfile'}
if binary then
- File.write Filepath::TMP_ZIP, Base64.decode64(code)
- if !unzip(Filepath::TMP_ZIP, Filepath::PROGRAM_DIR) then
+ File.write TMP_ZIP, Base64.decode64(code)
+ if !unzip(TMP_ZIP, PROGRAM_DIR) then
return ErrorResponse.new 'Invalid Binary: failed to open zip file. Please make sure you have finishied $bundle package successfully.', 500
end
- RackHelper.log `ls -alR #{Filepath::PROGRAM_DIR}`
# Try to resolve dependencies
- if File.exist?(Filepath::PROGRAM_DIR + 'Gemfile') then
- if !File.directory?(Filepath::PROGRAM_DIR + 'vendor/cache') then
+ if File.exist?(PROGRAM_DIR + 'Gemfile') then
+ if !File.directory?(PROGRAM_DIR + 'vendor/cache') then
return ErrorResponse.new 'Invalid Binary: vendor/cache folder is not found. Please make sure you have used valid zip binary.', 200
end
- if !system(env, "bundle install --local 2> #{Filepath::ERR} 1> #{Filepath::OUT}") then
- return ErrorResponse.new "Invalid Binary: failed to resolve dependencies / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}", 500
+ if !system(env, "bundle install --local 2> #{ERR} 1> #{OUT}") then
+ return ErrorResponse.new "Invalid Binary: failed to resolve dependencies / #{File.read(OUT)} / #{File.read(ERR)}", 500
end
else
File.write env['BUNDLE_GEMFILE'], '' # For better performance, better to remove Gemfile and remove "bundle exec" redundant call when binary=false. To be improved in future.
end
- if !File.exist?(Filepath::ENTRYPOINT) then
+ if !File.exist?(ENTRYPOINT) then
return ErrorResponse.new 'Invalid Ruby Code: zipped actions must contain main.rb at the root.', 500
end
else
# Save the code for future use
- File.write Filepath::ENTRYPOINT, code
+ File.write ENTRYPOINT, code
File.write env['BUNDLE_GEMFILE'], '' # For better performance, better to remove Gemfile and remove "bundle exec" redundant call when binary=false. To be improved in future.
end
# Check if the ENTRYPOINT code is valid or not
- RackHelper.log "TRACK-Zero"
- if !valid_code?(Filepath::ENTRYPOINT) then
- RackHelper.log "TRACK-alpha / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}"
+ if !valid_code?(ENTRYPOINT) then
return ErrorResponse.new 'Invalid Ruby Code: failed to parse the input code', 500
end
- RackHelper.log "TRACK-A"
# Check if the method exists as expected
- if !system(env, "bundle exec ruby -r #{Filepath::ENTRYPOINT} -e \"method(:#{main}) ? true : raise(Exception.new('Error'))\" 2> #{Filepath::ERR} 1> #{Filepath::OUT}") then
- return ErrorResponse.new "Invalid Ruby Code: method checking failed / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}", 500
+ if !system(env, "bundle exec ruby -r #{ENTRYPOINT} -e \"method(:#{main}) ? true : raise(Exception.new('Error'))\" 2> #{ERR} 1> #{OUT}") then
+ return ErrorResponse.new "Invalid Ruby Code: method checking failed / #{File.read(OUT)} / #{File.read(ERR)}", 500
end
- RackHelper.log "TRACK-B"
# Save config parameters to filesystem so that later /run can use this
- File.write Filepath::CONFIG, {:main=>main, :name=>name}.to_json
+ File.write CONFIG, {:main=>main, :name=>name}.to_json
# Proceed with the next step
SuccessResponse.new({'OK'=>true})
@@ -70,7 +64,7 @@
private
def valid_code?(path)
- system("ruby -e 'RubyVM::InstructionSequence.compile_file(\"#{path}\")' 2> #{Filepath::ERR} 1> #{Filepath::OUT}")
+ system("ruby -e 'RubyVM::InstructionSequence.compile_file(\"#{path}\")' 2> #{ERR} 1> #{OUT}")
rescue
false
end
diff --git a/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
index 92f57ad..3d1d1bf 100644
--- a/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
+++ b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
@@ -3,7 +3,6 @@
class SentinelHandler < MiddlewareBase
def call(env)
response = @app.call(env)
- RackHelper.log response.status.to_json
if !(env['REQUEST_PATH'] == '/init' && response.status == 200) then
puts response.body if response.status!=200
puts "XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"
diff --git a/core/ruby2.5Action/rackapp/response/error.rb b/core/ruby2.5Action/rackapp/response/error.rb
index f7c9365..57d9584 100644
--- a/core/ruby2.5Action/rackapp/response/error.rb
+++ b/core/ruby2.5Action/rackapp/response/error.rb
@@ -1,6 +1,5 @@
class ErrorResponse < Rack::Response
def initialize(body = [], status = 500, header = {})
- RackHelper.log body.to_s + caller.to_json
super({:error=>body}.to_json, status, header.merge({'Content-Type' => 'application/json'}))
end
end
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/run.rb b/core/ruby2.5Action/rackapp/run.rb
index 9735639..c4699d2 100644
--- a/core/ruby2.5Action/rackapp/run.rb
+++ b/core/ruby2.5Action/rackapp/run.rb
@@ -3,35 +3,31 @@
require "#{__dir__}/filepath.rb"
class RunApp
+ include Filepath
+
def call(env)
- RackHelper.log "YES"
- if !File.exist? Filepath::ENTRYPOINT then
+ if !File.exist? ENTRYPOINT then
return ErrorResponse.new 'Invalid Action: no action file found', 500
end
# Set environment variables
- RackHelper.log "NO"
body = Rack::Request.new(env).body.read
data = JSON.parse(body) || {}
- env = {'BUNDLE_GEMFILE' => Filepath::PROGRAM_DIR + 'Gemfile'}
+ env = {'BUNDLE_GEMFILE' => PROGRAM_DIR + 'Gemfile'}
['api_key', 'namespace', 'action_name', 'activation_id', 'deadline'].each{|e|
env["__OW_#{e.upcase}"] = data[e] if data[e] && data[e].is_a?(String)
}
# Save parameter values to file in order to let runner.rb read this later
- File.write Filepath::PARAM, data['value'].to_json
+ File.write PARAM, data['value'].to_json
# Execute the action with given parameters
- RackHelper.log File.read(Filepath::PARAM)
- if system(env, "bundle exec ruby -r #{Filepath::ENTRYPOINT} #{Filepath::RACKAPP_DIR}runner.rb | tee #{Filepath::OUT}") then
- if File.exist? Filepath::RESULT then
- result = File.read(Filepath::RESULT)
- RackHelper.log result
+ if system(env, "bundle exec ruby -r #{ENTRYPOINT} #{RACKAPP_DIR}runner.rb | tee #{OUT}") then
+ if File.exist? RESULT then
+ result = File.read(RESULT)
if valid_json?(result) then
- RackHelper.log "B"
SuccessResponse.new(JSON.parse(result))
else
- RackHelper.log "C"
warn "Result must be an array but has type '#{result.class.to_s}': #{result}"
ErrorResponse.new 'The action did not return a dictionary.', 502
end
@@ -39,8 +35,7 @@
ErrorResponse.new 'Invalid Action: An error occurred running the action', 502
end
else
- RackHelper.log File.read(Filepath::OUT) || "(No stdout found)"
- ErrorResponse.new "Invalid Action: the execution was not successful. / #{File.read(Filepath::OUT)}}", 502
+ ErrorResponse.new "Invalid Action: the execution was not successful. / #{File.read(OUT)}}", 502
end
end