Skip to content

Commit

Permalink
Merge pull request #9 from unimib-datAI/stecattaneo-dev
Browse files Browse the repository at this point in the history
Merge Stefano Cattaneo's work into main
  • Loading branch information
ema-pe authored Nov 27, 2024
2 parents 4713ee0 + 0c704cf commit 346ead8
Show file tree
Hide file tree
Showing 212 changed files with 118,615 additions and 1,249 deletions.
18 changes: 14 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,25 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/
# VIM temporary files.
*.swp

*.icloud
*.bin
# Ignore dfaasagent binary.
dfaasagent/dfaasagent

# Ignore temporary files.
dfaasagent/haproxy.cfg
dfaasagent/prvkey.dat

# Custom ignores
__pycache__
venv
.idea
.DS_Store
vegeta-results
emulator/containernet
emulator/openflow
framework/outputs/**
!framework/outputs/**/.gitkeep
simulation/outputs/**
!simulation/outputs/**/.gitkeep
84 changes: 49 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The edge node can receive functions' execution _requests_, in the form of HTTP r

## Prototype
This prototype relies on [HAProxy](https://www.haproxy.org/) to implement the proxy component,
and on [faasd 0.16.0](https://github.com/openfaas/faasd) (a lightweight version of OpenFaaS) to implement the FaaS platform.
and on [faasd 0.18.6](https://github.com/openfaas/faasd) (a lightweight version of OpenFaaS) to implement the FaaS platform.

Also, we exploit [Sysbox](https://github.com/nestybox/sysbox), an open-source and free container runtime
(a specialized "runc") that enhances containers in two key ways:
Expand All @@ -43,31 +43,55 @@ This way, we can run several emulated edge nodes by simply executing multiple Do

### Requirements

- Ubuntu 20.04 LTS
- containerd 1.6.4
- Docker CE 20.10.16
- Sysbox CE 0.5.2
- Ubuntu 22.04 LTS
- containerd 1.6.27
- Docker CE 25.0.1
- Sysbox CE 0.6.3

#### Setup environment using the convenience script
#### Setup environment and deploy using the Ansible playbook

The script has 3 arguments:
Install [Ansible](https://www.ansible.com/), an agentless automation tool that you install on a single host, referred to as the control node.
Then, using the [setup_playbook.yaml](setup_playbook.yaml) file, your Ansible control node can setup the environment to execute DFaaS on the managed node(s) specified in an inventory file.

Here is an example of an inventory.yaml file to setup the environment on a host via SSH connection:

```yaml
ungrouped:
hosts:
<hostname>:
ansible_port: <port_number>
ansible_connection: ssh
ansible_user: <user>
ansible_password: <password>
```
Run the `ansible-playbook` command on the control node to execute the tasks specified in the playbook with the following options:

- 1st arg: Sysbox CE version
- 2nd arg: shiftfs branch
`-i` : path to an inventory file
`--extra-vars` : to specify the Sysbox version and shiftfs branch to be installed
`--tags` : to specify steps of the playbook to be executed

> This scripts assumes you are using Ubuntu 20.04 LTS with kernel version 5.4.
> The following command assumes you are using Ubuntu 22.04 LTS with kernel version 5.15 or 5.16.

```shell
./setup-environment 0.5.2 k5.4
ansible-playbook -i inventory.yaml setup_playbook.yaml --extra-vars "sysbox_ver=0.6.3 shiftfs_ver=k5.16" --tags "installation, deploy"
```

This Ansible playbook installs the required software and executes the [docker-compose.yml](docker-compose.yml), deploying three DFaaS nodes containers, and a fourth container called [operator](operator), which deploys functions on DFaaS nodes and starts specified load tests.

If you have four different VMs it's recommended to deploy the entire system exploiting the playbook and configuration files in [test_environment](test_environment).

#### Manual

_Docker CE v20.10.16_
_Ansible_

You can follow the [official user guide](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html).

_Docker CE v25.0.1_

You can follow the [official user guide](https://docs.docker.com/engine/install/).

_Sysbox CE 0.5.2_
_Sysbox CE 0.6.3_

You can follow the [official user guide](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/install-package.md).

Expand All @@ -76,20 +100,6 @@ You can follow the [official user guide](https://github.com/nestybox/sysbox/blob
> We instead recommend installing [shiftfs](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/install-package.md#installing-shiftfs)
> according to your kernel version as suggested by the Sysbox CE user guide.

### Build Docker images

```shell
# Paths assume you are executing from the project root directory
docker build -t dfaas-agent-builder:latest -f docker/dfaas-agent-builder.dockerfile dfaasagent
docker build -t dfaas-node:latest -f docker/dfaas-node.dockerfile docker
```

### Run a 3 nodes network via Docker Compose
See the provided [docker-compose.yml](docker-compose.yml) file for technical details.
```shell
docker compose up -d
```

### Deploy functions
This script deploy the same set of functions on each of the nodes by using [docker/files/deploy_functions.sh](docker/files/deploy_functions.sh).
The [deploy_functions.sh](docker/files/deploy_functions.sh) script waits for the OpenFaaS gateway to be up (max 20 retries, 10s delay),
Expand All @@ -106,6 +116,8 @@ the default name you get when using the provided docker-compose.yml file.
./utils/deploy-functions-to-nodes.sh 3 "dfaas-node-" "-1"
```

Alternatively you can exploit the deployment functionalities of the [operator](operator).

### Invoke a function
Each node exposes port `808x:80` (e.g., `node-1` exposed port is `8081:80`), where port `80` is the HAProxy port.
This example assumes you run DFaaS nodes via Docker Compose with the provided [docker-compose.yml](docker-compose.yml) file.
Expand Down Expand Up @@ -144,22 +156,24 @@ jq -ncM '{method: "GET", url: "http://localhost:8081/function/figlet", body: "He
vegeta report -every=200ms
```

You can also start multiple parallel Vegeta attacks exploiting [operator](operator) functionalities.

### Create plots from vegeta results
You can produce some plots from vegeta results by exploiting the `vegeta plot` command or
our [utils/plot.py](utils/plot.py) script.
To use our script, you need to install the required Python packages listed in [utils/plot-requirements.txt](utils/plot-requirements.txt).
You can produce some plots from vegeta results by exploiting the `vegeta plot` command or our [plot-results.py](operator/docker/files/plot-results.py) script, which is automatically executed after tests execution with the [operator](operator).
To use our script, you need to install the required Python packages listed in [plot-requirements.txt](operator/docker/files/plot-requirements.txt).

```shell
# Encode results as JSON
cat $VEGFOLDER/results.bin | vegeta encode > $VEGFOLDER/results.json
# Create plot with vegeta
cat cat $VEGFOLDER/results.bin | vegeta plot > $VEGFOLDER/plot.html
cat $VEGFOLDER/results.bin | vegeta plot > $VEGFOLDER/plot.html
# 1st arg: path int results.json
# 2nd arg: path output plot
# 3rd arg: rate req/s used for the attack
./utils/plot.py $VEGFOLDER/results.json $VEGFOLDER/plot.png 50
# 1st arg: path results.json
# 2nd arg: path output folder
# 3rd arg: rate req/s used for the attack (if merged is True specify rate=0)
# 4th arg: boolean merged (is the input file merged from multiple attacks?)
./operator/docker/files/plot-results.py $VEGFOLDER/results.json $VEGFOLDER/plots 50 False
```

### Forwarding traffic as a malicious node
Expand Down
21 changes: 19 additions & 2 deletions dfaasagent.env
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ AGENT_PUBSUB_TOPIC="/dfaasagent/1.0.0"

AGENT_RECALC_PERIOD=1m

AGENT_HAPROXY_TEMPLATE_FILE="/agent/haproxycfg.tmpl"
AGENT_HAPROXY_TEMPLATE_FILE_NMS="/agent/haproxycfgnms.tmpl"
AGENT_HAPROXY_TEMPLATE_FILE_RECALC="/agent/haproxycfgrecalc.tmpl"
AGENT_HAPROXY_CONFIG_FILE="/etc/haproxy/haproxy.cfg"
AGENT_HAPROXY_CONFIG_UPDATE_COMMAND="/usr/bin/systemctl restart haproxy.service"
AGENT_HAPROXY_CONFIG_UPDATE_COMMAND="/usr/bin/systemctl reload haproxy.service"
AGENT_HAPROXY_HOST=127.0.0.1
AGENT_HAPROXY_PORT=80
AGENT_HAPROXY_SOCK_PATH="unix:///run/haproxy/admin.sock"
Expand All @@ -31,3 +32,19 @@ AGENT_OPENFAAS_PASS=admin

AGENT_PROMETHEUS_HOST=127.0.0.1
AGENT_PROMETHEUS_PORT=9090

AGENT_HTTPSERVER_HOST=127.0.0.1
AGENT_HTTPSERVER_PORT=8008

AGENT_FORECASTER_HOST=127.0.0.1
AGENT_FORECASTER_PORT=8000

AGENT_STRATEGY="nodemarginstrategy"

AGENT_GROUP_LIST_FILE_NAME="/agent/group_list.json"

AGENT_NODE_TYPE=1 # heavy=0 mid=1 light=2

AGENT_NMS_CPU_THRESHOLD=120.0 # max cpu usage percentage
AGENT_NMS_RAM_THRESHOLD=5500000000.0 # max ram usage in bytes
AGENT_NMS_POWER_THRESHOLD=2100000.0 # max power usage in microwatts
5 changes: 0 additions & 5 deletions dfaasagent/.gitignore

This file was deleted.

44 changes: 35 additions & 9 deletions dfaasagent/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import (
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/discovery/kademlia"
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/discovery/mdns"
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/logging"
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/logic"
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/loadbalancer"
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/utils/maddrhelp"
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/httpserver"
"gitlab.com/team-dfaas/dfaas/node-stack/dfaasagent/agent/nodestbl"
)

//////////////////// PRIVATE VARIABLES ////////////////////
Expand Down Expand Up @@ -124,23 +126,43 @@ func runAgent(config config.Configuration) error {
logger.Info(" ", i+1, ". ", addr)
}

////////// LOAD BALANCER INITIALIZATION //////////

loadbalancer.Initialize(_p2pHost, config)

// Get the Strategy instance (which is a singleton) of type
// dependent on the strategy specified in the configuration
var strategy loadbalancer.Strategy
strategy, err = loadbalancer.GetStrategyInstance()
if err != nil {
return errors.Wrap(err, "Error while getting strategy instance")
}

////////// PUBSUB INITIALIZATION //////////

// The PubSub initialization must be done before the Kademlia one. Otherwise
// the agent won't be able to publish or subscribe.
err = communication.Initialize(ctx, _p2pHost, config.PubSubTopic, logic.OnReceived)
err = communication.Initialize(ctx, _p2pHost, config.PubSubTopic, strategy.OnReceived)
if err != nil {
return err
}
logger.Debug("PubSub initialization completed")

////////// KADEMLIA DHT INITIALIZATION //////////

bootstrapConfig := kademlia.BootstrapConfiguration{
BootstrapNodes: config.BootstrapNodes,
PublicBootstrapNodes: config.PublicBootstrapNodes,
BootstrapNodesList: config.BootstrapNodesList,
BootstrapNodesFile: config.BootstrapNodesFile,
BootstrapForce: config.BootstrapForce,
}

// Kademlia and DHT initialization, with connection to bootstrap nodes
err = kademlia.Initialize(
ctx,
_p2pHost,
config.BoostrapConfig,
bootstrapConfig,
config.Rendezvous,
config.KadIdleTime,
)
Expand All @@ -162,12 +184,14 @@ func runAgent(config config.Configuration) error {
logger.Debug("mDNS discovery service is enabled and initialized")
}

////////// LOGIC INITIALIZATION //////////
////////// NODESTBL INITIALIZATION //////////

err = logic.Initialize(_p2pHost, config)
if err != nil {
return err
}
nodestbl.Initialize(config)

////////// HTTPSERVER INITIALIZATION //////////

httpserver.Initialize(config)


////////// GOROUTINES //////////

Expand All @@ -184,7 +208,9 @@ func runAgent(config config.Configuration) error {

go func() { chanErr <- communication.RunReceiver() }()

go func() { chanErr <- logic.RunRecalc() }()
go func() { chanErr <- strategy.RunStrategy() }()

go func() { chanErr <- httpserver.RunHttpServer() }()

select {
case sig := <-chanStop:
Expand Down
44 changes: 29 additions & 15 deletions dfaasagent/agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ import (
"time"
)

type BootstrapConfiguration struct {
BootstrapNodes bool `mapstructure:"AGENT_BOOTSTRAP_NODES"`
PublicBoostrapNodes bool `mapstructure:"AGENT_PUBLIC_BOOTSTRAP_NODES"`
BootstrapNodesList []string `mapstructure:"AGENT_BOOTSTRAP_NODES_LIST"`
BootstrapNodesFile string `mapstructure:"AGENT_BOOTSTRAP_NODES_FILE"`
BootstrapForce bool `mapstructure:"AGENT_BOOTSTRAP_FORCE"`
}

// Configuration holds the post-processed configuration values
type Configuration struct {
DebugMode bool `mapstructure:"AGENT_DEBUG"`
Expand All @@ -22,20 +14,26 @@ type Configuration struct {
Listen []string `mapstructure:"AGENT_LISTEN"`
PrivateKeyFile string `mapstructure:"AGENT_PRIVATE_KEY_FILE"`

BoostrapConfig BootstrapConfiguration
BootstrapNodes bool `mapstructure:"AGENT_BOOTSTRAP_NODES"`
PublicBootstrapNodes bool `mapstructure:"AGENT_PUBLIC_BOOTSTRAP_NODES"`
BootstrapNodesList []string `mapstructure:"AGENT_BOOTSTRAP_NODES_LIST"`
BootstrapNodesFile string `mapstructure:"AGENT_BOOTSTRAP_NODES_FILE"`
BootstrapForce bool `mapstructure:"AGENT_BOOTSTRAP_FORCE"`

Rendezvous string `mapstructure:"AGENT_RENDEZVOUS"`
MDNSInterval time.Duration `mapstructure:"AGENT_MDNS_INTERVAL"`
KadIdleTime time.Duration `mapstructure:"AGENT_KAD_IDLE_TIME"`
PubSubTopic string `mapstructure:"AGENT_PUBSUB_TOPIC"`

RecalcPeriod time.Duration `mapstructure:"AGENT_RECALC_PERIOD"`

HAPRoxyTemplateFile string `mapstructure:"AGENT_HAPROXY_TEMPLATE_FILE"`
HAProxyConfigFile string `mapstructure:"AGENT_HAPROXY_CONFIG_FILE"`
HAProxyConfigUpdateCommand string `mapstructure:"AGENT_HAPROXY_CONFIG_UPDATE_COMMAND"`
HAProxyHost string `mapstructure:"AGENT_HAPROXY_HOST"`
HAProxyPort uint `mapstructure:"AGENT_HAPROXY_PORT"`
HAProxySockPath string `mapstructure:"AGENT_HAPROXY_SOCK_PATH"`
HAProxyTemplateFileNMS string `mapstructure:"AGENT_HAPROXY_TEMPLATE_FILE_NMS"`
HAProxyTemplateFileRecalc string `mapstructure:"AGENT_HAPROXY_TEMPLATE_FILE_RECALC"`
HAProxyConfigFile string `mapstructure:"AGENT_HAPROXY_CONFIG_FILE"`
HAProxyConfigUpdateCommand string `mapstructure:"AGENT_HAPROXY_CONFIG_UPDATE_COMMAND"`
HAProxyHost string `mapstructure:"AGENT_HAPROXY_HOST"`
HAProxyPort uint `mapstructure:"AGENT_HAPROXY_PORT"`
HAProxySockPath string `mapstructure:"AGENT_HAPROXY_SOCK_PATH"`

OpenFaaSHost string `mapstructure:"AGENT_OPENFAAS_HOST"`
OpenFaaSPort uint `mapstructure:"AGENT_OPENFAAS_PORT"`
Expand All @@ -44,6 +42,22 @@ type Configuration struct {

PrometheusHost string `mapstructure:"AGENT_PROMETHEUS_HOST"`
PrometheusPort uint `mapstructure:"AGENT_PROMETHEUS_PORT"`

HttpServerHost string `mapstructure:"AGENT_HTTPSERVER_HOST"`
HttpServerPort uint `mapstructure:"AGENT_HTTPSERVER_PORT"`

ForecasterHost string `mapstructure:"AGENT_FORECASTER_HOST"`
ForecasterPort uint `mapstructure:"AGENT_FORECASTER_PORT"`

Strategy string `mapstructure:"AGENT_STRATEGY"`

GroupListFileName string `mapstructure:"AGENT_GROUP_LIST_FILE_NAME"`

NodeType int `mapstructure:"AGENT_NODE_TYPE"`

CPUThresholdNMS float64 `mapstructure:"AGENT_NMS_CPU_THRESHOLD"`
RAMThresholdNMS float64 `mapstructure:"AGENT_NMS_RAM_THRESHOLD"`
PowerThresholdNMS float64 `mapstructure:"AGENT_NMS_POWER_THRESHOLD"`
}

func LoadConfig(path string) (config Configuration, err error) {
Expand Down
4 changes: 4 additions & 0 deletions dfaasagent/agent/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ const (
// HAProxyMaxWeight is the maximum possible weight value that should be used
// in the HAProxy configuration file
HAProxyMaxWeight = 100

// Names of the different strategies supported by the DFaaS agent
RecalcStrategy = "recalcstrategy"
NodeMarginStrategy = "nodemarginstrategy"
)
Loading

0 comments on commit 346ead8

Please sign in to comment.