Pushed by YOCaml 2
This commit is contained in:
parent
b0defe67bd
commit
36a581e53e
6 changed files with 518 additions and 4 deletions
479
articles/arguments.html
Normal file
479
articles/arguments.html
Normal file
|
@ -0,0 +1,479 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>
|
||||||
|
Robur's blogRuntime arguments in MirageOS
|
||||||
|
</title>
|
||||||
|
<meta name="description" content="The history of runtime arguments to a MirageOS unikernel">
|
||||||
|
<link type="text/css" rel="stylesheet" href="https://blog.robur.coop/css/hl.css">
|
||||||
|
<link type="text/css" rel="stylesheet" href="https://blog.robur.coop/css/style.css">
|
||||||
|
<script src="https://blog.robur.coop/js/hl.js"></script>
|
||||||
|
<link rel="alternate" type="application/rss+xml" href="https://blog.robur.coop/feed.xml" title="blog.robur.coop">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>blog.robur.coop</h1>
|
||||||
|
<blockquote>
|
||||||
|
The <strong>Robur</strong> cooperative blog.
|
||||||
|
</blockquote>
|
||||||
|
</header>
|
||||||
|
<main><a href="https://blog.robur.coop/index.html">Back to index</a>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<h1>Runtime arguments in MirageOS</h1>
|
||||||
|
<ul class="tags-list"><li><a href="https://blog.robur.coop/tags.html#tag-OCaml">OCaml</a></li><li><a href="https://blog.robur.coop/tags.html#tag-MirageOS">MirageOS</a></li></ul><p>TL;DR: Passing runtime arguments around is tricky, and prone to change every other month.</p>
|
||||||
|
<h2 id="motivation"><a class="anchor" aria-hidden="true" href="#motivation"></a>Motivation</h2>
|
||||||
|
<p>Sometimes, as an unikernel developer and also as operator, it's nice to have
|
||||||
|
some runtime arguments passed to an unikernel. Now, if you're into OCaml,
|
||||||
|
command-line parsing - together with error messages, man page generation, ... -
|
||||||
|
can be done by the amazing <a href="https://erratique.ch/software/cmdliner">cmdliner</a>
|
||||||
|
package from Daniel Bünzli.</p>
|
||||||
|
<p>MirageOS uses cmdliner for command line argument passing. This also enabled
|
||||||
|
us from the early days to have nice man pages for unikernels (see
|
||||||
|
<code>my-unikernel-binary --help</code>). There are two kinds
|
||||||
|
of arguments: those at configuration time (<code>mirage configure</code>), such as the
|
||||||
|
target to compile for, and those at runtime - when the unikernel is executed.</p>
|
||||||
|
<p>In Mirage 4.8.1 and 4.8.0 (released October 2024) there have been some changes
|
||||||
|
to command-line arguments, which were motivated by 4.5.0 (released April 2024)
|
||||||
|
and user feedback.</p>
|
||||||
|
<p>First of all, our current way to pass a custom runtime argument to a unikernel
|
||||||
|
(<code>unikernel.ml</code>):</p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
open Cmdliner
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Arg.info ~doc:"How to say hello." [ "hello" ] in
|
||||||
|
let term = Arg.(value & opt string "Hello World!" doc) in
|
||||||
|
Mirage_runtime.register_arg term
|
||||||
|
|
||||||
|
module Hello (Time : Mirage_time.S) = struct
|
||||||
|
let start _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" (hello ()));
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () -> loop (n - 1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<p>We define the <a href="https://erratique.ch/software/cmdliner/doc/Cmdliner/Term/index.html#type-t">Cmdliner.Term.t</a>
|
||||||
|
in line 6 (<code>let term = ..</code>) - which provides documentation ("How to say hello."), the option to
|
||||||
|
use (<code>["hello"]</code> - which is then translated to <code>--hello=</code>), that it is optional,
|
||||||
|
of type <code>string</code> (cmdliner allows you to convert the incoming strings to more
|
||||||
|
complex (or more narrow) data types, with decent error handling).</p>
|
||||||
|
<p>The defined argument is directly passed to <a href="https://ocaml.org/p/mirage-runtime/4.8.1/doc/Mirage_runtime/index.html#val-register_arg"><code>Mirage_runtime.register_arg</code></a>,
|
||||||
|
(in line 7) so our binding <code>hello</code> is of type <code>unit -> string</code>.
|
||||||
|
In line 14, the value of the runtime argument is used (<code>hello ()</code>) for printing
|
||||||
|
a log message.</p>
|
||||||
|
<p>The nice property is that it is all local in <code>unikernel.ml</code>, there are no other
|
||||||
|
parts involved. It is just a bunch of API calls. The downside is that <code>hello ()</code>
|
||||||
|
should only be evaluated after the function <code>start</code> was called - since the
|
||||||
|
<code>Mirage_runtime</code> needs to parse and fill in the command line arguments. If you
|
||||||
|
call <code>hello ()</code> earlier, you'll get an exception "Called too early. Please delay
|
||||||
|
this call to after the start function of the unikernel.". Also, since
|
||||||
|
Mirage_runtime needs to collect and evaluate the command line arguments, the
|
||||||
|
<code>Mirage_runtime.register_arg</code> may only be called at top-level, otherwise you'll
|
||||||
|
get another exception "The function register_arg was called to late. Please call
|
||||||
|
register_arg before the start function is executed (e.g. in a top-level binding).".</p>
|
||||||
|
<p>Another advantage is, having it all in unikernel.ml means adding and removing
|
||||||
|
arguments doesn't need another execution of <code>mirage configure</code>. Also, any
|
||||||
|
type can be used that the unikernel depends on - the config.ml is compiled only
|
||||||
|
with a small set of dependencies (mirage itself) - and we don't want to impose a
|
||||||
|
large dependency cone for mirage just because someone may like to use
|
||||||
|
X509.Key_type.t as argument type.</p>
|
||||||
|
<p>Earlier, before mirage 4.5.0, we had runtime and configure arguments mixed
|
||||||
|
together. And code was generated when <code>mirage configure</code> was executed to
|
||||||
|
deal with these arguments. The downsides included: we needed serialization for
|
||||||
|
all command-line arguments (at configure time you could fill the argument, which
|
||||||
|
was then serialized, and deserialized at runtime and used unless the argument
|
||||||
|
was provided explicitly), they had to appear in <code>config.ml</code> (which also means
|
||||||
|
changing any would need an execution of <code>mirage configure</code>), since they generated code
|
||||||
|
potential errors were in code that the developer didn't write (though we had
|
||||||
|
some <code>__POS__</code> arguments to provide error locations in the developer code).</p>
|
||||||
|
<p>Related recent changes are:</p>
|
||||||
|
<ul>
|
||||||
|
<li>in mirage 4.8.1, the runtime arguments to configure the OCaml runtime system
|
||||||
|
(such as GC settings, randomization of hashtables, recording of backtraces)
|
||||||
|
are now provided using the <a href="https://ocaml.org/p/cmdliner-stdlib">cmdliner-stdlib</a>
|
||||||
|
package.</li>
|
||||||
|
<li>in mirage 4.8.0, for git, dns-client, and happy-eyeballs devices the optional
|
||||||
|
arguments are generated by default - so they are always available and don't
|
||||||
|
need to be manually done by the unikernel developer.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Let's dive a bit deeper into the history.</p>
|
||||||
|
<h2 id="history"><a class="anchor" aria-hidden="true" href="#history"></a>History</h2>
|
||||||
|
<p>In MirageOS, since the early stages (I'll go back to 2.7.0 (February 2016) where
|
||||||
|
functoria was introduced) used an embedded fork of <code>cmdliner</code> to handle command
|
||||||
|
line arguments.</p>
|
||||||
|
<p><a href="https://asciinema.org/a/ruHoadi2oZGOzgzMKk5ZYoFgf"><img src="https://asciinema.org/a/ruHoadi2oZGOzgzMKk5ZYoFgf.svg" alt="Animated changes to the hello world unikernel" ></a></p>
|
||||||
|
<h3 id="february-2016-mirage-270"><a class="anchor" aria-hidden="true" href="#february-2016-mirage-270"></a>February 2016 (Mirage 2.7.0)</h3>
|
||||||
|
<p>When looking into the MirageOS 2.x series, here's the code for our hello world
|
||||||
|
unikernel:</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Key.Arg.info ~doc:"How to say hello." ["hello"] in
|
||||||
|
Key.(create "hello" Arg.(opt string "Hello World!" doc))
|
||||||
|
|
||||||
|
let main =
|
||||||
|
foreign
|
||||||
|
~keys:[Key.abstract hello]
|
||||||
|
"Unikernel.Hello" (console @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_console]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
|
||||||
|
module Hello (C: V1_LWT.CONSOLE) = struct
|
||||||
|
let start c =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
C.log c (Key_gen.hello ());
|
||||||
|
OS.Time.sleep 1.0 >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<p>As you can see, the cmdliner term was provided in <code>config.ml</code>, and in
|
||||||
|
<code>unikernel.ml</code> the expression <code>Key_gen.hello ()</code> was used - <code>Key_gen</code> was
|
||||||
|
a module generated by the <code>mirage configure</code> invocation.</p>
|
||||||
|
<p>You can as well see that the term was wrapped in <code>Key.create "hello"</code> - where
|
||||||
|
this string was used as the identifier for the code generation.</p>
|
||||||
|
<p>As mentioned above, a change needed to be done in <code>config.ml</code> and a
|
||||||
|
<code>mirage configure</code> to take effect.</p>
|
||||||
|
<h3 id="july-2016-mirage-291"><a class="anchor" aria-hidden="true" href="#july-2016-mirage-291"></a>July 2016 (Mirage 2.9.1)</h3>
|
||||||
|
<p>The <code>OS.Time</code> was functorized with a <code>Time</code> functor:</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Key.Arg.info ~doc:"How to say hello." ["hello"] in
|
||||||
|
Key.(create "hello" Arg.(opt string "Hello World!" doc))
|
||||||
|
|
||||||
|
let main =
|
||||||
|
foreign
|
||||||
|
~keys:[Key.abstract hello]
|
||||||
|
"Unikernel.Hello" (console @-> time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_console $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
|
||||||
|
module Hello (C: V1_LWT.CONSOLE) (Time : V1_LWT.TIME) = struct
|
||||||
|
let start c _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
C.log c (Key_gen.hello ());
|
||||||
|
Time.sleep 1.0 >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="february-2017-mirage-pre3"><a class="anchor" aria-hidden="true" href="#february-2017-mirage-pre3"></a>February 2017 (Mirage pre3)</h3>
|
||||||
|
<p>The <code>Time</code> signature changed, now the <code>sleep_ns</code> function sleeps in nanoseconds.
|
||||||
|
This avoids floating point numbers at the core of MirageOS. The helper package
|
||||||
|
<code>duration</code> is used to avoid manual conversions.</p>
|
||||||
|
<p>Also, the console signature changed - and <code>log</code> is now inside the Lwt monad.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Key.Arg.info ~doc:"How to say hello." ["hello"] in
|
||||||
|
Key.(create "hello" Arg.(opt string "Hello World!" doc))
|
||||||
|
|
||||||
|
let main =
|
||||||
|
foreign
|
||||||
|
~keys:[Key.abstract hello]
|
||||||
|
~packages:[package "duration"]
|
||||||
|
"Unikernel.Hello" (console @-> time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_console $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
|
||||||
|
module Hello (C: V1_LWT.CONSOLE) (Time : V1_LWT.TIME) = struct
|
||||||
|
let start c _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
C.log c (Key_gen.hello ()) >>= fun () ->
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="february-2017-mirage-3"><a class="anchor" aria-hidden="true" href="#february-2017-mirage-3"></a>February 2017 (Mirage 3)</h3>
|
||||||
|
<p>Another big change is that now console is not used anymore, but
|
||||||
|
<a href="https://erratique.ch/software/logs">logs</a>.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Key.Arg.info ~doc:"How to say hello." ["hello"] in
|
||||||
|
Key.(create "hello" Arg.(opt string "Hello World!" doc))
|
||||||
|
|
||||||
|
let main =
|
||||||
|
foreign
|
||||||
|
~keys:[Key.abstract hello]
|
||||||
|
~packages:[package "duration"]
|
||||||
|
"Unikernel.Hello" (time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
|
||||||
|
module Hello (Time : Mirage_time_lwt.S) = struct
|
||||||
|
let start _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" (Key_gen.hello ()));
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="january-2020-mirage-370"><a class="anchor" aria-hidden="true" href="#january-2020-mirage-370"></a>January 2020 (Mirage 3.7.0)</h3>
|
||||||
|
<p>The <code>_lwt</code> is dropped from the interfaces (we used to have Mirage_time and
|
||||||
|
Mirage_time_lwt - where the latter was instantiating the former with concrete
|
||||||
|
types: <code>type 'a io = Lwt.t</code> and <code>type buffer = Cstruct.t</code> -- in a cleanup
|
||||||
|
session we dropped the <code>_lwt</code> interfaces and opam packages. The reasoning was
|
||||||
|
that when we'll get around to move to another IO system, we'll move everything
|
||||||
|
at once anyways. No need to have <code>lwt</code> and something else (<code>async</code>, or nowadays
|
||||||
|
<code>miou</code> or <code>eio</code>) in a single unikernel.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Key.Arg.info ~doc:"How to say hello." ["hello"] in
|
||||||
|
Key.(create "hello" Arg.(opt string "Hello World!" doc))
|
||||||
|
|
||||||
|
let main =
|
||||||
|
foreign
|
||||||
|
~keys:[Key.abstract hello]
|
||||||
|
~packages:[package "duration"]
|
||||||
|
"Unikernel.Hello" (time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
|
||||||
|
module Hello (Time : Mirage_time.S) = struct
|
||||||
|
let start _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" (Key_gen.hello ()));
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="october-2021-mirage-310"><a class="anchor" aria-hidden="true" href="#october-2021-mirage-310"></a>October 2021 (Mirage 3.10)</h3>
|
||||||
|
<p>Some renamings to fix warnings. Only <code>config.ml</code> changed.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Key.Arg.info ~doc:"How to say hello." ["hello"] in
|
||||||
|
Key.(create "hello" Arg.(opt string "Hello World!" doc))
|
||||||
|
|
||||||
|
let main =
|
||||||
|
main
|
||||||
|
~keys:[key hello]
|
||||||
|
~packages:[package "duration"]
|
||||||
|
"Unikernel.Hello" (time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
|
||||||
|
module Hello (Time : Mirage_time.S) = struct
|
||||||
|
let start _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" (Key_gen.hello ()));
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="june-2023-mirage-44"><a class="anchor" aria-hidden="true" href="#june-2023-mirage-44"></a>June 2023 (Mirage 4.4)</h3>
|
||||||
|
<p>The argument was moved to runtime.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Key.Arg.info ~doc:"How to say hello." ["hello"] in
|
||||||
|
Key.(create "hello" Arg.(opt ~stage:`Run string "Hello World!" doc))
|
||||||
|
|
||||||
|
let main =
|
||||||
|
main
|
||||||
|
~keys:[key hello]
|
||||||
|
~packages:[package "duration"]
|
||||||
|
"Unikernel.Hello" (time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
|
||||||
|
module Hello (Time : Mirage_time.S) = struct
|
||||||
|
let start _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" (Key_gen.hello ());
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="march-2024-mirage-45"><a class="anchor" aria-hidden="true" href="#march-2024-mirage-45"></a>March 2024 (Mirage 4.5)</h3>
|
||||||
|
<p>The runtime argument is in <code>config.ml</code> refering to the argument as string
|
||||||
|
("Unikernel.hello"), and being passed to the <code>start</code> function as argument.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let runtime_args = [ runtime_arg ~pos:__POS__ "Unikernel.hello" ]
|
||||||
|
|
||||||
|
let main =
|
||||||
|
main
|
||||||
|
~runtime_args
|
||||||
|
~packages:[package "duration"]
|
||||||
|
"Unikernel.Hello" (time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
open Cmdliner
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Arg.info ~doc:"How to say hello." [ "hello" ] in
|
||||||
|
Arg.(value & opt string "Hello World!" doc)
|
||||||
|
|
||||||
|
module Hello (Time : Mirage_time.S) = struct
|
||||||
|
let start _time hello =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" hello);
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="october-2024-mirage-48"><a class="anchor" aria-hidden="true" href="#october-2024-mirage-48"></a>October 2024 (Mirage 4.8)</h3>
|
||||||
|
<p>Again, moved out of <code>config.ml</code>.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let main =
|
||||||
|
main
|
||||||
|
~packages:[package "duration"]
|
||||||
|
"Unikernel.Hello" (time @-> job)
|
||||||
|
|
||||||
|
let () = register "hello-key" [main $ default_time]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
open Cmdliner
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Arg.info ~doc:"How to say hello." [ "hello" ] in
|
||||||
|
Mirage_runtime.register_arg Arg.(value & opt string "Hello World!" doc)
|
||||||
|
|
||||||
|
module Hello (Time : Mirage_time.S) = struct
|
||||||
|
let start _time =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" (hello ()));
|
||||||
|
Time.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="2024-not-yet-released"><a class="anchor" aria-hidden="true" href="#2024-not-yet-released"></a>2024 (Not yet released)</h3>
|
||||||
|
<p>This is the future with time defunctorized. Read more in the <a href="https://github.com/mirage/mirage/issues/1513">discussion</a>.
|
||||||
|
To delay the start function, a <code>dep</code> of <code>noop</code> is introduced.</p>
|
||||||
|
<p><code>config.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Mirage
|
||||||
|
|
||||||
|
let main =
|
||||||
|
main
|
||||||
|
~packages:[package "duration"]
|
||||||
|
~dep:[dep noop]
|
||||||
|
"Unikernel" job
|
||||||
|
|
||||||
|
let () = register "hello-key" [main]
|
||||||
|
</code></pre>
|
||||||
|
<p>and <code>unikernel.ml</code></p>
|
||||||
|
<pre><code class="language-OCaml">open Lwt.Infix
|
||||||
|
open Cmdliner
|
||||||
|
|
||||||
|
let hello =
|
||||||
|
let doc = Arg.info ~doc:"How to say hello." [ "hello" ] in
|
||||||
|
Mirage_runtime.register_arg Arg.(value & opt string "Hello World!" doc)
|
||||||
|
|
||||||
|
let start () =
|
||||||
|
let rec loop = function
|
||||||
|
| 0 -> Lwt.return_unit
|
||||||
|
| n ->
|
||||||
|
Logs.info (fun f -> f "%s" (hello ()));
|
||||||
|
Mirage_timer.sleep_ns (Duration.of_sec 1) >>= fun () ->
|
||||||
|
loop (n-1)
|
||||||
|
in
|
||||||
|
loop 4
|
||||||
|
</code></pre>
|
||||||
|
<h2 id="conclusion"><a class="anchor" aria-hidden="true" href="#conclusion"></a>Conclusion</h2>
|
||||||
|
<p>The history of hello world shows that over time we slowly improve the developer
|
||||||
|
experience, and removing the boilerplate needed to get MirageOS unikernels up
|
||||||
|
and running. This is work over a decade including lots of other (here invisible)
|
||||||
|
improvements to the mirage utility.</p>
|
||||||
|
<p>Our current goal is to minimize the code generated by mirage, since code
|
||||||
|
generation has lots of issues (e.g. error locations, naming, binary size). It
|
||||||
|
is a long journey. At the same time, we are working on improving the performance
|
||||||
|
of MirageOS unikernels, developing unikernels that are useful in the real
|
||||||
|
world (<a href="https://github.com/robur-coop/miragevpn">VPN endpoint</a>, <a href="https://github.com/robur-coop/dnsvizor">DNSmasq replacement</a>, ...), and also <a href="https://github.com/robur-coop/mollymawk">simplifying the
|
||||||
|
deployment of MirageOS unikernels</a>.</p>
|
||||||
|
<p>If you're interested in MirageOS and using it in your domain, don't hesitate
|
||||||
|
to reach out to us (via eMail: team@robur.coop) - we're keen to deploy MirageOS
|
||||||
|
and find more domains where it is useful. If you can spare a dime, we're a
|
||||||
|
registered non-profit in Germany - and can provide tax-deductable receipts for
|
||||||
|
donations (<a href="https://robur.coop/Donate">more information</a>).</p>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<a href="https://github.com/xhtmlboi/yocaml">Powered by <strong>YOCaml</strong></a>
|
||||||
|
<br />
|
||||||
|
</footer>
|
||||||
|
<script>hljs.highlightAll();</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
11
atom.xml
11
atom.xml
|
@ -3,12 +3,21 @@
|
||||||
<id>https://blog.robur.coop/atom.xml</id>
|
<id>https://blog.robur.coop/atom.xml</id>
|
||||||
<title type="text">The Robur's blog</title>
|
<title type="text">The Robur's blog</title>
|
||||||
<generator uri="https://github.com/xhtmlboi/yocaml" version="2">YOCaml</generator>
|
<generator uri="https://github.com/xhtmlboi/yocaml" version="2">YOCaml</generator>
|
||||||
<updated>2024-10-21T00:00:00Z</updated>
|
<updated>2024-10-22T00:00:00Z</updated>
|
||||||
<author>
|
<author>
|
||||||
<name>The Robur Team</name>
|
<name>The Robur Team</name>
|
||||||
</author>
|
</author>
|
||||||
<link href="https://blog.robur.coop/"/>
|
<link href="https://blog.robur.coop/"/>
|
||||||
<link href="https://blog.robur.coop/atom.xml" rel="self"/>
|
<link href="https://blog.robur.coop/atom.xml" rel="self"/>
|
||||||
|
<entry>
|
||||||
|
<id>https://blog.robur.coop//articles/arguments.html</id>
|
||||||
|
<title type="text">Runtime arguments in MirageOS</title>
|
||||||
|
<updated>2024-10-22T00:00:00Z</updated>
|
||||||
|
<summary type="text">The history of runtime arguments to a MirageOS unikernel</summary>
|
||||||
|
<link href="https://blog.robur.coop//articles/arguments.html" rel="alternate" title="Runtime arguments in MirageOS"/>
|
||||||
|
<category term="OCaml"/>
|
||||||
|
<category term="MirageOS"/>
|
||||||
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
<id>https://blog.robur.coop//articles/finances.html</id>
|
<id>https://blog.robur.coop//articles/finances.html</id>
|
||||||
<title type="text">How has robur financially been doing since 2018?</title>
|
<title type="text">How has robur financially been doing since 2018?</title>
|
||||||
|
|
9
feed.xml
9
feed.xml
|
@ -5,9 +5,16 @@
|
||||||
<link>https://blog.robur.coop/</link>
|
<link>https://blog.robur.coop/</link>
|
||||||
<description><![CDATA[The Robur cooperative blog]]></description>
|
<description><![CDATA[The Robur cooperative blog]]></description>
|
||||||
<atom:link href="https://blog.robur.coop/feed.xml" rel="self" type="application/rss+xml"/>
|
<atom:link href="https://blog.robur.coop/feed.xml" rel="self" type="application/rss+xml"/>
|
||||||
<lastBuildDate>Mon, 21 Oct 2024 00:00:00 GMT</lastBuildDate>
|
<lastBuildDate>Tue, 22 Oct 2024 00:00:00 GMT</lastBuildDate>
|
||||||
<docs>https://www.rssboard.org/rss-specification</docs>
|
<docs>https://www.rssboard.org/rss-specification</docs>
|
||||||
<generator>YOCaml</generator>
|
<generator>YOCaml</generator>
|
||||||
|
<item>
|
||||||
|
<title>Runtime arguments in MirageOS</title>
|
||||||
|
<link>https://blog.robur.coop//articles/arguments.html</link>
|
||||||
|
<description><![CDATA[The history of runtime arguments to a MirageOS unikernel]]></description>
|
||||||
|
<guid isPermaLink="true">https://blog.robur.coop//articles/arguments.html</guid>
|
||||||
|
<pubDate>Tue, 22 Oct 2024 00:00:00 GMT</pubDate>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<title>How has robur financially been doing since 2018?</title>
|
<title>How has robur financially been doing since 2018?</title>
|
||||||
<link>https://blog.robur.coop//articles/finances.html</link>
|
<link>https://blog.robur.coop//articles/finances.html</link>
|
||||||
|
|
13
index.html
13
index.html
|
@ -25,6 +25,19 @@
|
||||||
<h3>Essays and ramblings</h3>
|
<h3>Essays and ramblings</h3>
|
||||||
|
|
||||||
<ol reversed class="list-articles"><li>
|
<ol reversed class="list-articles"><li>
|
||||||
|
<div class="side">
|
||||||
|
<a href="https://hannes.robur.coop">
|
||||||
|
<img src="https://www.gravatar.com/avatar/25558b4457cf73159f5427fdf2b4a717">
|
||||||
|
</a></div>
|
||||||
|
<div class="content">
|
||||||
|
<span class="date">2024-10-22</span>
|
||||||
|
<a href="https://blog.robur.coop/articles/arguments.html">Runtime arguments in MirageOS</a><br />
|
||||||
|
<p>The history of runtime arguments to a MirageOS unikernel</p>
|
||||||
|
<div class="bottom">
|
||||||
|
<ul class="tags-list"><li><a href="https://blog.robur.coop/tags.html#tag-OCaml">OCaml</a></li><li><a href="https://blog.robur.coop/tags.html#tag-MirageOS">MirageOS</a></li></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li><li>
|
||||||
<div class="side">
|
<div class="side">
|
||||||
<a href="https://hannes.robur.coop">
|
<a href="https://hannes.robur.coop">
|
||||||
<img src="https://www.gravatar.com/avatar/25558b4457cf73159f5427fdf2b4a717">
|
<img src="https://www.gravatar.com/avatar/25558b4457cf73159f5427fdf2b4a717">
|
||||||
|
|
6
rss1.xml
6
rss1.xml
|
@ -6,6 +6,7 @@
|
||||||
<description><![CDATA[The Robur cooperative blog]]></description>
|
<description><![CDATA[The Robur cooperative blog]]></description>
|
||||||
<items>
|
<items>
|
||||||
<rdf:Seq>
|
<rdf:Seq>
|
||||||
|
<rdf:li resource="https://blog.robur.coop//articles/arguments.html"/>
|
||||||
<rdf:li resource="https://blog.robur.coop//articles/finances.html"/>
|
<rdf:li resource="https://blog.robur.coop//articles/finances.html"/>
|
||||||
<rdf:li resource="https://blog.robur.coop//articles/2024-08-21-OpenVPN-and-MirageVPN.html"/>
|
<rdf:li resource="https://blog.robur.coop//articles/2024-08-21-OpenVPN-and-MirageVPN.html"/>
|
||||||
<rdf:li resource="https://blog.robur.coop//articles/tar-release.html"/>
|
<rdf:li resource="https://blog.robur.coop//articles/tar-release.html"/>
|
||||||
|
@ -21,6 +22,11 @@
|
||||||
</rdf:Seq>
|
</rdf:Seq>
|
||||||
</items>
|
</items>
|
||||||
</channel>
|
</channel>
|
||||||
|
<item rdf:about="https://blog.robur.coop//articles/arguments.html">
|
||||||
|
<title>Runtime arguments in MirageOS</title>
|
||||||
|
<link>https://blog.robur.coop//articles/arguments.html</link>
|
||||||
|
<description><![CDATA[The history of runtime arguments to a MirageOS unikernel]]></description>
|
||||||
|
</item>
|
||||||
<item rdf:about="https://blog.robur.coop//articles/finances.html">
|
<item rdf:about="https://blog.robur.coop//articles/finances.html">
|
||||||
<title>How has robur financially been doing since 2018?</title>
|
<title>How has robur financially been doing since 2018?</title>
|
||||||
<link>https://blog.robur.coop//articles/finances.html</link>
|
<link>https://blog.robur.coop//articles/finances.html</link>
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<h3>
|
<h3>
|
||||||
<span>MirageOS</span>
|
<span>MirageOS</span>
|
||||||
</h3>
|
</h3>
|
||||||
<ul><li><a href="/articles/miragevpn.html">MirageVPN & tls-crypt-v2</a></li><li><a href="/articles/miragevpn-ncp.html">MirageVPN updated (AEAD, NCP)</a></li><li><a href="/articles/speeding-ec-string.html">Speeding elliptic curve cryptography</a></li><li><a href="/articles/miragevpn-performance.html">Speeding up MirageVPN and use it in the wild</a></li><li><a href="/articles/miragevpn-server.html">MirageVPN server</a></li></ul>
|
<ul><li><a href="/articles/miragevpn.html">MirageVPN & tls-crypt-v2</a></li><li><a href="/articles/miragevpn-ncp.html">MirageVPN updated (AEAD, NCP)</a></li><li><a href="/articles/speeding-ec-string.html">Speeding elliptic curve cryptography</a></li><li><a href="/articles/miragevpn-performance.html">Speeding up MirageVPN and use it in the wild</a></li><li><a href="/articles/miragevpn-server.html">MirageVPN server</a></li><li><a href="/articles/arguments.html">Runtime arguments in MirageOS</a></li></ul>
|
||||||
</div><div class="tag-box" id="tag-MirageVPN">
|
</div><div class="tag-box" id="tag-MirageVPN">
|
||||||
<h3>
|
<h3>
|
||||||
<span>MirageVPN</span>
|
<span>MirageVPN</span>
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
<h3>
|
<h3>
|
||||||
<span>OCaml</span>
|
<span>OCaml</span>
|
||||||
</h3>
|
</h3>
|
||||||
<ul><li><a href="/articles/miragevpn.html">MirageVPN & tls-crypt-v2</a></li><li><a href="/articles/miragevpn-ncp.html">MirageVPN updated (AEAD, NCP)</a></li><li><a href="/articles/2024-02-03-python-str-repr.html">Python's `str.__repr__()`</a></li><li><a href="/articles/lwt_pause.html">Cooperation and Lwt.pause</a></li><li><a href="/articles/speeding-ec-string.html">Speeding elliptic curve cryptography</a></li><li><a href="/articles/gptar.html">GPTar</a></li><li><a href="/articles/miragevpn-performance.html">Speeding up MirageVPN and use it in the wild</a></li><li><a href="/articles/miragevpn-server.html">MirageVPN server</a></li><li><a href="/articles/qubes-miragevpn.html">qubes-miragevpn, a MirageVPN client for QubesOS</a></li><li><a href="/articles/tar-release.html">The new Tar release, a retrospective</a></li></ul>
|
<ul><li><a href="/articles/miragevpn.html">MirageVPN & tls-crypt-v2</a></li><li><a href="/articles/miragevpn-ncp.html">MirageVPN updated (AEAD, NCP)</a></li><li><a href="/articles/2024-02-03-python-str-repr.html">Python's `str.__repr__()`</a></li><li><a href="/articles/lwt_pause.html">Cooperation and Lwt.pause</a></li><li><a href="/articles/speeding-ec-string.html">Speeding elliptic curve cryptography</a></li><li><a href="/articles/gptar.html">GPTar</a></li><li><a href="/articles/miragevpn-performance.html">Speeding up MirageVPN and use it in the wild</a></li><li><a href="/articles/miragevpn-server.html">MirageVPN server</a></li><li><a href="/articles/qubes-miragevpn.html">qubes-miragevpn, a MirageVPN client for QubesOS</a></li><li><a href="/articles/tar-release.html">The new Tar release, a retrospective</a></li><li><a href="/articles/arguments.html">Runtime arguments in MirageOS</a></li></ul>
|
||||||
</div><div class="tag-box" id="tag-OpenVPN">
|
</div><div class="tag-box" id="tag-OpenVPN">
|
||||||
<h3>
|
<h3>
|
||||||
<span>OpenVPN</span>
|
<span>OpenVPN</span>
|
||||||
|
|
Loading…
Reference in a new issue