I have scripts web.rb (sinatra) and rufus.rb (cron using rufus gem) running on the same computer (Win XP). Both are using functions.rb where I have all the functions. I have an array variable $webserver_status where I store history of commands web server performed/is performing. The web server runs some dos commands and php scripts and I want to be sure that only one runs at a time and also give the user some overview what is happening.
I used to run cron jobs (rufus.rb) over http so in fact I access the web server as from the browser. So the status variable was updated correctly. Now I started to call the same code from functions.rb so the variable doesn't show correct server status any more.
Is there any way cron can access the $webserver_status variable directly?
Or I have to update the variable over http? Or some kind of status file on the disk?
ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]
web server runs at all times
I have production and testing version of cron code
See the suggestions I made in this answer. The question was essentially the same unless I'm missing something in your scenario. There are many possible solutions depending on your needs.
Edit:
Based on your comment, I'm guessing that you want to share memory across two ruby processes or otherwise communicate between processes. Read about IPC in ruby to see how you could make UNIX sockets suit your needs.
It doesn't really make sense to talk about the same variable being accessed in two processes - you have to go via some kind of intermediary whether it's sockets, a database or a file. If this isn't what you want then I suggest you clarify the situation and why you need shared access to the memory rather than something like this.
I think something like this is what you're looking for:
#web.rb
require './functions'
print_value("apple")
and
#rufus.rb
require './functions'
print_value("not apple")
and
#functions.rb
def print_value(value)
puts value
end
Calling web.rb returns the string Apple.
Related
I'd like to start the server from inside my gem code, the way Rails starts Unicorn, Puma, Webrick or whatever with "rails server". I'd like to have a binary like "mygem server" and that would start Passenger.
I tried with backticks but I'd like to avoid spawning another process if it's at all possible. (Also, I lost the stdout from Passenger when I did that.)
Is the command line the only way to start Passenger?
Passanger is a C++ "gem" that actually runs the Ruby layer separated from the root server process.
The developers consider this approach to protect the server from Ruby related issues (I think this isn't necessary, but it's definitely interesting).
This leaves you with a couple of options:
You could use Kernel.exec which replaces the current process with the command line you provide.
You could use another server, such as Puma, Iodine, Agoo or whatever you fancy.
Each server has their advantages and their disadvantages so test and pick and choose.
I know from experience that you can start all of them from within a block of code (or so I recall).
I want to copy the Scribd developers challenge, but build it using the Gosu framework in ruby. I know how to do most of it, except I'm not 100% sure how to do the following. I'd like a few ideas on the best way to approach this.
Other people (students) will be able to check their ruby code into the repo and I'd like to eventually run all the different bots against each other to determine a winner. Here are my questions about how I would do this.
There is a time limit and ram usage limit. How would you enforce this. Essentially, what I think I want to do is have the game class have a board representation, and then call each engine's main method and pass it in the game board. The method then should return a move. If it doesn't return a move in the time limit, then we move on to the next move. Also, there should be a ram limit such that they can't just iterate over all possibilities and store them in memory and essentially store all the states in the game.
Specifically, how can I spawn a process I can monitor and kill in ruby?
Time and RAM are concerns, sure, but the greater concern is security. Running arbitrary user code on your server invites attacks. What's to prevent a user from uploading code that monkey-patches your app code in order to cheat, or send spam from your server, or break things with FileUtils.rm_rf(__dir__) or while { fork }?
To run user code safely, you must run it in a sandbox. But I'll get back to that.
The simplest way to start (and solve the time/RAM problem) will be to...
Run user code in a separate process
Mandate that the user's script must define a class (or module) with a specific name, e.g. Bot, that implements your main interface. Write a wrapper script that will take as an argument the path to a user's script and read the board data (as Marshaled data, or serialized to YAML or JSON) from $stdin. The script will then require the temporary file and pass the board data to Bot. Finally, it will take the output from Bot, marshal/serialized it, and write it to $stdout.
When a user uploads a script, your app will write it to a temporary file and run the above wrapper script (with e.g. Open3), passing it the marshaled/serialized board data on stdin, then reading and unmarshaling/deserializing the result from its stdout/stderr.
How does this solve the time/RAM problem? Well, since you're just running your wrapper script in a separate process by invoking ruby, you can lean on your OS's process-management features, thus removing the possibility of the user monkey-patching their way around those restrictions. If you google e.g. "limit process memory" along with the name of your OS you'll find lots of information. For example, for Linux this tool looks handy: timeout. With such a tool you might run e.g.:
$ timeout -t 60 -m 10000 ruby /path/to/user/script.rb
Security
Okay, so what about security? It's a hard problem, not least because Ruby is so flexible, and so I can't just tell you "this is the solution."
One thing you could do is run all user code in a virtual machine using e.g. Docker. This would make it easy to prevent the user code from accessing your (real) filesystem or the network. (In this case it may make sense to have a simple Ruby server running on the VM that can receive scripts and board data from your app, run the scripts, and respond with the results, since your app won't be able to directly invoke ruby on the VM.)
This still leaves a lot of room for mischief, though. It mitigates the damage that can be done by FileUtils.rm_rf or while { fork }, as you can just spin up a fresh VM, but that's still an inconvenience. To prevent those entirely, you really need a sandbox that reliably keeps the user from accessing methods and modules that could be used maliciously. There's no One True Way to do this in Ruby, alas, but there are some tools and some code out there that will help you get started. Googling "Ruby sandbox" will turn up a lot. One project I've found instructive is RubyFiddle, which is open source and so its code is available on GitHub. It will point you to jruby-sandbox, which does sandboxing with JRuby because Java, unlike (MRI) Ruby, does have mature sandboxing solutions.
I hope that's helpful. Good luck!
In my ruby on rails project, I have to take pull from sql-server to my mysql database.
When I run my project on port 3000, it makes system busy when I want to take pull.
I want such method or way which system can detect, how many ports are running for ruby application and how to close if it is not in use ?
Thanks in advance.
Hard to understand exactly what you're asking for, but I'm assuming that when you are synchronizing databases, the system becomes busy and you can't serve any pages. This is a perfect example for the use of a background job that allows you to do tasks like this without affecting the rails application. The two gems that come to mind that will allow you to do this is Delayed_job and Resque. An outstanding screencast for doing this type of stuff is listed below as well.
http://github.com/collectiveidea/delayed_job
https://github.com/defunkt/resque/
http://railscasts.com/episodes/171-delayed-job
http://railscasts.com/episodes/271-resque
I want to start my Rails server in a background thread from within a Ruby script. I could use Kernel#system but I want to be able to kill the Rails server when the thread is stopped. Is there a way to execute the Rails server using some Rails API call instead? I'm thinking something it would be nice to be able to put something like Rails.run_server(:port => 3000, ...)
I'm on Windows Server 2008.
Check out the file gems/rails.x.x.x/lib/commands/server.rb. It looks like that's the starting point that script/server uses.
Since script/server is itself a ruby script, it stands to reason that you ought to be able to start a server by doing something similar to what's in server.rb. But I imagine you might have some difficulty getting your ruby environment right...
Note that I'm looking at rails 2.3.8 here, so if you're on 3.whatever your results will probably be different.
I eventually decided to avoid any ickiness and start the rails server in its own process, as detailed in this post. (Being able to kill it plus its child processes consistently was the main blocker and the original reason I'd considered starting it in a thread instead.)
I have a server application that allows users to execute their own ruby scripts. The server that the scripts run on is a virtual instance on Amazon's EC2 so no permanent damage can be done. However I'd like to take whatever precautions I can to stop any dangerous/malicious script, reboots are still something I'd like to avoid.
At the moment I disallow any scripts that contain "require" or "include". I think it would actualy be safe to allow "include"? There is no need for any users to access the server's file system so if I disallow any occurrence of the string "file." will that prevent users being able to access the server's file system?
Disallowing occurrence of the string "file" will not help you at all. They still have eval, pack/unpack, Dir, ` and tons of other stuff.
YMMV, but this is what I would have done:
Run the ruby process as an unprivileged user
in a jailed environment (i.e. chroot, freebsd jail or equivalent)
in a stripped environment (no suids, no other unnecessary files -- bare minimum is best)
with $SAFE >= 2
and with no write access to any files/folders
Probably still not secure, but it's a start.
EDIT: Might also be a good idea to set limits on system resource consumption using ulimit or equivalent.
Sounds like you are in for a guessing game. Wouldn't it be easier to run the scripts as a user with very low privileges? Or you could take a look at how TryRuby solved similar problems.
Seems there are several options for sandboxing Ruby but I haven't used any of them so I can't hand out recommendations.