9 |
10 | #define MAGIC_IOPORT_SIGNAL_GUEST_BOOT_COMPLETE 0x03f0
11 |
12 | static __inline void boot_done(void)
13 | {
14 | iopl(3);
15 | outb_p(MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE, MAGIC_IOPORT_SIGNAL_GUEST_BOOT_COMPLETE);
16 | }
17 |
18 | int main(int argc, char* const argv[])
19 | {
20 | boot_done();
21 | return 0;
22 | }
23 |
--------------------------------------------------------------------------------
/builder/inittab:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | ::sysinit:/sbin/openrc sysinit
19 | ::sysinit:/sbin/openrc boot
20 | ::wait:/sbin/openrc default
21 |
22 | # Set up a couple of getty's
23 | # tty1::respawn:/sbin/getty 38400 tty1
24 | # tty2::respawn:/sbin/getty 38400 tty2
25 | # tty3::respawn:/sbin/getty 38400 tty3
26 | # tty4::respawn:/sbin/getty 38400 tty4
27 | # tty5::respawn:/sbin/getty 38400 tty5
28 | # tty6::respawn:/sbin/getty 38400 tty6
29 |
30 | # Put a getty on the serial port
31 | ttyS0::wait:-/bin/ash /sbin/run-user-script /start.sh
32 |
33 | # Stuff to do for the 3-finger salute
34 | ::ctrlaltdel:/sbin/reboot
35 |
36 | # Stuff to do before rebooting
37 | ::shutdown:/sbin/openrc shutdown
38 |
--------------------------------------------------------------------------------
/builder/interfaces:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | auto eth0
19 | iface eth0 inet manual
20 |
--------------------------------------------------------------------------------
/builder/prepare.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | # link rc services
20 | ln -sf /etc/init.d/devfs /etc/runlevels/boot/devfs
21 | ln -sf /etc/init.d/procfs /etc/runlevels/boot/procfs
22 | ln -sf /etc/init.d/sysfs /etc/runlevels/boot/sysfs
23 |
24 | ln -sf networking /etc/init.d/net.eth0
25 | ln -sf /etc/init.d/networking /etc/runlevels/default/networking
26 | ln -sf /etc/init.d/net.eth0 /etc/runlevels/default/net.eth0
27 |
28 | # disable modules
29 | echo rc_want="!modules">> /etc/rc.conf
30 | # disable fsck
31 | echo rc_need="!fsck">> /etc/rc.conf
32 |
33 | passwd root -d root
34 | exit
35 |
--------------------------------------------------------------------------------
/builder/run-user-script:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | # if /dev/ptp0 is available, we can use it as a time source
20 | if [ -e /dev/ptp0 ]; then
21 | # setup chrony to use PTP as the time source
22 | echo "refclock PHC /dev/ptp0 poll -2 dpoll -2 offset 0 trust prefer" > /etc/chrony/chrony.conf
23 | echo "Using PTP clock /dev/ptp0 as time source"
24 | else
25 | echo "NOT using PTP clock /dev/ptp0 as time source"
26 | fi
27 |
28 | # start chronyd
29 | rc-service chronyd start
30 |
31 | # clock synchronization
32 | chronyc makestep
33 | sleep 1
34 | chronyc makestep
35 | # chronyc tracking
36 |
37 | # network setup
38 | IP=$(/sbin/ip route | awk '/default/ { print $3 }')
39 | echo "$IP info.celestial" >> /etc/hosts
40 |
41 | echo "Celestial: Starting user script..."
42 |
43 | /bin/sh app.sh
44 |
45 | echo "Celestial: User script finished, shutting down..."
46 | reboot -f # reboot actually shuts down the microVM in Firecracker
47 |
--------------------------------------------------------------------------------
/celestial-make:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | make celestial-make
21 | docker run --platform=linux/amd64 --rm -v "$(pwd)":/celestial celestial-make $@
22 |
--------------------------------------------------------------------------------
/celestial/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | import os
19 | import sys
20 |
21 | currentdir = os.path.dirname(os.path.realpath(__file__))
22 | sys.path.append(currentdir)
23 |
--------------------------------------------------------------------------------
/celestial/dot_test.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | import numpy as np
19 | import numba
20 | import time
21 |
22 |
23 | @numba.njit # type: ignore
24 | def dot_product_manual(matrix_3x3: np.ndarray, vector_3x1: np.ndarray) -> np.ndarray: # type: ignore
25 | result = np.zeros((3,), dtype=np.int64)
26 |
27 | for i in range(3):
28 | for j in range(3):
29 | result[i] += matrix_3x3[i, j] * vector_3x1[j]
30 |
31 | return result # type: ignore
32 |
33 |
34 | def dot_product(matrix_3x3: np.ndarray, vector_3x1: np.ndarray) -> np.ndarray: # type: ignore
35 | result = np.dot(matrix_3x3, vector_3x1)
36 | return result # type: ignore
37 |
38 |
39 | if __name__ == "__main__":
40 | # Example usage
41 | matrix_3x3 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
42 | vector_3x1 = np.array([2, 3, 4])
43 |
44 | # Explicitly type the input arguments
45 | matrix_3x3 = matrix_3x3.astype(np.int64)
46 | vector_3x1 = vector_3x1.astype(np.int64)
47 |
48 | t1 = time.perf_counter()
49 | result = dot_product(matrix_3x3, vector_3x1)
50 | t2 = time.perf_counter()
51 | print(result)
52 |
53 | # Example usage
54 | matrix_3x3 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
55 | vector_3x1 = np.array([2, 3, 4])
56 |
57 | t3 = time.perf_counter()
58 | result_manual = dot_product_manual(matrix_3x3, vector_3x1)
59 | t4 = time.perf_counter()
60 | print(result_manual)
61 |
62 | print(f"dot_product took {t2 - t1} seconds")
63 | print(f"dot_product_manual took {t4 - t3} seconds")
64 |
--------------------------------------------------------------------------------
/celestial/host.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | """Adapter for communication with the Celestial hosts over gRPC"""
19 |
20 | import typing
21 | import grpc
22 | import time
23 | import logging
24 |
25 | import proto.celestial.celestial_pb2
26 | import proto.celestial.celestial_pb2_grpc
27 |
28 |
29 | class Host:
30 | """
31 | Communication link for a Celestial host.
32 | """
33 |
34 | def __init__(self, num: int, addr: str):
35 | """
36 | Initialize host communication.
37 |
38 | :param num: The host number.
39 | :param addr: The address of the host.
40 | """
41 | self.num = num
42 | self.addr = addr
43 |
44 | c = grpc.insecure_channel(self.addr)
45 | self.stub = proto.celestial.celestial_pb2_grpc.CelestialStub(c)
46 |
47 | self.public_key = ""
48 |
49 | def register(self) -> proto.celestial.celestial_pb2.RegisterResponse:
50 | """
51 | Send a `register` request to the host.
52 |
53 | :return: The response from the host.
54 | """
55 | try:
56 | request = proto.celestial.celestial_pb2.RegisterRequest(host=self.num)
57 |
58 | response: proto.celestial.celestial_pb2.RegisterResponse = (
59 | self.stub.Register(request)
60 | )
61 |
62 | except Exception as e:
63 | logging.error(f"Error registering host {self.num}: {e}")
64 | exit(1)
65 |
66 | # others currently not used
67 | self.peer_public_key = response.peer_public_key
68 |
69 | self.peer_listen_addr = (
70 | self.addr.split(":")[0] + ":" + response.peer_listen_addr.split(":")[1]
71 | )
72 |
73 | logging.debug(f"host {self.num} registered")
74 | logging.debug(f"memory: {response.available_ram}")
75 | logging.debug(f"cpu: {response.available_cpus}")
76 |
77 | return response
78 |
79 | def init(
80 | self,
81 | init_request: proto.celestial.celestial_pb2.InitRequest,
82 | ) -> None:
83 | """
84 | Send an `init` request to the host.
85 |
86 | :param hosts: A list of all hosts in the constellation.
87 | :param machines: A dictionary mapping host numbers to a list of machine ID and machine configuration tuples.
88 | """
89 |
90 | self.stub.Init(init_request)
91 |
92 | return
93 |
94 | def stop(self) -> None:
95 | """
96 | Send a `stop` request to the host.
97 | """
98 | self.stub.Stop(proto.celestial.celestial_pb2.Empty())
99 |
100 | def update(
101 | self,
102 | update_requests: typing.Iterator[
103 | proto.celestial.celestial_pb2.StateUpdateRequest
104 | ],
105 | ) -> None:
106 | """
107 | Send a `update` request to the host.
108 |
109 | :param machine_diff: An iterator of machine ID and machine state tuples.
110 | :param link_diff: An iterator of link tuples.
111 | """
112 |
113 | t1 = time.perf_counter()
114 | self.stub.Update(update_requests)
115 | t2 = time.perf_counter()
116 | logging.debug(f"update transmission took {t2-t1} seconds")
117 |
118 | return
119 |
--------------------------------------------------------------------------------
/celestial/serializer.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | """A protocol for serializers and deserializers"""
19 |
20 | import typing
21 | import celestial.types
22 |
23 |
24 | class Serializer(typing.Protocol):
25 | """
26 | A serializer takes constellation updates and serializes it into a format
27 | that can be used for emulation.
28 | """
29 |
30 | def init_machine(
31 | self,
32 | machine: celestial.types.MachineID_dtype,
33 | config: celestial.config.MachineConfig,
34 | ) -> None:
35 | """
36 | Serialize a machine initialization.
37 |
38 | :param machine: The machine ID of the machine.
39 | :param config: The configuration of the machine.
40 | """
41 | ...
42 |
43 | def diff_link(
44 | self,
45 | t: celestial.types.timestamp_s,
46 | source: celestial.types.MachineID_dtype,
47 | target: celestial.types.MachineID_dtype,
48 | link: celestial.types.Link_dtype,
49 | ) -> None:
50 | """
51 | Serialize a link update.
52 |
53 | :param t: The timestamp of the update.
54 | :param source: The source machine of the link.
55 | :param target: The target machine of the link.
56 | :param link: The link.
57 | """
58 | ...
59 |
60 | def diff_machine(
61 | self,
62 | t: celestial.types.timestamp_s,
63 | machine: celestial.types.MachineID_dtype,
64 | s: celestial.types.VMState,
65 | ) -> None:
66 | """
67 | Serialize a machine state update.
68 |
69 | :param t: The timestamp of the update.
70 | :param machine: The machine ID of the machine.
71 | :param s: The state of the machine.
72 | """
73 | ...
74 |
75 | def persist(self) -> None:
76 | """
77 | Persist the serialized state. Called at the end of the simulation.
78 | """
79 | ...
80 |
81 |
82 | class Deserializer(typing.Protocol):
83 | """
84 | Deserializes a serialized state into a constellation update.
85 | """
86 |
87 | def config(self) -> celestial.config.Config:
88 | """
89 | Get the configuration of the simulation.
90 |
91 | :return: The configuration of the simulation.
92 | """
93 | ...
94 |
95 | def init_machine(
96 | self,
97 | ) -> typing.List[
98 | typing.Tuple[celestial.types.MachineID_dtype, celestial.config.MachineConfig]
99 | ]:
100 | """
101 | Deserialize the initial machine states.
102 |
103 | :return: A list of machine ID and machine configuration tuples.
104 | """
105 | ...
106 |
107 | def diff_links(
108 | self, t: celestial.types.timestamp_s
109 | ) -> typing.List[
110 | typing.Tuple[
111 | celestial.types.MachineID_dtype,
112 | celestial.types.MachineID_dtype,
113 | celestial.types.Link_dtype,
114 | ]
115 | ]:
116 | """
117 | Deserialize the link updates.
118 |
119 | :param t: The timestamp of the update.
120 | :return: A list of link updates.
121 | """
122 | ...
123 |
124 | def diff_machines(
125 | self, t: celestial.types.timestamp_s
126 | ) -> typing.List[
127 | typing.Tuple[celestial.types.MachineID_dtype, celestial.types.VMState]
128 | ]:
129 | """
130 | Deserialize the machine state updates.
131 |
132 | :param t: The timestamp of the update.
133 | :return: A list of machine state updates.
134 | """
135 | ...
136 |
--------------------------------------------------------------------------------
/compile.Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 |
19 | FROM debian:bookworm@sha256:b16cef8cbcb20935c0f052e37fc3d38dc92bfec0bcfb894c328547f81e932d67
20 |
21 | ARG OS=linux
22 | ARG ARCH=x86_64
23 | ARG GO_ARCH=amd64
24 | ARG LIBPROTOC_VERSION=25.1
25 | ARG GO_VERSION=1.22.1
26 | ARG PROTOC_GEN_GO_VERSION=1.31.0
27 | ARG PROTOC_GEN_GO_GRPC_VERSION=1.3
28 |
29 | RUN apt-get update && apt-get install -y \
30 | --no-install-recommends \
31 | --no-install-suggests \
32 | ca-certificates \
33 | wget \
34 | make \
35 | clang \
36 | gcc-multilib \
37 | libbpf-dev \
38 | llvm \
39 | build-essential \
40 | unzip \
41 | python3 \
42 | git \
43 | python3-pip \
44 | python3-venv && \
45 | apt-get clean && rm -rf /var/lib/apt/lists/*
46 |
47 | RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v${LIBPROTOC_VERSION}/protoc-${LIBPROTOC_VERSION}-${OS}-${ARCH}.zip && \
48 | unzip protoc-${LIBPROTOC_VERSION}-${OS}-${ARCH}.zip -d protoc-${LIBPROTOC_VERSION} && \
49 | mv protoc-${LIBPROTOC_VERSION} /usr/local/protoc && \
50 | rm protoc-${LIBPROTOC_VERSION}-${OS}-${ARCH}.zip && \
51 | chmod +x /usr/local/protoc/bin/* && \
52 | ln -s /usr/local/protoc/bin/protoc /usr/local/bin/protoc
53 |
54 | RUN wget https://go.dev/dl/go${GO_VERSION}.${OS}-${GO_ARCH}.tar.gz && \
55 | rm -rf /usr/local/go && \
56 | tar -C /usr/local -xzf go${GO_VERSION}.${OS}-${GO_ARCH}.tar.gz && \
57 | echo 'export PATH="$PATH:/usr/local/go/bin"' >> /etc/profile && \
58 | echo 'export PATH="$PATH:/root/go/bin"' >> /etc/profile && \
59 | echo 'export GOPATH=/root/go' >> /etc/profile && \
60 | echo 'export GOBIN="/root/go/bin"' >> /etc/profile && \
61 | rm -rf go${GO_VERSION}.${OS}-${GO_ARCH}.tar.gz
62 |
63 | ENV PATH $PATH:/usr/local/go/bin
64 | ENV PATH $PATH:/root/go/bin
65 | ENV GOPATH /root/go
66 | ENV GOBIN /root/go/bin
67 |
68 | RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v${PROTOC_GEN_GO_VERSION} && \
69 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v${PROTOC_GEN_GO_GRPC_VERSION}
70 |
71 | RUN python3 -m venv /venv
72 | ENV PATH="/venv/bin:$PATH"
73 | COPY requirements.txt requirements.txt
74 | RUN python3 -m pip install -r requirements.txt -U
75 |
76 | WORKDIR /celestial
77 |
78 | ENTRYPOINT [ "make" ]
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .jekyll-cache
4 | .jekyll-metadata
5 | vendor
6 |
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 | ---
2 | permalink: /404.html
3 | layout: default
4 | ---
5 |
6 |
19 |
20 |
21 |
404
22 |
23 |
Page not found :(
24 |
The requested page could not be found.
25 |
26 |
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 | # Hello! This is where you manage which Jekyll version is used to run.
3 | # When you want to use a different version, change it below, save the
4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
5 | #
6 | # bundle exec jekyll serve
7 | #
8 | # This will help ensure the proper Jekyll version is running.
9 | # Happy Jekylling!
10 | # gem "jekyll", "~> 4.2.2"
11 | # This is the default theme for new Jekyll sites. You may change this to anything you like.
12 | #gem "minima", "~> 2.5"
13 | gem "just-the-docs"
14 |
15 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
16 | # uncomment the line below. To upgrade, run `bundle update github-pages`.
17 | gem "github-pages", "~> 228", group: :jekyll_plugins
18 |
19 | # somehow I need this
20 | gem "webrick"
21 |
22 | # Performance-booster for watching directories on Windows
23 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
24 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Celestial Docs
2 |
3 | These docs are made for GitHub pages using Jekyll and the `just-the-docs` theme.
4 | You need Ruby < v3.3.0 for this to work ([thanks, GitHub!](https://github.com/github/pages-gem/issues/899#issuecomment-1880156387)).
5 |
6 | GitHub recommends `bundler`:
7 |
8 | ```sh
9 | gem install bundler
10 | bundle install
11 | bundle exec jekyll serve
12 | ```
13 |
14 | You should now be able to view documentation locally at `http://localhost:4000`.
15 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | # Welcome to Jekyll!
2 | #
3 | # This config file is meant for settings that affect your whole blog, values
4 | # which you are expected to set up once and rarely edit after that. If you find
5 | # yourself editing this file very often, consider using Jekyll's data files
6 | # feature for the data you need to update frequently.
7 | #
8 | # For technical reasons, this file is *NOT* reloaded automatically when you use
9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process.
10 | #
11 | # If you need help with YAML syntax, here are some quick references for you:
12 | # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml
13 | # https://learnxinyminutes.com/docs/yaml/
14 | #
15 | # Site settings
16 | # These are used to personalize your new site. If you look in the HTML files,
17 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
18 | # You can create any custom variable you would like, and they will be accessible
19 | # in the templates via {{ site.myvariable }}.
20 |
21 | title: Celestial 🛰
22 | description: >- # this means to ignore newlines until "baseurl:"
23 | Celestial is an emulator for the LEO edge. It supports satellite servers as well as ground stations. Each node is booted as a microVM. Celestial scales across as many hosts as you want.
24 | baseurl: "/celestial" # the subpath of your site, e.g. /blog
25 | url: "https://openfogstack.github.io" # the base hostname & protocol for your site, e.g. http://example.com
26 |
27 | # Build settings
28 | remote_theme: just-the-docs/just-the-docs
29 |
30 | aux_links:
31 | "Celestial on GitHub":
32 | - "//github.com/OpenFogStack/celestial"
33 |
34 | footer_content: "Copyright © 2024 Tobias Pfandzelter, The OpenFogStack Team. Licensed under the terms of the GPLv3 license."
35 |
36 | gh_edit_link: true # show or hide edit this page link
37 | gh_edit_link_text: "Edit this page on GitHub"
38 | gh_edit_repository: "https://github.com/OpenFogStack/celestial" # the github URL for your repo
39 | gh_edit_branch: "main" # the branch that your docs is served from
40 | gh_edit_source: docs # the source that your files originate from
41 | gh_edit_view_mode: "tree" # "tree" or "edit" if you want the user to jump into the editor immediately
42 |
43 | # Exclude from processing.
44 | # The following items will not be processed, by default.
45 | # Any item listed under the `exclude:` key here will be automatically added to
46 | # the internal "default list".
47 | #
48 | # Excluded items can be processed by explicitly listing the directories or
49 | # their entries' file path in the `include:` list.
50 | #
51 | # exclude:
52 | # - .sass-cache/
53 | # - .jekyll-cache/
54 | # - gemfiles/
55 | # - Gemfile
56 | # - Gemfile.lock
57 | # - node_modules/
58 | # - vendor/bundle/
59 | # - vendor/cache/
60 | # - vendor/gems/
61 | # - vendor/ruby/
62 |
--------------------------------------------------------------------------------
/docs/assets/actual_line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/actual_line.png
--------------------------------------------------------------------------------
/docs/assets/celestial-constellation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/celestial-constellation.gif
--------------------------------------------------------------------------------
/docs/assets/diff_ecdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/diff_ecdf.png
--------------------------------------------------------------------------------
/docs/assets/expected_line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/expected_line.png
--------------------------------------------------------------------------------
/docs/assets/reachable_actual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/reachable_actual.png
--------------------------------------------------------------------------------
/docs/assets/reachable_expected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/reachable_expected.png
--------------------------------------------------------------------------------
/docs/assets/results_scatter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/docs/assets/results_scatter.png
--------------------------------------------------------------------------------
/docs/compilation.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Compilation
4 | nav_order: 4
5 | ---
6 |
7 | ## Compilation
8 |
9 | Compiling the project requires generating protocol buffer files, generating some
10 | Go code for eBPF, and compiling Go code into a static binary.
11 |
12 | We recommend using Docker to compile the project.
13 |
14 | ### Using Docker
15 |
16 | #### Building the Compile Container
17 |
18 | Run `make celestial-make` to build a container that has all the dependencies
19 | needed to compile the project.
20 |
21 | #### Protocol Buffer
22 |
23 | You can use the pre-compiled gRPC/protocol buffer files or compile your own:
24 |
25 | ```sh
26 | # compile all protofiles for python and go
27 | docker run --platform linux/amd64 --rm -v $(pwd):/celestial celestial-make proto
28 | ```
29 |
30 | #### Go Server
31 |
32 | Compile the host server with:
33 |
34 | ```sh
35 | docker run --platfrom linux/amd64 --rm -v $(pwd):/celestial celestial-make celestial.bin
36 | ```
37 |
38 | ### Manually
39 |
40 | To manually compile and generate code, install the dependencies found in [`compile.Dockerfile`](https://github.com/OpenFogStack/celestial/blob/compile.Dockerfile).
41 | Then run `make` to compile.
42 |
--------------------------------------------------------------------------------
/docs/contributing.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Contributing
4 | nav_order: 2
5 | ---
6 |
7 | ## Contributing
8 |
9 | Feel free to contribute to this project in any way you see fit.
10 | Please note that all contributions must adhere to the terms of the GPLv3 license.
11 |
12 | If you want to contribute code, please open a pull request on this GitHub repository.
13 | Please make sure that your code passes the quality checks.
14 | You can use [`act`](https://github.com/nektos/act) to run GitHub actions locally.
15 |
16 | Most importantly, please check that `mypy` type checking completes without errors.
17 | You can also use the tests in the [`test/`](https://github.com/OpenFogStack/celestial/blob/test)
18 | directory to confirm that there are no regressions.
19 |
20 | We include some tests for host-side code in the [`pkg/`](https://github.com/OpenFogStack/celestial/blob/pkg)
21 | directory as well that can be run with `go test`.
22 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 | title: About
4 | nav_order: 1
5 | ---
6 |
7 | ## About
8 |
9 | Celestial is an emulator for the LEO edge.
10 | It supports satellite servers as well as ground stations.
11 | Each node is booted as a microVM.
12 | Celestial scales across as many hosts as you want.
13 |
14 | At any given time, only a subset of given satellite servers are booted,
15 | dependent on your configured bounding box.
16 |
17 | Celestial...
18 |
19 | - ...creates Firecracker microVMs with your custom kernel and filesystem
20 | - ...modifies network connections for a realistic network condition
21 | - ...lets you define a bounding box on earth, so you only need to emulate
22 | satellites that you're actually interested in
23 | - ...creates/suspends microVMs as they move in to/out of your bounding box
24 | - ...has APIs for your satellites to retrieve some meta-information
25 |
26 | Check out [`celestial-videoconferencing-evaluation`](https://github.com/OpenFogStack/celestial-videoconferencing-evaluation)
27 | for an example application on Celestial!
28 | Also check out the [`celestial-buoy-evaluation`](https://github.com/OpenFogStack/celestial-buoy-evaluation)
29 | and the [`celestial-twissandra-evaluation`](https://github.com/OpenFogStack/celestial-twissandra-evaluation).
30 |
31 | **A word of caution**: you can technically run the server-side software on any
32 | computer you want, but it requires root access to fiddle with your network settings.
33 | Therefore, we _highly_ encourage you to only run it on dedicated servers.
34 | It's doing its best to clean up everything, but it has to make changes to a lot
35 | of networking settings, so we can't guarantee that it doesn't destroy any of your
36 | other stuff.
37 |
38 | ### Research
39 |
40 | If you use this software in a publication, please cite it as:
41 |
42 |
43 | T. Pfandzelter and D. Bermbach, **Celestial: Virtual Software System Testbeds
44 | for the LEO Edge**, 23rd ACM/IFIP International Middleware Conference
45 | (Middleware '22), Quebec City, Canada, 2022, doi: 10.1145/3528535.3531517.
46 |
47 | ```bibtex
48 | @inproceedings{pfandzelter2022celestial,
49 | author = "Pfandzelter, Tobias and Bermbach, David",
50 | title = "Celestial: Virtual Software System Testbeds for the LEO Edge",
51 | booktitle = "Proceedings of the 23rd ACM/IFIP International Middleware Conference",
52 | pages = "69--81",
53 | month = nov,
54 | year = 2022,
55 | publisher = "Association for Computing Machinery",
56 | address = "New York, NY, USA",
57 | series = "Middleware '22",
58 | location = "Quebec, QC, Canada",
59 | url = "https://doi.org/10.1145/3528535.3531517",
60 | doi = "10.1145/3528535.3531517"
61 | }
62 | ```
63 |
64 | A full list of our [publications](https://www.tu.berlin/en/mcc/research/publications/)
65 | and [prototypes](https://www.tu.berlin/en/mcc/research/prototypes/)
66 | is available on our group website.
67 |
68 | ### License
69 |
70 | The code in this repository is licensed under the terms of the [GPLv3](./LICENSE)
71 | license.
72 |
73 | ### Documentation
74 |
75 | The complete documentation can be found at [`openfogstack.github.io/celestial`](https://openfogstack.github.io/celestial)
76 | or in the `docs` directory.
77 |
--------------------------------------------------------------------------------
/docs/kernel.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Guest Kernel
4 | nav_order: 8
5 | ---
6 |
7 |
8 | ## Building a Kernel
9 |
10 | Compiling your own Linux is not actually that hard.
11 | You will want to do this if the `hello-world` kernel provided by Firecracker lacks
12 | options you need or if you want to use a newer kernel version.
13 | This documentation is adapted from the [Firecracker developer guide](https://github.com/firecracker-microvm/firecracker/blob/main/docs/rootfs-and-kernel-setup.md).
14 | We recommend using the `v5.12` kernel configuration we provide in the [`./kernel`](https://github.com/OpenFogStack/celestial/blob/kernel/config-5.12)
15 | directory.
16 |
17 | You need three things:
18 |
19 | 1. Kernel sources
20 | 2. A tool chain
21 | 3. A configuration file
22 |
23 | You can get the kernel sources by cloning the Linux repository:
24 |
25 | ```sh
26 | # warning! this is about 3.5GB in size so sit back and wait
27 | git clone https://github.com/torvalds/linux.git linux.git
28 | cd linux.git
29 |
30 | # then checkout the version you want, e.g. v4.19
31 | git checkout v4.19
32 | ```
33 |
34 | You also need a few things for your tool chain.
35 | The details depend on your distribution, here are the packages needed on Ubuntu 18.04:
36 |
37 | ```sh
38 | sudo apt-get install build-essential linux-source bc kmod cpio flex \
39 | libncurses5-dev libelf-dev libssl-dev bison -y
40 | ```
41 |
42 | Finally, your config file is used to configure your kernel.
43 | We recommend our [`./kernel/config-5.12`](https://github.com/OpenFogStack/celestial/blob/kernel/config-5.12)
44 | for the `v5.12` configuration.
45 | You should name your config file `.config` and place it in the `linux.git` folder.
46 |
47 | You can modify this configuration with the `menuconfig` tool:
48 |
49 | ```sh
50 | make menuconfig
51 | ```
52 |
53 | Save your configuration and build your kernel with:
54 |
55 | ```sh
56 | make vmlinux
57 | ```
58 |
59 | Pro-tip: use `make vmlinux -j [NO_THREADS]` to multi-thread your compilation.
60 |
61 | This takes a few minutes.
62 | There you go, now you have your `vmlinux` file that you can use as a kernel.
63 |
64 | If you want to use Docker within your microVM, you need to build a kernel that has
65 | support for everything Docker requires.
66 | Check out [this repository](https://github.com/njapke/docker-in-firecracker) for
67 | information on how to do that.
68 |
--------------------------------------------------------------------------------
/docs/nestedvirtualization.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Nested Virtualization
4 | nav_order: 9
5 | ---
6 |
7 | ## A Word On Virtualization Capabilities
8 |
9 | To use Firecracker on cloud VMs, those must support what is called _nested virtualization_.
10 | Not all cloud VMs support this, e.g., on AWS EC2 you must use `metal` instances.
11 |
12 | You can read more about this setup [here](https://github.com/firecracker-microvm/firecracker/blob/main/docs/dev-machine-setup.md).
13 |
14 | ### Example: Creating an Ubuntu 22.04 Image in Google Cloud
15 |
16 | This uses the `gcloud` shell:
17 |
18 | ```sh
19 | # set configuration
20 | # use Frankfurt as a region
21 | $ FC_REGION=europe-west3
22 | $ FC_ZONE=europe-west3-c
23 |
24 | $ gcloud config set compute/region ${FC_REGION}
25 | Updated property [compute/region].
26 |
27 | $ gcloud config set compute/zone ${FC_ZONE}
28 | Updated property [compute/zone].
29 |
30 | # set a name for the image
31 | $ FC_VDISK=disk-ubnt
32 | $ FC_IMAGE=ubnt-nested-kvm
33 |
34 | # create disk
35 | $ gcloud compute disks create ${FC_VDISK} \
36 | --image-project ubuntu-os-cloud --image-family ubuntu-2204-lts
37 | Created [https://www.googleapis.com/compute/v1/projects/[PROJECT-ID]/zones/europe-west3-c/disks/disk-ubnt].
38 | NAME ZONE SIZE_GB TYPE STATUS
39 | disk-ubnt europe-west3-c 10 pd-standard READY
40 |
41 | # create image from disk with associated nested virtualization option
42 | $ gcloud compute images create ${FC_IMAGE} --source-disk ${FC_VDISK} \
43 | --source-disk-zone ${FC_ZONE} \
44 | --licenses "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"
45 | Created [https://www.googleapis.com/compute/v1/projects/[PROJECT-ID]/global/images/ubnt-nested-kvm].
46 | NAME PROJECT FAMILY DEPRECATED STATUS
47 | ubnt-nested-kvm [PROJECT-ID] READY
48 | ```
49 |
50 | Once you have done that, start a VM with that image.
51 | Enter it with `ssh` and enable access to `/dev/kvm`, then check that it's working:
52 |
53 | ```sh
54 | $ sudo setfacl -m u:${USER}:rw /dev/kvm
55 | $ [ -r /dev/kvm ] && [ -w /dev/kvm ] && echo "OK" || echo "FAIL"
56 | OK
57 | ```
58 |
--------------------------------------------------------------------------------
/docs/output.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Output
4 | nav_order: 10
5 | ---
6 |
7 | ## Output
8 |
9 | There are different ways to retrieve experiment results from Celestial.
10 | You can also use your own cloud storage or logging database if your host has Internet
11 | access.
12 |
13 | ### `stderr` and `stdout`
14 |
15 | If your machines have terminal devices available (not using the `8250.nr_uarts=0`
16 | boot parameter), your software can write to `stdout` and `stderr`.
17 | The streams of those devices will be forwarded to text files on your host.
18 | You can see the outputs of your machines in the `/celestial/out` folder.
19 | For each machine, there is a `.out` and a `.err` file, that capture `stdout` and
20 | `stderr`, respectively.
21 |
22 | Note that this is not recommended for performance-critical applications as writing
23 | a lot of data to your host disk in this way can be slow.
24 |
25 | ### Retrieving Files from microVM Disks
26 |
27 | If your software manipulates files on your microVM file system, you also have the
28 | option to retrieve those files later.
29 | Celestial creates an overlay file system for each microVM as
30 | `ce[SHELL]-[ID].ext4` for satellites or `ce[NAME].ext4` for ground stations.
31 | Note that if you use multiple hosts, the file system will only be created on the
32 | host that hosts that particular machine.
33 |
34 | You can mount this file system to copy files (either directly on the host or by
35 | downloading a copy of the file system).
36 | For example, to copy a file named `output.csv` from the file system of satellite
37 | 840 in shell 1, do:
38 |
39 | ```sh
40 | # create a temporary mounting point
41 | sudo mkdir -p ./tmp-dir
42 |
43 | # mount the filesystem
44 | sudo mount /celestial/ce1-840.ext4 ./tmp-dir -o loop
45 |
46 | # copy the relevant file to your directory
47 | sudo cp ./tmp-dir/output.csv sat1-840-output.csv
48 |
49 | # unmount the filesystem
50 | sudo umount ./tmp-dir
51 |
52 | # remove the mounting point
53 | sudo rmdir ./tmp-dir
54 | ```
55 |
56 | We recommend only mounting the file system after its microVM has been shut down to
57 | avert any file system corruption.
58 | Also keep in mind that you must unmount the file system if you want to run Celestial
59 | again as Celestial will try to overwrite this file system with a fresh copy.
60 |
--------------------------------------------------------------------------------
/docs/runtime/dns.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: DNS API
4 | nav_order: 4
5 | parent: Runtime
6 | ---
7 |
8 | ## DNS API
9 |
10 | In addition to finding information about itself, a machine can also find the network
11 | address of another machine by querying the provided DNS service.
12 | This service is available at the machine's gateway on port 53 using `systemd-resolved`
13 | on the host.
14 | This is set as the default DNS server in Celestial.
15 | It supports only `A` requests for the custom `.celestial` TLD.
16 |
17 | Records are in the form `[ID].[SHELL].celestial` for satellites and `[NAME].gst.celestial`
18 | for ground stations.
19 | Note that all addresses are resolved if the machine is known, regardless of whether
20 | that machine is active or can be accessed.
21 |
22 | When using our builder, you can also use the hostname `info.celestial` as the address
23 | of the info server, alas the gateway IP for a microVM.
24 |
--------------------------------------------------------------------------------
/docs/runtime/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Runtime
4 | nav_order: 11
5 | has_children: True
6 | ---
7 |
8 | Celestial offers multiple advanced runtime features that your applications can
9 | leverage.
10 | These are available within your microVMs.
11 |
--------------------------------------------------------------------------------
/docs/runtime/networking.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Networking
4 | nav_order: 1
5 | parent: Runtime
6 | ---
7 |
8 | ## Networking
9 |
10 | In Celestial, all machines are equipped with a virtual network adapter that is
11 | available within the microVM as `eth0`.
12 | Each machine is placed in a dedicated subnet.
13 | Machines that can communicate with each other (these are machines where a network
14 | path exists between their corresponding satellites or ground stations) can find
15 | each other using the DNS service described below.
16 |
17 | All networks are subnets of the `10.0.0.0/8` network.
18 | Networks are calculated as follows:
19 |
20 | 1. Byte is always `10` (0x0A)
21 | 1. Byte is the shell identifier, `0` for ground stations and starting at `1` for
22 | satellite shells
23 | 1. Byte is the satellite's identifier in the shell, shifted right by 6 bits (e.g.
24 | `12` or `0x0C` for satellite `831`)
25 | 1. Byte is the satellite's identifier in the shell, shifted left by 2 bits (e.g.
26 | `252` or `0xFC` for satellite `831`)
27 |
28 | Within this network, the network + 1 is the gateway IP and network + 2 is the microVMs
29 | IP.
30 | The network has a `/30` network mask, hence only those two are available.
31 |
32 | eBPF programs and `tc` are used to modify network latency between microVMs.
33 | WireGuard is used to link machines on different hosts.
34 |
--------------------------------------------------------------------------------
/docs/runtime/time.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Time API
4 | nav_order: 2
5 | parent: Runtime
6 | ---
7 |
8 | ## Time
9 |
10 | Since the user provides kernel and root filesystem, all time and clock control is
11 | in their hands.
12 |
13 | If you're running experiments on Celestial you might be interested in an accurate
14 | wall clock in your VMs, e.g. to measure network delays.
15 | There are two ways to configure clock synchronization in your VMs: NTP and PTP.
16 | You can read a bit more about that in [the Firecracker documentation](https://github.com/firecracker-microvm/firecracker/blob/main/FAQ.md#my-guest-wall-clock-is-drifting-how-can-i-fix-it).
17 |
18 | By default, root file systems built with the builder toolchain are set up for PTP.
19 |
20 | ### PTP
21 |
22 | The downside of NTP is that all your machines synchronize with an external time-server.
23 | If you run hundreds of machines, that's quite a bit of network traffic.
24 |
25 | PTP synchronizes your machines with the host's time using cheap para-virtualized
26 | KVM calls.
27 | It's a lot more accurate as well (on one machine - if you run Celestial across
28 | multiple serves, make sure to synchronize those too, and expect some inaccuracies!).
29 |
30 | The downside here is that both hour host and guest must support it.
31 |
32 | On a host side, we have seen that it works with Amazon Linux 2 and
33 | Ubuntu 22.04 LTS, but we weren't able to get it to work with Debian.
34 | There is probably a way to find out if your host supports it, but maybe you just
35 | need to try it out.
36 | For Ubuntu 22.04 LTS, it worked for Amazon Web Services and Google Cloud, but not
37 | on our local machine.
38 | The reason was that the host clock source was `kvm-clock` (nested virtualization)
39 | and not `tsc`.
40 | If starting a microVM gives you the log message `NOT using /dev/ptp0`, `tsc` is
41 | not set as a clock source on your host.
42 | Celestial will try to set this, but it may not work.
43 |
44 | ```sh
45 | # reading current clock source says kvm-clock
46 | $ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
47 | kvm-clock
48 |
49 | # tsc is available
50 | $ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
51 | kvm-clock tsc acpi_pm
52 |
53 | # set tsc as a clock source
54 | $ echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource
55 | ```
56 |
57 | Note that this will change after a reboot.
58 | Making this persist requires changing you kernel parameters.
59 |
60 | On a client side, you need to configure a time synchronization service and have
61 | PTP support enabled in your kernel with these lines in your kernel config:
62 |
63 | ```config
64 | CONFIG_PTP_1588_CLOCK=y
65 | CONFIG_PTP_1588_CLOCK_KVM=y
66 | ```
67 |
68 | These configuration flags are set accordingly in our [default Linux guest kernel](./kernel.html).
69 |
70 | Once you boot, you should see a `/dev/ptp0` device (if you don't your host probably
71 | doesn't support it).
72 |
73 | You then need to configure that device for your time keeping service, e.g. in `chrony`:
74 |
75 | ```sh
76 | echo "refclock PHC /dev/ptp0 poll 3 dpoll -2 offset 0" > /etc/chrony/chrony.conf
77 | ```
78 |
79 | You should then restart the `chrony` daemon:
80 |
81 | ```sh
82 | service chronyd restart
83 | ```
84 |
85 | To force time synchronization in the guest, use:
86 |
87 | ```sh
88 | $ chronyc -a makestep
89 | 200 OK
90 |
91 | $ chronyc tracking
92 | Reference ID : 50484330 (PHC0)
93 | Stratum : 1
94 | Ref time (UTC) : Mon May 10 11:58:30 2021
95 | System time : 0.000000122 seconds fast of NTP time
96 | Last offset : -0.000005912 seconds
97 | RMS offset : 0.000003069 seconds
98 | Frequency : 83.203 ppm slow
99 | Residual freq : -0.177 ppm
100 | Skew : 0.502 ppm
101 | Root delay : 0.000000001 seconds
102 | Root dispersion : 0.000010668 seconds
103 | Update interval : 7.9 seconds
104 | Leap status : Normal
105 | ```
106 |
107 | This happens before your application script runs in guest root file systems built
108 | with our builder toolchain.
109 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | //
2 | // This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | // Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, version 3.
8 | //
9 | // This program is distributed in the hope that it will be useful, but
10 | // WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | // General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 | //
17 |
18 | module github.com/OpenFogStack/celestial
19 |
20 | go 1.21.0
21 |
22 | toolchain go1.22.1
23 |
24 | require (
25 | github.com/cilium/ebpf v0.15.0
26 | github.com/firecracker-microvm/firecracker-go-sdk v1.0.0
27 | github.com/go-ping/ping v1.1.0
28 | github.com/gorilla/mux v1.8.1
29 | github.com/miekg/dns v1.1.57
30 | github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
31 | github.com/pkg/errors v0.9.1
32 | github.com/sirupsen/logrus v1.9.3
33 | github.com/vishvananda/netlink v1.2.1-beta.2
34 | golang.org/x/sys v0.15.0
35 | golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
36 | google.golang.org/grpc v1.59.0
37 | google.golang.org/protobuf v1.31.0
38 | )
39 |
40 | require (
41 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
42 | github.com/containerd/fifo v1.1.0 // indirect
43 | github.com/containernetworking/cni v1.1.2 // indirect
44 | github.com/containernetworking/plugins v1.3.0 // indirect
45 | github.com/go-logr/logr v1.2.4 // indirect
46 | github.com/go-logr/stdr v1.2.2 // indirect
47 | github.com/go-openapi/analysis v0.21.4 // indirect
48 | github.com/go-openapi/errors v0.20.4 // indirect
49 | github.com/go-openapi/jsonpointer v0.20.0 // indirect
50 | github.com/go-openapi/jsonreference v0.20.2 // indirect
51 | github.com/go-openapi/loads v0.21.2 // indirect
52 | github.com/go-openapi/runtime v0.26.0 // indirect
53 | github.com/go-openapi/spec v0.20.9 // indirect
54 | github.com/go-openapi/strfmt v0.21.7 // indirect
55 | github.com/go-openapi/swag v0.22.4 // indirect
56 | github.com/go-openapi/validate v0.22.1 // indirect
57 | github.com/golang/protobuf v1.5.3 // indirect
58 | github.com/google/uuid v1.3.1 // indirect
59 | github.com/hashicorp/errwrap v1.1.0 // indirect
60 | github.com/hashicorp/go-multierror v1.1.1 // indirect
61 | github.com/josharian/intern v1.0.0 // indirect
62 | github.com/mailru/easyjson v0.7.7 // indirect
63 | github.com/mitchellh/mapstructure v1.5.0 // indirect
64 | github.com/oklog/ulid v1.3.1 // indirect
65 | github.com/opentracing/opentracing-go v1.2.0 // indirect
66 | github.com/vishvananda/netns v0.0.4 // indirect
67 | go.mongodb.org/mongo-driver v1.12.1 // indirect
68 | go.opentelemetry.io/otel v1.19.0 // indirect
69 | go.opentelemetry.io/otel/metric v1.19.0 // indirect
70 | go.opentelemetry.io/otel/trace v1.19.0 // indirect
71 | golang.org/x/crypto v0.14.0 // indirect
72 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect
73 | golang.org/x/mod v0.13.0 // indirect
74 | golang.org/x/net v0.17.0 // indirect
75 | golang.org/x/sync v0.4.0 // indirect
76 | golang.org/x/text v0.13.0 // indirect
77 | golang.org/x/tools v0.14.0 // indirect
78 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
79 | gopkg.in/yaml.v2 v2.4.0 // indirect
80 | gopkg.in/yaml.v3 v3.0.1 // indirect
81 | )
82 |
--------------------------------------------------------------------------------
/kernel/.gitignore:
--------------------------------------------------------------------------------
1 | vmlinux-*.bin
--------------------------------------------------------------------------------
/kernel/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | FROM ubuntu:18.04
19 |
20 | RUN apt-get update && \
21 | apt-get install -y \
22 | git \
23 | make \
24 | build-essential \
25 | linux-source \
26 | bc \
27 | kmod \
28 | cpio \
29 | flex \
30 | libncurses5-dev \
31 | libelf-dev \
32 | libssl-dev \
33 | bison -y && \
34 | rm -rf /var/lib/apt/lists/*
35 |
36 | ARG KERNEL_VERSION="5.12.0"
37 |
38 | RUN git clone https://github.com/torvalds/linux.git /linux.git --branch v${KERNEL_VERSION} --depth 1
39 | WORKDIR /linux.git
40 |
--------------------------------------------------------------------------------
/kernel/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | PWD=$(shell pwd)
19 |
20 | .PHONY: all container-%
21 |
22 | all: container-%
23 |
24 | container-%: Dockerfile
25 | @docker build --platform=linux/amd64 --build-arg KERNEL_VERSION=$* -t kernelbuilder:v$* .
26 |
27 | config-%: container-%
28 | @docker run --platform=linux/amd64 -it --rm -v ${PWD}:/input kernelbuilder:v$* /input/config.sh /input $*
29 |
30 | vmlinux-%.bin: container-% config-%
31 | @docker run --platform=linux/amd64 -it --rm -v ${PWD}:/input kernelbuilder:v$* /input/compile.sh /input $* $@
32 |
--------------------------------------------------------------------------------
/kernel/compile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -ex
4 |
5 | INPUT="$1"
6 | KERNEL_VERSION="$2"
7 | OUTPUT="$3"
8 |
9 | # check that $INPUT/config-$KERNEL_VERSION exists
10 | # if not, give an error
11 | if [ ! -f "${INPUT}/config-${KERNEL_VERSION}" ]; then
12 | echo "FATAL: config-${KERNEL_VERSION} does not exist in ${INPUT}"
13 | exit 1
14 | fi
15 |
16 | pushd /linux.git
17 |
18 | # then checkout the version you want, e.g. v4.19
19 | git checkout "v${KERNEL_VERSION}"
20 |
21 | cp "${INPUT}/config-${KERNEL_VERSION}" .config
22 |
23 | make vmlinux -j
24 |
25 | cp vmlinux "${OUTPUT}/vmlinux-${KERNEL-VERSION}.bin"
26 |
--------------------------------------------------------------------------------
/kernel/config.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | set -ex
20 |
21 | INPUT="$1"
22 | KERNEL_VERSION="$2"
23 |
24 | # check that $INPUT/config-$KERNEL_VERSION exists
25 | # if yes, do not overwrite
26 | if [ -f "${INPUT}/config-${KERNEL_VERSION}" ]; then
27 | echo "config-${KERNEL_VERSION} exists in ${INPUT}, skipping..."
28 | exit 0
29 | fi
30 |
31 | pushd /linux.git
32 |
33 | # then checkout the version you want, e.g. v4.19
34 | git checkout "v${KERNEL_VERSION}"
35 |
36 | make defconfig
37 |
38 | # enable CONFIG_RANDOM_TRUST_CPU
39 | sed -i 's/# CONFIG_RANDOM_TRUST_CPU is not set/CONFIG_RANDOM_TRUST_CPU=y/' .config
40 |
41 | cp .config "${INPUT}/config-${KERNEL_VERSION}"
42 |
--------------------------------------------------------------------------------
/pkg/ebpfem/ebpf/headers/helpers.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The
4 | * OpenFogStack Team.
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, version 3.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | * General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | **/
18 |
19 | // Source: https://github.com/srnbckr/ebpf-network-emulation/blob/main/cmd/headers/helpers.h
20 |
21 | // hdr_cursor is used to keep track of the current position in data parsing
22 | struct hdr_cursor
23 | {
24 | void *pos;
25 | };
26 |
27 | // parse_ethhdr parses the ethernet header of a packet, and performs necessary bounds checks.
28 | // returns the next protocol
29 | static __always_inline int parse_ethhdr(struct hdr_cursor *nh,
30 | void *data_end,
31 | struct ethhdr **ethhdr)
32 | {
33 | struct ethhdr *eth = nh->pos;
34 | int hdrsize = sizeof(*eth);
35 |
36 | /* Byte-count bounds check; check if current pointer + size of header
37 | * is after data_end.
38 | */
39 | if (nh->pos + hdrsize > data_end)
40 | return TC_ACT_SHOT;
41 |
42 | nh->pos += hdrsize;
43 | *ethhdr = eth;
44 |
45 | return eth->h_proto; /* network-byte-order */
46 | }
47 |
48 | // parse_iphdr parses the IP header of a packet, and performs necessary bounds checks (more complicated due to variable length of IPv4).
49 | // returns the next protocol
50 | static __always_inline int parse_iphdr(struct hdr_cursor *nh,
51 | void *data_end,
52 | struct iphdr **iphdr)
53 | {
54 | struct iphdr *iph = nh->pos;
55 | int hdrsize;
56 |
57 | // ignore compare-distinct-pointer-types warning
58 | #pragma GCC diagnostic push
59 | #pragma GCC diagnostic ignored "-Wcompare-distinct-pointer-types"
60 | if (iph + 1 > data_end)
61 | #pragma GCC diagnostic pop
62 | return TC_ACT_SHOT;
63 |
64 | hdrsize = iph->ihl * 4;
65 | /* Sanity check packet field is valid */
66 | if (hdrsize < sizeof(*iph))
67 | return TC_ACT_SHOT;
68 |
69 | /* Variable-length IPv4 header, need to use byte-based arithmetic */
70 | if (nh->pos + hdrsize > data_end)
71 | return TC_ACT_SHOT;
72 |
73 | nh->pos += hdrsize;
74 | *iphdr = iph;
75 |
76 | return iph->protocol;
77 | }
78 |
--------------------------------------------------------------------------------
/pkg/ebpfem/ebpf/headers/maps.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The
4 | * OpenFogStack Team.
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, version 3.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | * General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | **/
18 |
19 | // Adapted from: https://github.com/srnbckr/ebpf-network-emulation/blob/main/cmd/headers/maps.h
20 | struct handle_kbps_delay
21 | {
22 | __u32 throttle_rate_kbps;
23 | __u32 delay_us;
24 | } HANDLE_KBPS_DELAY;
25 |
26 | struct
27 | {
28 | __uint(type, BPF_MAP_TYPE_HASH);
29 | __type(key, __u32);
30 | __type(value, HANDLE_KBPS_DELAY);
31 | __uint(max_entries, 65535);
32 | } IP_HANDLE_KBPS_DELAY SEC(".maps");
33 |
--------------------------------------------------------------------------------
/pkg/ebpfem/ebpfem_test.go:
--------------------------------------------------------------------------------
1 | //go:build linux && amd64
2 | // +build linux,amd64
3 |
4 | /*
5 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
6 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The
7 | * OpenFogStack Team.
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation, version 3.
12 | *
13 | * This program is distributed in the hope that it will be useful, but
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program. If not, see .
20 | **/
21 |
22 | package ebpfem
23 |
24 | import (
25 | "fmt"
26 | "net"
27 | "os/exec"
28 | "testing"
29 |
30 | "github.com/pkg/errors"
31 | log "github.com/sirupsen/logrus"
32 |
33 | "github.com/OpenFogStack/celestial/pkg/orchestrator"
34 | )
35 |
36 | const (
37 | HOST_IF = "ens4"
38 | )
39 |
40 | func TestMain(m *testing.M) {
41 | log.SetLevel(log.DebugLevel)
42 |
43 | m.Run()
44 | }
45 |
46 | func TestBasic(t *testing.T) {
47 | id := orchestrator.MachineID{
48 | Group: 1,
49 | Id: 1,
50 | }
51 |
52 | gateway := net.IPNet{
53 | IP: net.IPv4(10, 1, 0, 1),
54 | Mask: net.IPv4Mask(255, 255, 255, 252),
55 | }
56 |
57 | tap := "test-1-1"
58 |
59 | e := New()
60 |
61 | // remove old network device (if it exists)
62 | // ip link del [TAP_NAME]
63 |
64 | cmd := exec.Command("ip", "link", "del", tap)
65 |
66 | if _, err := cmd.CombinedOutput(); err != nil {
67 | // ignore
68 | log.Debugf("could not delete tap %s: %s", tap, err)
69 | }
70 |
71 | // iptables -D FORWARD -i [TAP_NAME] -o [HOSTINTERFACE] -j ACCEPT
72 |
73 | cmd = exec.Command("iptables", "-D", "FORWARD", "-i", tap, "-o", HOST_IF, "-j", "ACCEPT")
74 |
75 | if _, err := cmd.CombinedOutput(); err != nil {
76 | // ignore
77 | log.Debugf("could not delete iptables rule: %s", err)
78 | }
79 |
80 | // create a tap device
81 |
82 | // ip tuntap add [TAP_NAME] mode tap
83 |
84 | cmd = exec.Command("ip", "tuntap", "add", tap, "mode", "tap")
85 |
86 | if out, err := cmd.CombinedOutput(); err != nil {
87 | t.Fatalf("%#v: output: %s", cmd.Args, out)
88 |
89 | }
90 |
91 | // set up proxy ARP
92 | // sysctl -w net.ipv4.conf.[TAP_NAME].proxy_arp=1
93 | cmd = exec.Command("sysctl", "-w", fmt.Sprintf("net.ipv4.conf.%s.proxy_arp=1", tap))
94 |
95 | if out, err := cmd.CombinedOutput(); err != nil {
96 | t.Fatalf("%#v: output: %s", cmd.Args, out)
97 |
98 | }
99 |
100 | // disable ipv6
101 | // sysctl -w net.ipv6.conf.[TAP_NAME].disable_ipv6=1
102 | cmd = exec.Command("sysctl", "-w", fmt.Sprintf("net.ipv6.conf.%s.disable_ipv6=1", tap))
103 |
104 | if out, err := cmd.CombinedOutput(); err != nil {
105 | t.Fatalf("%#v: output: %s", cmd.Args, out)
106 |
107 | }
108 |
109 | // ip addr add [IP_ADDRESS] dev [TAP_NAME]
110 |
111 | cmd = exec.Command("ip", "addr", "add", gateway.String(), "dev", tap)
112 |
113 | if out, err := cmd.CombinedOutput(); err != nil {
114 | t.Fatalf("%#v: output: %s", cmd.Args, out)
115 | }
116 |
117 | // ip link set [TAP_NAME] up
118 |
119 | cmd = exec.Command("ip", "link", "set", tap, "up")
120 |
121 | if out, err := cmd.CombinedOutput(); err != nil {
122 | t.Fatalf("%#v: output: %s", cmd.Args, out)
123 |
124 | }
125 |
126 | // iptables -A FORWARD -i [TAP_NAME] -o [HOSTINTERFACE] -j ACCEPT
127 |
128 | cmd = exec.Command("iptables", "-A", "FORWARD", "-i", tap, "-o", HOST_IF, "-j", "ACCEPT")
129 |
130 | if out, err := cmd.CombinedOutput(); err != nil {
131 | t.Fatalf("%#v: output: %s", cmd.Args, out)
132 |
133 | }
134 |
135 | log.Tracef("created tap %s", tap)
136 | log.Debug("starting ebpf stuff")
137 |
138 | // create a new machine with ebpfem
139 | err := e.Register(id, tap)
140 |
141 | if err != nil {
142 | t.Fatalf("error registering machine: %s", errors.WithStack(err))
143 | }
144 |
145 | // try to block a link
146 | target := net.IPNet{
147 | IP: net.IPv4(10, 1, 0, 4),
148 | Mask: net.IPv4Mask(255, 255, 255, 252),
149 | }
150 |
151 | err = e.SetBandwidth(id, target, 100)
152 |
153 | if err != nil {
154 | t.Fatalf("error setting bandwidth: %s", errors.WithStack(err))
155 | }
156 |
157 | err = e.SetLatency(id, target, 100)
158 |
159 | if err != nil {
160 | t.Fatalf("error setting latency: %s", errors.WithStack(err))
161 | }
162 |
163 | err = e.BlockLink(id, target)
164 |
165 | if err != nil {
166 | t.Fatalf("error blocking link: %s", errors.WithStack(err))
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/pkg/ebpfem/edt_x86_bpfel.go:
--------------------------------------------------------------------------------
1 | // Code generated by bpf2go; DO NOT EDIT.
2 | //go:build 386 || amd64
3 |
4 | package ebpfem
5 |
6 | import (
7 | "bytes"
8 | _ "embed"
9 | "fmt"
10 | "io"
11 |
12 | "github.com/cilium/ebpf"
13 | )
14 |
15 | type edtHandleKbpsDelay struct {
16 | ThrottleRateKbps uint32
17 | DelayUs uint32
18 | }
19 |
20 | // loadEdt returns the embedded CollectionSpec for edt.
21 | func loadEdt() (*ebpf.CollectionSpec, error) {
22 | reader := bytes.NewReader(_EdtBytes)
23 | spec, err := ebpf.LoadCollectionSpecFromReader(reader)
24 | if err != nil {
25 | return nil, fmt.Errorf("can't load edt: %w", err)
26 | }
27 |
28 | return spec, err
29 | }
30 |
31 | // loadEdtObjects loads edt and converts it into a struct.
32 | //
33 | // The following types are suitable as obj argument:
34 | //
35 | // *edtObjects
36 | // *edtPrograms
37 | // *edtMaps
38 | //
39 | // See ebpf.CollectionSpec.LoadAndAssign documentation for details.
40 | func loadEdtObjects(obj interface{}, opts *ebpf.CollectionOptions) error {
41 | spec, err := loadEdt()
42 | if err != nil {
43 | return err
44 | }
45 |
46 | return spec.LoadAndAssign(obj, opts)
47 | }
48 |
49 | // edtSpecs contains maps and programs before they are loaded into the kernel.
50 | //
51 | // It can be passed ebpf.CollectionSpec.Assign.
52 | type edtSpecs struct {
53 | edtProgramSpecs
54 | edtMapSpecs
55 | }
56 |
57 | // edtSpecs contains programs before they are loaded into the kernel.
58 | //
59 | // It can be passed ebpf.CollectionSpec.Assign.
60 | type edtProgramSpecs struct {
61 | TcMain *ebpf.ProgramSpec `ebpf:"tc_main"`
62 | }
63 |
64 | // edtMapSpecs contains maps before they are loaded into the kernel.
65 | //
66 | // It can be passed ebpf.CollectionSpec.Assign.
67 | type edtMapSpecs struct {
68 | IP_HANDLE_KBPS_DELAY *ebpf.MapSpec `ebpf:"IP_HANDLE_KBPS_DELAY"`
69 | FlowMap *ebpf.MapSpec `ebpf:"flow_map"`
70 | }
71 |
72 | // edtObjects contains all objects after they have been loaded into the kernel.
73 | //
74 | // It can be passed to loadEdtObjects or ebpf.CollectionSpec.LoadAndAssign.
75 | type edtObjects struct {
76 | edtPrograms
77 | edtMaps
78 | }
79 |
80 | func (o *edtObjects) Close() error {
81 | return _EdtClose(
82 | &o.edtPrograms,
83 | &o.edtMaps,
84 | )
85 | }
86 |
87 | // edtMaps contains all maps after they have been loaded into the kernel.
88 | //
89 | // It can be passed to loadEdtObjects or ebpf.CollectionSpec.LoadAndAssign.
90 | type edtMaps struct {
91 | IP_HANDLE_KBPS_DELAY *ebpf.Map `ebpf:"IP_HANDLE_KBPS_DELAY"`
92 | FlowMap *ebpf.Map `ebpf:"flow_map"`
93 | }
94 |
95 | func (m *edtMaps) Close() error {
96 | return _EdtClose(
97 | m.IP_HANDLE_KBPS_DELAY,
98 | m.FlowMap,
99 | )
100 | }
101 |
102 | // edtPrograms contains all programs after they have been loaded into the kernel.
103 | //
104 | // It can be passed to loadEdtObjects or ebpf.CollectionSpec.LoadAndAssign.
105 | type edtPrograms struct {
106 | TcMain *ebpf.Program `ebpf:"tc_main"`
107 | }
108 |
109 | func (p *edtPrograms) Close() error {
110 | return _EdtClose(
111 | p.TcMain,
112 | )
113 | }
114 |
115 | func _EdtClose(closers ...io.Closer) error {
116 | for _, closer := range closers {
117 | if err := closer.Close(); err != nil {
118 | return err
119 | }
120 | }
121 | return nil
122 | }
123 |
124 | // Do not access this directly.
125 | //
126 | //go:embed edt_x86_bpfel.o
127 | var _EdtBytes []byte
128 |
--------------------------------------------------------------------------------
/pkg/ebpfem/edt_x86_bpfel.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/pkg/ebpfem/edt_x86_bpfel.o
--------------------------------------------------------------------------------
/pkg/ebpfem/types.go:
--------------------------------------------------------------------------------
1 | //go:build linux && amd64
2 | // +build linux,amd64
3 |
4 | /*
5 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
6 | * Copyright (c) 2024 Soeren Becker, Nils Japke, Tobias Pfandzelter, The
7 | * OpenFogStack Team.
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation, version 3.
12 | *
13 | * This program is distributed in the hope that it will be useful, but
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program. If not, see .
20 | **/
21 |
22 | package ebpfem
23 |
24 | import (
25 | "sync"
26 |
27 | "github.com/OpenFogStack/celestial/pkg/orchestrator"
28 | )
29 |
30 | const (
31 | DEFAULT_LATENCY_US = 0
32 | DEFAULT_BANDWIDTH_KBPS = 1_000_000
33 |
34 | BLOCKED_LATENCY_US = 1_000_000_000
35 | BLOCKED_BANDWIDTH_KBPS = 0
36 | )
37 |
38 | type handleKbpsDelay struct {
39 | throttleRateKbps uint32
40 | delayUs uint32
41 | }
42 |
43 | type vm struct {
44 | netIf string
45 |
46 | // ebpf specific
47 | objs *edtObjects
48 | hbd map[string]*handleKbpsDelay
49 |
50 | sync.Mutex
51 | }
52 |
53 | type EBPFem struct {
54 | vms map[orchestrator.MachineID]*vm
55 | sync.RWMutex
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/info/api.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package info
19 |
20 | type Identifier struct {
21 | Shell uint8 `json:"shell"`
22 | ID uint32 `json:"id"`
23 | Name string `json:"name,omitempty"`
24 | }
25 |
26 | // Node is returned by `/self`, `/gst/{name}` and `/shell/{group}/{id}`.
27 | type Node struct {
28 | Type string `json:"type"`
29 | Active bool `json:"active"`
30 | Identifier Identifier `json:"identifier"`
31 | }
32 |
33 | // Shell is returned by `/shell/{group}`.
34 | type Shell struct {
35 | Sats []Node `json:"sats"`
36 | }
37 |
38 | // Constellation is returned by `/info`.
39 | type Constellation struct {
40 | Shells []Shell `json:"shells"`
41 | Groundstations []Node `json:"groundstations"`
42 | }
43 |
44 | type Segment struct {
45 | Source Identifier `json:"source"`
46 | Target Identifier `json:"target"`
47 | DelayUs uint32 `json:"delay_us,omitempty"`
48 | BandwidthKbps uint64 `json:"bandwidth_kbps,omitempty"`
49 | }
50 |
51 | // Path is returned by `/path/{source_group}/{source_id}/{target_group}/{target_id}`.
52 | type Path struct {
53 | Source Identifier `json:"source"`
54 | Target Identifier `json:"target"`
55 | DelayUs uint32 `json:"delay_us,omitempty"`
56 | BandwidthKbps uint64 `json:"bandwidth_kbits,omitempty"`
57 | Blocked bool `json:"blocked,omitempty"`
58 | Segments []Segment `json:"segments"`
59 | }
60 |
--------------------------------------------------------------------------------
/pkg/netem/ipnet.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package netem
19 |
20 | import "net"
21 |
22 | type ipnet struct {
23 | ipA byte
24 | ipB byte
25 | ipC byte
26 | ipD byte
27 | maskA byte
28 | maskB byte
29 | maskC byte
30 | maskD byte
31 | }
32 |
33 | func (i ipnet) String() string {
34 | n := i.ipnet()
35 | return n.String()
36 | }
37 |
38 | func (i ipnet) ip() net.IP {
39 | return net.IPv4(i.ipA, i.ipB, i.ipC, i.ipD)
40 | }
41 |
42 | func (i ipnet) mask() net.IPMask {
43 | return net.IPv4Mask(i.maskA, i.maskB, i.maskC, i.maskD)
44 | }
45 |
46 | func (i ipnet) ipnet() net.IPNet {
47 | return net.IPNet{
48 | IP: i.ip(),
49 | Mask: i.mask(),
50 | }
51 | }
52 |
53 | func fromIPNet(n net.IPNet) ipnet {
54 | ip := n.IP.To4()
55 | mask := n.Mask
56 |
57 | return ipnet{
58 | ipA: ip[0],
59 | ipB: ip[1],
60 | ipC: ip[2],
61 | ipD: ip[3],
62 | maskA: mask[0],
63 | maskB: mask[1],
64 | maskC: mask[2],
65 | maskD: mask[3],
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/pkg/netem/tc_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package netem
19 |
20 | import (
21 | "net"
22 | "testing"
23 | )
24 |
25 | func Test_getBaseNet(t *testing.T) {
26 | type args struct {
27 | ipNet net.IPNet
28 | }
29 | tests := []struct {
30 | name string
31 | args args
32 | want *net.IPNet
33 | }{
34 | {
35 | name: "test1",
36 | args: args{
37 | ipNet: net.IPNet{
38 | IP: net.IPv4(10, 1, 0, 0),
39 | Mask: net.IPv4Mask(255, 255, 255, 0),
40 | },
41 | },
42 | want: &net.IPNet{
43 | IP: net.IPv4(10, 1, 0, 0),
44 | Mask: net.IPv4Mask(255, 255, 255, 0),
45 | },
46 | },
47 | {
48 | name: "test2",
49 | args: args{
50 | ipNet: net.IPNet{
51 | IP: net.IPv4(10, 1, 0, 1),
52 | Mask: net.IPv4Mask(255, 255, 255, 0),
53 | },
54 | },
55 | want: &net.IPNet{
56 | IP: net.IPv4(10, 1, 0, 0),
57 | Mask: net.IPv4Mask(255, 255, 255, 0),
58 | },
59 | },
60 | {
61 | name: "test3",
62 | args: args{
63 | ipNet: net.IPNet{
64 | IP: net.IPv4(10, 1, 0, 2),
65 | Mask: net.IPv4Mask(255, 255, 255, 0),
66 | },
67 | },
68 | want: &net.IPNet{
69 | IP: net.IPv4(10, 1, 0, 0),
70 | Mask: net.IPv4Mask(255, 255, 255, 0),
71 | },
72 | },
73 | {
74 | name: "test4",
75 | args: args{
76 | ipNet: net.IPNet{
77 | IP: net.IPv4(10, 1, 0, 3),
78 | Mask: net.IPv4Mask(255, 255, 255, 0),
79 | },
80 | },
81 | want: &net.IPNet{
82 | IP: net.IPv4(10, 1, 0, 0),
83 | Mask: net.IPv4Mask(255, 255, 255, 0),
84 | },
85 | },
86 | {
87 | name: "test5",
88 | args: args{
89 | ipNet: net.IPNet{
90 | IP: net.IPv4(10, 1, 0, 4),
91 | Mask: net.IPv4Mask(255, 255, 255, 252),
92 | },
93 | },
94 | want: &net.IPNet{
95 | IP: net.IPv4(10, 1, 0, 4),
96 | Mask: net.IPv4Mask(255, 255, 255, 252),
97 | },
98 | },
99 | }
100 | for _, tt := range tests {
101 | t.Run(tt.name, func(t *testing.T) {
102 | if got := getBaseNet(tt.args.ipNet); got.String() != tt.want.String() {
103 | t.Errorf("getBaseNet() = %v, want %v", got, tt.want)
104 | }
105 | })
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/pkg/orchestrator/network.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package orchestrator
19 |
20 | import (
21 | "fmt"
22 | "sort"
23 | "strings"
24 |
25 | "github.com/pkg/errors"
26 | log "github.com/sirupsen/logrus"
27 | )
28 |
29 | func (n NetworkState) String() string {
30 | s := make([]string, 0)
31 |
32 | for i := range n {
33 | for j := range n[i] {
34 | s = append(s, fmt.Sprintf("%s -> %s : %s", i.String(), j.String(), n[i][j].String()))
35 | }
36 | }
37 |
38 | // sort
39 | sort.Strings(s)
40 |
41 | return strings.Join(s, "\n")
42 | }
43 |
44 | func (l Link) String() string {
45 | if l.Blocked {
46 | return "blocked"
47 | }
48 |
49 | return fmt.Sprintf("%dus %dkbps (next: %s)", l.LatencyUs, l.BandwidthKbps, l.Next.String())
50 | }
51 |
52 | func path(a, b MachineID, n NetworkState) (PathInfo, error) {
53 | if a == b {
54 | return PathInfo{}, errors.Errorf("cannot give path from %s to itself", a)
55 | }
56 |
57 | log.Tracef("path from %s to %s", a.String(), b.String())
58 |
59 | p := PathInfo{
60 | Source: a,
61 | Target: b,
62 | }
63 |
64 | if n[a][b].Blocked {
65 | log.Tracef("path from %s to %s is blocked", a.String(), b.String())
66 | p.Blocked = true
67 | return p, nil
68 | }
69 |
70 | p.LatencyUs = n[a][b].LatencyUs
71 | p.BandwidthKbps = n[a][b].BandwidthKbps
72 | p.Segments = make([]SegmentInfo, 0)
73 |
74 | for a != b {
75 | hop := n[a][b]
76 | log.Tracef("next hop from %s to %s: %s", a.String(), b.String(), hop.String())
77 |
78 | if _, ok := n[a][hop.Next]; !ok {
79 | return PathInfo{}, errors.Errorf("could not find next hop %s for %s", hop.Next.String(), a.String())
80 | }
81 |
82 | s := SegmentInfo{
83 | Source: a,
84 | Target: hop.Next,
85 | LatencyUs: n[a][hop.Next].LatencyUs,
86 | BandwidthKbps: n[a][hop.Next].BandwidthKbps,
87 | }
88 |
89 | p.Segments = append(p.Segments, s)
90 |
91 | a = hop.Next
92 | }
93 |
94 | return p, nil
95 | }
96 |
--------------------------------------------------------------------------------
/pkg/orchestrator/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package orchestrator
19 |
20 | import "fmt"
21 |
22 | type MachineState uint8
23 |
24 | const (
25 | STOPPED MachineState = iota
26 | ACTIVE
27 | )
28 |
29 | type Link struct {
30 | // Blocked is true if the link is blocked
31 | Blocked bool
32 | // Latency in microseconds
33 | LatencyUs uint32
34 | // Bandwidth in kilobytes per second
35 | BandwidthKbps uint64
36 |
37 | // used for path reconstruction
38 | Next MachineID
39 | }
40 |
41 | type MachineID struct {
42 | // is 0 for ground stations
43 | Group uint8
44 | Id uint32
45 | }
46 |
47 | func (m MachineID) String() string {
48 | return fmt.Sprintf("%d.%d", m.Group, m.Id)
49 | }
50 |
51 | type Host uint8
52 |
53 | type NetworkState map[MachineID]map[MachineID]*Link
54 |
55 | type MachinesState map[MachineID]MachineState
56 |
57 | type State struct {
58 | NetworkState
59 | MachinesState
60 | }
61 |
62 | type ISL struct {
63 | // Latency in microseconds
64 | Latency uint32
65 | // Bandwidth in bytes per second
66 | Bandwidth uint64
67 | }
68 |
69 | type machine struct {
70 | name string
71 | Host Host
72 | config MachineConfig
73 | }
74 |
75 | type MachineConfig struct {
76 | VCPUCount uint8
77 | // RAM in bytes
78 | RAM uint64
79 | // DiskSize in bytes
80 | DiskSize uint64
81 | // DiskImage is the path to the disk image
82 | DiskImage string
83 | // Kernel is the path to the kernel
84 | Kernel string
85 | // BootParams are the additional boot parameters
86 | BootParams []string
87 | }
88 |
--------------------------------------------------------------------------------
/pkg/orchestrator/virt.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package orchestrator
19 |
20 | import "net"
21 |
22 | type VirtualizationBackend interface {
23 | RegisterMachine(machine MachineID, name string, host Host, config MachineConfig) error
24 | BlockLink(source MachineID, target MachineID) error
25 | UnblockLink(source MachineID, target MachineID) error
26 | SetLatency(source MachineID, target MachineID, latency uint32) error
27 | SetBandwidth(source MachineID, target MachineID, bandwidth uint64) error
28 | StopMachine(machine MachineID) error
29 | StartMachine(machine MachineID) error
30 | GetIPAddress(id MachineID) (net.IPNet, error)
31 | ResolveIPAddress(ip net.IP) (MachineID, error)
32 | Stop() error
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/virt/link.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package virt
19 |
20 | import (
21 | "net"
22 |
23 | "github.com/OpenFogStack/celestial/pkg/orchestrator"
24 | )
25 |
26 | func (v *Virt) getNetwork(id orchestrator.MachineID) (net.IPNet, error) {
27 | n, err := getNet(id)
28 | if err != nil {
29 | return net.IPNet{}, err
30 | }
31 |
32 | return n.ip, nil
33 | }
34 |
35 | func (v *Virt) setbandwidth(source orchestrator.MachineID, target orchestrator.MachineID, bandwidth uint64) error {
36 | n, err := v.getNetwork(target)
37 | if err != nil {
38 | return err
39 | }
40 | return v.neb.SetBandwidth(source, n, bandwidth)
41 | }
42 |
43 | func (v *Virt) setlatency(source orchestrator.MachineID, target orchestrator.MachineID, latency uint32) error {
44 | n, err := v.getNetwork(target)
45 | if err != nil {
46 | return err
47 | }
48 | return v.neb.SetLatency(source, n, latency)
49 | }
50 |
51 | func (v *Virt) unblocklink(source orchestrator.MachineID, target orchestrator.MachineID) error {
52 | n, err := v.getNetwork(target)
53 | if err != nil {
54 | return err
55 | }
56 | return v.neb.UnblockLink(source, n)
57 | }
58 | func (v *Virt) blocklink(source orchestrator.MachineID, target orchestrator.MachineID) error {
59 | n, err := v.getNetwork(target)
60 | if err != nil {
61 | return err
62 | }
63 | return v.neb.BlockLink(source, n)
64 | }
65 |
--------------------------------------------------------------------------------
/pkg/virt/peer.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package virt
19 |
20 | import "github.com/OpenFogStack/celestial/pkg/orchestrator"
21 |
22 | func (v *Virt) route(m *machine, host orchestrator.Host) error {
23 | return v.pb.Route(m.network.network, host)
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/virt/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package virt
19 |
20 | import (
21 | "net"
22 | "sync"
23 |
24 | "github.com/firecracker-microvm/firecracker-go-sdk"
25 |
26 | "github.com/OpenFogStack/celestial/pkg/orchestrator"
27 | )
28 |
29 | type state uint8
30 |
31 | const (
32 | REGISTERED state = iota
33 | STARTED
34 | STOPPED
35 | KILLED
36 | )
37 |
38 | const HOST_INTERFACE = "ens4"
39 | const GUESTINTERFACE = "eth0"
40 | const ROOTPATH = "/celestial"
41 | const OUTPUTPATH = "/celestial/out"
42 |
43 | var (
44 | IPTABLES_BIN string
45 | IP_BIN string
46 | SYSCTL_BIN string
47 | DD_BIN string
48 | MKFS_BIN string
49 | )
50 |
51 | type network struct {
52 | ip net.IPNet
53 | gateway net.IPNet
54 | network net.IPNet
55 | mac net.HardwareAddr
56 | tap string
57 | }
58 |
59 | type machine struct {
60 | name string
61 |
62 | state state
63 |
64 | vcpucount uint8
65 | ram uint64
66 | disksize uint64
67 | diskimage string
68 | kernel string
69 | bootparams []string
70 |
71 | network network
72 |
73 | vm *firecracker.Machine
74 | }
75 |
76 | // Virt provides virtualization functionality using firecracker.
77 | type Virt struct {
78 | hostInterface string
79 | initDelay uint64 // ignored
80 | pb PeeringBackend
81 | neb NetworkEmulationBackend
82 |
83 | machines map[orchestrator.MachineID]*machine
84 | sync.RWMutex
85 | }
86 |
87 | // PeeringBackend is the interface for the peering backend.
88 | type PeeringBackend interface {
89 | GetHostID() (uint8, error)
90 | Route(network net.IPNet, host orchestrator.Host) error
91 | Stop() error
92 | }
93 |
94 | // NetworkEmulationBackend is the interface for the network emulation backend.
95 | type NetworkEmulationBackend interface {
96 | Register(id orchestrator.MachineID, tap string) error
97 | SetBandwidth(source orchestrator.MachineID, target net.IPNet, bandwidth uint64) error
98 | SetLatency(source orchestrator.MachineID, target net.IPNet, latency uint32) error
99 | UnblockLink(source orchestrator.MachineID, target net.IPNet) error
100 | BlockLink(source orchestrator.MachineID, target net.IPNet) error
101 | Stop() error
102 | }
103 |
--------------------------------------------------------------------------------
/pkg/virt/vm.go:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | package virt
19 |
20 | import (
21 | "context"
22 |
23 | "github.com/pkg/errors"
24 | log "github.com/sirupsen/logrus"
25 |
26 | "github.com/OpenFogStack/celestial/pkg/orchestrator"
27 | )
28 |
29 | func (v *Virt) transition(id orchestrator.MachineID, state state) error {
30 | v.RLock()
31 | m := v.machines[id]
32 | v.RUnlock()
33 |
34 | if m.state == state {
35 | return nil
36 | }
37 |
38 | switch state {
39 | case STOPPED:
40 | switch m.state {
41 | case STARTED:
42 | err := suspendMachine(m)
43 | if err != nil {
44 | return err
45 | }
46 | m.state = STOPPED
47 | return nil
48 | case REGISTERED:
49 | // not started yet, so nothing to do
50 | // but keep it as registered only, so that it can be started if it ever transitions to STARTED
51 | return nil
52 | default:
53 | log.Tracef("cannot transition %s from %d to %d", id, m.state, state)
54 | }
55 | case STARTED:
56 | switch m.state {
57 | case REGISTERED:
58 | err := startMachine(m)
59 | if err != nil {
60 | return err
61 | }
62 | m.state = STARTED
63 | return nil
64 |
65 | case STOPPED:
66 | err := resumeMachine(m)
67 | if err != nil {
68 | return err
69 | }
70 | m.state = STARTED
71 | return nil
72 | default:
73 | log.Tracef("cannot transition %s from %d to %d", id, m.state, state)
74 | }
75 | case REGISTERED:
76 | return errors.Errorf("cannot transition to REGISTERED")
77 | case KILLED:
78 | switch m.state {
79 | case STARTED:
80 | err := killMachine(m)
81 | if err != nil {
82 | return err
83 | }
84 | return nil
85 | case STOPPED:
86 | err := killMachine(m)
87 | if err != nil {
88 | return err
89 | }
90 | return nil
91 | default:
92 | log.Tracef("cannot transition %s from %d to %d", id, m.state, state)
93 | }
94 | }
95 | return nil
96 | }
97 |
98 | func (v *Virt) register(id orchestrator.MachineID, m *machine, config orchestrator.MachineConfig) error {
99 |
100 | m.state = REGISTERED
101 | m.vcpucount = config.VCPUCount
102 | m.ram = config.RAM
103 | m.disksize = config.DiskSize
104 | m.diskimage = config.DiskImage
105 | m.kernel = config.Kernel
106 | m.bootparams = config.BootParams
107 |
108 | // create the network
109 |
110 | err := m.createNetwork()
111 |
112 | if err != nil {
113 | return err
114 | }
115 |
116 | err = v.neb.Register(id, m.network.tap)
117 |
118 | if err != nil {
119 | return err
120 | }
121 |
122 | return nil
123 | }
124 |
125 | func killMachine(m *machine) error {
126 | log.Trace("Killing machine ", m.name)
127 |
128 | err := m.vm.StopVMM()
129 |
130 | if err != nil {
131 | return err
132 | }
133 |
134 | log.Trace("Killed machine ", m.name)
135 |
136 | return nil
137 | }
138 |
139 | func suspendMachine(m *machine) error {
140 | log.Trace("Suspending machine ", m.name)
141 | return m.vm.PauseVM(context.Background())
142 | }
143 |
144 | func resumeMachine(m *machine) error {
145 | log.Trace("Resuming machine ", m.name)
146 | return m.vm.ResumeVM(context.Background())
147 | }
148 |
149 | func startMachine(m *machine) error {
150 | log.Trace("Starting machine ", m.name)
151 | // perform init tasks
152 | err := m.initialize()
153 |
154 | if err != nil {
155 | return err
156 | }
157 |
158 | return m.vm.Start(context.Background())
159 | }
160 |
--------------------------------------------------------------------------------
/proto/celestial/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | import os
19 | import sys
20 |
21 | currentdir = os.path.dirname(os.path.realpath(__file__))
22 | sys.path.append(currentdir)
23 |
--------------------------------------------------------------------------------
/proto/celestial/celestial.proto:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | * Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | **/
17 |
18 | syntax = "proto3";
19 |
20 | package openfogstack.celestial.celestial;
21 | option go_package = "./;celestial";
22 |
23 | service Celestial {
24 | rpc Register(RegisterRequest) returns (RegisterResponse);
25 | rpc Init(InitRequest) returns (Empty);
26 | rpc Update(stream StateUpdateRequest) returns (Empty);
27 | rpc Stop(Empty) returns (Empty);
28 | }
29 |
30 | enum VMState {
31 | VM_STATE_STOPPED = 0;
32 | VM_STATE_ACTIVE = 1;
33 | }
34 |
35 | message MachineID {
36 | uint32 group = 1;
37 | uint32 id = 2;
38 | }
39 |
40 | message Empty {}
41 |
42 | message RegisterRequest {
43 | uint32 host = 1;
44 | }
45 |
46 | message RegisterResponse {
47 | uint32 available_cpus = 1;
48 | uint64 available_ram = 2;
49 | string peer_public_key = 3;
50 | string peer_listen_addr = 4;
51 | }
52 |
53 | message InitRequest {
54 | message Host {
55 | uint32 id = 1;
56 | string peer_public_key = 2;
57 | string peer_listen_addr = 3;
58 | }
59 |
60 | repeated Host hosts = 1;
61 | message Machine {
62 | message MachineConfig {
63 | // should also be 8 bit but protobuf doesn't support uint8...
64 | uint32 vcpu_count = 1;
65 | uint64 ram = 2;
66 | uint64 disk_size = 3;
67 | string root_image = 4;
68 | string kernel = 5;
69 | repeated string boot_parameters = 6;
70 | }
71 |
72 | MachineID id = 1;
73 | optional string name = 2;
74 | // should actually be 8 bit but protobuf doesn't support uint8...
75 | uint32 host = 3;
76 | MachineConfig config = 4;
77 | }
78 |
79 | repeated Machine machines = 2;
80 | }
81 |
82 | message StateUpdateRequest {
83 | message MachineDiff {
84 | VMState active = 1;
85 | MachineID id = 2;
86 | }
87 | message NetworkDiff {
88 | bool blocked = 1;
89 | MachineID source = 2;
90 | MachineID target = 3;
91 | uint32 latency_us = 4;
92 | uint64 bandwidth_kbps = 5;
93 | // used for path reconstruction
94 | MachineID next = 6;
95 | MachineID prev = 7;
96 | }
97 |
98 | repeated MachineDiff machine_diffs = 1;
99 | repeated NetworkDiff network_diffs = 2;
100 | }
101 |
--------------------------------------------------------------------------------
/proto/celestial/celestial_pb2_grpc.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 |
5 | This file is part of Celestial (https://github.com/OpenFogStack/celestial).
6 | Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, version 3.
11 |
12 | This program is distributed in the hope that it will be useful, but
13 | WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | """
20 | import abc
21 | import celestial_pb2
22 | import collections.abc
23 | import grpc
24 | import grpc.aio
25 | import typing
26 |
27 | _T = typing.TypeVar('_T')
28 |
29 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta):
30 | ...
31 |
32 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore
33 | ...
34 |
35 | class CelestialStub:
36 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ...
37 | Register: grpc.UnaryUnaryMultiCallable[
38 | celestial_pb2.RegisterRequest,
39 | celestial_pb2.RegisterResponse,
40 | ]
41 | Init: grpc.UnaryUnaryMultiCallable[
42 | celestial_pb2.InitRequest,
43 | celestial_pb2.Empty,
44 | ]
45 | Update: grpc.StreamUnaryMultiCallable[
46 | celestial_pb2.StateUpdateRequest,
47 | celestial_pb2.Empty,
48 | ]
49 | Stop: grpc.UnaryUnaryMultiCallable[
50 | celestial_pb2.Empty,
51 | celestial_pb2.Empty,
52 | ]
53 |
54 | class CelestialAsyncStub:
55 | Register: grpc.aio.UnaryUnaryMultiCallable[
56 | celestial_pb2.RegisterRequest,
57 | celestial_pb2.RegisterResponse,
58 | ]
59 | Init: grpc.aio.UnaryUnaryMultiCallable[
60 | celestial_pb2.InitRequest,
61 | celestial_pb2.Empty,
62 | ]
63 | Update: grpc.aio.StreamUnaryMultiCallable[
64 | celestial_pb2.StateUpdateRequest,
65 | celestial_pb2.Empty,
66 | ]
67 | Stop: grpc.aio.UnaryUnaryMultiCallable[
68 | celestial_pb2.Empty,
69 | celestial_pb2.Empty,
70 | ]
71 |
72 | class CelestialServicer(metaclass=abc.ABCMeta):
73 | @abc.abstractmethod
74 | def Register(
75 | self,
76 | request: celestial_pb2.RegisterRequest,
77 | context: _ServicerContext,
78 | ) -> typing.Union[celestial_pb2.RegisterResponse, collections.abc.Awaitable[celestial_pb2.RegisterResponse]]: ...
79 | @abc.abstractmethod
80 | def Init(
81 | self,
82 | request: celestial_pb2.InitRequest,
83 | context: _ServicerContext,
84 | ) -> typing.Union[celestial_pb2.Empty, collections.abc.Awaitable[celestial_pb2.Empty]]: ...
85 | @abc.abstractmethod
86 | def Update(
87 | self,
88 | request_iterator: _MaybeAsyncIterator[celestial_pb2.StateUpdateRequest],
89 | context: _ServicerContext,
90 | ) -> typing.Union[celestial_pb2.Empty, collections.abc.Awaitable[celestial_pb2.Empty]]: ...
91 | @abc.abstractmethod
92 | def Stop(
93 | self,
94 | request: celestial_pb2.Empty,
95 | context: _ServicerContext,
96 | ) -> typing.Union[celestial_pb2.Empty, collections.abc.Awaitable[celestial_pb2.Empty]]: ...
97 |
98 | def add_CelestialServicer_to_server(servicer: CelestialServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ...
99 |
--------------------------------------------------------------------------------
/quick-start/.gitignore:
--------------------------------------------------------------------------------
1 | *.zip
2 | *.img
3 | *.bin
4 | *.ext4
5 |
--------------------------------------------------------------------------------
/quick-start/README.md:
--------------------------------------------------------------------------------
1 | # Quick Start
2 |
3 | This directory contains a quick start example to help you get into Celestial.
4 | Please refer to our [quick start guide](https://openfogstack.github.io/celestial/quickstart)
5 | to get started.
6 |
--------------------------------------------------------------------------------
/quick-start/check_validator.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | import pandas as pd
5 | import matplotlib.pyplot as plt
6 | import seaborn as sns
7 |
8 | GRAPHS_DIR = "./graphs"
9 | NUM_HOSTS = 2
10 |
11 | sns.set(rc={"figure.figsize": (9, 3)}, style="whitegrid")
12 |
13 |
14 | def save_fig(ax: plt.Axes, name: str, file_type: str = "png") -> None:
15 | fig = ax.get_figure()
16 | fig.tight_layout()
17 | file_name = name + "." + file_type
18 | os.makedirs(GRAPHS_DIR, exist_ok=True)
19 | fig.savefig(os.path.join(GRAPHS_DIR, file_name), bbox_inches="tight")
20 | fig.clear()
21 |
22 |
23 | if __name__ == "__main__":
24 | # usage: python3 check_validator.py [results.csv]
25 | if not len(sys.argv) == 2:
26 | exit("Usage: python3 check_validator.py [results.csv]")
27 |
28 | results_file = sys.argv[1]
29 |
30 | # read the data file
31 | validate = pd.read_csv(results_file)
32 |
33 | # convert the "0.0" times to "1e7", i.e., "infinity"
34 | # validate["actual"] = validate["actual"].apply(lambda x: 1e7 if x == 0.0 else x)
35 |
36 | # normalize the start time to 0
37 | start_time = validate["t"].min()
38 | validate["t"] = validate["t"] - start_time
39 |
40 | # we check with the database service before and after the ping
41 | # so our expected value is the average of the two
42 | # BUT the database only gives us one-way latency, while the ping
43 | # service gives us two-way latency
44 | # so we need to double the expected latency as well
45 | validate["expected"] = (
46 | (validate["expected_before"] + validate["expected_after"]) / 2
47 | ) * 2
48 |
49 | # unless the value is 1e7, in which case the expected value becomes 2e7
50 | validate["expected"] = validate["expected"].apply(
51 | (lambda x: 1e7 if x == 2e7 else x)
52 | )
53 |
54 | # the difference is the expected value minus the actual measurement
55 | validate["diff"] = abs((validate["expected"]) - validate["actual"])
56 |
57 | # satellites are distributed across our hosts by modulo
58 | validate["host"] = validate["sat"] % NUM_HOSTS
59 |
60 | # let's give our differences a few limits
61 | # less than three ms difference is still acceptable, anything above 100 is
62 | # considered a problem
63 | # note that 1e7 is a lot above any measurement
64 | validate["OK"] = validate["diff"].apply(
65 | (lambda x: "OK" if abs(x) < 3 else "MEH" if abs(x) < 100 else "NOT OK")
66 | )
67 |
68 | # let's plot the results and check if there are any problems
69 | results_scatter = sns.scatterplot(
70 | data=validate, x="t", y="diff", hue="OK", style="host"
71 | )
72 |
73 | save_fig(results_scatter, "results_scatter")
74 |
75 | # let's see the differences we have observed
76 | # 60% are great at 0ms
77 | # 90% are ok below 4ms
78 | diff_ecdf = sns.ecdfplot(data=validate[validate["OK"] != "NOT OK"], x="diff")
79 | save_fig(diff_ecdf, "diff_ecdf")
80 |
81 | # first plot the _expected_ values
82 | expected_line = sns.lineplot(data=validate, x="t", y="expected", hue="sat")
83 | expected_line.set_yscale("log")
84 | save_fig(expected_line, "expected_line")
85 |
86 | # then plot the actual measurements
87 | actual_line = sns.lineplot(data=validate, x="t", y="actual", hue="sat")
88 | actual_line.set_yscale("log")
89 | save_fig(actual_line, "actual_line")
90 |
91 | # let's see only the ones that are not unreachable next
92 | validate_reachable = validate[
93 | (validate["expected"] < 1e7) & (validate["actual"] < 1e7)
94 | ]
95 |
96 | # first plot the _expected_ values
97 | reachable_expected = sns.lineplot(
98 | data=validate_reachable, x="t", y="expected", hue="sat"
99 | )
100 | reachable_expected.set_yscale("log")
101 | save_fig(reachable_expected, "reachable_expected")
102 |
103 | # then plot the actual measurements
104 | reachable_actual = sns.lineplot(
105 | data=validate_reachable, x="t", y="actual", hue="sat"
106 | )
107 | reachable_actual.set_yscale("log")
108 | save_fig(reachable_actual, "reachable_actual")
109 |
--------------------------------------------------------------------------------
/quick-start/graphs/actual_line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/actual_line.png
--------------------------------------------------------------------------------
/quick-start/graphs/diff_ecdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/diff_ecdf.png
--------------------------------------------------------------------------------
/quick-start/graphs/expected_line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/expected_line.png
--------------------------------------------------------------------------------
/quick-start/graphs/reachable_actual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/reachable_actual.png
--------------------------------------------------------------------------------
/quick-start/graphs/reachable_expected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/reachable_expected.png
--------------------------------------------------------------------------------
/quick-start/graphs/results_scatter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFogStack/celestial/13e79114c52fde94a11202c0992ac2fd298c6e1d/quick-start/graphs/results_scatter.png
--------------------------------------------------------------------------------
/quick-start/quickstart.toml:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | # This is a simple configuration file for Celestial that is used in our
19 | # quick-start guide.
20 |
21 | # Our bounding box determines which satellites will be emulated. We only
22 | # want satellites that are roughly above Europe.
23 | bbox = [35.000000, -15.000000, 65.000000, 35.000000]
24 |
25 | # We want an update to the topology every five second.
26 | resolution = 5
27 |
28 | # Our entire experiment should run for 15 minutes.
29 | duration = 900
30 |
31 | # These are the network parameters. We want a bandwidth of 10 Mbit/s, a
32 | # mininum elevation for radio links of about 25 degrees (common for Starlink),
33 | # and our ground station should connect to all satellites in reach (instead of
34 | # only the closest one).
35 | [network_params]
36 | bandwidth_kbits = 10_000_000
37 | min_elevation = 25
38 | ground_station_connection_type = "all"
39 |
40 | # This configures the compute parameters for our satellites. We want 1 vCPU,
41 | # 256 MiB of RAM, 1 GiB of disk space, and we want to boot the v5.12 kernel
42 | # we downloaded with the server.img root file system. We will override some
43 | # of these parameters for our ground station below.
44 | [compute_params]
45 | vcpu_count = 1
46 | mem_size_mib = 256
47 | disk_size_mib = 1
48 | kernel = "vmlinux-5.12.bin"
49 | rootfs = "server.img"
50 |
51 | # This is the satellite constellation configuration. We follow an older
52 | # Starlink configuration with 72 planes and 22 satellites per plane. The
53 | # satellites are at an altitude of 550 km, have an inclination of 53 degrees,
54 | # and their ascending nodes are evenly distributed over 360 degrees (Walker
55 | # Delta). The eccentricity is 0, so the orbits are circular.
56 | [[shell]]
57 | planes = 72
58 | sats = 22
59 | altitude_km = 550
60 | inclination = 53.0
61 | arc_of_ascending_nodes = 360.0
62 | eccentricity = 0.0
63 |
64 | # This is our validator ground station located in Berlin.
65 | [[ground_station]]
66 | name = "validator"
67 | lat = 52.51492067
68 | long = 13.32666938
69 |
70 | # We change some of the compute parameters for our ground station. We want
71 | # 4 vCPUs, 4 GiB of RAM, 10 GiB of disk space, and we want to boot with the
72 | # validator.img root file system.
73 | [ground_station.compute_params]
74 | vcpu_count = 4
75 | mem_size_mib = 4096
76 | disk_size_mib = 10
77 | rootfs = "validator.img"
78 |
--------------------------------------------------------------------------------
/quick-start/requirements.txt:
--------------------------------------------------------------------------------
1 | pandas==2.1.0
2 | seaborn==0.13.1
3 |
--------------------------------------------------------------------------------
/quick-start/tofu/gcloud.tf:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | terraform {
19 | backend "local" {}
20 | }
21 |
22 | provider "google" {
23 | project = var.gcp_project
24 | region = var.gcp_region
25 | }
26 |
27 | variable "gcp_project" {
28 | # default = YOUR_GCP_PROJECT_ID
29 | }
30 |
31 | variable "gcp_region" {
32 | default = "europe-west3"
33 | }
34 |
35 | variable "gcp_zone" {
36 | default = "c"
37 | }
38 |
39 | variable "coordinator_type" {
40 | default = "n2-standard-8"
41 | }
42 |
43 | variable "host_type" {
44 | default = "n2-standard-32"
45 | }
46 |
47 | variable "host_count" {
48 | default = 2
49 | }
50 |
51 | output "host_ip" {
52 | value = google_compute_instance.celestial-test-host.*.network_interface.0.access_config.0.nat_ip
53 | }
54 |
55 | # the zone variable must be within the region
56 | # hence this weird setup
57 | locals {
58 | zone = "${var.gcp_region}-${var.gcp_zone}"
59 | }
60 |
61 | # we use a version of Ubuntu 22.04 LTS
62 | # this data item gives us the latest available image
63 | data "google_compute_image" "ubuntu2204image" {
64 | family = "ubuntu-2204-lts"
65 | project = "ubuntu-os-cloud"
66 | }
67 |
68 | # we want our instances to be able to talk to each other directly
69 | # hence we add them all to a dedicated network
70 | resource "google_compute_network" "celestial-test-network" {
71 | name = "celestial-test-network"
72 | description = "This network connects Celestial hosts."
73 | auto_create_subnetworks = true
74 | }
75 |
76 | # we also need to enable ingress to our machines
77 | resource "google_compute_firewall" "celestial-test-net-firewall-external" {
78 | name = "celestial-test-net-firewall-external"
79 | description = "This firewall allows external connections to our instance for ssh."
80 | network = google_compute_network.celestial-test-network.id
81 | direction = "INGRESS"
82 | source_ranges = ["0.0.0.0/0"]
83 |
84 | allow {
85 | protocol = "tcp"
86 | ports = ["22", "1969"]
87 | }
88 | }
89 |
90 | # and enable ingress between the machines
91 | resource "google_compute_firewall" "celestial-test-net-firewall-internal" {
92 | name = "celestial-test-net-firewall-internal"
93 | description = "This firewall allows internal connections between our instances."
94 | network = google_compute_network.celestial-test-network.id
95 | direction = "INGRESS"
96 | source_ranges = formatlist("%s/32", google_compute_instance.celestial-test-host.*.network_interface.0.access_config.0.nat_ip)
97 |
98 | allow {
99 | protocol = "udp"
100 | ports = ["1970"]
101 | }
102 | allow {
103 | protocol = "icmp"
104 | }
105 | }
106 |
107 |
108 | # we need to create an image for our hosts
109 | # this needs a custom license to use nested virtualization
110 | resource "google_compute_image" "celestial-test-host-image" {
111 | name = "celestial-test-host-image"
112 | source_image = data.google_compute_image.ubuntu2204image.self_link
113 | licenses = ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-2204-lts", "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"]
114 | }
115 |
116 | # the host instance runs Ubuntu 22.04
117 | resource "google_compute_instance" "celestial-test-host" {
118 | name = "celestial-test-host-${count.index}"
119 | count = var.host_count
120 | machine_type = var.host_type
121 | zone = local.zone
122 |
123 | boot_disk {
124 | initialize_params {
125 | image = google_compute_image.celestial-test-host-image.self_link
126 | }
127 | }
128 |
129 | # adapter for internal network
130 | network_interface {
131 | network = google_compute_network.celestial-test-network.id
132 | # get an external IP address
133 | access_config {}
134 | }
135 |
136 | service_account {
137 | scopes = ["cloud-platform"]
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/quick-start/validator/server.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | # The app script runs when a microVM boots.
21 | # This server just needs to answer to pings, so to prevent it from shutting
22 | # down, we just run an infinite loop.
23 | while true; do
24 | echo "$(date): satellite server running!"
25 | sleep 300
26 | done
27 |
--------------------------------------------------------------------------------
/quick-start/validator/validator-base.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | # Our base script installs all the necessary dependencies for the validation
21 | # script. This is actually only Python 3 and a few Python 3 packages.
22 |
23 | # Add git, curl, and python3 to the root filesystem.
24 | # git and curl are needed for pip.
25 | apk add git curl python3 py3-pip
26 |
27 | # Add the python3 dependencies: request and ping3
28 | python3 -m pip install ping3 requests
29 |
--------------------------------------------------------------------------------
/quick-start/validator/validator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | # Our application script runs as soon as the microVM boots. Here, we mostly
21 | # need to start our validator.py script. This script requires one input:
22 | # the address of the HTTP info server. Using our builder, this is set as the
23 | # hostname "info.celestial".
24 |
25 | # Now we can start our validator script!
26 | python3 validator.py info.celestial
27 |
--------------------------------------------------------------------------------
/requirements-animation.txt:
--------------------------------------------------------------------------------
1 | vtk==9.3.0
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | cerberus==1.3.5
2 | grpcio==1.59.0
3 | grpcio-tools==1.59.0
4 | llvmlite==0.41.1
5 | mypy==1.9.0
6 | mypy-protobuf==3.5.0
7 | numba==0.58.1
8 | numpy==1.26.1
9 | protobuf==4.24.4
10 | seaborn==0.13.1
11 | sgp4==2.23
12 | toml @ git+https://github.com/uiri/toml@5706d31
13 | tqdm==4.66.1
14 | types-requests==2.31.0.20240106
15 | types-toml==0.10.8.7
16 |
--------------------------------------------------------------------------------
/satgen.Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | FROM python:3.11-slim
19 |
20 | RUN apt update && apt install -y \
21 | --no-install-recommends \
22 | --no-install-suggests \
23 | git && \
24 | apt clean && rm -rf /var/lib/apt/lists/*
25 |
26 | COPY requirements.txt .
27 | RUN pip install -r requirements.txt
28 |
29 | COPY satgen.py .
30 | COPY celestial/*.py celestial/
31 |
32 | ENTRYPOINT ["python", "satgen.py"]
--------------------------------------------------------------------------------
/satgen.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | """
19 | Satgen generates satellite trajectories and network configurationfs for a
20 | Celestial emulation run. It takes a TOML configuration file as an input
21 | and generates a custom .zip format file as an output that contains changes
22 | in network topologies at each time step.
23 |
24 | To use satgen.py, you will need a full Celestial configuration file. Satgen
25 | will check that the configuration file matches its expectations and will
26 | exit with an error if it does not.
27 |
28 | Prerequisites
29 | -------------
30 |
31 | Make sure you have all the necessary dependencies installed. You can install
32 | them using pip in a virtual environment:
33 |
34 | python3 -m venv .venv
35 | source .venv/bin/activate
36 | pip install -r requirements.txt
37 |
38 |
39 |
40 | Usage
41 | -----
42 |
43 | python3 satgen.py [config.toml] [output-file (optional)]
44 |
45 | The output will be in the specified path or in a generated file based on a hash
46 | of the configuration file if no output path is specified.
47 | """
48 |
49 | import sys
50 |
51 | import toml
52 | import tqdm
53 |
54 | import celestial.config
55 | import celestial.zip_serializer
56 | import celestial.satgen_connstellation
57 |
58 | if __name__ == "__main__":
59 | if len(sys.argv) > 3 or len(sys.argv) < 2:
60 | exit("Usage: python3 celestial.py [config.toml] [output-file (optional)]")
61 |
62 | # read toml
63 | try:
64 | text_config = toml.load(sys.argv[1])
65 | except Exception as e:
66 | exit(str(e))
67 |
68 | output_file = None
69 | if len(sys.argv) == 3:
70 | output_file = sys.argv[2]
71 |
72 | # read the configuration
73 | config: celestial.config.Config = celestial.config.Config(text_config)
74 |
75 | # prepare serializer
76 | # serializer = celestial.json_serializer.JSONSerializer(config)
77 | serializer = celestial.zip_serializer.ZipSerializer(config, output_file)
78 |
79 | # init the constellation
80 | constellation = celestial.satgen_connstellation.SatgenConstellation(
81 | config, serializer
82 | )
83 |
84 | # run the simulation
85 | i = 0 + config.offset
86 | pbar = tqdm.tqdm(total=int(config.duration / config.resolution))
87 | while i < config.duration + config.offset:
88 | # import cProfile
89 |
90 | # cProfile.run("constellation.step(i)", sort="cumtime")
91 | constellation.step(i)
92 | i += config.resolution
93 | pbar.update(1)
94 |
95 | # serialize the state
96 | serializer.persist()
97 |
98 | print(f"Output written to {serializer.filename}")
99 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [mypy]
2 | python_version = 3.11
3 | warn_unused_configs = True
4 | disallow_any_generics = True
5 | disallow_untyped_calls = True
6 | disallow_untyped_defs = True
7 | disallow_incomplete_defs = True
8 | check_untyped_defs = True
9 | warn_return_any = True
10 | strict_equality = True
11 | ignore_missing_imports = True
12 | show_column_numbers = True
13 | plugins = numpy.typing.mypy_plugin
14 |
--------------------------------------------------------------------------------
/test/integration/.gitignore:
--------------------------------------------------------------------------------
1 | id_ed25519
2 | id_ed25519.pub
3 | rootfs.id_rsa
4 | rootfs.ext4
5 |
--------------------------------------------------------------------------------
/test/integration/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "tofu init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.opentofu.org/hashicorp/google" {
5 | version = "5.11.0"
6 | hashes = [
7 | "h1:SZvItcManUwdLWQIxHWVgiW0BXbide6kqQAL7XgRTV8=",
8 | "zh:1a92a4e747b7ab14fdfa471a8b58155e3f509a18d4b5c155ca2cfb925a687f65",
9 | "zh:274ce607e702a28d1b2c8307341d2e0b95c85329b8ff743d05ea504811ccdd86",
10 | "zh:5f071bccac9325b771dce2bf83d44ab93159b2d175ebc4543323383da15e6dd3",
11 | "zh:6f6693b4097edf6644301724de54889d2d0f1f79c0d7d429e2957e5a88a9b31d",
12 | "zh:6f82dc7d012d587407bf2a0537bc0591c0de00ee4a31256ea3a8c562730ea88e",
13 | "zh:7f4783582548678630ffa583d27c561f2966d7c6bc0dd6ce7b96bf815396a4c3",
14 | "zh:844111efd3e6bd23fb9651cc889fe47cdc107d2c0606bc7293ca5e8694165d88",
15 | "zh:9e91d192d1a588cf1ee7c346547cff29134d39a378147b79637c23f0aaa350e8",
16 | "zh:b64b046a78e5ed3b26735bb32e53c8437fb416d278e44cf2a836ab415d30a81e",
17 | "zh:b9271c241890c5daaf0852ca533c58a649206f676e7aa115be88dd17a3365c04",
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/test/integration/dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | set -ex
20 |
21 | sudo apt-get update
22 |
23 | sudo apt-get install \
24 | --no-install-recommends \
25 | --no-install-suggests \
26 | -y g++ gcc make cmake build-essential
27 |
28 | # install go
29 | curl -fsSL -o go1.22.1.linux-amd64.tar.gz \
30 | https://go.dev/dl/go1.22.1.linux-amd64.tar.gz
31 | sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.22.1.linux-amd64.tar.gz
32 | export PATH=$PATH:/usr/local/go/bin
33 | echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
34 |
35 | # we need the /celestial folder available on the hosts
36 | sudo mkdir -p /celestial
37 |
38 | # we also need wireguard and ipset as dependencies
39 | sudo apt-get install \
40 | --no-install-recommends \
41 | --no-install-suggests \
42 | -y wireguard ipset
43 |
44 | # and we need firecracker on the machine
45 | # download the current release
46 | curl -fsSL -o firecracker-v1.6.0-x86_64.tgz \
47 | https://github.com/firecracker-microvm/firecracker/releases/download/v1.6.0/firecracker-v1.6.0-x86_64.tgz
48 | tar -xvf firecracker-v1.6.0-x86_64.tgz
49 | # and add the firecracker and jailer binaries
50 | sudo mv release-v1.6.0-x86_64/firecracker-v1.6.0-x86_64 /usr/local/bin/firecracker
51 | sudo mv release-v1.6.0-x86_64/seccompiler-bin-v1.6.0-x86_64 /usr/local/bin/jailer
52 |
53 | sudo mv vmlinux-5.12.bin /celestial/vmlinux.bin
54 |
55 | # sometimes it can also be helpful to increase process and file handler
56 | # limits on your host machines:
57 | cat << END > ./limits.conf
58 | * soft nofile 64000
59 | * hard nofile 64000
60 | root soft nofile 64000
61 | root hard nofile 64000
62 | * soft nproc 64000
63 | * hard nproc 64000
64 | root soft nproc 64000
65 | root hard nproc 64000
66 | END
67 |
68 | sudo mv ./limits.conf /etc/security/limits.conf
69 |
70 | go mod download
71 |
--------------------------------------------------------------------------------
/test/integration/fileslist.txt:
--------------------------------------------------------------------------------
1 | test/integration/dependencies.sh
2 | test/integration/id_ed25519
3 | test/integration/rootfs/ssh.img
4 | proto
5 | pkg
6 | celestial.go
7 | go.mod
8 | go.sum
9 | kernel/vmlinux-5.12.bin
10 | test/integration/celestial_test.go
11 |
--------------------------------------------------------------------------------
/test/integration/google.auto.tfvars:
--------------------------------------------------------------------------------
1 | gcp_project = "celestial-306310"
2 |
--------------------------------------------------------------------------------
/test/integration/infrastructure.tf:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | provider "google" {
19 | project = var.gcp_project
20 | region = var.gcp_region
21 | }
22 |
23 | variable "gcp_project" {
24 | # default = YOUR_GCP_PROJECT_ID
25 | }
26 |
27 | variable "gcp_region" {
28 | default = "europe-west3"
29 | }
30 |
31 | variable "gcp_zone" {
32 | default = "a"
33 | }
34 |
35 | variable "host_type" {
36 | default = "n2-standard-2"
37 | }
38 |
39 | output "zone" {
40 | value = local.zone
41 | }
42 |
43 | output "host_name" {
44 | value = format("%s.%s.%s", google_compute_instance.celestial-test-host.name, local.zone, var.gcp_project)
45 | }
46 |
47 | output "host_id" {
48 | value = google_compute_instance.celestial-test-host.name
49 | }
50 |
51 | output "project" {
52 | value = var.gcp_project
53 | }
54 |
55 | # the zone variable must be within the region
56 | # hence this weird setup
57 | locals {
58 | zone = "${var.gcp_region}-${var.gcp_zone}"
59 | }
60 |
61 | # we use a version of Ubuntu 22.04 LTS
62 | # this data item gives us the latest available image
63 | data "google_compute_image" "ubuntu2204image" {
64 | family = "ubuntu-2204-lts"
65 | project = "ubuntu-os-cloud"
66 | }
67 |
68 | # we want our instances to be able to talk to each other directly
69 | # hence we add them all to a dedicated network
70 | resource "google_compute_network" "celestial-test-network" {
71 | name = "celestial-test-network"
72 | description = "This network connects Celestial hosts."
73 | auto_create_subnetworks = true
74 | }
75 |
76 | # we also need to enable ingress to our machines
77 | resource "google_compute_firewall" "celestial-test-net-firewall-external" {
78 | name = "celestial-test-net-firewall-external"
79 | description = "This firewall allows external connections to our instance for ssh."
80 | network = google_compute_network.celestial-test-network.id
81 | direction = "INGRESS"
82 | source_ranges = ["0.0.0.0/0"]
83 |
84 | allow {
85 | protocol = "tcp"
86 | ports = ["22"]
87 | }
88 | }
89 |
90 | # reserve a static external IP address
91 | resource "google_compute_address" "celestial-test-host-ip" {
92 | name = "celestial-test-host-ip"
93 | }
94 |
95 | # we need to create an image for our hosts
96 | # this needs a custom license to use nested virtualization
97 | resource "google_compute_image" "celestial-test-host-image" {
98 | name = "celestial-test-host-image"
99 | # source_disk = google_compute_disk.celestial-host-disk.self_link
100 | source_image = data.google_compute_image.ubuntu2204image.self_link
101 | licenses = ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-2204-lts", "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"]
102 | }
103 |
104 | # the host instance runs Ubuntu 22.04
105 | resource "google_compute_instance" "celestial-test-host" {
106 | name = "celestial-test-host"
107 | machine_type = var.host_type
108 | zone = local.zone
109 |
110 | boot_disk {
111 | initialize_params {
112 | image = google_compute_image.celestial-test-host-image.self_link
113 | }
114 | }
115 |
116 | # adapter for internal network
117 | network_interface {
118 | network = google_compute_network.celestial-test-network.id
119 |
120 | # use the static IP address
121 | access_config {
122 | nat_ip = google_compute_address.celestial-test-host-ip.address
123 | }
124 | }
125 |
126 | service_account {
127 | scopes = ["cloud-platform"]
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/test/integration/integration.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | # the -no-reboot flag is used to prevent the instance from rebooting
20 | REBOOT=1
21 |
22 | # the other argument is the host: ip address or gcloud
23 | TEST_HOST=""
24 |
25 | for i in "$@"
26 | do
27 | case $i in
28 | -no-reboot)
29 | REBOOT=0
30 | shift # past argument=value
31 | ;;
32 | -host=*)
33 | TEST_HOST="${i#*=}"
34 | shift # past argument=value
35 | ;;
36 | *)
37 | # unknown option
38 | ;;
39 | esac
40 | done
41 |
42 | # check that the host is set
43 | if [ -z "$TEST_HOST" ]; then
44 | echo "No host set!"
45 | echo "Please set the host with -host=... or use -host=gcloud to use terraform"
46 | exit 1
47 | fi
48 |
49 | set -xe
50 |
51 | DIVIDER="=============================="
52 | ROOT="../.."
53 |
54 | pushd "$ROOT"
55 | make rootfsbuilder
56 | popd
57 |
58 | pushd rootfs
59 | make
60 | popd
61 |
62 | echo "$DIVIDER"
63 | echo "Running preparation..."
64 | echo "$DIVIDER"
65 |
66 | ./make_key.sh
67 |
68 | # make the infrastructure if we use gcloud
69 | if [ "$TEST_HOST" == "gcloud" ]; then
70 | tofu init
71 | tofu apply -auto-approve
72 |
73 |
74 | GCP_ZONE="$(tofu output -json | jq -r '.zone.value')"
75 | GCP_PROJECT="$(tofu output -json | jq -r '.project.value')"
76 | GCR_INSTANCE_FULL="$(tofu output -json | jq -r '.host_name.value')"
77 | GCP_INSTANCE="$(tofu output -json | jq -r '.host_id.value')"
78 |
79 | gcloud config set project "$GCP_PROJECT"
80 | SSH_ADDRESS="$GCR_INSTANCE_FULL"
81 | else
82 | SSH_ADDRESS="$TEST_HOST"
83 | fi
84 |
85 | if [ "$REBOOT" -eq 1 ]; then
86 | if [ "$TEST_HOST" == "gcloud" ]; then
87 | # restart the machines
88 | gcloud compute instances stop --zone="$GCP_ZONE" "$GCP_INSTANCE"
89 | sleep 1
90 | gcloud compute instances start --zone="$GCP_ZONE" "$GCP_INSTANCE"
91 |
92 | gcloud compute config-ssh
93 | else
94 | # at least reboot the machine
95 | ssh "$SSH_ADDRESS" sudo reboot now || true
96 | fi
97 | fi
98 |
99 | until ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SSH_ADDRESS" echo
100 | do
101 | echo "host instance not ready yet"
102 | sleep 5
103 | if [ "$TEST_HOST" == "gcloud" ]; then
104 | # make sure we have the right config
105 | gcloud compute config-ssh
106 | fi
107 | done
108 |
109 | ssh "$SSH_ADDRESS" sudo apt-get update
110 | ssh "$SSH_ADDRESS" sudo apt-get install \
111 | --no-install-recommends \
112 | --no-install-suggests \
113 | -y rsync
114 |
115 | # copy the necessary files
116 | while read -r f; do
117 | # check if the file or directory exists
118 | if [ ! -e "$ROOT/$f" ]; then
119 | echo "File or directory $f does not exist!"
120 | exit 1
121 | fi
122 |
123 | rsync -avz "$ROOT/$f" "$SSH_ADDRESS":
124 | done .
17 | #
18 |
19 | KEYFILE="id_ed25519"
20 |
21 | # check if file exists
22 | if [ -f "$KEYFILE" ]; then
23 | echo "File $KEYFILE exists..."
24 | exit 0
25 | fi
26 |
27 | ssh-keygen -t ed25519 -f "$KEYFILE" -N ""
28 | mv "$KEYFILE.pub" ./rootfs/
29 |
--------------------------------------------------------------------------------
/test/integration/rootfs/.gitignore:
--------------------------------------------------------------------------------
1 | *.ext4
2 | *.img
3 |
--------------------------------------------------------------------------------
/test/integration/rootfs/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | .PHONY: all
19 |
20 | all: ssh.img
21 |
22 | ssh.img: ssh.sh ssh-base.sh id_ed25519.pub
23 | @docker run -it --platform=linux/amd64 --rm -v $(PWD)/ssh.sh:/app.sh -v $(PWD)/id_ed25519.pub:/files/id_ed25519.pub -v $(PWD)/ssh-base.sh:/base.sh -v $(PWD):/opt/code --privileged rootfsbuilder $@
24 |
25 | id_ed25519.pub:
26 | cd .. ; ./make_key.sh
27 |
--------------------------------------------------------------------------------
/test/integration/rootfs/ssh-base.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | # the base script install all the necessary dependencies during root
21 | # filesystem compilation
22 | # configure ssh
23 |
24 | apk -U --allow-untrusted --root / add openssh
25 |
26 | ln -sf sshd /etc/init.d/sshd.eth0
27 | ln -sf /etc/init.d/sshd.eth0 /etc/runlevels/default/sshd.eth0
28 |
29 | mkdir -m 0600 -p /root/.ssh/
30 | ssh-keygen -f /root/.ssh/id_rsa -N ""
31 | ssh-keygen -A
32 | cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys
33 |
34 | cat >> /etc/conf.d/sshd << EOF
35 | sshd_disable_keygen="yes"
36 | rc_need="net.eth0"
37 | EOF
38 |
39 | sed -E -i /etc/ssh/sshd_config \
40 | -e "/^[# ]*PermitRootLogin .+$/d" \
41 | -e "/^[# ]*PermitEmptyPasswords .+$/d" \
42 | -e "/^[# ]*PubkeyAuthentication .+$/d"
43 |
44 | echo "
45 | PermitRootLogin yes
46 | PermitEmptyPasswords yes
47 | PubkeyAuthentication yes
48 | " | tee -a /etc/ssh/sshd_config >/dev/null
49 |
50 | cat id_ed25519.pub >> /root/.ssh/authorized_keys
51 |
52 | # add iperf3
53 | apk -U --allow-untrusted --root / add iperf3
--------------------------------------------------------------------------------
/test/integration/rootfs/ssh.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | while true; do
21 | echo "$(date): satellite server running"
22 | sleep 60
23 | done
24 |
--------------------------------------------------------------------------------
/test/microvm/.gitignore:
--------------------------------------------------------------------------------
1 | id_ed25519
2 | id_ed25519.pub
3 | rootfs.id_rsa
4 | rootfs.ext4
5 |
--------------------------------------------------------------------------------
/test/microvm/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "tofu init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.opentofu.org/hashicorp/google" {
5 | version = "5.11.0"
6 | hashes = [
7 | "h1:SZvItcManUwdLWQIxHWVgiW0BXbide6kqQAL7XgRTV8=",
8 | "zh:1a92a4e747b7ab14fdfa471a8b58155e3f509a18d4b5c155ca2cfb925a687f65",
9 | "zh:274ce607e702a28d1b2c8307341d2e0b95c85329b8ff743d05ea504811ccdd86",
10 | "zh:5f071bccac9325b771dce2bf83d44ab93159b2d175ebc4543323383da15e6dd3",
11 | "zh:6f6693b4097edf6644301724de54889d2d0f1f79c0d7d429e2957e5a88a9b31d",
12 | "zh:6f82dc7d012d587407bf2a0537bc0591c0de00ee4a31256ea3a8c562730ea88e",
13 | "zh:7f4783582548678630ffa583d27c561f2966d7c6bc0dd6ce7b96bf815396a4c3",
14 | "zh:844111efd3e6bd23fb9651cc889fe47cdc107d2c0606bc7293ca5e8694165d88",
15 | "zh:9e91d192d1a588cf1ee7c346547cff29134d39a378147b79637c23f0aaa350e8",
16 | "zh:b64b046a78e5ed3b26735bb32e53c8437fb416d278e44cf2a836ab415d30a81e",
17 | "zh:b9271c241890c5daaf0852ca533c58a649206f676e7aa115be88dd17a3365c04",
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/test/microvm/dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | set -ex
20 |
21 | sudo apt-get update
22 |
23 | sudo apt-get install \
24 | --no-install-recommends \
25 | --no-install-suggests \
26 | -y g++ gcc make cmake build-essential
27 |
28 | # and we need firecracker on the machine
29 | # download the current release
30 | curl -fsSL -o firecracker-v1.6.0-x86_64.tgz \
31 | https://github.com/firecracker-microvm/firecracker/releases/download/v1.6.0/firecracker-v1.6.0-x86_64.tgz
32 | tar -xvf firecracker-v1.6.0-x86_64.tgz
33 | # and add the firecracker and jailer binaries
34 | sudo mv release-v1.6.0-x86_64/firecracker-v1.6.0-x86_64 /usr/local/bin/firecracker
35 | sudo mv release-v1.6.0-x86_64/seccompiler-bin-v1.6.0-x86_64 /usr/local/bin/jailer
36 |
37 |
--------------------------------------------------------------------------------
/test/microvm/fileslist.txt:
--------------------------------------------------------------------------------
1 | test/microvm/dependencies.sh
2 | test/microvm/run_microvm.sh
3 | test/microvm/id_ed25519
4 | test/microvm/rootfs/ssh.img
5 | test/microvm/vmlinux.bin
6 |
--------------------------------------------------------------------------------
/test/microvm/google.auto.tfvars:
--------------------------------------------------------------------------------
1 | gcp_project = "celestial-306310"
2 |
--------------------------------------------------------------------------------
/test/microvm/infrastructure.tf:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | provider "google" {
19 | project = var.gcp_project
20 | region = var.gcp_region
21 | }
22 |
23 | variable "gcp_project" {
24 | # default = YOUR_GCP_PROJECT_ID
25 | }
26 |
27 | variable "gcp_region" {
28 | default = "europe-west3"
29 | }
30 |
31 | variable "gcp_zone" {
32 | default = "a"
33 | }
34 |
35 | variable "host_type" {
36 | default = "n2-standard-2"
37 | }
38 |
39 | output "zone" {
40 | value = local.zone
41 | }
42 |
43 | output "host_name" {
44 | value = format("%s.%s.%s", google_compute_instance.celestial-test-host.name, local.zone, var.gcp_project)
45 | }
46 |
47 | output "host_id" {
48 | value = google_compute_instance.celestial-test-host.name
49 | }
50 |
51 | output "project" {
52 | value = var.gcp_project
53 | }
54 |
55 | # the zone variable must be within the region
56 | # hence this weird setup
57 | locals {
58 | zone = "${var.gcp_region}-${var.gcp_zone}"
59 | }
60 |
61 | # we use a version of Ubuntu 22.04 LTS
62 | # this data item gives us the latest available image
63 | data "google_compute_image" "ubuntu2204image" {
64 | family = "ubuntu-2204-lts"
65 | project = "ubuntu-os-cloud"
66 | }
67 |
68 | # we want our instances to be able to talk to each other directly
69 | # hence we add them all to a dedicated network
70 | resource "google_compute_network" "celestial-test-network" {
71 | name = "celestial-test-network"
72 | description = "This network connects Celestial hosts."
73 | auto_create_subnetworks = true
74 | }
75 |
76 | # we also need to enable ingress to our machines
77 | resource "google_compute_firewall" "celestial-test-net-firewall-external" {
78 | name = "celestial-test-net-firewall-external"
79 | description = "This firewall allows external connections to our instance for ssh."
80 | network = google_compute_network.celestial-test-network.id
81 | direction = "INGRESS"
82 | source_ranges = ["0.0.0.0/0"]
83 |
84 | allow {
85 | protocol = "tcp"
86 | ports = ["22"]
87 | }
88 | }
89 |
90 | # reserve a static external IP address
91 | resource "google_compute_address" "celestial-test-host-ip" {
92 | name = "celestial-test-host-ip"
93 | }
94 |
95 | # we need to create an image for our hosts
96 | # this needs a custom license to use nested virtualization
97 | resource "google_compute_image" "celestial-test-host-image" {
98 | name = "celestial-test-host-image"
99 | # source_disk = google_compute_disk.celestial-host-disk.self_link
100 | source_image = data.google_compute_image.ubuntu2204image.self_link
101 | licenses = ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-2204-lts", "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"]
102 | }
103 |
104 | # the host instance runs Ubuntu 22.04
105 | resource "google_compute_instance" "celestial-test-host" {
106 | name = "celestial-test-host"
107 | machine_type = var.host_type
108 | zone = local.zone
109 |
110 | boot_disk {
111 | initialize_params {
112 | image = google_compute_image.celestial-test-host-image.self_link
113 | }
114 | }
115 |
116 | # adapter for internal network
117 | network_interface {
118 | network = google_compute_network.celestial-test-network.id
119 |
120 | # use the static IP address
121 | access_config {
122 | nat_ip = google_compute_address.celestial-test-host-ip.address
123 | }
124 | }
125 |
126 | service_account {
127 | scopes = ["cloud-platform"]
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/test/microvm/make_key.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | KEYFILE="id_ed25519"
20 |
21 | # check if file exists
22 | if [ -f "$KEYFILE" ]; then
23 | echo "File $KEYFILE exists..."
24 | exit 0
25 | fi
26 |
27 | ssh-keygen -t ed25519 -f "$KEYFILE" -N ""
28 | mv "$KEYFILE.pub" ./rootfs/
29 |
--------------------------------------------------------------------------------
/test/microvm/microvm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | # the -no-reboot flag is used to prevent the instance from rebooting
20 | REBOOT=1
21 |
22 | # the other argument is the host: ip address or gcloud
23 | TEST_HOST=""
24 |
25 | for i in "$@"
26 | do
27 | case $i in
28 | -no-reboot)
29 | REBOOT=0
30 | shift # past argument=value
31 | ;;
32 | -host=*)
33 | TEST_HOST="${i#*=}"
34 | shift # past argument=value
35 | ;;
36 | *)
37 | # unknown option
38 | ;;
39 | esac
40 | done
41 |
42 | # check that the host is set
43 | if [ -z "$TEST_HOST" ]; then
44 | echo "No host set!"
45 | echo "Please set the host with -host=... or use -host=gcloud to use terraform"
46 | exit 1
47 | fi
48 |
49 | set -xe
50 |
51 | DIVIDER="=============================="
52 | ROOT="../.."
53 |
54 | pushd "$ROOT"
55 | make rootfsbuilder
56 | popd
57 |
58 | pushd rootfs
59 | make -B
60 | popd
61 |
62 | echo "$DIVIDER"
63 | echo "Running preparation..."
64 | echo "$DIVIDER"
65 |
66 | ./make_key.sh
67 |
68 | # make the infrastructure if we use gcloud
69 | if [ "$TEST_HOST" == "gcloud" ]; then
70 | tofu init
71 | tofu apply -auto-approve
72 |
73 | GCP_ZONE="$(tofu output -json | jq -r '.zone.value')"
74 | GCP_PROJECT="$(tofu output -json | jq -r '.project.value')"
75 | GCR_INSTANCE_FULL="$(tofu output -json | jq -r '.host_name.value')"
76 | GCP_INSTANCE="$(tofu output -json | jq -r '.host_id.value')"
77 |
78 | gcloud config set project "$GCP_PROJECT"
79 | SSH_ADDRESS="$GCR_INSTANCE_FULL"
80 | else
81 | SSH_ADDRESS="$TEST_HOST"
82 | fi
83 |
84 | if [ "$REBOOT" -eq 1 ]; then
85 | if [ "$TEST_HOST" == "gcloud" ]; then
86 | # restart the machines
87 | gcloud compute instances stop --zone="$GCP_ZONE" "$GCP_INSTANCE"
88 | sleep 1
89 | gcloud compute instances start --zone="$GCP_ZONE" "$GCP_INSTANCE"
90 |
91 | gcloud compute config-ssh
92 | else
93 | # at least reboot the machine
94 | ssh "$SSH_ADDRESS" sudo reboot now || true
95 | fi
96 | fi
97 |
98 | until ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SSH_ADDRESS" echo
99 | do
100 | echo "host instance not ready yet"
101 | sleep 5
102 | if [ "$TEST_HOST" == "gcloud" ]; then
103 | # make sure we have the right config
104 | gcloud compute config-ssh
105 | fi
106 | done
107 |
108 | ssh "$SSH_ADDRESS" sudo apt-get update
109 | ssh "$SSH_ADDRESS" sudo apt-get install \
110 | --no-install-recommends \
111 | --no-install-suggests \
112 | -y rsync
113 |
114 | # copy the necessary files
115 | while read -r f; do
116 | # check if the file or directory exists
117 | if [ ! -e "$ROOT/$f" ]; then
118 | echo "File or directory $f does not exist!"
119 | exit 1
120 | fi
121 |
122 | rsync -avz "$ROOT/$f" "$SSH_ADDRESS":
123 | done .
16 | #
17 |
18 | .PHONY: all
19 |
20 | all: ssh.img
21 |
22 | ssh.img: ssh.sh ssh-base.sh id_ed25519.pub
23 | @docker run -it --platform=linux/amd64 --rm -v $(PWD)/ssh.sh:/app.sh -v $(PWD)/id_ed25519.pub:/files/id_ed25519.pub -v $(PWD)/ssh-base.sh:/base.sh -v $(PWD):/opt/code --privileged rootfsbuilder $@
24 |
25 | id_ed25519.pub:
26 | cd .. ; ./make_key.sh
27 |
--------------------------------------------------------------------------------
/test/microvm/rootfs/ssh-base.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | # the base script install all the necessary dependencies during root
21 | # filesystem compilation
22 | # configure ssh
23 |
24 | apk -U --allow-untrusted --root / add openssh
25 |
26 | ln -sf sshd /etc/init.d/sshd.eth0
27 | ln -sf /etc/init.d/sshd.eth0 /etc/runlevels/default/sshd.eth0
28 |
29 | mkdir -m 0600 -p /root/.ssh/
30 | ssh-keygen -f /root/.ssh/id_rsa -N ""
31 | ssh-keygen -A
32 | cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys
33 |
34 | cat >> /etc/conf.d/sshd << EOF
35 | sshd_disable_keygen="yes"
36 | rc_need="net.eth0"
37 | EOF
38 |
39 | sed -E -i /etc/ssh/sshd_config \
40 | -e "/^[# ]*PermitRootLogin .+$/d" \
41 | -e "/^[# ]*PermitEmptyPasswords .+$/d" \
42 | -e "/^[# ]*PubkeyAuthentication .+$/d"
43 |
44 | echo "
45 | PermitRootLogin yes
46 | PermitEmptyPasswords yes
47 | PubkeyAuthentication yes
48 | " | tee -a /etc/ssh/sshd_config >/dev/null
49 |
50 | cat id_ed25519.pub >> /root/.ssh/authorized_keys
51 |
--------------------------------------------------------------------------------
/test/microvm/rootfs/ssh.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | while true; do
21 | echo "$(date): satellite server running"
22 | sleep 10
23 | done
24 |
--------------------------------------------------------------------------------
/test/system/.gitignore:
--------------------------------------------------------------------------------
1 | out/
2 | output/results.csv
3 | host.log
4 | coordinator.log
--------------------------------------------------------------------------------
/test/system/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "tofu init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.opentofu.org/hashicorp/google" {
5 | version = "5.11.0"
6 | hashes = [
7 | "h1:SZvItcManUwdLWQIxHWVgiW0BXbide6kqQAL7XgRTV8=",
8 | "zh:1a92a4e747b7ab14fdfa471a8b58155e3f509a18d4b5c155ca2cfb925a687f65",
9 | "zh:274ce607e702a28d1b2c8307341d2e0b95c85329b8ff743d05ea504811ccdd86",
10 | "zh:5f071bccac9325b771dce2bf83d44ab93159b2d175ebc4543323383da15e6dd3",
11 | "zh:6f6693b4097edf6644301724de54889d2d0f1f79c0d7d429e2957e5a88a9b31d",
12 | "zh:6f82dc7d012d587407bf2a0537bc0591c0de00ee4a31256ea3a8c562730ea88e",
13 | "zh:7f4783582548678630ffa583d27c561f2966d7c6bc0dd6ce7b96bf815396a4c3",
14 | "zh:844111efd3e6bd23fb9651cc889fe47cdc107d2c0606bc7293ca5e8694165d88",
15 | "zh:9e91d192d1a588cf1ee7c346547cff29134d39a378147b79637c23f0aaa350e8",
16 | "zh:b64b046a78e5ed3b26735bb32e53c8437fb416d278e44cf2a836ab415d30a81e",
17 | "zh:b9271c241890c5daaf0852ca533c58a649206f676e7aa115be88dd17a3365c04",
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/test/system/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 |
18 | .PHONY: all
19 |
20 | all: app/validator.img satgen.zip
21 |
22 | app/validator.img: app/validator.sh app/validator-base.sh app/validator.py
23 | @docker run --platform=linux/amd64 --rm -v $(PWD)/app/validator.py:/files/validator.py -v $(PWD)/app/validator.sh:/app.sh -v $(PWD)/app/validator-base.sh:/base.sh -v $(PWD):/opt/code --privileged rootfsbuilder $@
24 |
25 | satgen.zip: config.toml
26 | cd ../.. && source .venv/bin/activate && python3 satgen.py test/system/$< test/system/$@ && deactivate
27 |
--------------------------------------------------------------------------------
/test/system/app/.gitignore:
--------------------------------------------------------------------------------
1 | *.ext4
2 | *.img
3 |
--------------------------------------------------------------------------------
/test/system/app/validator-base.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | # add git, curl, and python3 to the root filesystem.
21 | # our program is based on python3, hence we need to install python3.
22 | # git and curl are needed for pip.
23 | # note that the root filesystem here is based on alpine, hence uses the "apk"
24 | # package manager.
25 | apk add git curl python3 py3-pip
26 |
27 | # add the python3 dependencies: request and ping3
28 | python3 -m pip install ping3 requests
29 |
--------------------------------------------------------------------------------
/test/system/app/validator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
5 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, version 3.
10 | #
11 | # This program is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 | # check what chrony is doing
21 | # now it should report the correct timesource
22 | chronyc tracking
23 |
24 | # ready to start the application!
25 | # everything that is sent to stdout will be sent to our file
26 | echo "STARTING VALIDATOR"
27 |
28 | # the validation script should know where it can find the HTTP server
29 | # (at our gateway)
30 | python3 validator.py info.celestial
31 |
32 | while true; do
33 | echo "$(date): satellite server running"
34 | sleep 60
35 | done
36 |
--------------------------------------------------------------------------------
/test/system/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | set -xe
20 |
21 | ROOT="../.."
22 |
23 | pushd "$ROOT" || exit
24 |
25 | make build rootfsbuilder -B
26 |
27 | popd || exit
28 |
29 | make
30 |
--------------------------------------------------------------------------------
/test/system/cleanresults.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | import os
20 | import sys
21 |
22 | if __name__ == "__main__":
23 | # expect two input arguments
24 | # 1. raw results directory
25 | # 2. clean results file
26 |
27 | if not len(sys.argv) == 3:
28 | exit("Usage: python3 cleanresults.py [raw results] [clean results]")
29 |
30 | raw = sys.argv[1]
31 | clean = sys.argv[2]
32 |
33 | read_lines = 0
34 | written_lines = 0
35 |
36 | with open(clean, "w") as out_file:
37 | out_file.write(
38 | "a_shell,a_sat,t,b_shell,b_sat,expected_before,expected_after,actual\n"
39 | )
40 |
41 | # read all files in out directory
42 | for filename in os.listdir(raw):
43 | # split by underscore
44 | parts = filename.split("-")
45 |
46 | # check if gst or sat
47 |
48 | if len(parts) != 2:
49 | raise Exception("invalid filename")
50 |
51 | # first part is a_shell
52 | a_shell = parts[0]
53 |
54 | a_sat = parts[1].split(".")[0]
55 |
56 | with open(os.path.join(raw, filename), "r") as in_file:
57 | # read all lines
58 | # decide for each line if it is a data line
59 | while True:
60 | line = in_file.readline()
61 |
62 | if not line:
63 | break
64 |
65 | read_lines += 1
66 |
67 | if "," not in line:
68 | continue
69 |
70 | line = line.strip()
71 |
72 | # split line by comma
73 | parts = line.split(",")
74 |
75 | # second and third parts should be a number
76 | try:
77 | int(parts[1])
78 | int(parts[2])
79 | except Exception:
80 | if parts[1] != "gst":
81 | continue
82 |
83 | # write the line!
84 | out_file.write(f"{a_shell},{a_sat},{line}\n")
85 | written_lines += 1
86 |
87 | print(f"read {read_lines} lines, wrote {written_lines} lines")
88 |
--------------------------------------------------------------------------------
/test/system/config.toml:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
3 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, version 3.
8 | #
9 | # This program is distributed in the hope that it will be useful, but
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | #
17 | bbox = [0.0, -60.0, 90.0, 60.0]
18 | resolution = 10
19 | duration = 900
20 |
21 | [network_params]
22 | bandwidth_kbits = 10_000_000
23 | min_elevation = 25
24 | ground_station_connection_type = "all"
25 |
26 | [compute_params]
27 | vcpu_count = 1
28 | mem_size_mib = 512
29 | disk_size_mib = 10
30 | kernel = "vmlinux.bin"
31 | rootfs = "validator.img"
32 |
33 | [[shell]]
34 | planes = 72
35 | sats = 22
36 | altitude_km = 900
37 | inclination = 53.0
38 | arc_of_ascending_nodes = 360.0
39 | eccentricity = 0.0
40 |
41 | [[shell]]
42 | planes = 6
43 | sats = 10
44 | altitude_km = 1000
45 | inclination = 90.0
46 | arc_of_ascending_nodes = 180.0
47 | eccentricity = 0.0
48 |
49 | [[ground_station]]
50 | name = "Berlin"
51 | lat = 52.514182
52 | long = 13.328285
53 |
54 | [ground_station.compute_params]
55 | vcpu_count = 2
56 | mem_size_mib = 2048
57 | disk_size_mib = 100
58 | rootfs = "validator.img"
59 |
60 | [[ground_station]]
61 | name = "NewYork"
62 | lat = 40.76140
63 | long = -73.97165
64 |
65 | [ground_station.compute_params]
66 | vcpu_count = 2
67 | mem_size_mib = 2048
68 | disk_size_mib = 100
69 | rootfs = "validator.img"
70 |
--------------------------------------------------------------------------------
/test/system/dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | set -ex
20 |
21 | sudo apt-get update
22 |
23 | # for celestial coordinator: python + python-pip + python dependencies
24 | sudo apt-get install \
25 | --no-install-recommends \
26 | --no-install-suggests \
27 | -y python3 python3-pip python3-dev g++ gcc make cmake build-essential
28 |
29 | python3 -m pip install pip -U
30 | python3 -m pip install -r requirements.txt -U
31 |
32 | # for host
33 | # we need the /celestial folder available on the hosts
34 | sudo mkdir -p /celestial
35 |
36 | # we also need wireguard and ipset as dependencies
37 | sudo apt-get install \
38 | --no-install-recommends \
39 | --no-install-suggests \
40 | -y wireguard ipset
41 |
42 | # and we need firecracker on the machine
43 | # download the current release
44 | curl -fsSL -o firecracker-v1.6.0-x86_64.tgz \
45 | https://github.com/firecracker-microvm/firecracker/releases/download/v1.6.0/firecracker-v1.6.0-x86_64.tgz
46 | tar -xvf firecracker-v1.6.0-x86_64.tgz
47 | # and add the firecracker and jailer binaries
48 | sudo mv release-v1.6.0-x86_64/firecracker-v1.6.0-x86_64 /usr/local/bin/firecracker
49 | sudo mv release-v1.6.0-x86_64/seccompiler-bin-v1.6.0-x86_64 /usr/local/bin/jailer
50 |
51 | sudo mv vmlinux-5.12.bin /celestial/vmlinux.bin
52 |
53 | # sometimes it can also be helpful to increase process and file handler
54 | # limits on your host machines:
55 | cat << END > ./limits.conf
56 | * soft nofile 64000
57 | * hard nofile 64000
58 | root soft nofile 64000
59 | root hard nofile 64000
60 | * soft nproc 64000
61 | * hard nproc 64000
62 | root soft nproc 64000
63 | root hard nproc 64000
64 | END
65 |
66 | sudo mv ./limits.conf /etc/security/limits.conf
67 |
--------------------------------------------------------------------------------
/test/system/fileslist.txt:
--------------------------------------------------------------------------------
1 | test/system/dependencies.sh
2 | test/system/satgen.zip
3 | test/system/app/validator.img
4 | test/system/config.toml
5 | kernel/vmlinux-5.12.bin
6 | requirements.txt
7 | celestial
8 | proto
9 | celestial.py
10 | __init__.py
11 | celestial.bin
12 |
--------------------------------------------------------------------------------
/test/system/getresults.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # This file is part of Celestial (https://github.com/OpenFogStack/celestial).
4 | # Copyright (c) 2024 Tobias Pfandzelter, The OpenFogStack Team.
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, version 3.
9 | #
10 | # This program is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 |
19 | set -xe
20 |
21 | if [ $# -ne 1 ]; then
22 | echo "Usage: $0 "
23 | exit 1
24 | fi
25 |
26 | NUM_HOSTS="$1"
27 |
28 | RESULTS_DIR="out"
29 | RESULTS_CLEAN="results.csv"
30 |
31 | TEST_HOST_NAMES=()
32 | for ((i=0;i.
17 | #
18 |
19 | set -xe
20 |
21 | # check that one argument is set
22 | if [ $# -ne 1 ]; then
23 | echo "Usage: $0 "
24 | exit 1
25 | fi
26 |
27 | # check that the argument is a number
28 | if ! [ "$1" -eq "$1" ] 2>/dev/null; then
29 | echo "Argument must be a number"
30 | exit 1
31 | fi
32 |
33 | # check that the argument is greater than 0
34 | if [ "$1" -lt 1 ]; then
35 | echo "Argument must be greater than 0"
36 | exit 1
37 | fi
38 |
39 | HOSTS="$1"
40 |
41 | ROOT="../.."
42 |
43 | # create cloud infrastructure
44 | tofu init
45 |
46 | tofu apply -auto-approve --var "hosts=$HOSTS"
47 |
48 | GCP_ZONE="$(tofu output -json | jq -r '.zone.value')"
49 | GCP_PROJECT="$(tofu output -json | jq -r '.project.value')"
50 |
51 | TEST_HOST_IDS=()
52 | for ((i=0;i "${HOST_LOGS[$i]}"
40 | done
41 | echo -n "" > "$COORD_LOG"
42 |
43 | echo "Running tests..."
44 |
45 | echo "$DIVIDER"
46 | echo "Running build.sh..."
47 | echo "$DIVIDER"
48 | ./build.sh
49 |
50 | echo "$DIVIDER"
51 | echo "Running prepare.sh..."
52 | echo "$DIVIDER"
53 | ./prepare.sh "$NUM_HOSTS"
54 |
55 | gcloud compute config-ssh
56 | INSTANCE_NAMES=()
57 | for ((i=0;i> ${HOST_LOGS[$i]} 2>&1 &
88 | done
89 |
90 | echo -n "Waiting for celestial to start."
91 | for _ in {1..10} ; do
92 | echo -n "."
93 | sleep 1
94 | done
95 |
96 | echo "$DIVIDER"
97 | echo "Running celestial coordinator on host 0..."
98 | echo "$DIVIDER"
99 | command="PYTHONUNBUFFERED=1 python3 celestial.py satgen.zip "
100 | for ((i=0;i> $COORD_LOG 2>&1 &
104 |
105 | # run for 10 minutes
106 | echo "Running for 10 minutes... (Start time: $(date))"
107 | sleep 600
108 |
109 | echo "$DIVIDER"
110 | echo "Killing celestial coordinator..."
111 | echo "$DIVIDER"
112 | # necessary to get SIGTERM to work
113 | ssh "${INSTANCE_NAMES[0]}" "sudo killall python3"
114 |
115 | # get the results
116 | echo "$DIVIDER"
117 | echo "Getting results..."
118 | echo "$DIVIDER"
119 | ./getresults.sh "$NUM_HOSTS"
120 |
121 | echo "$DIVIDER"
122 | echo "Analyzing results..."
123 | echo "$DIVIDER"
124 | mkdir -p output
125 | python3 analyze.py
126 |
127 | echo "$DIVIDER"
128 | echo "Done!"
129 | echo "$DIVIDER"
130 |
131 | # destroy the infrastructure
132 | echo "Destroying infrastructure..."
133 | echo "Run the following command to destroy the infrastructure:"
134 | echo "tofu destroy -auto-approve --var 'hosts=$NUM_HOSTS'"
135 | # tofu destroy -auto-approve
136 |
--------------------------------------------------------------------------------