Porting native applications to OSv

tzach edited this page Nov 8, 2014 · 9 revisions
Clone this wiki locally

There are two way to run a native (e.g. C/C++) app on OSv:

  • Upload and call it on run time
  • Create a "precooked" appliance of OSv and the application

Once launching an appliance, it will automatically start both OSv and the application on top of it.

On both cases, the application has to be in a shared library format (.so). More on how to create a share library from an existing application here

Upload and call application on run time

Assuming you have a a shared library x.so you want to run. You will need to:

  1. Upload the library to OSv file system
  2. Call it
Upload an image to OSv file system:

To upload a file to OSv, you can use either:

  • REST API
  • REST API Dashboard (which use REST API)

To upload a file using REST API:

curl -F filedata=@temp-test-file.txt http://osv-ip:8000/file/{path}/

Where osv-ip is the OSv VM IP. To upload a file using Dashboard, brows to http://osv-ip:8000, click the REST button, and choose POST file/

Run the application

To Run application, use the POST /app/ REST API.

Create a OSv appliance

The easiest way to create an OSv appliance is using Capstan. Go check it out!

Examples of Capstan-enabled applications

Problems you may run into

We do not yet have full POSIX compatibility, so when running a new application you may encounter symbols that are not yet there. A list of applications that are known to work (as in specifically tested by us) can be found at our osv-apps repository.

Missing symbols

The most common issue one will encounter is a missing symbol. This is a real example from the enablement of redis:

Failed looking up symbol __register_atfork

[backtrace]
0x31a7f3 <elf::object::resolve_pltgot(unsigned int)+83>
0x35fbb3 <__elf_resolve_pltgot+47>
0x31c8e5 <elf::program::get_library(std::string, std::vector<std::string, std::allocator<std::string> >)+1317>
0x3b7734 <osv::run(std::string, int, char**, int*)+132>
0x3b7b80 <osv::run(std::string, std::vector<std::string, std::allocator<std::string> >, int*)+576>
0x20d366 <run_main(std::vector<std::string, std::allocator<std::string> > const&)+246>
0x20ef10 <do_main_thread(void*)+1024>
0x3fd6a6 <sync+70>
0x3a246b <thread_main_c+27>
0x360f06 <call_signal_handler_thunk+0>

As we currently don't have fork() support, all we need to do is provide an empty implementation to keep the program happy. See for instance the following example of how it can be fixed. Of course depending on what function you run into, it does have to be implemented in a proper way.

Some other applications tend to call the system calls directly. It is not common, but it does happen. In those cases, our syscall() implementation should show you the missing one:

syscall(): unimplemented system call 1. Aborting.

[backtrace]
0x1000000bf2ab <malloc_vcprintf+43>

We can see in this example, that the syscall "1" is missing. That corresponds to the write() system call. Here is an example of an implementation.

For most of the system calls, this implementation should be extremely trivial: it is just a matter of passing the right arguments to the corresponding function. Maybe at some point it will be even automatic.

Symbols with incorrect implementation

We try to keep implementation of symbols as simple as possible in order to support the applications. For example, if an application just calls into a symbol but is not interested at all in its output, just providing the symbol may be enough (see for instance the register_atfork in this same document). We tend to move to more significant work in those cases, and mark the function as WARN_STUBBED (See /include/osv/stubbing.hh)

But for other applications that same usage may not be enough. Those warnings are only visible when OSv is running in verbose mode. Assuming you are running OSv from the standalone command line as explained in our README, you need to add the -V switch to see those. For example:

[glauber@localhost osv]$ ./scripts/run.py -V
[...]
[I/35 dhcp]: Waiting for IP...
[I/206 dhcp]: Server acknowledged IP for interface eth0
[I/206 dhcp]: Configuring eth0: ip 192.168.122.15 subnet mask 255.255.255.0 gateway 192.168.122.1 MTU 0
pthread_mutexattr_init() stubbed   <=== Look here

If a stubbed function is affecting an application or not, is something that requires knowledge of application semantics to decide. But if something is misbehaving, looking at stubbed functions is a great start.