Hi, I have just committed a patch that addresses your comments. It also enhances it enough to allow running OSv with block and networking devices or firecracker. So once we have other 3 outstanding patches reviewed and merged we should have full firecracker support and be able to test it using this latest version the scripts/firecracker.py.
On Sunday, March 3, 2019 at 10:26:02 AM UTC-5, Waldek Kozaczuk wrote: > > I will definitely be sending a follow-up patch to address your concerns as > well as support block and networking devices. > > On Sunday, March 3, 2019 at 4:34:29 AM UTC-5, Nadav Har'El wrote: >> >> >> On Fri, Feb 22, 2019 at 4:15 PM Waldemar Kozaczuk <[email protected]> >> wrote: >> >>> This patch adds simple Python script that allows >>> booting OSv loader.elf on firecracker. >>> >>> It also automates process of downloading and installing >>> firecracker. Evenntually it might be incorporated >>> into scripts/run.py >>> >> >> I committed your patch, but have a few comments below for your >> consideration for future incremental patches. >> Thanks! >> >> >>> Signed-off-by: Waldemar Kozaczuk <[email protected]> >>> --- >>> scripts/firecracker.py | 126 +++++++++++++++++++++++++++++++++++++++++ >>> 1 file changed, 126 insertions(+) >>> create mode 100755 scripts/firecracker.py >>> >>> diff --git a/scripts/firecracker.py b/scripts/firecracker.py >>> new file mode 100755 >>> index 00000000..bed4cf58 >>> --- /dev/null >>> +++ b/scripts/firecracker.py >>> @@ -0,0 +1,126 @@ >>> +#!/usr/bin/env python >>> +# >>> +# pip install requests-unixsocket >>> >> >> >> I had an annoying Python problem that's not related to your code, of >> course, but maybe other people will encounter too. >> Trying to run firecracker.py I got Python errors complaining that urllib3 >> is trying to use ".util.queue" and it's missing. >> Or something like that. Took my a while to figure out that my urllib3, >> which in the past I got from some manual >> "pip install", was somehow broken. I had to manually remove it, and >> install from Fedora's package: >> >> # rm -r /usr/lib/python2.7/site-packages/urllib3 >> # dnf install python2-urllib >> >> I don't know why this happens, but if someone else has the same problem >> on Fedora 29, you can save a few minutes of frustration by doing the above. >> >> >>> +import sys >>> +import os >>> +import stat >>> +import json >>> +import subprocess >>> +import time >>> +from os.path import expanduser >>> +from datetime import datetime >>> +import requests_unixsocket >>> + >>> + >>> +class ApiClient(object): >>> + def __init__(self, domain_socket_path): >>> + self.socket_path = domain_socket_path >>> + self.session = requests_unixsocket.Session() >>> + >>> + def api_socket_url(self, path): >>> + return "http+unix://%s%s" % (self.socket_path, path) >>> + >>> + def make_put_call(self, path, request_body): >>> + url = self.api_socket_url(path) >>> + res = self.session.put(url, data=json.dumps(request_body)) >>> + print("%s: %s" % (path, res.status_code)) >>> + if res.status_code != 204: >>> + print(res.text) >>> + return res.status_code >>> + >>> + def create_instance(self, kernel_image_path, cmdline): >>> + self.make_put_call('/boot-source', { >>> + 'kernel_image_path': kernel_image_path, >>> + 'boot_args': cmdline >>> + }) >>> + >>> + def start_instance(self): >>> + self.make_put_call('/actions', { >>> + 'action_type': 'InstanceStart' >>> + }) >>> + >>> + def configure_logging(self): >>> + self.make_put_call('/logger', { >>> + "log_fifo": "log.fifo", >>> + "metrics_fifo": "metrics.fifo", >>> + "level": "Info", >>> + "show_level": True, >>> + "show_log_origin": True >>> + }) >>> + >>> + >>> +def print_time(msg): >>> + now = datetime.now() >>> + print("%s: %s" % (now.strftime('%H:%M:%S.%f'), msg)) >>> + >>> + >>> +# Check if firecracker is installed >>> +home_dir = expanduser("~") >>> +firecracker_path = os.path.join(home_dir, '.firecracker/firecracker') >>> >> >> Personally I would prefer that instead of this appearing in my home >> directory, we would just put firecracker in the current directory, i.e., >> the OSv build directory. >> It's just 6MB, and if you "strip" it (we should. I don't know why it >> isn't stripped by default!), it's just 2MB. Nobody will complain that each >> OSv build directory will have a copy of that 2MB. >> >> So you can honor FIRECRACKER_PATH below to allow a user to set a fixed >> location, but I'd personally prefer the default to be "." (or >> "./firecracker" or whatever it needs to be). >> >> >> +if os.environ.get('FIRECRACKER_PATH'): >>> + firecracker_path = os.environ.get('FIRECRACKER_PATH') >>> + >>> +# And offer to install if not found >>> +if not os.path.exists(firecracker_path): >>> + download_url = ' >>> https://github.com/firecracker-microvm/firecracker/releases/download/v0.14.0/firecracker-v0.14.0 >>> ' >>> + answer = raw_input("Firecracker executable has not been found under >>> %s. " >>> + "Would you like to download it from %s and place >>> it under %s? [y|Y]" % >>> >> >> "y/Y"? That's like an offer I cannot refuse :-) >> Looking at the code below, I guess you meant "y/N"? >> >> >>> + (firecracker_path, download_url, >>> firecracker_path)) >>> + if answer.capitalize() != 'Y': >>> >> + print("Firecracker not available. Exiting ...") >>> + sys.exit(-1) >>> + >>> + directory = os.path.dirname(firecracker_path) >>> + if not os.path.exists(directory): >>> + os.mkdir(directory) >>> + subprocess.call(['wget', download_url, '-O', firecracker_path]) >>> + os.chmod(firecracker_path, stat.S_IRUSR | stat.S_IXUSR) >>> + >>> +# Firecracker is installed so lets start >>> +print_time("Start") >>> +socket_path = '/tmp/firecracker.socket' >>> + >>> +# Delete socker file if exists >>> >> >> socket >> >> +if os.path.exists(socket_path): >>> + os.unlink(socket_path) >>> + >>> +# Start firecracker process to communicate over specified UNIX socker >>> file >>> >> >> socket >> >> +firecracker = subprocess.Popen([firecracker_path, '--api-sock', >>> socket_path], >>> + stdin=subprocess.PIPE, >>> stdout=sys.stdout, >>> + stderr=subprocess.STDOUT) >>> + >>> +# Prepare arguments we are going to pass when creating VM instance >>> +dirname = os.path.dirname(os.path.abspath(__file__)) >>> +kernel_path = os.path.join(dirname, >>> '../build/release/loader-stripped.elf') >>> + >>> +if len(sys.argv) > 1: >>> + cmdline = sys.argv[1] >>> +else: >>> + with open(os.path.join(dirname, '../build/release/cmdline'), 'r') >>> as f: >>> + cmdline = f.read() >>> + >>> +# Create API client and make API calls >>> +client = ApiClient(socket_path.replace("/", "%2F")) >>> + >>> +try: >>> + # Very often on the very first run firecracker process >>> + # is not ready yet to accept calls over socket file >>> + # so we poll existence of this file as an good >>> + # enough indicator of firecracker readyness >>> + while not os.path.exists(socket_path): >>> + time.sleep(0.01) >>> + print_time("Firecracker ready") >>> + >>> + client.create_instance(kernel_path, cmdline) >>> + print_time("Created OSv VM") >>> + >>> + client.start_instance() >>> + print_time("Booted OSv VM") >>> +except Exception as e: >>> + print("Failed to run OSv on firecracker due to: ({0}): {1} >>> !!!".format(e.errno, e.strerror)) >>> + firecracker.kill() >>> + exit(-1) >>> + >>> +print_time("Waiting for firecracker process to terminate") >>> +firecracker.wait() >>> +print_time("End") >>> >> >> In my case, where I didn't apply some of your patches yet so OSv doesn't >> really work with firecracker, I didn't get an exception above, but got: >> >> 11:30:12.743018: Created OSv VM >> 2019-03-03T11:30:12.748831329 [anonymous-instance:ERROR:vmm/src/ >> sigsys_handler.rs:70] Shutting down VM after intercepting a bad syscall >> (131). >> 2019-03-03T11:30:12.748820490 [anonymous-instance:ERROR:vmm/src/ >> lib.rs:1206] Failed to log metrics while stopping: Logger was not >> initialized. >> 2019-03-03T11:30:12.748871644 [anonymous-instance:ERROR:vmm/src/ >> sigsys_handler.rs:76] Failed to log metrics while stopping: Logger was >> not initialized. >> /actions: 204 >> 11:30:12.749496: Booted OSv VM >> 11:30:12.749533: Waiting for firecracker process to terminate >> 11:30:12.757930: End >> >> I can understand it's some sort of error, but it's not very clear what it >> means. >> Anyway, not critical - it's more important that it works *with* your >> patches to make it work :-) >> >> -- >>> 2.19.1 >>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "OSv Development" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to [email protected]. >>> For more options, visit https://groups.google.com/d/optout. >>> >> -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
