Skip to content

Commit e7bee50

Browse files
authored
Merge pull request #1453 from fwsGonzo/dev
test: Add integration test for LiveUpdate
2 parents 6104a8c + 0fc7006 commit e7bee50

10 files changed

Lines changed: 260 additions & 1 deletion

File tree

lib/LiveUpdate/liveupdate.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,15 @@ struct LiveUpdate
5151
typedef delegate<void(Restore&)> resume_func;
5252

5353
// Register a function to be called when serialization phase begins
54+
// Internally it will be stored as its own partition and can be restored using
55+
// the same @key value during the resume process
5456
static void register_serialization_callback(std::string key, storage_func);
5557

5658
// Start a live update process, storing all user-defined data
57-
// If no storage function is provided no state will be saved
59+
// If no storage functions are registered no state will be saved
5860
static void exec(const buffer_t& blob);
61+
// Same as above, but including the partition [@key, func]
62+
static void exec(const buffer_t& blob, std::string key, storage_func func);
5963

6064
// In the event that LiveUpdate::exec() fails,
6165
// call this function in the C++ exception catch scope:

lib/LiveUpdate/update.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ inline bool validate_header(const Class* hdr)
8484
hdr->e_ident[3] == 'F';
8585
}
8686

87+
void LiveUpdate::exec(const buffer_t& blob, std::string key, storage_func func)
88+
{
89+
register_serialization_callback(key, func);
90+
LiveUpdate::exec(blob);
91+
}
92+
8793
void LiveUpdate::exec(const buffer_t& blob)
8894
{
8995
void* location = OS::liveupdate_storage_area();
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
cmake_minimum_required(VERSION 2.8.9)
2+
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
3+
set(ENV{INCLUDEOS_PREFIX} /usr/local)
4+
endif()
5+
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
6+
project (service)
7+
8+
# Human-readable name of your service
9+
set(SERVICE_NAME "LiveUpdate integration test")
10+
11+
# Name of your service binary
12+
set(BINARY "service")
13+
14+
# Source files to be linked with OS library parts to form bootable image
15+
set(SOURCES
16+
service.cpp test_boot.cpp
17+
)
18+
19+
# DRIVERS / PLUGINS:
20+
set(DRIVERS
21+
virtionet
22+
)
23+
24+
set(PLUGINS )
25+
26+
# STATIC LIBRARIES:
27+
set(LIBRARIES
28+
libliveupdate.a
29+
)
30+
31+
# include service build script
32+
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"net" : [
3+
["10.0.0.49", "255.255.255.0", "10.0.0.1"]
4+
]
5+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
4+
// and Alfred Bratterud
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
#pragma once
19+
#include <liveupdate>
20+
#include "server.hpp"
21+
22+
void setup_liveupdate_server(net::Inet<net::IP4>& inet,
23+
const uint16_t PORT,
24+
liu::LiveUpdate::storage_func func)
25+
{
26+
static liu::LiveUpdate::storage_func save_function;
27+
save_function = func;
28+
29+
// listen for live updates
30+
server(inet, PORT,
31+
[] (liu::buffer_t& buffer)
32+
{
33+
printf("* Live updating from %p (len=%u)\n",
34+
buffer.data(), (uint32_t) buffer.size());
35+
try
36+
{
37+
// run live update process
38+
liu::LiveUpdate::exec(buffer, "test", save_function);
39+
}
40+
catch (std::exception& err)
41+
{
42+
liu::LiveUpdate::restore_environment();
43+
printf("Live update failed:\n%s\n", err.what());
44+
throw;
45+
}
46+
});
47+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Master thesis
3+
* by Alf-Andre Walla 2016-2017
4+
*
5+
**/
6+
#pragma once
7+
#include <stdexcept>
8+
9+
static inline
10+
void server(net::Inet<net::IP4>& inet,
11+
const uint16_t port,
12+
delegate<void(liu::buffer_t&)> callback)
13+
{
14+
auto& server = inet.tcp().listen(port);
15+
server.on_connect(
16+
net::tcp::Connection::ConnectCallback::make_packed(
17+
[callback, port] (auto conn)
18+
{
19+
auto* buffer = new liu::buffer_t;
20+
buffer->reserve(3*1024*1024);
21+
printf("Receiving blob on port %u\n", port);
22+
23+
// retrieve binary
24+
conn->on_read(9000,
25+
[conn, buffer] (net::tcp::buffer_t buf, size_t n)
26+
{
27+
buffer->insert(buffer->end(), buf.get(), buf.get() + n);
28+
})
29+
.on_disconnect(
30+
net::tcp::Connection::DisconnectCallback::make_packed(
31+
[buffer, callback] (auto conn, auto) {
32+
printf("* Blob size: %u b stored at %p\n",
33+
(uint32_t) buffer->size(), buffer->data());
34+
callback(*buffer);
35+
delete buffer;
36+
conn->close();
37+
}));
38+
}));
39+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
4+
// and Alfred Bratterud
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
#include <service>
19+
#include <net/inet4>
20+
#include <cstdio>
21+
#include "liu.hpp"
22+
23+
using storage_func_t = liu::LiveUpdate::storage_func;
24+
extern storage_func_t begin_test_boot();
25+
26+
void Service::start()
27+
{
28+
auto func = begin_test_boot();
29+
30+
if (liu::LiveUpdate::is_resumable() == false)
31+
{
32+
auto& inet = net::Super_stack::get<net::IP4>(0);
33+
setup_liveupdate_server(inet, 666, func);
34+
}
35+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#! /usr/bin/env python
2+
import sys
3+
import os
4+
import socket
5+
6+
includeos_src = os.environ.get('INCLUDEOS_SRC',
7+
os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))).split('/test')[0])
8+
sys.path.insert(0,includeos_src)
9+
10+
from vmrunner import vmrunner
11+
vm = vmrunner.vms[0]
12+
13+
14+
def begin_test(line):
15+
f = open('./service','rb')
16+
17+
s = socket.socket()
18+
s.connect(("10.0.0.49", 666))
19+
s.send(f.read())
20+
s.close()
21+
22+
vm.on_output("Ready to receive binary blob", begin_test)
23+
vm.cmake().boot(40).clean()
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include <kernel/os.hpp>
2+
#include <liveupdate>
3+
using namespace liu;
4+
5+
static std::vector<int64_t> timestamps;
6+
static buffer_t bloberino;
7+
8+
static void boot_save(Storage& storage, const buffer_t* blob)
9+
{
10+
timestamps.push_back(OS::micros_since_boot());
11+
storage.add_vector(0, timestamps);
12+
assert(blob != nullptr);
13+
storage.add_buffer(2, *blob);
14+
}
15+
static void boot_resume_all(Restore& thing)
16+
{
17+
timestamps = thing.as_vector<int64_t>(); thing.go_next();
18+
// calculate time spent
19+
auto t1 = timestamps.back();
20+
auto t2 = OS::micros_since_boot();
21+
// set final time
22+
timestamps.back() = t2 - t1;
23+
// retrieve old blob
24+
bloberino = thing.as_buffer(); thing.go_next();
25+
26+
thing.pop_marker();
27+
}
28+
29+
LiveUpdate::storage_func begin_test_boot()
30+
{
31+
try {
32+
LiveUpdate::resume("test", boot_resume_all);
33+
// if we are here,
34+
// resume() must have succeeded
35+
if (timestamps.size() >= 30)
36+
{
37+
// calculate median by sorting
38+
std::sort(timestamps.begin(), timestamps.end());
39+
auto median = timestamps[timestamps.size()/2];
40+
// show information
41+
printf("Median boot time over %lu samples: %llu micros\n",
42+
timestamps.size(), median);
43+
/*
44+
for (auto& stamp : timestamps) {
45+
printf("%lld\n", stamp);
46+
}
47+
*/
48+
printf("SUCCESS\n");
49+
OS::shutdown();
50+
}
51+
else {
52+
// immediately liveupdate
53+
LiveUpdate::exec(bloberino, "test", boot_save);
54+
}
55+
}
56+
catch (std::exception& e) {
57+
printf("Ready to receive binary blob\n");
58+
}
59+
// wait for update
60+
return boot_save;
61+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"description" : "VM with interface for testing LiveUpdate",
3+
"net" : [
4+
{"device" : "virtio"}
5+
],
6+
"mem" : 48
7+
}

0 commit comments

Comments
 (0)