Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

performance monitor package #2046

Merged
merged 10 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions cmds/modules/noded/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package noded
import (
"context"
"crypto/ed25519"
"encoding/json"
"fmt"
"os/exec"
"strings"
Expand All @@ -19,6 +20,7 @@ import (
"github.com/threefoldtech/zos/pkg/environment"
"github.com/threefoldtech/zos/pkg/events"
"github.com/threefoldtech/zos/pkg/monitord"
"github.com/threefoldtech/zos/pkg/perf"
"github.com/threefoldtech/zos/pkg/registrar"
"github.com/threefoldtech/zos/pkg/stubs"
"github.com/threefoldtech/zos/pkg/utils"
Expand Down Expand Up @@ -193,6 +195,27 @@ func action(cli *cli.Context) error {
return hypervisor, nil
})

log.Info().Msg("start perf scheduler")
perfMon, err := perf.NewPerformanceMonitor("unix://var/run/redis.sock")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be hard coded, specially that we already have a command line argument for that

if err != nil {
return errors.Wrap(err, "failed to create a new perfMon")
}
defer perfMon.Close()

err = perfMon.Run(ctx)
if err != nil {
log.Error().Err(err).Msg("failed to run the scheduler")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
err = perfMon.Run(ctx)
if err != nil {
log.Error().Err(err).Msg("failed to run the scheduler")
}
if err := perfMon.Run(ctx); err != nil {
log.Error().Err(err).Msg("failed to run the scheduler")
}

Also i think it's better if we return the error not just log

bus.WithHandler("zos.perf.get", func(ctx context.Context, payload []byte) (interface{}, error) {
var taskName string
err := json.Unmarshal(payload, &taskName)
if err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal payload: %v", payload)
}

return perfMon.GetCache(taskName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the API need to support returning all available tests, or specific one by name. so this function need to support not having a test-name and that name it call be results from all.

Also the GetCache is not a good name. Again this exposes the details of an implementation. The user of the API does not care where the result is stored or if the test is executed on request. Hence this should only called Get

})

// answer calls for dmi
go func() {
if err := bus.Run(ctx); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion docs/development/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- [Starting a local zos node](#starting-a-local-zos-node)
- [Accessing node](#accessing-node)
- [Development](#development)
- [Qemu docs](../../qemu/README.md)

## Starting a local zos node

Expand All @@ -19,7 +20,7 @@ Then, inside zos repository
make -C cmds
cd qemu
mv <downloaded image path> ./zos.efi
sudo ./vm.sh -n myzos-01 -c "farmer_id=<your farm id here> printk.devmsg=on runmode=dev"
sudo ./vm.sh -n node-01 -c "farmer_id=<your farm id here> printk.devmsg=on runmode=dev"
```

You should see the qemu console and boot logs, wait for awhile and you can [browse farms](https://dashboard.dev.grid.tf/explorer/farms) to see your node is added/detected automatically.
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ require (
github.com/fsnotify/fsnotify v1.6.0
github.com/g0rbe/go-chattr v0.0.0-20190906133247-aa435a6a0a37
github.com/gizak/termui/v3 v3.1.0
github.com/go-co-op/gocron v1.33.1
github.com/go-redis/redis v6.15.9+incompatible
github.com/gomodule/redigo v2.0.0+incompatible
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.3.0
github.com/google/uuid v1.3.1
github.com/gorilla/mux v1.8.0
github.com/gtank/merlin v0.1.1
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
Expand Down Expand Up @@ -120,6 +121,7 @@ require (
github.com/pkg/xattr v0.4.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/rs/cors v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/safchain/ethtool v0.0.0-20201023143004-874930cb3ce0 // indirect
Expand All @@ -135,6 +137,7 @@ require (
github.com/xxtea/xxtea-go v0.0.0-20170828040851-35c4b17eecf6 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/text v0.12.0 // indirect
Expand Down
15 changes: 13 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
Expand Down Expand Up @@ -156,6 +157,8 @@ github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc=
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
github.com/go-co-op/gocron v1.33.1 h1:wjX+Dg6Ae29a/f9BSQjY1Rl+jflTpW9aDyMqseCj78c=
github.com/go-co-op/gocron v1.33.1/go.mod h1:NLi+bkm4rRSy1F8U7iacZOz0xPseMoIOnvabGoSe/no=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
Expand Down Expand Up @@ -230,8 +233,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gordonklaus/ineffassign v0.0.0-20190601041439-ed7b1b5ee0f8/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
Expand Down Expand Up @@ -287,6 +290,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand Down Expand Up @@ -408,6 +412,7 @@ github.com/pierrec/lz4 v2.3.0+incompatible h1:CZzRn4Ut9GbUkHlQ7jqBXeZQV41ZSKWFc3
github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/xxHash v0.1.5 h1:n/jBpwTHiER4xYvK3/CdPVnLDPchj8eTJFFLUb4QHBo=
github.com/pierrec/xxHash v0.1.5/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand All @@ -432,9 +437,13 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
Expand Down Expand Up @@ -546,6 +555,8 @@ go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
Expand Down
39 changes: 39 additions & 0 deletions pkg/perf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Perf

Perf is a performance test module that is scheduled to run and cache those tests results in redis which can be retrieved later over RMB call.

Perf tests are monitored by `noded` service from zos modules.

### Usage Example

1. Create a task that implement `Task` interface

```go
type LoggingTask struct {
TaskID string
Schedule string // should be in cron syntax with seconds ("* 0 * * * *")
}

func (t *LoggingTask) ID() string {
return t.TaskID
}

func (t *LoggingTask) Cron() string {
return t.Schedule
}

// a simple task that returns a string with the current time
func (t *LoggingTask) Run(ctx context.Context) (interface{}, error) {
result := fmt.Sprintf("time is: %v", time.Now())
return result, nil
}
```

2. Add the created task to scheduler

```go
perfMon.AddTask(&perf.LoggingTask{
TaskID: "LoggingTask",
Schedule: "* 0 * * * *", // when minutes is 0 (aka: every hour)
})
```
43 changes: 43 additions & 0 deletions pkg/perf/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package perf

import (
"context"
"encoding/json"

"github.com/pkg/errors"
)

// TaskResult the result test schema
type TaskResult struct {
TaskName string `json:"task_name"`
RunTimestamp string `json:"run_timestamp"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change this to an actual unix timpestamp uint64. Storing time as a string is the most inefficient way to store time.

Result interface{} `json:"result"`
}

// setCache set result in redis
func (pm *PerformanceMonitor) setCache(ctx context.Context, taskName string, result TaskResult) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do u pass taskName when the TaskResult already have this?

data, err := json.Marshal(result)
if err != nil {
return errors.Wrap(err, "failed to marshal data to JSON")
}

_, err = pm.redisConn.Do("SET", taskName, data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the task name alone as a key is not a good idea. The same redis instance is used by other apps on the system to store and queue data. Hence you need to create some sort of a namespacing for your data. for example prefix all keys with perf. so for example a cpu test key will be perf.cpu instead of cpu so it has less chance of having collisions with other apps

Having a prefix also makes it easier for range scan. For example if u wanna return ALL tests u can scan KEYS with perf.* to return all results for all tests

return err
}

// GetCache get data from redis
func (pm *PerformanceMonitor) GetCache(taskName string) (TaskResult, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As commented before, the GetCache is not correct. The performance framework internal details (how tests are run or how results are retrieved) is only an implementation details. The PerformanceMonitor struct then API should be Get for a result.

In other words, why a user of this framework know that the result is cached for example

var res TaskResult

data, err := pm.redisConn.Do("GET", taskName)
if err != nil {
return res, errors.Wrap(err, "failed to get the cached result")
}

err = json.Unmarshal(data.([]byte), &res)
if err != nil {
return res, errors.Wrap(err, "failed to unmarshal data from json")
}

return res, nil
}
75 changes: 75 additions & 0 deletions pkg/perf/monitor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package perf

import (
"context"
"time"

"github.com/go-co-op/gocron"
"github.com/gomodule/redigo/redis"

"github.com/pkg/errors"
"github.com/threefoldtech/zos/pkg/utils"
)

// PerformanceMonitor holds the module data
type PerformanceMonitor struct {
scheduler *gocron.Scheduler
redisConn redis.Conn
tasks []Task
}

// NewPerformanceMonitor returns PerformanceMonitor instance
func NewPerformanceMonitor(redisAddr string) (*PerformanceMonitor, error) {
redisPool, err := utils.NewRedisPool(redisAddr)
if err != nil {
return nil, errors.Wrap(err, "failed creating new redis pool")
}

redisConn := redisPool.Get()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not how u use the redis Pool. The idea of a Pool of connection that u Get a connection from the pool, use it and then close it immediately when you are done using it.

Closing a connection will return the connection to the pool (the pool might not close the connection) but keep it alive for the next one to need a connection (by calling the pool.Get())

So what u are doing is breaking the pooling contract by hording a connection forever. This is also really bad because if the connection is interrupted (or lost because of any reason) there is NO way that u renew the connection. The pool on the other hand tests the connection before it give u one when u do a Get, and renew it if needed.

In summary, what u need to do is to keep the pool on you structure (not a connection) and in you setCache and Get methods what u need to do is

con := pm.pool.Get()
defer con.Clonse()

// use the con to get or set

scheduler := gocron.NewScheduler(time.UTC)

return &PerformanceMonitor{
scheduler: scheduler,
redisConn: redisConn,
tasks: []Task{},
}, nil
}

// AddTask a simple helper method to add new tasks
func (pm *PerformanceMonitor) AddTask(task Task) {
pm.tasks = append(pm.tasks, task)
}

// Run adds the tasks to the corn queue and start the scheduler
func (pm *PerformanceMonitor) Run(ctx context.Context) error {
for _, task := range pm.tasks {
_, err := pm.scheduler.CronWithSeconds(task.Cron()).Do(func() error {
res, err := task.Run(ctx)
if err != nil {
return errors.Wrapf(err, "failed to run task: %s", task.ID())
}

err = pm.setCache(ctx, task.ID(), TaskResult{
TaskName: task.ID(),
RunTimestamp: time.Now().Format("2006-01-02 15:04:05"),
Result: res,
})
if err != nil {
return errors.Wrap(err, "failed to set cache")
}

return nil
})
if err != nil {
return errors.Wrapf(err, "failed to schedule the task: %s", task.ID())
}
}

pm.scheduler.StartAsync()
return nil
}

// Close closes the redis connection
func (pm *PerformanceMonitor) Close() {
pm.redisConn.Close()
}
11 changes: 11 additions & 0 deletions pkg/perf/tasks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package perf

import (
"context"
)

type Task interface {
ID() string
Cron() string
Run(ctx context.Context) (interface{}, error)
}
13 changes: 13 additions & 0 deletions qemu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,16 @@ start:
bash vm.sh -n node1 -c "runmode=dev farmer_id=$(FARMERID)"
test:
bash vm.sh -n node1 -c "runmode=test farmer_id=$(FARMERID)"

auth:
@echo "Copying your public ssh to machine rootfs"
mkdir -p overlay/root/.ssh
cp ~/.ssh/id_rsa.pub overlay/root/.ssh/authorized_keys

net:
@echo "Creating a virtual natted network"
bash ./net.sh

run:
@echo "Running your node"
sudo ./vm.sh -g -n node-01 -c "farmer_id=$(id) version=v3 printk.devmsg=on runmode=dev nomodeset"
5 changes: 3 additions & 2 deletions qemu/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Run 0-OS in a VM using qemu
| For a quick development docs check [here](../docs/development/README.md)

This folder contains a script that you can use to run 0-OS in a VM using qemu.

Expand Down Expand Up @@ -111,7 +112,7 @@ sudo dnsmasq --strict-order \
1. Now run your vm

```bash
sudo ./vm.sh -n myzos-01 -c "farmer_id=47 printk.devmsg=on runmode=dev"
sudo ./vm.sh -n node-01 -c "farmer_id=47 printk.devmsg=on runmode=dev"
```

where `runmode` is one of `dev` , `test` or `prod`,
Expand Down Expand Up @@ -145,7 +146,7 @@ sudo ip link set forzos up
1. Now run your vm

```bash
./vm.sh -n myzos-01 -c "farmer_id=47 version=v3 printk.devmsg=on runmode=dev"
./vm.sh -n node-01 -c "farmer_id=47 version=v3 printk.devmsg=on runmode=dev"
```

where `runmode` is one of `dev` , `test` or `prod`,
Expand Down
File renamed without changes.