diff --git a/.gitmodules b/.gitmodules index f5954d6..ee71308 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "benchmarks/warp"] path = benchmarks/warp url = https://github.com/minio/warp +[submodule "analysis/quentin"] + path = analysis/quentin + url = https://git.deuxfleurs.fr/quentin/benchmarks diff --git a/README.md b/README.md index 92abc61..4ab842a 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,49 @@ # mknet -## Installation +mknet is a tool to simulate various network topologies +locally thanks to network namespaces and traffic control (tc). + +## Prepare your environment + +Get the repository and its submodules: ```bash -sudo pip3 install git+https://git.deuxfleurs.fr/trinity-1686a/mknet +git clone https://git.deuxfleurs.fr/Deuxfleurs/mknet.git +cd mknet +git submodule update --init ``` -## Usage +Compile benchmark tools: ```bash -sudo rm -rf /tmp/garage-testnet/ # always start by deleting previous run -sudo mknet create ./config.yml -sudo mknet run-all example/deploy_garage.sh -sudo mknet run dc1:dc1s1 garage -c /tmp/garage-testnet/dc1/dc1s1/garage.toml status -sudo mknet destroy +( cd benchmarks/warp && go build ) +( cd benchmarks/s3concurrent && go build ) +( cd benchmarks/s3lat && go build ) ``` -## Instrumented daemons - -If you want to use the scripts provided in the `example` folder, -you must add to your path some tools. - -### Garage (`deploy_garage.sh`) +Switch to root as it is required by our tool, +and setup your python environment. ```bash -# see versions on https://garagehq.deuxfleurs.fr/_releases.html -export GRG_ARCH=x86_64-unknown-linux-musl -export GRG_VERSION=v0.5.0 - -sudo wget https://garagehq.deuxfleurs.fr/_releases/${GRG_VERSION}/${GRG_ARCH}/garage -O /usr/local/bin/garage -sudo chmod +x /usr/local/bin/garage - -garage help +sudo -i +pip3 install --user . +( cd scenarios && pip3 install -r requirements.txt ) ``` -### Minio (`deploy_minio.py`) +## Run a test -``` -sudo wget https://dl.min.io/server/minio/release/linux-amd64/minio -O /usr/local/bin/minio -sudo chmod +x /usr/local/bin/minio +(Not yet implemented) + +```bash +./mknet scenario ./benchmarks/garage-s3lat ./topo/single-dc.yml ``` +## Manual usage + +```bash +./mknet create ./topo/with-vdsl.yml +./mknet run-all ./scenarios/garage-manual +./mknet run dc1:dc1s1 /tmp/mknet-bin/garage* -c /tmp/mknet-store/garage/dc1/dc1s1/garage.toml status +./mknet run-all ./scenarios/clean +./mknet destroy + diff --git a/analysis/quentin b/analysis/quentin new file mode 160000 index 0000000..902555b --- /dev/null +++ b/analysis/quentin @@ -0,0 +1 @@ +Subproject commit 902555b9d5db594fdad927f51c2d8984d6e9f6a5 diff --git a/benchmarks/s3concurrent/.gitignore b/benchmarks/s3concurrent/.gitignore new file mode 100644 index 0000000..22189b7 --- /dev/null +++ b/benchmarks/s3concurrent/.gitignore @@ -0,0 +1 @@ +s3concurrent diff --git a/benchmarks/s3concurrent/main.go b/benchmarks/s3concurrent/main.go index a67fc5b..9f7f3af 100644 --- a/benchmarks/s3concurrent/main.go +++ b/benchmarks/s3concurrent/main.go @@ -1,17 +1,17 @@ package main import ( - "context" - "crypto/tls" - "io" - "log" - "math/rand" - "net/http" - "os" + "context" + "crypto/tls" + "io" + "log" + "math/rand" + "net/http" + "os" + "github.com/google/uuid" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/google/uuid" ) func buildMc() (*minio.Client, error) { @@ -30,92 +30,93 @@ func buildMc() (*minio.Client, error) { } mc, err := minio.New(os.Getenv("ENDPOINT"), &opts) - return mc, err + return mc, err } -type PRNG struct { - rem int64 +type PRNG struct { + rem int64 } -func (r *PRNG) Read(p []byte) (n int, err error) { - //log.Printf("rem=%d, buf=%d\n", r.rem, len(p)) - if int64(len(p)) > r.rem { - p = p[:r.rem] - } - if int64(len(p)) > r.rem { - log.Fatal("LOGIC ERROR") - } +func (r *PRNG) Read(p []byte) (n int, err error) { + //log.Printf("rem=%d, buf=%d\n", r.rem, len(p)) + if int64(len(p)) > r.rem { + p = p[:r.rem] + } - n, err = rand.Read(p) - if err != nil { - return - } - r.rem -= int64(n) - if r.rem <= 0 { - err = io.EOF - //log.Printf("PRNG file has been fully read. rem=%d,n=%d,err=%s\n", r.rem, n, err) - } - return + if int64(len(p)) > r.rem { + log.Fatal("LOGIC ERROR") + } + + n, err = rand.Read(p) + if err != nil { + return + } + r.rem -= int64(n) + if r.rem <= 0 { + err = io.EOF + //log.Printf("PRNG file has been fully read. rem=%d,n=%d,err=%s\n", r.rem, n, err) + } + return } func putObj(buck string, size int64) error { - mc, err := buildMc() - if err != nil { - return err - } + mc, err := buildMc() + if err != nil { + return err + } - prng := new(PRNG) - prng.rem = size + prng := new(PRNG) + prng.rem = size - key := uuid.New().String() + key := uuid.New().String() - _, err = mc.PutObject( - context.Background(), - buck, - key, - prng, - size, - minio.PutObjectOptions{ContentType:"application/octet-stream"}, - ) + _, err = mc.PutObject( + context.Background(), + buck, + key, + prng, + size, + minio.PutObjectOptions{ContentType: "application/octet-stream"}, + ) - return err + return err } func main() { - minio.MaxRetry = 1 - mc, err := buildMc() + minio.MaxRetry = 1 + mc, err := buildMc() if err != nil { log.Fatal("failed connect", err) return } - // Create Bucket - buck := uuid.New().String() - err = mc.MakeBucket(context.Background(), buck, minio.MakeBucketOptions{ }) - if err != nil { - log.Fatal(err) - return - } - log.Printf("created bucket %s\n", buck) + // Create Bucket + buck := uuid.New().String() + err = mc.MakeBucket(context.Background(), buck, minio.MakeBucketOptions{}) + if err != nil { + log.Fatal(err) + return + } + log.Printf("created bucket %s\n", buck) - // Send to bucket - for i := 1; i <= 16; i++ { - log.Printf("start concurrent loop with %d coroutines\n", i) - syn := make(chan error) - for j := 1; j <= i; j++ { - go func() { - syn <- putObj(buck, 1024 * 1024) - }() - } + // Send to bucket + for i := 1; i <= 16; i++ { + log.Printf("start concurrent loop with %d coroutines\n", i) + syn := make(chan error) + for j := 1; j <= i; j++ { + go func() { + syn <- putObj(buck, 1024*1024) + }() + } - for j := 1; j <= i; j++ { - cerr := <-syn - if cerr != nil { - log.Printf("%d/%d failed with %s\n", j, i, cerr) - } - } - log.Printf("done, %d coroutines returned\n", i) - } + for j := 1; j <= i; j++ { + cerr := <-syn + if cerr != nil { + log.Printf("%d/%d failed with %s\n", j, i, cerr) + } + } + log.Printf("done, %d coroutines returned\n", i) + } - log.Println("done") + log.Println("done") } diff --git a/benchmarks/s3lat/.gitignore b/benchmarks/s3lat/.gitignore new file mode 100644 index 0000000..cca6e53 --- /dev/null +++ b/benchmarks/s3lat/.gitignore @@ -0,0 +1 @@ +s3lat diff --git a/benchmarks/s3lat/s3lat b/benchmarks/s3lat/s3lat deleted file mode 100755 index 8b1f095..0000000 Binary files a/benchmarks/s3lat/s3lat and /dev/null differ diff --git a/scenarios/fragments/garage.py b/scenarios/fragments/garage.py index cd8b888..f886b33 100644 --- a/scenarios/fragments/garage.py +++ b/scenarios/fragments/garage.py @@ -30,7 +30,7 @@ keys = key_api.KeyApi(api) # Setup, launch on import storage_path = Path(shared.storage_path) / "garage" / env['HOST'] -if 'ZONE' in env: +if 'ZONE' in env and env['ZONE'] != "": storage_path = Path(shared.storage_path) / "garage" / env['ZONE'] / env['HOST'] config = storage_path / "garage.toml" env['GARAGE_CONFIG_FILE'] = str(config) @@ -117,14 +117,17 @@ admin_token = "{admin}" f.write(json.dumps({ "node_addr": f"{node_id}@{env['IP']}:3901", "node_id": node_id, - "zone": env['ZONE'], + "zone": env['ZONE'] if 'ZONE' in env and env['ZONE'] != "" else env['HOST'], "host": env['HOST'], })) def destroy(): dpid = Path(storage_path) / "daemon.pid" if exists(dpid): - shared.exec(f"kill -9 $(cat {dpid})") + try: + shared.exec(f"kill -9 $(cat {dpid})") + except: + pass shared.exec(f"rm -f {dpid}") if len(str(storage_path)) < 8: # arbitrary, stupid safe guard print(storage_path) diff --git a/scenarios/garage-manual b/scenarios/garage-manual new file mode 100755 index 0000000..f2dfcc9 --- /dev/null +++ b/scenarios/garage-manual @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +from fragments import garage, s3lat, shared + +if shared.id() == 1: + garage.deploy_coord() +else: + garage.deploy_follow()